Skip to content

Commit

Permalink
Extract cache refresh into a separate function
Browse files Browse the repository at this point in the history
  • Loading branch information
vitalif committed Jun 8, 2023
1 parent 8fc5589 commit 533e178
Showing 1 changed file with 81 additions and 77 deletions.
158 changes: 81 additions & 77 deletions internal/goofys.go
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,86 @@ func (fs *Goofys) Unmount(mountPoint string) {
return
}

func (fs *Goofys) RefreshInodeCache(inode *Inode) error {
inode.mu.Lock()
parent := inode.Parent
parentId := fuseops.InodeID(0)
if parent != nil {
parentId = parent.Id
}
name := inode.Name
inodeId := inode.Id
inode.mu.Unlock()
inode.resetDirTimeRec()
var mappedErr error
if parent == nil {
// For regular directories it's enough to send one invalidation
// message, the kernel will send forgets for their children and
// everything will be refreshed just fine.
// But root directory is a special case: we should invalidate all
// inodes in it ourselves. Basically this means that we have to do
// a listing and notify the kernel about every file in a root
// directory.
dh := inode.OpenDir()
dh.mu.Lock()
var notifications []interface{}
for {
en, err := dh.ReadDir(dh.lastInternalOffset, dh.lastExternalOffset)
if err != nil {
mappedErr = mapAwsError(err)
break
}
if en == nil {
break
}
if dh.lastInternalOffset >= 2 {
// Delete notifications are send by ReadDir() itself
notifications = append(notifications, &fuseops.NotifyInvalEntry{
Parent: inode.Id,
Name: en.Name,
})
}
dh.lastInternalOffset++
dh.lastExternalOffset++
}
dh.CloseDir()
dh.mu.Unlock()
// Send notifications from another goroutine to prevent deadlocks
if fs.connection != nil {
go func() {
for _, n := range notifications {
fs.connection.Notify(n)
}
}()
}
return mappedErr
}
inode, err := fs.recheckInode(parent, inode, name)
mappedErr = mapAwsError(err)
if fs.connection != nil {
// Send notifications from another goroutine to prevent deadlocks
go func() {
if mappedErr == syscall.ENOENT {
fs.connection.Notify(&fuseops.NotifyDelete{
Parent: parentId,
Child: inodeId,
Name: name,
})
} else {
fs.connection.Notify(&fuseops.NotifyInvalEntry{
Parent: parentId,
Name: name,
})
}
}()
}
if mappedErr == syscall.ENOENT {
// We don't mind if the file disappeared
return nil
}
return mappedErr
}

func (fs *Goofys) StatFS(
ctx context.Context,
op *fuseops.StatFSOp) (err error) {
Expand Down Expand Up @@ -906,83 +986,7 @@ func (fs *Goofys) SetXattr(ctx context.Context,

if op.Name == fs.flags.RefreshAttr {
// Setting xattr with special name (.invalidate) refreshes the inode's cache
inode.mu.Lock()
parent := inode.Parent
parentId := fuseops.InodeID(0)
if parent != nil {
parentId = parent.Id
}
name := inode.Name
inodeId := inode.Id
inode.mu.Unlock()
inode.resetDirTimeRec()
var mappedErr error
if parent == nil {
// For regular directories it's enough to send one invalidation
// message, the kernel will send forgets for their children and
// everything will be refreshed just fine.
// But root directory is a special case: we should invalidate all
// inodes in it ourselves. Basically this means that we have to do
// a listing and notify the kernel about every file in a root
// directory.
dh := inode.OpenDir()
dh.mu.Lock()
var notifications []interface{}
for {
en, err := dh.ReadDir(dh.lastInternalOffset, dh.lastExternalOffset)
if err != nil {
mappedErr = mapAwsError(err)
break
}
if en == nil {
break
}
if dh.lastInternalOffset >= 2 {
// Delete notifications are send by ReadDir() itself
notifications = append(notifications, &fuseops.NotifyInvalEntry{
Parent: inode.Id,
Name: en.Name,
})
}
dh.lastInternalOffset++
dh.lastExternalOffset++
}
dh.CloseDir()
dh.mu.Unlock()
// Send notifications from another goroutine to prevent deadlocks
if fs.connection != nil {
go func() {
for _, n := range notifications {
fs.connection.Notify(n)
}
}()
}
return mappedErr
}
inode, err = fs.recheckInode(parent, inode, name)
mappedErr = mapAwsError(err)
if fs.connection != nil {
// Send notifications from another goroutine to prevent deadlocks
go func() {
if mappedErr == syscall.ENOENT {
fs.connection.Notify(&fuseops.NotifyDelete{
Parent: parentId,
Child: inodeId,
Name: name,
})
} else {
fs.connection.Notify(&fuseops.NotifyInvalEntry{
Parent: parentId,
Name: name,
})
}
}()
}
if mappedErr == syscall.ENOENT {
// We don't mind if the file disappeared
return nil
}
return mappedErr
return fs.RefreshInodeCache(inode)
}

err = inode.SetXattr(op.Name, op.Value, op.Flags)
Expand Down

0 comments on commit 533e178

Please sign in to comment.