vfs: fix virtual entries leak in removed directory
Deleting the contents of a directory and then the directory itself, before a listing has confirmed the deletes, left the directory's virtual entries behind. They are counted in every parent directory, and a directory which counts virtual entries refuses to forget its cache, so vfs/forget could not make changes made outside rclone visible. This lasted until the removed directory's own cleanup timer purged its entries, which happens 2 x --dir-cache-time later. This fix drops the removed directory's virtual entries once it has been removed. Fixes #10083
This commit is contained in:
1 parent
36ce1a28fe
commit
dcf3483513
2 files changed
+27
No files matched your search
@@ -1142,6 +1142,15 @@ func (d *Dir) Remove() error {
|
||||
fs.Errorf(d, "Dir.Remove failed to remove directory: %v", err)
|
||||
return err
|
||||
}
|
||||
// The directory is gone, so no listing will resolve its virtual
|
||||
// entries, which can only be deletes as it was empty. They must be
|
||||
// removed now, or they will be counted in every parent and
|
||||
// cache forgets blocked as a consequence
|
||||
d.mu.Lock()
|
||||
for leaf := range d.virtual {
|
||||
d._deleteVirtual(leaf)
|
||||
}
|
||||
d.mu.Unlock()
|
||||
// Remove the item from the parent directory listing
|
||||
if d.parent != nil {
|
||||
d.parent.delObject(d.Name())
|
||||
|
||||
@@ -553,6 +553,24 @@ func TestDirRemove(t *testing.T) {
|
||||
assert.Equal(t, EROFS, err)
|
||||
}
|
||||
|
||||
// Removing a directory leaves no virtual entries counted in its parent, so the
|
||||
// parent can still forget its cache.
|
||||
func TestDirRemoveVirtuals(t *testing.T) {
|
||||
_, vfs, dir, _ := dirCreate(t)
|
||||
root, err := vfs.Root()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Remove the directory's contents and then the directory, before a
|
||||
// listing has confirmed the contents are gone.
|
||||
require.NoError(t, dir.RemoveName("file1"))
|
||||
require.NoError(t, root.RemoveName("dir"))
|
||||
|
||||
assert.False(t, root.ForgetAll(), "root holds virtual entries after rmdir")
|
||||
|
||||
dir.ForgetAll()
|
||||
assert.False(t, root.ForgetAll(), "root holds virtual entries after the removed dir is forgotten")
|
||||
}
|
||||
|
||||
func TestDirRemoveAll(t *testing.T) {
|
||||
r, vfs, dir, _ := dirCreate(t)
|
||||
|
||||
|
||||
Reference in new issue
Block a user