mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Move VFS2 file description status flags to vfs.FileDescription.
PiperOrigin-RevId: 286616668
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user