summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fs/tmpfs
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/sentry/fs/tmpfs')
-rw-r--r--pkg/sentry/fs/tmpfs/BUILD2
-rw-r--r--pkg/sentry/fs/tmpfs/file_regular.go14
-rw-r--r--pkg/sentry/fs/tmpfs/file_test.go6
-rw-r--r--pkg/sentry/fs/tmpfs/fs.go2
-rw-r--r--pkg/sentry/fs/tmpfs/inode_file.go112
-rw-r--r--pkg/sentry/fs/tmpfs/tmpfs.go164
6 files changed, 212 insertions, 88 deletions
diff --git a/pkg/sentry/fs/tmpfs/BUILD b/pkg/sentry/fs/tmpfs/BUILD
index 9065cdd5d..14c7a9e62 100644
--- a/pkg/sentry/fs/tmpfs/BUILD
+++ b/pkg/sentry/fs/tmpfs/BUILD
@@ -23,11 +23,13 @@ go_library(
"//pkg/sentry/kernel",
"//pkg/sentry/kernel/auth",
"//pkg/sentry/kernel/pipe",
+ "//pkg/sentry/kernel/time",
"//pkg/sentry/memmap",
"//pkg/sentry/safemem",
"//pkg/sentry/socket/unix/transport",
"//pkg/sentry/usage",
"//pkg/sentry/usermem",
+ "//pkg/syserror",
"//pkg/waiter",
],
)
diff --git a/pkg/sentry/fs/tmpfs/file_regular.go b/pkg/sentry/fs/tmpfs/file_regular.go
index 1f9d69909..2c1eb0fd2 100644
--- a/pkg/sentry/fs/tmpfs/file_regular.go
+++ b/pkg/sentry/fs/tmpfs/file_regular.go
@@ -28,13 +28,13 @@ import (
//
// +stateify savable
type regularFileOperations struct {
- waiter.AlwaysReady `state:"nosave"`
- fsutil.NoopRelease `state:"nosave"`
- fsutil.GenericSeek `state:"nosave"`
- fsutil.NotDirReaddir `state:"nosave"`
- fsutil.NoopFsync `state:"nosave"`
- fsutil.NoopFlush `state:"nosave"`
- fsutil.NoIoctl `state:"nosave"`
+ waiter.AlwaysReady `state:"nosave"`
+ fsutil.FileNoopRelease `state:"nosave"`
+ fsutil.FileGenericSeek `state:"nosave"`
+ fsutil.FileNotDirReaddir `state:"nosave"`
+ fsutil.FileNoopFsync `state:"nosave"`
+ fsutil.FileNoopFlush `state:"nosave"`
+ fsutil.FileNoIoctl `state:"nosave"`
// iops is the InodeOperations of a regular tmpfs file. It is
// guaranteed to be the same as file.Dirent.Inode.InodeOperations,
diff --git a/pkg/sentry/fs/tmpfs/file_test.go b/pkg/sentry/fs/tmpfs/file_test.go
index 02da9af82..e7bbdc404 100644
--- a/pkg/sentry/fs/tmpfs/file_test.go
+++ b/pkg/sentry/fs/tmpfs/file_test.go
@@ -52,19 +52,19 @@ func TestGrow(t *testing.T) {
abuf := bytes.Repeat([]byte{'a'}, 68)
n, err := f.Pwritev(ctx, usermem.BytesIOSequence(abuf), 0)
if n != int64(len(abuf)) || err != nil {
- t.Fatalf("DeprecatedPwritev got (%d, %v) want (%d, nil)", n, err, len(abuf))
+ t.Fatalf("Pwritev got (%d, %v) want (%d, nil)", n, err, len(abuf))
}
bbuf := bytes.Repeat([]byte{'b'}, 856)
n, err = f.Pwritev(ctx, usermem.BytesIOSequence(bbuf), 68)
if n != int64(len(bbuf)) || err != nil {
- t.Fatalf("DeprecatedPwritev got (%d, %v) want (%d, nil)", n, err, len(bbuf))
+ t.Fatalf("Pwritev got (%d, %v) want (%d, nil)", n, err, len(bbuf))
}
rbuf := make([]byte, len(abuf)+len(bbuf))
n, err = f.Preadv(ctx, usermem.BytesIOSequence(rbuf), 0)
if n != int64(len(rbuf)) || err != nil {
- t.Fatalf("DeprecatedPreadv got (%d, %v) want (%d, nil)", n, err, len(rbuf))
+ t.Fatalf("Preadv got (%d, %v) want (%d, nil)", n, err, len(rbuf))
}
if want := append(abuf, bbuf...); !bytes.Equal(rbuf, want) {
diff --git a/pkg/sentry/fs/tmpfs/fs.go b/pkg/sentry/fs/tmpfs/fs.go
index 88f85b85a..caa3220ee 100644
--- a/pkg/sentry/fs/tmpfs/fs.go
+++ b/pkg/sentry/fs/tmpfs/fs.go
@@ -50,6 +50,8 @@ const (
// +stateify savable
type Filesystem struct{}
+var _ fs.Filesystem = (*Filesystem)(nil)
+
func init() {
fs.RegisterFilesystem(&Filesystem{})
}
diff --git a/pkg/sentry/fs/tmpfs/inode_file.go b/pkg/sentry/fs/tmpfs/inode_file.go
index ca2b4aabb..42d4bc76f 100644
--- a/pkg/sentry/fs/tmpfs/inode_file.go
+++ b/pkg/sentry/fs/tmpfs/inode_file.go
@@ -22,6 +22,7 @@ import (
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs/fsutil"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel"
+ ktime "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/time"
"gvisor.googlesource.com/gvisor/pkg/sentry/memmap"
"gvisor.googlesource.com/gvisor/pkg/sentry/safemem"
"gvisor.googlesource.com/gvisor/pkg/sentry/usage"
@@ -46,11 +47,13 @@ import (
//
// +stateify savable
type fileInodeOperations struct {
- fsutil.DeprecatedFileOperations `state:"nosave"`
- fsutil.InodeNotDirectory `state:"nosave"`
- fsutil.InodeNotSocket `state:"nosave"`
- fsutil.InodeNotSymlink `state:"nosave"`
- fsutil.NoopWriteOut `state:"nosave"`
+ fsutil.InodeGenericChecker `state:"nosave"`
+ fsutil.InodeNoopWriteOut `state:"nosave"`
+ fsutil.InodeNotDirectory `state:"nosave"`
+ fsutil.InodeNotSocket `state:"nosave"`
+ fsutil.InodeNotSymlink `state:"nosave"`
+
+ fsutil.InodeSimpleExtendedAttributes
// kernel is used to allocate platform memory that stores the file's contents.
kernel *kernel.Kernel
@@ -62,10 +65,10 @@ type fileInodeOperations struct {
// attr contains the unstable metadata for the file.
//
- // attr is protected by attrMu. attr.Unstable.Size is protected by both
- // attrMu and dataMu; reading it requires locking either mutex, while
- // mutating it requires locking both.
- attr fsutil.InMemoryAttributes
+ // attr is protected by attrMu. attr.Size is protected by both attrMu
+ // and dataMu; reading it requires locking either mutex, while mutating
+ // it requires locking both.
+ attr fs.UnstableAttr
mapsMu sync.Mutex `state:"nosave"`
@@ -83,12 +86,12 @@ type fileInodeOperations struct {
data fsutil.FileRangeSet
}
+var _ fs.InodeOperations = (*fileInodeOperations)(nil)
+
// NewInMemoryFile returns a new file backed by p.Memory().
func NewInMemoryFile(ctx context.Context, usage usage.MemoryKind, uattr fs.UnstableAttr, k *kernel.Kernel) fs.InodeOperations {
return &fileInodeOperations{
- attr: fsutil.InMemoryAttributes{
- Unstable: uattr,
- },
+ attr: uattr,
kernel: k,
memUsage: usage,
}
@@ -121,71 +124,56 @@ func (f *fileInodeOperations) GetFile(ctx context.Context, d *fs.Dirent, flags f
// UnstableAttr returns unstable attributes of this tmpfs file.
func (f *fileInodeOperations) UnstableAttr(ctx context.Context, inode *fs.Inode) (fs.UnstableAttr, error) {
f.attrMu.Lock()
- defer f.attrMu.Unlock()
f.dataMu.RLock()
- defer f.dataMu.RUnlock()
- attr := f.attr.Unstable
+ attr := f.attr
attr.Usage = int64(f.data.Span())
+ f.dataMu.RUnlock()
+ f.attrMu.Unlock()
return attr, nil
}
-// Getxattr implements fs.InodeOperations.Getxattr.
-func (f *fileInodeOperations) Getxattr(inode *fs.Inode, name string) ([]byte, error) {
- f.attrMu.Lock()
- defer f.attrMu.Unlock()
- return f.attr.Getxattr(name)
-}
-
-// Setxattr implements fs.InodeOperations.Setxattr.
-func (f *fileInodeOperations) Setxattr(inode *fs.Inode, name string, value []byte) error {
- f.attrMu.Lock()
- defer f.attrMu.Unlock()
- return f.attr.Setxattr(name, value)
-}
-
-// Listxattr implements fs.InodeOperations.Listxattr.
-func (f *fileInodeOperations) Listxattr(inode *fs.Inode) (map[string]struct{}, error) {
- f.attrMu.Lock()
- defer f.attrMu.Unlock()
- return f.attr.Listxattr()
-}
-
// Check implements fs.InodeOperations.Check.
func (f *fileInodeOperations) Check(ctx context.Context, inode *fs.Inode, p fs.PermMask) bool {
return fs.ContextCanAccessFile(ctx, inode, p)
}
// SetPermissions implements fs.InodeOperations.SetPermissions.
-func (f *fileInodeOperations) SetPermissions(ctx context.Context, inode *fs.Inode, p fs.FilePermissions) bool {
+func (f *fileInodeOperations) SetPermissions(ctx context.Context, _ *fs.Inode, p fs.FilePermissions) bool {
f.attrMu.Lock()
- defer f.attrMu.Unlock()
- return f.attr.SetPermissions(ctx, p)
+ f.attr.SetPermissions(ctx, p)
+ f.attrMu.Unlock()
+ return true
}
// SetTimestamps implements fs.InodeOperations.SetTimestamps.
-func (f *fileInodeOperations) SetTimestamps(ctx context.Context, inode *fs.Inode, ts fs.TimeSpec) error {
+func (f *fileInodeOperations) SetTimestamps(ctx context.Context, _ *fs.Inode, ts fs.TimeSpec) error {
f.attrMu.Lock()
- defer f.attrMu.Unlock()
- return f.attr.SetTimestamps(ctx, ts)
+ f.attr.SetTimestamps(ctx, ts)
+ f.attrMu.Unlock()
+ return nil
}
// SetOwner implements fs.InodeOperations.SetOwner.
-func (f *fileInodeOperations) SetOwner(ctx context.Context, inode *fs.Inode, owner fs.FileOwner) error {
+func (f *fileInodeOperations) SetOwner(ctx context.Context, _ *fs.Inode, owner fs.FileOwner) error {
f.attrMu.Lock()
- defer f.attrMu.Unlock()
- return f.attr.SetOwner(ctx, owner)
+ f.attr.SetOwner(ctx, owner)
+ f.attrMu.Unlock()
+ return nil
}
// Truncate implements fs.InodeOperations.Truncate.
-func (f *fileInodeOperations) Truncate(ctx context.Context, inode *fs.Inode, size int64) error {
+func (f *fileInodeOperations) Truncate(ctx context.Context, _ *fs.Inode, size int64) error {
f.attrMu.Lock()
defer f.attrMu.Unlock()
f.dataMu.Lock()
- oldSize := f.attr.Unstable.Size
+ oldSize := f.attr.Size
if oldSize != size {
- f.attr.Unstable.Size = size
- f.attr.TouchModificationTime(ctx)
+ f.attr.Size = size
+ // Update mtime and ctime.
+ now := ktime.NowFromContext(ctx)
+ f.attr.ModificationTime = now
+ f.attr.StatusChangeTime = now
}
f.dataMu.Unlock()
@@ -220,21 +208,21 @@ func (f *fileInodeOperations) Truncate(ctx context.Context, inode *fs.Inode, siz
// AddLink implements fs.InodeOperations.AddLink.
func (f *fileInodeOperations) AddLink() {
f.attrMu.Lock()
- f.attr.Unstable.Links++
+ f.attr.Links++
f.attrMu.Unlock()
}
// DropLink implements fs.InodeOperations.DropLink.
func (f *fileInodeOperations) DropLink() {
f.attrMu.Lock()
- f.attr.Unstable.Links--
+ f.attr.Links--
f.attrMu.Unlock()
}
// NotifyStatusChange implements fs.InodeOperations.NotifyStatusChange.
func (f *fileInodeOperations) NotifyStatusChange(ctx context.Context) {
f.attrMu.Lock()
- f.attr.TouchStatusChangeTime(ctx)
+ f.attr.StatusChangeTime = ktime.NowFromContext(ctx)
f.attrMu.Unlock()
}
@@ -264,7 +252,7 @@ func (f *fileInodeOperations) read(ctx context.Context, dst usermem.IOSequence,
// TODO: Separate out f.attr.Size and use atomics instead of
// f.dataMu.
f.dataMu.RLock()
- size := f.attr.Unstable.Size
+ size := f.attr.Size
f.dataMu.RUnlock()
if offset >= size {
return 0, io.EOF
@@ -273,7 +261,7 @@ func (f *fileInodeOperations) read(ctx context.Context, dst usermem.IOSequence,
n, err := dst.CopyOutFrom(ctx, &fileReadWriter{f, offset})
// Compare Linux's mm/filemap.c:do_generic_file_read() => file_accessed().
f.attrMu.Lock()
- f.attr.TouchAccessTime(ctx)
+ f.attr.AccessTime = ktime.NowFromContext(ctx)
f.attrMu.Unlock()
return n, err
}
@@ -287,7 +275,9 @@ func (f *fileInodeOperations) write(ctx context.Context, src usermem.IOSequence,
f.attrMu.Lock()
defer f.attrMu.Unlock()
// Compare Linux's mm/filemap.c:__generic_file_write_iter() => file_update_time().
- f.attr.TouchModificationTime(ctx)
+ now := ktime.NowFromContext(ctx)
+ f.attr.ModificationTime = now
+ f.attr.StatusChangeTime = now
return src.CopyInTo(ctx, &fileReadWriter{f, offset})
}
@@ -302,10 +292,10 @@ func (rw *fileReadWriter) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) {
defer rw.f.dataMu.RUnlock()
// Compute the range to read.
- if rw.offset >= rw.f.attr.Unstable.Size {
+ if rw.offset >= rw.f.attr.Size {
return 0, io.EOF
}
- end := fs.ReadEndOffset(rw.offset, int64(dsts.NumBytes()), rw.f.attr.Unstable.Size)
+ end := fs.ReadEndOffset(rw.offset, int64(dsts.NumBytes()), rw.f.attr.Size)
if end == rw.offset { // dsts.NumBytes() == 0?
return 0, nil
}
@@ -371,8 +361,8 @@ func (rw *fileReadWriter) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error)
defer func() {
// If the write ends beyond the file's previous size, it causes the
// file to grow.
- if rw.offset > rw.f.attr.Unstable.Size {
- rw.f.attr.Unstable.Size = rw.offset
+ if rw.offset > rw.f.attr.Size {
+ rw.f.attr.Size = rw.offset
}
}()
@@ -450,9 +440,9 @@ func (f *fileInodeOperations) Translate(ctx context.Context, required, optional
f.dataMu.Lock()
defer f.dataMu.Unlock()
- // Constrain translations to f.attr.Unstable.Size (rounded up) to prevent
+ // Constrain translations to f.attr.Size (rounded up) to prevent
// translation to pages that may be concurrently truncated.
- pgend := fs.OffsetPageEnd(f.attr.Unstable.Size)
+ pgend := fs.OffsetPageEnd(f.attr.Size)
var beyondEOF bool
if required.End > pgend {
if required.Start >= pgend {
diff --git a/pkg/sentry/fs/tmpfs/tmpfs.go b/pkg/sentry/fs/tmpfs/tmpfs.go
index 40a8c4b1e..a0277a132 100644
--- a/pkg/sentry/fs/tmpfs/tmpfs.go
+++ b/pkg/sentry/fs/tmpfs/tmpfs.go
@@ -19,12 +19,14 @@ import (
"gvisor.googlesource.com/gvisor/pkg/abi/linux"
"gvisor.googlesource.com/gvisor/pkg/sentry/context"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/fs/fsutil"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs/ramfs"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel/pipe"
"gvisor.googlesource.com/gvisor/pkg/sentry/socket/unix/transport"
"gvisor.googlesource.com/gvisor/pkg/sentry/usage"
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
+ "gvisor.googlesource.com/gvisor/pkg/syserror"
)
var fsInfo = fs.Info{
@@ -39,32 +41,54 @@ var fsInfo = fs.Info{
func rename(ctx context.Context, oldParent *fs.Inode, oldName string, newParent *fs.Inode, newName string) error {
op, ok := oldParent.InodeOperations.(*Dir)
if !ok {
- return ramfs.ErrCrossDevice
+ return syserror.EXDEV
}
np, ok := newParent.InodeOperations.(*Dir)
if !ok {
- return ramfs.ErrCrossDevice
+ return syserror.EXDEV
}
- return ramfs.Rename(ctx, &op.Dir, oldName, &np.Dir, newName)
+ return ramfs.Rename(ctx, op.ramfsDir, oldName, np.ramfsDir, newName)
}
// Dir is a directory.
//
// +stateify savable
type Dir struct {
- ramfs.Dir
+ fsutil.InodeGenericChecker `state:"nosave"`
+ fsutil.InodeIsDirTruncate `state:"nosave"`
+ fsutil.InodeNoopRelease `state:"nosave"`
+ fsutil.InodeNoopWriteOut `state:"nosave"`
+ fsutil.InodeNotMappable `state:"nosave"`
+ fsutil.InodeNotSocket `state:"nosave"`
+ fsutil.InodeNotSymlink `state:"nosave"`
+ fsutil.InodeVirtual `state:"nosave"`
+
+ // Ideally this would be embedded, so that we "inherit" all of the
+ // InodeOperations implemented by ramfs.Dir for free.
+ //
+ // However, ramfs.dirFileOperations stores a pointer to a ramfs.Dir,
+ // and our save/restore package does not allow saving a pointer to an
+ // embedded field elsewhere.
+ //
+ // Thus, we must make the ramfs.Dir is a field, and we delegate all the
+ // InodeOperation methods to it.
+ ramfsDir *ramfs.Dir
// kernel is used to allocate platform memory as storage for tmpfs Files.
kernel *kernel.Kernel
}
+var _ fs.InodeOperations = (*Dir)(nil)
+
// NewDir returns a new directory.
func NewDir(ctx context.Context, contents map[string]*fs.Inode, owner fs.FileOwner, perms fs.FilePermissions, msrc *fs.MountSource, kernel *kernel.Kernel) *fs.Inode {
- d := &Dir{kernel: kernel}
- d.InitDir(ctx, contents, owner, perms)
+ d := &Dir{
+ ramfsDir: ramfs.NewDir(ctx, contents, owner, perms),
+ kernel: kernel,
+ }
// Manually set the CreateOps.
- d.CreateOps = d.newCreateOps()
+ d.ramfsDir.CreateOps = d.newCreateOps()
return fs.NewInode(d, msrc, fs.StableAttr{
DeviceID: tmpfsDevice.DeviceID(),
@@ -77,7 +101,107 @@ func NewDir(ctx context.Context, contents map[string]*fs.Inode, owner fs.FileOwn
// afterLoad is invoked by stateify.
func (d *Dir) afterLoad() {
// Per NewDir, manually set the CreateOps.
- d.Dir.CreateOps = d.newCreateOps()
+ d.ramfsDir.CreateOps = d.newCreateOps()
+}
+
+// GetFile implements fs.InodeOperations.GetFile.
+func (d *Dir) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
+ return d.ramfsDir.GetFile(ctx, dirent, flags)
+}
+
+// AddLink implements fs.InodeOperations.AddLink.
+func (d *Dir) AddLink() {
+ d.ramfsDir.AddLink()
+}
+
+// DropLink implements fs.InodeOperations.DropLink.
+func (d *Dir) DropLink() {
+ d.ramfsDir.DropLink()
+}
+
+// Bind implements fs.InodeOperations.Bind.
+func (d *Dir) Bind(ctx context.Context, dir *fs.Inode, name string, ep transport.BoundEndpoint, perms fs.FilePermissions) (*fs.Dirent, error) {
+ return d.ramfsDir.Bind(ctx, dir, name, ep, perms)
+}
+
+// Create implements fs.InodeOperations.Create.
+func (d *Dir) Create(ctx context.Context, dir *fs.Inode, name string, flags fs.FileFlags, perms fs.FilePermissions) (*fs.File, error) {
+ return d.ramfsDir.Create(ctx, dir, name, flags, perms)
+}
+
+// CreateLink implements fs.InodeOperations.CreateLink.
+func (d *Dir) CreateLink(ctx context.Context, dir *fs.Inode, oldname, newname string) error {
+ return d.ramfsDir.CreateLink(ctx, dir, oldname, newname)
+}
+
+// CreateHardLink implements fs.InodeOperations.CreateHardLink.
+func (d *Dir) CreateHardLink(ctx context.Context, dir *fs.Inode, target *fs.Inode, name string) error {
+ return d.ramfsDir.CreateHardLink(ctx, dir, target, name)
+}
+
+// CreateDirectory implements fs.InodeOperations.CreateDirectory.
+func (d *Dir) CreateDirectory(ctx context.Context, dir *fs.Inode, name string, perms fs.FilePermissions) error {
+ return d.ramfsDir.CreateDirectory(ctx, dir, name, perms)
+}
+
+// CreateFifo implements fs.InodeOperations.CreateFifo.
+func (d *Dir) CreateFifo(ctx context.Context, dir *fs.Inode, name string, perms fs.FilePermissions) error {
+ return d.ramfsDir.CreateFifo(ctx, dir, name, perms)
+}
+
+// Getxattr implements fs.InodeOperations.Getxattr.
+func (d *Dir) Getxattr(i *fs.Inode, name string) ([]byte, error) {
+ return d.ramfsDir.Getxattr(i, name)
+}
+
+// Setxattr implements fs.InodeOperations.Setxattr.
+func (d *Dir) Setxattr(i *fs.Inode, name string, value []byte) error {
+ return d.ramfsDir.Setxattr(i, name, value)
+}
+
+// Listxattr implements fs.InodeOperations.Listxattr.
+func (d *Dir) Listxattr(i *fs.Inode) (map[string]struct{}, error) {
+ return d.ramfsDir.Listxattr(i)
+}
+
+// Lookup implements fs.InodeOperations.Lookup.
+func (d *Dir) Lookup(ctx context.Context, i *fs.Inode, p string) (*fs.Dirent, error) {
+ return d.ramfsDir.Lookup(ctx, i, p)
+}
+
+// NotifyStatusChange implements fs.InodeOperations.NotifyStatusChange.
+func (d *Dir) NotifyStatusChange(ctx context.Context) {
+ d.ramfsDir.NotifyStatusChange(ctx)
+}
+
+// Remove implements fs.InodeOperations.Remove.
+func (d *Dir) Remove(ctx context.Context, i *fs.Inode, name string) error {
+ return d.ramfsDir.Remove(ctx, i, name)
+}
+
+// RemoveDirectory implements fs.InodeOperations.RemoveDirectory.
+func (d *Dir) RemoveDirectory(ctx context.Context, i *fs.Inode, name string) error {
+ return d.ramfsDir.RemoveDirectory(ctx, i, name)
+}
+
+// UnstableAttr implements fs.InodeOperations.UnstableAttr.
+func (d *Dir) UnstableAttr(ctx context.Context, i *fs.Inode) (fs.UnstableAttr, error) {
+ return d.ramfsDir.UnstableAttr(ctx, i)
+}
+
+// SetPermissions implements fs.InodeOperations.SetPermissions.
+func (d *Dir) SetPermissions(ctx context.Context, i *fs.Inode, p fs.FilePermissions) bool {
+ return d.ramfsDir.SetPermissions(ctx, i, p)
+}
+
+// SetOwner implements fs.InodeOperations.SetOwner.
+func (d *Dir) SetOwner(ctx context.Context, i *fs.Inode, owner fs.FileOwner) error {
+ return d.ramfsDir.SetOwner(ctx, i, owner)
+}
+
+// SetTimestamps implements fs.InodeOperations.SetTimestamps.
+func (d *Dir) SetTimestamps(ctx context.Context, i *fs.Inode, ts fs.TimeSpec) error {
+ return d.ramfsDir.SetTimestamps(ctx, i, ts)
}
// newCreateOps builds the custom CreateOps for this Dir.
@@ -132,8 +256,7 @@ type Symlink struct {
// NewSymlink returns a new symlink with the provided permissions.
func NewSymlink(ctx context.Context, target string, owner fs.FileOwner, msrc *fs.MountSource) *fs.Inode {
- s := &Symlink{}
- s.InitSymlink(ctx, owner, target)
+ s := &Symlink{Symlink: *ramfs.NewSymlink(ctx, owner, target)}
return fs.NewInode(s, msrc, fs.StableAttr{
DeviceID: tmpfsDevice.DeviceID(),
InodeID: tmpfsDevice.NextIno(),
@@ -157,12 +280,12 @@ func (s *Symlink) StatFS(context.Context) (fs.Info, error) {
// +stateify savable
type Socket struct {
ramfs.Socket
+ fsutil.InodeNotTruncatable `state:"nosave"`
}
// NewSocket returns a new socket with the provided permissions.
func NewSocket(ctx context.Context, socket transport.BoundEndpoint, owner fs.FileOwner, perms fs.FilePermissions, msrc *fs.MountSource) *fs.Inode {
- s := &Socket{}
- s.InitSocket(ctx, socket, owner, perms)
+ s := &Socket{Socket: *ramfs.NewSocket(ctx, socket, owner, perms)}
return fs.NewInode(s, msrc, fs.StableAttr{
DeviceID: tmpfsDevice.DeviceID(),
InodeID: tmpfsDevice.NextIno(),
@@ -185,15 +308,22 @@ func (s *Socket) StatFS(context.Context) (fs.Info, error) {
//
// +stateify savable
type Fifo struct {
- ramfs.Entry
+ fs.InodeOperations
}
// NewFifo creates a new named pipe.
func NewFifo(ctx context.Context, owner fs.FileOwner, perms fs.FilePermissions, msrc *fs.MountSource) *fs.Inode {
- f := &Fifo{}
- f.InitEntry(ctx, owner, perms)
- iops := pipe.NewInodeOperations(f, pipe.NewPipe(ctx, true /* isNamed */, pipe.DefaultPipeSize, usermem.PageSize))
- return fs.NewInode(iops, msrc, fs.StableAttr{
+ // First create a pipe.
+ p := pipe.NewPipe(ctx, true /* isNamed */, pipe.DefaultPipeSize, usermem.PageSize)
+
+ // Build pipe InodeOperations.
+ iops := pipe.NewInodeOperations(ctx, perms, p)
+
+ // Wrap the iops with our Fifo.
+ fifoIops := &Fifo{iops}
+
+ // Build a new Inode.
+ return fs.NewInode(fifoIops, msrc, fs.StableAttr{
DeviceID: tmpfsDevice.DeviceID(),
InodeID: tmpfsDevice.NextIno(),
BlockSize: usermem.PageSize,