Skip to content

Commit 9f3b5c7

Browse files
committed
Exclude global FS lock from handleListResult, doMkDir, insertSubTree, completeInflightListing
1 parent b287c34 commit 9f3b5c7

File tree

3 files changed

+27
-55
lines changed

3 files changed

+27
-55
lines changed

internal/dir.go

Lines changed: 15 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,7 @@ func (parent *Inode) listObjectsSlurp(inode *Inode, startAfter string, lock bool
272272
}
273273
resp, err := cloud.ListBlobs(params)
274274
if err != nil {
275-
parent.fs.mu.Lock()
276-
parent.fs.completeInflightListingUnlocked(myList)
277-
parent.fs.mu.Unlock()
275+
parent.fs.completeInflightListing(myList)
278276
s3Log.Errorf("ListObjects %v = %v", params, err)
279277
return
280278
}
@@ -283,8 +281,7 @@ func (parent *Inode) listObjectsSlurp(inode *Inode, startAfter string, lock bool
283281
if lock {
284282
parent.mu.Lock()
285283
}
286-
parent.fs.mu.Lock()
287-
skipListing := parent.fs.completeInflightListingUnlocked(myList)
284+
skipListing := parent.fs.completeInflightListing(myList)
288285
dirs := make(map[*Inode]bool)
289286
for _, obj := range resp.Items {
290287
if skipListing != nil && skipListing[*obj.Key] {
@@ -295,7 +292,6 @@ func (parent *Inode) listObjectsSlurp(inode *Inode, startAfter string, lock bool
295292
parent.insertSubTree(baseName, &obj, dirs)
296293
}
297294
}
298-
parent.fs.mu.Unlock()
299295
if lock {
300296
parent.mu.Unlock()
301297
}
@@ -394,6 +390,7 @@ func listBlobsSafe(cloud StorageBackend, param *ListBlobsInput) (*ListBlobsOutpu
394390
return res, nil
395391
}
396392

393+
// LOCKS_EXCLUDED(dh.inode.fs)
397394
func (dh *DirHandle) handleListResult(resp *ListBlobsOutput, prefix string, skipListing map[string]bool) {
398395
parent := dh.inode
399396
fs := parent.fs
@@ -484,25 +481,20 @@ func (dh *DirHandle) listObjectsFlat() (err error) {
484481
ContinuationToken: dh.inode.dir.listMarker,
485482
Prefix: &prefix,
486483
}
487-
dh.mu.Unlock()
488484

485+
dh.mu.Unlock()
489486
resp, err := listBlobsSafe(cloud, params)
490487
dh.mu.Lock()
488+
491489
if err != nil {
492-
dh.inode.fs.mu.Lock()
493-
dh.inode.fs.completeInflightListingUnlocked(myList)
494-
dh.inode.fs.mu.Unlock()
490+
dh.inode.fs.completeInflightListing(myList)
495491
return
496492
}
497493

498494
s3Log.Debug(resp)
499495

500496
dh.inode.mu.Lock()
501-
dh.inode.fs.mu.Lock()
502-
503-
dh.handleListResult(resp, prefix, dh.inode.fs.completeInflightListingUnlocked(myList))
504-
505-
dh.inode.fs.mu.Unlock()
497+
dh.handleListResult(resp, prefix, dh.inode.fs.completeInflightListing(myList))
506498
dh.inode.mu.Unlock()
507499

508500
if resp.IsTruncated {
@@ -1006,9 +998,6 @@ func (parent *Inode) Create(name string) (inode *Inode, fh *FileHandle) {
1006998
parent.mu.Lock()
1007999
defer parent.mu.Unlock()
10081000

1009-
fs.mu.Lock()
1010-
defer fs.mu.Unlock()
1011-
10121001
now := time.Now()
10131002
inode = NewInode(fs, parent, name)
10141003
inode.userMetadata = make(map[string][]byte)
@@ -1041,9 +1030,6 @@ func (parent *Inode) MkDir(
10411030
parent.mu.Lock()
10421031
defer parent.mu.Unlock()
10431032

1044-
parent.fs.mu.Lock()
1045-
defer parent.fs.mu.Unlock()
1046-
10471033
inode = parent.doMkDir(name)
10481034
inode.mu.Unlock()
10491035
parent.fs.WakeupFlusher()
@@ -1052,7 +1038,7 @@ func (parent *Inode) MkDir(
10521038
}
10531039

10541040
// LOCKS_REQUIRED(parent.mu)
1055-
// LOCKS_REQUIRED(fs.mu)
1041+
// LOCKS_EXCLUDED(parent.fs.mu)
10561042
// Returns locked inode (!)
10571043
func (parent *Inode) doMkDir(name string) (inode *Inode) {
10581044
if parent.dir.DeletedChildren != nil {
@@ -1078,10 +1064,12 @@ func (parent *Inode) doMkDir(name string) (inode *Inode) {
10781064
inode.Id = oldInode.Id
10791065
// We leave the older inode in place only for forget() calls
10801066
inode.refcnt = oldInode.refcnt
1081-
parent.fs.inodes[oldInode.Id] = inode
10821067
oldInode.mu.Lock()
1068+
parent.fs.mu.Lock()
1069+
parent.fs.inodes[oldInode.Id] = inode
10831070
oldInode.Id = parent.fs.allocateInodeId()
10841071
parent.fs.inodes[oldInode.Id] = oldInode
1072+
parent.fs.mu.Unlock()
10851073
oldInode.userMetadataDirty = 0
10861074
oldInode.userMetadata = make(map[string][]byte)
10871075
oldInode.touch()
@@ -1132,9 +1120,6 @@ func (parent *Inode) CreateSymlink(
11321120
parent.mu.Lock()
11331121
defer parent.mu.Unlock()
11341122

1135-
fs.mu.Lock()
1136-
defer fs.mu.Unlock()
1137-
11381123
now := time.Now()
11391124
inode = NewInode(fs, parent, name)
11401125
inode.userMetadata = make(map[string][]byte)
@@ -1387,9 +1372,7 @@ func (parent *Inode) Rename(from string, newParent *Inode, to string) (err error
13871372
}
13881373

13891374
func renameRecursive(fromInode *Inode, newParent *Inode, to string) {
1390-
newParent.fs.mu.Lock()
13911375
toDir := newParent.doMkDir(to)
1392-
newParent.fs.mu.Unlock()
13931376
toDir.userMetadata = fromInode.userMetadata
13941377
toDir.ImplicitDir = fromInode.ImplicitDir
13951378
// Trick IDs
@@ -1518,9 +1501,8 @@ func sealPastDirs(dirs map[*Inode]bool, d *Inode) {
15181501
dirs[d] = false
15191502
}
15201503

1521-
// LOCKS_REQUIRED(fs.mu)
15221504
// LOCKS_REQUIRED(parent.mu)
1523-
// LOCKS_REQUIRED(parent.fs.mu)
1505+
// LOCKS_EXCLUDED(parent.fs.mu)
15241506
func (parent *Inode) insertSubTree(path string, obj *BlobItemOutput, dirs map[*Inode]bool) {
15251507
fs := parent.fs
15261508
slash := strings.Index(path, "/")
@@ -1531,14 +1513,12 @@ func (parent *Inode) insertSubTree(path string, obj *BlobItemOutput, dirs map[*I
15311513
_, deleted := parent.dir.DeletedChildren[path]
15321514
if !deleted {
15331515
inode = NewInode(fs, parent, path)
1516+
// our locking order is parent before child, inode before fs. try to respect it
15341517
fs.insertInode(parent, inode)
15351518
inode.SetFromBlobItem(obj)
15361519
}
15371520
} else {
1538-
// our locking order is parent before child, inode before fs. try to respect it
1539-
fs.mu.Unlock()
15401521
inode.SetFromBlobItem(obj)
1541-
fs.mu.Lock()
15421522
}
15431523
sealPastDirs(dirs, parent)
15441524
} else {
@@ -1558,12 +1538,10 @@ func (parent *Inode) insertSubTree(path string, obj *BlobItemOutput, dirs map[*I
15581538
} else if !inode.isDir() {
15591539
// replace unmodified file item with a directory
15601540
if atomic.LoadInt32(&inode.CacheState) == ST_CACHED {
1561-
fs.mu.Unlock()
15621541
inode.mu.Lock()
15631542
atomic.StoreInt32(&inode.refreshed, -1)
15641543
parent.removeChildUnlocked(inode)
15651544
inode.mu.Unlock()
1566-
fs.mu.Lock()
15671545
// create a directory inode instead
15681546
inode = NewInode(fs, parent, dir)
15691547
inode.ToDir()
@@ -1590,13 +1568,9 @@ func (parent *Inode) insertSubTree(path string, obj *BlobItemOutput, dirs map[*I
15901568
dirs[inode] = false
15911569

15921570
if !isDirBlob {
1593-
fs.mu.Unlock()
15941571
inode.mu.Lock()
1595-
fs.mu.Lock()
15961572
inode.insertSubTree(path, obj, dirs)
1597-
fs.mu.Unlock()
15981573
inode.mu.Unlock()
1599-
fs.mu.Lock()
16001574
}
16011575
}
16021576
}
@@ -1622,9 +1596,7 @@ func (parent *Inode) LookUp(name string) (*Inode, error) {
16221596
myList := parent.fs.addInflightListing()
16231597
blob, err := parent.LookUpInodeMaybeDir(name)
16241598
if err != nil {
1625-
parent.fs.mu.Lock()
1626-
parent.fs.completeInflightListingUnlocked(myList)
1627-
parent.fs.mu.Unlock()
1599+
parent.fs.completeInflightListing(myList)
16281600
return nil, err
16291601
}
16301602
dirs := make(map[*Inode]bool)
@@ -1634,12 +1606,10 @@ func (parent *Inode) LookUp(name string) (*Inode, error) {
16341606
prefixLen++
16351607
}
16361608
parent.mu.Lock()
1637-
parent.fs.mu.Lock()
1638-
skipListing := parent.fs.completeInflightListingUnlocked(myList)
1609+
skipListing := parent.fs.completeInflightListing(myList)
16391610
if skipListing == nil || !skipListing[*blob.Key] {
16401611
parent.insertSubTree((*blob.Key)[prefixLen : ], blob, dirs)
16411612
}
1642-
parent.fs.mu.Unlock()
16431613
inode := parent.findChildUnlocked(name)
16441614
parent.mu.Unlock()
16451615
return inode, nil

internal/goofys.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ type Goofys struct {
6363
bufferPool *BufferPool
6464

6565
// A lock protecting the state of the file system struct itself (distinct
66-
// from per-inode locks). Make sure to see the notes on lock ordering above.
66+
// from per-inode locks). Should be always taken after any inode locks.
6767
mu sync.RWMutex
6868

6969
flusherMu sync.Mutex
@@ -591,15 +591,12 @@ func (fs *Goofys) mount(mp *Inode, b *Mount) {
591591
mp.mu.Lock()
592592
dirInode := mp.findChildUnlocked(dirName)
593593
if dirInode == nil {
594-
fs.mu.Lock()
595-
596594
dirInode = NewInode(fs, mp, dirName)
597595
dirInode.ToDir()
598596
dirInode.AttrTime = TIME_MAX
599597
dirInode.userMetadata = make(map[string][]byte)
600598

601599
fs.insertInode(mp, dirInode)
602-
fs.mu.Unlock()
603600
}
604601
mp.mu.Unlock()
605602
mp = dirInode
@@ -617,10 +614,8 @@ func (fs *Goofys) mount(mp *Inode, b *Mount) {
617614
mountInode.AttrTime = TIME_MAX
618615
mountInode.userMetadata = make(map[string][]byte)
619616

620-
fs.mu.Lock()
621-
defer fs.mu.Unlock()
622-
623617
fs.insertInode(mp, mountInode)
618+
624619
prev = mountInode
625620
} else {
626621
if !prev.isDir() {
@@ -932,6 +927,7 @@ func pathEscape(path string) string {
932927
return u.EscapedPath()
933928
}
934929

930+
// LOCKS_REQUIRED(fs.mu)
935931
func (fs *Goofys) allocateInodeId() (id fuseops.InodeID) {
936932
id = fs.nextInodeID
937933
fs.nextInodeID++
@@ -1021,8 +1017,8 @@ func (fs *Goofys) recheckInode(parent *Inode, inode *Inode, name string) (*Inode
10211017
return newInode, nil
10221018
}
10231019

1024-
// LOCKS_REQUIRED(fs.mu)
10251020
// LOCKS_REQUIRED(parent.mu)
1021+
// LOCKS_EXCLUDED(fs.mu)
10261022
func (fs *Goofys) insertInode(parent *Inode, inode *Inode) {
10271023
addInode := false
10281024
if inode.Name == "." {
@@ -1036,12 +1032,14 @@ func (fs *Goofys) insertInode(parent *Inode, inode *Inode) {
10361032
if inode.Id != 0 {
10371033
panic(fmt.Sprintf("inode id is set: %v %v", inode.Name, inode.Id))
10381034
}
1035+
fs.mu.Lock()
10391036
inode.Id = fs.allocateInodeId()
10401037
addInode = true
10411038
}
10421039
parent.insertChildUnlocked(inode)
10431040
if addInode {
10441041
fs.inodes[inode.Id] = inode
1042+
fs.mu.Unlock()
10451043

10461044
// if we are inserting a new directory, also create
10471045
// the child . and ..
@@ -1051,6 +1049,7 @@ func (fs *Goofys) insertInode(parent *Inode, inode *Inode) {
10511049
}
10521050
}
10531051

1052+
// LOCKS_EXCLUDED(fs.mu)
10541053
func (fs *Goofys) addDotAndDotDot(dir *Inode) {
10551054
dot := NewInode(fs, dir, ".")
10561055
dot.ToDir()
@@ -1236,10 +1235,12 @@ func (fs *Goofys) addInflightListing() int {
12361235
// For any listing, we forcibly exclude all objects modifications of which were
12371236
// started before the completion of the listing, but were not completed before
12381237
// the beginning of the listing.
1239-
// LOCKS_REQUIRED(fs.mu)
1240-
func (fs *Goofys) completeInflightListingUnlocked(id int) map[string]bool {
1238+
// LOCKS_EXCLUDED(fs.mu)
1239+
func (fs *Goofys) completeInflightListing(id int) map[string]bool {
1240+
fs.mu.Lock()
12411241
m := fs.inflightListings[id]
12421242
delete(fs.inflightListings, id)
1243+
fs.mu.Unlock()
12431244
return m
12441245
}
12451246

internal/handles.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ func NewInode(fs *Goofys, parent *Inode, name string) (inode *Inode) {
186186
return
187187
}
188188

189+
// LOCKS_EXCLUDED(inode.mu)
189190
func (inode *Inode) SetFromBlobItem(item *BlobItemOutput) {
190191
inode.mu.Lock()
191192
defer inode.mu.Unlock()

0 commit comments

Comments
 (0)