Open parasyte opened 8 years ago
The unmount method is private since resources are meant to be managed by RAII and the FUSE filesystem lives as long as the Session
exists. Dropping the Session
will unmount the filesystem to clean up.
If you try to mount a filesystem at a path that already has a filesystem mounted, the correct behavior is to error. If you want to unmount an existing mount for convenience, you could try using the libc umount method.
The problem with Ctrl-C is, that the Rust program gets interrupted and immediately quits without running Session::drop
. We need a chance to free the resource (unmount) even with Ctrl-C. C/C++ programs typically use the libc atexit
mechanism for this, but afaik Rust does not provide such a mechanism yet(?)
That's right. There seems to be little interest in getting atexit
working in Rust at the moment: https://github.com/rust-lang/rfcs/issues/712 And it sounds like it won't be foolproof, anyway: https://github.com/rust-lang/rust/issues/11695#issuecomment-32834967
It can never be foolproof - e.g. SIGKILL
doesn't give a process any chance to react. But it sure would be nice to handle catchable signals like SIGINT
(crtl-c), SIGHUP
, SIGTERM
.
That was my conclusion, and reasoning for pre-mount cleanup. :wink: It looks like the private unmount
is perfect for that, since it takes care of some important details like the EPERM
case on Linux.
I've copy-pasted it into my crate for the time being. That will do if the function cannot be made public.
@parasyte A superior solution IMO would be handling signals in the application (e.g. with the chan-signal crate) and letting the cleanup happen naturally (through RAII).
We could also think about adding signal handling to rust-fuse
. With chan-signal
it seems pretty easy and could be enabled/disabled via a cargo feature flag. This sounds convenient, however I'm not sure if I like it, since signal handling should belong to the application rather than a filesystem library.
Interesting, I didn't know about chan-signal
. But I agree the
application should take control of signals, not the library.
Performing cleanup steps with signal handlers is a fine idea, but it doesn't eliminate the utility of a public umount
function. I can think of at least two cases where it would be convenient:
fuse::mount
only returns after the filesystem is unmounted: https://github.com/zargony/rust-fuse/blob/573233b236715a7bf56dd3202639aada983159c7/src/lib.rs#L374-L375SIGKILL
provides no opportunity to cleanup. But we can still unmount the killed mount on startup.I have fuse 2.9.5 on Linux, and it has the "-o auto_unmount" option which achieves what you want. Pass those options to the fuse::mount function, and on program exit, the filesystem will be unmounted.
@wfraser nice tip! From libfuse/NEWS, that option was added in 2.9.0, almost 4 years ago.
AFAICS this requires no kernel support -- the spawned fusermount
just daemonizes and waits for its socket to close, indicating that the original process is gone. It does mean that fusermount
is always used, even if current user privileges wouldn't otherwise require it for setuid.
I believe OSXFUSE is built on libfuse too, but I have no idea if they include fusermount
to allow this.
OSXFUSE is implemented by mount_bsd.c
, which doesn't include support for the auto_unmount
option. Good to know it exists for Linux, though.
auto-unmounting is probably a bad idea. Imagine a background process that runs rsync --delete fuse/mnt/ dir/
, and the fuse process crashes. If the filesystem was unmounted rsync would happily delete everything in dir/, whereas you'd get an error if it was still mounted.
I'm currently having issues with this. The -o auto_unmount
seems like a good solution, but it does not seem to work for me. I still get the error Transport endpoint is not connected
, which is solved by manually running umount. This is on Arch Linux. Is it since the last update on this ticket possible to do it another way?
Relevant bit of my code:
let mut options = Vec::new();
options.push(format!("-o fsname={:?}", &conf.name));
options.push(String::from("-o ro"));
if conf.allow_others {
debug!("Enabling others access to FUSE.");
options.push(String::from("-o allow_other"));
}
if conf.auto_unmount {
debug!("Automatic unmounting of FUSE enabled.");
options.push(String::from("-o auto_unmount"));
}
let option_slice = options.iter().map(|o| o.as_ref()).collect::<Vec<&OsStr>>();
mount(ShareFS, conf.mountpoint, &option_slice).unwrap();
I believe you need to pass them separately:
options.push(String::from("-o"))
options.push(String::from("auto_unmount"))
What's the consensus on this issue? Should I also just copy-paste unmount
into my project?
Also I can confirm that auto_unmount
doesn't work with osxfuse.
The file system is not unmounted when the application is terminated. E.g.
ctrl+c
in the hello example. Attempting to run the application again (on OSX) errors out with:I wanted to use the unmount function prior to calling
mount
, but it's private. Hoping this would do the necessary cleanup to attempt unmounting orphaned file systems, and let the application happily continue running.