btrfs: free qgroup pertrans reserve on transaction abort
authorBoris Burkov <boris@bur.io>
Fri, 1 Dec 2023 21:00:11 +0000 (13:00 -0800)
committerDavid Sterba <dsterba@suse.com>
Wed, 6 Dec 2023 21:32:49 +0000 (22:32 +0100)
If we abort a transaction, we never run the code that frees the pertrans
qgroup reservation. This results in warnings on unmount as that
reservation has been leaked. The leak isn't a huge issue since the fs is
read-only, but it's better to clean it up when we know we can/should. Do
it during the cleanup_transaction step of aborting.

CC: stable@vger.kernel.org # 5.15+
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Boris Burkov <boris@bur.io>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/disk-io.c
fs/btrfs/qgroup.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h

index bbcc3df776461f5b6952422c246e65bbcbc1ccc6..62cb97f7c94fa26e0969707f595e07ffa9bb3937 100644 (file)
@@ -4799,6 +4799,32 @@ void btrfs_cleanup_dirty_bgs(struct btrfs_transaction *cur_trans,
        }
 }
 
+static void btrfs_free_all_qgroup_pertrans(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_root *gang[8];
+       int i;
+       int ret;
+
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       while (1) {
+               ret = radix_tree_gang_lookup_tag(&fs_info->fs_roots_radix,
+                                                (void **)gang, 0,
+                                                ARRAY_SIZE(gang),
+                                                BTRFS_ROOT_TRANS_TAG);
+               if (ret == 0)
+                       break;
+               for (i = 0; i < ret; i++) {
+                       struct btrfs_root *root = gang[i];
+
+                       btrfs_qgroup_free_meta_all_pertrans(root);
+                       radix_tree_tag_clear(&fs_info->fs_roots_radix,
+                                       (unsigned long)root->root_key.objectid,
+                                       BTRFS_ROOT_TRANS_TAG);
+               }
+       }
+       spin_unlock(&fs_info->fs_roots_radix_lock);
+}
+
 void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
                                   struct btrfs_fs_info *fs_info)
 {
@@ -4827,6 +4853,8 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
                                     EXTENT_DIRTY);
        btrfs_destroy_pinned_extent(fs_info, &cur_trans->pinned_extents);
 
+       btrfs_free_all_qgroup_pertrans(fs_info);
+
        cur_trans->state =TRANS_STATE_COMPLETED;
        wake_up(&cur_trans->commit_wait);
 }
index a953c16c7eb82b924126d7f6ffbfa01b5fd84040..daec90342dad0f2bd0284aa0abe05fc9c9ea75d8 100644 (file)
@@ -4337,8 +4337,9 @@ static void qgroup_convert_meta(struct btrfs_fs_info *fs_info, u64 ref_root,
 
                qgroup_rsv_release(fs_info, qgroup, num_bytes,
                                BTRFS_QGROUP_RSV_META_PREALLOC);
-               qgroup_rsv_add(fs_info, qgroup, num_bytes,
-                               BTRFS_QGROUP_RSV_META_PERTRANS);
+               if (!sb_rdonly(fs_info->sb))
+                       qgroup_rsv_add(fs_info, qgroup, num_bytes,
+                                      BTRFS_QGROUP_RSV_META_PERTRANS);
 
                list_for_each_entry(glist, &qgroup->groups, next_group)
                        qgroup_iterator_add(&qgroup_list, glist->group);
index 7af9665bebae4f74d7dc263dc143f242da2a5fa6..b5aa83b7345ad01a6f1a61d2e31e624474ce0a1a 100644 (file)
@@ -37,8 +37,6 @@
 
 static struct kmem_cache *btrfs_trans_handle_cachep;
 
-#define BTRFS_ROOT_TRANS_TAG 0
-
 /*
  * Transaction states and transitions
  *
index 18c4f6e83b78839d3a2f65306eef097f0f28a944..2bf8bbdfd0b38b1b1caf3cf1cf0b6738d28f231f 100644 (file)
@@ -12,6 +12,9 @@
 #include "ctree.h"
 #include "misc.h"
 
+/* Radix-tree tag for roots that are part of the trasaction. */
+#define BTRFS_ROOT_TRANS_TAG                   0
+
 enum btrfs_trans_state {
        TRANS_STATE_RUNNING,
        TRANS_STATE_COMMIT_PREP,