cberner / fuser

Filesystem in Userspace (FUSE) for Rust
MIT License
836 stars 114 forks source link

RFC: Callback before entering the event loop #175

Closed cehteh closed 3 years ago

cehteh commented 3 years ago

I am sending a filesystem process into the background with the 'daemonize' crate. To make this somewhat reliable/scriptable I would like if the parent process returns when the mount is established (or failed thereof)

Imagine some shell script like:

./myfilesystem mymountpoint/ && ls mymountpoint/

Now there is some chance of a race between 'myfilesystem' forking into the background and starting the mount and the execution of the 'ls' command. Moreover there is no way to tell if the mounting was successful by the exit code.

I am already establishing an ipc channel from background child to the parent to pass information/errors up. All whats left is some way the 'fuser' lib can notify back that a mount was successful, after establishing an Session but right before entering the event loop.

Similar to 'mount2' i would propose the following API:

pub fn mount_with_callback<FS: Filesystem, P: AsRef<Path>, F: FnOnce(&io::Result<Session>) + Copy>(
    filesystem: FS,
    mountpoint: P,
    options: &[MountOption],
    callback: F,
) -> io::Result<()> {
    check_option_conflicts(options)?;
    Session::new(filesystem, mountpoint.as_ref(), options)
        .or_else(|e| { let e = Err(e); callback(&e); e})
        .and_then(|ok| { let ok = Ok(ok); callback(&ok); ok})        
        .and_then(|mut se| callback(&se); se.run())
}

The callback can then inspect the error or the session and take proper action (sending the status over the IPC channel).

This .or_else().and_then() chaining looks a bit ugly for now (could be written more pretty?), one may consider to implement a .inspect() for Result (there is an existing crate for that, but that one only passes the Ok() part).

cberner commented 3 years ago

I believe Filesystem::init already covers this, and I think it will be more reliable than the interface you proposed, because it's called only after the event loop has started, rather than right before se.run() is entered.

Let me know if that doesn't work

cehteh commented 3 years ago

Ah, good catch, I'll give it a try tomorrow. It may be a bit tricky to get a callback closure into the init, possibly has to be passed to my filesystems constructor and be stored there, lingering there forever after the once-use.

Either way I just implemented what I proposed above as proof or concept: https://github.com/cehteh/fuser/commit/4cc0df882279ef68d15ecfad2e7d227ba8516121 Works for me, but I don't make a PR before i see if the ::init thing works.

cehteh commented 3 years ago

Got it working, but its a bit tricky :) (have to impl Filesystem for &mut MyFilesystem)

wmanley commented 3 years ago

My draft PR #184 addresses this. mounting a filesystem is now separate from actually running the mainloop.