#endif
        qgroup->reserved = 0;
 }
+
 /*
- * The easy accounting, if we are adding/removing the only ref for an extent
- * then this qgroup and all of the parent qgroups get their reference and
- * exclusive counts adjusted.
+ * The easy accounting, we're updating qgroup relationship whose child qgroup
+ * only has exclusive extents.
+ *
+ * In this case, all exclsuive extents will also be exlusive for parent, so
+ * excl/rfer just get added/removed.
+ *
+ * So is qgroup reservation space, which should also be added/removed to
+ * parent.
+ * Or when child tries to release reservation space, parent will underflow its
+ * reservation (for relationship adding case).
  *
  * Caller should hold fs_info->qgroup_lock.
  */
 static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
                                    struct ulist *tmp, u64 ref_root,
-                                   u64 num_bytes, int sign)
+                                   struct btrfs_qgroup *src, int sign)
 {
        struct btrfs_qgroup *qgroup;
        struct btrfs_qgroup_list *glist;
        struct ulist_node *unode;
        struct ulist_iterator uiter;
+       u64 num_bytes = src->excl;
        int ret = 0;
 
        qgroup = find_qgroup_rb(fs_info, ref_root);
        WARN_ON(sign < 0 && qgroup->excl < num_bytes);
        qgroup->excl += sign * num_bytes;
        qgroup->excl_cmpr += sign * num_bytes;
-       if (sign > 0) {
-               trace_qgroup_update_reserve(fs_info, qgroup, -(s64)num_bytes);
-               if (qgroup->reserved < num_bytes)
-                       report_reserved_underflow(fs_info, qgroup, num_bytes);
-               else
-                       qgroup->reserved -= num_bytes;
-       }
+
+       if (sign > 0)
+               qgroup_rsv_add_by_qgroup(qgroup, src);
+       else
+               qgroup_rsv_release_by_qgroup(qgroup, src);
 
        qgroup_dirty(fs_info, qgroup);
 
                qgroup->rfer_cmpr += sign * num_bytes;
                WARN_ON(sign < 0 && qgroup->excl < num_bytes);
                qgroup->excl += sign * num_bytes;
-               if (sign > 0) {
-                       trace_qgroup_update_reserve(fs_info, qgroup,
-                                                   -(s64)num_bytes);
-                       if (qgroup->reserved < num_bytes)
-                               report_reserved_underflow(fs_info, qgroup,
-                                                         num_bytes);
-                       else
-                               qgroup->reserved -= num_bytes;
-               }
+               if (sign > 0)
+                       qgroup_rsv_add_by_qgroup(qgroup, src);
+               else
+                       qgroup_rsv_release_by_qgroup(qgroup, src);
                qgroup->excl_cmpr += sign * num_bytes;
                qgroup_dirty(fs_info, qgroup);
 
        if (qgroup->excl == qgroup->rfer) {
                ret = 0;
                err = __qgroup_excl_accounting(fs_info, tmp, dst,
-                                              qgroup->excl, sign);
+                                              qgroup, sign);
                if (err < 0) {
                        ret = err;
                        goto out;