mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Remove the Dirent field from Pipe.
Dirents are ref-counted, but Pipes are not. Holding a Dirent inside of a Pipe raises difficult questions about the lifecycle of the Pipe and Dirent. Fortunately, we can side-step those questions by removing the Dirent field from Pipe entirely. We only need the Dirent when constructing fs.Files (which are ref-counted), and in GetFile (when a Dirent is passed to us anyways). PiperOrigin-RevId: 251497628
This commit is contained in:
committed by
Shentubot
parent
7436ea247b
commit
0c292cdaab
@@ -38,7 +38,11 @@ type inodeOperations struct {
|
||||
fsutil.InodeNotMappable `state:"nosave"`
|
||||
fsutil.InodeNotSocket `state:"nosave"`
|
||||
fsutil.InodeNotSymlink `state:"nosave"`
|
||||
fsutil.InodeNotVirtual `state:"nosave"`
|
||||
|
||||
// Marking pipe inodes as virtual allows them to be saved and restored
|
||||
// even if they have been unlinked. We can get away with this because
|
||||
// their state exists entirely within the sentry.
|
||||
fsutil.InodeVirtual `state:"nosave"`
|
||||
|
||||
fsutil.InodeSimpleAttributes
|
||||
|
||||
@@ -86,7 +90,7 @@ func (i *inodeOperations) GetFile(ctx context.Context, d *fs.Dirent, flags fs.Fi
|
||||
|
||||
switch {
|
||||
case flags.Read && !flags.Write: // O_RDONLY.
|
||||
r := i.p.Open(ctx, flags)
|
||||
r := i.p.Open(ctx, d, flags)
|
||||
i.newHandleLocked(&i.rWakeup)
|
||||
|
||||
if i.p.isNamed && !flags.NonBlocking && !i.p.HasWriters() {
|
||||
@@ -102,7 +106,7 @@ func (i *inodeOperations) GetFile(ctx context.Context, d *fs.Dirent, flags fs.Fi
|
||||
return r, nil
|
||||
|
||||
case flags.Write && !flags.Read: // O_WRONLY.
|
||||
w := i.p.Open(ctx, flags)
|
||||
w := i.p.Open(ctx, d, flags)
|
||||
i.newHandleLocked(&i.wWakeup)
|
||||
|
||||
if i.p.isNamed && !i.p.HasReaders() {
|
||||
@@ -122,7 +126,7 @@ func (i *inodeOperations) GetFile(ctx context.Context, d *fs.Dirent, flags fs.Fi
|
||||
|
||||
case flags.Read && flags.Write: // O_RDWR.
|
||||
// Pipes opened for read-write always succeeds without blocking.
|
||||
rw := i.p.Open(ctx, flags)
|
||||
rw := i.p.Open(ctx, d, flags)
|
||||
i.newHandleLocked(&i.rWakeup)
|
||||
i.newHandleLocked(&i.wWakeup)
|
||||
return rw, nil
|
||||
|
||||
@@ -62,7 +62,9 @@ var perms fs.FilePermissions = fs.FilePermissions{
|
||||
}
|
||||
|
||||
func testOpenOrDie(ctx context.Context, t *testing.T, n fs.InodeOperations, flags fs.FileFlags, doneChan chan<- struct{}) (*fs.File, error) {
|
||||
file, err := n.GetFile(ctx, nil, flags)
|
||||
inode := fs.NewMockInode(ctx, fs.NewMockMountSource(nil), fs.StableAttr{Type: fs.Pipe})
|
||||
d := fs.NewDirent(inode, "pipe")
|
||||
file, err := n.GetFile(ctx, d, flags)
|
||||
if err != nil {
|
||||
t.Fatalf("open with flags %+v failed: %v", flags, err)
|
||||
}
|
||||
@@ -73,7 +75,9 @@ func testOpenOrDie(ctx context.Context, t *testing.T, n fs.InodeOperations, flag
|
||||
}
|
||||
|
||||
func testOpen(ctx context.Context, t *testing.T, n fs.InodeOperations, flags fs.FileFlags, resChan chan<- openResult) (*fs.File, error) {
|
||||
file, err := n.GetFile(ctx, nil, flags)
|
||||
inode := fs.NewMockInode(ctx, fs.NewMockMountSource(nil), fs.StableAttr{Type: fs.Pipe})
|
||||
d := fs.NewDirent(inode, "pipe")
|
||||
file, err := n.GetFile(ctx, d, flags)
|
||||
if resChan != nil {
|
||||
resChan <- openResult{file, err}
|
||||
}
|
||||
|
||||
@@ -71,11 +71,6 @@ type Pipe struct {
|
||||
// This value is immutable.
|
||||
atomicIOBytes int64
|
||||
|
||||
// The dirent backing this pipe. Shared by all readers and writers.
|
||||
//
|
||||
// This value is immutable.
|
||||
Dirent *fs.Dirent
|
||||
|
||||
// The number of active readers for this pipe.
|
||||
//
|
||||
// Access atomically.
|
||||
@@ -130,14 +125,20 @@ func NewPipe(ctx context.Context, isNamed bool, sizeBytes, atomicIOBytes int64)
|
||||
if atomicIOBytes > sizeBytes {
|
||||
atomicIOBytes = sizeBytes
|
||||
}
|
||||
p := &Pipe{
|
||||
return &Pipe{
|
||||
isNamed: isNamed,
|
||||
max: sizeBytes,
|
||||
atomicIOBytes: atomicIOBytes,
|
||||
}
|
||||
}
|
||||
|
||||
// Build the fs.Dirent of this pipe, shared by all fs.Files associated
|
||||
// with this pipe.
|
||||
// NewConnectedPipe initializes a pipe and returns a pair of objects
|
||||
// representing the read and write ends of the pipe.
|
||||
func NewConnectedPipe(ctx context.Context, sizeBytes, atomicIOBytes int64) (*fs.File, *fs.File) {
|
||||
p := NewPipe(ctx, false /* isNamed */, sizeBytes, atomicIOBytes)
|
||||
|
||||
// Build an fs.Dirent for the pipe which will be shared by both
|
||||
// returned files.
|
||||
perms := fs.FilePermissions{
|
||||
User: fs.PermMask{Read: true, Write: true},
|
||||
}
|
||||
@@ -150,36 +151,32 @@ func NewPipe(ctx context.Context, isNamed bool, sizeBytes, atomicIOBytes int64)
|
||||
BlockSize: int64(atomicIOBytes),
|
||||
}
|
||||
ms := fs.NewPseudoMountSource()
|
||||
p.Dirent = fs.NewDirent(fs.NewInode(iops, ms, sattr), fmt.Sprintf("pipe:[%d]", ino))
|
||||
return p
|
||||
}
|
||||
|
||||
// NewConnectedPipe initializes a pipe and returns a pair of objects
|
||||
// representing the read and write ends of the pipe.
|
||||
func NewConnectedPipe(ctx context.Context, sizeBytes, atomicIOBytes int64) (*fs.File, *fs.File) {
|
||||
p := NewPipe(ctx, false /* isNamed */, sizeBytes, atomicIOBytes)
|
||||
return p.Open(ctx, fs.FileFlags{Read: true}), p.Open(ctx, fs.FileFlags{Write: true})
|
||||
d := fs.NewDirent(fs.NewInode(iops, ms, sattr), fmt.Sprintf("pipe:[%d]", ino))
|
||||
// The p.Open calls below will each take a reference on the Dirent. We
|
||||
// must drop the one we already have.
|
||||
defer d.DecRef()
|
||||
return p.Open(ctx, d, fs.FileFlags{Read: true}), p.Open(ctx, d, fs.FileFlags{Write: true})
|
||||
}
|
||||
|
||||
// Open opens the pipe and returns a new file.
|
||||
//
|
||||
// Precondition: at least one of flags.Read or flags.Write must be set.
|
||||
func (p *Pipe) Open(ctx context.Context, flags fs.FileFlags) *fs.File {
|
||||
func (p *Pipe) Open(ctx context.Context, d *fs.Dirent, flags fs.FileFlags) *fs.File {
|
||||
switch {
|
||||
case flags.Read && flags.Write:
|
||||
p.rOpen()
|
||||
p.wOpen()
|
||||
return fs.NewFile(ctx, p.Dirent, flags, &ReaderWriter{
|
||||
return fs.NewFile(ctx, d, flags, &ReaderWriter{
|
||||
Pipe: p,
|
||||
})
|
||||
case flags.Read:
|
||||
p.rOpen()
|
||||
return fs.NewFile(ctx, p.Dirent, flags, &Reader{
|
||||
return fs.NewFile(ctx, d, flags, &Reader{
|
||||
ReaderWriter: ReaderWriter{Pipe: p},
|
||||
})
|
||||
case flags.Write:
|
||||
p.wOpen()
|
||||
return fs.NewFile(ctx, p.Dirent, flags, &Writer{
|
||||
return fs.NewFile(ctx, d, flags, &Writer{
|
||||
ReaderWriter: ReaderWriter{Pipe: p},
|
||||
})
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user