diff options
Diffstat (limited to 'pkg/sentry/fs/tmpfs')
-rw-r--r-- | pkg/sentry/fs/tmpfs/BUILD | 2 | ||||
-rw-r--r-- | pkg/sentry/fs/tmpfs/file_regular.go | 14 | ||||
-rw-r--r-- | pkg/sentry/fs/tmpfs/file_test.go | 6 | ||||
-rw-r--r-- | pkg/sentry/fs/tmpfs/fs.go | 2 | ||||
-rw-r--r-- | pkg/sentry/fs/tmpfs/inode_file.go | 112 | ||||
-rw-r--r-- | pkg/sentry/fs/tmpfs/tmpfs.go | 164 |
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, |