From 36f8810e2e3d7eeac4ac05b57f65690fbfba62a2 Mon Sep 17 00:00:00 2001 From: jszwec Date: Sat, 22 Jul 2017 18:23:01 -0400 Subject: [PATCH] Fix data races in MemMapFs Concurrent modifications of the file system while calling ReadDir was causing data races and sometimes panics. --- memmap.go | 5 +++++ memmap_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/memmap.go b/memmap.go index 767ac1d..14cd438 100644 --- a/memmap.go +++ b/memmap.go @@ -66,7 +66,10 @@ func (m *MemMapFs) unRegisterWithParent(fileName string) error { if parent == nil { log.Panic("parent of ", f.Name(), " is nil") } + + parent.Lock() mem.RemoveFromMemDir(parent, f) + parent.Unlock() return nil } @@ -99,8 +102,10 @@ func (m *MemMapFs) registerWithParent(f *mem.FileData) { } } + parent.Lock() mem.InitializeDir(parent) mem.AddToMemDir(parent, f) + parent.Unlock() } func (m *MemMapFs) lockfreeMkdir(name string, perm os.FileMode) error { diff --git a/memmap_test.go b/memmap_test.go index ca5abbc..d28e912 100644 --- a/memmap_test.go +++ b/memmap_test.go @@ -1,6 +1,7 @@ package afero import ( + "fmt" "os" "path/filepath" "runtime" @@ -343,3 +344,43 @@ func TestRacingDeleteAndClose(t *testing.T) { }() close(in) } + +// This test should be run with the race detector on: +// go test -run TestMemFsDataRace -race +func TestMemFsDataRace(t *testing.T) { + const dir = "test_dir" + fs := NewMemMapFs() + + if err := fs.MkdirAll(dir, 0777); err != nil { + t.Fatal(err) + } + + const n = 1000 + done := make(chan struct{}) + + go func() { + defer close(done) + for i := 0; i < n; i++ { + fname := filepath.Join(dir, fmt.Sprintf("%d.txt", i)) + if err := WriteFile(fs, fname, []byte(""), 0777); err != nil { + panic(err) + } + if err := fs.Remove(fname); err != nil { + panic(err) + } + } + }() + +loop: + for { + select { + case <-done: + break loop + default: + _, err := ReadDir(fs, dir) + if err != nil { + t.Fatal(err) + } + } + } +}