btrfs: provide btrfs_page_clamp_*() helpers
authorQu Wenruo <wqu@suse.com>
Mon, 31 May 2021 08:50:39 +0000 (16:50 +0800)
committerDavid Sterba <dsterba@suse.com>
Mon, 21 Jun 2021 13:19:09 +0000 (15:19 +0200)
In the coming subpage RW supports, there are a lot of page status update
calls which need to be converted to subpage compatible version, which
needs @start and @len.

Some call sites already have such @start/@len and are already in
page range, like various endio functions.

But there are also call sites which need to clamp the range for subpage
case, like btrfs_dirty_pagse() and __process_contig_pages().

Here we introduce new helpers, btrfs_page_clamp_*(), to do and only do the
clamp for subpage version.

Although in theory all existing btrfs_page_*() calls can be converted to
use btrfs_page_clamp_*() directly, but that would make us to do
unnecessary clamp operations.

Tested-by: Ritesh Harjani <riteshh@linux.ibm.com> # [ppc64]
Tested-by: Anand Jain <anand.jain@oracle.com> # [aarch64]
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/subpage.c
fs/btrfs/subpage.h

index 2d19089..a6cf177 100644 (file)
@@ -354,6 +354,16 @@ void btrfs_subpage_clear_writeback(const struct btrfs_fs_info *fs_info,
        spin_unlock_irqrestore(&subpage->lock, flags);
 }
 
+static void btrfs_subpage_clamp_range(struct page *page, u64 *start, u32 *len)
+{
+       u64 orig_start = *start;
+       u32 orig_len = *len;
+
+       *start = max_t(u64, page_offset(page), orig_start);
+       *len = min_t(u64, page_offset(page) + PAGE_SIZE,
+                    orig_start + orig_len) - *start;
+}
+
 /*
  * Unlike set/clear which is dependent on each page status, for test all bits
  * are tested in the same way.
@@ -408,6 +418,34 @@ bool btrfs_page_test_##name(const struct btrfs_fs_info *fs_info,   \
        if (unlikely(!fs_info) || fs_info->sectorsize == PAGE_SIZE)     \
                return test_page_func(page);                            \
        return btrfs_subpage_test_##name(fs_info, page, start, len);    \
+}                                                                      \
+void btrfs_page_clamp_set_##name(const struct btrfs_fs_info *fs_info,  \
+               struct page *page, u64 start, u32 len)                  \
+{                                                                      \
+       if (unlikely(!fs_info) || fs_info->sectorsize == PAGE_SIZE) {   \
+               set_page_func(page);                                    \
+               return;                                                 \
+       }                                                               \
+       btrfs_subpage_clamp_range(page, &start, &len);                  \
+       btrfs_subpage_set_##name(fs_info, page, start, len);            \
+}                                                                      \
+void btrfs_page_clamp_clear_##name(const struct btrfs_fs_info *fs_info, \
+               struct page *page, u64 start, u32 len)                  \
+{                                                                      \
+       if (unlikely(!fs_info) || fs_info->sectorsize == PAGE_SIZE) {   \
+               clear_page_func(page);                                  \
+               return;                                                 \
+       }                                                               \
+       btrfs_subpage_clamp_range(page, &start, &len);                  \
+       btrfs_subpage_clear_##name(fs_info, page, start, len);          \
+}                                                                      \
+bool btrfs_page_clamp_test_##name(const struct btrfs_fs_info *fs_info, \
+               struct page *page, u64 start, u32 len)                  \
+{                                                                      \
+       if (unlikely(!fs_info) || fs_info->sectorsize == PAGE_SIZE)     \
+               return test_page_func(page);                            \
+       btrfs_subpage_clamp_range(page, &start, &len);                  \
+       return btrfs_subpage_test_##name(fs_info, page, start, len);    \
 }
 IMPLEMENT_BTRFS_PAGE_OPS(uptodate, SetPageUptodate, ClearPageUptodate,
                         PageUptodate);
index bfd626e..291cb19 100644 (file)
@@ -72,6 +72,10 @@ void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info,
  * btrfs_page_*() are for call sites where the page can either be subpage
  * specific or regular page. The function will handle both cases.
  * But the range still needs to be inside the page.
+ *
+ * btrfs_page_clamp_*() are similar to btrfs_page_*(), except the range doesn't
+ * need to be inside the page. Those functions will truncate the range
+ * automatically.
  */
 #define DECLARE_BTRFS_SUBPAGE_OPS(name)                                        \
 void btrfs_subpage_set_##name(const struct btrfs_fs_info *fs_info,     \
@@ -85,6 +89,12 @@ void btrfs_page_set_##name(const struct btrfs_fs_info *fs_info,              \
 void btrfs_page_clear_##name(const struct btrfs_fs_info *fs_info,      \
                struct page *page, u64 start, u32 len);                 \
 bool btrfs_page_test_##name(const struct btrfs_fs_info *fs_info,       \
+               struct page *page, u64 start, u32 len);                 \
+void btrfs_page_clamp_set_##name(const struct btrfs_fs_info *fs_info,  \
+               struct page *page, u64 start, u32 len);                 \
+void btrfs_page_clamp_clear_##name(const struct btrfs_fs_info *fs_info,        \
+               struct page *page, u64 start, u32 len);                 \
+bool btrfs_page_clamp_test_##name(const struct btrfs_fs_info *fs_info, \
                struct page *page, u64 start, u32 len);
 
 DECLARE_BTRFS_SUBPAGE_OPS(uptodate);