mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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:
committed by
gVisor bot
parent
ef11bb936b
commit
b2ae7ea1bb
+5
-1
@@ -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
@@ -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
@@ -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")
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -46,7 +46,7 @@ type fullFD struct {
|
||||
}
|
||||
|
||||
// Release implements vfs.FileDescriptionImpl.Release.
|
||||
func (fd *fullFD) Release() {
|
||||
func (fd *fullFD) Release(context.Context) {
|
||||
// noop
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ type nullFD struct {
|
||||
}
|
||||
|
||||
// Release implements vfs.FileDescriptionImpl.Release.
|
||||
func (fd *nullFD) Release() {
|
||||
func (fd *nullFD) Release(context.Context) {
|
||||
// noop
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ type randomFD struct {
|
||||
}
|
||||
|
||||
// Release implements vfs.FileDescriptionImpl.Release.
|
||||
func (fd *randomFD) Release() {
|
||||
func (fd *randomFD) Release(context.Context) {
|
||||
// noop
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ type zeroFD struct {
|
||||
}
|
||||
|
||||
// Release implements vfs.FileDescriptionImpl.Release.
|
||||
func (fd *zeroFD) Release() {
|
||||
func (fd *zeroFD) Release(context.Context) {
|
||||
// noop
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user