Standard Grant: Sia NFS Gateway - indexd & NFSv4 (rebranded to: JanusFS)

July 2026 Progress Report

What progress was made on your grant this month?

  • Addressed issues that came up during review
  • Additional CLI options added to support branching & tagging (snapshots)
  • CLI options added to make using indexd more user-friendly
  • Rebranding: The project was rebranded to JanusFS. This includes the library names as well.
  • User-facing docs have been updated.
  • Milestone 4 - NFSv4 support

Detail the tasks worked on this month per milestone, with the appropriate Pull Request link(s), as outlined in the guide:

Milestone Task Pull Request(s) Additional Notes
Milestone 3 1. Review fixes Review/2026-06 · Pull Request #16 · rrauch/janus-fs · GitHub Completes Milestone 3
2. Extra CLI commands Extra CLI commands · Pull Request #17 · rrauch/janus-fs · GitHub branching & tagging
3. authorize & status CLI commands Additional CLI improvements · Pull Request #19 · rrauch/janus-fs · GitHub improves indexd ease-of-use
4. Rebranding Project Rebranding · Pull Request #18 · rrauch/janus-fs · GitHub to JanusFS
5. Documentation update Docs Update · Pull Request #20 · rrauch/janus-fs · GitHub
Milestone 4 3. NFSv4 support NFSv4 Support · Pull Request #21 · rrauch/janus-fs · GitHub Most of the work was done here

Summarize any problems that you ran into this month and how you’ll be solving them.

When planning Milestone 4 (NFSv4 support) I made the decision to focus on supporting NFSv4.1 (originally released in 2010) as it fixes several shortcomings of NFSv4.0 (originally released in 2000). As NFSv4.1 is already over 16 years old at this point, I expected it should be well supported by now.

However, during testing I found out that macOS does not support anything higher than NFSv4.0. So I had to retroactively add support for NFSv4.0 as well. This cost extra time and the result is not ideal. Especially as I have to deal with the shortcomings of NFSv4.0 (mainly around state-management).

I was able to add what was needed to make it work under macOS, but I feel like this part will need some additional testing + some refactoring in the long run.

On the plus side, this project now supports NFSv3, NFSv4 & NFSv4.1 simultaneously and without any extra configuration from the user.

What will you be working on next month?

  • Additional testing on macOS
  • Refactoring the state management (as mentioned above)
  • Any issues raised during the next review.

Other than that, the project is now considered complete from my side.

1 Like

Hi @rrauch - thank you for your final report. Your technical review is complete for this last milestone of your grant, and your reviewer passed on the following:

Area for Improvement:

> More testing of NFS code required

You’ve already acknowledged more testing is required on macOS, especially since you ran into some issues and needed to add support for NFSv4.0 after all.

We would like to see the results of that testing before marking this grant ‘complete’ and issuing the final payment.

Hi @mecsbecs, thank you for the feedback.

NFSv4

Since my previous update I have focused on refactoring & testing the NFSv4 support. The changes can be seen here: Commits · rrauch/nfsserve · GitHub

There is now a cleaner separation between v4.0 & v4.1, several missing commands have been added to increase compatibility (mainly for macOS) & more unit tests were added here: nfsserve/src/nfs4/state.rs at 8c7c3da49641ae99cebaac6969682426160361cb · rrauch/nfsserve · GitHub

Here is the result of running the unit tests:

running 28 tests
test nfs4::state::tests::bad_seqid_preserves_the_open_owner ... ok
test nfs4::state::tests::close_of_an_unknown_stateid_records_nothing ... ok
test nfs4::state::tests::client_owns_its_state ... ok
test nfs4::state::tests::close_tombstone_is_one_per_open_owner ... ok
test nfs4::state::tests::expiry_purges_everything_the_client_owned ... ok
test nfs4::state::tests::failed_op_does_not_desync_the_owner_seqid ... ok
test nfs4::state::tests::failed_op_still_consumes_the_owner_seqid ... ok
test nfs4::state::tests::open_confirm_marks_the_owner_and_replays ... ok
test nfs4::state::tests::open_confirm_rejects_a_stale_stateid_on_a_fresh_seqid ... ok
test nfs4::state::tests::open_downgrade_keeps_the_owner_seqid_level ... ok
test nfs4::state::tests::owner_seqid_detects_retransmits ... ok
test nfs4::state::tests::open_downgrade_retransmit_replays ... ok
test nfs4::state::tests::rejected_lock_books_the_open_owner_seqid ... ok
test nfs4::state::tests::rejected_owner_op_replays ... ok
test nfs4::state::tests::resolve_renews_the_lease ... ok
test nfs4::state::tests::repeat_open_upgrades_one_state ... ok
test nfs4::state::tests::setclientid_confirm_rejects_a_wrong_verifier_without_touching_state ... ok
test nfs4::state::tests::retained_errors_do_not_consume_the_owner_seqid ... ok
test nfs4::state::tests::setclientid_retry_keeps_state_and_only_a_confirmed_reboot_drops_it ... ok
test nfs4::state::tests::stale_stateid_seqid_is_rejected ... ok
test nfs4::state::tests::v40_close_retransmit_replays ... ok
test nfs4::state::tests::v41_cannot_open_confirm ... ok
test nfs4::state::tests::stateid_is_bound_to_its_client ... ok
test nfs4::state::tests::v41_close_releases_the_handle_despite_a_stale_wire_seqid ... ok
test nfs4::state::tests::v41_keeps_no_open_owner_state ... ok
test nfs4::state::tests::versions_do_not_share_an_owner_namespace ... ok
test nfs4::state::tests::v41_open_of_a_second_file_is_not_a_replay ... ok
test nfs4::state::tests::by_owner_ignores_a_pending_setclientid ... ok

test result: ok. 28 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Additionally, I have added a test script to run integration tests with common workloads on common NFS clients. I have run these tests on Linux (both using NFSv4.1 & NFSv4.0) & macOS (NFSV4.0 only):

Linux (NFSv4.0):

========================================================================
nfstest.py   Linux 6.8.0-137-generic   python 3.12.3
mountpoint : /tmp/foo/nfs
mount      : localhost:/ on /tmp/foo/nfs type nfs4 (rw,relatime,vers=4.0,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,port=11111,timeo=600,retrans=2,sec=sys,clientaddr=127.0.0.1,local_lock=none,addr=127.0.0.1)
uid/gid    : 1000/1000   umask 0002
scratch    : nfs/nfstest.thinkpad.22748
========================================================================
[ PASS ] rw/write-read-verify                 0.08s
[ PASS ] rw/append                            0.03s
[ PASS ] rw/overwrite-at-offset               0.04s
[ PASS ] rw/reopen-o-trunc                    0.03s
[ PASS ] rw/1MB-sha256                        0.04s
[ PASS ] rw/bigfile-sha256                    1.18s
[ PASS ] dir/mkdir-rmdir                      0.03s
[ PASS ] dir/readdir-10                       0.15s
[ PASS ] dir/readdir-100                      1.69s
[ PASS ] dir/recursive-walk                   0.48s
[ PASS ] ns/rename-same-dir                   0.03s
[ PASS ] ns/rename-across-dirs                0.04s
[ PASS ] ns/rename-over-existing              0.04s
[ PASS ] ns/rename-dir                        0.03s
[ PASS ] ns/unlink                            0.03s
[ PASS ] ns/symlink-readlink                  0.04s
[ PASS ] attr/size-after-close                0.08s
[ PASS ] attr/chmod                           0.03s
[ PASS ] attr/mtime-changes-on-write          1.24s
[ PASS ] attr/truncate-grow-shrink            0.04s
[ PASS ] err/enoent                           0.01s
[ PASS ] err/eexist                           0.02s
[ PASS ] err/rmdir-nonempty-fails             0.03s
[ PASS ] err/eisdir-enotdir                   0.03s
[ PASS ] coh/write-then-read-other-process    0.11s
[ PASS ] coh/truncate-then-stat               0.09s
[ PASS ] coh/create-then-readdir              0.08s
[ PASS ] coh/unlink-then-stat                 0.09s
------------------------------------------------------------------------
28 passed, 0 failed, 0 skipped in 6.7s

Linux (NFSv4.1):

========================================================================
nfstest.py   Linux 6.8.0-137-generic   python 3.12.3
mountpoint : /tmp/foo/nfs
mount      : localhost:/ on /tmp/foo/nfs type nfs4 (rw,relatime,vers=4.1,rsize=1047672,wsize=1047532,namlen=255,hard,proto=tcp,port=11111,timeo=600,retrans=2,sec=sys,clientaddr=127.0.0.1,local_lock=none,addr=127.0.0.1)
uid/gid    : 1000/1000   umask 0002
scratch    : nfs/nfstest.thinkpad.22792
========================================================================
[ PASS ] rw/write-read-verify                 0.12s
[ PASS ] rw/append                            0.03s
[ PASS ] rw/overwrite-at-offset               0.03s
[ PASS ] rw/reopen-o-trunc                    0.03s
[ PASS ] rw/1MB-sha256                        0.05s
[ PASS ] rw/bigfile-sha256                    2.64s
[ PASS ] dir/mkdir-rmdir                      0.04s
[ PASS ] dir/readdir-10                       0.16s
[ PASS ] dir/readdir-100                      1.85s
[ PASS ] dir/recursive-walk                   0.36s
[ PASS ] ns/rename-same-dir                   0.03s
[ PASS ] ns/rename-across-dirs                0.05s
[ PASS ] ns/rename-over-existing              0.05s
[ PASS ] ns/rename-dir                        0.03s
[ PASS ] ns/unlink                            0.03s
[ PASS ] ns/symlink-readlink                  0.04s
[ PASS ] attr/size-after-close                0.08s
[ PASS ] attr/chmod                           0.04s
[ PASS ] attr/mtime-changes-on-write          1.24s
[ PASS ] attr/truncate-grow-shrink            0.05s
[ PASS ] err/enoent                           0.01s
[ PASS ] err/eexist                           0.02s
[ PASS ] err/rmdir-nonempty-fails             0.03s
[ PASS ] err/eisdir-enotdir                   0.03s
[ PASS ] coh/write-then-read-other-process    0.11s
[ PASS ] coh/truncate-then-stat               0.09s
[ PASS ] coh/create-then-readdir              0.08s
[ PASS ] coh/unlink-then-stat                 0.08s
------------------------------------------------------------------------
28 passed, 0 failed, 0 skipped in 8.4s

macOS (NFSv4.0):

========================================================================
nfstest.py   Darwin 22.1.0   python 3.9.6
mountpoint : /private/tmp/nfs
mount      : 192.168.40.52:/ on /private/tmp/nfs (nfs, nodev, nosuid, mounted by foo)
uid/gid    : 501/20   umask 0022
scratch    : nfs/nfstest.Foos-Mac.1030
========================================================================
[ PASS ] rw/write-read-verify                 0.34s
[ PASS ] rw/append                            0.17s
[ PASS ] rw/overwrite-at-offset               0.22s
[ PASS ] rw/reopen-o-trunc                    0.11s
[ PASS ] rw/1MB-sha256                        0.17s
[ PASS ] rw/bigfile-sha256                   12.63s
[ PASS ] dir/mkdir-rmdir                      0.13s
[ PASS ] dir/readdir-10                       0.36s
[ PASS ] dir/readdir-100                      3.79s
[ PASS ] dir/recursive-walk                   1.21s
[ PASS ] ns/rename-same-dir                   0.08s
[ PASS ] ns/rename-across-dirs                0.12s
[ PASS ] ns/rename-over-existing              0.11s
[ PASS ] ns/rename-dir                        0.10s
[ PASS ] ns/unlink                            0.27s
[ PASS ] ns/symlink-readlink                  0.12s
[ PASS ] attr/size-after-close                0.16s
[ PASS ] attr/chmod                           0.09s
[ PASS ] attr/mtime-changes-on-write          1.30s
[ PASS ] attr/truncate-grow-shrink            0.11s
[ PASS ] err/enoent                           0.02s
[ PASS ] err/eexist                           0.05s
[ PASS ] err/rmdir-nonempty-fails             0.09s
[ PASS ] err/eisdir-enotdir                   0.06s
[ PASS ] coh/write-then-read-other-process    0.32s
[ PASS ] coh/truncate-then-stat               0.16s
[ PASS ] coh/create-then-readdir              0.16s
[ PASS ] coh/unlink-then-stat                 0.18s
------------------------------------------------------------------------
28 passed, 0 failed, 0 skipped in 25.8s

During the above work several issues were identified & fixed. At this point I cannot find any additional issues with the NFSv4 support & all tests pass reliably.

Release

I went ahead and pushed a release (0.5.0) to the projects Github. A corresponding docker image has been released along with it.

I believe the project has delivered the agreed-upon milestones and can be used as envisioned.

1 Like

Hi @rrauch - glad to see running these tests was useful, and thank you for completing them. With this, I will mark this grant as ‘Complete’ and congratulations! Your final payment will be issued on the 15th.

1 Like