mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Implement waiter.Waitable methods on VFS2 host inodes.
This fixes bash in Ubuntu. Updates #1672. PiperOrigin-RevId: 309298252
This commit is contained in:
committed by
gVisor bot
parent
c01e103256
commit
bae30a0c69
@@ -24,6 +24,7 @@ import (
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/fdnotifier"
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/pkg/refs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
|
||||
@@ -35,6 +36,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
|
||||
// filesystemType implements vfs.FilesystemType.
|
||||
@@ -88,11 +90,12 @@ func ImportFD(ctx context.Context, mnt *vfs.Mount, hostFD int, isTTY bool) (*vfs
|
||||
seekable := err != syserror.ESPIPE
|
||||
|
||||
i := &inode{
|
||||
hostFD: hostFD,
|
||||
seekable: seekable,
|
||||
isTTY: isTTY,
|
||||
canMap: canMap(uint32(fileType)),
|
||||
ino: fs.NextIno(),
|
||||
hostFD: hostFD,
|
||||
seekable: seekable,
|
||||
isTTY: isTTY,
|
||||
canMap: canMap(uint32(fileType)),
|
||||
wouldBlock: wouldBlock(uint32(fileType)),
|
||||
ino: fs.NextIno(),
|
||||
// For simplicity, set offset to 0. Technically, we should use the existing
|
||||
// offset on the host if the file is seekable.
|
||||
offset: 0,
|
||||
@@ -103,6 +106,17 @@ func ImportFD(ctx context.Context, mnt *vfs.Mount, hostFD int, isTTY bool) (*vfs
|
||||
panic("files that can return EWOULDBLOCK (sockets, pipes, etc.) cannot be memory mapped")
|
||||
}
|
||||
|
||||
// If the hostFD would block, we must set it to non-blocking and handle
|
||||
// blocking behavior in the sentry.
|
||||
if i.wouldBlock {
|
||||
if err := syscall.SetNonblock(i.hostFD, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := fdnotifier.AddFD(int32(i.hostFD), &i.queue); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
d := &kernfs.Dentry{}
|
||||
d.Init(i)
|
||||
// i.open will take a reference on d.
|
||||
@@ -125,6 +139,12 @@ type inode struct {
|
||||
// This field is initialized at creation time and is immutable.
|
||||
hostFD int
|
||||
|
||||
// wouldBlock is true if the host FD would return EWOULDBLOCK for
|
||||
// operations that would block.
|
||||
//
|
||||
// This field is initialized at creation time and is immutable.
|
||||
wouldBlock bool
|
||||
|
||||
// seekable is false if the host fd points to a file representing a stream,
|
||||
// e.g. a socket or a pipe. Such files are not seekable and can return
|
||||
// EWOULDBLOCK for I/O operations.
|
||||
@@ -152,6 +172,9 @@ type inode struct {
|
||||
|
||||
// offset specifies the current file offset.
|
||||
offset int64
|
||||
|
||||
// Event queue for blocking operations.
|
||||
queue waiter.Queue
|
||||
}
|
||||
|
||||
// Note that these flags may become out of date, since they can be modified
|
||||
@@ -354,6 +377,9 @@ func (i *inode) DecRef() {
|
||||
|
||||
// Destroy implements kernfs.Inode.
|
||||
func (i *inode) Destroy() {
|
||||
if i.wouldBlock {
|
||||
fdnotifier.RemoveFD(int32(i.hostFD))
|
||||
}
|
||||
if err := unix.Close(i.hostFD); err != nil {
|
||||
log.Warningf("failed to close host fd %d: %v", i.hostFD, err)
|
||||
}
|
||||
@@ -614,3 +640,20 @@ func (f *fileDescription) ConfigureMMap(_ context.Context, opts *memmap.MMapOpts
|
||||
// TODO(gvisor.dev/issue/1672): Implement ConfigureMMap and Mappable interface.
|
||||
return syserror.ENODEV
|
||||
}
|
||||
|
||||
// EventRegister implements waiter.Waitable.EventRegister.
|
||||
func (f *fileDescription) EventRegister(e *waiter.Entry, mask waiter.EventMask) {
|
||||
f.inode.queue.EventRegister(e, mask)
|
||||
fdnotifier.UpdateFD(int32(f.inode.hostFD))
|
||||
}
|
||||
|
||||
// EventUnregister implements waiter.Waitable.EventUnregister.
|
||||
func (f *fileDescription) EventUnregister(e *waiter.Entry) {
|
||||
f.inode.queue.EventUnregister(e)
|
||||
fdnotifier.UpdateFD(int32(f.inode.hostFD))
|
||||
}
|
||||
|
||||
// Readiness uses the poll() syscall to check the status of the underlying FD.
|
||||
func (f *fileDescription) Readiness(mask waiter.EventMask) waiter.EventMask {
|
||||
return fdnotifier.NonBlockingPoll(int32(f.inode.hostFD), mask)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user