btrfs: scrub: refactor scrub_find_csum()
authorQu Wenruo <wqu@suse.com>
Tue, 3 Nov 2020 13:31:04 +0000 (21:31 +0800)
committerDavid Sterba <dsterba@suse.com>
Tue, 8 Dec 2020 14:54:05 +0000 (15:54 +0100)
Function scrub_find_csum() is to locate the csum for bytenr @logical
from sctx->csum_list.

However it lacks a lot of comments to explain things like how the
csum_list is organized and why we need to drop csum range which is
before us.

Refactor the function by:

- Add more comments explaining the behavior
- Add comment explaining why we need to drop the csum range
- Put the csum copy in the main loop
  This is mostly for the incoming patches to make scrub_find_csum() able
  to find multiple checksums.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/scrub.c

index 7ca11ea001a146598f1090ec13b962b49b6d4510..57ee06d9215025a9c762f80ec6a691e9400bbd02 100644 (file)
@@ -2362,38 +2362,65 @@ static void scrub_block_complete(struct scrub_block *sblock)
        }
 }
 
+static void drop_csum_range(struct scrub_ctx *sctx, struct btrfs_ordered_sum *sum)
+{
+       sctx->stat.csum_discards += sum->len >> sctx->fs_info->sectorsize_bits;
+       list_del(&sum->list);
+       kfree(sum);
+}
+
+/*
+ * Find the desired csum for range [logical, logical + sectorsize), and store
+ * the csum into @csum.
+ *
+ * The search source is sctx->csum_list, which is a pre-populated list
+ * storing bytenr ordered csum ranges.  We're reponsible to cleanup any range
+ * that is before @logical.
+ *
+ * Return 0 if there is no csum for the range.
+ * Return 1 if there is csum for the range and copied to @csum.
+ */
 static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u8 *csum)
 {
-       struct btrfs_ordered_sum *sum = NULL;
-       unsigned long index;
-       unsigned long num_sectors;
+       bool found = false;
 
        while (!list_empty(&sctx->csum_list)) {
+               struct btrfs_ordered_sum *sum = NULL;
+               unsigned long index;
+               unsigned long num_sectors;
+
                sum = list_first_entry(&sctx->csum_list,
                                       struct btrfs_ordered_sum, list);
+               /* The current csum range is beyond our range, no csum found */
                if (sum->bytenr > logical)
-                       return 0;
-               if (sum->bytenr + sum->len > logical)
                        break;
 
-               ++sctx->stat.csum_discards;
-               list_del(&sum->list);
-               kfree(sum);
-               sum = NULL;
-       }
-       if (!sum)
-               return 0;
+               /*
+                * The current sum is before our bytenr, since scrub is always
+                * done in bytenr order, the csum will never be used anymore,
+                * clean it up so that later calls won't bother with the range,
+                * and continue search the next range.
+                */
+               if (sum->bytenr + sum->len <= logical) {
+                       drop_csum_range(sctx, sum);
+                       continue;
+               }
 
-       index = (logical - sum->bytenr) >> sctx->fs_info->sectorsize_bits;
-       ASSERT(index < UINT_MAX);
+               /* Now the csum range covers our bytenr, copy the csum */
+               found = true;
+               index = (logical - sum->bytenr) >> sctx->fs_info->sectorsize_bits;
+               num_sectors = sum->len >> sctx->fs_info->sectorsize_bits;
 
-       num_sectors = sum->len >> sctx->fs_info->sectorsize_bits;
-       memcpy(csum, sum->sums + index * sctx->fs_info->csum_size,
-               sctx->fs_info->csum_size);
-       if (index == num_sectors - 1) {
-               list_del(&sum->list);
-               kfree(sum);
+               memcpy(csum, sum->sums + index * sctx->fs_info->csum_size,
+                      sctx->fs_info->csum_size);
+
+               /* Cleanup the range if we're at the end of the csum range */
+               if (index == num_sectors - 1)
+                       drop_csum_range(sctx, sum);
+               break;
        }
+       if (!found)
+               return 0;
        return 1;
 }