]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
btrfs: disable large folios for systems with highmem
authorQu Wenruo <wqu@suse.com>
Mon, 20 Jul 2026 09:49:41 +0000 (19:19 +0930)
committerDavid Sterba <dsterba@suse.com>
Fri, 31 Jul 2026 14:54:30 +0000 (16:54 +0200)
[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
Reported-by: Erhard Furtner <erhard_f@mailbox.org>
Fixes: 9bce95edb1b4 ("btrfs: move large data folios out of experimental features")
Reviewed-by: Jeff Layton <jlayton@kernel.org>
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/disk-io.c

index 36332df9a0f1c0736c9e9dc56f9fe5a71a3e690d..87385b97c81bd355dde58224995b089d39ab28e8 100644 (file)
@@ -3468,7 +3468,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->stripesize = stripesize;
        fs_info->fs_devices->fs_info = fs_info;