Skip to content

Commit 058e09e

Browse files
adam900710kdave
authored andcommitted
btrfs: scrub: introduce a writeback helper for scrub_stripe
Add a new helper, scrub_write_sectors(), to submit write bios for specified sectors to the target disk. There are several differences compared to read path: - Utilize btrfs_submit_scrub_write() Now we still rely on the @mirror_num based writeback, but the requirement is also a little different than regular writeback or read, thus we have to call btrfs_submit_scrub_write(). - We cannot write the full stripe back We can only write the sectors we have. There will be two call sites later, one for repaired sectors, one for all utilized sectors of dev-replace. Thus the callers should specify their own write_bitmap. This function only submit the bios, will not wait for them unless for zoned case. Caller must explicitly wait for the IO to finish. Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 9ecb5ef commit 058e09e

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

fs/btrfs/scrub.c

+93
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ struct scrub_stripe {
152152
unsigned long csum_error_bitmap;
153153
unsigned long meta_error_bitmap;
154154

155+
/* For writeback (repair or replace) error reporting. */
156+
unsigned long write_error_bitmap;
157+
158+
/* Writeback can be concurrent, thus we need to protect the bitmap. */
159+
spinlock_t write_error_lock;
160+
155161
/*
156162
* Checksum for the whole stripe if this stripe is inside a data block
157163
* group.
@@ -386,6 +392,7 @@ int init_scrub_stripe(struct btrfs_fs_info *fs_info, struct scrub_stripe *stripe
386392
init_waitqueue_head(&stripe->io_wait);
387393
init_waitqueue_head(&stripe->repair_wait);
388394
atomic_set(&stripe->pending_io, 0);
395+
spin_lock_init(&stripe->write_error_lock);
389396

390397
ret = btrfs_alloc_page_array(SCRUB_STRIPE_PAGES, stripe->pages);
391398
if (ret < 0)
@@ -2541,6 +2548,92 @@ void scrub_read_endio(struct btrfs_bio *bbio)
25412548
}
25422549
}
25432550

2551+
static void scrub_write_endio(struct btrfs_bio *bbio)
2552+
{
2553+
struct scrub_stripe *stripe = bbio->private;
2554+
struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
2555+
struct bio_vec *bvec;
2556+
int sector_nr = calc_sector_number(stripe, bio_first_bvec_all(&bbio->bio));
2557+
u32 bio_size = 0;
2558+
int i;
2559+
2560+
bio_for_each_bvec_all(bvec, &bbio->bio, i)
2561+
bio_size += bvec->bv_len;
2562+
2563+
if (bbio->bio.bi_status) {
2564+
unsigned long flags;
2565+
2566+
spin_lock_irqsave(&stripe->write_error_lock, flags);
2567+
bitmap_set(&stripe->write_error_bitmap, sector_nr,
2568+
bio_size >> fs_info->sectorsize_bits);
2569+
spin_unlock_irqrestore(&stripe->write_error_lock, flags);
2570+
}
2571+
bio_put(&bbio->bio);
2572+
2573+
if (atomic_dec_and_test(&stripe->pending_io))
2574+
wake_up(&stripe->io_wait);
2575+
}
2576+
2577+
/*
2578+
* Submit the write bio(s) for the sectors specified by @write_bitmap.
2579+
*
2580+
* Here we utilize btrfs_submit_repair_write(), which has some extra benefits:
2581+
*
2582+
* - Only needs logical bytenr and mirror_num
2583+
* Just like the scrub read path
2584+
*
2585+
* - Would only result in writes to the specified mirror
2586+
* Unlike the regular writeback path, which would write back to all stripes
2587+
*
2588+
* - Handle dev-replace and read-repair writeback differently
2589+
*/
2590+
void scrub_write_sectors(struct scrub_ctx *sctx, struct scrub_stripe *stripe,
2591+
unsigned long write_bitmap, bool dev_replace)
2592+
{
2593+
struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
2594+
struct btrfs_bio *bbio = NULL;
2595+
const bool zoned = btrfs_is_zoned(fs_info);
2596+
int sector_nr;
2597+
2598+
for_each_set_bit(sector_nr, &write_bitmap, stripe->nr_sectors) {
2599+
struct page *page = scrub_stripe_get_page(stripe, sector_nr);
2600+
unsigned int pgoff = scrub_stripe_get_page_offset(stripe, sector_nr);
2601+
int ret;
2602+
2603+
/* We should only writeback sectors covered by an extent. */
2604+
ASSERT(test_bit(sector_nr, &stripe->extent_sector_bitmap));
2605+
2606+
/* Cannot merge with previous sector, submit the current one. */
2607+
if (bbio && sector_nr && !test_bit(sector_nr - 1, &write_bitmap)) {
2608+
fill_writer_pointer_gap(sctx, stripe->physical +
2609+
(sector_nr << fs_info->sectorsize_bits));
2610+
atomic_inc(&stripe->pending_io);
2611+
btrfs_submit_repair_write(bbio, stripe->mirror_num, dev_replace);
2612+
/* For zoned writeback, queue depth must be 1. */
2613+
if (zoned)
2614+
wait_scrub_stripe_io(stripe);
2615+
bbio = NULL;
2616+
}
2617+
if (!bbio) {
2618+
bbio = btrfs_bio_alloc(stripe->nr_sectors, REQ_OP_WRITE,
2619+
fs_info, scrub_write_endio, stripe);
2620+
bbio->bio.bi_iter.bi_sector = (stripe->logical +
2621+
(sector_nr << fs_info->sectorsize_bits)) >>
2622+
SECTOR_SHIFT;
2623+
}
2624+
ret = bio_add_page(&bbio->bio, page, fs_info->sectorsize, pgoff);
2625+
ASSERT(ret == fs_info->sectorsize);
2626+
}
2627+
if (bbio) {
2628+
fill_writer_pointer_gap(sctx, bbio->bio.bi_iter.bi_sector <<
2629+
SECTOR_SHIFT);
2630+
atomic_inc(&stripe->pending_io);
2631+
btrfs_submit_repair_write(bbio, stripe->mirror_num, dev_replace);
2632+
if (zoned)
2633+
wait_scrub_stripe_io(stripe);
2634+
}
2635+
}
2636+
25442637
static int scrub_checksum_tree_block(struct scrub_block *sblock)
25452638
{
25462639
struct scrub_ctx *sctx = sblock->sctx;

fs/btrfs/scrub.h

+3
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,8 @@ int scrub_find_fill_first_stripe(struct btrfs_block_group *bg,
2424
int mirror_num, u64 logical_start,
2525
u32 logical_len, struct scrub_stripe *stripe);
2626
void scrub_read_endio(struct btrfs_bio *bbio);
27+
void scrub_write_sectors(struct scrub_ctx *sctx,
28+
struct scrub_stripe *stripe,
29+
unsigned long write_bitmap, bool dev_replace);
2730

2831
#endif

0 commit comments

Comments
 (0)