Skip to content

Commit

Permalink
mount: fix caching of old directories after renaming them
Browse files Browse the repository at this point in the history
It was discovered `rclone mount` (but not `rclone cmount`) cached
directories after rename which it shouldn't have done.

This caused IO errors when trying to access files in renamed
directories on bucket based file systems.

This turned out to be the kernel caching the directories as basil/fuse
sets their expiry time to 60s for some reason.

This fix invalidates the relevant kernel cache entries in the for the
directories which fixes the problem.

Fixes: #4977
See: https://forum.rclone.org/t/after-a-directory-renmane-using-mv-files-are-not-visible-any-longer/22797
  • Loading branch information
ncw committed Mar 17, 2021
1 parent e646465 commit d6bce21
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 4 deletions.
16 changes: 16 additions & 0 deletions cmd/mount/dir.go
Expand Up @@ -181,6 +181,15 @@ func (d *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) (err error) {
return nil
}

// Invalidate a leaf in a directory
func (d *Dir) invalidateEntry(dirNode fusefs.Node, leaf string) {
fs.Debugf(dirNode, "Invalidating %q", leaf)
err := d.fsys.server.InvalidateEntry(dirNode, leaf)
if err != nil {
fs.Debugf(dirNode, "Failed to invalidate %q: %v", leaf, err)
}
}

// Check interface satisfied
var _ fusefs.NodeRenamer = (*Dir)(nil)

Expand All @@ -197,6 +206,13 @@ func (d *Dir) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fusefs
return translateError(err)
}

// Invalidate the new directory entry so it gets re-read (in
// the background otherwise we cause a deadlock)
//
// See https://github.com/rclone/rclone/issues/4977 for why
go d.invalidateEntry(newDir, req.NewName)
//go d.invalidateEntry(d, req.OldName)

return nil
}

Expand Down
5 changes: 3 additions & 2 deletions cmd/mount/fs.go
Expand Up @@ -20,8 +20,9 @@ import (
// FS represents the top level filing system
type FS struct {
*vfs.VFS
f fs.Fs
opt *mountlib.Options
f fs.Fs
opt *mountlib.Options
server *fusefs.Server
}

// Check interface satisfied
Expand Down
4 changes: 2 additions & 2 deletions cmd/mount/mount.go
Expand Up @@ -91,12 +91,12 @@ func mount(VFS *vfs.VFS, mountpoint string, opt *mountlib.Options) (<-chan error
}

filesys := NewFS(VFS, opt)
server := fusefs.New(c, nil)
filesys.server = fusefs.New(c, nil)

// Serve the mount point in the background returning error to errChan
errChan := make(chan error, 1)
go func() {
err := server.Serve(filesys)
err := filesys.server.Serve(filesys)
closeErr := c.Close()
if err == nil {
err = closeErr
Expand Down

0 comments on commit d6bce21

Please sign in to comment.