]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
btrfs: qgroup: allow quick inherit if snapshot is created and added to the same parent
authorQu Wenruo <wqu@suse.com>
Mon, 26 Feb 2024 03:51:13 +0000 (14:21 +1030)
committerDavid Sterba <dsterba@suse.com>
Tue, 5 Mar 2024 16:13:24 +0000 (17:13 +0100)
Currently "btrfs subvolume snapshot -i <qgroupid>" would always mark the
qgroup inconsistent.

This can be annoying if the fs has a lot of snapshots, and needs qgroup
to get the accounting for the amount of bytes it can free for each
snapshot.

Although we have the new simple quote as a solution, there is also a
case where we can skip the full scan, if all the following conditions
are met:

- The source subvolume belongs to a higher level parent qgroup
- The parent qgroup already owns all its bytes exclusively
- The new snapshot is also added to the same parent qgroup

In that case, we only need to add nodesize to the parent qgroup and
avoid a full rescan.

This patch would add the extra quick accounting update for such inherit.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/qgroup.c

index af241aaa654a226864b6fb356b2361562ac51754..5f90f0605b12f7126e93d69e7fbec42720301fad 100644 (file)
@@ -3138,6 +3138,62 @@ static int qgroup_auto_inherit(struct btrfs_fs_info *fs_info,
        return 0;
 }
 
+/*
+ * Check if we can skip rescan when inheriting qgroups.  If @src has a single
+ * @parent, and that @parent is owning all its bytes exclusively, we can skip
+ * the full rescan, by just adding nodesize to the @parent's excl/rfer.
+ *
+ * Return <0 for fatal errors (like srcid/parentid has no qgroup).
+ * Return 0 if a quick inherit is done.
+ * Return >0 if a quick inherit is not possible, and a full rescan is needed.
+ */
+static int qgroup_snapshot_quick_inherit(struct btrfs_fs_info *fs_info,
+                                        u64 srcid, u64 parentid)
+{
+       struct btrfs_qgroup *src;
+       struct btrfs_qgroup *parent;
+       struct btrfs_qgroup_list *list;
+       int nr_parents = 0;
+
+       src = find_qgroup_rb(fs_info, srcid);
+       if (!src)
+               return -ENOENT;
+       parent = find_qgroup_rb(fs_info, parentid);
+       if (!parent)
+               return -ENOENT;
+
+       /*
+        * Source has no parent qgroup, but our new qgroup would have one.
+        * Qgroup numbers would become inconsistent.
+        */
+       if (list_empty(&src->groups))
+               return 1;
+
+       list_for_each_entry(list, &src->groups, next_group) {
+               /* The parent is not the same, quick update is not possible. */
+               if (list->group->qgroupid != parentid)
+                       return 1;
+               nr_parents++;
+               /*
+                * More than one parent qgroup, we can't be sure about accounting
+                * consistency.
+                */
+               if (nr_parents > 1)
+                       return 1;
+       }
+
+       /*
+        * The parent is not exclusively owning all its bytes.  We're not sure
+        * if the source has any bytes not fully owned by the parent.
+        */
+       if (parent->excl != parent->rfer)
+               return 1;
+
+       parent->excl += fs_info->nodesize;
+       parent->rfer += fs_info->nodesize;
+       return 0;
+}
+
 /*
  * Copy the accounting information between qgroups. This is necessary
  * when a snapshot or a subvolume is created. Throwing an error will
@@ -3306,6 +3362,13 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
 
                qgroup_dirty(fs_info, dstgroup);
                qgroup_dirty(fs_info, srcgroup);
+
+               /*
+                * If the source qgroup has parent but the new one doesn't,
+                * we need a full rescan.
+                */
+               if (!inherit && !list_empty(&srcgroup->groups))
+                       need_rescan = true;
        }
 
        if (!inherit)
@@ -3320,14 +3383,16 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
                        if (ret)
                                goto unlock;
                }
+               if (srcid) {
+                       /* Check if we can do a quick inherit. */
+                       ret = qgroup_snapshot_quick_inherit(fs_info, srcid, *i_qgroups);
+                       if (ret < 0)
+                               goto unlock;
+                       if (ret > 0)
+                               need_rescan = true;
+                       ret = 0;
+               }
                ++i_qgroups;
-
-               /*
-                * If we're doing a snapshot, and adding the snapshot to a new
-                * qgroup, the numbers are guaranteed to be incorrect.
-                */
-               if (srcid)
-                       need_rescan = true;
        }
 
        for (i = 0; i <  inherit->num_ref_copies; ++i, i_qgroups += 2) {