/* * This is only the first step towards a full-features scrub. It reads all * extent and super block and verifies the checksums. In case a bad checksum * is found or the extent cannot be read, good data will be written back if * any can be found. * * Future enhancements: * - In case an unrepairable extent is encountered, track which files are * affected and report them * - track and record media errors, throw out bad devices * - add a mode to also read unallocated space
*/
struct scrub_ctx;
/* * The following value only influences the performance. * * This determines how many stripes would be submitted in one go, * which is 512KiB (BTRFS_STRIPE_LEN * SCRUB_STRIPES_PER_GROUP).
*/ #define SCRUB_STRIPES_PER_GROUP 8
/* * How many groups we have for each sctx. * * This would be 8M per device, the same value as the old scrub in-flight bios * size limit.
*/ #define SCRUB_GROUPS_PER_SCTX 16
/* * The following value times PAGE_SIZE needs to be large enough to match the * largest node/leaf/sector size that shall be supported.
*/ #define SCRUB_MAX_SECTORS_PER_BLOCK (BTRFS_MAX_METADATA_BLOCKSIZE / SZ_4K)
/* Represent one sector and its needed info to verify the content. */ struct scrub_sector_verification { union { /* * Csum pointer for data csum verification. Should point to a * sector csum inside scrub_stripe::csums. * * NULL if this data sector has no csum.
*/
u8 *csum;
/* * Extra info for metadata verification. All sectors inside a * tree block share the same generation.
*/
u64 generation;
};
};
enum scrub_stripe_flags { /* Set when @mirror_num, @dev, @physical and @logical are set. */
SCRUB_STRIPE_FLAG_INITIALIZED,
/* Set when the read-repair is finished. */
SCRUB_STRIPE_FLAG_REPAIR_DONE,
/* * Set for data stripes if it's triggered from P/Q stripe. * During such scrub, we should not report errors in data stripes, nor * update the accounting.
*/
SCRUB_STRIPE_FLAG_NO_REPORT,
};
/* * We have multiple bitmaps for one scrub_stripe. * However each bitmap has at most (BTRFS_STRIPE_LEN / blocksize) bits, * which is normally 16, and much smaller than BITS_PER_LONG (32 or 64). * * So to reduce memory usage for each scrub_stripe, we pack those bitmaps * into a larger one. * * These enum records where the sub-bitmap are inside the larger one. * Each subbitmap starts at scrub_bitmap_nr_##name * nr_sectors bit.
*/ enum { /* Which blocks are covered by extent items. */
scrub_bitmap_nr_has_extent = 0,
/* Which blocks are meteadata. */
scrub_bitmap_nr_is_metadata,
/* * Which blocks have errors, including IO, csum, and metadata * errors. * This sub-bitmap is the OR results of the next few error related * sub-bitmaps.
*/
scrub_bitmap_nr_error,
scrub_bitmap_nr_io_error,
scrub_bitmap_nr_csum_error,
scrub_bitmap_nr_meta_error,
scrub_bitmap_nr_meta_gen_error,
scrub_bitmap_nr_last,
};
/* * Indicate the states of the stripe. Bits are defined in * scrub_stripe_flags enum.
*/ unsignedlong state;
/* The large bitmap contains all the sub-bitmaps. */ unsignedlong bitmaps[BITS_TO_LONGS(scrub_bitmap_nr_last *
(BTRFS_STRIPE_LEN / BTRFS_MIN_BLOCKSIZE))];
/* * For writeback (repair or replace) error reporting. * This one is protected by a spinlock, thus can not be packed into * the larger bitmap.
*/ unsignedlong write_error_bitmap;
/* Writeback can be concurrent, thus we need to protect the bitmap. */
spinlock_t write_error_lock;
/* * Checksum for the whole stripe if this stripe is inside a data block * group.
*/
u8 *csums;
struct work_struct work;
};
struct scrub_ctx { struct scrub_stripe stripes[SCRUB_TOTAL_STRIPES]; struct scrub_stripe *raid56_data_stripes; struct btrfs_fs_info *fs_info; struct btrfs_path extent_path; struct btrfs_path csum_path; int first_free; int cur_stripe;
atomic_t cancel_req; int readonly;
/* State of IO submission throttling affecting the associated device */
ktime_t throttle_deadline;
u64 throttle_sent;
/* * Use a ref counter to avoid use-after-free issues. Scrub workers * decrement bios_in_flight and workers_pending and then do a wakeup * on the list_wait wait queue. We must ensure the main scrub task * doesn't free the scrub context before or while the workers are * doing the wakeup() call.
*/
refcount_t refs;
};
/* * init_path might indirectly call vmalloc, or use GFP_KERNEL. Scrub * uses GFP_NOFS in this context, so we keep it consistent but it does * not seem to be strictly necessary.
*/
nofs_flag = memalloc_nofs_save();
ipath = init_ipath(4096, local_root, swarn->path);
memalloc_nofs_restore(nofs_flag); if (IS_ERR(ipath)) {
btrfs_put_root(local_root);
ret = PTR_ERR(ipath);
ipath = NULL; goto err;
}
ret = paths_from_inode(inum, ipath);
if (ret < 0) goto err;
/* * we deliberately ignore the bit ipath might have been too small to * hold all of the paths here
*/ for (i = 0; i < ipath->fspath->elem_cnt; ++i)
btrfs_warn(fs_info, "scrub: %s at logical %llu on dev %s, physical %llu root %llu inode %llu offset %llu length %u links %u (path: %s)",
swarn->errstr, swarn->logical,
btrfs_dev_name(swarn->dev),
swarn->physical,
root, inum, offset,
fs_info->sectorsize, nlink,
(char *)(unsignedlong)ipath->fspath->val[i]);
/* Super block error, no need to search extent tree. */ if (is_super) {
btrfs_warn(fs_info, "scrub: %s on device %s, physical %llu",
errstr, btrfs_dev_name(dev), physical); return;
}
path = btrfs_alloc_path(); if (!path) return;
/* stripe->pages[] is allocated by us and no highmem is allowed. */
ASSERT(page);
ASSERT(!PageHighMem(page)); return page_address(page) + offset_in_page(offset);
}
/* * Here we don't have a good way to attach the pages (and subpages) * to a dummy extent buffer, thus we have to directly grab the members * from pages.
*/
memcpy(on_disk_csum, header->csum, fs_info->csum_size);
if (logical != btrfs_stack_header_bytenr(header)) {
scrub_bitmap_set_meta_error(stripe, sector_nr, sectors_per_tree);
scrub_bitmap_set_error(stripe, sector_nr, sectors_per_tree);
btrfs_warn_rl(fs_info, "scrub: tree block %llu mirror %u has bad bytenr, has %llu want %llu",
logical, stripe->mirror_num,
btrfs_stack_header_bytenr(header), logical); return;
} if (memcmp(header->fsid, fs_info->fs_devices->metadata_uuid,
BTRFS_FSID_SIZE) != 0) {
scrub_bitmap_set_meta_error(stripe, sector_nr, sectors_per_tree);
scrub_bitmap_set_error(stripe, sector_nr, sectors_per_tree);
btrfs_warn_rl(fs_info, "scrub: tree block %llu mirror %u has bad fsid, has %pU want %pU",
logical, stripe->mirror_num,
header->fsid, fs_info->fs_devices->fsid); return;
} if (memcmp(header->chunk_tree_uuid, fs_info->chunk_tree_uuid,
BTRFS_UUID_SIZE) != 0) {
scrub_bitmap_set_meta_error(stripe, sector_nr, sectors_per_tree);
scrub_bitmap_set_error(stripe, sector_nr, sectors_per_tree);
btrfs_warn_rl(fs_info, "scrub: tree block %llu mirror %u has bad chunk tree uuid, has %pU want %pU",
logical, stripe->mirror_num,
header->chunk_tree_uuid, fs_info->chunk_tree_uuid); return;
}
/* Now check tree block csum. */
shash->tfm = fs_info->csum_shash;
crypto_shash_init(shash);
crypto_shash_update(shash, first_kaddr + BTRFS_CSUM_SIZE,
fs_info->sectorsize - BTRFS_CSUM_SIZE);
for (int i = sector_nr + 1; i < sector_nr + sectors_per_tree; i++) {
crypto_shash_update(shash, scrub_stripe_get_kaddr(stripe, i),
fs_info->sectorsize);
}
crypto_shash_final(shash, calculated_csum); if (memcmp(calculated_csum, on_disk_csum, fs_info->csum_size) != 0) {
scrub_bitmap_set_meta_error(stripe, sector_nr, sectors_per_tree);
scrub_bitmap_set_error(stripe, sector_nr, sectors_per_tree);
btrfs_warn_rl(fs_info, "scrub: tree block %llu mirror %u has bad csum, has " CSUM_FMT " want " CSUM_FMT,
logical, stripe->mirror_num,
CSUM_FMT_VALUE(fs_info->csum_size, on_disk_csum),
CSUM_FMT_VALUE(fs_info->csum_size, calculated_csum)); return;
} if (stripe->sectors[sector_nr].generation !=
btrfs_stack_header_generation(header)) {
scrub_bitmap_set_meta_gen_error(stripe, sector_nr, sectors_per_tree);
scrub_bitmap_set_error(stripe, sector_nr, sectors_per_tree);
btrfs_warn_rl(fs_info, "scrub: tree block %llu mirror %u has bad generation, has %llu want %llu",
logical, stripe->mirror_num,
btrfs_stack_header_generation(header),
stripe->sectors[sector_nr].generation); return;
}
scrub_bitmap_clear_error(stripe, sector_nr, sectors_per_tree);
scrub_bitmap_clear_csum_error(stripe, sector_nr, sectors_per_tree);
scrub_bitmap_clear_meta_error(stripe, sector_nr, sectors_per_tree);
scrub_bitmap_clear_meta_gen_error(stripe, sector_nr, sectors_per_tree);
}
/* Sector not utilized, skip it. */ if (!scrub_bitmap_test_bit_has_extent(stripe, sector_nr)) return;
/* IO error, no need to check. */ if (scrub_bitmap_test_bit_io_error(stripe, sector_nr)) return;
/* Metadata, verify the full tree block. */ if (scrub_bitmap_test_bit_is_metadata(stripe, sector_nr)) { /* * Check if the tree block crosses the stripe boundary. If * crossed the boundary, we cannot verify it but only give a * warning. * * This can only happen on a very old filesystem where chunks * are not ensured to be stripe aligned.
*/ if (unlikely(sector_nr + sectors_per_tree > stripe->nr_sectors)) {
btrfs_warn_rl(fs_info, "scrub: tree block at %llu crosses stripe boundary %llu",
stripe->logical +
(sector_nr << fs_info->sectorsize_bits),
stripe->logical); return;
}
scrub_verify_one_metadata(stripe, sector_nr); return;
}
/* * Data is easier, we just verify the data csum (if we have it). For * cases without csum, we have no other choice but to trust it.
*/ if (!sector->csum) {
scrub_bitmap_clear_bit_error(stripe, sector_nr); return;
}
staticint calc_sector_number(struct scrub_stripe *stripe, struct bio_vec *first_bvec)
{ int i;
for (i = 0; i < stripe->nr_sectors; i++) { if (scrub_stripe_get_kaddr(stripe, i) == bvec_virt(first_bvec)) break;
}
ASSERT(i < stripe->nr_sectors); return i;
}
/* * Repair read is different to the regular read: * * - Only reads the failed sectors * - May have extra blocksize limits
*/ staticvoid scrub_repair_read_endio(struct btrfs_bio *bbio)
{ struct scrub_stripe *stripe = bbio->private; struct btrfs_fs_info *fs_info = stripe->bg->fs_info; struct bio_vec *bvec; int sector_nr = calc_sector_number(stripe, bio_first_bvec_all(&bbio->bio));
u32 bio_size = 0; int i;
staticvoid scrub_bio_add_sector(struct btrfs_bio *bbio, struct scrub_stripe *stripe, int sector_nr)
{ void *kaddr = scrub_stripe_get_kaddr(stripe, sector_nr); int ret;
ret = bio_add_page(&bbio->bio, virt_to_page(kaddr), bbio->fs_info->sectorsize,
offset_in_page(kaddr)); /* * Caller should ensure the bbio has enough size. * And we cannot use __bio_add_page(), which doesn't do any merge. * * Meanwhile for scrub_submit_initial_read() we fully rely on the merge * to create the minimal amount of bio vectors, for fs block size < page * size cases.
*/
ASSERT(ret == bbio->fs_info->sectorsize);
}
staticvoid scrub_stripe_submit_repair_read(struct scrub_stripe *stripe, int mirror, int blocksize, bool wait)
{ struct btrfs_fs_info *fs_info = stripe->bg->fs_info; struct btrfs_bio *bbio = NULL; constunsignedlong old_error_bitmap = scrub_bitmap_read_error(stripe); int i;
if (test_bit(SCRUB_STRIPE_FLAG_NO_REPORT, &stripe->state)) return;
/* * Init needed infos for error reporting. * * Although our scrub_stripe infrastructure is mostly based on btrfs_submit_bio() * thus no need for dev/physical, error reporting still needs dev and physical.
*/ if (!bitmap_empty(&errors->init_error_bitmap, stripe->nr_sectors)) {
u64 mapped_len = fs_info->sectorsize; struct btrfs_io_context *bioc = NULL; int stripe_index = stripe->mirror_num - 1; int ret;
/* For scrub, our mirror_num should always start at 1. */
ASSERT(stripe->mirror_num >= 1);
ret = btrfs_map_block(fs_info, BTRFS_MAP_GET_READ_MIRRORS,
stripe->logical, &mapped_len, &bioc,
NULL, NULL); /* * If we failed, dev will be NULL, and later detailed reports * will just be skipped.
*/ if (ret < 0) goto skip;
physical = bioc->stripes[stripe_index].physical;
dev = bioc->stripes[stripe_index].dev;
btrfs_put_bioc(bioc);
}
/* Good sector from the beginning, nothing need to be done. */ if (!test_bit(sector_nr, &errors->init_error_bitmap)) continue;
/* * Report error for the corrupted sectors. If repaired, just * output the message of repaired message.
*/ if (repaired) { if (dev) {
btrfs_err_rl(fs_info, "scrub: fixed up error at logical %llu on dev %s physical %llu",
stripe->logical, btrfs_dev_name(dev),
physical);
} else {
btrfs_err_rl(fs_info, "scrub: fixed up error at logical %llu on mirror %u",
stripe->logical, stripe->mirror_num);
} continue;
}
/* The remaining are all for unrepaired. */ if (dev) {
btrfs_err_rl(fs_info, "scrub: unable to fixup (regular) error at logical %llu on dev %s physical %llu",
stripe->logical, btrfs_dev_name(dev),
physical);
} else {
btrfs_err_rl(fs_info, "scrub: unable to fixup (regular) error at logical %llu on mirror %u",
stripe->logical, stripe->mirror_num);
}
if (scrub_bitmap_test_bit_io_error(stripe, sector_nr)) if (__ratelimit(&rs) && dev)
scrub_print_common_warning("i/o error", dev, false,
stripe->logical, physical); if (scrub_bitmap_test_bit_csum_error(stripe, sector_nr)) if (__ratelimit(&rs) && dev)
scrub_print_common_warning("checksum error", dev, false,
stripe->logical, physical); if (scrub_bitmap_test_bit_meta_error(stripe, sector_nr)) if (__ratelimit(&rs) && dev)
scrub_print_common_warning("header error", dev, false,
stripe->logical, physical); if (scrub_bitmap_test_bit_meta_gen_error(stripe, sector_nr)) if (__ratelimit(&rs) && dev)
scrub_print_common_warning("generation error", dev, false,
stripe->logical, physical);
}
/* Update the device stats. */ for (int i = 0; i < errors->nr_io_errors; i++)
btrfs_dev_stat_inc_and_print(stripe->dev, BTRFS_DEV_STAT_READ_ERRS); for (int i = 0; i < errors->nr_csum_errors; i++)
btrfs_dev_stat_inc_and_print(stripe->dev, BTRFS_DEV_STAT_CORRUPTION_ERRS); /* Generation mismatch error is based on each metadata, not each block. */ for (int i = 0; i < errors->nr_meta_gen_errors;
i += (fs_info->nodesize >> fs_info->sectorsize_bits))
btrfs_dev_stat_inc_and_print(stripe->dev, BTRFS_DEV_STAT_GENERATION_ERRS);
/* * The main entrance for all read related scrub work, including: * * - Wait for the initial read to finish * - Verify and locate any bad sectors * - Go through the remaining mirrors and try to read as large blocksize as * possible * - Go through all mirrors (including the failed mirror) sector-by-sector * - Submit writeback for repaired sectors * * Writeback for dev-replace does not happen here, it needs extra * synchronization for zoned devices.
*/ staticvoid scrub_stripe_read_repair_worker(struct work_struct *work)
{ struct scrub_stripe *stripe = container_of(work, struct scrub_stripe, work); struct scrub_ctx *sctx = stripe->sctx; struct btrfs_fs_info *fs_info = sctx->fs_info; struct scrub_error_records errors = { 0 }; int num_copies = btrfs_num_copies(fs_info, stripe->bg->start,
stripe->bg->length); unsignedlong repaired; unsignedlong error; int mirror; int i;
ASSERT(stripe->mirror_num > 0);
wait_scrub_stripe_io(stripe);
scrub_verify_one_stripe(stripe, scrub_bitmap_read_has_extent(stripe)); /* Save the initial failed bitmap for later repair and report usage. */
errors.init_error_bitmap = scrub_bitmap_read_error(stripe);
errors.nr_io_errors = scrub_bitmap_weight_io_error(stripe);
errors.nr_csum_errors = scrub_bitmap_weight_csum_error(stripe);
errors.nr_meta_errors = scrub_bitmap_weight_meta_error(stripe);
errors.nr_meta_gen_errors = scrub_bitmap_weight_meta_gen_error(stripe);
if (bitmap_empty(&errors.init_error_bitmap, stripe->nr_sectors)) goto out;
/* * Try all remaining mirrors. * * Here we still try to read as large block as possible, as this is * faster and we have extra safety nets to rely on.
*/ for (mirror = calc_next_mirror(stripe->mirror_num, num_copies);
mirror != stripe->mirror_num;
mirror = calc_next_mirror(mirror, num_copies)) { constunsignedlong old_error_bitmap = scrub_bitmap_read_error(stripe);
/* * Last safety net, try re-checking all mirrors, including the failed * one, sector-by-sector. * * As if one sector failed the drive's internal csum, the whole read * containing the offending sector would be marked as error. * Thus here we do sector-by-sector read. * * This can be slow, thus we only try it as the last resort.
*/
for (i = 0, mirror = stripe->mirror_num;
i < num_copies;
i++, mirror = calc_next_mirror(mirror, num_copies)) { constunsignedlong old_error_bitmap = scrub_bitmap_read_error(stripe);
scrub_stripe_submit_repair_read(stripe, mirror,
fs_info->sectorsize, true);
wait_scrub_stripe_io(stripe);
scrub_verify_one_stripe(stripe, old_error_bitmap); if (scrub_bitmap_empty_error(stripe)) goto out;
}
out:
error = scrub_bitmap_read_error(stripe); /* * Submit the repaired sectors. For zoned case, we cannot do repair * in-place, but queue the bg to be relocated.
*/
bitmap_andnot(&repaired, &errors.init_error_bitmap, &error,
stripe->nr_sectors); if (!sctx->readonly && !bitmap_empty(&repaired, stripe->nr_sectors)) { if (btrfs_is_zoned(fs_info)) {
btrfs_repair_one_zone(fs_info, sctx->stripes[0].bg->start);
} else {
scrub_write_sectors(sctx, stripe, repaired, false);
wait_scrub_stripe_io(stripe);
}
}
fill_writer_pointer_gap(sctx, stripe->physical + bio_off);
atomic_inc(&stripe->pending_io);
btrfs_submit_repair_write(bbio, stripe->mirror_num, dev_replace); if (!btrfs_is_zoned(fs_info)) return; /* * For zoned writeback, queue depth must be 1, thus we must wait for * the write to finish before the next write.
*/
wait_scrub_stripe_io(stripe);
/* * And also need to update the write pointer if write finished * successfully.
*/ if (!test_bit(bio_off >> fs_info->sectorsize_bits,
&stripe->write_error_bitmap))
sctx->write_pointer += bio_len;
}
/* * Submit the write bio(s) for the sectors specified by @write_bitmap. * * Here we utilize btrfs_submit_repair_write(), which has some extra benefits: * * - Only needs logical bytenr and mirror_num * Just like the scrub read path * * - Would only result in writes to the specified mirror * Unlike the regular writeback path, which would write back to all stripes * * - Handle dev-replace and read-repair writeback differently
*/ staticvoid scrub_write_sectors(struct scrub_ctx *sctx, struct scrub_stripe *stripe, unsignedlong write_bitmap, bool dev_replace)
{ struct btrfs_fs_info *fs_info = stripe->bg->fs_info; struct btrfs_bio *bbio = NULL; int sector_nr;
for_each_set_bit(sector_nr, &write_bitmap, stripe->nr_sectors) { /* We should only writeback sectors covered by an extent. */
ASSERT(scrub_bitmap_test_bit_has_extent(stripe, sector_nr));
/* Cannot merge with previous sector, submit the current one. */ if (bbio && sector_nr && !test_bit(sector_nr - 1, &write_bitmap)) {
scrub_submit_write_bio(sctx, stripe, bbio, dev_replace);
bbio = NULL;
} if (!bbio) {
bbio = btrfs_bio_alloc(stripe->nr_sectors, REQ_OP_WRITE,
fs_info, scrub_write_endio, stripe);
bbio->bio.bi_iter.bi_sector = (stripe->logical +
(sector_nr << fs_info->sectorsize_bits)) >>
SECTOR_SHIFT;
}
scrub_bio_add_sector(bbio, stripe, sector_nr);
} if (bbio)
scrub_submit_write_bio(sctx, stripe, bbio, dev_replace);
}
/* * Throttling of IO submission, bandwidth-limit based, the timeslice is 1 * second. Limit can be set via /sys/fs/UUID/devinfo/devid/scrub_speed_max.
*/ staticvoid scrub_throttle_dev_io(struct scrub_ctx *sctx, struct btrfs_device *device, unsignedint bio_size)
{ constint time_slice = 1000;
s64 delta;
ktime_t now;
u32 div;
u64 bwlimit;
bwlimit = READ_ONCE(device->scrub_speed_max); if (bwlimit == 0) return;
/* * Slice is divided into intervals when the IO is submitted, adjust by * bwlimit and maximum of 64 intervals.
*/
div = clamp(bwlimit / (16 * 1024 * 1024), 1, 64);
/* Start new epoch, set deadline */
now = ktime_get(); if (sctx->throttle_deadline == 0) {
sctx->throttle_deadline = ktime_add_ms(now, time_slice / div);
sctx->throttle_sent = 0;
}
/* Still in the time to send? */ if (ktime_before(now, sctx->throttle_deadline)) { /* If current bio is within the limit, send it */
sctx->throttle_sent += bio_size; if (sctx->throttle_sent <= div_u64(bwlimit, div)) return;
/* We're over the limit, sleep until the rest of the slice */
delta = ktime_ms_delta(sctx->throttle_deadline, now);
} else { /* New request after deadline, start new epoch */
delta = 0;
}
/* Next call will start the deadline period */
sctx->throttle_deadline = 0;
}
/* * Given a physical address, this will calculate it's * logical offset. if this is a parity stripe, it will return * the most left data stripe's logical offset. * * return 0 if it is a data stripe, 1 means parity stripe.
*/ staticint get_raid56_logic_offset(u64 physical, int num, struct btrfs_chunk_map *map, u64 *offset,
u64 *stripe_start)
{ int i; int j = 0;
u64 last_offset; constint data_stripes = nr_data_stripes(map);
/* Work out the disk rotation on this stripe-set */
rot = stripe_nr % map->num_stripes; /* calculate which stripe this data locates */
rot += i;
stripe_index = rot % map->num_stripes; if (stripe_index == num) return 0; if (stripe_index < num)
j++;
}
*offset = last_offset + btrfs_stripe_nr_to_offset(j); return 1;
}
/* * Return 0 if the extent item range covers any byte of the range. * Return <0 if the extent item is before @search_start. * Return >0 if the extent item is after @start_start + @search_len.
*/ staticint compare_extent_item_range(struct btrfs_path *path,
u64 search_start, u64 search_len)
{ struct btrfs_fs_info *fs_info = path->nodes[0]->fs_info;
u64 len; struct btrfs_key key;
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
ASSERT(key.type == BTRFS_EXTENT_ITEM_KEY ||
key.type == BTRFS_METADATA_ITEM_KEY); if (key.type == BTRFS_METADATA_ITEM_KEY)
len = fs_info->nodesize; else
len = key.offset;
if (key.objectid + len <= search_start) return -1; if (key.objectid >= search_start + search_len) return 1; return 0;
}
/* * Locate one extent item which covers any byte in range * [@search_start, @search_start + @search_length) * * If the path is not initialized, we will initialize the search by doing * a btrfs_search_slot(). * If the path is already initialized, we will use the path as the initial * slot, to avoid duplicated btrfs_search_slot() calls. * * NOTE: If an extent item starts before @search_start, we will still * return the extent item. This is for data extent crossing stripe boundary. * * Return 0 if we found such extent item, and @path will point to the extent item. * Return >0 if no such extent item can be found, and @path will be released. * Return <0 if hit fatal error, and @path will be released.
*/ staticint find_first_extent_item(struct btrfs_root *extent_root, struct btrfs_path *path,
u64 search_start, u64 search_len)
{ struct btrfs_fs_info *fs_info = extent_root->fs_info; struct btrfs_key key; int ret;
/* Continue using the existing path */ if (path->nodes[0]) goto search_forward;
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0); if (ret < 0) return ret; if (ret == 0) { /* * Key with offset -1 found, there would have to exist an extent * item with such offset, but this is out of the valid range.
*/
btrfs_release_path(path); return -EUCLEAN;
}
/* * Here we intentionally pass 0 as @min_objectid, as there could be * an extent item starting before @search_start.
*/
ret = btrfs_previous_extent_item(extent_root, path, 0); if (ret < 0) return ret; /* * No matter whether we have found an extent item, the next loop will * properly do every check on the key.
*/
search_forward: while (true) {
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); if (key.objectid >= search_start + search_len) break; if (key.type != BTRFS_METADATA_ITEM_KEY &&
key.type != BTRFS_EXTENT_ITEM_KEY) goto next;
ret = compare_extent_item_range(path, search_start, search_len); if (ret == 0) return ret; if (ret > 0) break;
next:
ret = btrfs_next_item(extent_root, path); if (ret) { /* Either no more items or a fatal error. */
btrfs_release_path(path); return ret;
}
}
btrfs_release_path(path); return 1;
}
/* * Locate one stripe which has at least one extent in its range. * * Return 0 if found such stripe, and store its info into @stripe. * Return >0 if there is no such stripe in the specified range. * Return <0 for error.
*/ staticint scrub_find_fill_first_stripe(struct btrfs_block_group *bg, struct btrfs_path *extent_path, struct btrfs_path *csum_path, struct btrfs_device *dev, u64 physical, int mirror_num, u64 logical_start,
u32 logical_len, struct scrub_stripe *stripe)
{ struct btrfs_fs_info *fs_info = bg->fs_info; struct btrfs_root *extent_root = btrfs_extent_root(fs_info, bg->start); struct btrfs_root *csum_root = btrfs_csum_root(fs_info, bg->start); const u64 logical_end = logical_start + logical_len;
u64 cur_logical = logical_start;
u64 stripe_end;
u64 extent_start;
u64 extent_len;
u64 extent_flags;
u64 extent_gen; int ret;
if (unlikely(!extent_root || !csum_root)) {
btrfs_err(fs_info, "scrub: no valid extent or csum root found"); return -EUCLEAN;
}
memset(stripe->sectors, 0, sizeof(struct scrub_sector_verification) *
stripe->nr_sectors);
scrub_stripe_reset_bitmaps(stripe);
/* The range must be inside the bg. */
ASSERT(logical_start >= bg->start && logical_end <= bg->start + bg->length);
ret = find_first_extent_item(extent_root, extent_path, logical_start,
logical_len); /* Either error or not found. */ if (ret) goto out;
get_extent_info(extent_path, &extent_start, &extent_len, &extent_flags,
&extent_gen); if (extent_flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)
stripe->nr_meta_extents++; if (extent_flags & BTRFS_EXTENT_FLAG_DATA)
stripe->nr_data_extents++;
cur_logical = max(extent_start, cur_logical);
/* * Round down to stripe boundary. * * The extra calculation against bg->start is to handle block groups * whose logical bytenr is not BTRFS_STRIPE_LEN aligned.
*/
stripe->logical = round_down(cur_logical - bg->start, BTRFS_STRIPE_LEN) +
bg->start;
stripe->physical = physical + stripe->logical - logical_start;
stripe->dev = dev;
stripe->bg = bg;
stripe->mirror_num = mirror_num;
stripe_end = stripe->logical + BTRFS_STRIPE_LEN - 1;
/* Fill the first extent info into stripe->sectors[] array. */
fill_one_extent_info(fs_info, stripe, extent_start, extent_len,
extent_flags, extent_gen);
cur_logical = extent_start + extent_len;
/* Fill the extent info for the remaining sectors. */ while (cur_logical <= stripe_end) {
ret = find_first_extent_item(extent_root, extent_path, cur_logical,
stripe_end - cur_logical + 1); if (ret < 0) goto out; if (ret > 0) {
ret = 0; break;
}
get_extent_info(extent_path, &extent_start, &extent_len,
&extent_flags, &extent_gen); if (extent_flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)
stripe->nr_meta_extents++; if (extent_flags & BTRFS_EXTENT_FLAG_DATA)
stripe->nr_data_extents++;
fill_one_extent_info(fs_info, stripe, extent_start, extent_len,
extent_flags, extent_gen);
cur_logical = extent_start + extent_len;
}
/* Now fill the data csum. */ if (bg->flags & BTRFS_BLOCK_GROUP_DATA) { int sector_nr; unsignedlong csum_bitmap = 0;
/* Csum space should have already been allocated. */
ASSERT(stripe->csums);
/* * Our csum bitmap should be large enough, as BTRFS_STRIPE_LEN * should contain at most 16 sectors.
*/
ASSERT(BITS_PER_LONG >= BTRFS_STRIPE_LEN >> fs_info->sectorsize_bits);
ret = btrfs_lookup_csums_bitmap(csum_root, csum_path,
stripe->logical, stripe_end,
stripe->csums, &csum_bitmap); if (ret < 0) goto out; if (ret > 0)
ret = 0;
for_each_set_bit(i, &has_extent, stripe->nr_sectors) { /* We're beyond the chunk boundary, no need to read anymore. */ if (i >= nr_sectors) break;
/* The current sector cannot be merged, submit the bio. */ if (bbio &&
((i > 0 && !test_bit(i - 1, &has_extent)) ||
bbio->bio.bi_iter.bi_size >= stripe_len)) {
ASSERT(bbio->bio.bi_iter.bi_size);
atomic_inc(&stripe->pending_io);
btrfs_submit_bbio(bbio, mirror);
bbio = NULL;
}
if (!bbio) { struct btrfs_io_stripe io_stripe = {}; struct btrfs_io_context *bioc = NULL; const u64 logical = stripe->logical +
(i << fs_info->sectorsize_bits); int ret;
io_stripe.rst_search_commit_root = true;
stripe_len = (nr_sectors - i) << fs_info->sectorsize_bits; /* * For RST cases, we need to manually split the bbio to * follow the RST boundary.
*/
ret = btrfs_map_block(fs_info, BTRFS_MAP_READ, logical,
&stripe_len, &bioc, &io_stripe, &mirror);
btrfs_put_bioc(bioc); if (ret < 0) { if (ret != -ENODATA) { /* * Earlier btrfs_get_raid_extent_offset() * returned -ENODATA, which means there's * no entry for the corresponding range * in the stripe tree. But if it's in * the extent tree, then it's a preallocated * extent and not an error.
*/
scrub_bitmap_set_bit_io_error(stripe, i);
scrub_bitmap_set_bit_error(stripe, i);
} continue;
}
bbio->bio.bi_iter.bi_sector = stripe->logical >> SECTOR_SHIFT; /* Read the whole range inside the chunk boundary. */ for (unsignedint cur = 0; cur < nr_sectors; cur++)
scrub_bio_add_sector(bbio, stripe, cur);
atomic_inc(&stripe->pending_io);
/* * For dev-replace, either user asks to avoid the source dev, or * the device is missing, we try the next mirror instead.
*/ if (sctx->is_dev_replace &&
(fs_info->dev_replace.cont_reading_from_srcdev_mode ==
BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_AVOID ||
!stripe->dev->bdev)) { int num_copies = btrfs_num_copies(fs_info, stripe->bg->start,
stripe->bg->length);
scrub_throttle_dev_io(sctx, sctx->stripes[0].dev,
btrfs_stripe_nr_to_offset(nr_stripes));
blk_start_plug(&plug); for (int i = 0; i < nr_stripes; i++) { struct scrub_stripe *stripe = &sctx->stripes[first_slot + i];
/* Those stripes should be initialized. */
ASSERT(test_bit(SCRUB_STRIPE_FLAG_INITIALIZED, &stripe->state));
scrub_submit_initial_read(sctx, stripe);
}
blk_finish_plug(&plug);
}
/* Submit the stripes which are populated but not submitted. */ if (nr_stripes % SCRUB_STRIPES_PER_GROUP) { constint first_slot = round_down(nr_stripes, SCRUB_STRIPES_PER_GROUP);
/* Submit for dev-replace. */ if (sctx->is_dev_replace) { /* * For dev-replace, if we know there is something wrong with * metadata, we should immediately abort.
*/ for (int i = 0; i < nr_stripes; i++) { if (stripe_has_metadata_error(&sctx->stripes[i])) {
ret = -EIO; goto out;
}
} for (int i = 0; i < nr_stripes; i++) { unsignedlong good; unsignedlong has_extent; unsignedlong error;
/* * There should always be one slot left, as caller filling the last * slot should flush them all.
*/
ASSERT(sctx->cur_stripe < SCRUB_TOTAL_STRIPES);
/* @found_logical_ret must be specified. */
ASSERT(found_logical_ret);
stripe = &sctx->stripes[sctx->cur_stripe];
scrub_reset_stripe(stripe);
ret = scrub_find_fill_first_stripe(bg, &sctx->extent_path,
&sctx->csum_path, dev, physical,
mirror_num, logical, length, stripe); /* Either >0 as no more extents or <0 for error. */ if (ret) return ret;
*found_logical_ret = stripe->logical;
sctx->cur_stripe++;
/* We filled one group, submit it. */ if (sctx->cur_stripe % SCRUB_STRIPES_PER_GROUP == 0) { constint first_slot = sctx->cur_stripe - SCRUB_STRIPES_PER_GROUP;
/* * For data stripe search, we cannot reuse the same extent/csum paths, * as the data stripe bytenr may be smaller than previous extent. Thus * we have to use our own extent/csum paths.
*/
extent_path.search_commit_root = 1;
extent_path.skip_locking = 1;
csum_path.search_commit_root = 1;
csum_path.skip_locking = 1;
for (int i = 0; i < data_stripes; i++) { int stripe_index; int rot;
u64 physical;
scrub_reset_stripe(stripe);
set_bit(SCRUB_STRIPE_FLAG_NO_REPORT, &stripe->state);
ret = scrub_find_fill_first_stripe(bg, &extent_path, &csum_path,
map->stripes[stripe_index].dev, physical, 1,
full_stripe_start + btrfs_stripe_nr_to_offset(i),
BTRFS_STRIPE_LEN, stripe); if (ret < 0) goto out; /* * No extent in this data stripe, need to manually mark them * initialized to make later read submission happy.
*/ if (ret > 0) {
stripe->logical = full_stripe_start +
btrfs_stripe_nr_to_offset(i);
stripe->dev = map->stripes[stripe_index].dev;
stripe->mirror_num = 1;
set_bit(SCRUB_STRIPE_FLAG_INITIALIZED, &stripe->state);
}
}
/* Check if all data stripes are empty. */ for (int i = 0; i < data_stripes; i++) {
stripe = &sctx->raid56_data_stripes[i]; if (!scrub_bitmap_empty_has_extent(stripe)) {
all_empty = false; break;
}
} if (all_empty) {
ret = 0; goto out;
}
for (int i = 0; i < data_stripes; i++) {
stripe = &sctx->raid56_data_stripes[i];
scrub_submit_initial_read(sctx, stripe);
} for (int i = 0; i < data_stripes; i++) {
stripe = &sctx->raid56_data_stripes[i];
wait_event(stripe->repair_wait,
test_bit(SCRUB_STRIPE_FLAG_REPAIR_DONE, &stripe->state));
} /* For now, no zoned support for RAID56. */
ASSERT(!btrfs_is_zoned(sctx->fs_info));
/* * Now all data stripes are properly verified. Check if we have any * unrepaired, if so abort immediately or we could further corrupt the * P/Q stripes. * * During the loop, also populate extent_bitmap.
*/ for (int i = 0; i < data_stripes; i++) { unsignedlong error; unsignedlong has_extent;
/* * We should only check the errors where there is an extent. * As we may hit an empty data stripe while it's missing.
*/
bitmap_and(&error, &error, &has_extent, stripe->nr_sectors); if (!bitmap_empty(&error, stripe->nr_sectors)) {
btrfs_err(fs_info, "scrub: unrepaired sectors detected, full stripe %llu data stripe %u errors %*pbl",
full_stripe_start, i, stripe->nr_sectors,
&error);
ret = -EIO; goto out;
}
bitmap_or(&extent_bitmap, &extent_bitmap, &has_extent,
stripe->nr_sectors);
}
/* Now we can check and regenerate the P/Q stripe. */
bio = bio_alloc(NULL, 1, REQ_OP_READ, GFP_NOFS);
bio->bi_iter.bi_sector = full_stripe_start >> SECTOR_SHIFT;
bio->bi_private = &io_done;
bio->bi_end_io = raid56_scrub_wait_endio;
btrfs_bio_counter_inc_blocked(fs_info);
ret = btrfs_map_block(fs_info, BTRFS_MAP_WRITE, full_stripe_start,
&length, &bioc, NULL, NULL); if (ret < 0) {
bio_put(bio);
btrfs_put_bioc(bioc);
btrfs_bio_counter_dec(fs_info); goto out;
}
rbio = raid56_parity_alloc_scrub_rbio(bio, bioc, scrub_dev, &extent_bitmap,
BTRFS_STRIPE_LEN >> fs_info->sectorsize_bits);
btrfs_put_bioc(bioc); if (!rbio) {
ret = -ENOMEM;
bio_put(bio);
btrfs_bio_counter_dec(fs_info); goto out;
} /* Use the recovered stripes as cache to avoid read them from disk again. */ for (int i = 0; i < data_stripes; i++) {
stripe = &sctx->raid56_data_stripes[i];
raid56_parity_cache_data_pages(rbio, stripe->pages,
full_stripe_start + (i << BTRFS_STRIPE_LEN_SHIFT));
}
raid56_parity_submit_scrub_rbio(rbio);
wait_for_completion_io(&io_done);
ret = blk_status_to_errno(bio->bi_status);
bio_put(bio);
btrfs_bio_counter_dec(fs_info);
/* * Scrub one range which can only has simple mirror based profile. * (Including all range in SINGLE/DUP/RAID1/RAID1C*, and each stripe in * RAID0/RAID10). * * Since we may need to handle a subset of block group, we need @logical_start * and @logical_length parameter.
*/ staticint scrub_simple_mirror(struct scrub_ctx *sctx, struct btrfs_block_group *bg,
u64 logical_start, u64 logical_length, struct btrfs_device *device,
u64 physical, int mirror_num)
{ struct btrfs_fs_info *fs_info = sctx->fs_info; const u64 logical_end = logical_start + logical_length;
u64 cur_logical = logical_start; int ret = 0;
/* The range must be inside the bg */
ASSERT(logical_start >= bg->start && logical_end <= bg->start + bg->length);
/* Go through each extent items inside the logical range */ while (cur_logical < logical_end) {
u64 found_logical = U64_MAX;
u64 cur_physical = physical + cur_logical - logical_start;
/* Canceled? */ if (atomic_read(&fs_info->scrub_cancel_req) ||
atomic_read(&sctx->cancel_req)) {
ret = -ECANCELED; break;
} /* Paused? */ if (atomic_read(&fs_info->scrub_pause_req)) { /* Push queued extents */
scrub_blocked_if_needed(fs_info);
} /* Block group removed? */
spin_lock(&bg->lock); if (test_bit(BLOCK_GROUP_FLAG_REMOVED, &bg->runtime_flags)) {
spin_unlock(&bg->lock);
ret = 0; break;
}
spin_unlock(&bg->lock);
ret = queue_scrub_stripe(sctx, bg, device, mirror_num,
cur_logical, logical_end - cur_logical,
cur_physical, &found_logical); if (ret > 0) { /* No more extent, just update the accounting */
spin_lock(&sctx->stat_lock);
sctx->stat.last_physical = physical + logical_length;
spin_unlock(&sctx->stat_lock);
ret = 0; break;
} if (ret < 0) break;
/* queue_scrub_stripe() returned 0, @found_logical must be updated. */
ASSERT(found_logical != U64_MAX);
cur_logical = found_logical + BTRFS_STRIPE_LEN;
/* Don't hold CPU for too long time */
cond_resched();
} return ret;
}
/* Calculate the full stripe length for simple stripe based profiles */ static u64 simple_stripe_full_stripe_len(conststruct btrfs_chunk_map *map)
{
ASSERT(map->type & (BTRFS_BLOCK_GROUP_RAID0 |
BTRFS_BLOCK_GROUP_RAID10));
/* Get the logical bytenr for the stripe */ static u64 simple_stripe_get_logical(struct btrfs_chunk_map *map, struct btrfs_block_group *bg, int stripe_index)
{
ASSERT(map->type & (BTRFS_BLOCK_GROUP_RAID0 |
BTRFS_BLOCK_GROUP_RAID10));
ASSERT(stripe_index < map->num_stripes);
/* * (stripe_index / sub_stripes) gives how many data stripes we need to * skip.
*/ return btrfs_stripe_nr_to_offset(stripe_index / map->sub_stripes) +
bg->start;
}
/* Get the mirror number for the stripe */ staticint simple_stripe_mirror_num(struct btrfs_chunk_map *map, int stripe_index)
{
ASSERT(map->type & (BTRFS_BLOCK_GROUP_RAID0 |
BTRFS_BLOCK_GROUP_RAID10));
ASSERT(stripe_index < map->num_stripes);
/* For RAID0, it's fixed to 1, for RAID10 it's 0,1,0,1... */ return stripe_index % map->sub_stripes + 1;
}
while (cur_logical < bg->start + bg->length) { /* * Inside each stripe, RAID0 is just SINGLE, and RAID10 is * just RAID1, so we can reuse scrub_simple_mirror() to scrub * this stripe.
*/
ret = scrub_simple_mirror(sctx, bg, cur_logical,
BTRFS_STRIPE_LEN, device, cur_physical,
mirror_num); if (ret) return ret; /* Skip to next stripe which belongs to the target device */
cur_logical += logical_increment; /* For physical offset, we just go to next stripe */
cur_physical += BTRFS_STRIPE_LEN;
} return ret;
}
static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, struct btrfs_block_group *bg, struct btrfs_chunk_map *map, struct btrfs_device *scrub_dev, int stripe_index)
{ struct btrfs_fs_info *fs_info = sctx->fs_info; const u64 profile = map->type & BTRFS_BLOCK_GROUP_PROFILE_MASK; const u64 chunk_logical = bg->start; int ret; int ret2;
u64 physical = map->stripes[stripe_index].physical; const u64 dev_stripe_len = btrfs_calc_stripe_length(map); const u64 physical_end = physical + dev_stripe_len;
u64 logical;
u64 logic_end; /* The logical increment after finishing one stripe */
u64 increment; /* Offset inside the chunk */
u64 offset;
u64 stripe_logical;
/* Extent_path should be released by now. */
ASSERT(sctx->extent_path.nodes[0] == NULL);
/* Prepare the extra data stripes used by RAID56. */ if (profile & BTRFS_BLOCK_GROUP_RAID56_MASK) {
ASSERT(sctx->raid56_data_stripes == NULL);
sctx->raid56_data_stripes = kcalloc(nr_data_stripes(map), sizeof(struct scrub_stripe),
GFP_KERNEL); if (!sctx->raid56_data_stripes) {
ret = -ENOMEM; goto out;
} for (int i = 0; i < nr_data_stripes(map); i++) {
ret = init_scrub_stripe(fs_info,
&sctx->raid56_data_stripes[i]); if (ret < 0) goto out;
sctx->raid56_data_stripes[i].bg = bg;
sctx->raid56_data_stripes[i].sctx = sctx;
}
} /* * There used to be a big double loop to handle all profiles using the * same routine, which grows larger and more gross over time. * * So here we handle each profile differently, so simpler profiles * have simpler scrubbing function.
*/ if (!(profile & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10 |
BTRFS_BLOCK_GROUP_RAID56_MASK))) { /* * Above check rules out all complex profile, the remaining * profiles are SINGLE|DUP|RAID1|RAID1C*, which is simple * mirrored duplication without stripe. * * Only @physical and @mirror_num needs to calculated using * @stripe_index.
*/
ret = scrub_simple_mirror(sctx, bg, bg->start, bg->length,
scrub_dev, map->stripes[stripe_index].physical,
stripe_index + 1);
offset = 0; goto out;
} if (profile & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10)) {
ret = scrub_simple_stripe(sctx, bg, map, scrub_dev, stripe_index);
offset = btrfs_stripe_nr_to_offset(stripe_index / map->sub_stripes); goto out;
}
/* Only RAID56 goes through the old code */
ASSERT(map->type & BTRFS_BLOCK_GROUP_RAID56_MASK);
ret = 0;
/* Calculate the logical end of the stripe */
get_raid56_logic_offset(physical_end, stripe_index,
map, &logic_end, NULL);
logic_end += chunk_logical;
/* Initialize @offset in case we need to go to out: label */
get_raid56_logic_offset(physical, stripe_index, map, &offset, NULL);
increment = btrfs_stripe_nr_to_offset(nr_data_stripes(map));
/* * Due to the rotation, for RAID56 it's better to iterate each stripe * using their physical offset.
*/ while (physical < physical_end) {
ret = get_raid56_logic_offset(physical, stripe_index, map,
&logical, &stripe_logical);
logical += chunk_logical; if (ret) { /* it is parity strip */
stripe_logical += chunk_logical;
ret = scrub_raid56_parity_stripe(sctx, scrub_dev, bg,
map, stripe_logical);
spin_lock(&sctx->stat_lock);
sctx->stat.last_physical = min(physical + BTRFS_STRIPE_LEN,
physical_end);
spin_unlock(&sctx->stat_lock); if (ret) goto out; goto next;
}
/* * Now we're at a data stripe, scrub each extents in the range. * * At this stage, if we ignore the repair part, inside each data * stripe it is no different than SINGLE profile. * We can reuse scrub_simple_mirror() here, as the repair part * is still based on @mirror_num.
*/
ret = scrub_simple_mirror(sctx, bg, logical, BTRFS_STRIPE_LEN,
scrub_dev, physical, 1); if (ret < 0) goto out;
next:
logical += increment;
physical += BTRFS_STRIPE_LEN;
spin_lock(&sctx->stat_lock);
sctx->stat.last_physical = physical;
spin_unlock(&sctx->stat_lock);
}
out:
ret2 = flush_scrub_stripes(sctx); if (!ret)
ret = ret2;
btrfs_release_path(&sctx->extent_path);
btrfs_release_path(&sctx->csum_path);
if (sctx->raid56_data_stripes) { for (int i = 0; i < nr_data_stripes(map); i++)
release_scrub_stripe(&sctx->raid56_data_stripes[i]);
kfree(sctx->raid56_data_stripes);
sctx->raid56_data_stripes = NULL;
}
if (sctx->is_dev_replace && ret >= 0) { int ret2;
ret2 = sync_write_pointer_for_zoned(sctx,
chunk_logical + offset,
map->stripes[stripe_index].physical,
physical_end); if (ret2)
ret = ret2;
}
return ret < 0 ? ret : 0;
}
static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx, struct btrfs_block_group *bg, struct btrfs_device *scrub_dev,
u64 dev_offset,
u64 dev_extent_len)
{ struct btrfs_fs_info *fs_info = sctx->fs_info; struct btrfs_chunk_map *map; int i; int ret = 0;
map = btrfs_find_chunk_map(fs_info, bg->start, bg->length); if (!map) { /* * Might have been an unused block group deleted by the cleaner * kthread or relocation.
*/
spin_lock(&bg->lock); if (!test_bit(BLOCK_GROUP_FLAG_REMOVED, &bg->runtime_flags))
ret = -EINVAL;
spin_unlock(&bg->lock);
return ret;
} if (map->start != bg->start) goto out; if (map->chunk_len < dev_extent_len) goto out;
for (i = 0; i < map->num_stripes; ++i) { if (map->stripes[i].dev->bdev == scrub_dev->bdev &&
map->stripes[i].physical == dev_offset) {
ret = scrub_stripe(sctx, bg, map, scrub_dev, i); if (ret) goto out;
}
}
out:
btrfs_free_chunk_map(map);
/* * get a reference on the corresponding block group to prevent * the chunk from going away while we scrub it
*/
cache = btrfs_lookup_block_group(fs_info, chunk_offset);
/* some chunks are removed but not committed to disk yet,
* continue scrubbing */ if (!cache) goto skip;
ASSERT(cache->start <= chunk_offset); /* * We are using the commit root to search for device extents, so * that means we could have found a device extent item from a * block group that was deleted in the current transaction. The * logical start offset of the deleted block group, stored at * @chunk_offset, might be part of the logical address range of * a new block group (which uses different physical extents). * In this case btrfs_lookup_block_group() has returned the new * block group, and its start address is less than @chunk_offset. * * We skip such new block groups, because it's pointless to * process them, as we won't find their extents because we search * for them using the commit root of the extent tree. For a device * replace it's also fine to skip it, we won't miss copying them * to the target device because we have the write duplication * setup through the regular write path (by btrfs_map_block()), * and we have committed a transaction when we started the device * replace, right after setting up the device replace state.
*/ if (cache->start < chunk_offset) {
btrfs_put_block_group(cache); goto skip;
}
if (sctx->is_dev_replace && btrfs_is_zoned(fs_info)) { if (!test_bit(BLOCK_GROUP_FLAG_TO_COPY, &cache->runtime_flags)) {
btrfs_put_block_group(cache); goto skip;
}
}
/* * Make sure that while we are scrubbing the corresponding block * group doesn't get its logical address and its device extents * reused for another block group, which can possibly be of a * different type and different profile. We do this to prevent * false error detections and crashes due to bogus attempts to * repair extents.
*/
spin_lock(&cache->lock); if (test_bit(BLOCK_GROUP_FLAG_REMOVED, &cache->runtime_flags)) {
spin_unlock(&cache->lock);
btrfs_put_block_group(cache); goto skip;
}
btrfs_freeze_block_group(cache);
spin_unlock(&cache->lock);
/* * we need call btrfs_inc_block_group_ro() with scrubs_paused, * to avoid deadlock caused by: * btrfs_inc_block_group_ro() * -> btrfs_wait_for_commit() * -> btrfs_commit_transaction() * -> btrfs_scrub_pause()
*/
scrub_pause_on(fs_info);
/* * Don't do chunk preallocation for scrub. * * This is especially important for SYSTEM bgs, or we can hit * -EFBIG from btrfs_finish_chunk_alloc() like: * 1. The only SYSTEM bg is marked RO. * Since SYSTEM bg is small, that's pretty common. * 2. New SYSTEM bg will be allocated * Due to regular version will allocate new chunk. * 3. New SYSTEM bg is empty and will get cleaned up * Before cleanup really happens, it's marked RO again. * 4. Empty SYSTEM bg get scrubbed * We go back to 2. * * This can easily boost the amount of SYSTEM chunks if cleaner * thread can't be triggered fast enough, and use up all space * of btrfs_super_block::sys_chunk_array * * While for dev replace, we need to try our best to mark block * group RO, to prevent race between: * - Write duplication * Contains latest data * - Scrub copy * Contains data from commit tree * * If target block group is not marked RO, nocow writes can * be overwritten by scrub copy, causing data corruption. * So for dev-replace, it's not allowed to continue if a block * group is not RO.
*/
ret = btrfs_inc_block_group_ro(cache, sctx->is_dev_replace); if (!ret && sctx->is_dev_replace) {
ret = finish_extent_writes_for_zoned(root, cache); if (ret) {
btrfs_dec_block_group_ro(cache);
scrub_pause_off(fs_info);
btrfs_put_block_group(cache); break;
}
}
if (ret == 0) {
ro_set = 1;
} elseif (ret == -ENOSPC && !sctx->is_dev_replace &&
!(cache->flags & BTRFS_BLOCK_GROUP_RAID56_MASK)) { /* * btrfs_inc_block_group_ro return -ENOSPC when it * failed in creating new chunk for metadata. * It is not a problem for scrub, because * metadata are always cowed, and our scrub paused * commit_transactions. * * For RAID56 chunks, we have to mark them read-only * for scrub, as later we would use our own cache * out of RAID56 realm. * Thus we want the RAID56 bg to be marked RO to * prevent RMW from screwing up out cache.
*/
ro_set = 0;
} elseif (ret == -ETXTBSY) {
btrfs_warn(fs_info, "scrub: skipping scrub of block group %llu due to active swapfile",
cache->start);
scrub_pause_off(fs_info);
ret = 0; goto skip_unfreeze;
} else {
btrfs_warn(fs_info, "scrub: failed setting block group ro: %d",
ret);
btrfs_unfreeze_block_group(cache);
btrfs_put_block_group(cache);
scrub_pause_off(fs_info); break;
}
/* * Now the target block is marked RO, wait for nocow writes to * finish before dev-replace. * COW is fine, as COW never overwrites extents in commit tree.
*/ if (sctx->is_dev_replace) {
btrfs_wait_nocow_writers(cache);
btrfs_wait_ordered_roots(fs_info, U64_MAX, cache);
}
/* * We might have prevented the cleaner kthread from deleting * this block group if it was already unused because we raced * and set it to RO mode first. So add it back to the unused * list, otherwise it might not ever be deleted unless a manual * balance is triggered or it becomes used and unused again.
*/
spin_lock(&cache->lock); if (!test_bit(BLOCK_GROUP_FLAG_REMOVED, &cache->runtime_flags) &&
!cache->ro && cache->reserved == 0 && cache->used == 0) {
spin_unlock(&cache->lock); if (btrfs_test_opt(fs_info, DISCARD_ASYNC))
btrfs_discard_queue_work(&fs_info->discard_ctl,
cache); else
btrfs_mark_bg_unused(cache);
} else {
spin_unlock(&cache->lock);
}
skip_unfreeze:
btrfs_unfreeze_block_group(cache);
btrfs_put_block_group(cache); if (ret) break; if (sctx->is_dev_replace &&
atomic64_read(&dev_replace->num_write_errors) > 0) {
ret = -EIO; break;
} if (sctx->stat.malloc_errors > 0) {
ret = -ENOMEM; break;
}
skip:
key.offset = found_key.offset + dev_extent_len;
btrfs_release_path(path);
}
/* Seed devices of a new filesystem has their own generation. */ if (scrub_dev->fs_devices != fs_info->fs_devices)
gen = scrub_dev->generation; else
gen = btrfs_get_last_trans_committed(fs_info);
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
ret = btrfs_sb_log_location(scrub_dev, i, 0, &bytenr); if (ret == -ENOENT) break;
if (ret) {
spin_lock(&sctx->stat_lock);
sctx->stat.super_errors++;
spin_unlock(&sctx->stat_lock); continue;
}
if (bytenr + BTRFS_SUPER_INFO_SIZE >
scrub_dev->commit_total_bytes) break; if (!btrfs_check_super_location(scrub_dev, bytenr)) continue;
ret = scrub_one_super(sctx, scrub_dev, page, bytenr, gen); if (ret) {
spin_lock(&sctx->stat_lock);
sctx->stat.super_errors++;
spin_unlock(&sctx->stat_lock);
}
}
__free_page(page); return 0;
}
if (scrub_workers)
destroy_workqueue(scrub_workers);
}
}
/* * get a reference count on fs_info->scrub_workers. start worker if necessary
*/ static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info)
{ struct workqueue_struct *scrub_workers = NULL; unsignedint flags = WQ_FREEZABLE | WQ_UNBOUND; int max_active = fs_info->thread_pool_size; int ret = -ENOMEM;
if (refcount_inc_not_zero(&fs_info->scrub_workers_refcnt)) return 0;
scrub_workers = alloc_workqueue("btrfs-scrub", flags, max_active); if (!scrub_workers) return -ENOMEM;
mutex_lock(&fs_info->scrub_lock); if (refcount_read(&fs_info->scrub_workers_refcnt) == 0) {
ASSERT(fs_info->scrub_workers == NULL);
fs_info->scrub_workers = scrub_workers;
refcount_set(&fs_info->scrub_workers_refcnt, 1);
mutex_unlock(&fs_info->scrub_lock); return 0;
} /* Other thread raced in and created the workers for us */
refcount_inc(&fs_info->scrub_workers_refcnt);
mutex_unlock(&fs_info->scrub_lock);
/* At mount time we have ensured nodesize is in the range of [4K, 64K]. */
ASSERT(fs_info->nodesize <= BTRFS_STRIPE_LEN);
/* * SCRUB_MAX_SECTORS_PER_BLOCK is calculated using the largest possible * value (max nodesize / min sectorsize), thus nodesize should always * be fine.
*/
ASSERT(fs_info->nodesize <=
SCRUB_MAX_SECTORS_PER_BLOCK << fs_info->sectorsize_bits);
/* Allocate outside of device_list_mutex */
sctx = scrub_setup_ctx(fs_info, is_dev_replace); if (IS_ERR(sctx)) return PTR_ERR(sctx);
ret = scrub_workers_get(fs_info); if (ret) goto out_free_ctx;
mutex_lock(&fs_info->fs_devices->device_list_mutex);
dev = btrfs_find_device(fs_info->fs_devices, &args); if (!dev || (test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state) &&
!is_dev_replace)) {
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
ret = -ENODEV; goto out;
}
if (!is_dev_replace && !readonly &&
!test_bit(BTRFS_DEV_STATE_WRITEABLE, &dev->dev_state)) {
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
btrfs_err(fs_info, "scrub: devid %llu: filesystem on %s is not writable",
devid, btrfs_dev_name(dev));
ret = -EROFS; goto out;
}
mutex_lock(&fs_info->scrub_lock); if (!test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &dev->dev_state) ||
test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &dev->dev_state)) {
mutex_unlock(&fs_info->scrub_lock);
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
ret = -EIO; goto out;
}
down_read(&fs_info->dev_replace.rwsem); if (dev->scrub_ctx ||
(!is_dev_replace &&
btrfs_dev_replace_is_ongoing(&fs_info->dev_replace))) {
up_read(&fs_info->dev_replace.rwsem);
mutex_unlock(&fs_info->scrub_lock);
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
ret = -EINPROGRESS; goto out;
}
up_read(&fs_info->dev_replace.rwsem);
/* * checking @scrub_pause_req here, we can avoid * race between committing transaction and scrubbing.
*/
__scrub_blocked_if_needed(fs_info);
atomic_inc(&fs_info->scrubs_running);
mutex_unlock(&fs_info->scrub_lock);
/* * In order to avoid deadlock with reclaim when there is a transaction * trying to pause scrub, make sure we use GFP_NOFS for all the * allocations done at btrfs_scrub_sectors() and scrub_sectors_for_parity() * invoked by our callees. The pausing request is done when the * transaction commit starts, and it blocks the transaction until scrub * is paused (done at specific points at scrub_stripe() or right above * before incrementing fs_info->scrubs_running).
*/
nofs_flag = memalloc_nofs_save(); if (!is_dev_replace) {
u64 old_super_errors;
btrfs_info(fs_info, "scrub: started on devid %llu", devid); /* * by holding device list mutex, we can * kick off writing super in log tree sync.
*/
mutex_lock(&fs_info->fs_devices->device_list_mutex);
ret = scrub_supers(sctx, dev);
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
spin_lock(&sctx->stat_lock); /* * Super block errors found, but we can not commit transaction * at current context, since btrfs_commit_transaction() needs * to pause the current running scrub (hold by ourselves).
*/ if (sctx->stat.super_errors > old_super_errors && !sctx->readonly)
need_commit = true;
spin_unlock(&sctx->stat_lock);
}
if (!ret)
ret = scrub_enumerate_chunks(sctx, dev, start, end);
memalloc_nofs_restore(nofs_flag);
/* * We found some super block errors before, now try to force a * transaction commit, as scrub has finished.
*/ if (need_commit) { struct btrfs_trans_handle *trans;
trans = btrfs_start_transaction(fs_info->tree_root, 0); if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
btrfs_err(fs_info, "scrub: failed to start transaction to fix super block errors: %d", ret); return ret;
}
ret = btrfs_commit_transaction(trans); if (ret < 0)
btrfs_err(fs_info, "scrub: failed to commit transaction to fix super block errors: %d", ret);
} return ret;
out:
scrub_workers_put(fs_info);
out_free_ctx:
scrub_free_ctx(sctx);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.