From 6003c20dbd87ec5ab68ef9c1872096b4915ab195 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 31 Jul 2026 10:14:50 +0930 Subject: [PATCH] btrfs: add extra ASSERT()s to make sure the folio size is correct Inspired by the previous crash exposed by generic/795, we want to make sure every folio from btrfs page cache is properly aligned to block size. This is especially important for bs > ps support, as every btrfs infrastructure, e.g. extent map and extent state, requires strong block alignment checks. Furthermore, also output the minimal folio order from the inode mapping, which is the determining factor during debugging, helping a lot pinning down the final cause. Reviewed-by: Filipe Manana Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- fs/btrfs/extent_io.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index fa9f45cd7652..d7600e5fa3d9 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1392,6 +1392,22 @@ static void lock_extents_for_read(struct btrfs_inode *inode, u64 start, u64 end, } } +static void assert_folio_range(const struct btrfs_inode *inode, + u64 start, u64 end) +{ + const u32 blocksize = inode->root->fs_info->sectorsize; + + /* + * For btrfs page cache, a folio always contains at least one block, + * so the range should always be block size aligned. + */ + ASSERT(IS_ALIGNED(start, blocksize) && IS_ALIGNED(end + 1, blocksize), + "blocksize=%u root=%lld ino=%llu start=%llu end=%llu mapping min order=%u", + blocksize, btrfs_root_id(inode->root), btrfs_ino(inode), + start, end, + mapping_min_folio_order(inode->vfs_inode.i_mapping)); +} + int btrfs_read_folio(struct file *file, struct folio *folio) { struct inode *vfs_inode = folio->mapping->host; @@ -1407,6 +1423,7 @@ int btrfs_read_folio(struct file *file, struct folio *folio) struct fsverity_info *vi = NULL; int ret; + assert_folio_range(inode, start, end); lock_extents_for_read(inode, start, end, &cached_state); if (folio_pos(folio) < i_size_read(vfs_inode)) vi = fsverity_get_info(vfs_inode); @@ -1914,6 +1931,7 @@ static noinline_for_stack int extent_writepage_io(struct btrfs_inode *inode, ASSERT(start >= folio_start, "start=%llu folio_start=%llu", start, folio_start); ASSERT(end <= folio_end, "start=%llu len=%u folio_start=%llu folio_size=%zu", start, len, folio_start, folio_size(folio)); + assert_folio_range(inode, folio_start, folio_end - 1); /* * We are about to checksum and write out the data, so it must not be @@ -2976,6 +2994,7 @@ void btrfs_readahead(struct readahead_control *rac) struct extent_map *em_cached = NULL; struct fsverity_info *vi = NULL; + assert_folio_range(inode, start, end); lock_extents_for_read(inode, start, end, &cached_state); /* We don't use cached state for a bulk unlock, just free it. */ btrfs_free_extent_state(cached_state);