aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2015-11-05 05:06:23 -0500
committerFilipe Manana <fdmanana@suse.com>2015-11-05 05:32:21 -0500
commit190631f1c8cb7e4d5c27ff87e22ed53817e78759 (patch)
treea0b01561f6504793d66fe12351a784303fa2327d
parent7343dd61fd1b57c40cc06a5b5b5386df7f73c3ac (diff)
Btrfs: fix race waiting for qgroup rescan worker
We were initializing the completion (fs_info->qgroup_rescan_completion) object after releasing the qgroup rescan lock, which gives a small time window for a rescan waiter to not actually wait for the rescan worker to finish. Example: CPU 1 CPU 2 fs_info->qgroup_rescan_completion->done is 0 btrfs_qgroup_rescan_worker() complete_all(&fs_info->qgroup_rescan_completion) sets fs_info->qgroup_rescan_completion->done to UINT_MAX / 2 ... do some other stuff .... qgroup_rescan_init() mutex_lock(&fs_info->qgroup_rescan_lock) set flag BTRFS_QGROUP_STATUS_FLAG_RESCAN in fs_info->qgroup_flags mutex_unlock(&fs_info->qgroup_rescan_lock) btrfs_qgroup_wait_for_completion() mutex_lock(&fs_info->qgroup_rescan_lock) sees flag BTRFS_QGROUP_STATUS_FLAG_RESCAN in fs_info->qgroup_flags mutex_unlock(&fs_info->qgroup_rescan_lock) wait_for_completion_interruptible( &fs_info->qgroup_rescan_completion) fs_info->qgroup_rescan_completion->done is > 0 so it returns immediately init_completion(&fs_info->qgroup_rescan_completion) sets fs_info->qgroup_rescan_completion->done to 0 So fix this by initializing the completion object while holding the mutex fs_info->qgroup_rescan_lock. Signed-off-by: Filipe Manana <fdmanana@suse.com>
-rw-r--r--fs/btrfs/qgroup.c3
1 files changed, 1 insertions, 2 deletions
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 75c0249702df..75bb4af98a93 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -2387,12 +2387,11 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
2387 memset(&fs_info->qgroup_rescan_progress, 0, 2387 memset(&fs_info->qgroup_rescan_progress, 0,
2388 sizeof(fs_info->qgroup_rescan_progress)); 2388 sizeof(fs_info->qgroup_rescan_progress));
2389 fs_info->qgroup_rescan_progress.objectid = progress_objectid; 2389 fs_info->qgroup_rescan_progress.objectid = progress_objectid;
2390 init_completion(&fs_info->qgroup_rescan_completion);
2390 2391
2391 spin_unlock(&fs_info->qgroup_lock); 2392 spin_unlock(&fs_info->qgroup_lock);
2392 mutex_unlock(&fs_info->qgroup_rescan_lock); 2393 mutex_unlock(&fs_info->qgroup_rescan_lock);
2393 2394
2394 init_completion(&fs_info->qgroup_rescan_completion);
2395
2396 memset(&fs_info->qgroup_rescan_work, 0, 2395 memset(&fs_info->qgroup_rescan_work, 0,
2397 sizeof(fs_info->qgroup_rescan_work)); 2396 sizeof(fs_info->qgroup_rescan_work));
2398 btrfs_init_work(&fs_info->qgroup_rescan_work, 2397 btrfs_init_work(&fs_info->qgroup_rescan_work,