Have you run any POSIX compliance checks against it? In particular, how are you handling assignment of inode numbers (fileid in NFS speak) to "virtual" files and making sure those stay reasonably consistent? (I vaguely remember this being a bit of a tripwire)
Also did you look at NFSv4 / what made you decide to go with NFSv3? My (superficial) impression was that NFSv4 did a lot of simplifying and throwing out legacy stuff (e.g. rpcbind), but I don't know too many details on this…
I tested by uh... building a "mirrorfs" and compiling this project in it :-) (cargo does stress it pretty hard). I have not looked for POSIX compliance testers. Is there one you can point me to?
NFSv4 did throw out a lot of the legacy stuff, but also added a bunch of other state information like locks and delegation which is quite a bit more annoying to implement. Technically cos this is meant for "localhost-mounting-only", delegation should be easy to build (since we are expecting only exactly 1 mount). But v3 had far fewer APIs to implement, and so is a good starting point.
Note that there’s absolutely no requirement to support more advanced features such as locking and delegations. Even if a client offers to accept a delegation, a server may just deny/ignore it as part of OPEN.
There's https://github.com/google/file-system-stress-testing but in this case I believe it would mostly stress-test the NFS client rather than your code… and I have never tried to use it, no idea if it even does anything useful.
I know from lore that there are compliance-test suites for the POSIX file system API, but I believe those are commercial products :(
If I may ask, is this mirrorfs available somewhere? The demofs from nfsserve seems to create and server a pure in-memory fs tree if I read the sources correctly.
NFSv4 is a completely different protocol and basically doesn't share anything with v2/v3. While technically it's still implemented using Sun RPC, it only has two procedures: NULL and COMPOUND. Version 3 is actually an RPC protocol, with a different procedure for each filesystem operation (READ, WRITE, CREATE, ...). One of the genius moves that Sun made with NFS was to distribute the protocol files (rpcgen) which autogenerate stubs (in C) making it easy to implement servers and clients. Nothing like that exists for v4.
Which is also what you want, right? The issue is that with compound calls there is some state that’s carried over between operations (current/saved file handle), so you’d need to implement that yourself anyway.
Well yeah that's the difference, it doesn't generate the state machine for you so you "just" need to implement it yourself. For v3, rpcgen spits out a working function that you link into your program and you're done (on the client side anyway). Much easier.
You simply need to implement the vfs::NFSFileSystem trait.
Wait, what......
.. So not only is it an easy-to-run Rust NFS server and client (I gave up on NFS some years ago because I couldn't figure out how to run Samba) but it's also meant to use as a _substitute_ for FUSE in stacks like SSHFS or an app wanting to serve debug data as files?
Sweet! I've been monkeying around with writing an HFS interpreter (in rust ofc). Unfortunately 'fuser' is less than ideal on a Mac. This could be an interesting alternative.
Edit: Oh. It's async. The other bit that I liked from fuser: the default implementations in the trait cut down on the boiler plate. Setting the RO mount option got you defaults that DTRT.
I don't think this includes a client, in fact the post argues that not having to implement the client because it already exists in the kernel was a major benefit of the approach…
I have not looked at WebDAV closely. I was looking for something that is already supported in all the major operating systems without additional libraries. I don't believe WebDAV is commonly supported out of the box?
WebDAV is supported by Windows, MacOS and Linux. On all platforms you can mount it without admin/sudo (`net use` on Windows, `mount_webdav` on macOS and `gio mount` on Linux). Here is official Go package[1] using which you can implement your own WebDAV server (you only need to implement your FS interface).
I believe you can install an NFS client on windows home if you just go to programs and features > add a feature > NFS client, but I don't have a way to check.
The fact you just need to impl one trait is amazing. I will definitely be testing this out
Comments
Hi! Author here. Happy to answer any questions!
Have you run any POSIX compliance checks against it? In particular, how are you handling assignment of inode numbers (fileid in NFS speak) to "virtual" files and making sure those stay reasonably consistent? (I vaguely remember this being a bit of a tripwire)
Also did you look at NFSv4 / what made you decide to go with NFSv3? My (superficial) impression was that NFSv4 did a lot of simplifying and throwing out legacy stuff (e.g. rpcbind), but I don't know too many details on this…
[edit: NFSv4 answered on parent / https://news.ycombinator.com/item?id=37575304 ]
FWIW I think NFSv4 would be a rewrite rather than an extension :D
I tested by uh... building a "mirrorfs" and compiling this project in it :-) (cargo does stress it pretty hard). I have not looked for POSIX compliance testers. Is there one you can point me to?
NFSv4 did throw out a lot of the legacy stuff, but also added a bunch of other state information like locks and delegation which is quite a bit more annoying to implement. Technically cos this is meant for "localhost-mounting-only", delegation should be easy to build (since we are expecting only exactly 1 mount). But v3 had far fewer APIs to implement, and so is a good starting point.
Note that there’s absolutely no requirement to support more advanced features such as locking and delegations. Even if a client offers to accept a delegation, a server may just deny/ignore it as part of OPEN.
There's https://github.com/google/file-system-stress-testing but in this case I believe it would mostly stress-test the NFS client rather than your code… and I have never tried to use it, no idea if it even does anything useful.
I know from lore that there are compliance-test suites for the POSIX file system API, but I believe those are commercial products :(
xfstests is very thorough and reusable beyond xfs.
If I may ask, is this mirrorfs available somewhere? The demofs from nfsserve seems to create and server a pure in-memory fs tree if I read the sources correctly.
NFSv4 is a completely different protocol and basically doesn't share anything with v2/v3. While technically it's still implemented using Sun RPC, it only has two procedures: NULL and COMPOUND. Version 3 is actually an RPC protocol, with a different procedure for each filesystem operation (READ, WRITE, CREATE, ...). One of the genius moves that Sun made with NFS was to distribute the protocol files (rpcgen) which autogenerate stubs (in C) making it easy to implement servers and clients. Nothing like that exists for v4.
Look at RFC 7531. XDR definitions for NFSv4 exists, and they can also be used to generate C bindings if you want.
Sure, running it through rpcgen generates bindings for both RPCs, NULL and COMPOUND:
Which is also what you want, right? The issue is that with compound calls there is some state that’s carried over between operations (current/saved file handle), so you’d need to implement that yourself anyway.
Well yeah that's the difference, it doesn't generate the state machine for you so you "just" need to implement it yourself. For v3, rpcgen spits out a working function that you link into your program and you're done (on the client side anyway). Much easier.
Wait, what......
.. So not only is it an easy-to-run Rust NFS server and client (I gave up on NFS some years ago because I couldn't figure out how to run Samba) but it's also meant to use as a _substitute_ for FUSE in stacks like SSHFS or an app wanting to serve debug data as files?
Awesome!
Exactly. You build the server-side (as a FUSE alternative), and just use the OS's NFS client to mount it.
Sweet! I've been monkeying around with writing an HFS interpreter (in rust ofc). Unfortunately 'fuser' is less than ideal on a Mac. This could be an interesting alternative.
Edit: Oh. It's async. The other bit that I liked from fuser: the default implementations in the trait cut down on the boiler plate. Setting the RO mount option got you defaults that DTRT.
You can interoperate async and threads, but yes you have to tolerate having Tokio or similar as a dep
I don't think this includes a client, in fact the post argues that not having to implement the client because it already exists in the kernel was a major benefit of the approach…
This library is amazing. Also very happy to see such a permissive license.
Btw, why did you decide to use NFS instead of WebDAV? WebDAV should be easier to implement and is also supported on all platforms.
I have not looked at WebDAV closely. I was looking for something that is already supported in all the major operating systems without additional libraries. I don't believe WebDAV is commonly supported out of the box?
WebDAV is supported by Windows, MacOS and Linux. On all platforms you can mount it without admin/sudo (`net use` on Windows, `mount_webdav` on macOS and `gio mount` on Linux). Here is official Go package[1] using which you can implement your own WebDAV server (you only need to implement your FS interface).
[1] https://pkg.go.dev/golang.org/x/net/webdav
Interesting. I do not know much about webdav. Great to learn something new! Will take a look.
WebDAV on Linux works over drumrull FUSE :D
I believe you can install an NFS client on windows home if you just go to programs and features > add a feature > NFS client, but I don't have a way to check.
The fact you just need to impl one trait is amazing. I will definitely be testing this out
You're right, there is no way to do it in windows home edition