Commit c1a4d6c4 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

fs: describe one more deadlock scenario

Change-Id: I43f09613acd119daefe64350a46f79d58b2e4b6a
parent 5b76a74a
......@@ -145,14 +145,30 @@
// threads, and makes assumptions that some system calls do not
// block. When accessing a file system from the same process that
// serves the file system (e.g. in unittests), this can lead to
// deadlocks, especially when GOMAXPROCS=1. The following deadlocks
// are known:
// deadlocks, especially when GOMAXPROCS=1, when the Go runtime
// assumes a system call does not block, but actually is served by the
// Go-FUSE process.
//
// 1. Spawning a subprocess uses a fork/exec sequence. In this
// sequence, the child process uses dup3() to remap file
// descriptors. If the destination fd happens to be backed by Go-FUSE,
// the dup3() call will implicitly close the fd, generating a FLUSH
// operation. If there is no thread left to respond, the process is deadlocked.
// The following deadlocks are known:
//
// 1. Spawning a subprocess uses a fork/exec sequence: the process
// forks itself into a parent and child. The parent waits for the
// child to signal that the exec failed or succeeded, while the child
// prepares for calling exec(). Any setup step in the child that
// triggers a FUSE request can cause a deadlock.
//
// 1a. If the subprocess has a directory specified, the child will
// chdir into that directory. This generates an ACCESS operation on
// the directory.
//
// This deadlock can be avoided by disabling the ACCESS
// operation: return syscall.ENOSYS in the Access implementation, and
// ensure it is triggered called before initiating the subprocess.
//
// 1b. If the subprocess inherits files, the child process uses dup3()
// to remap file descriptors. If the destination fd happens to be
// backed by Go-FUSE, the dup3() call will implicitly close the fd,
// generating a FLUSH operation, eg.
//
// f1, err := os.Open("/fusemnt/file1")
// // f1.Fd() == 3
......@@ -164,9 +180,10 @@
// // f2 (fd 4) is moved to fd 3. Deadlocks with GOMAXPROCS=1.
// cmd.Start()
//
// This can be avoided by ensuring that file descriptors pointing into
// FUSE mounts and file descriptors passed into subprocesses do not
// overlap, e.g. inserting the following before the above example:
// This deadlock can be avoided by ensuring that file descriptors
// pointing into FUSE mounts and file descriptors passed into
// subprocesses do not overlap, e.g. inserting the following before
// the above example:
//
// for {
// f, _ := os.Open("/dev/null")
......@@ -176,14 +193,12 @@
// }
// }
//
// 2. The Go runtime uses the epoll system call to schedule
// goroutines, and assumes that epoll does not block. However, the
// FUSE kernel module implements the POLL opcode. If the Go runtime
// calls epoll() with files opened on a FUSE mount, and if there is
// only one thread available for execution, there is no thread left to
// respond to the POLL opcode, leading to deadlock. To prevent this
// from happening, Go-FUSE centrally disables the POLL opcode. (See
// commit 4f10e248ebabd3cdf9c0aa3ae58fd15235f82a79)
// 2. The Go runtime uses the epoll system call to understand which
// goroutines can respond to I/O. The runtime assumes that epoll does
// not block, but if files are on a FUSE filesystem, the kernel will
// generate a POLL operation. To prevent this from happening, Go-FUSE
// disables the POLL opcode on mount. To ensure this has happened, call
// WaitMount.
//
// # Dynamically discovered file systems
//
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment