From 238c0ba90df7ef47a9562aa9fb911ca9361859cf Mon Sep 17 00:00:00 2001 From: "M. J. Fromberger" Date: Mon, 21 Aug 2023 07:32:12 -0700 Subject: [PATCH] fs: avert data races on the nodeRef map Under load, a filesystem that attempts to explicitly invalidate nodes via the InvalidateEntry and InvalidateNodeAttr methods of the server can race on access to the server's nodeRef map. This leads to panics when the runtime detects it. According to the comments on the server, the "meta" lock is supposed to be held when accessing this map; however the Invalidate* methods do not do this. The obvious fix of adding locks there does not quite work, since in some cases the server already holds that lock (vending a request to the FS) making the upcall a deadlock. This patch addresses the problem by introducing a new lock specifically for the nodeRef map, and ensuring it is explicitly acquired by the methods that access that map. --- fs/serve.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/serve.go b/fs/serve.go index de9eb26c..a4c80a59 100644 --- a/fs/serve.go +++ b/fs/serve.go @@ -460,6 +460,7 @@ type Server struct { meta sync.Mutex req map[fuse.RequestID]func() // map request to cancel functions node []*serveNode + nodeRefLock sync.Mutex nodeRef map[Node]fuse.NodeID inode2idLock sync.Mutex inode2id map[uint64]fuse.NodeID @@ -1716,6 +1717,8 @@ func (s *Server) getNodeId(node Node) (id fuse.NodeID, ok bool) { s.inode2idLock.Unlock() return } + s.nodeRefLock.Lock() + defer s.nodeRefLock.Unlock() id, ok = s.nodeRef[node] return } @@ -1726,6 +1729,8 @@ func (s *Server) setNodeId(node Node, id fuse.NodeID) { s.inode2idLock.Unlock() return } + s.nodeRefLock.Lock() + defer s.nodeRefLock.Unlock() s.nodeRef[node] = id } func (s *Server) delNodeId(node Node) { @@ -1735,6 +1740,8 @@ func (s *Server) delNodeId(node Node) { s.inode2idLock.Unlock() return } + s.nodeRefLock.Lock() + defer s.nodeRefLock.Unlock() delete(s.nodeRef, node) }