From 1ab97fb2ebca4ac38b4e50291e28533b4b86e0cb Mon Sep 17 00:00:00 2001 From: Ka-Hing Cheung Date: Thu, 5 Oct 2017 22:45:50 -0700 Subject: [PATCH] handle forget inline instead of in goroutine when we are under memory pressure, or echo 3 > /proc/sys/vm/drop_caches, kernel can send us many forget ops at the same time if we have lots of inodes in memory. Running them all in goroutines can lead to even more memory usage and eventually OOM. --- fuseutil/file_system.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/fuseutil/file_system.go b/fuseutil/file_system.go index 9cc0fa8..fce16db 100644 --- a/fuseutil/file_system.go +++ b/fuseutil/file_system.go @@ -72,8 +72,10 @@ type FileSystem interface { // method.Respond with the resulting error. Unsupported ops are responded to // directly with ENOSYS. // -// Each call to a FileSystem method is made on its own goroutine, and is free -// to block. +// Each call to a FileSystem method (except ForgetInode) is made on +// its own goroutine, and is free to block. ForgetInode may be called +// synchronously, and should not depend on calls to other methods +// being received concurrently. // // (It is safe to naively process ops concurrently because the kernel // guarantees to serialize operations that the user expects to happen in order, @@ -109,7 +111,15 @@ func (s *fileSystemServer) ServeOps(c *fuse.Connection) { } s.opsInFlight.Add(1) - go s.handleOp(c, ctx, op) + if _, ok := op.(*fuseops.ForgetInodeOp); ok { + // Special case: call in this goroutine for + // forget inode ops, which may come in a + // flurry from the kernel and are generally + // cheap for the file system to handle + s.handleOp(c, ctx, op) + } else { + go s.handleOp(c, ctx, op) + } } }