]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
btrfs: make subpage attach and detach handle metadata properly
authorQu Wenruo <wqu@suse.com>
Tue, 28 Jan 2025 05:24:40 +0000 (15:54 +1030)
committerDavid Sterba <dsterba@suse.com>
Tue, 18 Mar 2025 19:35:41 +0000 (20:35 +0100)
Currently subpage attach/detach is not doing proper dummy extent buffer
subpage check, as btrfs_is_subpage() is not reliable for dummy extent
buffer folios.

Since we have a metadata specific check now, use that for
btrfs_attach_subpage() first.

Then enhance btrfs_detach_subpage() to accept a type parameter, so that
we can do extra checks for dummy extent buffers properly.

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/extent_io.c
fs/btrfs/subpage.c
fs/btrfs/subpage.h

index c1afd8aab77c251d78f211f21f2d8d0efdd795fa..089fb6cecbba5115cd024e2d7f733ec0ecc74ca3 100644 (file)
@@ -888,7 +888,7 @@ void clear_folio_extent_mapped(struct folio *folio)
 
        fs_info = folio_to_fs_info(folio);
        if (btrfs_is_subpage(fs_info, folio->mapping))
-               return btrfs_detach_subpage(fs_info, folio);
+               return btrfs_detach_subpage(fs_info, folio, BTRFS_SUBPAGE_DATA);
 
        folio_detach_private(folio);
 }
@@ -2622,7 +2622,7 @@ static void detach_extent_buffer_folio(const struct extent_buffer *eb, struct fo
         * attached to one dummy eb, no sharing.
         */
        if (!mapped) {
-               btrfs_detach_subpage(fs_info, folio);
+               btrfs_detach_subpage(fs_info, folio, BTRFS_SUBPAGE_METADATA);
                return;
        }
 
@@ -2633,7 +2633,7 @@ static void detach_extent_buffer_folio(const struct extent_buffer *eb, struct fo
         * page range and no unfinished IO.
         */
        if (!folio_range_has_eb(folio))
-               btrfs_detach_subpage(fs_info, folio);
+               btrfs_detach_subpage(fs_info, folio, BTRFS_SUBPAGE_METADATA);
 
        spin_unlock(&folio->mapping->i_private_lock);
 }
index e34694f0cdcc9a76309036bacfedd2fee737c2dd..073eca132292f5f211d70a0477324c0455c9be3e 100644 (file)
@@ -104,7 +104,11 @@ int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info,
                ASSERT(folio_test_locked(folio));
 
        /* Either not subpage, or the folio already has private attached. */
-       if (!btrfs_is_subpage(fs_info, folio->mapping) || folio_test_private(folio))
+       if (folio_test_private(folio))
+               return 0;
+       if (type == BTRFS_SUBPAGE_METADATA && !btrfs_meta_is_subpage(fs_info))
+               return 0;
+       if (type == BTRFS_SUBPAGE_DATA && !btrfs_is_subpage(fs_info, folio->mapping))
                return 0;
 
        subpage = btrfs_alloc_subpage(fs_info, type);
@@ -115,12 +119,17 @@ int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info,
        return 0;
 }
 
-void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info, struct folio *folio)
+void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info, struct folio *folio,
+                         enum btrfs_subpage_type type)
 {
        struct btrfs_subpage *subpage;
 
        /* Either not subpage, or the folio already has private attached. */
-       if (!btrfs_is_subpage(fs_info, folio->mapping) || !folio_test_private(folio))
+       if (!folio_test_private(folio))
+               return;
+       if (type == BTRFS_SUBPAGE_METADATA && !btrfs_meta_is_subpage(fs_info))
+               return;
+       if (type == BTRFS_SUBPAGE_DATA && !btrfs_is_subpage(fs_info, folio->mapping))
                return;
 
        subpage = folio_detach_private(folio);
index 7aacf5ff029692d9f80d1234d0d7a4777762066d..4de61ee938592bcb1695fc66054909859baee16f 100644 (file)
@@ -98,7 +98,8 @@ static inline bool btrfs_is_subpage(const struct btrfs_fs_info *fs_info,
 
 int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info,
                         struct folio *folio, enum btrfs_subpage_type type);
-void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info, struct folio *folio);
+void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info, struct folio *folio,
+                         enum btrfs_subpage_type type);
 
 /* Allocate additional data where page represents more than one sector */
 struct btrfs_subpage *btrfs_alloc_subpage(const struct btrfs_fs_info *fs_info,