mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
[vfs] kernfs: Implement remaining InodeAttr fields.
Added the following fields in kernfs.InodeAttr: - blockSize - atime - mtime - ctime Also resolved all TODOs for #1193. Fixes #1193 PiperOrigin-RevId: 338714527
This commit is contained in:
@@ -60,7 +60,7 @@ func (fstype *FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Vir
|
||||
}
|
||||
|
||||
fstype.initOnce.Do(func() {
|
||||
fs, root, err := fstype.newFilesystem(vfsObj, creds)
|
||||
fs, root, err := fstype.newFilesystem(ctx, vfsObj, creds)
|
||||
if err != nil {
|
||||
fstype.initErr = err
|
||||
return
|
||||
@@ -93,7 +93,7 @@ type filesystem struct {
|
||||
|
||||
// newFilesystem creates a new devpts filesystem with root directory and ptmx
|
||||
// master inode. It returns the filesystem and root Dentry.
|
||||
func (fstype *FilesystemType) newFilesystem(vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials) (*filesystem, *kernfs.Dentry, error) {
|
||||
func (fstype *FilesystemType) newFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials) (*filesystem, *kernfs.Dentry, error) {
|
||||
devMinor, err := vfsObj.GetAnonBlockDevMinor()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -108,7 +108,7 @@ func (fstype *FilesystemType) newFilesystem(vfsObj *vfs.VirtualFilesystem, creds
|
||||
root := &rootInode{
|
||||
replicas: make(map[uint32]*replicaInode),
|
||||
}
|
||||
root.InodeAttrs.Init(creds, linux.UNNAMED_MAJOR, devMinor, 1, linux.ModeDirectory|0555)
|
||||
root.InodeAttrs.Init(ctx, creds, linux.UNNAMED_MAJOR, devMinor, 1, linux.ModeDirectory|0555)
|
||||
root.OrderedChildren.Init(kernfs.OrderedChildrenOptions{})
|
||||
root.EnableLeakCheck()
|
||||
|
||||
@@ -120,7 +120,7 @@ func (fstype *FilesystemType) newFilesystem(vfsObj *vfs.VirtualFilesystem, creds
|
||||
master := &masterInode{
|
||||
root: root,
|
||||
}
|
||||
master.InodeAttrs.Init(creds, linux.UNNAMED_MAJOR, devMinor, 2, linux.ModeCharacterDevice|0666)
|
||||
master.InodeAttrs.Init(ctx, creds, linux.UNNAMED_MAJOR, devMinor, 2, linux.ModeCharacterDevice|0666)
|
||||
|
||||
// Add the master as a child of the root.
|
||||
links := root.OrderedChildren.Populate(map[string]kernfs.Inode{
|
||||
@@ -170,7 +170,7 @@ type rootInode struct {
|
||||
var _ kernfs.Inode = (*rootInode)(nil)
|
||||
|
||||
// allocateTerminal creates a new Terminal and installs a pts node for it.
|
||||
func (i *rootInode) allocateTerminal(creds *auth.Credentials) (*Terminal, error) {
|
||||
func (i *rootInode) allocateTerminal(ctx context.Context, creds *auth.Credentials) (*Terminal, error) {
|
||||
i.mu.Lock()
|
||||
defer i.mu.Unlock()
|
||||
if i.nextIdx == math.MaxUint32 {
|
||||
@@ -192,7 +192,7 @@ func (i *rootInode) allocateTerminal(creds *auth.Credentials) (*Terminal, error)
|
||||
}
|
||||
// Linux always uses pty index + 3 as the inode id. See
|
||||
// fs/devpts/inode.c:devpts_pty_new().
|
||||
replica.InodeAttrs.Init(creds, i.InodeAttrs.DevMajor(), i.InodeAttrs.DevMinor(), uint64(idx+3), linux.ModeCharacterDevice|0600)
|
||||
replica.InodeAttrs.Init(ctx, creds, i.InodeAttrs.DevMajor(), i.InodeAttrs.DevMinor(), uint64(idx+3), linux.ModeCharacterDevice|0600)
|
||||
i.replicas[idx] = replica
|
||||
|
||||
return t, nil
|
||||
@@ -248,9 +248,10 @@ func (i *rootInode) Lookup(ctx context.Context, name string) (kernfs.Inode, erro
|
||||
}
|
||||
|
||||
// IterDirents implements kernfs.Inode.IterDirents.
|
||||
func (i *rootInode) IterDirents(ctx context.Context, cb vfs.IterDirentsCallback, offset, relOffset int64) (int64, error) {
|
||||
func (i *rootInode) IterDirents(ctx context.Context, mnt *vfs.Mount, cb vfs.IterDirentsCallback, offset, relOffset int64) (int64, error) {
|
||||
i.mu.Lock()
|
||||
defer i.mu.Unlock()
|
||||
i.InodeAttrs.TouchAtime(ctx, mnt)
|
||||
ids := make([]int, 0, len(i.replicas))
|
||||
for id := range i.replicas {
|
||||
ids = append(ids, int(id))
|
||||
|
||||
@@ -50,7 +50,7 @@ var _ kernfs.Inode = (*masterInode)(nil)
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
func (mi *masterInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
t, err := mi.root.allocateTerminal(rp.Credentials())
|
||||
t, err := mi.root.allocateTerminal(ctx, rp.Credentials())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ func (fsType FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
||||
}
|
||||
|
||||
// root is the fusefs root directory.
|
||||
root := fs.newRootInode(creds, fsopts.rootMode)
|
||||
root := fs.newRootInode(ctx, creds, fsopts.rootMode)
|
||||
|
||||
return fs.VFSFilesystem(), root.VFSDentry(), nil
|
||||
}
|
||||
@@ -284,9 +284,9 @@ type inode struct {
|
||||
link string
|
||||
}
|
||||
|
||||
func (fs *filesystem) newRootInode(creds *auth.Credentials, mode linux.FileMode) *kernfs.Dentry {
|
||||
func (fs *filesystem) newRootInode(ctx context.Context, creds *auth.Credentials, mode linux.FileMode) *kernfs.Dentry {
|
||||
i := &inode{fs: fs, nodeID: 1}
|
||||
i.InodeAttrs.Init(creds, linux.UNNAMED_MAJOR, fs.devMinor, 1, linux.ModeDirectory|0755)
|
||||
i.InodeAttrs.Init(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, 1, linux.ModeDirectory|0755)
|
||||
i.OrderedChildren.Init(kernfs.OrderedChildrenOptions{})
|
||||
i.EnableLeakCheck()
|
||||
|
||||
@@ -295,10 +295,10 @@ func (fs *filesystem) newRootInode(creds *auth.Credentials, mode linux.FileMode)
|
||||
return &d
|
||||
}
|
||||
|
||||
func (fs *filesystem) newInode(nodeID uint64, attr linux.FUSEAttr) kernfs.Inode {
|
||||
func (fs *filesystem) newInode(ctx context.Context, nodeID uint64, attr linux.FUSEAttr) kernfs.Inode {
|
||||
i := &inode{fs: fs, nodeID: nodeID}
|
||||
creds := auth.Credentials{EffectiveKGID: auth.KGID(attr.UID), EffectiveKUID: auth.KUID(attr.UID)}
|
||||
i.InodeAttrs.Init(&creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.FileMode(attr.Mode))
|
||||
i.InodeAttrs.Init(ctx, &creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.FileMode(attr.Mode))
|
||||
atomic.StoreUint64(&i.size, attr.Size)
|
||||
i.OrderedChildren.Init(kernfs.OrderedChildrenOptions{})
|
||||
i.EnableLeakCheck()
|
||||
@@ -424,7 +424,7 @@ func (i *inode) Keep() bool {
|
||||
}
|
||||
|
||||
// IterDirents implements kernfs.Inode.IterDirents.
|
||||
func (*inode) IterDirents(ctx context.Context, callback vfs.IterDirentsCallback, offset, relOffset int64) (int64, error) {
|
||||
func (*inode) IterDirents(ctx context.Context, mnt *vfs.Mount, callback vfs.IterDirentsCallback, offset, relOffset int64) (int64, error) {
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
@@ -544,7 +544,7 @@ func (i *inode) newEntry(ctx context.Context, name string, fileType linux.FileMo
|
||||
if opcode != linux.FUSE_LOOKUP && ((out.Attr.Mode&linux.S_IFMT)^uint32(fileType) != 0 || out.NodeID == 0 || out.NodeID == linux.FUSE_ROOT_ID) {
|
||||
return nil, syserror.EIO
|
||||
}
|
||||
child := i.fs.newInode(out.NodeID, out.Attr)
|
||||
child := i.fs.newInode(ctx, out.NodeID, out.Attr)
|
||||
return child, nil
|
||||
}
|
||||
|
||||
@@ -696,7 +696,7 @@ func (i *inode) getAttr(ctx context.Context, fs *vfs.Filesystem, opts vfs.StatOp
|
||||
}
|
||||
|
||||
// Set the metadata of kernfs.InodeAttrs.
|
||||
if err := i.SetInodeStat(ctx, fs, creds, vfs.SetStatOptions{
|
||||
if err := i.InodeAttrs.SetStat(ctx, fs, creds, vfs.SetStatOptions{
|
||||
Stat: statFromFUSEAttr(out.Attr, linux.STATX_ALL, i.fs.devMinor),
|
||||
}); err != nil {
|
||||
return linux.FUSEAttr{}, err
|
||||
@@ -812,7 +812,7 @@ func (i *inode) setAttr(ctx context.Context, fs *vfs.Filesystem, creds *auth.Cre
|
||||
}
|
||||
|
||||
// Set the metadata of kernfs.InodeAttrs.
|
||||
if err := i.SetInodeStat(ctx, fs, creds, vfs.SetStatOptions{
|
||||
if err := i.InodeAttrs.SetStat(ctx, fs, creds, vfs.SetStatOptions{
|
||||
Stat: statFromFUSEAttr(out.Attr, linux.STATX_ALL, i.fs.devMinor),
|
||||
}); err != nil {
|
||||
return err
|
||||
|
||||
@@ -132,7 +132,7 @@ func (fs *filesystem) ReadCallback(ctx context.Context, fd *regularFileFD, off u
|
||||
// May need to update the signature.
|
||||
|
||||
i := fd.inode()
|
||||
// TODO(gvisor.dev/issue/1193): Invalidate or update atime.
|
||||
i.InodeAttrs.TouchAtime(ctx, fd.vfsfd.Mount())
|
||||
|
||||
// Reached EOF.
|
||||
if sizeRead < size {
|
||||
@@ -179,6 +179,7 @@ func (fs *filesystem) Write(ctx context.Context, fd *regularFileFD, off uint64,
|
||||
Flags: fd.statusFlags(),
|
||||
}
|
||||
|
||||
inode := fd.inode()
|
||||
var written uint32
|
||||
|
||||
// This loop is intended for fragmented write where the bytes to write is
|
||||
@@ -203,7 +204,7 @@ func (fs *filesystem) Write(ctx context.Context, fd *regularFileFD, off uint64,
|
||||
in.Offset = off + uint64(written)
|
||||
in.Size = toWrite
|
||||
|
||||
req, err := fs.conn.NewRequest(auth.CredentialsFromContext(ctx), uint32(t.ThreadID()), fd.inode().nodeID, linux.FUSE_WRITE, &in)
|
||||
req, err := fs.conn.NewRequest(auth.CredentialsFromContext(ctx), uint32(t.ThreadID()), inode.nodeID, linux.FUSE_WRITE, &in)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -237,6 +238,7 @@ func (fs *filesystem) Write(ctx context.Context, fd *regularFileFD, off uint64,
|
||||
break
|
||||
}
|
||||
}
|
||||
inode.InodeAttrs.TouchCMtime(ctx)
|
||||
|
||||
return written, nil
|
||||
}
|
||||
|
||||
@@ -916,10 +916,10 @@ func (d *dentry) statTo(stat *linux.Statx) {
|
||||
// This is consistent with regularFileFD.Seek(), which treats regular files
|
||||
// as having no holes.
|
||||
stat.Blocks = (stat.Size + 511) / 512
|
||||
stat.Atime = statxTimestampFromDentry(atomic.LoadInt64(&d.atime))
|
||||
stat.Btime = statxTimestampFromDentry(atomic.LoadInt64(&d.btime))
|
||||
stat.Ctime = statxTimestampFromDentry(atomic.LoadInt64(&d.ctime))
|
||||
stat.Mtime = statxTimestampFromDentry(atomic.LoadInt64(&d.mtime))
|
||||
stat.Atime = linux.NsecToStatxTimestamp(atomic.LoadInt64(&d.atime))
|
||||
stat.Btime = linux.NsecToStatxTimestamp(atomic.LoadInt64(&d.btime))
|
||||
stat.Ctime = linux.NsecToStatxTimestamp(atomic.LoadInt64(&d.ctime))
|
||||
stat.Mtime = linux.NsecToStatxTimestamp(atomic.LoadInt64(&d.mtime))
|
||||
stat.DevMajor = linux.UNNAMED_MAJOR
|
||||
stat.DevMinor = d.fs.devMinor
|
||||
}
|
||||
@@ -967,10 +967,10 @@ func (d *dentry) setStat(ctx context.Context, creds *auth.Credentials, opts *vfs
|
||||
// Use client clocks for timestamps.
|
||||
now = d.fs.clock.Now().Nanoseconds()
|
||||
if stat.Mask&linux.STATX_ATIME != 0 && stat.Atime.Nsec == linux.UTIME_NOW {
|
||||
stat.Atime = statxTimestampFromDentry(now)
|
||||
stat.Atime = linux.NsecToStatxTimestamp(now)
|
||||
}
|
||||
if stat.Mask&linux.STATX_MTIME != 0 && stat.Mtime.Nsec == linux.UTIME_NOW {
|
||||
stat.Mtime = statxTimestampFromDentry(now)
|
||||
stat.Mtime = linux.NsecToStatxTimestamp(now)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1029,11 +1029,11 @@ func (d *dentry) setStat(ctx context.Context, creds *auth.Credentials, opts *vfs
|
||||
// !d.cachedMetadataAuthoritative() then we returned after calling
|
||||
// d.file.setAttr(). For the same reason, now must have been initialized.
|
||||
if stat.Mask&linux.STATX_ATIME != 0 {
|
||||
atomic.StoreInt64(&d.atime, dentryTimestampFromStatx(stat.Atime))
|
||||
atomic.StoreInt64(&d.atime, stat.Atime.ToNsec())
|
||||
atomic.StoreUint32(&d.atimeDirty, 0)
|
||||
}
|
||||
if stat.Mask&linux.STATX_MTIME != 0 {
|
||||
atomic.StoreInt64(&d.mtime, dentryTimestampFromStatx(stat.Mtime))
|
||||
atomic.StoreInt64(&d.mtime, stat.Mtime.ToNsec())
|
||||
atomic.StoreUint32(&d.mtimeDirty, 0)
|
||||
}
|
||||
atomic.StoreInt64(&d.ctime, now)
|
||||
|
||||
@@ -17,7 +17,6 @@ package gofer
|
||||
import (
|
||||
"sync/atomic"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
)
|
||||
|
||||
@@ -25,17 +24,6 @@ func dentryTimestampFromP9(s, ns uint64) int64 {
|
||||
return int64(s*1e9 + ns)
|
||||
}
|
||||
|
||||
func dentryTimestampFromStatx(ts linux.StatxTimestamp) int64 {
|
||||
return ts.Sec*1e9 + int64(ts.Nsec)
|
||||
}
|
||||
|
||||
func statxTimestampFromDentry(ns int64) linux.StatxTimestamp {
|
||||
return linux.StatxTimestamp{
|
||||
Sec: ns / 1e9,
|
||||
Nsec: uint32(ns % 1e9),
|
||||
}
|
||||
}
|
||||
|
||||
// Preconditions: d.cachedMetadataAuthoritative() == true.
|
||||
func (d *dentry) touchAtime(mnt *vfs.Mount) {
|
||||
if mnt.Flags.NoATime || mnt.ReadOnly() {
|
||||
|
||||
@@ -107,6 +107,7 @@ go_library(
|
||||
"//pkg/refsvfs2",
|
||||
"//pkg/sentry/fs/lock",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sentry/kernel/time",
|
||||
"//pkg/sentry/memmap",
|
||||
"//pkg/sentry/socket/unix/transport",
|
||||
"//pkg/sentry/vfs",
|
||||
|
||||
@@ -47,11 +47,11 @@ type DynamicBytesFile struct {
|
||||
var _ Inode = (*DynamicBytesFile)(nil)
|
||||
|
||||
// Init initializes a dynamic bytes file.
|
||||
func (f *DynamicBytesFile) Init(creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, data vfs.DynamicBytesSource, perm linux.FileMode) {
|
||||
func (f *DynamicBytesFile) Init(ctx context.Context, creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, data vfs.DynamicBytesSource, perm linux.FileMode) {
|
||||
if perm&^linux.PermissionsMask != 0 {
|
||||
panic(fmt.Sprintf("Only permission mask must be set: %x", perm&linux.PermissionsMask))
|
||||
}
|
||||
f.InodeAttrs.Init(creds, devMajor, devMinor, ino, linux.ModeRegular|perm)
|
||||
f.InodeAttrs.Init(ctx, creds, devMajor, devMinor, ino, linux.ModeRegular|perm)
|
||||
f.data = data
|
||||
}
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ func (fd *GenericDirectoryFD) IterDirents(ctx context.Context, cb vfs.IterDirent
|
||||
|
||||
var err error
|
||||
relOffset := fd.off - int64(len(fd.children.set)) - 2
|
||||
fd.off, err = fd.inode().IterDirents(ctx, cb, fd.off, relOffset)
|
||||
fd.off, err = fd.inode().IterDirents(ctx, fd.vfsfd.Mount(), cb, fd.off, relOffset)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -373,7 +373,7 @@ func (fs *Filesystem) MkdirAt(ctx context.Context, rp *vfs.ResolvingPath, opts v
|
||||
if !opts.ForSyntheticMountpoint || err == syserror.EEXIST {
|
||||
return err
|
||||
}
|
||||
childI = newSyntheticDirectory(rp.Credentials(), opts.Mode)
|
||||
childI = newSyntheticDirectory(ctx, rp.Credentials(), opts.Mode)
|
||||
}
|
||||
var child Dentry
|
||||
child.Init(fs, childI)
|
||||
@@ -517,9 +517,6 @@ afterTrailingSymlink:
|
||||
}
|
||||
var child Dentry
|
||||
child.Init(fs, childI)
|
||||
// FIXME(gvisor.dev/issue/1193): Race between checking existence with
|
||||
// fs.stepExistingLocked and parent.insertChild. If possible, we should hold
|
||||
// dirMu from one to the other.
|
||||
parent.insertChild(pc, &child)
|
||||
// Open may block so we need to unlock fs.mu. IncRef child to prevent
|
||||
// its destruction while fs.mu is unlocked.
|
||||
|
||||
@@ -21,9 +21,11 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
|
||||
// InodeNoopRefCount partially implements the Inode interface, specifically the
|
||||
@@ -143,7 +145,7 @@ func (InodeNotDirectory) Lookup(ctx context.Context, name string) (Inode, error)
|
||||
}
|
||||
|
||||
// IterDirents implements Inode.IterDirents.
|
||||
func (InodeNotDirectory) IterDirents(ctx context.Context, callback vfs.IterDirentsCallback, offset, relOffset int64) (newOffset int64, err error) {
|
||||
func (InodeNotDirectory) IterDirents(ctx context.Context, mnt *vfs.Mount, callback vfs.IterDirentsCallback, offset, relOffset int64) (newOffset int64, err error) {
|
||||
panic("IterDirents called on non-directory inode")
|
||||
}
|
||||
|
||||
@@ -172,17 +174,23 @@ func (InodeNotSymlink) Getlink(context.Context, *vfs.Mount) (vfs.VirtualDentry,
|
||||
//
|
||||
// +stateify savable
|
||||
type InodeAttrs struct {
|
||||
devMajor uint32
|
||||
devMinor uint32
|
||||
ino uint64
|
||||
mode uint32
|
||||
uid uint32
|
||||
gid uint32
|
||||
nlink uint32
|
||||
devMajor uint32
|
||||
devMinor uint32
|
||||
ino uint64
|
||||
mode uint32
|
||||
uid uint32
|
||||
gid uint32
|
||||
nlink uint32
|
||||
blockSize uint32
|
||||
|
||||
// Timestamps, all nsecs from the Unix epoch.
|
||||
atime int64
|
||||
mtime int64
|
||||
ctime int64
|
||||
}
|
||||
|
||||
// Init initializes this InodeAttrs.
|
||||
func (a *InodeAttrs) Init(creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, mode linux.FileMode) {
|
||||
func (a *InodeAttrs) Init(ctx context.Context, creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, mode linux.FileMode) {
|
||||
if mode.FileType() == 0 {
|
||||
panic(fmt.Sprintf("No file type specified in 'mode' for InodeAttrs.Init(): mode=0%o", mode))
|
||||
}
|
||||
@@ -198,6 +206,11 @@ func (a *InodeAttrs) Init(creds *auth.Credentials, devMajor, devMinor uint32, in
|
||||
atomic.StoreUint32(&a.uid, uint32(creds.EffectiveKUID))
|
||||
atomic.StoreUint32(&a.gid, uint32(creds.EffectiveKGID))
|
||||
atomic.StoreUint32(&a.nlink, nlink)
|
||||
atomic.StoreUint32(&a.blockSize, usermem.PageSize)
|
||||
now := ktime.NowFromContext(ctx).Nanoseconds()
|
||||
atomic.StoreInt64(&a.atime, now)
|
||||
atomic.StoreInt64(&a.mtime, now)
|
||||
atomic.StoreInt64(&a.ctime, now)
|
||||
}
|
||||
|
||||
// DevMajor returns the device major number.
|
||||
@@ -220,12 +233,33 @@ func (a *InodeAttrs) Mode() linux.FileMode {
|
||||
return linux.FileMode(atomic.LoadUint32(&a.mode))
|
||||
}
|
||||
|
||||
// TouchAtime updates a.atime to the current time.
|
||||
func (a *InodeAttrs) TouchAtime(ctx context.Context, mnt *vfs.Mount) {
|
||||
if mnt.Flags.NoATime || mnt.ReadOnly() {
|
||||
return
|
||||
}
|
||||
if err := mnt.CheckBeginWrite(); err != nil {
|
||||
return
|
||||
}
|
||||
atomic.StoreInt64(&a.atime, ktime.NowFromContext(ctx).Nanoseconds())
|
||||
mnt.EndWrite()
|
||||
}
|
||||
|
||||
// TouchCMtime updates a.{c/m}time to the current time. The caller should
|
||||
// synchronize calls to this so that ctime and mtime are updated to the same
|
||||
// value.
|
||||
func (a *InodeAttrs) TouchCMtime(ctx context.Context) {
|
||||
now := ktime.NowFromContext(ctx).Nanoseconds()
|
||||
atomic.StoreInt64(&a.mtime, now)
|
||||
atomic.StoreInt64(&a.ctime, now)
|
||||
}
|
||||
|
||||
// Stat partially implements Inode.Stat. Note that this function doesn't provide
|
||||
// all the stat fields, and the embedder should consider extending the result
|
||||
// with filesystem-specific fields.
|
||||
func (a *InodeAttrs) Stat(context.Context, *vfs.Filesystem, vfs.StatOptions) (linux.Statx, error) {
|
||||
var stat linux.Statx
|
||||
stat.Mask = linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_UID | linux.STATX_GID | linux.STATX_INO | linux.STATX_NLINK
|
||||
stat.Mask = linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_UID | linux.STATX_GID | linux.STATX_INO | linux.STATX_NLINK | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME
|
||||
stat.DevMajor = a.devMajor
|
||||
stat.DevMinor = a.devMinor
|
||||
stat.Ino = atomic.LoadUint64(&a.ino)
|
||||
@@ -233,21 +267,15 @@ func (a *InodeAttrs) Stat(context.Context, *vfs.Filesystem, vfs.StatOptions) (li
|
||||
stat.UID = atomic.LoadUint32(&a.uid)
|
||||
stat.GID = atomic.LoadUint32(&a.gid)
|
||||
stat.Nlink = atomic.LoadUint32(&a.nlink)
|
||||
|
||||
// TODO(gvisor.dev/issue/1193): Implement other stat fields like timestamps.
|
||||
|
||||
stat.Blksize = atomic.LoadUint32(&a.blockSize)
|
||||
stat.Atime = linux.NsecToStatxTimestamp(atomic.LoadInt64(&a.atime))
|
||||
stat.Mtime = linux.NsecToStatxTimestamp(atomic.LoadInt64(&a.mtime))
|
||||
stat.Ctime = linux.NsecToStatxTimestamp(atomic.LoadInt64(&a.ctime))
|
||||
return stat, nil
|
||||
}
|
||||
|
||||
// SetStat implements Inode.SetStat.
|
||||
func (a *InodeAttrs) SetStat(ctx context.Context, fs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error {
|
||||
return a.SetInodeStat(ctx, fs, creds, opts)
|
||||
}
|
||||
|
||||
// SetInodeStat sets the corresponding attributes from opts to InodeAttrs.
|
||||
// This function can be used by other kernfs-based filesystem implementation to
|
||||
// sets the unexported attributes into InodeAttrs.
|
||||
func (a *InodeAttrs) SetInodeStat(ctx context.Context, fs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error {
|
||||
if opts.Stat.Mask == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -256,9 +284,7 @@ func (a *InodeAttrs) SetInodeStat(ctx context.Context, fs *vfs.Filesystem, creds
|
||||
// inode numbers are immutable after node creation. Setting the size is often
|
||||
// allowed by kernfs files but does not do anything. If some other behavior is
|
||||
// needed, the embedder should consider extending SetStat.
|
||||
//
|
||||
// TODO(gvisor.dev/issue/1193): Implement other stat fields like timestamps.
|
||||
if opts.Stat.Mask&^(linux.STATX_MODE|linux.STATX_UID|linux.STATX_GID|linux.STATX_SIZE) != 0 {
|
||||
if opts.Stat.Mask&^(linux.STATX_MODE|linux.STATX_UID|linux.STATX_GID|linux.STATX_ATIME|linux.STATX_MTIME|linux.STATX_SIZE) != 0 {
|
||||
return syserror.EPERM
|
||||
}
|
||||
if opts.Stat.Mask&linux.STATX_SIZE != 0 && a.Mode().IsDir() {
|
||||
@@ -286,6 +312,20 @@ func (a *InodeAttrs) SetInodeStat(ctx context.Context, fs *vfs.Filesystem, creds
|
||||
atomic.StoreUint32(&a.gid, stat.GID)
|
||||
}
|
||||
|
||||
now := ktime.NowFromContext(ctx).Nanoseconds()
|
||||
if stat.Mask&linux.STATX_ATIME != 0 {
|
||||
if stat.Atime.Nsec == linux.UTIME_NOW {
|
||||
stat.Atime = linux.NsecToStatxTimestamp(now)
|
||||
}
|
||||
atomic.StoreInt64(&a.atime, stat.Atime.ToNsec())
|
||||
}
|
||||
if stat.Mask&linux.STATX_MTIME != 0 {
|
||||
if stat.Mtime.Nsec == linux.UTIME_NOW {
|
||||
stat.Mtime = linux.NsecToStatxTimestamp(now)
|
||||
}
|
||||
atomic.StoreInt64(&a.mtime, stat.Mtime.ToNsec())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -421,7 +461,7 @@ func (o *OrderedChildren) Lookup(ctx context.Context, name string) (Inode, error
|
||||
}
|
||||
|
||||
// IterDirents implements Inode.IterDirents.
|
||||
func (o *OrderedChildren) IterDirents(ctx context.Context, cb vfs.IterDirentsCallback, offset, relOffset int64) (newOffset int64, err error) {
|
||||
func (o *OrderedChildren) IterDirents(ctx context.Context, mnt *vfs.Mount, cb vfs.IterDirentsCallback, offset, relOffset int64) (newOffset int64, err error) {
|
||||
// All entries from OrderedChildren have already been handled in
|
||||
// GenericDirectoryFD.IterDirents.
|
||||
return offset, nil
|
||||
@@ -619,9 +659,9 @@ type StaticDirectory struct {
|
||||
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]Inode, fdOpts GenericDirectoryFDOptions) Inode {
|
||||
func NewStaticDir(ctx context.Context, creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, perm linux.FileMode, children map[string]Inode, fdOpts GenericDirectoryFDOptions) Inode {
|
||||
inode := &StaticDirectory{}
|
||||
inode.Init(creds, devMajor, devMinor, ino, perm, fdOpts)
|
||||
inode.Init(ctx, creds, devMajor, devMinor, ino, perm, fdOpts)
|
||||
inode.EnableLeakCheck()
|
||||
|
||||
inode.OrderedChildren.Init(OrderedChildrenOptions{})
|
||||
@@ -632,12 +672,12 @@ 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, fdOpts GenericDirectoryFDOptions) {
|
||||
func (s *StaticDirectory) Init(ctx context.Context, 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)
|
||||
s.InodeAttrs.Init(ctx, creds, devMajor, devMinor, ino, linux.ModeDirectory|perm)
|
||||
}
|
||||
|
||||
// Open implements Inode.Open.
|
||||
|
||||
@@ -267,7 +267,9 @@ func (d *Dentry) OnZeroWatches(context.Context) {}
|
||||
// this dentry. This does not update the directory inode, so calling this on its
|
||||
// own isn't sufficient to insert a child into a directory.
|
||||
//
|
||||
// Precondition: d must represent a directory inode.
|
||||
// Preconditions:
|
||||
// * d must represent a directory inode.
|
||||
// * d.fs.mu must be locked for at least reading.
|
||||
func (d *Dentry) insertChild(name string, child *Dentry) {
|
||||
d.dirMu.Lock()
|
||||
d.insertChildLocked(name, child)
|
||||
@@ -280,6 +282,7 @@ func (d *Dentry) insertChild(name string, child *Dentry) {
|
||||
// Preconditions:
|
||||
// * d must represent a directory inode.
|
||||
// * d.dirMu must be locked.
|
||||
// * d.fs.mu must be locked for at least reading.
|
||||
func (d *Dentry) insertChildLocked(name string, child *Dentry) {
|
||||
if !d.isDir() {
|
||||
panic(fmt.Sprintf("insertChildLocked called on non-directory Dentry: %+v.", d))
|
||||
@@ -436,7 +439,7 @@ type inodeDirectory interface {
|
||||
// the inode is a directory.
|
||||
//
|
||||
// The child returned by Lookup will be hashed into the VFS dentry tree,
|
||||
// atleast for the duration of the current FS operation.
|
||||
// at least for the duration of the current FS operation.
|
||||
//
|
||||
// Lookup must return the child with an extra reference whose ownership is
|
||||
// transferred to the dentry that is created to point to that inode. If
|
||||
@@ -454,7 +457,7 @@ type inodeDirectory interface {
|
||||
// inside the entries returned by this IterDirents invocation. In other words,
|
||||
// 'offset' should be used to calculate each vfs.Dirent.NextOff as well as
|
||||
// the return value, while 'relOffset' is the place to start iteration.
|
||||
IterDirents(ctx context.Context, callback vfs.IterDirentsCallback, offset, relOffset int64) (newOffset int64, err error)
|
||||
IterDirents(ctx context.Context, mnt *vfs.Mount, callback vfs.IterDirentsCallback, offset, relOffset int64) (newOffset int64, err error)
|
||||
}
|
||||
|
||||
type inodeSymlink interface {
|
||||
|
||||
@@ -36,7 +36,7 @@ const staticFileContent = "This is sample content for a static test file."
|
||||
|
||||
// RootDentryFn is a generator function for creating the root dentry of a test
|
||||
// filesystem. See newTestSystem.
|
||||
type RootDentryFn func(*auth.Credentials, *filesystem) kernfs.Inode
|
||||
type RootDentryFn func(context.Context, *auth.Credentials, *filesystem) kernfs.Inode
|
||||
|
||||
// newTestSystem sets up a minimal environment for running a test, including an
|
||||
// instance of a test filesystem. Tests can control the contents of the
|
||||
@@ -72,10 +72,10 @@ type file struct {
|
||||
content string
|
||||
}
|
||||
|
||||
func (fs *filesystem) newFile(creds *auth.Credentials, content string) kernfs.Inode {
|
||||
func (fs *filesystem) newFile(ctx context.Context, creds *auth.Credentials, content string) kernfs.Inode {
|
||||
f := &file{}
|
||||
f.content = content
|
||||
f.DynamicBytesFile.Init(creds, 0 /* devMajor */, 0 /* devMinor */, fs.NextIno(), f, 0777)
|
||||
f.DynamicBytesFile.Init(ctx, creds, 0 /* devMajor */, 0 /* devMinor */, fs.NextIno(), f, 0777)
|
||||
return f
|
||||
}
|
||||
|
||||
@@ -105,9 +105,9 @@ type readonlyDir struct {
|
||||
locks vfs.FileLocks
|
||||
}
|
||||
|
||||
func (fs *filesystem) newReadonlyDir(creds *auth.Credentials, mode linux.FileMode, contents map[string]kernfs.Inode) kernfs.Inode {
|
||||
func (fs *filesystem) newReadonlyDir(ctx context.Context, creds *auth.Credentials, mode linux.FileMode, contents map[string]kernfs.Inode) kernfs.Inode {
|
||||
dir := &readonlyDir{}
|
||||
dir.attrs.Init(creds, 0 /* devMajor */, 0 /* devMinor */, fs.NextIno(), linux.ModeDirectory|mode)
|
||||
dir.attrs.Init(ctx, creds, 0 /* devMajor */, 0 /* devMinor */, fs.NextIno(), linux.ModeDirectory|mode)
|
||||
dir.OrderedChildren.Init(kernfs.OrderedChildrenOptions{})
|
||||
dir.EnableLeakCheck()
|
||||
dir.IncLinks(dir.OrderedChildren.Populate(contents))
|
||||
@@ -142,10 +142,10 @@ type dir struct {
|
||||
fs *filesystem
|
||||
}
|
||||
|
||||
func (fs *filesystem) newDir(creds *auth.Credentials, mode linux.FileMode, contents map[string]kernfs.Inode) kernfs.Inode {
|
||||
func (fs *filesystem) newDir(ctx context.Context, creds *auth.Credentials, mode linux.FileMode, contents map[string]kernfs.Inode) kernfs.Inode {
|
||||
dir := &dir{}
|
||||
dir.fs = fs
|
||||
dir.attrs.Init(creds, 0 /* devMajor */, 0 /* devMinor */, fs.NextIno(), linux.ModeDirectory|mode)
|
||||
dir.attrs.Init(ctx, creds, 0 /* devMajor */, 0 /* devMinor */, fs.NextIno(), linux.ModeDirectory|mode)
|
||||
dir.OrderedChildren.Init(kernfs.OrderedChildrenOptions{Writable: true})
|
||||
dir.EnableLeakCheck()
|
||||
|
||||
@@ -169,22 +169,24 @@ func (d *dir) DecRef(ctx context.Context) {
|
||||
|
||||
func (d *dir) NewDir(ctx context.Context, name string, opts vfs.MkdirOptions) (kernfs.Inode, error) {
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
dir := d.fs.newDir(creds, opts.Mode, nil)
|
||||
dir := d.fs.newDir(ctx, creds, opts.Mode, nil)
|
||||
if err := d.OrderedChildren.Insert(name, dir); err != nil {
|
||||
dir.DecRef(ctx)
|
||||
return nil, err
|
||||
}
|
||||
d.TouchCMtime(ctx)
|
||||
d.IncLinks(1)
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
func (d *dir) NewFile(ctx context.Context, name string, opts vfs.OpenOptions) (kernfs.Inode, error) {
|
||||
creds := auth.CredentialsFromContext(ctx)
|
||||
f := d.fs.newFile(creds, "")
|
||||
f := d.fs.newFile(ctx, creds, "")
|
||||
if err := d.OrderedChildren.Insert(name, f); err != nil {
|
||||
f.DecRef(ctx)
|
||||
return nil, err
|
||||
}
|
||||
d.TouchCMtime(ctx)
|
||||
return f, nil
|
||||
}
|
||||
|
||||
@@ -209,7 +211,7 @@ func (fsType) Release(ctx context.Context) {}
|
||||
func (fst fsType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, source string, opt vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) {
|
||||
fs := &filesystem{}
|
||||
fs.VFSFilesystem().Init(vfsObj, &fst, fs)
|
||||
root := fst.rootFn(creds, fs)
|
||||
root := fst.rootFn(ctx, creds, fs)
|
||||
var d kernfs.Dentry
|
||||
d.Init(&fs.Filesystem, root)
|
||||
return fs.VFSFilesystem(), d.VFSDentry(), nil
|
||||
@@ -218,9 +220,9 @@ func (fst fsType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesyst
|
||||
// -------------------- Remainder of the file are test cases --------------------
|
||||
|
||||
func TestBasic(t *testing.T) {
|
||||
sys := newTestSystem(t, func(creds *auth.Credentials, fs *filesystem) kernfs.Inode {
|
||||
return fs.newReadonlyDir(creds, 0755, map[string]kernfs.Inode{
|
||||
"file1": fs.newFile(creds, staticFileContent),
|
||||
sys := newTestSystem(t, func(ctx context.Context, creds *auth.Credentials, fs *filesystem) kernfs.Inode {
|
||||
return fs.newReadonlyDir(ctx, creds, 0755, map[string]kernfs.Inode{
|
||||
"file1": fs.newFile(ctx, creds, staticFileContent),
|
||||
})
|
||||
})
|
||||
defer sys.Destroy()
|
||||
@@ -228,9 +230,9 @@ func TestBasic(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMkdirGetDentry(t *testing.T) {
|
||||
sys := newTestSystem(t, func(creds *auth.Credentials, fs *filesystem) kernfs.Inode {
|
||||
return fs.newReadonlyDir(creds, 0755, map[string]kernfs.Inode{
|
||||
"dir1": fs.newDir(creds, 0755, nil),
|
||||
sys := newTestSystem(t, func(ctx context.Context, creds *auth.Credentials, fs *filesystem) kernfs.Inode {
|
||||
return fs.newReadonlyDir(ctx, creds, 0755, map[string]kernfs.Inode{
|
||||
"dir1": fs.newDir(ctx, creds, 0755, nil),
|
||||
})
|
||||
})
|
||||
defer sys.Destroy()
|
||||
@@ -243,9 +245,9 @@ func TestMkdirGetDentry(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestReadStaticFile(t *testing.T) {
|
||||
sys := newTestSystem(t, func(creds *auth.Credentials, fs *filesystem) kernfs.Inode {
|
||||
return fs.newReadonlyDir(creds, 0755, map[string]kernfs.Inode{
|
||||
"file1": fs.newFile(creds, staticFileContent),
|
||||
sys := newTestSystem(t, func(ctx context.Context, creds *auth.Credentials, fs *filesystem) kernfs.Inode {
|
||||
return fs.newReadonlyDir(ctx, creds, 0755, map[string]kernfs.Inode{
|
||||
"file1": fs.newFile(ctx, creds, staticFileContent),
|
||||
})
|
||||
})
|
||||
defer sys.Destroy()
|
||||
@@ -269,9 +271,9 @@ func TestReadStaticFile(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCreateNewFileInStaticDir(t *testing.T) {
|
||||
sys := newTestSystem(t, func(creds *auth.Credentials, fs *filesystem) kernfs.Inode {
|
||||
return fs.newReadonlyDir(creds, 0755, map[string]kernfs.Inode{
|
||||
"dir1": fs.newDir(creds, 0755, nil),
|
||||
sys := newTestSystem(t, func(ctx context.Context, creds *auth.Credentials, fs *filesystem) kernfs.Inode {
|
||||
return fs.newReadonlyDir(ctx, creds, 0755, map[string]kernfs.Inode{
|
||||
"dir1": fs.newDir(ctx, creds, 0755, nil),
|
||||
})
|
||||
})
|
||||
defer sys.Destroy()
|
||||
@@ -296,8 +298,8 @@ func TestCreateNewFileInStaticDir(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDirFDReadWrite(t *testing.T) {
|
||||
sys := newTestSystem(t, func(creds *auth.Credentials, fs *filesystem) kernfs.Inode {
|
||||
return fs.newReadonlyDir(creds, 0755, nil)
|
||||
sys := newTestSystem(t, func(ctx context.Context, creds *auth.Credentials, fs *filesystem) kernfs.Inode {
|
||||
return fs.newReadonlyDir(ctx, creds, 0755, nil)
|
||||
})
|
||||
defer sys.Destroy()
|
||||
|
||||
@@ -320,14 +322,14 @@ func TestDirFDReadWrite(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDirFDIterDirents(t *testing.T) {
|
||||
sys := newTestSystem(t, func(creds *auth.Credentials, fs *filesystem) kernfs.Inode {
|
||||
return fs.newReadonlyDir(creds, 0755, map[string]kernfs.Inode{
|
||||
sys := newTestSystem(t, func(ctx context.Context, creds *auth.Credentials, fs *filesystem) kernfs.Inode {
|
||||
return fs.newReadonlyDir(ctx, creds, 0755, map[string]kernfs.Inode{
|
||||
// Fill root with nodes backed by various inode implementations.
|
||||
"dir1": fs.newReadonlyDir(creds, 0755, nil),
|
||||
"dir2": fs.newDir(creds, 0755, map[string]kernfs.Inode{
|
||||
"dir3": fs.newDir(creds, 0755, nil),
|
||||
"dir1": fs.newReadonlyDir(ctx, creds, 0755, nil),
|
||||
"dir2": fs.newDir(ctx, creds, 0755, map[string]kernfs.Inode{
|
||||
"dir3": fs.newDir(ctx, creds, 0755, nil),
|
||||
}),
|
||||
"file1": fs.newFile(creds, staticFileContent),
|
||||
"file1": fs.newFile(ctx, creds, staticFileContent),
|
||||
})
|
||||
})
|
||||
defer sys.Destroy()
|
||||
|
||||
@@ -38,16 +38,16 @@ type StaticSymlink struct {
|
||||
var _ Inode = (*StaticSymlink)(nil)
|
||||
|
||||
// NewStaticSymlink creates a new symlink file pointing to 'target'.
|
||||
func NewStaticSymlink(creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, target string) Inode {
|
||||
func NewStaticSymlink(ctx context.Context, creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, target string) Inode {
|
||||
inode := &StaticSymlink{}
|
||||
inode.Init(creds, devMajor, devMinor, ino, target)
|
||||
inode.Init(ctx, creds, devMajor, devMinor, ino, target)
|
||||
return inode
|
||||
}
|
||||
|
||||
// Init initializes the instance.
|
||||
func (s *StaticSymlink) Init(creds *auth.Credentials, devMajor uint32, devMinor uint32, ino uint64, target string) {
|
||||
func (s *StaticSymlink) Init(ctx context.Context, creds *auth.Credentials, devMajor uint32, devMinor uint32, ino uint64, target string) {
|
||||
s.target = target
|
||||
s.InodeAttrs.Init(creds, devMajor, devMinor, ino, linux.ModeSymlink|0777)
|
||||
s.InodeAttrs.Init(ctx, creds, devMajor, devMinor, ino, linux.ModeSymlink|0777)
|
||||
}
|
||||
|
||||
// Readlink implements Inode.Readlink.
|
||||
|
||||
@@ -41,17 +41,17 @@ type syntheticDirectory struct {
|
||||
|
||||
var _ Inode = (*syntheticDirectory)(nil)
|
||||
|
||||
func newSyntheticDirectory(creds *auth.Credentials, perm linux.FileMode) Inode {
|
||||
func newSyntheticDirectory(ctx context.Context, creds *auth.Credentials, perm linux.FileMode) Inode {
|
||||
inode := &syntheticDirectory{}
|
||||
inode.Init(creds, 0 /* devMajor */, 0 /* devMinor */, 0 /* ino */, perm)
|
||||
inode.Init(ctx, creds, 0 /* devMajor */, 0 /* devMinor */, 0 /* ino */, perm)
|
||||
return inode
|
||||
}
|
||||
|
||||
func (dir *syntheticDirectory) Init(creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, perm linux.FileMode) {
|
||||
func (dir *syntheticDirectory) Init(ctx context.Context, creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, perm linux.FileMode) {
|
||||
if perm&^linux.PermissionsMask != 0 {
|
||||
panic(fmt.Sprintf("perm contains non-permission bits: %#o", perm))
|
||||
}
|
||||
dir.InodeAttrs.Init(creds, devMajor, devMinor, ino, linux.S_IFDIR|perm)
|
||||
dir.InodeAttrs.Init(ctx, creds, devMajor, devMinor, ino, linux.S_IFDIR|perm)
|
||||
dir.OrderedChildren.Init(OrderedChildrenOptions{
|
||||
Writable: true,
|
||||
})
|
||||
@@ -76,11 +76,12 @@ func (dir *syntheticDirectory) NewDir(ctx context.Context, name string, opts vfs
|
||||
if !opts.ForSyntheticMountpoint {
|
||||
return nil, syserror.EPERM
|
||||
}
|
||||
subdirI := newSyntheticDirectory(auth.CredentialsFromContext(ctx), opts.Mode&linux.PermissionsMask)
|
||||
subdirI := newSyntheticDirectory(ctx, auth.CredentialsFromContext(ctx), opts.Mode&linux.PermissionsMask)
|
||||
if err := dir.OrderedChildren.Insert(name, subdirI); err != nil {
|
||||
subdirI.DecRef(ctx)
|
||||
return nil, err
|
||||
}
|
||||
dir.TouchCMtime(ctx)
|
||||
return subdirI, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ func (ft FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualF
|
||||
cgroups = data.Cgroups
|
||||
}
|
||||
|
||||
inode := procfs.newTasksInode(k, pidns, cgroups)
|
||||
inode := procfs.newTasksInode(ctx, k, pidns, cgroups)
|
||||
var dentry kernfs.Dentry
|
||||
dentry.Init(&procfs.Filesystem, inode)
|
||||
return procfs.VFSFilesystem(), dentry.VFSDentry(), nil
|
||||
@@ -94,11 +94,11 @@ type dynamicInode interface {
|
||||
kernfs.Inode
|
||||
vfs.DynamicBytesSource
|
||||
|
||||
Init(creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, data vfs.DynamicBytesSource, perm linux.FileMode)
|
||||
Init(ctx context.Context, creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, data vfs.DynamicBytesSource, perm linux.FileMode)
|
||||
}
|
||||
|
||||
func (fs *filesystem) newInode(creds *auth.Credentials, perm linux.FileMode, inode dynamicInode) dynamicInode {
|
||||
inode.Init(creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), inode, perm)
|
||||
func (fs *filesystem) newInode(ctx context.Context, creds *auth.Credentials, perm linux.FileMode, inode dynamicInode) dynamicInode {
|
||||
inode.Init(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), inode, perm)
|
||||
return inode
|
||||
}
|
||||
|
||||
@@ -114,8 +114,8 @@ func newStaticFile(data string) *staticFile {
|
||||
return &staticFile{StaticData: vfs.StaticData{Data: data}}
|
||||
}
|
||||
|
||||
func (fs *filesystem) newStaticDir(creds *auth.Credentials, children map[string]kernfs.Inode) kernfs.Inode {
|
||||
return kernfs.NewStaticDir(creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, children, kernfs.GenericDirectoryFDOptions{
|
||||
func (fs *filesystem) newStaticDir(ctx context.Context, creds *auth.Credentials, children map[string]kernfs.Inode) kernfs.Inode {
|
||||
return kernfs.NewStaticDir(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, children, kernfs.GenericDirectoryFDOptions{
|
||||
SeekEnd: kernfs.SeekEndZero,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ func (fs *filesystem) newSubtasks(task *kernel.Task, pidns *kernel.PIDNamespace,
|
||||
cgroupControllers: cgroupControllers,
|
||||
}
|
||||
// Note: credentials are overridden by taskOwnedInode.
|
||||
subInode.InodeAttrs.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555)
|
||||
subInode.InodeAttrs.Init(task, task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555)
|
||||
subInode.OrderedChildren.Init(kernfs.OrderedChildrenOptions{})
|
||||
subInode.EnableLeakCheck()
|
||||
|
||||
@@ -84,7 +84,7 @@ func (i *subtasksInode) Lookup(ctx context.Context, name string) (kernfs.Inode,
|
||||
}
|
||||
|
||||
// IterDirents implements kernfs.inodeDirectory.IterDirents.
|
||||
func (i *subtasksInode) IterDirents(ctx context.Context, cb vfs.IterDirentsCallback, offset, relOffset int64) (int64, error) {
|
||||
func (i *subtasksInode) IterDirents(ctx context.Context, mnt *vfs.Mount, cb vfs.IterDirentsCallback, offset, relOffset int64) (int64, error) {
|
||||
tasks := i.task.ThreadGroup().MemberIDs(i.pidns)
|
||||
if len(tasks) == 0 {
|
||||
return offset, syserror.ENOENT
|
||||
|
||||
@@ -89,7 +89,7 @@ func (fs *filesystem) newTaskInode(task *kernel.Task, pidns *kernel.PIDNamespace
|
||||
|
||||
taskInode := &taskInode{task: task}
|
||||
// Note: credentials are overridden by taskOwnedInode.
|
||||
taskInode.InodeAttrs.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555)
|
||||
taskInode.InodeAttrs.Init(task, task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555)
|
||||
taskInode.EnableLeakCheck()
|
||||
|
||||
inode := &taskOwnedInode{Inode: taskInode, owner: task}
|
||||
@@ -144,7 +144,7 @@ var _ kernfs.Inode = (*taskOwnedInode)(nil)
|
||||
|
||||
func (fs *filesystem) newTaskOwnedInode(task *kernel.Task, ino uint64, perm linux.FileMode, inode dynamicInode) kernfs.Inode {
|
||||
// Note: credentials are overridden by taskOwnedInode.
|
||||
inode.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, inode, perm)
|
||||
inode.Init(task, task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, inode, perm)
|
||||
|
||||
return &taskOwnedInode{Inode: inode, owner: task}
|
||||
}
|
||||
@@ -152,7 +152,7 @@ func (fs *filesystem) newTaskOwnedInode(task *kernel.Task, ino uint64, perm linu
|
||||
func (fs *filesystem) newTaskOwnedDir(task *kernel.Task, ino uint64, perm linux.FileMode, children map[string]kernfs.Inode) kernfs.Inode {
|
||||
// Note: credentials are overridden by taskOwnedInode.
|
||||
fdOpts := kernfs.GenericDirectoryFDOptions{SeekEnd: kernfs.SeekEndZero}
|
||||
dir := kernfs.NewStaticDir(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, perm, children, fdOpts)
|
||||
dir := kernfs.NewStaticDir(task, task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, perm, children, fdOpts)
|
||||
|
||||
return &taskOwnedInode{Inode: dir, owner: task}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ type fdDir struct {
|
||||
}
|
||||
|
||||
// IterDirents implements kernfs.inodeDirectory.IterDirents.
|
||||
func (i *fdDir) IterDirents(ctx context.Context, cb vfs.IterDirentsCallback, offset, relOffset int64) (int64, error) {
|
||||
func (i *fdDir) IterDirents(ctx context.Context, mnt *vfs.Mount, cb vfs.IterDirentsCallback, offset, relOffset int64) (int64, error) {
|
||||
var fds []int32
|
||||
i.task.WithMuLocked(func(t *kernel.Task) {
|
||||
if fdTable := t.FDTable(); fdTable != nil {
|
||||
@@ -127,15 +127,15 @@ func (fs *filesystem) newFDDirInode(task *kernel.Task) kernfs.Inode {
|
||||
produceSymlink: true,
|
||||
},
|
||||
}
|
||||
inode.InodeAttrs.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555)
|
||||
inode.InodeAttrs.Init(task, task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555)
|
||||
inode.EnableLeakCheck()
|
||||
inode.OrderedChildren.Init(kernfs.OrderedChildrenOptions{})
|
||||
return inode
|
||||
}
|
||||
|
||||
// IterDirents implements kernfs.inodeDirectory.IterDirents.
|
||||
func (i *fdDirInode) IterDirents(ctx context.Context, cb vfs.IterDirentsCallback, offset, relOffset int64) (int64, error) {
|
||||
return i.fdDir.IterDirents(ctx, cb, offset, relOffset)
|
||||
func (i *fdDirInode) IterDirents(ctx context.Context, mnt *vfs.Mount, cb vfs.IterDirentsCallback, offset, relOffset int64) (int64, error) {
|
||||
return i.fdDir.IterDirents(ctx, mnt, cb, offset, relOffset)
|
||||
}
|
||||
|
||||
// Lookup implements kernfs.inodeDirectory.Lookup.
|
||||
@@ -209,7 +209,7 @@ func (fs *filesystem) newFDSymlink(task *kernel.Task, fd int32, ino uint64) kern
|
||||
task: task,
|
||||
fd: fd,
|
||||
}
|
||||
inode.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, linux.ModeSymlink|0777)
|
||||
inode.Init(task, task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, linux.ModeSymlink|0777)
|
||||
return inode
|
||||
}
|
||||
|
||||
@@ -264,7 +264,7 @@ func (fs *filesystem) newFDInfoDirInode(task *kernel.Task) kernfs.Inode {
|
||||
task: task,
|
||||
},
|
||||
}
|
||||
inode.InodeAttrs.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555)
|
||||
inode.InodeAttrs.Init(task, task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555)
|
||||
inode.EnableLeakCheck()
|
||||
inode.OrderedChildren.Init(kernfs.OrderedChildrenOptions{})
|
||||
return inode
|
||||
@@ -288,8 +288,8 @@ func (i *fdInfoDirInode) Lookup(ctx context.Context, name string) (kernfs.Inode,
|
||||
}
|
||||
|
||||
// IterDirents implements Inode.IterDirents.
|
||||
func (i *fdInfoDirInode) IterDirents(ctx context.Context, cb vfs.IterDirentsCallback, offset, relOffset int64) (newOffset int64, err error) {
|
||||
return i.fdDir.IterDirents(ctx, cb, offset, relOffset)
|
||||
func (i *fdInfoDirInode) IterDirents(ctx context.Context, mnt *vfs.Mount, cb vfs.IterDirentsCallback, offset, relOffset int64) (newOffset int64, err error) {
|
||||
return i.fdDir.IterDirents(ctx, mnt, cb, offset, relOffset)
|
||||
}
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
|
||||
@@ -249,7 +249,7 @@ type commInode struct {
|
||||
|
||||
func (fs *filesystem) newComm(task *kernel.Task, ino uint64, perm linux.FileMode) kernfs.Inode {
|
||||
inode := &commInode{task: task}
|
||||
inode.DynamicBytesFile.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, &commData{task: task}, perm)
|
||||
inode.DynamicBytesFile.Init(task, task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, &commData{task: task}, perm)
|
||||
return inode
|
||||
}
|
||||
|
||||
@@ -657,7 +657,7 @@ var _ kernfs.Inode = (*exeSymlink)(nil)
|
||||
|
||||
func (fs *filesystem) newExeSymlink(task *kernel.Task, ino uint64) kernfs.Inode {
|
||||
inode := &exeSymlink{task: task}
|
||||
inode.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, linux.ModeSymlink|0777)
|
||||
inode.Init(task, task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, linux.ModeSymlink|0777)
|
||||
return inode
|
||||
}
|
||||
|
||||
@@ -733,7 +733,7 @@ var _ kernfs.Inode = (*cwdSymlink)(nil)
|
||||
|
||||
func (fs *filesystem) newCwdSymlink(task *kernel.Task, ino uint64) kernfs.Inode {
|
||||
inode := &cwdSymlink{task: task}
|
||||
inode.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, linux.ModeSymlink|0777)
|
||||
inode.Init(task, task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, linux.ModeSymlink|0777)
|
||||
return inode
|
||||
}
|
||||
|
||||
@@ -850,7 +850,7 @@ func (fs *filesystem) newNamespaceSymlink(task *kernel.Task, ino uint64, ns stri
|
||||
|
||||
inode := &namespaceSymlink{task: task}
|
||||
// Note: credentials are overridden by taskOwnedInode.
|
||||
inode.Init(task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, target)
|
||||
inode.Init(task, task.Credentials(), linux.UNNAMED_MAJOR, fs.devMinor, ino, target)
|
||||
|
||||
taskInode := &taskOwnedInode{Inode: inode, owner: task}
|
||||
return taskInode
|
||||
@@ -872,8 +872,10 @@ func (s *namespaceSymlink) Getlink(ctx context.Context, mnt *vfs.Mount) (vfs.Vir
|
||||
|
||||
// Create a synthetic inode to represent the namespace.
|
||||
fs := mnt.Filesystem().Impl().(*filesystem)
|
||||
nsInode := &namespaceInode{}
|
||||
nsInode.Init(ctx, auth.CredentialsFromContext(ctx), linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0444)
|
||||
dentry := &kernfs.Dentry{}
|
||||
dentry.Init(&fs.Filesystem, &namespaceInode{})
|
||||
dentry.Init(&fs.Filesystem, nsInode)
|
||||
vd := vfs.MakeVirtualDentry(mnt, dentry.VFSDentry())
|
||||
// Only IncRef vd.Mount() because vd.Dentry() already holds a ref of 1.
|
||||
mnt.IncRef()
|
||||
@@ -897,11 +899,11 @@ type namespaceInode struct {
|
||||
var _ kernfs.Inode = (*namespaceInode)(nil)
|
||||
|
||||
// Init initializes a namespace inode.
|
||||
func (i *namespaceInode) Init(creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, perm linux.FileMode) {
|
||||
func (i *namespaceInode) Init(ctx context.Context, creds *auth.Credentials, devMajor, devMinor uint32, ino uint64, perm linux.FileMode) {
|
||||
if perm&^linux.PermissionsMask != 0 {
|
||||
panic(fmt.Sprintf("Only permission mask must be set: %x", perm&linux.PermissionsMask))
|
||||
}
|
||||
i.InodeAttrs.Init(creds, devMajor, devMinor, ino, linux.ModeRegular|perm)
|
||||
i.InodeAttrs.Init(ctx, creds, devMajor, devMinor, ino, linux.ModeRegular|perm)
|
||||
}
|
||||
|
||||
// Open implements kernfs.Inode.Open.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user