memfs fixes.

- Unexport Filesystem/Dentry/Inode.

- Support SEEK_CUR in directoryFD.Seek().

- Hold Filesystem.mu before touching directoryFD.off in
directoryFD.Seek().

- Remove deleted Dentries from their parent directory.childLists.

- Remove invalid FIXMEs.

PiperOrigin-RevId: 262400633
This commit is contained in:
Jamie Liu
2019-08-08 11:46:38 -07:00
committed by gVisor bot
parent 08cd5e1d36
commit 06102af65a
6 changed files with 120 additions and 109 deletions
+2 -2
View File
@@ -11,8 +11,8 @@ go_template_instance(
prefix = "dentry",
template = "//pkg/ilist:generic_list",
types = {
"Element": "*Dentry",
"Linker": "*Dentry",
"Element": "*dentry",
"Linker": "*dentry",
},
)
+32 -23
View File
@@ -23,23 +23,23 @@ import (
)
type directory struct {
inode Inode
inode inode
// childList is a list containing (1) child Dentries and (2) fake Dentries
// (with inode == nil) that represent the iteration position of
// directoryFDs. childList is used to support directoryFD.IterDirents()
// efficiently. childList is protected by Filesystem.mu.
// efficiently. childList is protected by filesystem.mu.
childList dentryList
}
func (fs *Filesystem) newDirectory(creds *auth.Credentials, mode uint16) *Inode {
func (fs *filesystem) newDirectory(creds *auth.Credentials, mode uint16) *inode {
dir := &directory{}
dir.inode.init(dir, fs, creds, mode)
dir.inode.nlink = 2 // from "." and parent directory or ".." for root
return &dir.inode
}
func (i *Inode) isDir() bool {
func (i *inode) isDir() bool {
_, ok := i.impl.(*directory)
return ok
}
@@ -48,8 +48,8 @@ type directoryFD struct {
fileDescription
vfs.DirectoryFileDescriptionDefaultImpl
// Protected by Filesystem.mu.
iter *Dentry
// Protected by filesystem.mu.
iter *dentry
off int64
}
@@ -68,7 +68,7 @@ func (fd *directoryFD) Release() {
// IterDirents implements vfs.FileDescriptionImpl.IterDirents.
func (fd *directoryFD) IterDirents(ctx context.Context, cb vfs.IterDirentsCallback) error {
fs := fd.filesystem()
d := fd.vfsfd.VirtualDentry().Dentry()
vfsd := fd.vfsfd.VirtualDentry().Dentry()
fs.mu.Lock()
defer fs.mu.Unlock()
@@ -77,7 +77,7 @@ func (fd *directoryFD) IterDirents(ctx context.Context, cb vfs.IterDirentsCallba
if !cb.Handle(vfs.Dirent{
Name: ".",
Type: linux.DT_DIR,
Ino: d.Impl().(*Dentry).inode.ino,
Ino: vfsd.Impl().(*dentry).inode.ino,
Off: 0,
}) {
return nil
@@ -85,7 +85,7 @@ func (fd *directoryFD) IterDirents(ctx context.Context, cb vfs.IterDirentsCallba
fd.off++
}
if fd.off == 1 {
parentInode := d.ParentOrSelf().Impl().(*Dentry).inode
parentInode := vfsd.ParentOrSelf().Impl().(*dentry).inode
if !cb.Handle(vfs.Dirent{
Name: "..",
Type: parentInode.direntType(),
@@ -97,12 +97,12 @@ func (fd *directoryFD) IterDirents(ctx context.Context, cb vfs.IterDirentsCallba
fd.off++
}
dir := d.Impl().(*Dentry).inode.impl.(*directory)
var child *Dentry
dir := vfsd.Impl().(*dentry).inode.impl.(*directory)
var child *dentry
if fd.iter == nil {
// Start iteration at the beginning of dir.
child = dir.childList.Front()
fd.iter = &Dentry{}
fd.iter = &dentry{}
} else {
// Continue iteration from where we left off.
child = fd.iter.Next()
@@ -130,32 +130,41 @@ func (fd *directoryFD) IterDirents(ctx context.Context, cb vfs.IterDirentsCallba
// Seek implements vfs.FileDescriptionImpl.Seek.
func (fd *directoryFD) Seek(ctx context.Context, offset int64, whence int32) (int64, error) {
if whence != linux.SEEK_SET {
// TODO: Linux also allows SEEK_CUR.
fs := fd.filesystem()
fs.mu.Lock()
defer fs.mu.Unlock()
switch whence {
case linux.SEEK_SET:
// Use offset as given.
case linux.SEEK_CUR:
offset += fd.off
default:
return 0, syserror.EINVAL
}
if offset < 0 {
return 0, syserror.EINVAL
}
// If the offset isn't changing (e.g. due to lseek(0, SEEK_CUR)), don't
// seek even if doing so might reposition the iterator due to concurrent
// mutation of the directory. Compare fs/libfs.c:dcache_dir_lseek().
if fd.off == offset {
return offset, nil
}
fd.off = offset
// Compensate for "." and "..".
var remChildren int64
if offset < 2 {
remChildren = 0
} else {
remChildren := int64(0)
if offset >= 2 {
remChildren = offset - 2
}
fs := fd.filesystem()
dir := fd.inode().impl.(*directory)
fs.mu.Lock()
defer fs.mu.Unlock()
// Ensure that fd.iter exists and is not linked into dir.childList.
if fd.iter == nil {
fd.iter = &Dentry{}
fd.iter = &dentry{}
} else {
dir.childList.Remove(fd.iter)
}
+35 -33
View File
@@ -28,9 +28,9 @@ import (
//
// stepLocked is loosely analogous to fs/namei.c:walk_component().
//
// Preconditions: Filesystem.mu must be locked. !rp.Done(). inode ==
// vfsd.Impl().(*Dentry).inode.
func stepLocked(rp *vfs.ResolvingPath, vfsd *vfs.Dentry, inode *Inode) (*vfs.Dentry, *Inode, error) {
// Preconditions: filesystem.mu must be locked. !rp.Done(). inode ==
// vfsd.Impl().(*dentry).inode.
func stepLocked(rp *vfs.ResolvingPath, vfsd *vfs.Dentry, inode *inode) (*vfs.Dentry, *inode, error) {
if !inode.isDir() {
return nil, nil, syserror.ENOTDIR
}
@@ -47,7 +47,7 @@ afterSymlink:
// not in the Dentry tree, it doesn't exist.
return nil, nil, syserror.ENOENT
}
nextInode := nextVFSD.Impl().(*Dentry).inode
nextInode := nextVFSD.Impl().(*dentry).inode
if symlink, ok := nextInode.impl.(*symlink); ok && rp.ShouldFollowSymlink() {
// TODO: symlink traversals update access time
if err := rp.HandleSymlink(symlink.target); err != nil {
@@ -64,10 +64,10 @@ afterSymlink:
// walkExistingLocked is loosely analogous to Linux's
// fs/namei.c:path_lookupat().
//
// Preconditions: Filesystem.mu must be locked.
func walkExistingLocked(rp *vfs.ResolvingPath) (*vfs.Dentry, *Inode, error) {
// Preconditions: filesystem.mu must be locked.
func walkExistingLocked(rp *vfs.ResolvingPath) (*vfs.Dentry, *inode, error) {
vfsd := rp.Start()
inode := vfsd.Impl().(*Dentry).inode
inode := vfsd.Impl().(*dentry).inode
for !rp.Done() {
var err error
vfsd, inode, err = stepLocked(rp, vfsd, inode)
@@ -88,10 +88,10 @@ func walkExistingLocked(rp *vfs.ResolvingPath) (*vfs.Dentry, *Inode, error) {
// walkParentDirLocked is loosely analogous to Linux's
// fs/namei.c:path_parentat().
//
// Preconditions: Filesystem.mu must be locked. !rp.Done().
func walkParentDirLocked(rp *vfs.ResolvingPath) (*vfs.Dentry, *Inode, error) {
// Preconditions: filesystem.mu must be locked. !rp.Done().
func walkParentDirLocked(rp *vfs.ResolvingPath) (*vfs.Dentry, *inode, error) {
vfsd := rp.Start()
inode := vfsd.Impl().(*Dentry).inode
inode := vfsd.Impl().(*dentry).inode
for !rp.Final() {
var err error
vfsd, inode, err = stepLocked(rp, vfsd, inode)
@@ -108,9 +108,9 @@ func walkParentDirLocked(rp *vfs.ResolvingPath) (*vfs.Dentry, *Inode, error) {
// checkCreateLocked checks that a file named rp.Component() may be created in
// directory parentVFSD, then returns rp.Component().
//
// Preconditions: Filesystem.mu must be locked. parentInode ==
// parentVFSD.Impl().(*Dentry).inode. parentInode.isDir() == true.
func checkCreateLocked(rp *vfs.ResolvingPath, parentVFSD *vfs.Dentry, parentInode *Inode) (string, error) {
// Preconditions: filesystem.mu must be locked. parentInode ==
// parentVFSD.Impl().(*dentry).inode. parentInode.isDir() == true.
func checkCreateLocked(rp *vfs.ResolvingPath, parentVFSD *vfs.Dentry, parentInode *inode) (string, error) {
if err := parentInode.checkPermissions(rp.Credentials(), vfs.MayWrite|vfs.MayExec, true); err != nil {
return "", err
}
@@ -144,7 +144,7 @@ func checkDeleteLocked(vfsd *vfs.Dentry) error {
}
// GetDentryAt implements vfs.FilesystemImpl.GetDentryAt.
func (fs *Filesystem) GetDentryAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.GetDentryOptions) (*vfs.Dentry, error) {
func (fs *filesystem) GetDentryAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.GetDentryOptions) (*vfs.Dentry, error) {
fs.mu.RLock()
defer fs.mu.RUnlock()
vfsd, inode, err := walkExistingLocked(rp)
@@ -164,7 +164,7 @@ func (fs *Filesystem) GetDentryAt(ctx context.Context, rp *vfs.ResolvingPath, op
}
// LinkAt implements vfs.FilesystemImpl.LinkAt.
func (fs *Filesystem) LinkAt(ctx context.Context, rp *vfs.ResolvingPath, vd vfs.VirtualDentry) error {
func (fs *filesystem) LinkAt(ctx context.Context, rp *vfs.ResolvingPath, vd vfs.VirtualDentry) error {
if rp.Done() {
return syserror.EEXIST
}
@@ -185,7 +185,7 @@ func (fs *Filesystem) LinkAt(ctx context.Context, rp *vfs.ResolvingPath, vd vfs.
return err
}
defer rp.Mount().EndWrite()
d := vd.Dentry().Impl().(*Dentry)
d := vd.Dentry().Impl().(*dentry)
if d.inode.isDir() {
return syserror.EPERM
}
@@ -197,7 +197,7 @@ func (fs *Filesystem) LinkAt(ctx context.Context, rp *vfs.ResolvingPath, vd vfs.
}
// MkdirAt implements vfs.FilesystemImpl.MkdirAt.
func (fs *Filesystem) MkdirAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.MkdirOptions) error {
func (fs *filesystem) MkdirAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.MkdirOptions) error {
if rp.Done() {
return syserror.EEXIST
}
@@ -223,7 +223,7 @@ func (fs *Filesystem) MkdirAt(ctx context.Context, rp *vfs.ResolvingPath, opts v
}
// MknodAt implements vfs.FilesystemImpl.MknodAt.
func (fs *Filesystem) MknodAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.MknodOptions) error {
func (fs *filesystem) MknodAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.MknodOptions) error {
if rp.Done() {
return syserror.EEXIST
}
@@ -246,7 +246,7 @@ func (fs *Filesystem) MknodAt(ctx context.Context, rp *vfs.ResolvingPath, opts v
}
// OpenAt implements vfs.FilesystemImpl.OpenAt.
func (fs *Filesystem) OpenAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
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
@@ -265,11 +265,10 @@ func (fs *Filesystem) OpenAt(ctx context.Context, rp *vfs.ResolvingPath, opts vf
mustCreate := opts.Flags&linux.O_EXCL != 0
vfsd := rp.Start()
inode := vfsd.Impl().(*Dentry).inode
inode := vfsd.Impl().(*dentry).inode
fs.mu.Lock()
defer fs.mu.Unlock()
if rp.Done() {
// FIXME: ???
if rp.MustBeDir() {
return nil, syserror.EISDIR
}
@@ -327,7 +326,7 @@ afterTrailingSymlink:
if mustCreate {
return nil, syserror.EEXIST
}
childInode := childVFSD.Impl().(*Dentry).inode
childInode := childVFSD.Impl().(*dentry).inode
if symlink, ok := childInode.impl.(*symlink); ok && rp.ShouldFollowSymlink() {
// TODO: symlink traversals update access time
if err := rp.HandleSymlink(symlink.target); err != nil {
@@ -340,7 +339,7 @@ afterTrailingSymlink:
return childInode.open(rp, childVFSD, opts.Flags, false)
}
func (i *Inode) open(rp *vfs.ResolvingPath, vfsd *vfs.Dentry, flags uint32, afterCreate bool) (*vfs.FileDescription, error) {
func (i *inode) open(rp *vfs.ResolvingPath, vfsd *vfs.Dentry, flags uint32, afterCreate bool) (*vfs.FileDescription, error) {
ats := vfs.AccessTypesForOpenFlags(flags)
if !afterCreate {
if err := i.checkPermissions(rp.Credentials(), ats, i.isDir()); err != nil {
@@ -385,7 +384,7 @@ func (i *Inode) open(rp *vfs.ResolvingPath, vfsd *vfs.Dentry, flags uint32, afte
}
// ReadlinkAt implements vfs.FilesystemImpl.ReadlinkAt.
func (fs *Filesystem) ReadlinkAt(ctx context.Context, rp *vfs.ResolvingPath) (string, error) {
func (fs *filesystem) ReadlinkAt(ctx context.Context, rp *vfs.ResolvingPath) (string, error) {
fs.mu.RLock()
_, inode, err := walkExistingLocked(rp)
fs.mu.RUnlock()
@@ -400,9 +399,8 @@ func (fs *Filesystem) ReadlinkAt(ctx context.Context, rp *vfs.ResolvingPath) (st
}
// RenameAt implements vfs.FilesystemImpl.RenameAt.
func (fs *Filesystem) RenameAt(ctx context.Context, rp *vfs.ResolvingPath, vd vfs.VirtualDentry, opts vfs.RenameOptions) error {
func (fs *filesystem) RenameAt(ctx context.Context, rp *vfs.ResolvingPath, vd vfs.VirtualDentry, opts vfs.RenameOptions) error {
if rp.Done() {
// FIXME
return syserror.ENOENT
}
fs.mu.Lock()
@@ -424,7 +422,7 @@ func (fs *Filesystem) RenameAt(ctx context.Context, rp *vfs.ResolvingPath, vd vf
}
// RmdirAt implements vfs.FilesystemImpl.RmdirAt.
func (fs *Filesystem) RmdirAt(ctx context.Context, rp *vfs.ResolvingPath) error {
func (fs *filesystem) RmdirAt(ctx context.Context, rp *vfs.ResolvingPath) error {
fs.mu.Lock()
defer fs.mu.Unlock()
vfsd, inode, err := walkExistingLocked(rp)
@@ -447,12 +445,14 @@ func (fs *Filesystem) RmdirAt(ctx context.Context, rp *vfs.ResolvingPath) error
if err := rp.VirtualFilesystem().DeleteDentry(vfs.MountNamespaceFromContext(ctx), vfsd); err != nil {
return err
}
// Remove from parent directory's childList.
vfsd.Parent().Impl().(*dentry).inode.impl.(*directory).childList.Remove(vfsd.Impl().(*dentry))
inode.decRef()
return nil
}
// SetStatAt implements vfs.FilesystemImpl.SetStatAt.
func (fs *Filesystem) SetStatAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.SetStatOptions) error {
func (fs *filesystem) SetStatAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.SetStatOptions) error {
fs.mu.RLock()
_, _, err := walkExistingLocked(rp)
fs.mu.RUnlock()
@@ -462,12 +462,12 @@ func (fs *Filesystem) SetStatAt(ctx context.Context, rp *vfs.ResolvingPath, opts
if opts.Stat.Mask == 0 {
return nil
}
// TODO: implement Inode.setStat
// TODO: implement inode.setStat
return syserror.EPERM
}
// StatAt implements vfs.FilesystemImpl.StatAt.
func (fs *Filesystem) StatAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.StatOptions) (linux.Statx, error) {
func (fs *filesystem) StatAt(ctx context.Context, rp *vfs.ResolvingPath, opts vfs.StatOptions) (linux.Statx, error) {
fs.mu.RLock()
_, inode, err := walkExistingLocked(rp)
fs.mu.RUnlock()
@@ -480,7 +480,7 @@ func (fs *Filesystem) StatAt(ctx context.Context, rp *vfs.ResolvingPath, opts vf
}
// StatFSAt implements vfs.FilesystemImpl.StatFSAt.
func (fs *Filesystem) StatFSAt(ctx context.Context, rp *vfs.ResolvingPath) (linux.Statfs, error) {
func (fs *filesystem) StatFSAt(ctx context.Context, rp *vfs.ResolvingPath) (linux.Statfs, error) {
fs.mu.RLock()
_, _, err := walkExistingLocked(rp)
fs.mu.RUnlock()
@@ -492,7 +492,7 @@ func (fs *Filesystem) StatFSAt(ctx context.Context, rp *vfs.ResolvingPath) (linu
}
// SymlinkAt implements vfs.FilesystemImpl.SymlinkAt.
func (fs *Filesystem) SymlinkAt(ctx context.Context, rp *vfs.ResolvingPath, target string) error {
func (fs *filesystem) SymlinkAt(ctx context.Context, rp *vfs.ResolvingPath, target string) error {
if rp.Done() {
return syserror.EEXIST
}
@@ -517,7 +517,7 @@ func (fs *Filesystem) SymlinkAt(ctx context.Context, rp *vfs.ResolvingPath, targ
}
// UnlinkAt implements vfs.FilesystemImpl.UnlinkAt.
func (fs *Filesystem) UnlinkAt(ctx context.Context, rp *vfs.ResolvingPath) error {
func (fs *filesystem) UnlinkAt(ctx context.Context, rp *vfs.ResolvingPath) error {
fs.mu.Lock()
defer fs.mu.Unlock()
vfsd, inode, err := walkExistingLocked(rp)
@@ -537,6 +537,8 @@ func (fs *Filesystem) UnlinkAt(ctx context.Context, rp *vfs.ResolvingPath) error
if err := rp.VirtualFilesystem().DeleteDentry(vfs.MountNamespaceFromContext(ctx), vfsd); err != nil {
return err
}
// Remove from parent directory's childList.
vfsd.Parent().Impl().(*dentry).inode.impl.(*directory).childList.Remove(vfsd.Impl().(*dentry))
inode.decLinksLocked()
return nil
}
+46 -46
View File
@@ -21,10 +21,10 @@
//
// Lock order:
//
// Filesystem.mu
// filesystem.mu
// regularFileFD.offMu
// regularFile.mu
// Inode.mu
// inode.mu
package memfs
import (
@@ -42,8 +42,8 @@ import (
// FilesystemType implements vfs.FilesystemType.
type FilesystemType struct{}
// Filesystem implements vfs.FilesystemImpl.
type Filesystem struct {
// filesystem implements vfs.FilesystemImpl.
type filesystem struct {
vfsfs vfs.Filesystem
// mu serializes changes to the Dentry tree.
@@ -54,44 +54,44 @@ type Filesystem struct {
// NewFilesystem implements vfs.FilesystemType.NewFilesystem.
func (fstype FilesystemType) NewFilesystem(ctx context.Context, creds *auth.Credentials, source string, opts vfs.NewFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) {
var fs Filesystem
var fs filesystem
fs.vfsfs.Init(&fs)
root := fs.newDentry(fs.newDirectory(creds, 01777))
return &fs.vfsfs, &root.vfsd, nil
}
// Release implements vfs.FilesystemImpl.Release.
func (fs *Filesystem) Release() {
func (fs *filesystem) Release() {
}
// Sync implements vfs.FilesystemImpl.Sync.
func (fs *Filesystem) Sync(ctx context.Context) error {
func (fs *filesystem) Sync(ctx context.Context) error {
// All filesystem state is in-memory.
return nil
}
// Dentry implements vfs.DentryImpl.
type Dentry struct {
// dentry implements vfs.DentryImpl.
type dentry struct {
vfsd vfs.Dentry
// inode is the inode represented by this Dentry. Multiple Dentries may
// share a single non-directory Inode (with hard links). inode is
// inode is the inode represented by this dentry. Multiple Dentries may
// share a single non-directory inode (with hard links). inode is
// immutable.
inode *Inode
inode *inode
// memfs doesn't count references on Dentries; because the Dentry tree is
// memfs doesn't count references on dentries; because the dentry tree is
// the sole source of truth, it is by definition always consistent with the
// state of the filesystem. However, it does count references on Inodes,
// because Inode resources are released when all references are dropped.
// state of the filesystem. However, it does count references on inodes,
// because inode resources are released when all references are dropped.
// (memfs doesn't really have resources to release, but we implement
// reference counting because tmpfs regular files will.)
// dentryEntry (ugh) links Dentries into their parent directory.childList.
// dentryEntry (ugh) links dentries into their parent directory.childList.
dentryEntry
}
func (fs *Filesystem) newDentry(inode *Inode) *Dentry {
d := &Dentry{
func (fs *filesystem) newDentry(inode *inode) *dentry {
d := &dentry{
inode: inode,
}
d.vfsd.Init(d)
@@ -99,37 +99,37 @@ func (fs *Filesystem) newDentry(inode *Inode) *Dentry {
}
// IncRef implements vfs.DentryImpl.IncRef.
func (d *Dentry) IncRef(vfsfs *vfs.Filesystem) {
func (d *dentry) IncRef(vfsfs *vfs.Filesystem) {
d.inode.incRef()
}
// TryIncRef implements vfs.DentryImpl.TryIncRef.
func (d *Dentry) TryIncRef(vfsfs *vfs.Filesystem) bool {
func (d *dentry) TryIncRef(vfsfs *vfs.Filesystem) bool {
return d.inode.tryIncRef()
}
// DecRef implements vfs.DentryImpl.DecRef.
func (d *Dentry) DecRef(vfsfs *vfs.Filesystem) {
func (d *dentry) DecRef(vfsfs *vfs.Filesystem) {
d.inode.decRef()
}
// Inode represents a filesystem object.
type Inode struct {
// inode represents a filesystem object.
type inode struct {
// refs is a reference count. refs is accessed using atomic memory
// operations.
//
// A reference is held on all Inodes that are reachable in the filesystem
// A reference is held on all inodes that are reachable in the filesystem
// tree. For non-directories (which may have multiple hard links), this
// means that a reference is dropped when nlink reaches 0. For directories,
// nlink never reaches 0 due to the "." entry; instead,
// Filesystem.RmdirAt() drops the reference.
// filesystem.RmdirAt() drops the reference.
refs int64
// Inode metadata; protected by mu and accessed using atomic memory
// operations unless otherwise specified.
mu sync.RWMutex
mode uint32 // excluding file type bits, which are based on impl
nlink uint32 // protected by Filesystem.mu instead of Inode.mu
nlink uint32 // protected by filesystem.mu instead of inode.mu
uid uint32 // auth.KUID, but stored as raw uint32 for sync/atomic
gid uint32 // auth.KGID, but ...
ino uint64 // immutable
@@ -137,7 +137,7 @@ type Inode struct {
impl interface{} // immutable
}
func (i *Inode) init(impl interface{}, fs *Filesystem, creds *auth.Credentials, mode uint16) {
func (i *inode) init(impl interface{}, fs *filesystem, creds *auth.Credentials, mode uint16) {
i.refs = 1
i.mode = uint32(mode)
i.uid = uint32(creds.EffectiveKUID)
@@ -147,29 +147,29 @@ func (i *Inode) init(impl interface{}, fs *Filesystem, creds *auth.Credentials,
i.impl = impl
}
// Preconditions: Filesystem.mu must be locked for writing.
func (i *Inode) incLinksLocked() {
// Preconditions: filesystem.mu must be locked for writing.
func (i *inode) incLinksLocked() {
if atomic.AddUint32(&i.nlink, 1) <= 1 {
panic("memfs.Inode.incLinksLocked() called with no existing links")
panic("memfs.inode.incLinksLocked() called with no existing links")
}
}
// Preconditions: Filesystem.mu must be locked for writing.
func (i *Inode) decLinksLocked() {
// Preconditions: filesystem.mu must be locked for writing.
func (i *inode) decLinksLocked() {
if nlink := atomic.AddUint32(&i.nlink, ^uint32(0)); nlink == 0 {
i.decRef()
} else if nlink == ^uint32(0) { // negative overflow
panic("memfs.Inode.decLinksLocked() called with no existing links")
panic("memfs.inode.decLinksLocked() called with no existing links")
}
}
func (i *Inode) incRef() {
func (i *inode) incRef() {
if atomic.AddInt64(&i.refs, 1) <= 1 {
panic("memfs.Inode.incRef() called without holding a reference")
panic("memfs.inode.incRef() called without holding a reference")
}
}
func (i *Inode) tryIncRef() bool {
func (i *inode) tryIncRef() bool {
for {
refs := atomic.LoadInt64(&i.refs)
if refs == 0 {
@@ -181,7 +181,7 @@ func (i *Inode) tryIncRef() bool {
}
}
func (i *Inode) decRef() {
func (i *inode) decRef() {
if refs := atomic.AddInt64(&i.refs, -1); refs == 0 {
// This is unnecessary; it's mostly to simulate what tmpfs would do.
if regfile, ok := i.impl.(*regularFile); ok {
@@ -191,18 +191,18 @@ func (i *Inode) decRef() {
regfile.mu.Unlock()
}
} else if refs < 0 {
panic("memfs.Inode.decRef() called without holding a reference")
panic("memfs.inode.decRef() called without holding a reference")
}
}
func (i *Inode) checkPermissions(creds *auth.Credentials, ats vfs.AccessTypes, isDir bool) error {
func (i *inode) checkPermissions(creds *auth.Credentials, ats vfs.AccessTypes, isDir bool) error {
return vfs.GenericCheckPermissions(creds, ats, isDir, uint16(atomic.LoadUint32(&i.mode)), auth.KUID(atomic.LoadUint32(&i.uid)), auth.KGID(atomic.LoadUint32(&i.gid)))
}
// Go won't inline this function, and returning linux.Statx (which is quite
// big) means spending a lot of time in runtime.duffcopy(), so instead it's an
// output parameter.
func (i *Inode) statTo(stat *linux.Statx) {
func (i *inode) statTo(stat *linux.Statx) {
stat.Mask = linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_NLINK | linux.STATX_UID | linux.STATX_GID | linux.STATX_INO
stat.Blksize = 1 // usermem.PageSize in tmpfs
stat.Nlink = atomic.LoadUint32(&i.nlink)
@@ -241,7 +241,7 @@ func allocatedBlocksForSize(size uint64) uint64 {
return (size + 511) / 512
}
func (i *Inode) direntType() uint8 {
func (i *inode) direntType() uint8 {
switch i.impl.(type) {
case *regularFile:
return linux.DT_REG
@@ -262,12 +262,12 @@ type fileDescription struct {
flags uint32 // status flags; immutable
}
func (fd *fileDescription) filesystem() *Filesystem {
return fd.vfsfd.VirtualDentry().Mount().Filesystem().Impl().(*Filesystem)
func (fd *fileDescription) filesystem() *filesystem {
return fd.vfsfd.VirtualDentry().Mount().Filesystem().Impl().(*filesystem)
}
func (fd *fileDescription) inode() *Inode {
return fd.vfsfd.VirtualDentry().Dentry().Impl().(*Dentry).inode
func (fd *fileDescription) inode() *inode {
return fd.vfsfd.VirtualDentry().Dentry().Impl().(*dentry).inode
}
// StatusFlags implements vfs.FileDescriptionImpl.StatusFlags.
@@ -294,6 +294,6 @@ func (fd *fileDescription) SetStat(ctx context.Context, opts vfs.SetStatOptions)
if opts.Stat.Mask == 0 {
return nil
}
// TODO: implement Inode.setStat
// TODO: implement inode.setStat
return syserror.EPERM
}
+3 -3
View File
@@ -28,16 +28,16 @@ import (
)
type regularFile struct {
inode Inode
inode inode
mu sync.RWMutex
data []byte
// dataLen is len(data), but accessed using atomic memory operations to
// avoid locking in Inode.stat().
// avoid locking in inode.stat().
dataLen int64
}
func (fs *Filesystem) newRegularFile(creds *auth.Credentials, mode uint16) *Inode {
func (fs *filesystem) newRegularFile(creds *auth.Credentials, mode uint16) *inode {
file := &regularFile{}
file.inode.init(file, fs, creds, mode)
file.inode.nlink = 1 // from parent directory
+2 -2
View File
@@ -19,11 +19,11 @@ import (
)
type symlink struct {
inode Inode
inode inode
target string // immutable
}
func (fs *Filesystem) newSymlink(creds *auth.Credentials, target string) *Inode {
func (fs *filesystem) newSymlink(creds *auth.Credentials, target string) *inode {
link := &symlink{
target: target,
}