Move VFS2 file description status flags to vfs.FileDescription.

PiperOrigin-RevId: 286616668
This commit is contained in:
Jamie Liu
2019-12-20 11:53:48 -08:00
committed by gVisor bot
parent 822d847cca
commit 3eb489ed6c
9 changed files with 107 additions and 123 deletions
-19
View File
@@ -26,13 +26,6 @@ import (
type fileDescription struct {
vfsfd vfs.FileDescription
vfs.FileDescriptionDefaultImpl
// flags is the same as vfs.OpenOptions.Flags which are passed to
// vfs.FilesystemImpl.OpenAt.
// TODO(b/134676337): syscalls like read(2), write(2), fchmod(2), fchown(2),
// fgetxattr(2), ioctl(2), mmap(2) should fail with EBADF if O_PATH is set.
// Only close(2), fstat(2), fstatfs(2) should work.
flags uint32
}
func (fd *fileDescription) filesystem() *filesystem {
@@ -43,18 +36,6 @@ func (fd *fileDescription) inode() *inode {
return fd.vfsfd.Dentry().Impl().(*dentry).inode
}
// StatusFlags implements vfs.FileDescriptionImpl.StatusFlags.
func (fd *fileDescription) StatusFlags(ctx context.Context) (uint32, error) {
return fd.flags, nil
}
// SetStatusFlags implements vfs.FileDescriptionImpl.SetStatusFlags.
func (fd *fileDescription) SetStatusFlags(ctx context.Context, flags uint32) error {
// None of the flags settable by fcntl(F_SETFL) are supported, so this is a
// no-op.
return nil
}
// Stat implements vfs.FileDescriptionImpl.Stat.
func (fd *fileDescription) Stat(ctx context.Context, opts vfs.StatOptions) (linux.Statx, error) {
var stat linux.Statx
+3 -6
View File
@@ -157,10 +157,9 @@ func (in *inode) open(rp *vfs.ResolvingPath, vfsd *vfs.Dentry, flags uint32) (*v
switch in.impl.(type) {
case *regularFile:
var fd regularFileFD
fd.flags = flags
mnt.IncRef()
vfsd.IncRef()
fd.vfsfd.Init(&fd, mnt, vfsd)
fd.vfsfd.Init(&fd, flags, mnt, vfsd, &vfs.FileDescriptionOptions{})
return &fd.vfsfd, nil
case *directory:
// Can't open directories writably. This check is not necessary for a read
@@ -169,10 +168,9 @@ func (in *inode) open(rp *vfs.ResolvingPath, vfsd *vfs.Dentry, flags uint32) (*v
return nil, syserror.EISDIR
}
var fd directoryFD
fd.flags = flags
mnt.IncRef()
vfsd.IncRef()
fd.vfsfd.Init(&fd, mnt, vfsd)
fd.vfsfd.Init(&fd, flags, mnt, vfsd, &vfs.FileDescriptionOptions{})
return &fd.vfsfd, nil
case *symlink:
if flags&linux.O_PATH == 0 {
@@ -180,10 +178,9 @@ func (in *inode) open(rp *vfs.ResolvingPath, vfsd *vfs.Dentry, flags uint32) (*v
return nil, syserror.ELOOP
}
var fd symlinkFD
fd.flags = flags
mnt.IncRef()
vfsd.IncRef()
fd.vfsfd.Init(&fd, mnt, vfsd)
fd.vfsfd.Init(&fd, flags, mnt, vfsd, &vfs.FileDescriptionOptions{})
return &fd.vfsfd, nil
default:
panic(fmt.Sprintf("unknown inode type: %T", in.impl))
+1 -15
View File
@@ -65,17 +65,15 @@ type DynamicBytesFD struct {
vfsfd vfs.FileDescription
inode Inode
flags uint32
}
// Init initializes a DynamicBytesFD.
func (fd *DynamicBytesFD) Init(m *vfs.Mount, d *vfs.Dentry, data vfs.DynamicBytesSource, flags uint32) {
m.IncRef() // DecRef in vfs.FileDescription.vd.DecRef on final ref.
d.IncRef() // DecRef in vfs.FileDescription.vd.DecRef on final ref.
fd.flags = flags
fd.inode = d.Impl().(*Dentry).inode
fd.SetDataSource(data)
fd.vfsfd.Init(fd, m, d)
fd.vfsfd.Init(fd, flags, m, d, &vfs.FileDescriptionOptions{})
}
// Seek implements vfs.FileDescriptionImpl.Seek.
@@ -117,15 +115,3 @@ func (fd *DynamicBytesFD) SetStat(context.Context, vfs.SetStatOptions) error {
// DynamicBytesFiles are immutable.
return syserror.EPERM
}
// StatusFlags implements vfs.FileDescriptionImpl.StatusFlags.
func (fd *DynamicBytesFD) StatusFlags(ctx context.Context) (uint32, error) {
return fd.flags, nil
}
// SetStatusFlags implements vfs.FileDescriptionImpl.SetStatusFlags.
func (fd *DynamicBytesFD) SetStatusFlags(ctx context.Context, flags uint32) error {
// None of the flags settable by fcntl(F_SETFL) are supported, so this is a
// no-op.
return nil
}
+1 -15
View File
@@ -39,7 +39,6 @@ type GenericDirectoryFD struct {
vfsfd vfs.FileDescription
children *OrderedChildren
flags uint32
off int64
}
@@ -48,8 +47,7 @@ func (fd *GenericDirectoryFD) Init(m *vfs.Mount, d *vfs.Dentry, children *Ordere
m.IncRef() // DecRef in vfs.FileDescription.vd.DecRef on final ref.
d.IncRef() // DecRef in vfs.FileDescription.vd.DecRef on final ref.
fd.children = children
fd.flags = flags
fd.vfsfd.Init(fd, m, d)
fd.vfsfd.Init(fd, flags, m, d, &vfs.FileDescriptionOptions{})
}
// VFSFileDescription returns a pointer to the vfs.FileDescription representing
@@ -180,18 +178,6 @@ func (fd *GenericDirectoryFD) Seek(ctx context.Context, offset int64, whence int
return offset, nil
}
// StatusFlags implements vfs.FileDescriptionImpl.StatusFlags.
func (fd *GenericDirectoryFD) StatusFlags(ctx context.Context) (uint32, error) {
return fd.flags, nil
}
// SetStatusFlags implements vfs.FileDescriptionImpl.SetStatusFlags.
func (fd *GenericDirectoryFD) SetStatusFlags(ctx context.Context, flags uint32) error {
// None of the flags settable by fcntl(F_SETFL) are supported, so this is a
// no-op.
return nil
}
// Stat implements vfs.FileDescriptionImpl.Stat.
func (fd *GenericDirectoryFD) Stat(ctx context.Context, opts vfs.StatOptions) (linux.Statx, error) {
fs := fd.filesystem()
+4 -7
View File
@@ -282,9 +282,8 @@ func (fs *filesystem) MknodAt(ctx context.Context, rp *vfs.ResolvingPath, opts v
func (fs *filesystem) OpenAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
// Filter out flags that are not supported by memfs. O_DIRECTORY and
// O_NOFOLLOW have no effect here (they're handled by VFS by setting
// appropriate bits in rp), but are returned by
// FileDescriptionImpl.StatusFlags(). O_NONBLOCK is supported only by
// pipes.
// appropriate bits in rp), but are visible in FD status flags. O_NONBLOCK
// is supported only by pipes.
opts.Flags &= linux.O_ACCMODE | linux.O_CREAT | linux.O_EXCL | linux.O_TRUNC | linux.O_DIRECTORY | linux.O_NOFOLLOW | linux.O_NONBLOCK
if opts.Flags&linux.O_CREAT == 0 {
@@ -384,7 +383,6 @@ func (i *inode) open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentr
switch impl := i.impl.(type) {
case *regularFile:
var fd regularFileFD
fd.flags = flags
fd.readable = vfs.MayReadFileWithOpenFlags(flags)
fd.writable = vfs.MayWriteFileWithOpenFlags(flags)
if fd.writable {
@@ -395,7 +393,7 @@ func (i *inode) open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentr
}
mnt.IncRef()
vfsd.IncRef()
fd.vfsfd.Init(&fd, mnt, vfsd)
fd.vfsfd.Init(&fd, flags, mnt, vfsd, &vfs.FileDescriptionOptions{})
if flags&linux.O_TRUNC != 0 {
impl.mu.Lock()
impl.data = impl.data[:0]
@@ -411,8 +409,7 @@ func (i *inode) open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentr
var fd directoryFD
mnt.IncRef()
vfsd.IncRef()
fd.vfsfd.Init(&fd, mnt, vfsd)
fd.flags = flags
fd.vfsfd.Init(&fd, flags, mnt, vfsd, &vfs.FileDescriptionOptions{})
return &fd.vfsfd, nil
case *symlink:
// Can't open symlinks without O_PATH (which is unimplemented).
-14
View File
@@ -261,8 +261,6 @@ func (i *inode) direntType() uint8 {
type fileDescription struct {
vfsfd vfs.FileDescription
vfs.FileDescriptionDefaultImpl
flags uint32 // status flags; immutable
}
func (fd *fileDescription) filesystem() *filesystem {
@@ -273,18 +271,6 @@ func (fd *fileDescription) inode() *inode {
return fd.vfsfd.Dentry().Impl().(*dentry).inode
}
// StatusFlags implements vfs.FileDescriptionImpl.StatusFlags.
func (fd *fileDescription) StatusFlags(ctx context.Context) (uint32, error) {
return fd.flags, nil
}
// SetStatusFlags implements vfs.FileDescriptionImpl.SetStatusFlags.
func (fd *fileDescription) SetStatusFlags(ctx context.Context, flags uint32) error {
// None of the flags settable by fcntl(F_SETFL) are supported, so this is a
// no-op.
return nil
}
// Stat implements vfs.FileDescriptionImpl.Stat.
func (fd *fileDescription) Stat(ctx context.Context, opts vfs.StatOptions) (linux.Statx, error) {
var stat linux.Statx
+1 -1
View File
@@ -57,6 +57,6 @@ func newNamedPipeFD(ctx context.Context, np *namedPipe, rp *vfs.ResolvingPath, v
mnt := rp.Mount()
mnt.IncRef()
vfsd.IncRef()
fd.vfsfd.Init(&fd, mnt, vfsd)
fd.vfsfd.Init(&fd, flags, mnt, vfsd, &vfs.FileDescriptionOptions{})
return &fd.vfsfd, nil
}
+96 -45
View File
@@ -20,6 +20,7 @@ import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/context"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/memmap"
"gvisor.dev/gvisor/pkg/sentry/usermem"
"gvisor.dev/gvisor/pkg/syserror"
@@ -39,49 +40,43 @@ type FileDescription struct {
// operations.
refs int64
// statusFlags contains status flags, "initialized by open(2) and possibly
// modified by fcntl()" - fcntl(2). statusFlags is accessed using atomic
// memory operations.
statusFlags uint32
// vd is the filesystem location at which this FileDescription was opened.
// A reference is held on vd. vd is immutable.
vd VirtualDentry
opts FileDescriptionOptions
// impl is the FileDescriptionImpl associated with this Filesystem. impl is
// immutable. This should be the last field in FileDescription.
impl FileDescriptionImpl
}
// FileDescriptionOptions contains options to FileDescription.Init().
type FileDescriptionOptions struct {
// If AllowDirectIO is true, allow O_DIRECT to be set on the file. This is
// usually only the case if O_DIRECT would actually have an effect.
AllowDirectIO bool
}
// Init must be called before first use of fd. It takes ownership of references
// on mnt and d held by the caller.
func (fd *FileDescription) Init(impl FileDescriptionImpl, mnt *Mount, d *Dentry) {
// on mnt and d held by the caller. statusFlags is the initial file description
// status flags, which is usually the full set of flags passed to open(2).
func (fd *FileDescription) Init(impl FileDescriptionImpl, statusFlags uint32, mnt *Mount, d *Dentry, opts *FileDescriptionOptions) {
fd.refs = 1
fd.statusFlags = statusFlags | linux.O_LARGEFILE
fd.vd = VirtualDentry{
mount: mnt,
dentry: d,
}
fd.opts = *opts
fd.impl = impl
}
// Impl returns the FileDescriptionImpl associated with fd.
func (fd *FileDescription) Impl() FileDescriptionImpl {
return fd.impl
}
// Mount returns the mount on which fd was opened. It does not take a reference
// on the returned Mount.
func (fd *FileDescription) Mount() *Mount {
return fd.vd.mount
}
// Dentry returns the dentry at which fd was opened. It does not take a
// reference on the returned Dentry.
func (fd *FileDescription) Dentry() *Dentry {
return fd.vd.dentry
}
// VirtualDentry returns the location at which fd was opened. It does not take
// a reference on the returned VirtualDentry.
func (fd *FileDescription) VirtualDentry() VirtualDentry {
return fd.vd
}
// IncRef increments fd's reference count.
func (fd *FileDescription) IncRef() {
atomic.AddInt64(&fd.refs, 1)
@@ -113,6 +108,82 @@ func (fd *FileDescription) DecRef() {
}
}
// Mount returns the mount on which fd was opened. It does not take a reference
// on the returned Mount.
func (fd *FileDescription) Mount() *Mount {
return fd.vd.mount
}
// Dentry returns the dentry at which fd was opened. It does not take a
// reference on the returned Dentry.
func (fd *FileDescription) Dentry() *Dentry {
return fd.vd.dentry
}
// VirtualDentry returns the location at which fd was opened. It does not take
// a reference on the returned VirtualDentry.
func (fd *FileDescription) VirtualDentry() VirtualDentry {
return fd.vd
}
// StatusFlags returns file description status flags, as for fcntl(F_GETFL).
func (fd *FileDescription) StatusFlags() uint32 {
return atomic.LoadUint32(&fd.statusFlags)
}
// SetStatusFlags sets file description status flags, as for fcntl(F_SETFL).
func (fd *FileDescription) SetStatusFlags(ctx context.Context, creds *auth.Credentials, flags uint32) error {
// Compare Linux's fs/fcntl.c:setfl().
oldFlags := fd.StatusFlags()
// Linux documents this check as "O_APPEND cannot be cleared if the file is
// marked as append-only and the file is open for write", which would make
// sense. However, the check as actually implemented seems to be "O_APPEND
// cannot be changed if the file is marked as append-only".
if (flags^oldFlags)&linux.O_APPEND != 0 {
stat, err := fd.impl.Stat(ctx, StatOptions{
// There is no mask bit for stx_attributes.
Mask: 0,
// Linux just reads inode::i_flags directly.
Sync: linux.AT_STATX_DONT_SYNC,
})
if err != nil {
return err
}
if (stat.AttributesMask&linux.STATX_ATTR_APPEND != 0) && (stat.Attributes&linux.STATX_ATTR_APPEND != 0) {
return syserror.EPERM
}
}
if (flags&linux.O_NOATIME != 0) && (oldFlags&linux.O_NOATIME == 0) {
stat, err := fd.impl.Stat(ctx, StatOptions{
Mask: linux.STATX_UID,
// Linux's inode_owner_or_capable() just reads inode::i_uid
// directly.
Sync: linux.AT_STATX_DONT_SYNC,
})
if err != nil {
return err
}
if stat.Mask&linux.STATX_UID == 0 {
return syserror.EPERM
}
if !CanActAsOwner(creds, auth.KUID(stat.UID)) {
return syserror.EPERM
}
}
if flags&linux.O_DIRECT != 0 && !fd.opts.AllowDirectIO {
return syserror.EINVAL
}
// TODO(jamieliu): FileDescriptionImpl.SetOAsync()?
const settableFlags = linux.O_APPEND | linux.O_ASYNC | linux.O_DIRECT | linux.O_NOATIME | linux.O_NONBLOCK
atomic.StoreUint32(&fd.statusFlags, (oldFlags&^settableFlags)|(flags&settableFlags))
return nil
}
// Impl returns the FileDescriptionImpl associated with fd.
func (fd *FileDescription) Impl() FileDescriptionImpl {
return fd.impl
}
// FileDescriptionImpl contains implementation details for an FileDescription.
// Implementations of FileDescriptionImpl should contain their associated
// FileDescription by value as their first field.
@@ -132,14 +203,6 @@ type FileDescriptionImpl interface {
// prevent the file descriptor from being closed.
OnClose(ctx context.Context) error
// StatusFlags returns file description status flags, as for
// fcntl(F_GETFL).
StatusFlags(ctx context.Context) (uint32, error)
// SetStatusFlags sets file description status flags, as for
// fcntl(F_SETFL).
SetStatusFlags(ctx context.Context, flags uint32) error
// Stat returns metadata for the file represented by the FileDescription.
Stat(ctx context.Context, opts StatOptions) (linux.Statx, error)
@@ -264,18 +327,6 @@ func (fd *FileDescription) OnClose(ctx context.Context) error {
return fd.impl.OnClose(ctx)
}
// StatusFlags returns file description status flags, as for fcntl(F_GETFL).
func (fd *FileDescription) StatusFlags(ctx context.Context) (uint32, error) {
flags, err := fd.impl.StatusFlags(ctx)
flags |= linux.O_LARGEFILE
return flags, err
}
// SetStatusFlags sets file description status flags, as for fcntl(F_SETFL).
func (fd *FileDescription) SetStatusFlags(ctx context.Context, flags uint32) error {
return fd.impl.SetStatusFlags(ctx, flags)
}
// Stat returns metadata for the file represented by fd.
func (fd *FileDescription) Stat(ctx context.Context, opts StatOptions) (linux.Statx, error) {
return fd.impl.Stat(ctx, opts)
@@ -48,7 +48,7 @@ type genCountFD struct {
func newGenCountFD(mnt *Mount, vfsd *Dentry) *FileDescription {
var fd genCountFD
fd.vfsfd.Init(&fd, mnt, vfsd)
fd.vfsfd.Init(&fd, 0 /* statusFlags */, mnt, vfsd, &FileDescriptionOptions{})
fd.DynamicBytesFileDescriptionImpl.SetDataSource(&fd)
return &fd.vfsfd
}