15928: Fix deadlock.
authorTom Clegg <tom@tomclegg.ca>
Wed, 11 Dec 2019 15:40:01 +0000 (10:40 -0500)
committerTom Clegg <tom@tomclegg.ca>
Thu, 12 Dec 2019 06:25:12 +0000 (01:25 -0500)
Locking the parent dir isn't necessary to finish async writes, and
deadlocks if a waitPrune() is waiting for the async writes to finish.

Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom@tomclegg.ca>

sdk/go/arvados/fs_collection.go

index d206cb3b24897fd581af0348a7971cb5e619011d..609eeb6e9e2b8fcc0fd4caf5cae114f19965c247 100644 (file)
@@ -695,21 +695,9 @@ func (dn *dirnode) commitBlock(ctx context.Context, refs []fnSegmentRef, bufsize
        go func() {
                defer close(done)
                defer close(errs)
-               locked := map[*filenode]bool{}
                locator, _, err := dn.fs.PutB(block)
                dn.fs.throttle().Release()
                {
-                       if !sync {
-                               dn.Lock()
-                               defer dn.Unlock()
-                               for _, name := range dn.sortedNames() {
-                                       if fn, ok := dn.inodes[name].(*filenode); ok {
-                                               fn.Lock()
-                                               defer fn.Unlock()
-                                               locked[fn] = true
-                                       }
-                               }
-                       }
                        defer func() {
                                for _, seg := range segs {
                                        if seg.flushing == done {
@@ -724,6 +712,7 @@ func (dn *dirnode) commitBlock(ctx context.Context, refs []fnSegmentRef, bufsize
                }
                for idx, ref := range refs {
                        if !sync {
+                               ref.fn.Lock()
                                // In async mode, fn's lock was
                                // released while we were waiting for
                                // PutB(); lots of things might have
@@ -732,17 +721,15 @@ func (dn *dirnode) commitBlock(ctx context.Context, refs []fnSegmentRef, bufsize
                                        // file segments have
                                        // rearranged or changed in
                                        // some way
+                                       ref.fn.Unlock()
                                        continue
                                } else if seg, ok := ref.fn.segments[ref.idx].(*memSegment); !ok || seg != segs[idx] {
                                        // segment has been replaced
+                                       ref.fn.Unlock()
                                        continue
                                } else if seg.flushing != done {
                                        // seg.buf has been replaced
-                                       continue
-                               } else if !locked[ref.fn] {
-                                       // file was renamed, moved, or
-                                       // deleted since we called
-                                       // PutB
+                                       ref.fn.Unlock()
                                        continue
                                }
                        }
@@ -760,6 +747,9 @@ func (dn *dirnode) commitBlock(ctx context.Context, refs []fnSegmentRef, bufsize
                        // lock, writing different segments from the
                        // same file.
                        atomic.AddInt64(&ref.fn.memsize, -int64(len(data)))
+                       if !sync {
+                               ref.fn.Unlock()
+                       }
                }
        }()
        if sync {