summaryrefslogtreecommitdiff
path: root/lib/mpi/mpiutil.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.com>2017-08-08 16:56:36 +1000
committerShaohua Li <shli@fb.com>2017-08-08 07:42:36 -0700
commit81fe48e9aa00bdd509bd3c37a76d1132da6b9f09 (patch)
tree9e8748e00c47df70818f7b4aa8d994f6e1cc4b4c /lib/mpi/mpiutil.c
parent33182d15c6bf182f7ae32a66ea4a547d979cd6d7 (diff)
md: fix test in md_write_start()
md_write_start() needs to clear the in_sync flag is it is set, or if there might be a race with set_in_sync() such that the later will set it very soon. In the later case it is sufficient to take the spinlock to synchronize with set_in_sync(), and then set the flag if needed. The current test is incorrect. It should be: if "flag is set" or "race is possible" "flag is set" is trivially "mddev->in_sync". "race is possible" should be tested by "mddev->sync_checkers". If sync_checkers is 0, then there can be no race. set_in_sync() will wait in percpu_ref_switch_to_atomic_sync() for an RCU grace period, and as md_write_start() holds the rcu_read_lock(), set_in_sync() will be sure ot see the update to writes_pending. If sync_checkers is > 0, there could be race. If md_write_start() happened entirely between if (!mddev->in_sync && percpu_ref_is_zero(&mddev->writes_pending)) { and mddev->in_sync = 1; in set_in_sync(), then it would not see that is_sync had been set, and set_in_sync() would not see that writes_pending had been incremented. This bug means that in_sync is sometimes not set when it should be. Consequently there is a small chance that the array will be marked as "clean" when in fact it is inconsistent. Fixes: 4ad23a976413 ("MD: use per-cpu counter for writes_pending") cc: stable@vger.kernel.org (v4.12+) Signed-off-by: NeilBrown <neilb@suse.com> Signed-off-by: Shaohua Li <shli@fb.com>
Diffstat (limited to 'lib/mpi/mpiutil.c')
0 files changed, 0 insertions, 0 deletions