mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Clarify seek behaviour for kernfs.GenericDirectoryFD.
- Remove comment about GenericDirectoryFD not being compatible with dynamic directories. It is currently being used to implement dynamic directories. - Try to handle SEEK_END better than setting the offset to infinity. SEEK_END is poorly defined for dynamic directories anyways, so at least try make it work correctly for the static entries. Updates #1193. PiperOrigin-RevId: 327890128
This commit is contained in:
committed by
gVisor bot
parent
5f33fdf37e
commit
0ea03f501b
@@ -185,7 +185,9 @@ func (i *rootInode) masterClose(t *Terminal) {
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (i *rootInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &i.OrderedChildren, &i.locks, &opts)
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &i.OrderedChildren, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndStaticEntries,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -220,7 +220,9 @@ func (fs *filesystem) newInode(creds *auth.Credentials, mode linux.FileMode) *ke
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (i *inode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &i.OrderedChildren, &i.locks, &opts)
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &i.OrderedChildren, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndStaticEntries,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
package kernfs
|
||||
|
||||
import (
|
||||
"math"
|
||||
"fmt"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
@@ -28,9 +28,25 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
|
||||
// SeekEndConfig describes the SEEK_END behaviour for FDs.
|
||||
type SeekEndConfig int
|
||||
|
||||
// Constants related to SEEK_END behaviour for FDs.
|
||||
const (
|
||||
// Consider the end of the file to be after the final static entry. This is
|
||||
// the default option.
|
||||
SeekEndStaticEntries = iota
|
||||
// Consider the end of the file to be at offset 0.
|
||||
SeekEndZero
|
||||
)
|
||||
|
||||
// GenericDirectoryFDOptions contains configuration for a GenericDirectoryFD.
|
||||
type GenericDirectoryFDOptions struct {
|
||||
SeekEnd SeekEndConfig
|
||||
}
|
||||
|
||||
// GenericDirectoryFD implements vfs.FileDescriptionImpl for a generic directory
|
||||
// inode that uses OrderChildren to track child nodes. GenericDirectoryFD is not
|
||||
// compatible with dynamic directories.
|
||||
// inode that uses OrderChildren to track child nodes.
|
||||
//
|
||||
// Note that GenericDirectoryFD holds a lock over OrderedChildren while calling
|
||||
// IterDirents callback. The IterDirents callback therefore cannot hash or
|
||||
@@ -45,6 +61,9 @@ type GenericDirectoryFD struct {
|
||||
vfs.DirectoryFileDescriptionDefaultImpl
|
||||
vfs.LockFD
|
||||
|
||||
// Immutable.
|
||||
seekEnd SeekEndConfig
|
||||
|
||||
vfsfd vfs.FileDescription
|
||||
children *OrderedChildren
|
||||
|
||||
@@ -57,9 +76,9 @@ type GenericDirectoryFD struct {
|
||||
|
||||
// NewGenericDirectoryFD creates a new GenericDirectoryFD and returns its
|
||||
// dentry.
|
||||
func NewGenericDirectoryFD(m *vfs.Mount, d *vfs.Dentry, children *OrderedChildren, locks *vfs.FileLocks, opts *vfs.OpenOptions) (*GenericDirectoryFD, error) {
|
||||
func NewGenericDirectoryFD(m *vfs.Mount, d *vfs.Dentry, children *OrderedChildren, locks *vfs.FileLocks, opts *vfs.OpenOptions, fdOpts GenericDirectoryFDOptions) (*GenericDirectoryFD, error) {
|
||||
fd := &GenericDirectoryFD{}
|
||||
if err := fd.Init(children, locks, opts); err != nil {
|
||||
if err := fd.Init(children, locks, opts, fdOpts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := fd.vfsfd.Init(fd, opts.Flags, m, d, &vfs.FileDescriptionOptions{}); err != nil {
|
||||
@@ -71,12 +90,13 @@ func NewGenericDirectoryFD(m *vfs.Mount, d *vfs.Dentry, children *OrderedChildre
|
||||
// Init initializes a GenericDirectoryFD. Use it when overriding
|
||||
// GenericDirectoryFD. Caller must call fd.VFSFileDescription.Init() with the
|
||||
// correct implementation.
|
||||
func (fd *GenericDirectoryFD) Init(children *OrderedChildren, locks *vfs.FileLocks, opts *vfs.OpenOptions) error {
|
||||
func (fd *GenericDirectoryFD) Init(children *OrderedChildren, locks *vfs.FileLocks, opts *vfs.OpenOptions, fdOpts GenericDirectoryFDOptions) error {
|
||||
if vfs.AccessTypesForOpenFlags(opts)&vfs.MayWrite != 0 {
|
||||
// Can't open directories for writing.
|
||||
return syserror.EISDIR
|
||||
}
|
||||
fd.LockFD.Init(locks)
|
||||
fd.seekEnd = fdOpts.SeekEnd
|
||||
fd.children = children
|
||||
return nil
|
||||
}
|
||||
@@ -209,9 +229,17 @@ func (fd *GenericDirectoryFD) Seek(ctx context.Context, offset int64, whence int
|
||||
case linux.SEEK_CUR:
|
||||
offset += fd.off
|
||||
case linux.SEEK_END:
|
||||
// TODO(gvisor.dev/issue/1193): This can prevent new files from showing up
|
||||
// if they are added after SEEK_END.
|
||||
offset = math.MaxInt64
|
||||
switch fd.seekEnd {
|
||||
case SeekEndStaticEntries:
|
||||
fd.children.mu.RLock()
|
||||
offset += int64(len(fd.children.set))
|
||||
offset += 2 // '.' and '..' aren't tracked in children.
|
||||
fd.children.mu.RUnlock()
|
||||
case SeekEndZero:
|
||||
// No-op: offset += 0.
|
||||
default:
|
||||
panic(fmt.Sprintf("Invalid GenericDirectoryFD.seekEnd = %v", fd.seekEnd))
|
||||
}
|
||||
default:
|
||||
return 0, syserror.EINVAL
|
||||
}
|
||||
|
||||
@@ -555,15 +555,16 @@ type StaticDirectory struct {
|
||||
InodeNoDynamicLookup
|
||||
OrderedChildren
|
||||
|
||||
locks vfs.FileLocks
|
||||
locks vfs.FileLocks
|
||||
fdOpts GenericDirectoryFDOptions
|
||||
}
|
||||
|
||||
var _ Inode = (*StaticDirectory)(nil)
|
||||
|
||||
// NewStaticDir creates a new static directory and returns its dentry.
|
||||
func NewStaticDir(creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, perm linux.FileMode, children map[string]*Dentry) *Dentry {
|
||||
func NewStaticDir(creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, perm linux.FileMode, children map[string]*Dentry, fdOpts GenericDirectoryFDOptions) *Dentry {
|
||||
inode := &StaticDirectory{}
|
||||
inode.Init(creds, devMajor, devMinor, ino, perm)
|
||||
inode.Init(creds, devMajor, devMinor, ino, perm, fdOpts)
|
||||
|
||||
dentry := &Dentry{}
|
||||
dentry.Init(inode)
|
||||
@@ -576,16 +577,17 @@ func NewStaticDir(creds *auth.Credentials, devMajor, devMinor uint32, ino uint64
|
||||
}
|
||||
|
||||
// Init initializes StaticDirectory.
|
||||
func (s *StaticDirectory) Init(creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, perm linux.FileMode) {
|
||||
func (s *StaticDirectory) Init(creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, perm linux.FileMode, fdOpts GenericDirectoryFDOptions) {
|
||||
if perm&^linux.PermissionsMask != 0 {
|
||||
panic(fmt.Sprintf("Only permission mask must be set: %x", perm&linux.PermissionsMask))
|
||||
}
|
||||
s.fdOpts = fdOpts
|
||||
s.InodeAttrs.Init(creds, devMajor, devMinor, ino, linux.ModeDirectory|perm)
|
||||
}
|
||||
|
||||
// Open implements kernfs.Inode.
|
||||
func (s *StaticDirectory) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := NewGenericDirectoryFD(rp.Mount(), vfsd, &s.OrderedChildren, &s.locks, &opts)
|
||||
fd, err := NewGenericDirectoryFD(rp.Mount(), vfsd, &s.OrderedChildren, &s.locks, &opts, s.fdOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -119,7 +119,9 @@ func (fs *filesystem) newReadonlyDir(creds *auth.Credentials, mode linux.FileMod
|
||||
}
|
||||
|
||||
func (d *readonlyDir) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &d.OrderedChildren, &d.locks, &opts)
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &d.OrderedChildren, &d.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndStaticEntries,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -151,7 +153,9 @@ func (fs *filesystem) newDir(creds *auth.Credentials, mode linux.FileMode, conte
|
||||
}
|
||||
|
||||
func (d *dir) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &d.OrderedChildren, &d.locks, &opts)
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &d.OrderedChildren, &d.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndStaticEntries,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -110,6 +110,12 @@ func newStaticFile(data string) *staticFile {
|
||||
return &staticFile{StaticData: vfs.StaticData{Data: data}}
|
||||
}
|
||||
|
||||
func newStaticDir(creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, perm linux.FileMode, children map[string]*kernfs.Dentry) *kernfs.Dentry {
|
||||
return kernfs.NewStaticDir(creds, devMajor, devMinor, ino, perm, children, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndZero,
|
||||
})
|
||||
}
|
||||
|
||||
// InternalData contains internal data passed in to the procfs mount via
|
||||
// vfs.GetFilesystemOptions.InternalData.
|
||||
type InternalData struct {
|
||||
|
||||
@@ -155,7 +155,9 @@ func (fd *subtasksFD) SetStat(ctx context.Context, opts vfs.SetStatOptions) erro
|
||||
// Open implements kernfs.Inode.
|
||||
func (i *subtasksInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd := &subtasksFD{task: i.task}
|
||||
if err := fd.Init(&i.OrderedChildren, &i.locks, &opts); err != nil {
|
||||
if err := fd.Init(&i.OrderedChildren, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndZero,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := fd.VFSFileDescription().Init(fd, opts.Flags, rp.Mount(), vfsd, &vfs.FileDescriptionOptions{}); err != nil {
|
||||
|
||||
@@ -105,7 +105,9 @@ func (i *taskInode) Valid(ctx context.Context) bool {
|
||||
|
||||
// Open implements kernfs.Inode.
|
||||
func (i *taskInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &i.OrderedChildren, &i.locks, &opts)
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &i.OrderedChildren, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndZero,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -142,7 +144,9 @@ func (fs *filesystem) newTaskOwnedDir(task *kernel.Task, ino uint64, perm linux.
|
||||
dir := &kernfs.StaticDirectory{}
|
||||
|
||||
// Note: credentials are overridden by taskOwnedInode.
|
||||
dir.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, perm)
|
||||
dir.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, perm, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndZero,
|
||||
})
|
||||
|
||||
inode := &taskOwnedInode{Inode: dir, owner: task}
|
||||
d := &kernfs.Dentry{}
|
||||
|
||||
@@ -144,7 +144,9 @@ func (i *fdDirInode) Lookup(ctx context.Context, name string) (*vfs.Dentry, erro
|
||||
|
||||
// Open implements kernfs.Inode.
|
||||
func (i *fdDirInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &i.OrderedChildren, &i.locks, &opts)
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &i.OrderedChildren, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndZero,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -271,7 +273,9 @@ func (i *fdInfoDirInode) Lookup(ctx context.Context, name string) (*vfs.Dentry,
|
||||
|
||||
// Open implements kernfs.Inode.
|
||||
func (i *fdInfoDirInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &i.OrderedChildren, &i.locks, &opts)
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &i.OrderedChildren, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndZero,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -199,7 +199,9 @@ func (i *tasksInode) IterDirents(ctx context.Context, cb vfs.IterDirentsCallback
|
||||
|
||||
// Open implements kernfs.Inode.
|
||||
func (i *tasksInode) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &i.OrderedChildren, &i.locks, &opts)
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &i.OrderedChildren, &i.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndZero,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -39,14 +39,14 @@ const (
|
||||
|
||||
// newSysDir returns the dentry corresponding to /proc/sys directory.
|
||||
func (fs *filesystem) newSysDir(root *auth.Credentials, k *kernel.Kernel) *kernfs.Dentry {
|
||||
return kernfs.NewStaticDir(root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, map[string]*kernfs.Dentry{
|
||||
"kernel": kernfs.NewStaticDir(root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, map[string]*kernfs.Dentry{
|
||||
return newStaticDir(root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, map[string]*kernfs.Dentry{
|
||||
"kernel": newStaticDir(root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, map[string]*kernfs.Dentry{
|
||||
"hostname": fs.newDentry(root, fs.NextIno(), 0444, &hostnameData{}),
|
||||
"shmall": fs.newDentry(root, fs.NextIno(), 0444, shmData(linux.SHMALL)),
|
||||
"shmmax": fs.newDentry(root, fs.NextIno(), 0444, shmData(linux.SHMMAX)),
|
||||
"shmmni": fs.newDentry(root, fs.NextIno(), 0444, shmData(linux.SHMMNI)),
|
||||
}),
|
||||
"vm": kernfs.NewStaticDir(root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, map[string]*kernfs.Dentry{
|
||||
"vm": newStaticDir(root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, map[string]*kernfs.Dentry{
|
||||
"mmap_min_addr": fs.newDentry(root, fs.NextIno(), 0444, &mmapMinAddrData{k: k}),
|
||||
"overcommit_memory": fs.newDentry(root, fs.NextIno(), 0444, newStaticFile("0\n")),
|
||||
}),
|
||||
@@ -62,7 +62,7 @@ func (fs *filesystem) newSysNetDir(root *auth.Credentials, k *kernel.Kernel) *ke
|
||||
// network namespace of the calling process.
|
||||
if stack := k.RootNetworkNamespace().Stack(); stack != nil {
|
||||
contents = map[string]*kernfs.Dentry{
|
||||
"ipv4": kernfs.NewStaticDir(root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, map[string]*kernfs.Dentry{
|
||||
"ipv4": newStaticDir(root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, map[string]*kernfs.Dentry{
|
||||
"tcp_recovery": fs.newDentry(root, fs.NextIno(), 0644, &tcpRecoveryData{stack: stack}),
|
||||
"tcp_rmem": fs.newDentry(root, fs.NextIno(), 0644, &tcpMemData{stack: stack, dir: tcpRMem}),
|
||||
"tcp_sack": fs.newDentry(root, fs.NextIno(), 0644, &tcpSackData{stack: stack}),
|
||||
@@ -109,7 +109,7 @@ func (fs *filesystem) newSysNetDir(root *auth.Credentials, k *kernel.Kernel) *ke
|
||||
"tcp_syn_retries": fs.newDentry(root, fs.NextIno(), 0444, newStaticFile("3")),
|
||||
"tcp_timestamps": fs.newDentry(root, fs.NextIno(), 0444, newStaticFile("1")),
|
||||
}),
|
||||
"core": kernfs.NewStaticDir(root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, map[string]*kernfs.Dentry{
|
||||
"core": newStaticDir(root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, map[string]*kernfs.Dentry{
|
||||
"default_qdisc": fs.newDentry(root, fs.NextIno(), 0444, newStaticFile("pfifo_fast")),
|
||||
"message_burst": fs.newDentry(root, fs.NextIno(), 0444, newStaticFile("10")),
|
||||
"message_cost": fs.newDentry(root, fs.NextIno(), 0444, newStaticFile("5")),
|
||||
@@ -123,7 +123,7 @@ func (fs *filesystem) newSysNetDir(root *auth.Credentials, k *kernel.Kernel) *ke
|
||||
}
|
||||
}
|
||||
|
||||
return kernfs.NewStaticDir(root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, contents)
|
||||
return newStaticDir(root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, contents)
|
||||
}
|
||||
|
||||
// mmapMinAddrData implements vfs.DynamicBytesSource for
|
||||
|
||||
@@ -131,7 +131,9 @@ func (*dir) SetStat(context.Context, *vfs.Filesystem, *auth.Credentials, vfs.Set
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (d *dir) Open(ctx context.Context, rp *vfs.ResolvingPath, vfsd *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &d.OrderedChildren, &d.locks, &opts)
|
||||
fd, err := kernfs.NewGenericDirectoryFD(rp.Mount(), vfsd, &d.OrderedChildren, &d.locks, &opts, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndStaticEntries,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user