[PATCH] btrfs: relocation: Fix NULL pointer access and leaking qgroups in btrfs_recover_relocation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <rgoldwyn@xxxxxxx>
Signed-off-by: Qu Wenruo <quwenruo@xxxxxxxxxxxxxx>
---
 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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Filesystem Development]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux