Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/fs/btrfs/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 94 kB image not shown  

Quelle  scrub.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2011, 2012 STRATO.  All rights reserved.
 */


#include <linux/blkdev.h>
#include <linux/ratelimit.h>
#include <linux/sched/mm.h>
#include <crypto/hash.h>
#include "ctree.h"
#include "discard.h"
#include "volumes.h"
#include "disk-io.h"
#include "ordered-data.h"
#include "transaction.h"
#include "backref.h"
#include "extent_io.h"
#include "dev-replace.h"
#include "raid56.h"
#include "block-group.h"
#include "zoned.h"
#include "fs.h"
#include "accessors.h"
#include "file-item.h"
#include "scrub.h"
#include "raid-stripe-tree.h"

/*
 * 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

#define SCRUB_TOTAL_STRIPES  (SCRUB_GROUPS_PER_SCTX * SCRUB_STRIPES_PER_GROUP)

/*
 * 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,
};

#define SCRUB_STRIPE_PAGES  (BTRFS_STRIPE_LEN / PAGE_SIZE)

/*
 * Represent one contiguous range with a length of BTRFS_STRIPE_LEN.
 */

struct scrub_stripe {
 struct scrub_ctx *sctx;
 struct btrfs_block_group *bg;

 struct page *pages[SCRUB_STRIPE_PAGES];
 struct scrub_sector_verification *sectors;

 struct btrfs_device *dev;
 u64 logical;
 u64 physical;

 u16 mirror_num;

 /* Should be BTRFS_STRIPE_LEN / sectorsize. */
 u16 nr_sectors;

 /*
 * How many data/meta extents are in this stripe.  Only for scrub status
 * reporting purposes.
 */

 u16 nr_data_extents;
 u16 nr_meta_extents;

 atomic_t pending_io;
 wait_queue_head_t io_wait;
 wait_queue_head_t repair_wait;

 /*
 * Indicate the states of the stripe.  Bits are defined in
 * scrub_stripe_flags enum.
 */

 unsigned long state;

 /* The large bitmap contains all the sub-bitmaps. */
 unsigned long 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.
 */

 unsigned long 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;

 int   is_dev_replace;
 u64   write_pointer;

 struct mutex            wr_lock;
 struct btrfs_device     *wr_tgtdev;

 /*
 * statistics
 */

 struct btrfs_scrub_progress stat;
 spinlock_t  stat_lock;

 /*
 * 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;
};

#define scrub_calc_start_bit(stripe, name, block_nr)   \
({         \
 unsigned int __start_bit;     \
         \
 ASSERT(block_nr < stripe->nr_sectors,    \
  "nr_sectors=%u block_nr=%u", stripe->nr_sectors, block_nr); \
 __start_bit = scrub_bitmap_nr_##name * stripe->nr_sectors + block_nr; \
 __start_bit;       \
})

#define IMPLEMENT_SCRUB_BITMAP_OPS(name)    \
static inline void scrub_bitmap_set_##name(struct scrub_stripe *stripe, \
        unsigned int block_nr,  \
        unsigned int nr_blocks)  \
{         \
 const unsigned int start_bit = scrub_calc_start_bit(stripe, \
           name, block_nr); \
         \
 bitmap_set(stripe->bitmaps, start_bit, nr_blocks);  \
}         \
static inline void scrub_bitmap_clear_##name(struct scrub_stripe *stripe, \
          unsigned int block_nr,  \
          unsigned int nr_blocks)  \
{         \
 const unsigned int start_bit = scrub_calc_start_bit(stripe, name, \
           block_nr); \
         \
 bitmap_clear(stripe->bitmaps, start_bit, nr_blocks);  \
}         \
static inline bool scrub_bitmap_test_bit_##name(struct scrub_stripe *stripe, \
         unsigned int block_nr)  \
{         \
 const unsigned int start_bit = scrub_calc_start_bit(stripe, name, \
           block_nr); \
         \
 return test_bit(start_bit, stripe->bitmaps);   \
}         \
static inline void scrub_bitmap_set_bit_##name(struct scrub_stripe *stripe, \
         unsigned int block_nr)  \
{         \
 const unsigned int start_bit = scrub_calc_start_bit(stripe, name, \
           block_nr); \
         \
 set_bit(start_bit, stripe->bitmaps);    \
}         \
static inline void scrub_bitmap_clear_bit_##name(struct scrub_stripe *stripe, \
         unsigned int block_nr)  \
{         \
 const unsigned int start_bit = scrub_calc_start_bit(stripe, name, \
           block_nr); \
         \
 clear_bit(start_bit, stripe->bitmaps);    \
}         \
static inline unsigned long scrub_bitmap_read_##name(struct scrub_stripe *stripe) \
{         \
 const unsigned int nr_blocks = stripe->nr_sectors;  \
         \
 ASSERT(nr_blocks > 0 && nr_blocks <= BITS_PER_LONG,  \
        "nr_blocks=%u BITS_PER_LONG=%u",    \
        nr_blocks, BITS_PER_LONG);    \
         \
 return bitmap_read(stripe->bitmaps, nr_blocks * scrub_bitmap_nr_##name, \
      stripe->nr_sectors);    \
}         \
static inline bool scrub_bitmap_empty_##name(struct scrub_stripe *stripe) \
{         \
 unsigned long bitmap = scrub_bitmap_read_##name(stripe); \
         \
 return bitmap_empty(&bitmap, stripe->nr_sectors);  \
}         \
static inline unsigned int scrub_bitmap_weight_##name(struct scrub_stripe *stripe) \
{         \
 unsigned long bitmap = scrub_bitmap_read_##name(stripe); \
         \
 return bitmap_weight(&bitmap, stripe->nr_sectors);  \
}
IMPLEMENT_SCRUB_BITMAP_OPS(has_extent);
IMPLEMENT_SCRUB_BITMAP_OPS(is_metadata);
IMPLEMENT_SCRUB_BITMAP_OPS(error);
IMPLEMENT_SCRUB_BITMAP_OPS(io_error);
IMPLEMENT_SCRUB_BITMAP_OPS(csum_error);
IMPLEMENT_SCRUB_BITMAP_OPS(meta_error);
IMPLEMENT_SCRUB_BITMAP_OPS(meta_gen_error);

struct scrub_warning {
 struct btrfs_path *path;
 u64   extent_item_size;
 const char  *errstr;
 u64   physical;
 u64   logical;
 struct btrfs_device *dev;
};

struct scrub_error_records {
 /*
 * Bitmap recording which blocks hit errors (IO/csum/...) during the
 * initial read.
 */

 unsigned long init_error_bitmap;

 unsigned int nr_io_errors;
 unsigned int nr_csum_errors;
 unsigned int nr_meta_errors;
 unsigned int nr_meta_gen_errors;
};

static void release_scrub_stripe(struct scrub_stripe *stripe)
{
 if (!stripe)
  return;

 for (int i = 0; i < SCRUB_STRIPE_PAGES; i++) {
  if (stripe->pages[i])
   __free_page(stripe->pages[i]);
  stripe->pages[i] = NULL;
 }
 kfree(stripe->sectors);
 kfree(stripe->csums);
 stripe->sectors = NULL;
 stripe->csums = NULL;
 stripe->sctx = NULL;
 stripe->state = 0;
}

static int init_scrub_stripe(struct btrfs_fs_info *fs_info,
        struct scrub_stripe *stripe)
{
 int ret;

 memset(stripe, 0, sizeof(*stripe));

 stripe->nr_sectors = BTRFS_STRIPE_LEN >> fs_info->sectorsize_bits;
 stripe->state = 0;

 init_waitqueue_head(&stripe->io_wait);
 init_waitqueue_head(&stripe->repair_wait);
 atomic_set(&stripe->pending_io, 0);
 spin_lock_init(&stripe->write_error_lock);

 ret = btrfs_alloc_page_array(SCRUB_STRIPE_PAGES, stripe->pages, false);
 if (ret < 0)
  goto error;

 stripe->sectors = kcalloc(stripe->nr_sectors,
      sizeof(struct scrub_sector_verification),
      GFP_KERNEL);
 if (!stripe->sectors)
  goto error;

 stripe->csums = kcalloc(BTRFS_STRIPE_LEN >> fs_info->sectorsize_bits,
    fs_info->csum_size, GFP_KERNEL);
 if (!stripe->csums)
  goto error;
 return 0;
error:
 release_scrub_stripe(stripe);
 return -ENOMEM;
}

static void wait_scrub_stripe_io(struct scrub_stripe *stripe)
{
 wait_event(stripe->io_wait, atomic_read(&stripe->pending_io) == 0);
}

static void scrub_put_ctx(struct scrub_ctx *sctx);

static void __scrub_blocked_if_needed(struct btrfs_fs_info *fs_info)
{
 while (atomic_read(&fs_info->scrub_pause_req)) {
  mutex_unlock(&fs_info->scrub_lock);
  wait_event(fs_info->scrub_pause_wait,
     atomic_read(&fs_info->scrub_pause_req) == 0);
  mutex_lock(&fs_info->scrub_lock);
 }
}

static void scrub_pause_on(struct btrfs_fs_info *fs_info)
{
 atomic_inc(&fs_info->scrubs_paused);
 wake_up(&fs_info->scrub_pause_wait);
}

static void scrub_pause_off(struct btrfs_fs_info *fs_info)
{
 mutex_lock(&fs_info->scrub_lock);
 __scrub_blocked_if_needed(fs_info);
 atomic_dec(&fs_info->scrubs_paused);
 mutex_unlock(&fs_info->scrub_lock);

 wake_up(&fs_info->scrub_pause_wait);
}

static void scrub_blocked_if_needed(struct btrfs_fs_info *fs_info)
{
 scrub_pause_on(fs_info);
 scrub_pause_off(fs_info);
}

static noinline_for_stack void scrub_free_ctx(struct scrub_ctx *sctx)
{
 int i;

 if (!sctx)
  return;

 for (i = 0; i < SCRUB_TOTAL_STRIPES; i++)
  release_scrub_stripe(&sctx->stripes[i]);

 kvfree(sctx);
}

static void scrub_put_ctx(struct scrub_ctx *sctx)
{
 if (refcount_dec_and_test(&sctx->refs))
  scrub_free_ctx(sctx);
}

static noinline_for_stack struct scrub_ctx *scrub_setup_ctx(
  struct btrfs_fs_info *fs_info, int is_dev_replace)
{
 struct scrub_ctx *sctx;
 int  i;

 /* Since sctx has inline 128 stripes, it can go beyond 64K easily.  Use
 * kvzalloc().
 */

 sctx = kvzalloc(sizeof(*sctx), GFP_KERNEL);
 if (!sctx)
  goto nomem;
 refcount_set(&sctx->refs, 1);
 sctx->is_dev_replace = is_dev_replace;
 sctx->fs_info = fs_info;
 sctx->extent_path.search_commit_root = 1;
 sctx->extent_path.skip_locking = 1;
 sctx->csum_path.search_commit_root = 1;
 sctx->csum_path.skip_locking = 1;
 for (i = 0; i < SCRUB_TOTAL_STRIPES; i++) {
  int ret;

  ret = init_scrub_stripe(fs_info, &sctx->stripes[i]);
  if (ret < 0)
   goto nomem;
  sctx->stripes[i].sctx = sctx;
 }
 sctx->first_free = 0;
 atomic_set(&sctx->cancel_req, 0);

 spin_lock_init(&sctx->stat_lock);
 sctx->throttle_deadline = 0;

 mutex_init(&sctx->wr_lock);
 if (is_dev_replace) {
  WARN_ON(!fs_info->dev_replace.tgtdev);
  sctx->wr_tgtdev = fs_info->dev_replace.tgtdev;
 }

 return sctx;

nomem:
 scrub_free_ctx(sctx);
 return ERR_PTR(-ENOMEM);
}

static int scrub_print_warning_inode(u64 inum, u64 offset, u64 num_bytes,
         u64 root, void *warn_ctx)
{
 u32 nlink;
 int ret;
 int i;
 unsigned nofs_flag;
 struct extent_buffer *eb;
 struct btrfs_inode_item *inode_item;
 struct scrub_warning *swarn = warn_ctx;
 struct btrfs_fs_info *fs_info = swarn->dev->fs_info;
 struct inode_fs_paths *ipath = NULL;
 struct btrfs_root *local_root;
 struct btrfs_key key;

 local_root = btrfs_get_fs_root(fs_info, root, true);
 if (IS_ERR(local_root)) {
  ret = PTR_ERR(local_root);
  goto err;
 }

 /*
 * this makes the path point to (inum INODE_ITEM ioff)
 */

 key.objectid = inum;
 key.type = BTRFS_INODE_ITEM_KEY;
 key.offset = 0;

 ret = btrfs_search_slot(NULL, local_root, &key, swarn->path, 0, 0);
 if (ret) {
  btrfs_put_root(local_root);
  btrfs_release_path(swarn->path);
  goto err;
 }

 eb = swarn->path->nodes[0];
 inode_item = btrfs_item_ptr(eb, swarn->path->slots[0],
     struct btrfs_inode_item);
 nlink = btrfs_inode_nlink(eb, inode_item);
 btrfs_release_path(swarn->path);

 /*
 * 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 *)(unsigned long)ipath->fspath->val[i]);

 btrfs_put_root(local_root);
 free_ipath(ipath);
 return 0;

err:
 btrfs_warn(fs_info,
     "scrub: %s at logical %llu on dev %s, physical %llu root %llu inode %llu offset %llu: path resolving failed with ret=%d",
     swarn->errstr, swarn->logical,
     btrfs_dev_name(swarn->dev),
     swarn->physical,
     root, inum, offset, ret);

 free_ipath(ipath);
 return 0;
}

static void scrub_print_common_warning(const char *errstr, struct btrfs_device *dev,
           bool is_super, u64 logical, u64 physical)
{
 struct btrfs_fs_info *fs_info = dev->fs_info;
 struct btrfs_path *path;
 struct btrfs_key found_key;
 struct extent_buffer *eb;
 struct btrfs_extent_item *ei;
 struct scrub_warning swarn;
 u64 flags = 0;
 u32 item_size;
 int ret;

 /* 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;

 swarn.physical = physical;
 swarn.logical = logical;
 swarn.errstr = errstr;
 swarn.dev = NULL;

 ret = extent_from_logical(fs_info, swarn.logical, path, &found_key,
      &flags);
 if (ret < 0)
  goto out;

 swarn.extent_item_size = found_key.offset;

 eb = path->nodes[0];
 ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item);
 item_size = btrfs_item_size(eb, path->slots[0]);

 if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
  unsigned long ptr = 0;
  u8 ref_level;
  u64 ref_root;

  while (true) {
   ret = tree_backref_for_extent(&ptr, eb, &found_key, ei,
            item_size, &ref_root,
            &ref_level);
   if (ret < 0) {
    btrfs_warn(fs_info,
     "scrub: failed to resolve tree backref for logical %llu: %d",
        swarn.logical, ret);
    break;
   }
   if (ret > 0)
    break;
   btrfs_warn(fs_info,
"scrub: %s at logical %llu on dev %s, physical %llu: metadata %s (level %d) in tree %llu",
    errstr, swarn.logical, btrfs_dev_name(dev),
    swarn.physical, (ref_level ? "node" : "leaf"),
    ref_level, ref_root);
  }
  btrfs_release_path(path);
 } else {
  struct btrfs_backref_walk_ctx ctx = { 0 };

  btrfs_release_path(path);

  ctx.bytenr = found_key.objectid;
  ctx.extent_item_pos = swarn.logical - found_key.objectid;
  ctx.fs_info = fs_info;

  swarn.path = path;
  swarn.dev = dev;

  iterate_extent_inodes(&ctx, true, scrub_print_warning_inode, &swarn);
 }

out:
 btrfs_free_path(path);
}

static int fill_writer_pointer_gap(struct scrub_ctx *sctx, u64 physical)
{
 int ret = 0;
 u64 length;

 if (!btrfs_is_zoned(sctx->fs_info))
  return 0;

 if (!btrfs_dev_is_sequential(sctx->wr_tgtdev, physical))
  return 0;

 if (sctx->write_pointer < physical) {
  length = physical - sctx->write_pointer;

  ret = btrfs_zoned_issue_zeroout(sctx->wr_tgtdev,
      sctx->write_pointer, length);
  if (!ret)
   sctx->write_pointer = physical;
 }
 return ret;
}

static void *scrub_stripe_get_kaddr(struct scrub_stripe *stripe, int sector_nr)
{
 u32 offset = (sector_nr << stripe->bg->fs_info->sectorsize_bits);
 const struct page *page = stripe->pages[offset >> PAGE_SHIFT];

 /* stripe->pages[] is allocated by us and no highmem is allowed. */
 ASSERT(page);
 ASSERT(!PageHighMem(page));
 return page_address(page) + offset_in_page(offset);
}

static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr)
{
 struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
 const u32 sectors_per_tree = fs_info->nodesize >> fs_info->sectorsize_bits;
 const u64 logical = stripe->logical + (sector_nr << fs_info->sectorsize_bits);
 void *first_kaddr = scrub_stripe_get_kaddr(stripe, sector_nr);
 struct btrfs_header *header = first_kaddr;
 SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
 u8 on_disk_csum[BTRFS_CSUM_SIZE];
 u8 calculated_csum[BTRFS_CSUM_SIZE];

 /*
 * 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);
}

static void scrub_verify_one_sector(struct scrub_stripe *stripe, int sector_nr)
{
 struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
 struct scrub_sector_verification *sector = &stripe->sectors[sector_nr];
 const u32 sectors_per_tree = fs_info->nodesize >> fs_info->sectorsize_bits;
 void *kaddr = scrub_stripe_get_kaddr(stripe, sector_nr);
 u8 csum_buf[BTRFS_CSUM_SIZE];
 int ret;

 ASSERT(sector_nr >= 0 && sector_nr < stripe->nr_sectors);

 /* 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;
 }

 ret = btrfs_check_sector_csum(fs_info, kaddr, csum_buf, sector->csum);
 if (ret < 0) {
  scrub_bitmap_set_bit_csum_error(stripe, sector_nr);
  scrub_bitmap_set_bit_error(stripe, sector_nr);
 } else {
  scrub_bitmap_clear_bit_csum_error(stripe, sector_nr);
  scrub_bitmap_clear_bit_error(stripe, sector_nr);
 }
}

/* Verify specified sectors of a stripe. */
static void scrub_verify_one_stripe(struct scrub_stripe *stripe, unsigned long bitmap)
{
 struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
 const u32 sectors_per_tree = fs_info->nodesize >> fs_info->sectorsize_bits;
 int sector_nr;

 for_each_set_bit(sector_nr, &bitmap, stripe->nr_sectors) {
  scrub_verify_one_sector(stripe, sector_nr);
  if (scrub_bitmap_test_bit_is_metadata(stripe, sector_nr))
   sector_nr += sectors_per_tree - 1;
 }
}

static int 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
 */

static void 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;

 ASSERT(sector_nr < stripe->nr_sectors);

 bio_for_each_bvec_all(bvec, &bbio->bio, i)
  bio_size += bvec->bv_len;

 if (bbio->bio.bi_status) {
  scrub_bitmap_set_io_error(stripe, sector_nr,
       bio_size >> fs_info->sectorsize_bits);
  scrub_bitmap_set_error(stripe, sector_nr,
           bio_size >> fs_info->sectorsize_bits);
 } else {
  scrub_bitmap_clear_io_error(stripe, sector_nr,
       bio_size >> fs_info->sectorsize_bits);
 }
 bio_put(&bbio->bio);
 if (atomic_dec_and_test(&stripe->pending_io))
  wake_up(&stripe->io_wait);
}

static int calc_next_mirror(int mirror, int num_copies)
{
 ASSERT(mirror <= num_copies);
 return (mirror + 1 > num_copies) ? 1 : mirror + 1;
}

static void 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);
}

static void 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;
 const unsigned long old_error_bitmap = scrub_bitmap_read_error(stripe);
 int i;

 ASSERT(stripe->mirror_num >= 1);
 ASSERT(atomic_read(&stripe->pending_io) == 0);

 for_each_set_bit(i, &old_error_bitmap, stripe->nr_sectors) {
  /* The current sector cannot be merged, submit the bio. */
  if (bbio && ((i > 0 && !test_bit(i - 1, &old_error_bitmap)) ||
        bbio->bio.bi_iter.bi_size >= blocksize)) {
   ASSERT(bbio->bio.bi_iter.bi_size);
   atomic_inc(&stripe->pending_io);
   btrfs_submit_bbio(bbio, mirror);
   if (wait)
    wait_scrub_stripe_io(stripe);
   bbio = NULL;
  }

  if (!bbio) {
   bbio = btrfs_bio_alloc(stripe->nr_sectors, REQ_OP_READ,
    fs_info, scrub_repair_read_endio, stripe);
   bbio->bio.bi_iter.bi_sector = (stripe->logical +
    (i << fs_info->sectorsize_bits)) >> SECTOR_SHIFT;
  }

  scrub_bio_add_sector(bbio, stripe, i);
 }
 if (bbio) {
  ASSERT(bbio->bio.bi_iter.bi_size);
  atomic_inc(&stripe->pending_io);
  btrfs_submit_bbio(bbio, mirror);
  if (wait)
   wait_scrub_stripe_io(stripe);
 }
}

static void scrub_stripe_report_errors(struct scrub_ctx *sctx,
           struct scrub_stripe *stripe,
           const struct scrub_error_records *errors)
{
 static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
          DEFAULT_RATELIMIT_BURST);
 struct btrfs_fs_info *fs_info = sctx->fs_info;
 struct btrfs_device *dev = NULL;
 const unsigned long extent_bitmap = scrub_bitmap_read_has_extent(stripe);
 const unsigned long error_bitmap = scrub_bitmap_read_error(stripe);
 u64 physical = 0;
 int nr_data_sectors = 0;
 int nr_meta_sectors = 0;
 int nr_nodatacsum_sectors = 0;
 int nr_repaired_sectors = 0;
 int sector_nr;

 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);
 }

skip:
 for_each_set_bit(sector_nr, &extent_bitmap, stripe->nr_sectors) {
  bool repaired = false;

  if (scrub_bitmap_test_bit_is_metadata(stripe, sector_nr)) {
   nr_meta_sectors++;
  } else {
   nr_data_sectors++;
   if (!stripe->sectors[sector_nr].csum)
    nr_nodatacsum_sectors++;
  }

  if (test_bit(sector_nr, &errors->init_error_bitmap) &&
      !test_bit(sector_nr, &error_bitmap)) {
   nr_repaired_sectors++;
   repaired = true;
  }

  /* 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);

 spin_lock(&sctx->stat_lock);
 sctx->stat.data_extents_scrubbed += stripe->nr_data_extents;
 sctx->stat.tree_extents_scrubbed += stripe->nr_meta_extents;
 sctx->stat.data_bytes_scrubbed += nr_data_sectors << fs_info->sectorsize_bits;
 sctx->stat.tree_bytes_scrubbed += nr_meta_sectors << fs_info->sectorsize_bits;
 sctx->stat.no_csum += nr_nodatacsum_sectors;
 sctx->stat.read_errors += errors->nr_io_errors;
 sctx->stat.csum_errors += errors->nr_csum_errors;
 sctx->stat.verify_errors += errors->nr_meta_errors +
        errors->nr_meta_gen_errors;
 sctx->stat.uncorrectable_errors +=
  bitmap_weight(&error_bitmap, stripe->nr_sectors);
 sctx->stat.corrected_errors += nr_repaired_sectors;
 spin_unlock(&sctx->stat_lock);
}

static void scrub_write_sectors(struct scrub_ctx *sctx, struct scrub_stripe *stripe,
    unsigned long write_bitmap, bool dev_replace);

/*
 * 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.
 */

static void 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);
 unsigned long repaired;
 unsigned long 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)) {
  const unsigned long old_error_bitmap = scrub_bitmap_read_error(stripe);

  scrub_stripe_submit_repair_read(stripe, mirror,
      BTRFS_STRIPE_LEN, false);
  wait_scrub_stripe_io(stripe);
  scrub_verify_one_stripe(stripe, old_error_bitmap);
  if (scrub_bitmap_empty_error(stripe))
   goto out;
 }

 /*
 * 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)) {
  const unsigned long 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);
  }
 }

 scrub_stripe_report_errors(sctx, stripe, &errors);
 set_bit(SCRUB_STRIPE_FLAG_REPAIR_DONE, &stripe->state);
 wake_up(&stripe->repair_wait);
}

static void scrub_read_endio(struct btrfs_bio *bbio)
{
 struct scrub_stripe *stripe = bbio->private;
 struct bio_vec *bvec;
 int sector_nr = calc_sector_number(stripe, bio_first_bvec_all(&bbio->bio));
 int num_sectors;
 u32 bio_size = 0;
 int i;

 ASSERT(sector_nr < stripe->nr_sectors);
 bio_for_each_bvec_all(bvec, &bbio->bio, i)
  bio_size += bvec->bv_len;
 num_sectors = bio_size >> stripe->bg->fs_info->sectorsize_bits;

 if (bbio->bio.bi_status) {
  scrub_bitmap_set_io_error(stripe, sector_nr, num_sectors);
  scrub_bitmap_set_error(stripe, sector_nr, num_sectors);
 } else {
  scrub_bitmap_clear_io_error(stripe, sector_nr, num_sectors);
 }
 bio_put(&bbio->bio);
 if (atomic_dec_and_test(&stripe->pending_io)) {
  wake_up(&stripe->io_wait);
  INIT_WORK(&stripe->work, scrub_stripe_read_repair_worker);
  queue_work(stripe->bg->fs_info->scrub_workers, &stripe->work);
 }
}

static void scrub_write_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;

 bio_for_each_bvec_all(bvec, &bbio->bio, i)
  bio_size += bvec->bv_len;

 if (bbio->bio.bi_status) {
  unsigned long flags;

  spin_lock_irqsave(&stripe->write_error_lock, flags);
  bitmap_set(&stripe->write_error_bitmap, sector_nr,
      bio_size >> fs_info->sectorsize_bits);
  spin_unlock_irqrestore(&stripe->write_error_lock, flags);
  for (int i = 0; i < (bio_size >> fs_info->sectorsize_bits); i++)
   btrfs_dev_stat_inc_and_print(stripe->dev,
           BTRFS_DEV_STAT_WRITE_ERRS);
 }
 bio_put(&bbio->bio);

 if (atomic_dec_and_test(&stripe->pending_io))
  wake_up(&stripe->io_wait);
}

static void scrub_submit_write_bio(struct scrub_ctx *sctx,
       struct scrub_stripe *stripe,
       struct btrfs_bio *bbio, bool dev_replace)
{
 struct btrfs_fs_info *fs_info = sctx->fs_info;
 u32 bio_len = bbio->bio.bi_iter.bi_size;
 u32 bio_off = (bbio->bio.bi_iter.bi_sector << SECTOR_SHIFT) -
        stripe->logical;

 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
 */

static void scrub_write_sectors(struct scrub_ctx *sctx, struct scrub_stripe *stripe,
    unsigned long 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.
 */

static void scrub_throttle_dev_io(struct scrub_ctx *sctx, struct btrfs_device *device,
      unsigned int bio_size)
{
 const int 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;
 }

 if (delta) {
  long timeout;

  timeout = div_u64(delta * HZ, 1000);
  schedule_timeout_interruptible(timeout);
 }

 /* 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.
 */

static int 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;
 const int data_stripes = nr_data_stripes(map);

 last_offset = (physical - map->stripes[num].physical) * data_stripes;
 if (stripe_start)
  *stripe_start = last_offset;

 *offset = last_offset;
 for (i = 0; i < data_stripes; i++) {
  u32 stripe_nr;
  u32 stripe_index;
  u32 rot;

  *offset = last_offset + btrfs_stripe_nr_to_offset(i);

  stripe_nr = (u32)(*offset >> BTRFS_STRIPE_LEN_SHIFT) / data_stripes;

  /* 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.
 */

static int 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.
 */

static int 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;

 key.objectid = search_start;
 if (btrfs_fs_incompat(fs_info, SKINNY_METADATA))
  key.type = BTRFS_METADATA_ITEM_KEY;
 else
  key.type = BTRFS_EXTENT_ITEM_KEY;
 key.offset = (u64)-1;

 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;
}

static void get_extent_info(struct btrfs_path *path, u64 *extent_start_ret,
       u64 *size_ret, u64 *flags_ret, u64 *generation_ret)
{
 struct btrfs_key key;
 struct btrfs_extent_item *ei;

 btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
 ASSERT(key.type == BTRFS_METADATA_ITEM_KEY ||
        key.type == BTRFS_EXTENT_ITEM_KEY);
 *extent_start_ret = key.objectid;
 if (key.type == BTRFS_METADATA_ITEM_KEY)
  *size_ret = path->nodes[0]->fs_info->nodesize;
 else
  *size_ret = key.offset;
 ei = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_extent_item);
 *flags_ret = btrfs_extent_flags(path->nodes[0], ei);
 *generation_ret = btrfs_extent_generation(path->nodes[0], ei);
}

static int sync_write_pointer_for_zoned(struct scrub_ctx *sctx, u64 logical,
     u64 physical, u64 physical_end)
{
 struct btrfs_fs_info *fs_info = sctx->fs_info;
 int ret = 0;

 if (!btrfs_is_zoned(fs_info))
  return 0;

 mutex_lock(&sctx->wr_lock);
 if (sctx->write_pointer < physical_end) {
  ret = btrfs_sync_zone_write_pointer(sctx->wr_tgtdev, logical,
          physical,
          sctx->write_pointer);
  if (ret)
   btrfs_err(fs_info, "scrub: zoned: failed to recover write pointer");
 }
 mutex_unlock(&sctx->wr_lock);
 btrfs_dev_clear_zone_empty(sctx->wr_tgtdev, physical);

 return ret;
}

static void fill_one_extent_info(struct btrfs_fs_info *fs_info,
     struct scrub_stripe *stripe,
     u64 extent_start, u64 extent_len,
     u64 extent_flags, u64 extent_gen)
{
 for (u64 cur_logical = max(stripe->logical, extent_start);
      cur_logical < min(stripe->logical + BTRFS_STRIPE_LEN,
          extent_start + extent_len);
      cur_logical += fs_info->sectorsize) {
  const int nr_sector = (cur_logical - stripe->logical) >>
          fs_info->sectorsize_bits;
  struct scrub_sector_verification *sector =
      &stripe->sectors[nr_sector];

  scrub_bitmap_set_bit_has_extent(stripe, nr_sector);
  if (extent_flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
   scrub_bitmap_set_bit_is_metadata(stripe, nr_sector);
   sector->generation = extent_gen;
  }
 }
}

static void scrub_stripe_reset_bitmaps(struct scrub_stripe *stripe)
{
 ASSERT(stripe->nr_sectors);
 bitmap_zero(stripe->bitmaps, scrub_bitmap_nr_last * stripe->nr_sectors);
}

/*
 * 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.
 */

static int 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;
  unsigned long 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(sector_nr, &csum_bitmap, stripe->nr_sectors) {
   stripe->sectors[sector_nr].csum = stripe->csums +
    sector_nr * fs_info->csum_size;
  }
 }
 set_bit(SCRUB_STRIPE_FLAG_INITIALIZED, &stripe->state);
out:
 return ret;
}

static void scrub_reset_stripe(struct scrub_stripe *stripe)
{
 scrub_stripe_reset_bitmaps(stripe);

 stripe->nr_meta_extents = 0;
 stripe->nr_data_extents = 0;
 stripe->state = 0;

 for (int i = 0; i < stripe->nr_sectors; i++) {
  stripe->sectors[i].csum = NULL;
  stripe->sectors[i].generation = 0;
 }
}

static u32 stripe_length(const struct scrub_stripe *stripe)
{
 ASSERT(stripe->bg);

 return min(BTRFS_STRIPE_LEN,
     stripe->bg->start + stripe->bg->length - stripe->logical);
}

static void scrub_submit_extent_sector_read(struct scrub_stripe *stripe)
{
 struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
 struct btrfs_bio *bbio = NULL;
 unsigned int nr_sectors = stripe_length(stripe) >> fs_info->sectorsize_bits;
 const unsigned long has_extent = scrub_bitmap_read_has_extent(stripe);
 u64 stripe_len = BTRFS_STRIPE_LEN;
 int mirror = stripe->mirror_num;
 int i;

 atomic_inc(&stripe->pending_io);

 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 = btrfs_bio_alloc(stripe->nr_sectors, REQ_OP_READ,
            fs_info, scrub_read_endio, stripe);
   bbio->bio.bi_iter.bi_sector = logical >> SECTOR_SHIFT;
  }

  scrub_bio_add_sector(bbio, stripe, i);
 }

 if (bbio) {
  ASSERT(bbio->bio.bi_iter.bi_size);
  atomic_inc(&stripe->pending_io);
  btrfs_submit_bbio(bbio, mirror);
 }

 if (atomic_dec_and_test(&stripe->pending_io)) {
  wake_up(&stripe->io_wait);
  INIT_WORK(&stripe->work, scrub_stripe_read_repair_worker);
  queue_work(stripe->bg->fs_info->scrub_workers, &stripe->work);
 }
}

static void scrub_submit_initial_read(struct scrub_ctx *sctx,
          struct scrub_stripe *stripe)
{
 struct btrfs_fs_info *fs_info = sctx->fs_info;
 struct btrfs_bio *bbio;
 unsigned int nr_sectors = stripe_length(stripe) >> fs_info->sectorsize_bits;
 int mirror = stripe->mirror_num;

 ASSERT(stripe->bg);
 ASSERT(stripe->mirror_num > 0);
 ASSERT(test_bit(SCRUB_STRIPE_FLAG_INITIALIZED, &stripe->state));

 if (btrfs_need_stripe_tree_update(fs_info, stripe->bg->flags)) {
  scrub_submit_extent_sector_read(stripe);
  return;
 }

 bbio = btrfs_bio_alloc(SCRUB_STRIPE_PAGES, REQ_OP_READ, fs_info,
          scrub_read_endio, stripe);

 bbio->bio.bi_iter.bi_sector = stripe->logical >> SECTOR_SHIFT;
 /* Read the whole range inside the chunk boundary. */
 for (unsigned int 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);

  mirror = calc_next_mirror(mirror, num_copies);
 }
 btrfs_submit_bbio(bbio, mirror);
}

static bool stripe_has_metadata_error(struct scrub_stripe *stripe)
{
 const unsigned long error = scrub_bitmap_read_error(stripe);
 int i;

 for_each_set_bit(i, &error, stripe->nr_sectors) {
  if (scrub_bitmap_test_bit_is_metadata(stripe, i)) {
   struct btrfs_fs_info *fs_info = stripe->bg->fs_info;

   btrfs_err(fs_info,
      "scrub: stripe %llu has unrepaired metadata sector at logical %llu",
      stripe->logical,
      stripe->logical + (i << fs_info->sectorsize_bits));
   return true;
  }
 }
 return false;
}

static void submit_initial_group_read(struct scrub_ctx *sctx,
          unsigned int first_slot,
          unsigned int nr_stripes)
{
 struct blk_plug plug;

 ASSERT(first_slot < SCRUB_TOTAL_STRIPES);
 ASSERT(first_slot + nr_stripes <= SCRUB_TOTAL_STRIPES);

 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);
}

static int flush_scrub_stripes(struct scrub_ctx *sctx)
{
 struct btrfs_fs_info *fs_info = sctx->fs_info;
 struct scrub_stripe *stripe;
 const int nr_stripes = sctx->cur_stripe;
 int ret = 0;

 if (!nr_stripes)
  return 0;

 ASSERT(test_bit(SCRUB_STRIPE_FLAG_INITIALIZED, &sctx->stripes[0].state));

 /* Submit the stripes which are populated but not submitted. */
 if (nr_stripes % SCRUB_STRIPES_PER_GROUP) {
  const int first_slot = round_down(nr_stripes, SCRUB_STRIPES_PER_GROUP);

  submit_initial_group_read(sctx, first_slot, nr_stripes - first_slot);
 }

 for (int i = 0; i < nr_stripes; i++) {
  stripe = &sctx->stripes[i];

  wait_event(stripe->repair_wait,
      test_bit(SCRUB_STRIPE_FLAG_REPAIR_DONE, &stripe->state));
 }

 /* 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++) {
   unsigned long good;
   unsigned long has_extent;
   unsigned long error;

   stripe = &sctx->stripes[i];

   ASSERT(stripe->dev == fs_info->dev_replace.srcdev);

   has_extent = scrub_bitmap_read_has_extent(stripe);
   error = scrub_bitmap_read_error(stripe);
   bitmap_andnot(&good, &has_extent, &error, stripe->nr_sectors);
   scrub_write_sectors(sctx, stripe, good, true);
  }
 }

 /* Wait for the above writebacks to finish. */
 for (int i = 0; i < nr_stripes; i++) {
  stripe = &sctx->stripes[i];

  wait_scrub_stripe_io(stripe);
  spin_lock(&sctx->stat_lock);
  sctx->stat.last_physical = stripe->physical + stripe_length(stripe);
  spin_unlock(&sctx->stat_lock);
  scrub_reset_stripe(stripe);
 }
out:
 sctx->cur_stripe = 0;
 return ret;
}

static void raid56_scrub_wait_endio(struct bio *bio)
{
 complete(bio->bi_private);
}

static int queue_scrub_stripe(struct scrub_ctx *sctx, struct btrfs_block_group *bg,
         struct btrfs_device *dev, int mirror_num,
         u64 logical, u32 length, u64 physical,
         u64 *found_logical_ret)
{
 struct scrub_stripe *stripe;
 int ret;

 /*
 * 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) {
  const int first_slot = sctx->cur_stripe - SCRUB_STRIPES_PER_GROUP;

  submit_initial_group_read(sctx, first_slot, SCRUB_STRIPES_PER_GROUP);
 }

 /* Last slot used, flush them all. */
 if (sctx->cur_stripe == SCRUB_TOTAL_STRIPES)
  return flush_scrub_stripes(sctx);
 return 0;
}

static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx,
          struct btrfs_device *scrub_dev,
          struct btrfs_block_group *bg,
          struct btrfs_chunk_map *map,
          u64 full_stripe_start)
{
 DECLARE_COMPLETION_ONSTACK(io_done);
 struct btrfs_fs_info *fs_info = sctx->fs_info;
 struct btrfs_raid_bio *rbio;
 struct btrfs_io_context *bioc = NULL;
 struct btrfs_path extent_path = { 0 };
 struct btrfs_path csum_path = { 0 };
 struct bio *bio;
 struct scrub_stripe *stripe;
 bool all_empty = true;
 const int data_stripes = nr_data_stripes(map);
 unsigned long extent_bitmap = 0;
 u64 length = btrfs_stripe_nr_to_offset(data_stripes);
 int ret;

 ASSERT(sctx->raid56_data_stripes);

 /*
 * 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;

  stripe = &sctx->raid56_data_stripes[i];
  rot = div_u64(full_stripe_start - bg->start,
         data_stripes) >> BTRFS_STRIPE_LEN_SHIFT;
  stripe_index = (i + rot) % map->num_stripes;
  physical = map->stripes[stripe_index].physical +
      btrfs_stripe_nr_to_offset(rot);

  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++) {
  unsigned long error;
  unsigned long has_extent;

  stripe = &sctx->raid56_data_stripes[i];

  error = scrub_bitmap_read_error(stripe);
  has_extent = scrub_bitmap_read_has_extent(stripe);

  /*
 * 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;
 }
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=92 G=93

¤ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.