Implement waiter.Waitable methods on VFS2 host inodes.

This fixes bash in Ubuntu.

Updates #1672.

PiperOrigin-RevId: 309298252
This commit is contained in:
Nicolas Lacasse
2020-04-30 14:19:45 -07:00
committed by gVisor bot
parent c01e103256
commit bae30a0c69
+48 -5
View File
@@ -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)
}