Code Monkey home page Code Monkey logo

Comments (5)

zargony avatar zargony commented on May 30, 2024

Mmh, that's weird. Dropping a BackgroundSession actually does an unmount on the mount point which should be the same than using umount at the console. It actually does not kill the background task (which wouldn't unmount and therefore leave the system with an inaccessible path and stale inodes until some timeout in the filesystem driver unmounts it). I tried killing the background task before, but neither native blocking reads nor green blocking reads are interruptible in Rust.

Anyway, since it actually does an unmount, that should lead to the background task exiting. Probably that doesn't work reliable when the filesystem is still in use (or even because of #9). Maybe channel::unmount should try harder to unmount by checking if the unmount succeeds (without accessing the mount point, since it may still be mounted but stale - it would need to check the kernel's mount table to see if unmount succeeded). If unmount doesn't work after a few tries with a small delay, do a force unmount (umount -f) as a last resort. Just like process kill handlers try to send SIGTERM a few times before they finally force a process to quit with SIGKILL.

from fuse-rs.

MicahChalmer avatar MicahChalmer commented on May 30, 2024

Ok, now I know what the underlying cause is here. The problem only appears if the filesystem returns an error for getattr on its root.

In osxfuse, fuse_unmount_compat22 is a very short function that looks like this:

void
fuse_unmount_compat22(const char *mountpoint)
{
    char resolved_path[PATH_MAX];
    char *rp = realpath(mountpoint, resolved_path);
    if (rp) {
        (void)unmount(resolved_path, 0);
    }

    return;
}

The problem is that if the call to realpath fails, the error is swallowed and the filesystem is not unmounted. But the call to realpath actually calls getattr on the mounted FUSE file system. If that returns an error, it will never unmount.

The call to realpath is there for a reason--I don't think it'll work with a non-canonical path. I would suggest this as a fix: before mounting, call realpath before mounting, and store the resolved path name instead of the path as passed in. Then at unmount, for OS X only, call unmount directly instead of fuse_unmount_compat22 using the stored real path. (On Linux, fuse_unmount_compat22 is more than just realpath and then unmount, and does not have the underlying problem, so we'll keep it as is.)

Of course, a decent filesystem would always be able to getattr its own root anyway, so this isn't that big of a problem in the first place.

from fuse-rs.

zargony avatar zargony commented on May 30, 2024

Ah, I see. Could this be related to the ioctl we're still missing? For some reason, the C lib sends ioctl FUSEDEVIOCSETDAEMONDEAD to the kernel driver before closing the fd (on OS X only). This sounds like it could be related to that.

Getting the realpath of the mount point shouldn't be hard for us, it's already there in mountpoint inside a channel. To make sure it's absolute, we just need to use os::make_absolute in Channel::new and we could call libc::umount instead of fuse_unmount in the destructor.

I'm not sure if replacing fuse_unmount for certain environments is a good idea. FUSE is doing so much stuff when mounting/unmounting depending on wether it's on Linux, OS X or BSD, depending on which driver version is installed, sometimes it uses fusermount, sometimes not, and so on. I was always glad to leave that weird logic to libfuse instead of replacing it. Can't we just call libc::umount and keep doing the fuse_unmount? The kernel unmount would bring down the mountpoint so that the following FUSE unmount will work and FUSE has a chance to properly shut down in cases where it's doing more than just calling the kernel unmount (just like if the user unmounts the mountpoint from terminal or in the finder).

from fuse-rs.

MicahChalmer avatar MicahChalmer commented on May 30, 2024

I don't think the ioctl has anything to do with this. This problem doesn't arise when we're unmounting after the session has already been destroyed and we're closing the FD. It's when we're trying to unmount from another task, outside of the session loop. (I tried making it close the FD at that point in #12, mistakenly thinking that's what osxfuse did, but you correctly pointed out that this was mistaken and would lead to race conditions. Osxfuse only sends the FUSEDEVIOCSETDAEMONDEAD ioctl, and closes the FD, after the session ends. We need to continue do the same.)

I agree that we need to keep the fuse_unmount_compat22 on non-OSX platforms. Sorry if this wasn't clear in the original comment. If I understand you correctly, we intend the same thing--call libc's unmount on OS X, but continue to use fuse_unmount_compat22 elsewhere.

from fuse-rs.

mciantyre avatar mciantyre commented on May 30, 2024

I'm sorry to bring up a four year old issue, but I feel it may be related to an issue I'm experiencing. After dropping a BackgroundSession, I am unable to remount a filesystem at the same mountpoint. I get the error

fuse: attempt to remount on active mount point: /path/to/the/mount/point

from FUSE. I'm running macOS 10.13 and osxfuse 3.7.1. I can show that the same issue is not present when running on a Linux system.

I created a test here to demonstrate the behavior. Essentially, I took the hello.rs example filesystem, mount it using spawn_mount to get a BackgroundSession, and try to read the hello.txt file. I let the BackgroundSession drop, then I try again after a 1 second delay.

We might expect the filesystem to unmount and remount successfully. However, the test seems to demonstrate that remounting the filesystem at the same mountpoint throws an error. Compiling and running the same test on Linux passes.

git clone [email protected]:mciantyre/rust-fuse.git
cd rust-fuse
cargo test -- --test-threads 1

Could this be because the BackgroundSession isn't stopping the filesystem thread on macOS? I noticed the TODO in the impl Drop for Channel implementation, and I might try to address it if we feel it's related. Or, am I trying to do something that FUSE and this library can't support?

Thanks for your help and for this great library!

from fuse-rs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.