btrfs: free qgroup pertrans reserve on transaction abort
authorBoris Burkov <boris@bur.io>
Fri, 1 Dec 2023 21:00:11 +0000 (13:00 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 1 Jan 2024 12:42:24 +0000 (12:42 +0000)
[ Upstream commit b321a52cce062ec7ed385333a33905d22159ce36 ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/btrfs/disk-io.c
fs/btrfs/qgroup.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h

index 71efb68..b79781d 100644 (file)
@@ -4836,6 +4836,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)
 {
@@ -4864,6 +4890,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 0d2212f..a006f51 100644 (file)
@@ -4124,8 +4124,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 c780d37..0ac2d19 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 93869cd..238a0ab 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,