From a2336ad774d8f707707d238eaa159977e29fadb4 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Fri, 9 Mar 2018 09:49:41 +0000 Subject: [PATCH] vfs: fix deadlock in mount tests This was caused by this sequence of calls 1> file.Release 1> file.close -> takes the file lock 2> vfs.waitforWriters 2> dir.walk -> takes the dir lock 1> file.setObject 1> dir.addObject -> attempts to take the dir lock - BLOCKS 2> file.activeWriters -> tries to take file lock - BLOCKS - DEADLOCK The fix is to make activeWriters not take the file lock and use atomic operations to read the number of writers instead. --- vfs/file.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/vfs/file.go b/vfs/file.go index 63513d44d..967adae60 100644 --- a/vfs/file.go +++ b/vfs/file.go @@ -23,6 +23,7 @@ type File struct { leaf string // leaf name of the object rwOpenCount int // number of open files on this handle writers []Handle // writers for this file + nwriters int32 // len(writers) which is read/updated with atomic readWriters int // how many RWFileHandle are open for writing readWriterClosing bool // is a RWFileHandle currently cosing? modified bool // has the cache file be modified by a RWFileHandle? @@ -103,6 +104,7 @@ func (f *File) rename(d *Dir, o fs.Object) { func (f *File) addWriter(h Handle) { f.mu.Lock() f.writers = append(f.writers, h) + atomic.AddInt32(&f.nwriters, 1) if _, ok := h.(*RWFileHandle); ok { f.readWriters++ } @@ -122,6 +124,7 @@ func (f *File) delWriter(h Handle, modifiedCacheFile bool) (lastWriterAndModifie } if found >= 0 { f.writers = append(f.writers[:found], f.writers[found+1:]...) + atomic.AddInt32(&f.nwriters, -1) } else { fs.Debugf(f.o, "File.delWriter couldn't find handle") } @@ -172,10 +175,11 @@ func (f *File) finishWriterClose() { } // activeWriters returns the number of writers on the file +// +// Note that we don't take the mutex here. If we do then we can get a +// deadlock. func (f *File) activeWriters() int { - f.mu.Lock() - defer f.mu.Unlock() - return len(f.writers) + return int(atomic.LoadInt32(&f.nwriters)) } // ModTime returns the modified time of the file