提交 f1c29379 编写于 作者: C Christoph Hellwig 提交者: David Sterba

btrfs: properly abstract the parity raid bio handling

The parity raid write/recover functionality is currently not very well
abstracted from the bio submission and completion handling in volumes.c:

 - the raid56 code directly completes the original btrfs_bio fed into
   btrfs_submit_bio instead of dispatching back to volumes.c
 - the raid56 code consumes the bioc and bio_counter references taken
   by volumes.c, which also leads to special casing of the calls from
   the scrub code into the raid56 code

To fix this up supply a bi_end_io handler that calls back into the
volumes.c machinery, which then puts the bioc, decrements the bio_counter
and completes the original bio, and updates the scrub code to also
take ownership of the bioc and bio_counter in all cases.
Reviewed-by: NNikolay Borisov <nborisov@suse.com>
Reviewed-by: NAnand Jain <anand.jain@oracle.com>
Tested-by: NNikolay Borisov <nborisov@suse.com>
Tested-by: NJohannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: NChristoph Hellwig <hch@lst.de>
Signed-off-by: NDavid Sterba <dsterba@suse.com>
上级 c3a62baf
...@@ -275,7 +275,6 @@ static void merge_rbio(struct btrfs_raid_bio *dest, ...@@ -275,7 +275,6 @@ static void merge_rbio(struct btrfs_raid_bio *dest,
/* Also inherit the bitmaps from @victim. */ /* Also inherit the bitmaps from @victim. */
bitmap_or(&dest->dbitmap, &victim->dbitmap, &dest->dbitmap, bitmap_or(&dest->dbitmap, &victim->dbitmap, &dest->dbitmap,
dest->stripe_nsectors); dest->stripe_nsectors);
dest->generic_bio_cnt += victim->generic_bio_cnt;
bio_list_init(&victim->bio_list); bio_list_init(&victim->bio_list);
} }
...@@ -814,8 +813,6 @@ static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, blk_status_t err) ...@@ -814,8 +813,6 @@ 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 *extra; struct bio *extra;
if (rbio->generic_bio_cnt)
btrfs_bio_counter_sub(rbio->bioc->fs_info, rbio->generic_bio_cnt);
/* /*
* Clear the data bitmap, as the rbio may be cached for later usage. * Clear the data bitmap, as the rbio may be cached for later usage.
* do this before before unlock_stripe() so there will be no new bio * do this before before unlock_stripe() so there will be no new bio
...@@ -946,6 +943,7 @@ static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info, ...@@ -946,6 +943,7 @@ static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info,
spin_lock_init(&rbio->bio_list_lock); spin_lock_init(&rbio->bio_list_lock);
INIT_LIST_HEAD(&rbio->stripe_cache); INIT_LIST_HEAD(&rbio->stripe_cache);
INIT_LIST_HEAD(&rbio->hash_list); INIT_LIST_HEAD(&rbio->hash_list);
btrfs_get_bioc(bioc);
rbio->bioc = bioc; rbio->bioc = bioc;
rbio->nr_pages = num_pages; rbio->nr_pages = num_pages;
rbio->nr_sectors = num_sectors; rbio->nr_sectors = num_sectors;
...@@ -1813,15 +1811,12 @@ void raid56_parity_write(struct bio *bio, struct btrfs_io_context *bioc) ...@@ -1813,15 +1811,12 @@ void raid56_parity_write(struct bio *bio, struct btrfs_io_context *bioc)
rbio = alloc_rbio(fs_info, bioc); rbio = alloc_rbio(fs_info, bioc);
if (IS_ERR(rbio)) { if (IS_ERR(rbio)) {
btrfs_put_bioc(bioc);
ret = PTR_ERR(rbio); ret = PTR_ERR(rbio);
goto out_dec_counter; goto fail;
} }
rbio->operation = BTRFS_RBIO_WRITE; rbio->operation = BTRFS_RBIO_WRITE;
rbio_add_bio(rbio, bio); rbio_add_bio(rbio, bio);
rbio->generic_bio_cnt = 1;
/* /*
* don't plug on full rbios, just get them out the door * don't plug on full rbios, just get them out the door
* as quickly as we can * as quickly as we can
...@@ -1829,7 +1824,7 @@ void raid56_parity_write(struct bio *bio, struct btrfs_io_context *bioc) ...@@ -1829,7 +1824,7 @@ void raid56_parity_write(struct bio *bio, struct btrfs_io_context *bioc)
if (rbio_is_full(rbio)) { if (rbio_is_full(rbio)) {
ret = full_stripe_write(rbio); ret = full_stripe_write(rbio);
if (ret) if (ret)
goto out_dec_counter; goto fail;
return; return;
} }
...@@ -1844,13 +1839,12 @@ void raid56_parity_write(struct bio *bio, struct btrfs_io_context *bioc) ...@@ -1844,13 +1839,12 @@ void raid56_parity_write(struct bio *bio, struct btrfs_io_context *bioc)
} else { } else {
ret = __raid56_parity_write(rbio); ret = __raid56_parity_write(rbio);
if (ret) if (ret)
goto out_dec_counter; goto fail;
} }
return; return;
out_dec_counter: fail:
btrfs_bio_counter_dec(fs_info);
bio->bi_status = errno_to_blk_status(ret); bio->bi_status = errno_to_blk_status(ret);
bio_endio(bio); bio_endio(bio);
} }
...@@ -2198,18 +2192,11 @@ static int __raid56_parity_recover(struct btrfs_raid_bio *rbio) ...@@ -2198,18 +2192,11 @@ static int __raid56_parity_recover(struct btrfs_raid_bio *rbio)
* of the drive. * of the drive.
*/ */
void raid56_parity_recover(struct bio *bio, struct btrfs_io_context *bioc, void raid56_parity_recover(struct bio *bio, struct btrfs_io_context *bioc,
int mirror_num, bool generic_io) int mirror_num)
{ {
struct btrfs_fs_info *fs_info = bioc->fs_info; struct btrfs_fs_info *fs_info = bioc->fs_info;
struct btrfs_raid_bio *rbio; struct btrfs_raid_bio *rbio;
if (generic_io) {
ASSERT(bioc->mirror_num == mirror_num);
btrfs_bio(bio)->mirror_num = mirror_num;
} else {
btrfs_get_bioc(bioc);
}
rbio = alloc_rbio(fs_info, bioc); rbio = alloc_rbio(fs_info, bioc);
if (IS_ERR(rbio)) { if (IS_ERR(rbio)) {
bio->bi_status = errno_to_blk_status(PTR_ERR(rbio)); bio->bi_status = errno_to_blk_status(PTR_ERR(rbio));
...@@ -2225,14 +2212,11 @@ void raid56_parity_recover(struct bio *bio, struct btrfs_io_context *bioc, ...@@ -2225,14 +2212,11 @@ void raid56_parity_recover(struct bio *bio, struct btrfs_io_context *bioc,
"%s could not find the bad stripe in raid56 so that we cannot recover any more (bio has logical %llu len %llu, bioc has map_type %llu)", "%s could not find the bad stripe in raid56 so that we cannot recover any more (bio has logical %llu len %llu, bioc has map_type %llu)",
__func__, bio->bi_iter.bi_sector << 9, __func__, bio->bi_iter.bi_sector << 9,
(u64)bio->bi_iter.bi_size, bioc->map_type); (u64)bio->bi_iter.bi_size, bioc->map_type);
kfree(rbio); __free_raid_bio(rbio);
bio->bi_status = BLK_STS_IOERR; bio->bi_status = BLK_STS_IOERR;
goto out_end_bio; goto out_end_bio;
} }
if (generic_io)
rbio->generic_bio_cnt = 1;
/* /*
* Loop retry: * Loop retry:
* for 'mirror == 2', reconstruct from all other stripes. * for 'mirror == 2', reconstruct from all other stripes.
...@@ -2261,8 +2245,6 @@ void raid56_parity_recover(struct bio *bio, struct btrfs_io_context *bioc, ...@@ -2261,8 +2245,6 @@ void raid56_parity_recover(struct bio *bio, struct btrfs_io_context *bioc,
return; return;
out_end_bio: out_end_bio:
btrfs_bio_counter_dec(fs_info);
btrfs_put_bioc(bioc);
bio_endio(bio); bio_endio(bio);
} }
...@@ -2326,13 +2308,6 @@ struct btrfs_raid_bio *raid56_parity_alloc_scrub_rbio(struct bio *bio, ...@@ -2326,13 +2308,6 @@ struct btrfs_raid_bio *raid56_parity_alloc_scrub_rbio(struct bio *bio,
ASSERT(i < rbio->real_stripes); ASSERT(i < rbio->real_stripes);
bitmap_copy(&rbio->dbitmap, dbitmap, stripe_nsectors); bitmap_copy(&rbio->dbitmap, dbitmap, stripe_nsectors);
/*
* We have already increased bio_counter when getting bioc, record it
* so we can free it at rbio_orig_end_io().
*/
rbio->generic_bio_cnt = 1;
return rbio; return rbio;
} }
...@@ -2772,12 +2747,6 @@ raid56_alloc_missing_rbio(struct bio *bio, struct btrfs_io_context *bioc) ...@@ -2772,12 +2747,6 @@ raid56_alloc_missing_rbio(struct bio *bio, struct btrfs_io_context *bioc)
return NULL; return NULL;
} }
/*
* When we get bioc, we have already increased bio_counter, record it
* so we can free it at rbio_orig_end_io()
*/
rbio->generic_bio_cnt = 1;
return rbio; return rbio;
} }
......
...@@ -89,8 +89,6 @@ struct btrfs_raid_bio { ...@@ -89,8 +89,6 @@ struct btrfs_raid_bio {
*/ */
int bio_list_bytes; int bio_list_bytes;
int generic_bio_cnt;
refcount_t refs; refcount_t refs;
atomic_t stripes_pending; atomic_t stripes_pending;
...@@ -166,7 +164,7 @@ static inline int nr_data_stripes(const struct map_lookup *map) ...@@ -166,7 +164,7 @@ static inline int nr_data_stripes(const struct map_lookup *map)
struct btrfs_device; struct btrfs_device;
void raid56_parity_recover(struct bio *bio, struct btrfs_io_context *bioc, void raid56_parity_recover(struct bio *bio, struct btrfs_io_context *bioc,
int mirror_num, bool generic_io); int mirror_num);
void raid56_parity_write(struct bio *bio, struct btrfs_io_context *bioc); void raid56_parity_write(struct bio *bio, struct btrfs_io_context *bioc);
void raid56_add_scrub_pages(struct btrfs_raid_bio *rbio, struct page *page, void raid56_add_scrub_pages(struct btrfs_raid_bio *rbio, struct page *page,
......
...@@ -1568,8 +1568,7 @@ static int scrub_submit_raid56_bio_wait(struct btrfs_fs_info *fs_info, ...@@ -1568,8 +1568,7 @@ static int scrub_submit_raid56_bio_wait(struct btrfs_fs_info *fs_info,
SECTOR_SHIFT; SECTOR_SHIFT;
bio->bi_private = &done; bio->bi_private = &done;
bio->bi_end_io = scrub_bio_wait_endio; bio->bi_end_io = scrub_bio_wait_endio;
raid56_parity_recover(bio, sector->recover->bioc, raid56_parity_recover(bio, sector->recover->bioc, sector->sblock->mirror_num);
sector->sblock->mirror_num, false);
wait_for_completion_io(&done); wait_for_completion_io(&done);
return blk_status_to_errno(bio->bi_status); return blk_status_to_errno(bio->bi_status);
...@@ -2285,6 +2284,7 @@ static void scrub_missing_raid56_end_io(struct bio *bio) ...@@ -2285,6 +2284,7 @@ static void scrub_missing_raid56_end_io(struct bio *bio)
struct scrub_block *sblock = bio->bi_private; struct scrub_block *sblock = bio->bi_private;
struct btrfs_fs_info *fs_info = sblock->sctx->fs_info; struct btrfs_fs_info *fs_info = sblock->sctx->fs_info;
btrfs_bio_counter_dec(fs_info);
if (bio->bi_status) if (bio->bi_status)
sblock->no_io_error_seen = 0; sblock->no_io_error_seen = 0;
...@@ -2385,6 +2385,7 @@ static void scrub_missing_raid56_pages(struct scrub_block *sblock) ...@@ -2385,6 +2385,7 @@ static void scrub_missing_raid56_pages(struct scrub_block *sblock)
scrub_block_get(sblock); scrub_block_get(sblock);
scrub_pending_bio_inc(sctx); scrub_pending_bio_inc(sctx);
raid56_submit_missing_rbio(rbio); raid56_submit_missing_rbio(rbio);
btrfs_put_bioc(bioc);
return; return;
rbio_out: rbio_out:
...@@ -2924,6 +2925,7 @@ static void scrub_parity_bio_endio_worker(struct work_struct *work) ...@@ -2924,6 +2925,7 @@ static void scrub_parity_bio_endio_worker(struct work_struct *work)
work); work);
struct scrub_ctx *sctx = sparity->sctx; struct scrub_ctx *sctx = sparity->sctx;
btrfs_bio_counter_dec(sctx->fs_info);
scrub_free_parity(sparity); scrub_free_parity(sparity);
scrub_pending_bio_dec(sctx); scrub_pending_bio_dec(sctx);
} }
...@@ -2974,6 +2976,7 @@ static void scrub_parity_check_and_repair(struct scrub_parity *sparity) ...@@ -2974,6 +2976,7 @@ static void scrub_parity_check_and_repair(struct scrub_parity *sparity)
sparity->scrub_dev, sparity->scrub_dev,
&sparity->dbitmap, &sparity->dbitmap,
sparity->nsectors); sparity->nsectors);
btrfs_put_bioc(bioc);
if (!rbio) if (!rbio)
goto rbio_out; goto rbio_out;
...@@ -2985,7 +2988,6 @@ static void scrub_parity_check_and_repair(struct scrub_parity *sparity) ...@@ -2985,7 +2988,6 @@ static void scrub_parity_check_and_repair(struct scrub_parity *sparity)
bio_put(bio); bio_put(bio);
bioc_out: bioc_out:
btrfs_bio_counter_dec(fs_info); btrfs_bio_counter_dec(fs_info);
btrfs_put_bioc(bioc);
bitmap_or(&sparity->ebitmap, &sparity->ebitmap, &sparity->dbitmap, bitmap_or(&sparity->ebitmap, &sparity->ebitmap, &sparity->dbitmap,
sparity->nsectors); sparity->nsectors);
spin_lock(&sctx->stat_lock); spin_lock(&sctx->stat_lock);
......
...@@ -6684,6 +6684,20 @@ static void btrfs_end_bio_work(struct work_struct *work) ...@@ -6684,6 +6684,20 @@ static void btrfs_end_bio_work(struct work_struct *work)
bio_endio(&bbio->bio); bio_endio(&bbio->bio);
} }
static void btrfs_raid56_end_io(struct bio *bio)
{
struct btrfs_io_context *bioc = bio->bi_private;
struct btrfs_bio *bbio = btrfs_bio(bio);
btrfs_bio_counter_dec(bioc->fs_info);
bbio->mirror_num = bioc->mirror_num;
bio->bi_end_io = bioc->end_io;
bio->bi_private = bioc->private;
bio->bi_end_io(bio);
btrfs_put_bioc(bioc);
}
static void btrfs_end_bio(struct bio *bio) static void btrfs_end_bio(struct bio *bio)
{ {
struct btrfs_io_stripe *stripe = bio->bi_private; struct btrfs_io_stripe *stripe = bio->bi_private;
...@@ -6817,10 +6831,12 @@ void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror ...@@ -6817,10 +6831,12 @@ void btrfs_submit_bio(struct btrfs_fs_info *fs_info, struct bio *bio, int mirror
if ((bioc->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK) && if ((bioc->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK) &&
((btrfs_op(bio) == BTRFS_MAP_WRITE) || (mirror_num > 1))) { ((btrfs_op(bio) == BTRFS_MAP_WRITE) || (mirror_num > 1))) {
bio->bi_private = bioc;
bio->bi_end_io = btrfs_raid56_end_io;
if (btrfs_op(bio) == BTRFS_MAP_WRITE) if (btrfs_op(bio) == BTRFS_MAP_WRITE)
raid56_parity_write(bio, bioc); raid56_parity_write(bio, bioc);
else else
raid56_parity_recover(bio, bioc, mirror_num, true); raid56_parity_recover(bio, bioc, mirror_num);
return; return;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册