Skip to content

Add FUSE remap_file_range support for FICLONE/FICLONERANGE#21

Merged
ejc3 merged 101 commits intomainfrom
fuse-remap-support
Dec 26, 2025
Merged

Add FUSE remap_file_range support for FICLONE/FICLONERANGE#21
ejc3 merged 101 commits intomainfrom
fuse-remap-support

Conversation

@ejc3
Copy link
Copy Markdown
Owner

@ejc3 ejc3 commented Dec 26, 2025

Summary

Enables cp --reflink=always and FICLONE/FICLONERANGE ioctls through FUSE by adding remap_file_range support to the full stack.

Problem: FICLONE fails with EOPNOTSUPP through FUSE because there's no kernel opcode for it.

Solution:

  • Kernel patch adds FUSE_REMAP_FILE_RANGE opcode (54)
  • fuse-pipe protocol extension for RemapFileRange
  • Passthrough implementation using copy_file_range (which handles FICLONE on btrfs)
  • Integration tests that skip gracefully on unpatched kernels

Full Stack Implementation

Layer Component Changes
Kernel kernel/build.sh Inlines FUSE_REMAP_FILE_RANGE patch (opcode 54, struct, handler)
fuser ejc3/fuser:remap-file-range Opcode constant + remap_file_range trait method
fuse-backend-rs ejc3/fuse-backend-rs:remap-file-range PassthroughFs impl using copy_file_range
libfuse ejc3/libfuse:remap-file-range passthrough_ll.c impl for C-based testing
fuse-pipe src/protocol/, src/client/, src/server/ Wire protocol + handler
Tests tests/test_remap_file_range.rs VM end-to-end test
Tests fuse-pipe/tests/test_remap_file_range.rs Host-side FUSE tests
Tests Containerfile.libfuse-remap libfuse container test

Key Fixes During Development

  1. Opcode 54 (not 53) - opcode 53 is reserved for FUSE_SYNCFS
  2. len=0 semantics - FICLONE passes len=0 meaning "to end of file", fixed underflow in writeback range calculation
  3. Return value - must return bytes cloned via fuse_write_out, not just success/fail
  4. Exit code handling - cp --reflink=always returns 1 (not errno) on failure

Test Behavior

Tests skip gracefully without patched kernel - won't break CI:

Test Skip Condition
test_ficlone_cp_reflink_in_vm No btrfs, or exit code 1/38/95
test_ficlone_whole_file ENOSYS or EOPNOTSUPP from kernel
test_ficlonerange_partial ENOSYS or EOPNOTSUPP from kernel

To run with patched kernel:

REMAP_KERNEL=/mnt/fcvm-btrfs/kernels/vmlinux-6.12.10-*.bin make test-root FILTER=remap

Verified Working

remap_file_range called ino_in=2 fh_in=2 offset_in=0 ino_out=3 fh_out=3 len=0 remap_flags=0
remap_file_range response response=Written { size: 0 }
[ctr:stdout] FICLONE test passed
✓ Verified: files share physical extents (true reflink)
[REMAP-VM] ✓ ficlone (6.9s)

Test plan

  • cargo build --release passes
  • make test-root passes (tests skip on standard kernel)
  • REMAP_KERNEL=... make test-root FILTER=remap passes with patched kernel
  • libfuse container test passes: FICLONE + FICLONERANGE (offset=0 and offset=512KB)
  • filefrag confirms shared extents (true reflinks on btrfs)

ejc3 added 30 commits December 24, 2025 09:09
- Remove needless Ok()? in find_plan_file
- Remove useless format!() in fix_fstab_in_image
- Use .map() instead of if let Some for Option::map pattern
- Use function reference instead of closure for is_process_alive
- Replace deprecated into_path() with keep()
- Add CACHE_REGISTRY variable to Makefile (optional)
- When set, podman build uses --cache-from and --cache-to flags
- CI sets CACHE_REGISTRY=ghcr.io/${{ github.repository }}/cache
- All jobs login to ghcr.io before building
- Removes actions/cache in favor of native podman registry caching
- Renamed job to "VM (bare metal)" for clarity
- Install Rust, deps, Firecracker, cargo-nextest directly on host
- Run make test-vm instead of make container-test-vm
- Removes podman version issues on buildjet runner
- Container (rootless): make ci-container-rootless (fuse-pipe tests)
- Container (sudo): make ci-container-sudo (fuse-pipe root tests)
- VM (bare metal): make test-vm (Firecracker VM tests)

All on buildjet-32vcpu-ubuntu-2204 to avoid GHA ulimit restrictions.
- CI container targets now call make test-noroot/test-root inside container
- Remove redundant test enumeration variables
- Remove separate pjdfstest target (included in test-root)
- test-noroot runs: unit tests + non-root fuse-pipe tests
- test-root runs: root fuse-pipe tests (integration_root, permission_edge, pjdfstest)
Major changes:
- Replace enumeration-based test filtering with compile-time features
- test-rootless: no features (privileged tests not compiled)
- test-root: --features privileged-tests (requires sudo + KVM)
- Container tests call back to Makefile (single source of truth)
- pjdfstest built via Makefile, not Containerfile (setup-pjdfstest target)
- All pjdfstest moved to root-only (C suite requires chown/mknod/user-switch)

Linting:
- Add tests/lint.rs - runs fmt, clippy, audit, deny in parallel via nextest
- Add deny.toml for license/security checks
- Replace unmaintained atty crate with std::io::IsTerminal

Makefile:
- Removed ~300 lines of redundant targets
- test-rootless, test-root, test (both)
- container-test-rootless, container-test-root, container-test (both)
- setup-pjdfstest builds pjdfstest on first test run (idempotent)

Files:
- pjdfstest_matrix.rs -> pjdfstest_matrix_root.rs (all categories need root)
- Containerfile: removed pjdfstest build (now via Makefile)
- src/main.rs: use std::io::IsTerminal instead of atty
- Cargo.toml: removed atty dependency
Previously, fcvm would automatically download the kernel and create the
rootfs on first run of `fcvm podman run`. This caused issues in CI where
parallel tests would timeout waiting for the 5-minute setup to complete.

Changes:
- Add `fcvm setup` command that downloads kernel, creates rootfs, and
  creates fc-agent initrd
- Add `--setup` flag to `fcvm podman run` to opt-in to auto-setup
- Without --setup, fcvm now fails immediately with a helpful error if
  any required asset is missing
- All ensure_* functions now take `allow_create: bool` parameter:
  - ensure_kernel(allow_create)
  - ensure_rootfs(allow_create)
  - ensure_fc_agent_initrd(allow_create)
- Internal rootfs creation still allows kernel download (since creating
  rootfs requires booting a VM with the kernel)

Error messages direct users to run `fcvm setup` or use `--setup` flag.

Tested:
- Removed rootfs and ran without --setup: fails immediately with
  "Rootfs not found. Run 'fcvm setup' first, or use --setup flag."
- Ran `fcvm setup`: creates kernel, rootfs, and initrd successfully
- Ran `fcvm podman run` after setup: works without --setup flag
- New target `setup-fcvm` runs `fcvm setup` to download kernel and
  create rootfs before tests
- Updated dependencies:
  - test-root: setup-fcvm (instead of just setup-btrfs)
  - container-test-root: setup-fcvm
  - bench-exec: setup-fcvm
  - ci-host: setup-fcvm
  - ci-root: setup-fcvm
- setup-fcvm depends on build and setup-btrfs (correct order)
- Added to help text and .PHONY list

This ensures rootfs is created once before parallel tests run,
avoiding the timeout issues from previous approach where each
test would race to create the rootfs.
Documentation updates:
- CLAUDE.md: Document fcvm setup command and --setup flag behavior
- README.md: Add setup section to Quick Start, add fcvm setup to CLI Reference
- DESIGN.md: Add fcvm setup command documentation
- CONTRIBUTING.md: Add setup step to development workflow

Code changes:
- Disallow --setup flag when running as root (must use fcvm setup explicitly)
- Add disk space check to Makefile setup-fcvm target with remediation options
- Explain btrfs CoW usage in disk space error message

The --setup flag is only available for rootless mode. For bridged networking
(which requires root), run `fcvm setup` first.
Introduces three test tiers using Cargo feature flags:
- test-unit: No VMs, ~1s (107 tests) - cli parsing, state manager, lint
- test-integration-fast: Quick VMs, ~80s (176 tests) - sanity, exec, port forward
- test-root: All tests, ~6min (196 tests) - includes clone, snapshot, POSIX

Implementation:
- Cargo.toml: Added integration-fast and integration-slow features
  with default = ["integration-fast", "integration-slow"]
- Test files: Added #![cfg(feature = "...")] to categorize by speed
  - integration-fast: sanity, signal_cleanup, exec, port_forward,
    localhost_image, readme_examples, lint
  - integration-slow: snapshot_clone, clone_connection, fuse_posix,
    fuse_in_vm, egress, egress_stress
- Makefile: New targets test-unit, test-integration-fast
  (test-root unchanged, runs all tests)
- Container targets: container-test-unit, container-test-integration-fast
- CI targets: ci-unit, ci-integration-fast

Unit tests always compile (no feature flag) so test-unit uses
--no-default-features to exclude VM tests entirely.

Tested:
  make test-unit              # 107 tests, 1.2s
  make test-integration-fast  # 176 tests, 81s
  make test-root              # 196 tests, 367s (all passed)
Problem: pjdfstest (POSIX compliance tests, ~80s) was running in
test-integration-fast when it should only run in test-root.

Root cause: Cargo feature unification was merging features across
workspace members, causing fuse-pipe to get `integration-slow` even
when `--no-default-features` was passed.

Changes:

1. Workspace (Cargo.toml):
   - Add resolver = "2" for proper workspace-wide feature handling

2. fuse-pipe/Cargo.toml:
   - Remove fuse-client feature (fuser is now always included)
   - Add integration-slow feature to gate slow tests
   - default = ["integration-slow"] (all tests run by default)

3. fc-agent/Cargo.toml:
   - Use default-features = false to exclude integration-slow
   - This prevents feature unification from enabling slow tests

4. fuse-pipe/tests/pjdfstest_matrix_root.rs:
   - Add #![cfg(all(feature = "privileged-tests", feature = "integration-slow"))]

5. Makefile:
   - Add LIST=1 flag for fast test listing without running
   - Remove test pre-compilation from build target

Test counts:
  test-unit:             189 tests (~1s)
  test-integration-fast: 243 tests (~12s, no pjdfstest)
  test-root:             280 tests (~6min, includes pjdfstest)

Tested: make test-unit LIST=1, make test-integration-fast LIST=1,
        make test-root LIST=1 (verified pjdfstest excluded from fast tier)
Add Build Performance section to DESIGN.md with benchmarks from
c6g.metal (64 ARM cores):

- Cold build: 44s (~12 parallel rustc, dependency-graph limited)
- Incremental: 13s (only recompiles changed crate)
- test-unit LIST: 24s cold, 1.2s warm

Tested mold linker and sccache:
- mold: ~1s savings, not worth the config complexity
- sccache: adds overhead for local dev, may help CI

Conclusion: defaults are fine, compilation (not linking) is the bottleneck.
README.md (684 → 445 lines, -35%):
- Consolidate detailed sections with links to DESIGN.md
- Remove dnsmasq from prerequisites (not needed - VMs use host DNS)
- Update Makefile targets (test-vm → test-root/integration-fast/unit)
- Add --strace-agent option documentation

DESIGN.md:
- Fix nftables → iptables (6 locations) to match actual implementation
- Remove fake config file section (we use env vars, not config files)
- Update state file path and format to match actual code
- Add pjdfstest skip breakdown (54/237 files skipped on Linux)
- Add fcvm exec command documentation
- Fix directory structure (remove memory_server.rs, add exec.rs)

src/cli/args.rs:
- Fix setup description: "~500MB download" → "kernel ~15MB, rootfs ~10GB"

Makefile:
- Add LIST=$(LIST) passthrough to container test targets
The problem: all test tiers were running with `sudo -E` as the test
binary runner, even tests that don't need root (rootless networking).

New test tiers:
- test-unit: no features, no sudo, no VMs
- test-fast: integration-fast, no sudo, rootless VMs only
- test-all: default features (fast+slow), no sudo, rootless VMs only
- test-root: + privileged-tests, sudo via runner, bridged + pjdfstest

Key changes:
- Add TEST_ENV_BASE without sudo for rootless tiers
- Only TEST_ROOT uses CARGO_TARGET_*_RUNNER='sudo -E'
- Align container targets (container-test-fast, container-test-all)
- Align CI targets (ci-fast instead of ci-integration-fast)
- Add namespace holder retry logic (2s deadline) for transient failures
- Switch egress tests to checkip.amazonaws.com (faster, more reliable)
- Reduce curl/wget timeouts from 15s to 5s
- Update CLAUDE.md with test tier documentation

Tested:
  make test-unit   # 107 passed
  make test-fast   # 115 passed
  make test-all    # 127 passed
  make test-root   # 196 passed, 3 skipped (intentionally ignored)
New test file: tests/test_fuse_in_vm_matrix.rs
- 17 tests (one per pjdfstest category)
- Each test spins up a VM with pjdfstest container
- Runs category inside VM against FUSE-mounted volume
- Nextest runs all 17 in parallel

This complements the host-side matrix (fuse-pipe/tests/pjdfstest_matrix_root.rs):
- Host matrix: tests fuse-pipe FUSE directly (no VM)
- VM matrix: tests full stack (host VolumeServer → vsock → guest FUSE)

Removed obsolete files:
- tests/test_fuse_in_vm.rs (replaced by matrix)
- tests/test_fuse_posix.rs (ignored sequential test)

Tested: make test-root FILTER=test_pjdfstest_vm_posix_fallocate (passed)
- CLAUDE.md: Fix test tier tables (test-unit/fast/all/root)
- CLAUDE.md: Document both pjdfstest matrices with test counts
- CLAUDE.md: Update project structure (remove old test files)
- Cross-reference between host-side and in-VM matrices
Containerfile (118 → 48 lines):
- Consolidate RUN commands to reduce layers
- Remove verbose comments
- Keep --no-same-owner for tar (fixes rootless builds)
- Install cargo-audit and cargo-deny alongside nextest
- Add uidmap package inline with other apt deps

Makefile (269 → 90 lines):
- Remove separate CONTAINER_RUN_ROOTLESS/ROOT configs
- Use single CONTAINER_RUN with --userns=keep-id for UID mapping
- Use bind mounts (./target, ./cargo-home) instead of named volumes
- Remove CI-specific targets (ci-host, ci-unit, ci-fast, ci-root)
- Remove container-build-root (single container-build works for all)
- Consolidate help text
- Remove verbose disk space error messages

Tested: make container-test-all (125 tests passed in 211s)
DNAT scoping fix:
- Scope iptables DNAT rules to veth IP (`-d 172.30.x.y`) instead of
  matching any destination. This allows parallel VMs to use the same
  host port since each rule only matches traffic to its specific veth IP.
- Update tests to curl the veth IP instead of localhost.

Timeout fixes for pjdfstest:
- Increase localhost test timeout from 60s to 120s to handle podman
  storage lock contention during parallel test runs.
- Add 15-minute timeout for pjdfstest_vm tests in nextest.toml.

Bottleneck analysis (proved via controlled experiment):
- Single VM: 25s total (skopeo export: 3.2s, fuse import: 6.5s)
- 2 VMs parallel: 29s for chmod (skopeo export: 6.2s, fuse import: 6.6s)
- Bottleneck is skopeo export (podman storage lock), NOT fuse-pipe.
- fuse-pipe maintains 66 MB/s read speed regardless of parallelism.

Files changed:
- src/network/bridged.rs: Scope DNAT to veth IP
- src/network/namespace.rs, portmap.rs: Update veth IP accessor
- tests/test_*.rs: Use veth IP for curl, increase timeouts
- .config/nextest.toml: Add pjdfstest_vm timeout override

Tested:
  Single VM chmod: 25s
  2 parallel VMs (chmod + chown): 29s + 96s
  fuse-pipe import speed: 66 MB/s (consistent)
fc-agent was using only 1 FUSE reader thread, severely limiting
parallel I/O throughput over vsock. Benchmarks showed 256 readers
gives best performance.

Change:
- fc-agent/src/fuse/mod.rs: Add NUM_READERS=256 constant
- Use mount_vsock_with_readers() instead of mount_vsock()

Performance improvement (image import via FUSE over vsock):
- Before (1 reader): 6.6s for 430MB pjdfstest image
- After (256 readers): 5.6s (15% faster)

The import phase now properly utilizes parallel I/O, reducing the
per-VM overhead during pjdfstest matrix runs.
Problem: When running 17 pjdfstest VM tests in parallel, all tests
serialize on `skopeo copy containers-storage:localhost/pjdfstest`.
This creates a "thundering herd" where all tests wait ~120s, then
all try to start VMs at once, causing Firecracker crashes.

From logs:
  # FAILING (truncate):
  05:01:26 Exporting image with skopeo
  05:03:34 Image exported (122s later - lock contention!)
  05:03:34.835 Firecracker spawned
  05:03:34.859 VM setup failed (24ms - crashed immediately)

  # PASSING (chmod):
  05:01:27 Exporting image with skopeo
  05:03:10 Image exported (103s - finished earlier)
  05:03:11.258 Firecracker spawned
  05:03:11.258 API server received request (success)

Solution: Content-addressable cache at /mnt/fcvm-btrfs/image-cache/{digest}/
- Get image digest with `podman image inspect`
- First test exports to cache (with file lock to prevent races)
- All other tests hit cache instantly

Result: 17 pjdfstest VM tests now complete in 95s with 0 failures
(was 128s with 2 failures from Firecracker crashes)

Also updated CLAUDE.md race condition debugging section with this
real example to emphasize "show, don't tell" - always find the
smoking gun in logs rather than guessing.
Host runner (bare metal with KVM):
  test-unit → test-fast → test-root

Container runner (podman):
  container-test-unit → container-test-fast → container-test-all

Each target runs sequentially within its runner. Both runners
execute in parallel.
The test was calling link() with an inode from create() without an
intermediate lookup(). In real FUSE, the kernel calls LOOKUP on the
source file before LINK to resolve the path to an inode. This lookup
refreshes the inode reference in fuse-backend-rs.

Without this lookup, the inode may be unreachable after release()
because fuse-backend-rs tracks inode references internally and the
create() reference may not persist correctly across all environments.

The fix:
1. After release(), call lookup() to refresh the inode reference
2. Use the inode from lookup() for the link() call

This simulates what the kernel does and makes the test work correctly
on all environments (not just by accident on some filesystems).

Also:
- Reverted fuse-pipe tests to use /tmp (the .local/ workaround was wrong)
- Added POSIX compliance testing guidelines to CLAUDE.md

Tested: cargo test -p fuse-pipe --lib test_passthrough_hardlink -- passes
ejc3 added a commit to ejc3/fuser that referenced this pull request Dec 26, 2025
Adds userspace support for the new FUSE_REMAP_FILE_RANGE opcode (53)
which enables reflink operations (FICLONE/FICLONERANGE ioctls) through
FUSE filesystems.

Changes:
- Add FUSE_REMAP_FILE_RANGE opcode (53) to fuse_opcode enum
- Add fuse_remap_file_range_in wire struct matching kernel ABI
- Add RemapFileRange request parsing in ll/request.rs
- Add remap_file_range() method to Filesystem trait with default ENOSYS
- Wire up request dispatch in request.rs

Wire format (fuse_remap_file_range_in):
  - fh_in: u64, off_in: i64, nodeid_out: u64, fh_out: u64
  - off_out: i64, len: u64, remap_flags: u32, padding: u32

Requires kernel patch (FUSE_REMAP_FILE_RANGE not yet upstream).

Tested:
  cargo build --features abi-7-28
  cargo test --features abi-7-28
  E2E: ejc3/fcvm#21
    - cp --reflink=always through FUSE → btrfs
    - filefrag confirms shared extents
ejc3 added a commit to ejc3/fuse-backend-rs that referenced this pull request Dec 26, 2025
Add remap_file_range to the FileSystem trait to enable reflink
operations through FUSE. This maps to the kernel's .remap_file_range
VFS callback, which handles FICLONE and FICLONERANGE ioctls.

Changes:
- Add remap_file_range method to FileSystem trait (default: ENOSYS)
- Implement remap_file_range in PassthroughFs using FICLONE/FICLONERANGE
- Add Arc<FS> delegations for copy_file_range and remap_file_range

The Arc<FS> blanket implementation was missing delegations for these
methods, causing operations through Arc<PassthroughFs> to incorrectly
return ENOSYS instead of calling the actual implementation.

On CoW filesystems (btrfs, xfs with reflink), this enables instant
file cloning where the copy shares physical storage until modified.

Tested:
  cargo test (unit tests pass)
  E2E: ejc3/fcvm#21
    - cp --reflink=always through FUSE → btrfs
    - filefrag confirms shared extents (true reflinks)
ejc3 added 7 commits December 26, 2025 10:07
Changes:
- Fix FUSE_REMAP_FILE_RANGE opcode from 53 to 54 (matching fuser/fuse-backend-rs)
- Add CONFIG_BTRFS_FS to kernel/build.sh for reflink testing
- Add libfuse-test feature flag in Cargo.toml
- Add container-based test (test_libfuse_remap_container)
- Add Containerfile.libfuse-remap for self-contained test environment
- Add libfuse patch and ficlone_test.c for testing FICLONE through FUSE

The container test:
1. Creates btrfs loopback inside container
2. Runs passthrough_ll (patched libfuse) on top
3. Tests FICLONE through FUSE -> btrfs
4. Verifies shared extents with filefrag

Tested:
  REMAP_KERNEL=/mnt/fcvm-btrfs/kernels/vmlinux-6.12.10-*.bin \
  cargo test --features privileged-tests,libfuse-test test_libfuse_remap
  # Container shows: opcode: REMAP_FILE_RANGE (54)
  # filefrag shows: flags: last,shared,eof (both files)
Switch from cloning upstream + applying patch to cloning
ejc3/libfuse remap-file-range branch directly.

Simpler and keeps all remap_file_range changes in forks.
Kernel patch fixes:
- Handle len=0 (whole file) without underflow in writeback range
- Add end_in/end_out variables for proper range calculation
- Skip response size validation when len=0

libfuse patch updates (synced from ejc3/libfuse:remap-file-range):
- Add FICLONE optimization for whole-file clone
- Fix return value: use fstat to get actual size when len=0
- Cast fd arguments to int for proper ioctl usage

These fixes ensure correct behavior for FICLONE (whole-file clone)
vs FICLONERANGE (partial clone) operations.
Test coverage:
- Test 1: FICLONE (whole file clone) - tests len=0 path
- Test 2: FICLONERANGE (offset=0, len=512KB) - partial from start
- Test 3: FICLONERANGE (offset=512KB, len=512KB) - partial from middle

ficlone_test.c enhancements:
- Add --range mode for FICLONERANGE testing
- Verify size matches for FICLONE (catches len=0 return bug)
- Better error messages with specific errno explanations

These tests cover the edge cases fixed in the kernel patch
and fuse-backend-rs/libfuse implementations.
The previous approach used `git apply` to apply patches, which doesn't
work on non-git kernel source directories. Changed to inline the
modifications directly using sed commands.

Changes:
- build.sh now uses sed to add FUSE_REMAP_FILE_RANGE opcode (54)
- Adds fuse_remap_file_range_in struct to include/uapi/linux/fuse.h
- Adds no_remap_file_range flag to fs/fuse/fuse_i.h
- Inlines the full fuse_remap_file_range() function in fs/fuse/file.c
- Check for already-applied changes before modifying kernel source
- Keep patch file for reference/documentation

Tested: All 3 libfuse FICLONE/FICLONERANGE tests pass with rebuilt
kernel. filefrag confirms shared extents on btrfs through FUSE.
Instead of requiring REMAP_KERNEL env var, the test now:
- Uses REMAP_KERNEL if set (for testing with patched kernel)
- Otherwise uses default kernel
- If kernel returns ENOSYS (exit 38), test skips gracefully
- If kernel returns EOPNOTSUPP (exit 95), test skips gracefully

This matches fuse-pipe's test_remap_file_range.rs behavior which
does runtime kernel support detection.
cp --reflink=always returns exit code 1 (not ENOSYS/EOPNOTSUPP errno)
when reflink is not supported. Add exit code 1 to skip conditions.

Tested: make test-root FILTER=remap - all tests skip gracefully
@ejc3 ejc3 merged commit 17dd898 into main Dec 26, 2025
0 of 4 checks passed
ejc3 added a commit that referenced this pull request Dec 26, 2025
This reverts commit 17dd898, reversing
changes made to 0953d12.
ejc3 added a commit that referenced this pull request Dec 26, 2025
ejc3 added a commit that referenced this pull request Dec 26, 2025
@ejc3
Copy link
Copy Markdown
Owner Author

ejc3 commented Dec 26, 2025

This PR was merged then reverted. Work continues in #27.

ejc3 added a commit to ejc3/fuser that referenced this pull request Jan 25, 2026
Adds userspace support for the new FUSE_REMAP_FILE_RANGE opcode (53)
which enables reflink operations (FICLONE/FICLONERANGE ioctls) through
FUSE filesystems.

Changes:
- Add FUSE_REMAP_FILE_RANGE opcode (53) to fuse_opcode enum
- Add fuse_remap_file_range_in wire struct matching kernel ABI
- Add RemapFileRange request parsing in ll/request.rs
- Add remap_file_range() method to Filesystem trait with default ENOSYS
- Wire up request dispatch in request.rs

Wire format (fuse_remap_file_range_in):
  - fh_in: u64, off_in: i64, nodeid_out: u64, fh_out: u64
  - off_out: i64, len: u64, remap_flags: u32, padding: u32

Requires kernel patch (FUSE_REMAP_FILE_RANGE not yet upstream).

Tested:
  cargo build --features abi-7-28
  cargo test --features abi-7-28
  E2E: ejc3/fcvm#21
    - cp --reflink=always through FUSE → btrfs
    - filefrag confirms shared extents
ejc3 added a commit to ejc3/fuser that referenced this pull request Jan 25, 2026
Adds userspace support for the new FUSE_REMAP_FILE_RANGE opcode (53)
which enables reflink operations (FICLONE/FICLONERANGE ioctls) through
FUSE filesystems.

Changes:
- Add FUSE_REMAP_FILE_RANGE opcode (53) to fuse_opcode enum
- Add fuse_remap_file_range_in wire struct matching kernel ABI
- Add RemapFileRange request parsing in ll/request.rs
- Add remap_file_range() method to Filesystem trait with default ENOSYS
- Wire up request dispatch in request.rs

Wire format (fuse_remap_file_range_in):
  - fh_in: u64, off_in: i64, nodeid_out: u64, fh_out: u64
  - off_out: i64, len: u64, remap_flags: u32, padding: u32

Requires kernel patch (FUSE_REMAP_FILE_RANGE not yet upstream).

Tested:
  cargo build --features abi-7-28
  cargo test --features abi-7-28
  E2E: ejc3/fcvm#21
    - cp --reflink=always through FUSE → btrfs
    - filefrag confirms shared extents
ejc3 added a commit to ejc3/fuser that referenced this pull request Jan 25, 2026
Adds userspace support for the new FUSE_REMAP_FILE_RANGE opcode (53)
which enables reflink operations (FICLONE/FICLONERANGE ioctls) through
FUSE filesystems.

Changes:
- Add FUSE_REMAP_FILE_RANGE opcode (53) to fuse_opcode enum
- Add fuse_remap_file_range_in wire struct matching kernel ABI
- Add RemapFileRange request parsing in ll/request.rs
- Add remap_file_range() method to Filesystem trait with default ENOSYS
- Wire up request dispatch in request.rs

Wire format (fuse_remap_file_range_in):
  - fh_in: u64, off_in: i64, nodeid_out: u64, fh_out: u64
  - off_out: i64, len: u64, remap_flags: u32, padding: u32

Requires kernel patch (FUSE_REMAP_FILE_RANGE not yet upstream).

Tested:
  cargo build --features abi-7-28
  cargo test --features abi-7-28
  E2E: ejc3/fcvm#21
    - cp --reflink=always through FUSE → btrfs
    - filefrag confirms shared extents
ejc3 added a commit to ejc3/fuser that referenced this pull request Feb 1, 2026
Adds userspace support for the new FUSE_REMAP_FILE_RANGE opcode (53)
which enables reflink operations (FICLONE/FICLONERANGE ioctls) through
FUSE filesystems.

Changes:
- Add FUSE_REMAP_FILE_RANGE opcode (53) to fuse_opcode enum
- Add fuse_remap_file_range_in wire struct matching kernel ABI
- Add RemapFileRange request parsing in ll/request.rs
- Add remap_file_range() method to Filesystem trait with default ENOSYS
- Wire up request dispatch in request.rs

Wire format (fuse_remap_file_range_in):
  - fh_in: u64, off_in: i64, nodeid_out: u64, fh_out: u64
  - off_out: i64, len: u64, remap_flags: u32, padding: u32

Requires kernel patch (FUSE_REMAP_FILE_RANGE not yet upstream).

Tested:
  cargo build --features abi-7-28
  cargo test --features abi-7-28
  E2E: ejc3/fcvm#21
    - cp --reflink=always through FUSE → btrfs
    - filefrag confirms shared extents
ejc3 added a commit to ejc3/fuser that referenced this pull request Feb 1, 2026
Adds userspace support for the new FUSE_REMAP_FILE_RANGE opcode (53)
which enables reflink operations (FICLONE/FICLONERANGE ioctls) through
FUSE filesystems.

Changes:
- Add FUSE_REMAP_FILE_RANGE opcode (53) to fuse_opcode enum
- Add fuse_remap_file_range_in wire struct matching kernel ABI
- Add RemapFileRange request parsing in ll/request.rs
- Add remap_file_range() method to Filesystem trait with default ENOSYS
- Wire up request dispatch in request.rs

Wire format (fuse_remap_file_range_in):
  - fh_in: u64, off_in: i64, nodeid_out: u64, fh_out: u64
  - off_out: i64, len: u64, remap_flags: u32, padding: u32

Requires kernel patch (FUSE_REMAP_FILE_RANGE not yet upstream).

Tested:
  cargo build --features abi-7-28
  cargo test --features abi-7-28
  E2E: ejc3/fcvm#21
    - cp --reflink=always through FUSE → btrfs
    - filefrag confirms shared extents
ejc3 added a commit to ejc3/fuser that referenced this pull request Feb 1, 2026
Adds userspace support for the new FUSE_REMAP_FILE_RANGE opcode (53)
which enables reflink operations (FICLONE/FICLONERANGE ioctls) through
FUSE filesystems.

Changes:
- Add FUSE_REMAP_FILE_RANGE opcode (53) to fuse_opcode enum
- Add fuse_remap_file_range_in wire struct matching kernel ABI
- Add RemapFileRange request parsing in ll/request.rs
- Add remap_file_range() method to Filesystem trait with default ENOSYS
- Wire up request dispatch in request.rs

Wire format (fuse_remap_file_range_in):
  - fh_in: u64, off_in: i64, nodeid_out: u64, fh_out: u64
  - off_out: i64, len: u64, remap_flags: u32, padding: u32

Requires kernel patch (FUSE_REMAP_FILE_RANGE not yet upstream).

Tested:
  cargo build --features abi-7-28
  cargo test --features abi-7-28
  E2E: ejc3/fcvm#21
    - cp --reflink=always through FUSE → btrfs
    - filefrag confirms shared extents
ejc3 added a commit to ejc3/fuser that referenced this pull request Feb 1, 2026
Adds userspace support for the new FUSE_REMAP_FILE_RANGE opcode (53)
which enables reflink operations (FICLONE/FICLONERANGE ioctls) through
FUSE filesystems.

Changes:
- Add FUSE_REMAP_FILE_RANGE opcode (53) to fuse_opcode enum
- Add fuse_remap_file_range_in wire struct matching kernel ABI
- Add RemapFileRange request parsing in ll/request.rs
- Add remap_file_range() method to Filesystem trait with default ENOSYS
- Wire up request dispatch in request.rs

Wire format (fuse_remap_file_range_in):
  - fh_in: u64, off_in: i64, nodeid_out: u64, fh_out: u64
  - off_out: i64, len: u64, remap_flags: u32, padding: u32

Requires kernel patch (FUSE_REMAP_FILE_RANGE not yet upstream).

Tested:
  cargo build --features abi-7-28
  cargo test --features abi-7-28
  E2E: ejc3/fcvm#21
    - cp --reflink=always through FUSE → btrfs
    - filefrag confirms shared extents
ejc3 added a commit to ejc3/fuser that referenced this pull request Feb 1, 2026
Adds userspace support for the new FUSE_REMAP_FILE_RANGE opcode (53)
which enables reflink operations (FICLONE/FICLONERANGE ioctls) through
FUSE filesystems.

Changes:
- Add FUSE_REMAP_FILE_RANGE opcode (53) to fuse_opcode enum
- Add fuse_remap_file_range_in wire struct matching kernel ABI
- Add RemapFileRange request parsing in ll/request.rs
- Add remap_file_range() method to Filesystem trait with default ENOSYS
- Wire up request dispatch in request.rs

Wire format (fuse_remap_file_range_in):
  - fh_in: u64, off_in: i64, nodeid_out: u64, fh_out: u64
  - off_out: i64, len: u64, remap_flags: u32, padding: u32

Requires kernel patch (FUSE_REMAP_FILE_RANGE not yet upstream).

Tested:
  cargo build --features abi-7-28
  cargo test --features abi-7-28
  E2E: ejc3/fcvm#21
    - cp --reflink=always through FUSE → btrfs
    - filefrag confirms shared extents
ejc3 added a commit to ejc3/fuser that referenced this pull request Feb 1, 2026
Adds userspace support for the new FUSE_REMAP_FILE_RANGE opcode (53)
which enables reflink operations (FICLONE/FICLONERANGE ioctls) through
FUSE filesystems.

Changes:
- Add FUSE_REMAP_FILE_RANGE opcode (53) to fuse_opcode enum
- Add fuse_remap_file_range_in wire struct matching kernel ABI
- Add RemapFileRange request parsing in ll/request.rs
- Add remap_file_range() method to Filesystem trait with default ENOSYS
- Wire up request dispatch in request.rs

Wire format (fuse_remap_file_range_in):
  - fh_in: u64, off_in: i64, nodeid_out: u64, fh_out: u64
  - off_out: i64, len: u64, remap_flags: u32, padding: u32

Requires kernel patch (FUSE_REMAP_FILE_RANGE not yet upstream).

Tested:
  cargo build --features abi-7-28
  cargo test --features abi-7-28
  E2E: ejc3/fcvm#21
    - cp --reflink=always through FUSE → btrfs
    - filefrag confirms shared extents
ejc3 added a commit to ejc3/fuser that referenced this pull request Feb 2, 2026
Adds userspace support for the new FUSE_REMAP_FILE_RANGE opcode (53)
which enables reflink operations (FICLONE/FICLONERANGE ioctls) through
FUSE filesystems.

Changes:
- Add FUSE_REMAP_FILE_RANGE opcode (53) to fuse_opcode enum
- Add fuse_remap_file_range_in wire struct matching kernel ABI
- Add RemapFileRange request parsing in ll/request.rs
- Add remap_file_range() method to Filesystem trait with default ENOSYS
- Wire up request dispatch in request.rs

Wire format (fuse_remap_file_range_in):
  - fh_in: u64, off_in: i64, nodeid_out: u64, fh_out: u64
  - off_out: i64, len: u64, remap_flags: u32, padding: u32

Requires kernel patch (FUSE_REMAP_FILE_RANGE not yet upstream).

Tested:
  cargo build --features abi-7-28
  cargo test --features abi-7-28
  E2E: ejc3/fcvm#21
    - cp --reflink=always through FUSE → btrfs
    - filefrag confirms shared extents
ejc3 added a commit to ejc3/fuser that referenced this pull request Feb 2, 2026
Adds userspace support for the new FUSE_REMAP_FILE_RANGE opcode (53)
which enables reflink operations (FICLONE/FICLONERANGE ioctls) through
FUSE filesystems.

Changes:
- Add FUSE_REMAP_FILE_RANGE opcode (53) to fuse_opcode enum
- Add fuse_remap_file_range_in wire struct matching kernel ABI
- Add RemapFileRange request parsing in ll/request.rs
- Add remap_file_range() method to Filesystem trait with default ENOSYS
- Wire up request dispatch in request.rs

Wire format (fuse_remap_file_range_in):
  - fh_in: u64, off_in: i64, nodeid_out: u64, fh_out: u64
  - off_out: i64, len: u64, remap_flags: u32, padding: u32

Requires kernel patch (FUSE_REMAP_FILE_RANGE not yet upstream).

Tested:
  cargo build --features abi-7-28
  cargo test --features abi-7-28
  E2E: ejc3/fcvm#21
    - cp --reflink=always through FUSE → btrfs
    - filefrag confirms shared extents
ejc3 added a commit to ejc3/fuser that referenced this pull request Feb 5, 2026
Adds userspace support for the new FUSE_REMAP_FILE_RANGE opcode (53)
which enables reflink operations (FICLONE/FICLONERANGE ioctls) through
FUSE filesystems.

Changes:
- Add FUSE_REMAP_FILE_RANGE opcode (53) to fuse_opcode enum
- Add fuse_remap_file_range_in wire struct matching kernel ABI
- Add RemapFileRange request parsing in ll/request.rs
- Add remap_file_range() method to Filesystem trait with default ENOSYS
- Wire up request dispatch in request.rs

Wire format (fuse_remap_file_range_in):
  - fh_in: u64, off_in: i64, nodeid_out: u64, fh_out: u64
  - off_out: i64, len: u64, remap_flags: u32, padding: u32

Requires kernel patch (FUSE_REMAP_FILE_RANGE not yet upstream).

Tested:
  cargo build --features abi-7-28
  cargo test --features abi-7-28
  E2E: ejc3/fcvm#21
    - cp --reflink=always through FUSE → btrfs
    - filefrag confirms shared extents
ejc3 added a commit to ejc3/fuser that referenced this pull request Feb 6, 2026
Adds userspace support for the new FUSE_REMAP_FILE_RANGE opcode (53)
which enables reflink operations (FICLONE/FICLONERANGE ioctls) through
FUSE filesystems.

Changes:
- Add FUSE_REMAP_FILE_RANGE opcode (53) to fuse_opcode enum
- Add fuse_remap_file_range_in wire struct matching kernel ABI
- Add RemapFileRange request parsing in ll/request.rs
- Add remap_file_range() method to Filesystem trait with default ENOSYS
- Wire up request dispatch in request.rs

Wire format (fuse_remap_file_range_in):
  - fh_in: u64, off_in: i64, nodeid_out: u64, fh_out: u64
  - off_out: i64, len: u64, remap_flags: u32, padding: u32

Requires kernel patch (FUSE_REMAP_FILE_RANGE not yet upstream).

Tested:
  cargo build --features abi-7-28
  cargo test --features abi-7-28
  E2E: ejc3/fcvm#21
    - cp --reflink=always through FUSE → btrfs
    - filefrag confirms shared extents
ejc3 added a commit that referenced this pull request Mar 2, 2026
Add FUSE remap_file_range support for FICLONE/FICLONERANGE
ejc3 added a commit that referenced this pull request Mar 2, 2026
Add FUSE remap_file_range support for FICLONE/FICLONERANGE
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