Skip to content

Support page sizes larger than 4K#430

Open
dzianisbely wants to merge 2 commits into
datto:mainfrom
dzianisbely:page-size-more-than-4k
Open

Support page sizes larger than 4K#430
dzianisbely wants to merge 2 commits into
datto:mainfrom
dzianisbely:page-size-more-than-4k

Conversation

@dzianisbely

Copy link
Copy Markdown

Summary

dattobd's COW manager operates in fixed 4096-byte blocks, but several spots in the snapshot path assumed PAGE_SIZE == COW_BLOCK_SIZE. That assumption holds on 4K-page kernels but breaks on PAGE_SIZE > 4K, where a single page spans multiple COW blocks (16 on 64K), leading to silent snapshot data corruption. This change makes the COW path size-correct. It is architecture-independent: the logic keys only on PAGE_SIZE / SECTORS_PER_PAGE / COW_BLOCK_SIZE, with no arch #ifdefs, and is a no-op on 4K.

What changed and why

  1. Read-clone page count a COW-block-aligned range is not necessarily a whole number of pages. On 64K pages a page holds 16 COW blocks, so a small request rounded to < 1 page and integer division yielded pages == 0 → empty read clone → corrupt snapshot. Fixed by rounding the page count up and tracking a tail so the read clone reads only real data. The refill loop now compares real data bytes (a page-count compare would loop forever given the short tail page).
  2. COW_SECTION_SIZEPAGE_SIZE. COW_SECTION_SIZE is the number of index entries per COW section, and a section's mapping array is a page-granularity allocation get_order(sect_size * 8) in cow_init(). It was hard-coded to 4096, which only lines up with a 4K page. The COW data block granularity is unaffected (COW_BLOCK_SIZE = 4096, separate).
  3. Root cause of 64K garbage: snap_handle_write_bio() looped over COW blocks within a bvec passing the same un-advanced data pointer to cow_write_current(). On 64K a page holds 16 COW blocks, so all 16 got the page's first 4096 bytes → COW store garbage → snapshot reads garbage.
    Fix: advance block_data by COW_BLOCK_SIZE per iteration. On 4K the loop runs once, so the bug was invisible there.

Evidence

Environments:

===== ENVIRONMENT (arm64, emulated, 64K pages) =====
Sat Jun 20 08:41:11 UTC 2026
Linux arm64test 6.8.0-124-generic-64k #124-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 13:54:55 UTC 2026 aarch64 aarch64 aarch64 GNU/Linux
PAGE_SIZE=65536
gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0
version:        0.12.2
srcversion:     FD08148BF1FD432415BF50E
vermagic:       6.8.0-124-generic SMP preempt mod_unload modversions aarch64
--- module after build ---
srcversion:     A58570CFA61090438956EFF
vermagic:       6.8.0-124-generic-64k SMP preempt mod_unload modversions aarch64
version:        0.12.2
srcversion:     3A57035502391B4076B7EC9
vermagic:       6.8.0-124-generic-64k SMP preempt mod_unload modversions aarch64
#define HAVE_ENUM_REQ_OP_WRITE_ZEROES


  • 64K-page kernel (arm64, 6.8.0-124-generic-64k, PAGE_SIZE 65536): clean
    build (0 warnings)
    build-arm64-6-8-64k.txt.txt

  • Full tests/ suite: 24 OK
    full-tests-arm64-6-8-64k.txt

  • ftrace hooksinsmod succeeds, the path_mount / path_umount hooks register, and a real mount fires handle_bdev_mount_event (the IPMODIFY redirect works on 64K).
    runtime-hooks-arm64-6-8-64k.txt

  • snapshot demo:
    snapshot-demo-arm64-6-8-64k.txt

  • Direct test COW-store fix. 16 MB random pattern was written raw to the origin at offset 300 MB (outside the filesystem). Snapshot was taken that region was then overwritten data. This pushes full 16 MB of originals through snap_handle_write_bio. The read-only snapshot still returns source data while the origin returns overwritten data (sha256 match). Verified both on the VM (seekable block devices) and after pulling both device images to a separate host and comparing. With the bug, the snapshot will return corrupted data.
    snap-cow-write-arm64-6-8-64k.txt
    state-log-arm64-6-8-64k.txt

  • No regression on 4K (x86 7.0.0-22, real hardware). Same source builds clean and the full tests/ suite passes (24 OK) with snapshot and COW correct, confirming the change is a true no-op on 4K-page kernels. I took my changes from Add arm64(AArch64) support #429 to make test on Ubuntu 26.04
    build.txt
    noregression-4k-x86-7.0.txt
    snapshot-demo.txt
    tests.txt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant