Correctly update link and ref counts in rmdir.

Inotify sends events when a watch target is reaches a link count of 0 (see
include/linux/fsnotify.h:fsnotify_inoderemove). Currently, we do not account
for both dir/ and dir/.. in unlink, causing
syscalls/linux/inotify.cc:WatchTargetDeletionGeneratesEvent to fail because
the expected inotify events are not generated.

Furthermore, we should DecRef() once the inode reaches zero links; otherwise,
we will leak a reference.

PiperOrigin-RevId: 313502091
This commit is contained in:
Dean Deng
2020-05-27 18:19:38 -07:00
committed by gVisor bot
parent 835e8c89a5
commit 32021bce96
2 changed files with 11 additions and 8 deletions
+3 -1
View File
@@ -603,8 +603,10 @@ func (fs *filesystem) RmdirAt(ctx context.Context, rp *vfs.ResolvingPath) error
return err
}
parentDir.removeChildLocked(child)
parentDir.inode.decLinksLocked() // from child's ".."
// Remove links for child, child/., and child/..
child.inode.decLinksLocked()
child.inode.decLinksLocked()
parentDir.inode.decLinksLocked()
vfsObj.CommitDeleteDentry(&child.vfsd)
parentDir.inode.touchCMtime()
return nil
+8 -7
View File
@@ -209,11 +209,9 @@ type inode struct {
// refs is a reference count. refs is accessed using atomic memory
// operations.
//
// A reference is held on all inodes that are reachable in the filesystem
// tree. For non-directories (which may have multiple hard links), this
// means that a reference is dropped when nlink reaches 0. For directories,
// nlink never reaches 0 due to the "." entry; instead,
// filesystem.RmdirAt() drops the reference.
// A reference is held on all inodes as long as they are reachable in the
// filesystem tree, i.e. nlink is nonzero. This reference is dropped when
// nlink reaches 0.
refs int64
// xattrs implements extended attributes.
@@ -276,14 +274,17 @@ func (i *inode) incLinksLocked() {
atomic.AddUint32(&i.nlink, 1)
}
// decLinksLocked decrements i's link count.
// decLinksLocked decrements i's link count. If the link count reaches 0, we
// remove a reference on i as well.
//
// Preconditions: filesystem.mu must be locked for writing. i.nlink != 0.
func (i *inode) decLinksLocked() {
if i.nlink == 0 {
panic("tmpfs.inode.decLinksLocked() called with no existing links")
}
atomic.AddUint32(&i.nlink, ^uint32(0))
if atomic.AddUint32(&i.nlink, ^uint32(0)) == 0 {
i.decRef()
}
}
func (i *inode) incRef() {