Skip to content

Add sync_fs() to service FUSE_SYNCFS#692

Open
edmc-ss wants to merge 1 commit into
cberner:masterfrom
edmc-ss:syncfs
Open

Add sync_fs() to service FUSE_SYNCFS#692
edmc-ss wants to merge 1 commit into
cberner:masterfrom
edmc-ss:syncfs

Conversation

@edmc-ss

@edmc-ss edmc-ss commented Jul 1, 2026

Copy link
Copy Markdown

Summary

Adds support for servicing FUSE_SYNCFS — the opcode the kernel issues for syncfs(2)/sync(2) — plus the opt-in FUSE_HAS_SYNCFS INIT capability that lets a privileged /dev/fuse server receive it.

  • New Filesystem::sync_fs(&self, req, ino, ReplyEmpty) trait method; defaults to ENOSYS, which the kernel treats as a permanent success (same convention as fsync/statfs).
  • FUSE_SYNCFS = 50 opcode, a header-only SyncFs request, its Operation variant, and request parsing/dispatch/Display.
  • InitFlags::FUSE_HAS_SYNCFS = 1 << 43 (protocol 7.46), requested by a server via KernelConfig::add_capabilities().

Dependency on the Linux VFS fuse driver (please read)

This is the important caveat. Although the FUSE_SYNCFS opcode has existed for a while (added for virtiofs), the in-kernel fuse driver only propagates syncfs()/sync() to the userspace server (fc->sync_fs) for virtiofs and fuseblk mounts. A plain /dev/fuse server never receives it today — regardless of what it advertises — because an untrusted server could stall sync() indefinitely.

Consequences:

  • On current released kernels, this PR immediately benefits fuseblk fuser servers (they already receive FUSE_SYNCFS), and is a harmless no-op for plain servers.
  • For plain /dev/fuse servers to receive it, the kernel needs the in-flight opt-in: a new FUSE_HAS_SYNCFS INIT flag, honored only when the server opened /dev/fuse with CAP_SYS_ADMIN in the initial user namespace (the same privilege that mounting virtiofs/fuseblk already requires). That series — "fuse: allow FUSE_SYNCFS for privileged userspace servers" — is on LKML (patch, LWN summary) and not yet merged. The 1 << 43 bit and protocol minor 7.46 here match that patch's UAPI.

Because KernelConfig::add_capabilities(InitFlags::FUSE_HAS_SYNCFS) returns Err when the running kernel doesn't offer the flag, a server can cleanly detect an unsupporting kernel and fall back (e.g. to an out-of-band flush) rather than silently never being called.

Design notes

  • FUSE_KERNEL_MINOR_VERSION is intentionally left at 40. The kernel gates this flag on the opener's privilege rather than the negotiated minor, and it rides in the high-32 flags2 (already carried via FUSE_INIT_EXT), so it works without claiming the intervening 7.41–7.45 features fuser doesn't yet implement. Happy to bump the minor if you'd prefer.
  • SyncFs is modeled on StatFs: filesystem-wide and header-only (the wire fuse_syncfs_in is a single reserved u64 padding word, so there's no argument to expose).
  • Mirrors libfuse's low-level syncfs op, which likewise replies ENOSYS when unimplemented.

Testing

cargo test (including a new FUSE_SYNCFS parse test), cargo clippy --all-targets, cargo fmt --check, and cargo doc (with -D rustdoc::broken_intra_doc_links) all pass on Linux (aarch64, toolchain 1.85). Not exercised against a live mount, since the privileged-plain-server kernel path isn't in a shipping kernel yet (see above).

Wire up the FUSE_SYNCFS opcode (50) so a filesystem can service
syncfs(2)/sync(2): a new header-only SyncFs request, an Operation
variant, request parsing/dispatch, and a Filesystem::sync_fs() trait
method that defaults to ENOSYS (which the kernel treats as a permanent
success, matching fsync/statfs).

Also add the InitFlags::FUSE_HAS_SYNCFS (1 << 43, protocol 7.46) opt-in
capability. Because Init negotiation already carries the high-32 flags2
via FUSE_INIT_EXT, a server enables it by requesting it through
KernelConfig::add_capabilities(); add_capabilities() returns Err when the
kernel doesn't offer it, so a server can detect an unsupporting kernel
and fall back.

FUSE_KERNEL_MINOR_VERSION is intentionally left at 40: the kernel gates
this flag on the opener's privilege rather than the negotiated minor, and
it rides in flags2, so it works without claiming the intervening
7.41-7.45 features fuser doesn't implement.
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