Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
89a144a
feat: sparse writes with range_upload, zero-download write path
XciD Mar 20, 2026
1d0eb68
fix: upgrade NFS read-only handles to writable on first write
XciD Mar 20, 2026
c50d539
feat(vfs): wire sparse-write paths in mod.rs (open/read/write/setattr…
XciD May 4, 2026
5f1910a
ci: trigger
XciD May 4, 2026
e5b818e
fixup! feat: sparse writes with range_upload, zero-download write path
XciD May 5, 2026
9dca8d0
test: add fsx_paranoid CAS round-trip variant
XciD May 5, 2026
831dfc6
test: gate sparse-write fs_tests behind HF_MOUNT_SPARSE_TESTS
XciD May 5, 2026
c390636
fix: update xet-core to verification fix, remove sparse test gate, cl…
XciD May 6, 2026
872619c
chore(deps): pin xet-core to 40f95307
XciD May 21, 2026
2a5f7e5
fix(vfs): only install sparse_write when staging is freshly sparse
XciD May 21, 2026
0402a44
fix(vfs): preserve sparse state after range_upload flush
XciD May 21, 2026
6038c5c
test(vfs): regression for post-flush read on sparse handle
XciD May 21, 2026
027ba32
fix(vfs): install sparse_write even if inode xet_hash drifts mid-open
XciD May 21, 2026
4289aee
fix(vfs): no-op flush must not roll back drifted inode hash
XciD May 21, 2026
1df3886
fix(vfs): bail with EAGAIN on inode drift during sparse open
XciD May 21, 2026
0c180fd
fix(vfs): transparently retry open on inode drift instead of surfacin…
XciD May 21, 2026
9fcd9de
test(vfs): cover range_upload truncate-past-end, clean->dirty fallbac…
XciD May 21, 2026
140fe76
refactor(flush): extract find_regular_run_end and centralize abort lo…
XciD May 21, 2026
5be7939
fix(vfs): clamp tracked dirty range to staging length + cleanup nits
XciD May 21, 2026
f5f5708
style: cargo +nightly fmt
XciD May 21, 2026
d3c67f1
fix(vfs): 3 P0/P1 bugs caught by code review (panic, mtime, spurious …
XciD May 21, 2026
ff77bec
perf(vfs): share one staging FD across all DirtyInputs in range_upload
XciD May 21, 2026
54052fc
fix(vfs): close sparse-write correctness gaps in open/write paths
XciD May 21, 2026
62aa4b5
fix(vfs): skip CAS round-trip for reads on reused-staging opens
XciD May 22, 2026
06dbe6e
ci: wire fsx_paranoid into the fsx job
XciD May 22, 2026
0387c23
fix(vfs): close 3 sparse-flush correctness gaps from codex review
XciD May 22, 2026
78c38b7
fix(vfs): tighten sparse_write lifecycle (codex round 2)
XciD May 22, 2026
ca4ade5
fix(vfs): close remaining sparse_write lifecycle races
XciD May 22, 2026
202b50a
fix(vfs): lazily install sparse_write on reused-fh writes after regul…
XciD May 27, 2026
a04bcdd
fix(vfs): close 15 sparse-write correctness gaps from code review
XciD May 27, 2026
d6c7408
ci: trigger
XciD May 28, 2026
d1cf853
chore: remove TODO.md
XciD May 28, 2026
6d54716
refactor(vfs): drop over-engineered defenses from code-review fixes
XciD May 28, 2026
1e9da5d
fix(vfs): use sync per-inode I/O lock so NFS handlers don't panic
XciD May 28, 2026
df642bc
feat(vfs): gate sparse writes behind --sparse-writes (off by default)
XciD May 28, 2026
20f6f46
fix(vfs): close 3 sparse-write findings from codex review
XciD May 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ jobs:
timeout-minutes: 10
run: cargo test --release --test fsx -- --test-threads=1 --nocapture

- name: fsx paranoid (CAS round-trip per mutation)
timeout-minutes: 15
run: cargo test --release --test fsx_paranoid -- --test-threads=1 --nocapture

xfstests:
name: xfstests (filesystem exerciser)
runs-on:
Expand Down
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ categories = ["filesystem", "command-line-utilities"]

[dependencies]
# xet-core crates
xet-client = { git = "https://github.com/huggingface/xet-core.git", branch = "main" }
xet-core-structures = { git = "https://github.com/huggingface/xet-core.git", branch = "main" }
xet-data = { git = "https://github.com/huggingface/xet-core.git", branch = "main" }
xet-runtime = { git = "https://github.com/huggingface/xet-core.git", branch = "main" }
xet-client = { git = "https://github.com/huggingface/xet-core.git", rev = "40f9530753e48f9517b5ad09e2339df7059d8de4" }
xet-core-structures = { git = "https://github.com/huggingface/xet-core.git", rev = "40f9530753e48f9517b5ad09e2339df7059d8de4" }
xet-data = { git = "https://github.com/huggingface/xet-core.git", rev = "40f9530753e48f9517b5ad09e2339df7059d8de4" }
xet-runtime = { git = "https://github.com/huggingface/xet-core.git", rev = "40f9530753e48f9517b5ad09e2339df7059d8de4" }

# External crates
async-trait = "0.1"
Expand Down
2 changes: 1 addition & 1 deletion src/cached_xet_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl CachedXetClient {
}
}

/// Derive a range-scoped `QueryReconstructionResponse` from a cached full-file response.
/// Derive a range-scoped `QueryReconstructionResponseV2` from a cached full-file response.
///
/// The full-file response lists all terms in file order with their unpacked byte lengths.
/// We walk the terms, track cumulative byte offsets, and keep only terms that overlap
Expand Down
5 changes: 5 additions & 0 deletions src/nfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,11 @@ fn errno_to_nfs(e: i32) -> nfsstat3 {
libc::ENOTEMPTY => nfsstat3::NFS3ERR_NOTEMPTY,
libc::EBADF => nfsstat3::NFS3ERR_STALE,
libc::ENOSPC => nfsstat3::NFS3ERR_NOSPC,
// EAGAIN signals a transient condition the caller should retry
// (e.g., open_advanced_write exhausted its drift-retry budget).
// NFS3ERR_JUKEBOX tells the client to back off and retry; mapping
// to EIO would surface as a hard failure for a recoverable case.
libc::EAGAIN => nfsstat3::NFS3ERR_JUKEBOX,
_ => nfsstat3::NFS3ERR_IO,
}
}
Expand Down
24 changes: 24 additions & 0 deletions src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,15 @@ pub struct MountOptions {
#[arg(long, default_value_t = false)]
pub advanced_writes: bool,

/// EXPERIMENTAL (beta). Skip the full CAS download when opening for write
/// and only upload modified byte ranges via `range_upload`. Much faster
/// for large files with small edits, but exercises more lifecycle paths
/// (handle pool reuse, drift retries, multi-handle reads/writes) than the
/// download-then-upload mode. Off by default — opt in if you understand
/// the trade-off. Implies --advanced-writes.
#[arg(long, default_value_t = false)]
pub sparse_writes: bool,

/// Interval in seconds for polling remote changes (0 to disable).
#[arg(long, default_value_t = 30)]
pub poll_interval_secs: u64,
Expand Down Expand Up @@ -230,6 +239,7 @@ pub struct MountSetup {
pub mount_point: PathBuf,
pub read_only: bool,
pub advanced_writes: bool,
pub sparse_writes: bool,
pub direct_io: bool,
pub metadata_ttl: std::time::Duration,
pub max_threads: usize,
Expand Down Expand Up @@ -428,6 +438,18 @@ pub fn build_with_runtime(
let xet_sessions = XetSessions::new(xet_ctx, download_session, upload_config, cached_client, xorb_cache);

let advanced_writes = options.advanced_writes || options.overlay || (is_nfs && !read_only);
// Sparse writes are an experimental optimization on top of advanced writes.
// They imply advanced_writes (the advanced_writes path is where the sparse
// staging lives), but advanced_writes does NOT imply sparse_writes — the
// safe default is to download-then-write, which is well-tested and avoids
// the lifecycle edge cases that sparse staging exposes.
let sparse_writes = options.sparse_writes && advanced_writes;
if options.sparse_writes && !advanced_writes {
warn!("--sparse-writes ignored: requires --advanced-writes (or NFS read-write, or --overlay)");
}
if sparse_writes {
warn!("--sparse-writes is EXPERIMENTAL. Disable with `--sparse-writes=false` if you see issues.");
}

// Overlay: open a pre-mount fd to the mount point directory. The fd is
// held by OverlayBacking so overlay-local filesystem ops can stay rooted
Expand Down Expand Up @@ -526,6 +548,7 @@ pub fn build_with_runtime(
VfsConfig {
read_only,
advanced_writes,
sparse_writes,
uid,
gid,
poll_interval_secs: options.poll_interval_secs,
Expand All @@ -552,6 +575,7 @@ pub fn build_with_runtime(
mount_point,
read_only,
advanced_writes,
sparse_writes,
direct_io: options.direct_io,
metadata_ttl,
max_threads: options.max_threads,
Expand Down
Loading
Loading