Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non-blocking mounts are racy -- can return success prematurely #41

Open
stevebriskin opened this issue Sep 17, 2014 · 3 comments
Open

Comments

@stevebriskin
Copy link
Contributor

Non-Blocking mounts are mounted via a new thread and a 750ms sleep. It assumes that the thread will complete the mount operation within 750ms, but there's no guarantee of that.

Impact:

  1. The caller may think the mount succeeded whereas it actually failed.
  2. The caller may attempt to read data that's isn't available yet.
  3. The caller may write to the mount directory. This will subsequently cause the fuse mount operation to fail due to the mount point being a non-empty directory.

Can you suggest a work around for detecting whether a mount request has completed?

@EtiennePerot
Copy link
Owner

Unfortunately the way the fuse library creates a filesystem is through the blocking call fuse_main_real function. This does return when there's an error creating the mount, and it usually does so pretty quickly, but there's no guarantee of that. That's why the non-blocking mode sleeps for a short while to give fuse a chance to return an error, and after that short while it assumes the call is blocked and that the mount was successful. When fuse_main_real is successful, it doesn't return until the filesystem is unmounted.

Potential solutions:

  • Make fuse-jna more closely reflect the reality of the library it has to work with, and thus simply stop pretending it has a nonblocking mode. The problem with this approach is that I think it'll essentially make people essentially write their own version of the same thing: start fuse off in some background thread, and then maybe sleep for a while and check for potential errors.
  • Have the non-blocking mode sleep for a short while, then attempt just once to call stat on a non-existent, unique-filename file like /wherever/the/mountpoint/is/fuse-jna-test-3489056743895032. Then add some code somewhere in the layer between JNA and the user's filesystem class that catches this first stat attempt, and somehow report this to the mount thread and propagate it up. (Further stat attempts would be passed down to the user filesystem). It'd involve having these two parts of the code (mounting vs filesystem stat call handler) be coupled, which isn't ideal. However, it would work fairly reliably in that it would no longer return false positives, but it will still return false negatives on slow systems (i.e. in the case where the mount would have succeeded but we didn't sleep long enough before trying the stat call).

I think solution 2 would be a good compromise.

@stevebriskin
Copy link
Contributor Author

I'm going to implement a variation of #2 in my FS in the user layer. My FS lends itself well to this approach.

But for the general implementation (if you choose to keep the non-blocking option), I don't think the "just once" stat would be sufficient since there's no way to predict how long it will take the FS to be mounted. I suspect you'll have to do a period check until it succeeds, fails, or a timeout is reached.

Do you know how the "fusermount" binary knows when to return?

@EtiennePerot
Copy link
Owner

Yes, it'll indeed need to fail after a timeout and return a false negative in such cases.

fusermount calls some more inner functions of the fuse library rather than fuse_main_real.
fuse_main_real isn't the only entry point for mounting filesystems that fuse provides. It's a convenience wrapper that does a lot of things on top that I'd really rather not reimplement on the Java side (though tbh it would be the proper fix to this particular issue).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants