diff options
author | Filipe Manana <fdmanana@suse.com> | 2015-11-05 05:06:23 -0500 |
---|---|---|
committer | Filipe Manana <fdmanana@suse.com> | 2015-11-05 05:32:21 -0500 |
commit | 190631f1c8cb7e4d5c27ff87e22ed53817e78759 (patch) | |
tree | a0b01561f6504793d66fe12351a784303fa2327d | |
parent | 7343dd61fd1b57c40cc06a5b5b5386df7f73c3ac (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.c | 3 |
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, |