btrfs: add helper for recording simple quota deltas
authorBoris Burkov <boris@bur.io>
Tue, 28 Mar 2023 20:43:47 +0000 (13:43 -0700)
committerDavid Sterba <dsterba@suse.com>
Thu, 12 Oct 2023 14:44:11 +0000 (16:44 +0200)
Rather than re-computing shared/exclusive ownership based on backrefs
and walking roots for implicit backrefs, simple quotas does an increment
when creating an extent and a decrement when deleting it. Add the API
for the extent item code to use to track those events.

Signed-off-by: Boris Burkov <boris@bur.io>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/qgroup.c
fs/btrfs/qgroup.h

index 3a6fb57b99f03252c0ffb27162ca2afa7035f9b6..4c70417f13b0e483b656bd11383ef0126bc7492c 100644 (file)
@@ -4586,3 +4586,49 @@ void btrfs_qgroup_destroy_extent_records(struct btrfs_transaction *trans)
        }
        *root = RB_ROOT;
 }
+
+int btrfs_record_squota_delta(struct btrfs_fs_info *fs_info,
+                             struct btrfs_squota_delta *delta)
+{
+       int ret;
+       struct btrfs_qgroup *qgroup;
+       struct btrfs_qgroup *qg;
+       LIST_HEAD(qgroup_list);
+       u64 root = delta->root;
+       u64 num_bytes = delta->num_bytes;
+       const int sign = (delta->is_inc ? 1 : -1);
+
+       if (btrfs_qgroup_mode(fs_info) != BTRFS_QGROUP_MODE_SIMPLE)
+               return 0;
+
+       if (!is_fstree(root))
+               return 0;
+
+       spin_lock(&fs_info->qgroup_lock);
+       qgroup = find_qgroup_rb(fs_info, root);
+       if (!qgroup) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       ret = 0;
+       qgroup_iterator_add(&qgroup_list, qgroup);
+       list_for_each_entry(qg, &qgroup_list, iterator) {
+               struct btrfs_qgroup_list *glist;
+
+               qg->excl += num_bytes * sign;
+               qg->rfer += num_bytes * sign;
+               qgroup_dirty(fs_info, qg);
+
+               list_for_each_entry(glist, &qg->groups, next_group)
+                       qgroup_iterator_add(&qgroup_list, glist->group);
+       }
+       qgroup_iterator_clean(&qgroup_list);
+
+out:
+       spin_unlock(&fs_info->qgroup_lock);
+       if (!ret && delta->rsv_bytes)
+               btrfs_qgroup_free_refroot(fs_info, root, delta->rsv_bytes,
+                                         BTRFS_QGROUP_RSV_DATA);
+       return ret;
+}
index 0441d2ff5a49a25dbc0138a2ce7ee20b331ac9e0..1e0eb04ef96c5bac30f71663a0436ec699f53226 100644 (file)
@@ -269,6 +269,19 @@ struct btrfs_qgroup {
        struct kobject kobj;
 };
 
+struct btrfs_squota_delta {
+       /* The fstree root this delta counts against. */
+       u64 root;
+       /* The number of bytes in the extent being counted. */
+       u64 num_bytes;
+       /* The number of bytes reserved for this extent. */
+       u64 rsv_bytes;
+       /* Whether we are using or freeing the extent. */
+       bool is_inc;
+       /* Whether the extent is data or metadata. */
+       bool is_data;
+};
+
 static inline u64 btrfs_qgroup_subvolid(u64 qgroupid)
 {
        return (qgroupid & ((1ULL << BTRFS_QGROUP_LEVEL_SHIFT) - 1));
@@ -407,5 +420,7 @@ int btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans,
                struct btrfs_root *root, struct extent_buffer *eb);
 void btrfs_qgroup_destroy_extent_records(struct btrfs_transaction *trans);
 bool btrfs_check_quota_leak(struct btrfs_fs_info *fs_info);
+int btrfs_record_squota_delta(struct btrfs_fs_info *fs_info,
+                             struct btrfs_squota_delta *delta);
 
 #endif