btrfs: scrub: introduce structure for new BTRFS_STRIPE_LEN based interface
[sfrench/cifs-2.6.git] / fs / btrfs / scrub.c
index f182a1ba61ea3ece290f1f70c5a8b2cbd5592922..26763113b19b70dd050c53e4c34ebba96a733d22 100644 (file)
@@ -70,6 +70,94 @@ struct scrub_ctx;
  */
 #define BTRFS_MAX_MIRRORS (4 + 1)
 
+/* Represent one sector and its needed info to verify the content. */
+struct scrub_sector_verification {
+       bool is_metadata;
+
+       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,
+};
+
+#define SCRUB_STRIPE_PAGES             (BTRFS_STRIPE_LEN / PAGE_SIZE)
+
+/*
+ * Represent one contiguous range with a length of BTRFS_STRIPE_LEN.
+ */
+struct scrub_stripe {
+       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;
+
+       atomic_t pending_io;
+       wait_queue_head_t io_wait;
+
+       /*
+        * Indicate the states of the stripe.  Bits are defined in
+        * scrub_stripe_flags enum.
+        */
+       unsigned long state;
+
+       /* Indicate which sectors are covered by extent items. */
+       unsigned long extent_sector_bitmap;
+
+       /*
+        * The errors hit during the initial read of the stripe.
+        *
+        * Would be utilized for error reporting and repair.
+        */
+       unsigned long init_error_bitmap;
+
+       /*
+        * The following error bitmaps are all for the current status.
+        * Every time we submit a new read, these bitmaps may be updated.
+        *
+        * error_bitmap = io_error_bitmap | csum_error_bitmap | meta_error_bitmap;
+        *
+        * IO and csum errors can happen for both metadata and data.
+        */
+       unsigned long error_bitmap;
+       unsigned long io_error_bitmap;
+       unsigned long csum_error_bitmap;
+       unsigned long meta_error_bitmap;
+
+       /*
+        * Checksum for the whole stripe if this stripe is inside a data block
+        * group.
+        */
+       u8 *csums;
+};
+
 struct scrub_recover {
        refcount_t              refs;
        struct btrfs_io_context *bioc;
@@ -266,6 +354,60 @@ static void detach_scrub_page_private(struct page *page)
 #endif
 }
 
+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->state = 0;
+}
+
+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);
+       atomic_set(&stripe->pending_io, 0);
+
+       ret = btrfs_alloc_page_array(SCRUB_STRIPE_PAGES, stripe->pages);
+       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;
+}
+
+void wait_scrub_stripe_io(struct scrub_stripe *stripe)
+{
+       wait_event(stripe->io_wait, atomic_read(&stripe->pending_io) == 0);
+}
+
 static struct scrub_block *alloc_scrub_block(struct scrub_ctx *sctx,
                                             struct btrfs_device *dev,
                                             u64 logical, u64 physical,