15928: Fix deadlock.
authorTom Clegg <tom@tomclegg.ca>
Wed, 11 Dec 2019 15:40:01 +0000 (10:40 -0500)
committerTom Clegg <tom@tomclegg.ca>
Wed, 11 Dec 2019 15:40:01 +0000 (10:40 -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 3d0928b84ea77ef3817ac9c3d2cfe3679bd970e0..d0e97f2ad184b44e7800a577247704e8af717581 100644 (file)
@@ -698,21 +698,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 {
@@ -727,6 +715,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
@@ -735,17 +724,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
                                }
                        }
@@ -763,6 +750,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 {