[PATCH 00/20] f2fs: support block size smaller than PAGE_SIZE

From: Daeho Jeong

Date: Mon Nov 02 2026 - 17:26:05 EST


From: Daeho Jeong <daehojeong@xxxxxxxxxx>

F2FS has required the filesystem block size to equal PAGE_SIZE. On a
kernel with 16KB pages, this means an existing F2FS image with 4KB
blocks cannot be mounted, e.g. the userdata partition of an Android
device that moves from a 4KB page kernel to a 16KB page kernel.

This series lets F2FS mount and use a filesystem whose block size is
smaller than PAGE_SIZE, such as 4KB blocks on a 16KB page kernel. The
on-disk format does not change.

With subpage blocks, even an order-0 folio holds several blocks, so
the series builds on the large folio support from Nanzhe Zhao [1] and
tracks uptodate and dirty state per block in f2fs_folio_state for any
folio that holds more than one block. Most paths then work in blocks
instead of pages:

- Patches 1-2 convert the remaining page based index and size
calculations to block based ones, and add the superblock and mount
infrastructure. Subpage block sizes are still rejected at this
point.
- Patch 3 extends f2fs_folio_state with per-block state, identified by
a magic number, and allocates it on demand with __GFP_NOFAIL.
- Patches 4-7 handle directories, the per-inode dirty counters, the
read path and GC, and the write path and writeback per block.
- Patches 8-19 adapt the remaining features: range operations and
mmap, pinned files, collapse/insert range, move range,
defragmentation, swapfile, fs-verity, atomic writes, inline data,
online resize and compression, and remove the -EOPNOTSUPP checks
that patch 2 added for the features that need them.
- Patch 20 stops rejecting subpage block sizes.

When the block size equals PAGE_SIZE, the behavior does not change,
except for the fixes noted in the individual patches, some of which
also apply to large folios.

A few of the patches adjust code from the large folio series [1]:

- f2fs_folio_has_ffs() checks the folio state magic instead of
requiring a large folio, since order-0 multi-block folios also carry
a folio state, and the page private flags can legitimately be set
before a state is attached.
- f2fs_ffs_find_or_alloc() cannot fail with __GFP_NOFAIL, so the NULL
checks of its result in f2fs_get_lock_data_folio() and
redirty_blocks() are removed.
- Defragmentation and swapfile activation mark only the target block
dirty instead of the whole page.
- redirty_blocks() does not dirty the blocks past EOF.

Testing:

Built every patch for x86_64 and arm64 (16KB pages), and the whole
series for arm (32-bit).

Ran the xfstests auto group (excluding the clone, dedupe and thin
groups) on arm64 QEMU with mount options "discard,fsync_mode=strict"
in these combinations of page size / block size:

- 16KB/4KB: default, compression (lz4, zstd, lz4hc, lzo-rle with
64KB clusters and checksum), compression+encryption,
encryption+verity, mode=lfs, atgc
- 4KB/4KB: default, compression, encryption+verity,
compression+encryption, mode=lfs
- 16KB/16KB: default, compression, encryption+verity,
compression+encryption, mode=lfs

plus generic/019, 521 and 522 for each combination, and a 24 hour
power-off recovery test with fsstress for each of the three
combinations.

There were no crashes or hangs, and the power-off recovery tests found
no corruption.

[1] https://lore.kernel.org/linux-f2fs-devel/20261028154407.1601430-1-nzzhao.sigma@xxxxxxxxx/

Daeho Jeong (20):
f2fs: use block-based index and size calculations in remaining paths
f2fs: support subpage block size superblock and mount
f2fs: extend f2fs_folio_state for subpage blocks
f2fs: support subpage blocks in directory operations
f2fs: convert inode dirty page counters to dirty block counters
f2fs: support subpage blocks in data read path and GC
f2fs: support subpage blocks in data write path and writeback
f2fs: adapt range operations and mmap for subpage blocks
f2fs: support subpage blocks in pinned files
f2fs: support subpage blocks in collapse and insert range
f2fs: support subpage blocks in move range
f2fs: support subpage blocks in defragmentation
f2fs: support subpage blocks in swapfile activation
f2fs: support subpage blocks in fs-verity enablement
f2fs: support subpage blocks in atomic writes
f2fs: preserve inline data in subpage block mode
f2fs: support subpage blocks in online resize
f2fs: support subpage blocks in compression
f2fs: count compress cache entries in pages for its memory limit
f2fs: enable subpage block size support

fs/f2fs/checkpoint.c | 41 +-
fs/f2fs/compress.c | 518 +++++++++----
fs/f2fs/data.c | 1552 +++++++++++++++++++++++----------------
fs/f2fs/dir.c | 124 +++-
fs/f2fs/f2fs.h | 225 ++++--
fs/f2fs/file.c | 553 ++++++++------
fs/f2fs/gc.c | 89 ++-
fs/f2fs/inline.c | 13 +-
fs/f2fs/inode.c | 4 +-
fs/f2fs/node.c | 17 +-
fs/f2fs/segment.c | 7 +-
fs/f2fs/super.c | 162 ++--
fs/f2fs/verity.c | 5 -
include/linux/f2fs_fs.h | 1 +
14 files changed, 2078 insertions(+), 1233 deletions(-)


base-commit: 4c5e07aaeeb8a27d769a7e4e13d0b26aea0cb108
--
2.56.0.317.g454f8302e1-goog