We fixed balance qgroup leaking by introducing
qgroup_fix_relocated_data_extents(), but it only covers normal balance
routine well.

For case btrfs_recover_relocation() routine, since rc->stage or
rc->data_inode are not initialized, we either skip
qgroup_fix_relocated_data_extents() or just cause NULL pointer access.

Since we skip qgroup_fix_relocated_data_extents() in
btrfs_recover_relocation(), we will still leak qgroup numbers for that
routine.

In the fix, we won't use data_inode any longer, as at the timing of the
qgroup fix, noone will modify data_reloc tree any longer, so path
locking should be good enough.

And add check against rc->merge_reloc_tree, so we can detect if we are
in btrfs_recover_relocation() routine and continue qgroup fix.

Reported-by: Goldwyn Rodrigues <rgold...@suse.de>
Signed-off-by: Qu Wenruo <quwen...@cn.fujitsu.com>
---
 fs/btrfs/relocation.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index c0c13dc..f250187 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -3946,8 +3946,7 @@ static int qgroup_fix_relocated_data_extents(struct 
btrfs_trans_handle *trans,
                                             struct reloc_control *rc)
 {
        struct btrfs_fs_info *fs_info = rc->extent_root->fs_info;
-       struct inode *inode = rc->data_inode;
-       struct btrfs_root *data_reloc_root = BTRFS_I(inode)->root;
+       struct btrfs_root *data_reloc_root;
        struct btrfs_path *path;
        struct btrfs_key key;
        int ret = 0;
@@ -3956,18 +3955,28 @@ static int qgroup_fix_relocated_data_extents(struct 
btrfs_trans_handle *trans,
                return 0;
 
        /*
+        * For normal balance routine, merge_reloc_tree flag is always cleared
+        * before commit trans.
+        * For recover relocation routine, merge_reloc_tree is always 1, we need
+        * to continue anyway.
+        *
         * Only for stage where we update data pointers the qgroup fix is
         * valid.
         * For MOVING_DATA stage, we will miss the timing of swapping tree
         * blocks, and won't fix it.
         */
-       if (!(rc->stage == UPDATE_DATA_PTRS && rc->extents_found))
+       if (!(rc->stage == UPDATE_DATA_PTRS && rc->extents_found) &&
+           rc->merge_reloc_tree == 0)
                return 0;
 
+       data_reloc_root = read_fs_root(fs_info, BTRFS_DATA_RELOC_TREE_OBJECTID);
+       if (IS_ERR(data_reloc_root))
+               return PTR_ERR(data_reloc_root);
+
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
-       key.objectid = btrfs_ino(inode);
+       key.objectid = BTRFS_FIRST_FREE_OBJECTID + 1;
        key.type = BTRFS_EXTENT_DATA_KEY;
        key.offset = 0;
 
@@ -3975,13 +3984,10 @@ static int qgroup_fix_relocated_data_extents(struct 
btrfs_trans_handle *trans,
        if (ret < 0)
                goto out;
 
-       lock_extent(&BTRFS_I(inode)->io_tree, 0, (u64)-1);
        while (1) {
                struct btrfs_file_extent_item *fi;
 
                btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
-               if (key.objectid > btrfs_ino(inode))
-                       break;
                if (key.type != BTRFS_EXTENT_DATA_KEY)
                        goto next;
                fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
@@ -4004,7 +4010,6 @@ next:
                        break;
                }
        }
-       unlock_extent(&BTRFS_I(inode)->io_tree, 0 , (u64)-1);
 out:
        btrfs_free_path(path);
        return ret;
-- 
2.10.0



--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to