[PATCH] md/raid10: protect head_position accesses consistency

"Chen Cheng" <[email protected]>
Newsgroups gmane.linux.raid,gmane.linux.kernel
Message-ID <[email protected]>
From: Chen Cheng <[email protected]>

the completion paths update conf->mirrors[x].head_position
without a lock, while read_balance() reads the same field
locklessly.

protect conf->mirror[x].head_position consistency for
multi-CPUs by READ_ONCE()/WRITE_ONCE().

the report #1:
=====================
 BUG: KCSAN: data-race in find_bio_disk.isra.0 / read_balance

 write to 0xffff8f0309679fd0 of 8 bytes by interrupt on cpu 9:
  find_bio_disk.isra.0+0x108/0x180
  raid10_end_write_request+0xd2/0x530
  bio_endio+0x3c9/0x3e0
 [...]

 read to 0xffff8f0309679fd0 of 8 bytes by task 338766 on cpu 7:
  read_balance+0x2ec/0x700
  raid10_read_request+0x17b/0x550
  raid10_make_request+0x27e/0x1080
  md_handle_request+0x2c5/0x700
  [...]

 value changed: 0x000000000032f440 -> 0x000000000014f8e0

the report #2:
=======================
 BUG: KCSAN: data-race in raid10_end_read_request / read_balance

 write to 0xffff8f03291091b0 of 8 bytes by interrupt on cpu 9:
  raid10_end_read_request+0xf0/0x400
  bio_endio+0x3c9/0x3e0
  [...]

 read to 0xffff8f03291091b0 of 8 bytes by task 336943 on cpu 8:
  read_balance+0x2ec/0x700
  raid10_read_request+0x17b/0x550
  raid10_make_request+0x27e/0x1080
  md_handle_request+0x2c5/0x700
 [...]

 value changed: 0x000000000041c188 -> 0x000000000041c1b8

Signed-off-by: Chen Cheng <[email protected]>
---
 drivers/md/raid10.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index caf1da15aa87..55aa052a957b 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -343,12 +343,12 @@ static void raid_end_bio_io(struct r10bio *r10_bio)
  */
 static inline void update_head_pos(int slot, struct r10bio *r10_bio)
 {
 	struct r10conf *conf = r10_bio->mddev->private;
 
-	conf->mirrors[r10_bio->devs[slot].devnum].head_position =
-		r10_bio->devs[slot].addr + (r10_bio->sectors);
+	WRITE_ONCE(conf->mirrors[r10_bio->devs[slot].devnum].head_position,
+		   r10_bio->devs[slot].addr + (r10_bio->sectors));
 }
 
 /*
  * Find the disk number which triggered given bio
  */
@@ -841,11 +841,11 @@ static struct md_rdev *read_balance(struct r10conf *conf,
 		/* for far > 1 always use the lowest address */
 		else if (geo->far_copies > 1)
 			new_distance = r10_bio->devs[slot].addr;
 		else
 			new_distance = abs(r10_bio->devs[slot].addr -
-					   conf->mirrors[disk].head_position);
+					   READ_ONCE(conf->mirrors[disk].head_position));
 
 		if (new_distance < best_dist) {
 			best_dist = new_distance;
 			best_dist_slot = slot;
 			best_dist_rdev = rdev;
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.