[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