Plumbing context.Context to DecRef() and Release().

context is passed to DecRef() and Release() which is
needed for SO_LINGER implementation.

PiperOrigin-RevId: 324672584
This commit is contained in:
Nayana Bidari
2020-08-03 13:36:05 -07:00
committed by gVisor bot
parent ef11bb936b
commit b2ae7ea1bb
252 changed files with 1711 additions and 1668 deletions
+5 -1
View File
@@ -24,6 +24,7 @@ go_library(
],
visibility = ["//:sandbox"],
deps = [
"//pkg/context",
"//pkg/log",
"//pkg/sync",
],
@@ -34,5 +35,8 @@ go_test(
size = "small",
srcs = ["refcounter_test.go"],
library = ":refs",
deps = ["//pkg/sync"],
deps = [
"//pkg/context",
"//pkg/sync",
],
)
+10 -9
View File
@@ -23,6 +23,7 @@ import (
"runtime"
"sync/atomic"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sync"
)
@@ -38,7 +39,7 @@ type RefCounter interface {
// Note that AtomicRefCounter.DecRef() does not support destructors.
// If a type has a destructor, it must implement its own DecRef()
// method and call AtomicRefCounter.DecRefWithDestructor(destructor).
DecRef()
DecRef(ctx context.Context)
// TryIncRef attempts to increase the reference counter on the object,
// but may fail if all references have already been dropped. This
@@ -57,7 +58,7 @@ type RefCounter interface {
// A WeakRefUser is notified when the last non-weak reference is dropped.
type WeakRefUser interface {
// WeakRefGone is called when the last non-weak reference is dropped.
WeakRefGone()
WeakRefGone(ctx context.Context)
}
// WeakRef is a weak reference.
@@ -123,7 +124,7 @@ func (w *WeakRef) Get() RefCounter {
// Drop drops this weak reference. You should always call drop when you are
// finished with the weak reference. You may not use this object after calling
// drop.
func (w *WeakRef) Drop() {
func (w *WeakRef) Drop(ctx context.Context) {
rc, ok := w.get()
if !ok {
// We've been zapped already. When the refcounter has called
@@ -145,7 +146,7 @@ func (w *WeakRef) Drop() {
// And now aren't on the object's list of weak references. So it won't
// zap us if this causes the reference count to drop to zero.
rc.DecRef()
rc.DecRef(ctx)
// Return to the pool.
weakRefPool.Put(w)
@@ -427,7 +428,7 @@ func (r *AtomicRefCount) dropWeakRef(w *WeakRef) {
// A: TryIncRef [transform speculative to real]
//
//go:nosplit
func (r *AtomicRefCount) DecRefWithDestructor(destroy func()) {
func (r *AtomicRefCount) DecRefWithDestructor(ctx context.Context, destroy func(context.Context)) {
switch v := atomic.AddInt64(&r.refCount, -1); {
case v < -1:
panic("Decrementing non-positive ref count")
@@ -448,7 +449,7 @@ func (r *AtomicRefCount) DecRefWithDestructor(destroy func()) {
if user != nil {
r.mu.Unlock()
user.WeakRefGone()
user.WeakRefGone(ctx)
r.mu.Lock()
}
}
@@ -456,7 +457,7 @@ func (r *AtomicRefCount) DecRefWithDestructor(destroy func()) {
// Call the destructor.
if destroy != nil {
destroy()
destroy(ctx)
}
}
}
@@ -464,6 +465,6 @@ func (r *AtomicRefCount) DecRefWithDestructor(destroy func()) {
// DecRef decrements this object's reference count.
//
//go:nosplit
func (r *AtomicRefCount) DecRef() {
r.DecRefWithDestructor(nil)
func (r *AtomicRefCount) DecRef(ctx context.Context) {
r.DecRefWithDestructor(ctx, nil)
}
+22 -16
View File
@@ -18,6 +18,7 @@ import (
"reflect"
"testing"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/sync"
)
@@ -31,11 +32,11 @@ type testCounter struct {
destroyed bool
}
func (t *testCounter) DecRef() {
t.AtomicRefCount.DecRefWithDestructor(t.destroy)
func (t *testCounter) DecRef(ctx context.Context) {
t.AtomicRefCount.DecRefWithDestructor(ctx, t.destroy)
}
func (t *testCounter) destroy() {
func (t *testCounter) destroy(context.Context) {
t.mu.Lock()
defer t.mu.Unlock()
t.destroyed = true
@@ -53,7 +54,7 @@ func newTestCounter() *testCounter {
func TestOneRef(t *testing.T) {
tc := newTestCounter()
tc.DecRef()
tc.DecRef(context.Background())
if !tc.IsDestroyed() {
t.Errorf("object should have been destroyed")
@@ -63,8 +64,9 @@ func TestOneRef(t *testing.T) {
func TestTwoRefs(t *testing.T) {
tc := newTestCounter()
tc.IncRef()
tc.DecRef()
tc.DecRef()
ctx := context.Background()
tc.DecRef(ctx)
tc.DecRef(ctx)
if !tc.IsDestroyed() {
t.Errorf("object should have been destroyed")
@@ -74,12 +76,13 @@ func TestTwoRefs(t *testing.T) {
func TestMultiRefs(t *testing.T) {
tc := newTestCounter()
tc.IncRef()
tc.DecRef()
ctx := context.Background()
tc.DecRef(ctx)
tc.IncRef()
tc.DecRef()
tc.DecRef(ctx)
tc.DecRef()
tc.DecRef(ctx)
if !tc.IsDestroyed() {
t.Errorf("object should have been destroyed")
@@ -89,19 +92,20 @@ func TestMultiRefs(t *testing.T) {
func TestWeakRef(t *testing.T) {
tc := newTestCounter()
w := NewWeakRef(tc, nil)
ctx := context.Background()
// Try resolving.
if x := w.Get(); x == nil {
t.Errorf("weak reference didn't resolve: expected %v, got nil", tc)
} else {
x.DecRef()
x.DecRef(ctx)
}
// Try resolving again.
if x := w.Get(); x == nil {
t.Errorf("weak reference didn't resolve: expected %v, got nil", tc)
} else {
x.DecRef()
x.DecRef(ctx)
}
// Shouldn't be destroyed yet. (Can't continue if this fails.)
@@ -110,7 +114,7 @@ func TestWeakRef(t *testing.T) {
}
// Drop the original reference.
tc.DecRef()
tc.DecRef(ctx)
// Assert destroyed.
if !tc.IsDestroyed() {
@@ -126,7 +130,8 @@ func TestWeakRef(t *testing.T) {
func TestWeakRefDrop(t *testing.T) {
tc := newTestCounter()
w := NewWeakRef(tc, nil)
w.Drop()
ctx := context.Background()
w.Drop(ctx)
// Just assert the list is empty.
if !tc.weakRefs.Empty() {
@@ -134,14 +139,14 @@ func TestWeakRefDrop(t *testing.T) {
}
// Drop the original reference.
tc.DecRef()
tc.DecRef(ctx)
}
type testWeakRefUser struct {
weakRefGone func()
}
func (u *testWeakRefUser) WeakRefGone() {
func (u *testWeakRefUser) WeakRefGone(ctx context.Context) {
u.weakRefGone()
}
@@ -165,7 +170,8 @@ func TestCallback(t *testing.T) {
}})
// Drop the original reference, this must trigger the callback.
tc.DecRef()
ctx := context.Background()
tc.DecRef(ctx)
if !called {
t.Fatalf("Callback not called")
+1 -1
View File
@@ -139,7 +139,6 @@ func ExecAsync(proc *Proc, args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadID
func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadID, *host.TTYFileOperations, *hostvfs2.TTYFileDescription, error) {
// Import file descriptors.
fdTable := proc.Kernel.NewFDTable()
defer fdTable.DecRef()
creds := auth.NewUserCredentials(
args.KUID,
@@ -177,6 +176,7 @@ func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadI
initArgs.MountNamespaceVFS2.IncRef()
}
ctx := initArgs.NewContext(proc.Kernel)
defer fdTable.DecRef(ctx)
if kernel.VFS2Enabled {
// Get the full path to the filename from the PATH env variable.
+1 -1
View File
@@ -46,7 +46,7 @@ type fullFD struct {
}
// Release implements vfs.FileDescriptionImpl.Release.
func (fd *fullFD) Release() {
func (fd *fullFD) Release(context.Context) {
// noop
}
+1 -1
View File
@@ -47,7 +47,7 @@ type nullFD struct {
}
// Release implements vfs.FileDescriptionImpl.Release.
func (fd *nullFD) Release() {
func (fd *nullFD) Release(context.Context) {
// noop
}
+1 -1
View File
@@ -56,7 +56,7 @@ type randomFD struct {
}
// Release implements vfs.FileDescriptionImpl.Release.
func (fd *randomFD) Release() {
func (fd *randomFD) Release(context.Context) {
// noop
}
+1 -1
View File
@@ -48,7 +48,7 @@ type zeroFD struct {
}
// Release implements vfs.FileDescriptionImpl.Release.
func (fd *zeroFD) Release() {
func (fd *zeroFD) Release(context.Context) {
// noop
}
+1 -1
View File
@@ -55,7 +55,7 @@ type ttyFD struct {
}
// Release implements vfs.FileDescriptionImpl.Release.
func (fd *ttyFD) Release() {}
func (fd *ttyFD) Release(context.Context) {}
// PRead implements vfs.FileDescriptionImpl.PRead.
func (fd *ttyFD) PRead(ctx context.Context, dst usermem.IOSequence, offset int64, opts vfs.ReadOptions) (int64, error) {
+2 -2
View File
@@ -108,8 +108,8 @@ func (fd *tunFD) Ioctl(ctx context.Context, uio usermem.IO, args arch.SyscallArg
}
// Release implements vfs.FileDescriptionImpl.Release.
func (fd *tunFD) Release() {
fd.device.Release()
func (fd *tunFD) Release(ctx context.Context) {
fd.device.Release(ctx)
}
// PRead implements vfs.FileDescriptionImpl.PRead.
+4 -4
View File
@@ -50,7 +50,7 @@ func importFS(ctx context.Context, fdTable *kernel.FDTable, console bool, fds []
if err != nil {
return nil, err
}
defer appFile.DecRef()
defer appFile.DecRef(ctx)
// Remember this in the TTY file, as we will
// use it for the other stdio FDs.
@@ -69,7 +69,7 @@ func importFS(ctx context.Context, fdTable *kernel.FDTable, console bool, fds []
if err != nil {
return nil, err
}
defer appFile.DecRef()
defer appFile.DecRef(ctx)
}
// Add the file to the FD map.
@@ -102,7 +102,7 @@ func importVFS2(ctx context.Context, fdTable *kernel.FDTable, console bool, stdi
if err != nil {
return nil, err
}
defer appFile.DecRef()
defer appFile.DecRef(ctx)
// Remember this in the TTY file, as we will use it for the other stdio
// FDs.
@@ -119,7 +119,7 @@ func importVFS2(ctx context.Context, fdTable *kernel.FDTable, console bool, stdi
if err != nil {
return nil, err
}
defer appFile.DecRef()
defer appFile.DecRef(ctx)
}
if err := fdTable.NewFDAtVFS2(ctx, int32(appFD), appFile, kernel.FDFlags{}); err != nil {
+6 -6
View File
@@ -201,7 +201,7 @@ func copyUpLocked(ctx context.Context, parent *Dirent, next *Dirent) error {
parentUpper := parent.Inode.overlay.upper
root := RootFromContext(ctx)
if root != nil {
defer root.DecRef()
defer root.DecRef(ctx)
}
// Create the file in the upper filesystem and get an Inode for it.
@@ -212,7 +212,7 @@ func copyUpLocked(ctx context.Context, parent *Dirent, next *Dirent) error {
log.Warningf("copy up failed to create file: %v", err)
return syserror.EIO
}
defer childFile.DecRef()
defer childFile.DecRef(ctx)
childUpperInode = childFile.Dirent.Inode
case Directory:
@@ -226,7 +226,7 @@ func copyUpLocked(ctx context.Context, parent *Dirent, next *Dirent) error {
cleanupUpper(ctx, parentUpper, next.name, werr)
return syserror.EIO
}
defer childUpper.DecRef()
defer childUpper.DecRef(ctx)
childUpperInode = childUpper.Inode
case Symlink:
@@ -246,7 +246,7 @@ func copyUpLocked(ctx context.Context, parent *Dirent, next *Dirent) error {
cleanupUpper(ctx, parentUpper, next.name, werr)
return syserror.EIO
}
defer childUpper.DecRef()
defer childUpper.DecRef(ctx)
childUpperInode = childUpper.Inode
default:
@@ -352,14 +352,14 @@ func copyContentsLocked(ctx context.Context, upper *Inode, lower *Inode, size in
if err != nil {
return err
}
defer upperFile.DecRef()
defer upperFile.DecRef(ctx)
// Get a handle to the lower filesystem, which we will read from.
lowerFile, err := overlayFile(ctx, lower, FileFlags{Read: true})
if err != nil {
return err
}
defer lowerFile.DecRef()
defer lowerFile.DecRef(ctx)
// Use a buffer pool to minimize allocations.
buf := copyUpBuffers.Get().([]byte)
+2 -2
View File
@@ -126,7 +126,7 @@ func makeOverlayTestFiles(t *testing.T) []*overlayTestFile {
if err != nil {
t.Fatalf("failed to create file %q: %v", name, err)
}
defer f.DecRef()
defer f.DecRef(ctx)
relname, _ := f.Dirent.FullName(lowerRoot)
@@ -171,7 +171,7 @@ func makeOverlayTestFiles(t *testing.T) []*overlayTestFile {
if err != nil {
t.Fatalf("failed to find %q: %v", f.name, err)
}
defer d.DecRef()
defer d.DecRef(ctx)
f.File, err = d.Inode.GetFile(ctx, d, fs.FileFlags{Read: true})
if err != nil {
+2 -2
View File
@@ -80,8 +80,8 @@ type netTunFileOperations struct {
var _ fs.FileOperations = (*netTunFileOperations)(nil)
// Release implements fs.FileOperations.Release.
func (fops *netTunFileOperations) Release() {
fops.device.Release()
func (fops *netTunFileOperations) Release(ctx context.Context) {
fops.device.Release(ctx)
}
// Ioctl implements fs.FileOperations.Ioctl.
+55 -55
View File
@@ -325,7 +325,7 @@ func (d *Dirent) SyncAll(ctx context.Context) {
for _, w := range d.children {
if child := w.Get(); child != nil {
child.(*Dirent).SyncAll(ctx)
child.DecRef()
child.DecRef(ctx)
}
}
}
@@ -451,7 +451,7 @@ func (d *Dirent) walk(ctx context.Context, root *Dirent, name string, walkMayUnl
// which don't hold a hard reference on their parent (their parent holds a
// hard reference on them, and they contain virtually no state). But this is
// good house-keeping.
child.DecRef()
child.DecRef(ctx)
return nil, syscall.ENOENT
}
@@ -468,20 +468,20 @@ func (d *Dirent) walk(ctx context.Context, root *Dirent, name string, walkMayUnl
// their pins on the child. Inotify doesn't properly support filesystems that
// revalidate dirents (since watches are lost on revalidation), but if we fail
// to unpin the watches child will never be GCed.
cd.Inode.Watches.Unpin(cd)
cd.Inode.Watches.Unpin(ctx, cd)
// This child needs to be revalidated, fallthrough to unhash it. Make sure
// to not leak a reference from Get().
//
// Note that previous lookups may still have a reference to this stale child;
// this can't be helped, but we can ensure that *new* lookups are up-to-date.
child.DecRef()
child.DecRef(ctx)
}
// Either our weak reference expired or we need to revalidate it. Unhash child first, we're
// about to replace it.
delete(d.children, name)
w.Drop()
w.Drop(ctx)
}
// Slow path: load the InodeOperations into memory. Since this is a hot path and the lookup may be
@@ -512,12 +512,12 @@ func (d *Dirent) walk(ctx context.Context, root *Dirent, name string, walkMayUnl
// There are active references to the existing child, prefer it to the one we
// retrieved from Lookup. Likely the Lookup happened very close to the insertion
// of child, so considering one stale over the other is fairly arbitrary.
c.DecRef()
c.DecRef(ctx)
// The child that was installed could be negative.
if cd.IsNegative() {
// If so, don't leak a reference and short circuit.
child.DecRef()
child.DecRef(ctx)
return nil, syscall.ENOENT
}
@@ -531,7 +531,7 @@ func (d *Dirent) walk(ctx context.Context, root *Dirent, name string, walkMayUnl
// we did the Inode.Lookup. Fully drop the weak reference and fallback to using the child
// we looked up.
delete(d.children, name)
w.Drop()
w.Drop(ctx)
}
// Give the looked up child a parent. We cannot kick out entries, since we just checked above
@@ -587,7 +587,7 @@ func (d *Dirent) exists(ctx context.Context, root *Dirent, name string) bool {
return false
}
// Child exists.
child.DecRef()
child.DecRef(ctx)
return true
}
@@ -622,7 +622,7 @@ func (d *Dirent) Create(ctx context.Context, root *Dirent, name string, flags Fi
}
child := file.Dirent
d.finishCreate(child, name)
d.finishCreate(ctx, child, name)
// Return the reference and the new file. When the last reference to
// the file is dropped, file.Dirent may no longer be cached.
@@ -631,7 +631,7 @@ func (d *Dirent) Create(ctx context.Context, root *Dirent, name string, flags Fi
// finishCreate validates the created file, adds it as a child of this dirent,
// and notifies any watchers.
func (d *Dirent) finishCreate(child *Dirent, name string) {
func (d *Dirent) finishCreate(ctx context.Context, child *Dirent, name string) {
// Sanity check c, its name must be consistent.
if child.name != name {
panic(fmt.Sprintf("create from %q to %q returned unexpected name %q", d.name, name, child.name))
@@ -650,14 +650,14 @@ func (d *Dirent) finishCreate(child *Dirent, name string) {
panic(fmt.Sprintf("hashed child %q over a positive child", child.name))
}
// Don't leak a reference.
old.DecRef()
old.DecRef(ctx)
// Drop d's reference.
old.DecRef()
old.DecRef(ctx)
}
// Finally drop the useless weak reference on the floor.
w.Drop()
w.Drop(ctx)
}
d.Inode.Watches.Notify(name, linux.IN_CREATE, 0)
@@ -686,17 +686,17 @@ func (d *Dirent) genericCreate(ctx context.Context, root *Dirent, name string, c
panic(fmt.Sprintf("hashed over a positive child %q", old.(*Dirent).name))
}
// Don't leak a reference.
old.DecRef()
old.DecRef(ctx)
// Drop d's reference.
old.DecRef()
old.DecRef(ctx)
}
// Unhash the negative Dirent, name needs to exist now.
delete(d.children, name)
// Finally drop the useless weak reference on the floor.
w.Drop()
w.Drop(ctx)
}
// Execute the create operation.
@@ -756,7 +756,7 @@ func (d *Dirent) Bind(ctx context.Context, root *Dirent, name string, data trans
if e != nil {
return e
}
d.finishCreate(childDir, name)
d.finishCreate(ctx, childDir, name)
return nil
})
if err == syscall.EEXIST {
@@ -901,7 +901,7 @@ func direntReaddir(ctx context.Context, d *Dirent, it DirIterator, root *Dirent,
// references to children.
//
// Preconditions: d.mu must be held.
func (d *Dirent) flush() {
func (d *Dirent) flush(ctx context.Context) {
expired := make(map[string]*refs.WeakRef)
for n, w := range d.children {
// Call flush recursively on each child before removing our
@@ -912,7 +912,7 @@ func (d *Dirent) flush() {
if !cd.IsNegative() {
// Flush the child.
cd.mu.Lock()
cd.flush()
cd.flush(ctx)
cd.mu.Unlock()
// Allow the file system to drop extra references on child.
@@ -920,13 +920,13 @@ func (d *Dirent) flush() {
}
// Don't leak a reference.
child.DecRef()
child.DecRef(ctx)
}
// Check if the child dirent is closed, and mark it as expired if it is.
// We must call w.Get() again here, since the child could have been closed
// by the calls to flush() and cache.Remove() in the above if-block.
if child := w.Get(); child != nil {
child.DecRef()
child.DecRef(ctx)
} else {
expired[n] = w
}
@@ -935,7 +935,7 @@ func (d *Dirent) flush() {
// Remove expired entries.
for n, w := range expired {
delete(d.children, n)
w.Drop()
w.Drop(ctx)
}
}
@@ -977,7 +977,7 @@ func (d *Dirent) mount(ctx context.Context, inode *Inode) (newChild *Dirent, err
if !ok {
panic("mount must mount over an existing dirent")
}
weakRef.Drop()
weakRef.Drop(ctx)
// Note that even though `d` is now hidden, it still holds a reference
// to its parent.
@@ -1002,13 +1002,13 @@ func (d *Dirent) unmount(ctx context.Context, replacement *Dirent) error {
if !ok {
panic("mount must mount over an existing dirent")
}
weakRef.Drop()
weakRef.Drop(ctx)
// d is not reachable anymore, and hence not mounted anymore.
d.mounted = false
// Drop mount reference.
d.DecRef()
d.DecRef(ctx)
return nil
}
@@ -1029,7 +1029,7 @@ func (d *Dirent) Remove(ctx context.Context, root *Dirent, name string, dirPath
// Child does not exist.
return err
}
defer child.DecRef()
defer child.DecRef(ctx)
// Remove cannot remove directories.
if IsDir(child.Inode.StableAttr) {
@@ -1055,7 +1055,7 @@ func (d *Dirent) Remove(ctx context.Context, root *Dirent, name string, dirPath
atomic.StoreInt32(&child.deleted, 1)
if w, ok := d.children[name]; ok {
delete(d.children, name)
w.Drop()
w.Drop(ctx)
}
// Allow the file system to drop extra references on child.
@@ -1067,7 +1067,7 @@ func (d *Dirent) Remove(ctx context.Context, root *Dirent, name string, dirPath
// inode may have other links. If this was the last link, the events for the
// watch removal will be queued by the inode destructor.
child.Inode.Watches.MarkUnlinked()
child.Inode.Watches.Unpin(child)
child.Inode.Watches.Unpin(ctx, child)
d.Inode.Watches.Notify(name, linux.IN_DELETE, 0)
return nil
@@ -1100,7 +1100,7 @@ func (d *Dirent) RemoveDirectory(ctx context.Context, root *Dirent, name string)
// Child does not exist.
return err
}
defer child.DecRef()
defer child.DecRef(ctx)
// RemoveDirectory can only remove directories.
if !IsDir(child.Inode.StableAttr) {
@@ -1121,7 +1121,7 @@ func (d *Dirent) RemoveDirectory(ctx context.Context, root *Dirent, name string)
atomic.StoreInt32(&child.deleted, 1)
if w, ok := d.children[name]; ok {
delete(d.children, name)
w.Drop()
w.Drop(ctx)
}
// Allow the file system to drop extra references on child.
@@ -1130,14 +1130,14 @@ func (d *Dirent) RemoveDirectory(ctx context.Context, root *Dirent, name string)
// Finally, let inotify know the child is being unlinked. Drop any extra
// refs from inotify to this child dirent.
child.Inode.Watches.MarkUnlinked()
child.Inode.Watches.Unpin(child)
child.Inode.Watches.Unpin(ctx, child)
d.Inode.Watches.Notify(name, linux.IN_ISDIR|linux.IN_DELETE, 0)
return nil
}
// destroy closes this node and all children.
func (d *Dirent) destroy() {
func (d *Dirent) destroy(ctx context.Context) {
if d.IsNegative() {
// Nothing to tear-down and no parent references to drop, since a negative
// Dirent does not take a references on its parent, has no Inode and no children.
@@ -1153,19 +1153,19 @@ func (d *Dirent) destroy() {
if c.(*Dirent).IsNegative() {
// The parent holds both weak and strong refs in the case of
// negative dirents.
c.DecRef()
c.DecRef(ctx)
}
// Drop the reference we just acquired in WeakRef.Get.
c.DecRef()
c.DecRef(ctx)
}
w.Drop()
w.Drop(ctx)
}
d.children = nil
allDirents.remove(d)
// Drop our reference to the Inode.
d.Inode.DecRef()
d.Inode.DecRef(ctx)
// Allow the Dirent to be GC'ed after this point, since the Inode may still
// be referenced after the Dirent is destroyed (for instance by filesystem
@@ -1175,7 +1175,7 @@ func (d *Dirent) destroy() {
// Drop the reference we have on our parent if we took one. renameMu doesn't need to be
// held because d can't be reparented without any references to it left.
if d.parent != nil {
d.parent.DecRef()
d.parent.DecRef(ctx)
}
}
@@ -1201,14 +1201,14 @@ func (d *Dirent) TryIncRef() bool {
// DecRef decreases the Dirent's refcount and drops its reference on its mount.
//
// DecRef implements RefCounter.DecRef with destructor d.destroy.
func (d *Dirent) DecRef() {
func (d *Dirent) DecRef(ctx context.Context) {
if d.Inode != nil {
// Keep mount around, since DecRef may destroy d.Inode.
msrc := d.Inode.MountSource
d.DecRefWithDestructor(d.destroy)
d.DecRefWithDestructor(ctx, d.destroy)
msrc.DecDirentRefs()
} else {
d.DecRefWithDestructor(d.destroy)
d.DecRefWithDestructor(ctx, d.destroy)
}
}
@@ -1359,7 +1359,7 @@ func (d *Dirent) MayDelete(ctx context.Context, root *Dirent, name string) error
if err != nil {
return err
}
defer victim.DecRef()
defer victim.DecRef(ctx)
return d.mayDelete(ctx, victim)
}
@@ -1411,7 +1411,7 @@ func Rename(ctx context.Context, root *Dirent, oldParent *Dirent, oldName string
if err != nil {
return err
}
defer renamed.DecRef()
defer renamed.DecRef(ctx)
// Check that the renamed dirent is deletable.
if err := oldParent.mayDelete(ctx, renamed); err != nil {
@@ -1453,13 +1453,13 @@ func Rename(ctx context.Context, root *Dirent, oldParent *Dirent, oldName string
// Check that we can delete replaced.
if err := newParent.mayDelete(ctx, replaced); err != nil {
replaced.DecRef()
replaced.DecRef(ctx)
return err
}
// Target should not be an ancestor of source.
if oldParent.descendantOf(replaced) {
replaced.DecRef()
replaced.DecRef(ctx)
// Note that Linux returns EINVAL if the source is an
// ancestor of target, but ENOTEMPTY if the target is
@@ -1470,7 +1470,7 @@ func Rename(ctx context.Context, root *Dirent, oldParent *Dirent, oldName string
// Check that replaced is not a mount point.
if replaced.isMountPointLocked() {
replaced.DecRef()
replaced.DecRef(ctx)
return syscall.EBUSY
}
@@ -1478,11 +1478,11 @@ func Rename(ctx context.Context, root *Dirent, oldParent *Dirent, oldName string
oldIsDir := IsDir(renamed.Inode.StableAttr)
newIsDir := IsDir(replaced.Inode.StableAttr)
if !newIsDir && oldIsDir {
replaced.DecRef()
replaced.DecRef(ctx)
return syscall.ENOTDIR
}
if !oldIsDir && newIsDir {
replaced.DecRef()
replaced.DecRef(ctx)
return syscall.EISDIR
}
@@ -1493,13 +1493,13 @@ func Rename(ctx context.Context, root *Dirent, oldParent *Dirent, oldName string
// open across renames is currently broken for multiple
// reasons, so we flush all references on the replaced node and
// its children.
replaced.Inode.Watches.Unpin(replaced)
replaced.Inode.Watches.Unpin(ctx, replaced)
replaced.mu.Lock()
replaced.flush()
replaced.flush(ctx)
replaced.mu.Unlock()
// Done with replaced.
replaced.DecRef()
replaced.DecRef(ctx)
}
if err := renamed.Inode.Rename(ctx, oldParent, renamed, newParent, newName, replaced != nil); err != nil {
@@ -1513,14 +1513,14 @@ func Rename(ctx context.Context, root *Dirent, oldParent *Dirent, oldName string
// can't destroy oldParent (and try to retake its lock) because
// Rename's caller must be holding a reference.
newParent.IncRef()
oldParent.DecRef()
oldParent.DecRef(ctx)
}
if w, ok := newParent.children[newName]; ok {
w.Drop()
w.Drop(ctx)
delete(newParent.children, newName)
}
if w, ok := oldParent.children[oldName]; ok {
w.Drop()
w.Drop(ctx)
delete(oldParent.children, oldName)
}
@@ -1551,7 +1551,7 @@ func Rename(ctx context.Context, root *Dirent, oldParent *Dirent, oldName string
// Same as replaced.flush above.
renamed.mu.Lock()
renamed.flush()
renamed.flush(ctx)
renamed.mu.Unlock()
return nil
+2 -1
View File
@@ -17,6 +17,7 @@ package fs
import (
"fmt"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/sync"
)
@@ -101,7 +102,7 @@ func (c *DirentCache) remove(d *Dirent) {
panic(fmt.Sprintf("trying to remove %v, which is not in the dirent cache", d))
}
c.list.Remove(d)
d.DecRef()
d.DecRef(context.Background())
c.currentSize--
if c.limit != nil {
c.limit.dec()
+8 -8
View File
@@ -51,7 +51,7 @@ func TestWalkPositive(t *testing.T) {
t.Fatalf("child name = %q has a ref count of %d, want %d", d.name, got, 1)
}
d.DecRef()
d.DecRef(ctx)
if got := root.ReadRefs(); got != 1 {
t.Fatalf("root has a ref count of %d, want %d", got, 1)
@@ -61,7 +61,7 @@ func TestWalkPositive(t *testing.T) {
t.Fatalf("child name = %q has a ref count of %d, want %d", d.name, got, 0)
}
root.flush()
root.flush(ctx)
if got := len(root.children); got != 0 {
t.Fatalf("root has %d children, want %d", got, 0)
@@ -114,7 +114,7 @@ func TestWalkNegative(t *testing.T) {
t.Fatalf("child has a ref count of %d, want %d", got, 2)
}
child.DecRef()
child.DecRef(ctx)
if got := child.(*Dirent).ReadRefs(); got != 1 {
t.Fatalf("child has a ref count of %d, want %d", got, 1)
@@ -124,7 +124,7 @@ func TestWalkNegative(t *testing.T) {
t.Fatalf("root has %d children, want %d", got, 1)
}
root.DecRef()
root.DecRef(ctx)
if got := root.ReadRefs(); got != 0 {
t.Fatalf("root has a ref count of %d, want %d", got, 0)
@@ -351,9 +351,9 @@ func TestRemoveExtraRefs(t *testing.T) {
t.Fatalf("dirent has a ref count of %d, want %d", got, 1)
}
d.DecRef()
d.DecRef(ctx)
test.root.flush()
test.root.flush(ctx)
if got := len(test.root.children); got != 0 {
t.Errorf("root has %d children, want %d", got, 0)
@@ -403,8 +403,8 @@ func TestRenameExtraRefs(t *testing.T) {
t.Fatalf("Rename got error %v, want nil", err)
}
oldParent.flush()
newParent.flush()
oldParent.flush(ctx)
newParent.flush(ctx)
// Expect to have only active references.
if got := renamed.ReadRefs(); got != 1 {
+2 -1
View File
@@ -18,6 +18,7 @@ import (
"fmt"
"sync/atomic"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/refs"
)
@@ -48,7 +49,7 @@ func (d *Dirent) saveChildren() map[string]*Dirent {
for name, w := range d.children {
if rc := w.Get(); rc != nil {
// Drop the reference count obtain in w.Get()
rc.DecRef()
rc.DecRef(context.Background())
cd := rc.(*Dirent)
if cd.IsNegative() {
+1 -1
View File
@@ -115,7 +115,7 @@ func (p *pipeOperations) Readiness(mask waiter.EventMask) (eventMask waiter.Even
}
// Release implements fs.FileOperations.Release.
func (p *pipeOperations) Release() {
func (p *pipeOperations) Release(context.Context) {
fdnotifier.RemoveFD(int32(p.file.FD()))
p.file.Close()
p.file = nil
+8 -8
View File
@@ -182,7 +182,7 @@ func TestTryOpen(t *testing.T) {
// Cleanup the state of the pipe, and remove the fd from the
// fdnotifier. Sadly this needed to maintain the correctness
// of other tests because the fdnotifier is global.
pipeOps.Release()
pipeOps.Release(ctx)
}
continue
}
@@ -191,7 +191,7 @@ func TestTryOpen(t *testing.T) {
}
if pipeOps != nil {
// Same as above.
pipeOps.Release()
pipeOps.Release(ctx)
}
}
}
@@ -279,7 +279,7 @@ func TestPipeOpenUnblocksEventually(t *testing.T) {
pipeOps, err := Open(ctx, opener, flags)
if pipeOps != nil {
// Same as TestTryOpen.
pipeOps.Release()
pipeOps.Release(ctx)
}
// Check that the partner opened the file successfully.
@@ -325,7 +325,7 @@ func TestCopiedReadAheadBuffer(t *testing.T) {
ctx := contexttest.Context(t)
pipeOps, err := pipeOpenState.TryOpen(ctx, opener, fs.FileFlags{Read: true})
if pipeOps != nil {
pipeOps.Release()
pipeOps.Release(ctx)
t.Fatalf("open(%s, %o) got file, want nil", name, syscall.O_RDONLY)
}
if err != syserror.ErrWouldBlock {
@@ -351,7 +351,7 @@ func TestCopiedReadAheadBuffer(t *testing.T) {
if pipeOps == nil {
t.Fatalf("open(%s, %o) got nil file, want not nil", name, syscall.O_RDONLY)
}
defer pipeOps.Release()
defer pipeOps.Release(ctx)
if err != nil {
t.Fatalf("open(%s, %o) got error %v, want nil", name, syscall.O_RDONLY, err)
@@ -471,14 +471,14 @@ func TestPipeHangup(t *testing.T) {
f := <-fdchan
if f < 0 {
t.Errorf("%s: partner routine got fd %d, want > 0", test.desc, f)
pipeOps.Release()
pipeOps.Release(ctx)
continue
}
if test.hangupSelf {
// Hangup self and assert that our partner got the expected hangup
// error.
pipeOps.Release()
pipeOps.Release(ctx)
if test.flags.Read {
// Partner is writer.
@@ -490,7 +490,7 @@ func TestPipeHangup(t *testing.T) {
} else {
// Hangup our partner and expect us to get the hangup error.
syscall.Close(f)
defer pipeOps.Release()
defer pipeOps.Release(ctx)
if test.flags.Read {
assertReaderHungup(t, test.desc, pipeOps.(*pipeOperations).file)

Some files were not shown because too many files have changed in this diff Show More