Re: [PATCH v6 3/3] md/raid10: free r10bio before ending master_bio in raid_end_bio_io() and raid_end_discard_bio()

"Chen Cheng" <[email protected]>
Newsgroups gmane.linux.raid,gmane.linux.kernel
Message-ID <[email protected]>
在 2026/7/5 15:48, yu kuai 写道:
> Hi,
> 
> 在 2026/6/23 20:38, Chen Cheng 写道:
>> From: Chen Cheng <[email protected]>
>>
>> origin flow:
>>
>>         bio_endio(master_bio);   /* may drop active_io to zero */
>>         allow_barrier(conf);
>>         free_r10bio(r10_bio);    /* reads conf->geo, returns to pool */
>>
>> one scenario is:
>>
>>     CPU A (softirq, raid_end_bio_io)         CPU B (action_store) --> reshape
>>     ================================         ===============================
>>     bio_endio(master_bio)
>>       md_end_clone_io
>>         percpu_ref_put -> 0
>>                                              wait_event wakeup, and,
>>                                              	mddev_suspend return
>>                                              raid10_start_reshape:
>>                                                setup_geo(&conf->geo, new)
>>                                                ...
>>                                                mempool_destroy(old_pool)
>>                                                conf->r10bio_pool = new_pool
>>     allow_barrier(conf)
>>     free_r10bio(r10_bio)
>>       put_all_bios:
>>         for (i=0; i<conf->geo.raid_disks; i++)
>>             ==> old obj, new geo, OOB
>>       mempool_free(r10_bio, conf->r10bio_pool)
>>             ==> old-geometry obj freed into new pool
>>
>> so .. fix by reorder the flow:
>>
>> 	free_r10bio(r10_bio)
>> 	allow_barrier(conf)
>> 	bio_endio(master_io)
>>
>> raid_end_discard_bio() is exactly the same.
>>
>> Signed-off-by: Chen Cheng <[email protected]>
>> ---
>>    drivers/md/raid10.c | 17 ++++++++++-------
>>    1 file changed, 10 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
>> index d740744a9746..e44a9b6e95c7 100644
>> --- a/drivers/md/raid10.c
>> +++ b/drivers/md/raid10.c
>> @@ -330,24 +330,25 @@ static void reschedule_retry(struct r10bio *r10_bio)
>>     */
>>    static void raid_end_bio_io(struct r10bio *r10_bio)
>>    {
>>    	struct bio *bio = r10_bio->master_bio;
>>    	struct r10conf *conf = r10_bio->mddev->private;
>> +	unsigned long state = r10_bio->state;
>>    
>> -	if (!test_and_set_bit(R10BIO_Returned, &r10_bio->state)) {
>> -		if (!test_bit(R10BIO_Uptodate, &r10_bio->state))
>> -			bio->bi_status = BLK_STS_IOERR;
>> -		bio_endio(bio);
>> -	}
>> +	free_r10bio(r10_bio);
>>    
>>    	/*
>>    	 * Wake up any possible resync thread that waits for the device
>>    	 * to go idle.
>>    	 */
>>    	allow_barrier(conf);
>>    
>> -	free_r10bio(r10_bio);
>> +	if (!test_and_set_bit(R10BIO_Returned, &state)) {
>> +		if (!test_bit(R10BIO_Uptodate, &state))
>> +			bio->bi_status = BLK_STS_IOERR;
>> +		bio_endio(bio);
>> +	}
> 
> Why is this moved to the end? I feel it's not necessary.
> 

yes, point is let endio after free r10bio.

free_r10bio(r10_bio) -> allow_barrier(conf) -> bio_endio(master_io) or

free_r10bio(r10_bio) -> bio_endio(master_io) -> allow_barrier(conf)

both order is correct to fix the bug.

>>    }
>>    
>>    /*
>>     * Update disk head position estimator based on IRQ completion info.
>>     */
>> @@ -1580,13 +1581,15 @@ static void raid_end_discard_bio(struct r10bio *r10bio)
>>    		if (!test_bit(R10BIO_Discard, &r10bio->state)) {
>>    			first_r10bio = (struct r10bio *)r10bio->master_bio;
>>    			free_r10bio(r10bio);
>>    			r10bio = first_r10bio;
>>    		} else {
>> +			struct bio *master_bio = r10bio->master_bio;
>> +
>>    			md_write_end(r10bio->mddev);
>> -			bio_endio(r10bio->master_bio);
>>    			free_r10bio(r10bio);
>> +			bio_endio(master_bio);
>>    			break;
>>    		}
>>    	}
>>    }
>>    
>
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.