btrfs: subpage: introduce btrfs_subpage_bitmap_info
authorQu Wenruo <wqu@suse.com>
Tue, 17 Aug 2021 09:38:51 +0000 (17:38 +0800)
committerDavid Sterba <dsterba@suse.com>
Mon, 25 Oct 2021 19:17:16 +0000 (21:17 +0200)
Currently we use fixed size u16 bitmap for subpage bitmap.  This is fine
for 4K sectorsize with 64K page size.

But for 4K sectorsize and larger page size, the bitmap is too small,
while for smaller page size like 16K, u16 bitmaps waste too much space.

Here we introduce a new helper structure, btrfs_subpage_bitmap_info, to
record the proper bitmap size, and where each bitmap should start at.

By this, we can later compact all subpage bitmaps into one u32 bitmap.
This patch is the first step.

Reviewed-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/subpage.c
fs/btrfs/subpage.h

index c0cebcf745cefdbe94ac83f3605acc380ef18a5c..8736347d1fa36136adc2bf21c09f1b6e204f0d46 100644 (file)
@@ -899,6 +899,7 @@ struct btrfs_fs_info {
        struct btrfs_workqueue *scrub_workers;
        struct btrfs_workqueue *scrub_wr_completion_workers;
        struct btrfs_workqueue *scrub_parity_workers;
+       struct btrfs_subpage_info *subpage_info;
 
        struct btrfs_discard_ctl discard_ctl;
 
index 355ea88d5c5f72113924e3bb891c89dcbe9d342b..71aafe9606e045358a4724e5b6ee1e9eba5e59b8 100644 (file)
@@ -1644,6 +1644,7 @@ void btrfs_free_fs_info(struct btrfs_fs_info *fs_info)
        btrfs_extent_buffer_leak_debug_check(fs_info);
        kfree(fs_info->super_copy);
        kfree(fs_info->super_for_commit);
+       kfree(fs_info->subpage_info);
        kvfree(fs_info);
 }
 
@@ -3392,12 +3393,12 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
                goto fail_alloc;
        }
 
-       if (sectorsize != PAGE_SIZE) {
+       if (sectorsize < PAGE_SIZE) {
+               struct btrfs_subpage_info *subpage_info;
+
                btrfs_warn(fs_info,
                "read-write for sector size %u with page size %lu is experimental",
                           sectorsize, PAGE_SIZE);
-       }
-       if (sectorsize != PAGE_SIZE) {
                if (btrfs_super_incompat_flags(fs_info->super_copy) &
                        BTRFS_FEATURE_INCOMPAT_RAID56) {
                        btrfs_err(fs_info,
@@ -3406,6 +3407,11 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
                        err = -EINVAL;
                        goto fail_alloc;
                }
+               subpage_info = kzalloc(sizeof(*subpage_info), GFP_KERNEL);
+               if (!subpage_info)
+                       goto fail_alloc;
+               btrfs_init_subpage_info(subpage_info, sectorsize);
+               fs_info->subpage_info = subpage_info;
        }
 
        ret = btrfs_init_workqueues(fs_info, fs_devices);
index 03dcc35d7d0b3a50f8c8916ff9899ddf0a11392f..f127bac6d6101b813fd1f276bc2c162f39e6b6f7 100644 (file)
  *   This means a slightly higher tree locking latency.
  */
 
+void btrfs_init_subpage_info(struct btrfs_subpage_info *subpage_info, u32 sectorsize)
+{
+       unsigned int cur = 0;
+       unsigned int nr_bits;
+
+       ASSERT(IS_ALIGNED(PAGE_SIZE, sectorsize));
+
+       nr_bits = PAGE_SIZE / sectorsize;
+       subpage_info->bitmap_nr_bits = nr_bits;
+
+       subpage_info->uptodate_offset = cur;
+       cur += nr_bits;
+
+       subpage_info->error_offset = cur;
+       cur += nr_bits;
+
+       subpage_info->dirty_offset = cur;
+       cur += nr_bits;
+
+       subpage_info->writeback_offset = cur;
+       cur += nr_bits;
+
+       subpage_info->ordered_offset = cur;
+       cur += nr_bits;
+
+       subpage_info->total_nr_bits = cur;
+}
+
 int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info,
                         struct page *page, enum btrfs_subpage_type type)
 {
index fdcadc5193c1d9fa703f6f55335a8322900dad58..386246a7770f3565e86853145f119f9b1a367862 100644 (file)
  */
 #define BTRFS_SUBPAGE_BITMAP_SIZE      16
 
+/*
+ * Extra info for subpapge bitmap.
+ *
+ * For subpage we pack all uptodate/error/dirty/writeback/ordered bitmaps into
+ * one larger bitmap.
+ *
+ * This structure records how they are organized in the bitmap:
+ *
+ * /- uptodate_offset  /- error_offset /- dirty_offset
+ * |                   |               |
+ * v                   v               v
+ * |u|u|u|u|........|u|u|e|e|.......|e|e| ...  |o|o|
+ * |<- bitmap_nr_bits ->|
+ * |<--------------- total_nr_bits ---------------->|
+ */
+struct btrfs_subpage_info {
+       /* Number of bits for each bitmap */
+       unsigned int bitmap_nr_bits;
+
+       /* Total number of bits for the whole bitmap */
+       unsigned int total_nr_bits;
+
+       /*
+        * *_start indicates where the bitmap starts, the length is always
+        * @bitmap_size, which is calculated from PAGE_SIZE / sectorsize.
+        */
+       unsigned int uptodate_offset;
+       unsigned int error_offset;
+       unsigned int dirty_offset;
+       unsigned int writeback_offset;
+       unsigned int ordered_offset;
+};
+
 /*
  * Structure to trace status of each sector inside a page, attached to
  * page::private for both data and metadata inodes.
@@ -53,6 +86,7 @@ enum btrfs_subpage_type {
        BTRFS_SUBPAGE_DATA,
 };
 
+void btrfs_init_subpage_info(struct btrfs_subpage_info *subpage_info, u32 sectorsize);
 int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info,
                         struct page *page, enum btrfs_subpage_type type);
 void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info,