// Look up the child with the given name within the parent, then return an // existing inode for that child or create a new one if necessary. Return // ENOENT if the child doesn't exist. // // Return the child locked, incrementing its lookup count. // // LOCKS_EXCLUDED(fs.mu) // LOCKS_EXCLUDED(parent) // LOCK_FUNCTION(child) func (fs *fileSystem) lookUpOrCreateChildInode( ctx context.Context, parent inode.DirInode, childName string) (child inode.Inode, err error) { // Set up a function that will find a lookup result for the child with the // given name. Expects no locks to be held. getLookupResult := func() (r inode.LookUpResult, err error) { parent.Lock() defer parent.Unlock() r, err = parent.LookUpChild(ctx, childName) if err != nil { err = fmt.Errorf("LookUpChild: %v", err) return } return } // Run a retry loop around lookUpOrCreateInodeIfNotStale. const maxTries = 3 for n := 0; n < maxTries; n++ { // Create a record. var result inode.LookUpResult result, err = getLookupResult() if err != nil { return } if !result.Exists() { err = fuse.ENOENT return } // Attempt to create the inode. Return if successful. fs.mu.Lock() child = fs.lookUpOrCreateInodeIfNotStale(result.FullName, result.Object) if child != nil { return } } err = fmt.Errorf("Did not converge after %v tries", maxTries) return }