Btrfs: raid56: fix race between merge_bio and rbio_orig_end_io
Before rbio_orig_end_io() goes to free rbio, rbio may get merged with more bios from other rbios and rbio->bio_list becomes non-empty, in that case, these newly merged bios don't end properly. Once unlock_stripe() is done, rbio->bio_list will not be updated any more and we can call bio_endio() on all queued bios. It should only happen in error-out cases, the normal path of recover and full stripe write have already set RBIO_RMW_LOCKED_BIT to disable merge before doing IO, so rbio_orig_end_io() called by them doesn't have the above issue. Reported-by: Jérôme Carretero <cJ-ko@zougloub.eu> Signed-off-by: Liu Bo <bo.li.liu@oracle.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
44ac474def
commit
7583d8d088
|
@ -864,10 +864,17 @@ static void __free_raid_bio(struct btrfs_raid_bio *rbio)
|
||||||
kfree(rbio);
|
kfree(rbio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_raid_bio(struct btrfs_raid_bio *rbio)
|
static void rbio_endio_bio_list(struct bio *cur, blk_status_t err)
|
||||||
{
|
{
|
||||||
unlock_stripe(rbio);
|
struct bio *next;
|
||||||
__free_raid_bio(rbio);
|
|
||||||
|
while (cur) {
|
||||||
|
next = cur->bi_next;
|
||||||
|
cur->bi_next = NULL;
|
||||||
|
cur->bi_status = err;
|
||||||
|
bio_endio(cur);
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -877,20 +884,26 @@ static void free_raid_bio(struct btrfs_raid_bio *rbio)
|
||||||
static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, blk_status_t err)
|
static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, blk_status_t err)
|
||||||
{
|
{
|
||||||
struct bio *cur = bio_list_get(&rbio->bio_list);
|
struct bio *cur = bio_list_get(&rbio->bio_list);
|
||||||
struct bio *next;
|
struct bio *extra;
|
||||||
|
|
||||||
if (rbio->generic_bio_cnt)
|
if (rbio->generic_bio_cnt)
|
||||||
btrfs_bio_counter_sub(rbio->fs_info, rbio->generic_bio_cnt);
|
btrfs_bio_counter_sub(rbio->fs_info, rbio->generic_bio_cnt);
|
||||||
|
|
||||||
free_raid_bio(rbio);
|
/*
|
||||||
|
* At this moment, rbio->bio_list is empty, however since rbio does not
|
||||||
|
* always have RBIO_RMW_LOCKED_BIT set and rbio is still linked on the
|
||||||
|
* hash list, rbio may be merged with others so that rbio->bio_list
|
||||||
|
* becomes non-empty.
|
||||||
|
* Once unlock_stripe() is done, rbio->bio_list will not be updated any
|
||||||
|
* more and we can call bio_endio() on all queued bios.
|
||||||
|
*/
|
||||||
|
unlock_stripe(rbio);
|
||||||
|
extra = bio_list_get(&rbio->bio_list);
|
||||||
|
__free_raid_bio(rbio);
|
||||||
|
|
||||||
while (cur) {
|
rbio_endio_bio_list(cur, err);
|
||||||
next = cur->bi_next;
|
if (extra)
|
||||||
cur->bi_next = NULL;
|
rbio_endio_bio_list(extra, err);
|
||||||
cur->bi_status = err;
|
|
||||||
bio_endio(cur);
|
|
||||||
cur = next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue