[PATCH] btrfs: disable large folios for systems with highmem

Qu Wenruo <[email protected]>
Newsgroups org.kernel.vger.linux-btrfs
Message-ID <555623ad2f49989444fd60eb2bd11f0371086670.1784540975.git.wqu@suse.com>
[BUG]
There is a bug report that on 32bit systems (i686), btrfs crashes when
trying to do zstd compression:

 BUG: unable to handle page fault for address: fffbc000
 #PF: supervisor read access in kernel mode
 #PF: error_code(0x0000) - not-present page
 CPU: 0 UID: 0 PID: 61 Comm: kworker/u8:5 Tainted: G                 N  7.2.0-rc3-P3 #2 PREEMPTLAZY
 Hardware name: LENOVO 2007F2G/2007F2G, BIOS 79ETE7WW (2.27 ) 03/21/2011
 Workqueue: btrfs-delalloc btrfs_work_helper
 EIP: ZSTD_compressStream2+0x221/0x5fc
 Call Trace:
  ZSTD_compressStream+0xd/0x48
  zstd_compress_stream+0x8/0x10
  zstd_compress_bio+0x20a/0x564
  btrfs_compress_bio+0x94/0xc0
  compress_file_range+0x20a/0x380
  btrfs_work_helper+0xc1/0x1b4
  process_scheduled_works+0x15f/0x204
  worker_thread+0x10c/0x178
  kthread+0xe1/0xe8
  ret_from_fork+0x1d/0x14c
  ret_from_fork_asm+0x12/0x18
  entry_INT80_32+0xf0/0xf0
 CR2: 00000000fffbc000
 ---[ end trace 0000000000000000 ]---

[CAUSE]
Inside zstd_compress_bio(), we assume the whole page cache folio can be
mapped in one go.

However that assumption is not true on systems with CONFIG_HIGHMEM, the
pages of the large folio can be in HIGHMEM, which needs to be mapped
before access.

Meanwhile zstd_compress_bio() only map the page of a large folio where
the start filepos is, the remaining pages are not mapped, and accessing
the remaining pages will trigger the above crash.

[FIX]
Do not enable large folios when the kernel has CONFIG_HIGHMEM enabled.

This is the same handling for bs > ps support.

Link: https://github.com/kdave/btrfs-progs/issues/1146
Fixes: 9bce95edb1b4 ("btrfs: move large data folios out of experimental features")
Signed-off-by: Qu Wenruo <[email protected]>
---
 fs/btrfs/disk-io.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 37fc0d6b960d..5de8210070eb 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3477,7 +3477,15 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
 	fs_info->sectorsize = sectorsize;
 	fs_info->sectorsize_bits = ilog2(sectorsize);
 	fs_info->block_min_order = ilog2(round_up(sectorsize, PAGE_SIZE) >> PAGE_SHIFT);
-	fs_info->block_max_order = calc_block_max_order(fs_info->sectorsize_bits);
+	/*
+	 * For HIGHMEM, a large folio cannot be mapped in one go, breaking a lot
+	 * of basic assumptions for btrfs IOs.
+	 * Disable large folios for such 32-bit systems.
+	 */
+	if (IS_ENABLED(CONFIG_HIGHMEM))
+		fs_info->block_max_order = fs_info->block_min_order;
+	else
+		fs_info->block_max_order = calc_block_max_order(fs_info->sectorsize_bits);
 	fs_info->csums_per_leaf = BTRFS_MAX_ITEM_SIZE(fs_info) / fs_info->csum_size;
 	fs_info->fs_devices->fs_info = fs_info;
 
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.