Re: [PATCH v2] md/raid5: protect bitmap batch counters aka seq_flush/seq_write consistency

"Chen Cheng" <[email protected]>
Newsgroups gmane.linux.raid,gmane.linux.kernel
Message-ID <[email protected]>
在 2026/6/21 05:13, yu kuai 写道:
> Hi,
> 
> 在 2026/6/17 22:28, Chen Cheng 写道:
>> From: Chen Cheng <[email protected]>
>>
>> kcsan detect race :
>> - raid5d() closes the current bitmap batch by updating
>> 	conf->seq_flush under conf->device_lock.
>> - __add_stripe_bio() read conf->seq_flush without that
>> 	lock when assigning sh->bm_seq.
>>
>> so, protect seq_flush/seq_write consistency for multiple CPUs by
>> READ_ONCE()/WRITE_ONCE() under the path without held device_lock.
>>
>> re-explain the stripe batch sequence number update flow:
>> 1. sh->bm_seq declare which batch number the stripe belongs to
>>      when perform bitmap-related write.
>> 	==> bm_seq = seq_flush+1
>>
>> 2. stripe be handled,
>> 	* if sh->bm_seq - conf->seq_write > 0, means the
>> 	  batch stripes **newer than** the last written
>> 	  batch, it cannot proceed yet, queued on bitmap_list.
>> 	* otherwise , has already proceed.
>>
>> 3. raid5d() `++seq_flush` to closes the current batch, means
>> 	* no more stripes join that old batch
>> 	* just-closed batch ready to write-out to disk
>>
>> 4. raid5d() calls bitmap hooks unplug() or writeout, then,
>>      `++seq_write` to the same as bm_seq.
>>
>> - seq_flush - for producer, to close batches.
>> - seq_write - for consumer, the checkpoint number.
>>
>> the report:
>> ====================================
>> BUG: KCSAN: data-race in __add_stripe_bio / raid5d
>>
>> write to 0xffff88ba5625d470 of 4 bytes by task 82401 on cpu 0:
>>    raid5d+0x1d9/0xba0
>>    [.....]
>>
>> read to 0xffff88ba5625d470 of 4 bytes by task 82421 on cpu 8:
>>    __add_stripe_bio+0x332/0x400
>>    raid5_make_request+0x6ac/0x2930
>>    md_handle_request+0x4a2/0xa40
>>    md_submit_bio+0x109/0x1a0
>>    __submit_bio+0x2ec/0x390
>>    [.....]
>>
>> v1 -> v2:
>> - remove WRITE_ONCE(conf->seq_write) in held device_lock path.
>> - remove READ_ONCE(conf->seq_flush) in held device_lock path.
>>
>> Signed-off-by: Chen Cheng <[email protected]>
>> ---
>>    drivers/md/raid5.c | 9 +++++----
>>    1 file changed, 5 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
>> index a320b71d7117..b2c5a1930841 100644
>> --- a/drivers/md/raid5.c
>> +++ b/drivers/md/raid5.c
>> @@ -3536,11 +3536,11 @@ static void __add_stripe_bio(struct stripe_head *sh, struct bio *bi,
>>    	pr_debug("added bi b#%llu to stripe s#%llu, disk %d, logical %llu\n",
>>    		 (*bip)->bi_iter.bi_sector, sh->sector, dd_idx,
>>    		 sh->dev[dd_idx].sector);
>>    
>>    	if (conf->mddev->bitmap && firstwrite && !sh->batch_head) {
>> -		sh->bm_seq = conf->seq_flush+1;
>> +		sh->bm_seq = READ_ONCE(conf->seq_flush) + 1;
>>    		set_bit(STRIPE_BIT_DELAY, &sh->state);
>>    	}
>>    }
>>    
>>    /*
>> @@ -5827,11 +5827,11 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi)
>>    			md_write_inc(mddev, bi);
>>    			sh->overwrite_disks++;
>>    		}
>>    		spin_unlock_irq(&sh->stripe_lock);
>>    		if (conf->mddev->bitmap) {
>> -			sh->bm_seq = conf->seq_flush + 1;
>> +			sh->bm_seq = READ_ONCE(conf->seq_flush) + 1;
>>    			set_bit(STRIPE_BIT_DELAY, &sh->state);
>>    		}
>>    
>>    		set_bit(STRIPE_HANDLE, &sh->state);
>>    		clear_bit(STRIPE_DELAYED, &sh->state);
>> @@ -6877,16 +6877,17 @@ static void raid5d(struct md_thread *thread)
>>    			clear_bit(R5_DID_ALLOC, &conf->cache_state);
>>    
>>    		if (
>>    		    !list_empty(&conf->bitmap_list)) {
>>    			/* Now is a good time to flush some bitmap updates */
>> -			conf->seq_flush++;
>> +			int seq = conf->seq_flush + 1;
> 
> checkpatch should warn this about missing blank line after declaration.

ok.

> 
>> +			WRITE_ONCE(conf->seq_flush, seq);
> 
> WRITE_ONCE(a, a + 1) is safe, you can see lots of examples.

Gotta re-use `conf->seq_flush` snapshot aka. `seq` below..

> 
>>    			spin_unlock_irq(&conf->device_lock);
>>    			if (md_bitmap_enabled(mddev, true))
>>    				mddev->bitmap_ops->unplug(mddev, true);
>>    			spin_lock_irq(&conf->device_lock);
>> -			conf->seq_write = conf->seq_flush;
>> +			conf->seq_write = seq;
>>    			activate_bit_delay(conf, conf->temp_inactive_list);
>>    		}
>>    		raid5_activate_delayed(conf);
>>    
>>    		while ((bio = remove_bio_from_retry(conf, &offset))) {
>
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.