Remove fs.Handle, ramfs.Entry, and all the DeprecatedFileOperations.

More helper structs have been added to the fsutil package to make it easier to
implement fs.InodeOperations and fs.FileOperations.

PiperOrigin-RevId: 229305982
Change-Id: Ib6f8d3862f4216745116857913dbfa351530223b
This commit is contained in:
Nicolas Lacasse
2019-01-14 20:34:28 -08:00
committed by Shentubot
parent 343ebe9789
commit dc8450b567
100 changed files with 2612 additions and 3209 deletions
+2
View File
@@ -22,8 +22,10 @@ const (
DEVPTS_SUPER_MAGIC = 0x00001cd1
OVERLAYFS_SUPER_MAGIC = 0x794c7630
PIPEFS_MAGIC = 0x50495045
PROC_SUPER_MAGIC = 0x9fa0
RAMFS_MAGIC = 0x09041934
SOCKFS_MAGIC = 0x534F434B
SYSFS_MAGIC = 0x62656572
TMPFS_MAGIC = 0x01021994
V9FS_MAGIC = 0x01021997
)
+2 -1
View File
@@ -94,7 +94,8 @@ go_test(
deps = [
":fs",
"//pkg/sentry/context",
"//pkg/sentry/fs/ramfs/test",
"//pkg/sentry/fs/fsutil",
"//pkg/sentry/fs/ramfs",
"//pkg/sentry/fs/tmpfs",
"//pkg/sentry/kernel/contexttest",
"//pkg/sentry/usermem",
+6 -10
View File
@@ -28,16 +28,12 @@ import (
// with any real filesystem. Some types depend on completely pseudo
// "anon" inodes (eventfds, epollfds, etc).
func NewInode(ctx context.Context) *fs.Inode {
return fs.NewInode(fsutil.NewSimpleInodeOperations(fsutil.InodeSimpleAttributes{
FSType: linux.ANON_INODE_FS_MAGIC,
UAttr: fs.WithCurrentTime(ctx, fs.UnstableAttr{
Owner: fs.FileOwnerFromContext(ctx),
Perms: fs.FilePermissions{
User: fs.PermMask{Read: true, Write: true},
},
Links: 1,
}),
}), fs.NewNonCachingMountSource(nil, fs.MountSourceFlags{}), fs.StableAttr{
iops := &fsutil.SimpleFileInode{
InodeSimpleAttributes: fsutil.NewInodeSimpleAttributes(ctx, fs.RootOwner, fs.FilePermissions{
User: fs.PermMask{Read: true, Write: true},
}, linux.ANON_INODE_FS_MAGIC),
}
return fs.NewInode(iops, fs.NewPseudoMountSource(), fs.StableAttr{
Type: fs.Anonymous,
DeviceID: PseudoDevice.DeviceID(),
InodeID: PseudoDevice.NextIno(),
+1
View File
@@ -28,6 +28,7 @@ go_library(
"//pkg/sentry/usage",
"//pkg/sentry/usermem",
"//pkg/syserror",
"//pkg/waiter",
],
)
+6 -10
View File
@@ -28,6 +28,7 @@ import (
"gvisor.googlesource.com/gvisor/pkg/sentry/usage"
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
"gvisor.googlesource.com/gvisor/pkg/syserror"
"gvisor.googlesource.com/gvisor/pkg/waiter"
)
const (
@@ -42,9 +43,10 @@ const (
//
// +stateify savable
type Area struct {
fsutil.NoFsync `state:"nosave"`
fsutil.DeprecatedFileOperations `state:"nosave"`
fsutil.NotDirReaddir `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
fsutil.FileNoFsync `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
ad *Device
@@ -98,11 +100,6 @@ func (a *Area) Write(ctx context.Context, file *fs.File, src usermem.IOSequence,
return 0, syserror.ENOSYS
}
// Flush implements fs.FileOperations.Flush.
func (a *Area) Flush(ctx context.Context, file *fs.File) error {
return nil
}
// ConfigureMMap implements fs.FileOperations.ConfigureMMap.
func (a *Area) ConfigureMMap(ctx context.Context, file *fs.File, opts *memmap.MMapOpts) error {
a.mu.Lock()
@@ -122,8 +119,7 @@ func (a *Area) ConfigureMMap(ctx context.Context, file *fs.File, opts *memmap.MM
return syserror.ENOMEM
}
tmpfsInodeOps := tmpfs.NewInMemoryFile(ctx, usage.Tmpfs, fs.UnstableAttr{}, k)
// This is not backed by a real filesystem, so we pass in nil.
tmpfsInode := fs.NewInode(tmpfsInodeOps, fs.NewNonCachingMountSource(nil, fs.MountSourceFlags{}), fs.StableAttr{})
tmpfsInode := fs.NewInode(tmpfsInodeOps, fs.NewPseudoMountSource(), fs.StableAttr{})
dirent := fs.NewDirent(tmpfsInode, namePrefix+"/"+a.name)
tmpfsFile, err := tmpfsInode.GetFile(ctx, dirent, fs.FileFlags{Read: true, Write: true})
// Drop the extra reference on the Dirent.
+11 -122
View File
@@ -16,49 +16,40 @@
package ashmem
import (
"sync"
"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/kernel/time"
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
"gvisor.googlesource.com/gvisor/pkg/syserror"
)
// Device implements fs.InodeOperations.
//
// +stateify savable
type Device struct {
fsutil.DeprecatedFileOperations `state:"nosave"`
fsutil.InodeGenericChecker `state:"nosave"`
fsutil.InodeNoExtendedAttributes `state:"nosave"`
fsutil.InodeNoopRelease `state:"nosave"`
fsutil.InodeNoopTruncate `state:"nosave"`
fsutil.InodeNoopWriteOut `state:"nosave"`
fsutil.InodeNotDirectory `state:"nosave"`
fsutil.InodeNotRenameable `state:"nosave"`
fsutil.InodeNotMappable `state:"nosave"`
fsutil.InodeNotSocket `state:"nosave"`
fsutil.InodeNotSymlink `state:"nosave"`
fsutil.NoFsync `state:"nosave"`
fsutil.NoMappable `state:"nosave"`
fsutil.NoopWriteOut `state:"nosave"`
fsutil.NotDirReaddir `state:"nosave"`
fsutil.InodeVirtual `state:"nosave"`
mu sync.Mutex `state:"nosave"`
unstable fs.UnstableAttr
fsutil.InodeSimpleAttributes
}
var _ fs.InodeOperations = (*Device)(nil)
// NewDevice creates and intializes a Device structure.
func NewDevice(ctx context.Context, owner fs.FileOwner, fp fs.FilePermissions) *Device {
return &Device{
unstable: fs.WithCurrentTime(ctx, fs.UnstableAttr{
Owner: owner,
Perms: fp,
Links: 1,
}),
InodeSimpleAttributes: fsutil.NewInodeSimpleAttributes(ctx, owner, fp, linux.ANON_INODE_FS_MAGIC),
}
}
// Release implements fs.InodeOperations.Release.
func (ad *Device) Release(context.Context) {}
// GetFile implements fs.InodeOperations.GetFile.
func (ad *Device) GetFile(ctx context.Context, d *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
return fs.NewFile(ctx, d, flags, &Area{
@@ -67,105 +58,3 @@ func (ad *Device) GetFile(ctx context.Context, d *fs.Dirent, flags fs.FileFlags)
perms: usermem.AnyAccess,
}), nil
}
// UnstableAttr implements fs.InodeOperations.UnstableAttr.
func (ad *Device) UnstableAttr(ctx context.Context, inode *fs.Inode) (fs.UnstableAttr, error) {
ad.mu.Lock()
defer ad.mu.Unlock()
return ad.unstable, nil
}
// Check implements fs.InodeOperations.Check.
func (ad *Device) Check(ctx context.Context, inode *fs.Inode, p fs.PermMask) bool {
return fs.ContextCanAccessFile(ctx, inode, p)
}
// SetPermissions implements fs.InodeOperations.SetPermissions.
func (ad *Device) SetPermissions(ctx context.Context, inode *fs.Inode, fp fs.FilePermissions) bool {
ad.mu.Lock()
defer ad.mu.Unlock()
ad.unstable.Perms = fp
ad.unstable.StatusChangeTime = time.NowFromContext(ctx)
return true
}
// SetOwner implements fs.InodeOperations.SetOwner.
func (ad *Device) SetOwner(ctx context.Context, inode *fs.Inode, owner fs.FileOwner) error {
ad.mu.Lock()
defer ad.mu.Unlock()
if owner.UID.Ok() {
ad.unstable.Owner.UID = owner.UID
}
if owner.GID.Ok() {
ad.unstable.Owner.GID = owner.GID
}
return nil
}
// SetTimestamps implements fs.InodeOperations.SetTimestamps.
func (ad *Device) SetTimestamps(ctx context.Context, inode *fs.Inode, ts fs.TimeSpec) error {
if ts.ATimeOmit && ts.MTimeOmit {
return nil
}
ad.mu.Lock()
defer ad.mu.Unlock()
now := time.NowFromContext(ctx)
if !ts.ATimeOmit {
if ts.ATimeSetSystemTime {
ad.unstable.AccessTime = now
} else {
ad.unstable.AccessTime = ts.ATime
}
}
if !ts.MTimeOmit {
if ts.MTimeSetSystemTime {
ad.unstable.ModificationTime = now
} else {
ad.unstable.ModificationTime = ts.MTime
}
}
ad.unstable.StatusChangeTime = now
return nil
}
// Truncate implements fs.InodeOperations.WriteOut.
//
// Ignored by ashmem.
func (ad *Device) Truncate(ctx context.Context, inode *fs.Inode, size int64) error {
return nil
}
// AddLink implements fs.InodeOperations.AddLink.
//
// Ashmem doesn't support links, no-op.
func (ad *Device) AddLink() {}
// DropLink implements fs.InodeOperations.DropLink.
//
// Ashmem doesn't support links, no-op.
func (ad *Device) DropLink() {}
// NotifyStatusChange implements fs.InodeOperations.NotifyStatusChange.
func (ad *Device) NotifyStatusChange(ctx context.Context) {
ad.mu.Lock()
defer ad.mu.Unlock()
now := time.NowFromContext(ctx)
ad.unstable.ModificationTime = now
ad.unstable.StatusChangeTime = now
}
// IsVirtual implements fs.InodeOperations.IsVirtual.
//
// Ashmem is virtual.
func (ad *Device) IsVirtual() bool {
return true
}
// StatFS implements fs.InodeOperations.StatFS.
//
// Ashmem doesn't support querying for filesystem info.
func (ad *Device) StatFS(context.Context) (fs.Info, error) {
return fs.Info{}, syserror.ENOSYS
}
+47
View File
@@ -180,6 +180,53 @@ type UnstableAttr struct {
Links uint64
}
// SetOwner sets the owner and group if they are valid.
//
// This method is NOT thread-safe. Callers must prevent concurrent calls.
func (ua *UnstableAttr) SetOwner(ctx context.Context, owner FileOwner) {
if owner.UID.Ok() {
ua.Owner.UID = owner.UID
}
if owner.GID.Ok() {
ua.Owner.GID = owner.GID
}
ua.StatusChangeTime = ktime.NowFromContext(ctx)
}
// SetPermissions sets the permissions.
//
// This method is NOT thread-safe. Callers must prevent concurrent calls.
func (ua *UnstableAttr) SetPermissions(ctx context.Context, p FilePermissions) {
ua.Perms = p
ua.StatusChangeTime = ktime.NowFromContext(ctx)
}
// SetTimestamps sets the timestamps according to the TimeSpec.
//
// This method is NOT thread-safe. Callers must prevent concurrent calls.
func (ua *UnstableAttr) SetTimestamps(ctx context.Context, ts TimeSpec) {
if ts.ATimeOmit && ts.MTimeOmit {
return
}
now := ktime.NowFromContext(ctx)
if !ts.ATimeOmit {
if ts.ATimeSetSystemTime {
ua.AccessTime = now
} else {
ua.AccessTime = ts.ATime
}
}
if !ts.MTimeOmit {
if ts.MTimeSetSystemTime {
ua.ModificationTime = now
} else {
ua.ModificationTime = ts.MTime
}
}
ua.StatusChangeTime = now
}
// WithCurrentTime returns u with AccessTime == ModificationTime == current time.
func WithCurrentTime(ctx context.Context, u UnstableAttr) UnstableAttr {
t := ktime.NowFromContext(ctx)
+1 -1
View File
@@ -16,11 +16,11 @@ go_library(
"//pkg/sentry/fs",
"//pkg/sentry/fs/fsutil",
"//pkg/sentry/kernel",
"//pkg/sentry/kernel/time",
"//pkg/sentry/memmap",
"//pkg/sentry/platform",
"//pkg/sentry/usage",
"//pkg/sentry/usermem",
"//pkg/syserror",
"//pkg/waiter",
],
)
+14 -121
View File
@@ -24,12 +24,12 @@ import (
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs/fsutil"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel/time"
"gvisor.googlesource.com/gvisor/pkg/sentry/memmap"
"gvisor.googlesource.com/gvisor/pkg/sentry/platform"
"gvisor.googlesource.com/gvisor/pkg/sentry/usage"
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
"gvisor.googlesource.com/gvisor/pkg/syserror"
"gvisor.googlesource.com/gvisor/pkg/waiter"
)
const (
@@ -43,34 +43,29 @@ const (
//
// +stateify savable
type Device struct {
fsutil.InodeGenericChecker `state:"nosave"`
fsutil.InodeNoExtendedAttributes `state:"nosave"`
fsutil.InodeNoopRelease `state:"nosave"`
fsutil.InodeNoopTruncate `state:"nosave"`
fsutil.InodeNoopWriteOut `state:"nosave"`
fsutil.InodeNotDirectory `state:"nosave"`
fsutil.InodeNotRenameable `state:"nosave"`
fsutil.InodeNotMappable `state:"nosave"`
fsutil.InodeNotSocket `state:"nosave"`
fsutil.InodeNotSymlink `state:"nosave"`
fsutil.NoMappable `state:"nosave"`
fsutil.NoopWriteOut `state:"nosave"`
fsutil.DeprecatedFileOperations `state:"nosave"`
fsutil.InodeVirtual `state:"nosave"`
// mu protects unstable.
mu sync.Mutex `state:"nosave"`
unstable fs.UnstableAttr
fsutil.InodeSimpleAttributes
}
var _ fs.InodeOperations = (*Device)(nil)
// NewDevice creates and intializes a Device structure.
func NewDevice(ctx context.Context, owner fs.FileOwner, fp fs.FilePermissions) *Device {
return &Device{
unstable: fs.WithCurrentTime(ctx, fs.UnstableAttr{
Owner: owner,
Perms: fp,
Links: 1,
}),
InodeSimpleAttributes: fsutil.NewInodeSimpleAttributes(ctx, owner, fp, 0),
}
}
// Release implements fs.InodeOperations.Release.
func (bd *Device) Release(context.Context) {}
// GetFile implements fs.InodeOperations.GetFile.
//
// TODO: Add functionality to GetFile: Additional fields will be
@@ -85,115 +80,13 @@ func (bd *Device) GetFile(ctx context.Context, d *fs.Dirent, flags fs.FileFlags)
}), nil
}
// UnstableAttr implements fs.InodeOperations.UnstableAttr.
func (bd *Device) UnstableAttr(ctx context.Context, inode *fs.Inode) (fs.UnstableAttr, error) {
bd.mu.Lock()
defer bd.mu.Unlock()
return bd.unstable, nil
}
// Check implements fs.InodeOperations.Check.
func (bd *Device) Check(ctx context.Context, inode *fs.Inode, p fs.PermMask) bool {
return fs.ContextCanAccessFile(ctx, inode, p)
}
// SetPermissions implements fs.InodeOperations.SetPermissions.
func (bd *Device) SetPermissions(ctx context.Context, inode *fs.Inode, fp fs.FilePermissions) bool {
bd.mu.Lock()
defer bd.mu.Unlock()
bd.unstable.Perms = fp
bd.unstable.StatusChangeTime = time.NowFromContext(ctx)
return true
}
// SetOwner implements fs.InodeOperations.SetOwner.
func (bd *Device) SetOwner(ctx context.Context, inode *fs.Inode, owner fs.FileOwner) error {
bd.mu.Lock()
defer bd.mu.Unlock()
if owner.UID.Ok() {
bd.unstable.Owner.UID = owner.UID
}
if owner.GID.Ok() {
bd.unstable.Owner.GID = owner.GID
}
return nil
}
// SetTimestamps implements fs.InodeOperations.SetTimestamps.
func (bd *Device) SetTimestamps(ctx context.Context, inode *fs.Inode, ts fs.TimeSpec) error {
if ts.ATimeOmit && ts.MTimeOmit {
return nil
}
bd.mu.Lock()
defer bd.mu.Unlock()
now := time.NowFromContext(ctx)
if !ts.ATimeOmit {
if ts.ATimeSetSystemTime {
bd.unstable.AccessTime = now
} else {
bd.unstable.AccessTime = ts.ATime
}
}
if !ts.MTimeOmit {
if ts.MTimeSetSystemTime {
bd.unstable.ModificationTime = now
} else {
bd.unstable.ModificationTime = ts.MTime
}
}
bd.unstable.StatusChangeTime = now
return nil
}
// Truncate implements fs.InodeOperations.WriteOut.
//
// Ignored for a character device, such as Binder.
func (bd *Device) Truncate(ctx context.Context, inode *fs.Inode, size int64) error {
return nil
}
// AddLink implements fs.InodeOperations.AddLink.
//
// Binder doesn't support links, no-op.
func (bd *Device) AddLink() {}
// DropLink implements fs.InodeOperations.DropLink.
//
// Binder doesn't support links, no-op.
func (bd *Device) DropLink() {}
// NotifyStatusChange implements fs.InodeOperations.NotifyStatusChange.
func (bd *Device) NotifyStatusChange(ctx context.Context) {
bd.mu.Lock()
defer bd.mu.Unlock()
now := time.NowFromContext(ctx)
bd.unstable.ModificationTime = now
bd.unstable.StatusChangeTime = now
}
// IsVirtual implements fs.InodeOperations.IsVirtual.
//
// Binder is virtual.
func (bd *Device) IsVirtual() bool {
return true
}
// StatFS implements fs.InodeOperations.StatFS.
//
// Binder doesn't support querying for filesystem info.
func (bd *Device) StatFS(context.Context) (fs.Info, error) {
return fs.Info{}, syserror.ENOSYS
}
// Proc implements fs.FileOperations and fs.IoctlGetter.
//
// +stateify savable
type Proc struct {
fsutil.NoFsync `state:"nosave"`
fsutil.DeprecatedFileOperations `state:"nosave"`
fsutil.NotDirReaddir `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
fsutil.FileNoFsync `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
bd *Device
task *kernel.Task
+1
View File
@@ -32,5 +32,6 @@ go_library(
"//pkg/sentry/safemem",
"//pkg/sentry/usermem",
"//pkg/syserror",
"//pkg/waiter",
],
)
+14 -15
View File
@@ -16,6 +16,8 @@
package dev
import (
"math"
"gvisor.googlesource.com/gvisor/pkg/sentry/context"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs/ashmem"
@@ -26,13 +28,6 @@ import (
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
)
// Dev is the root node.
//
// +stateify savable
type Dev struct {
ramfs.Dir
}
func newCharacterDevice(iops fs.InodeOperations, msrc *fs.MountSource) *fs.Inode {
return fs.NewInode(iops, msrc, fs.StableAttr{
DeviceID: devDevice.DeviceID(),
@@ -43,8 +38,7 @@ func newCharacterDevice(iops fs.InodeOperations, msrc *fs.MountSource) *fs.Inode
}
func newDirectory(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
iops := &ramfs.Dir{}
iops.InitDir(ctx, map[string]*fs.Inode{}, fs.RootOwner, fs.FilePermsFromMode(0555))
iops := ramfs.NewDir(ctx, nil, fs.RootOwner, fs.FilePermsFromMode(0555))
return fs.NewInode(iops, msrc, fs.StableAttr{
DeviceID: devDevice.DeviceID(),
InodeID: devDevice.NextIno(),
@@ -54,8 +48,7 @@ func newDirectory(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
}
func newSymlink(ctx context.Context, target string, msrc *fs.MountSource) *fs.Inode {
iops := &ramfs.Symlink{}
iops.InitSymlink(ctx, fs.RootOwner, target)
iops := ramfs.NewSymlink(ctx, fs.RootOwner, target)
return fs.NewInode(iops, msrc, fs.StableAttr{
DeviceID: devDevice.DeviceID(),
InodeID: devDevice.NextIno(),
@@ -66,8 +59,6 @@ func newSymlink(ctx context.Context, target string, msrc *fs.MountSource) *fs.In
// New returns the root node of a device filesystem.
func New(ctx context.Context, msrc *fs.MountSource, binderEnabled bool, ashmemEnabled bool) *fs.Inode {
d := &Dev{}
contents := map[string]*fs.Inode{
"fd": newSymlink(ctx, "/proc/self/fd", msrc),
"stdin": newSymlink(ctx, "/proc/self/fd/0", msrc),
@@ -114,11 +105,19 @@ func New(ctx context.Context, msrc *fs.MountSource, binderEnabled bool, ashmemEn
contents["ashmem"] = newCharacterDevice(ashmem, msrc)
}
d.InitDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555))
return fs.NewInode(d, msrc, fs.StableAttr{
iops := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555))
return fs.NewInode(iops, msrc, fs.StableAttr{
DeviceID: devDevice.DeviceID(),
InodeID: devDevice.NextIno(),
BlockSize: usermem.PageSize,
Type: fs.Directory,
})
}
// readZeros implements fs.FileOperations.Read with infinite null bytes.
type readZeros struct{}
// Read implements fs.FileOperations.Read.
func (readZeros) Read(ctx context.Context, file *fs.File, dst usermem.IOSequence, offset int64) (int64, error) {
return dst.ZeroOut(ctx, math.MaxInt64)
}
+2
View File
@@ -33,6 +33,8 @@ const ashmemEnabledKey = "ashmem_enabled"
// +stateify savable
type filesystem struct{}
var _ fs.Filesystem = (*filesystem)(nil)
func init() {
fs.RegisterFilesystem(&filesystem{})
}
+42 -19
View File
@@ -15,41 +15,64 @@
package dev
import (
"math"
"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/ramfs"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs/fsutil"
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
"gvisor.googlesource.com/gvisor/pkg/syserror"
"gvisor.googlesource.com/gvisor/pkg/waiter"
)
// fullDevice is used to implement /dev/full.
//
// +stateify savable
type fullDevice struct {
ramfs.Entry
fsutil.InodeGenericChecker `state:"nosave"`
fsutil.InodeNoExtendedAttributes `state:"nosave"`
fsutil.InodeNoopRelease `state:"nosave"`
fsutil.InodeNoopTruncate `state:"nosave"`
fsutil.InodeNoopWriteOut `state:"nosave"`
fsutil.InodeNotDirectory `state:"nosave"`
fsutil.InodeNotMappable `state:"nosave"`
fsutil.InodeNotSocket `state:"nosave"`
fsutil.InodeNotSymlink `state:"nosave"`
fsutil.InodeVirtual `state:"nosave"`
fsutil.InodeSimpleAttributes
}
var _ fs.InodeOperations = (*fullDevice)(nil)
func newFullDevice(ctx context.Context, owner fs.FileOwner, mode linux.FileMode) *fullDevice {
f := &fullDevice{}
f.InitEntry(ctx, owner, fs.FilePermsFromMode(mode))
f := &fullDevice{
InodeSimpleAttributes: fsutil.NewInodeSimpleAttributes(ctx, owner, fs.FilePermsFromMode(mode), linux.TMPFS_MAGIC),
}
return f
}
// DeprecatedPwritev implements fs.InodeOperations.DeprecatedPwritev by
// returining ENOSPC.
func (f *fullDevice) DeprecatedPwritev(_ context.Context, _ usermem.IOSequence, _ int64) (int64, error) {
// GetFile implements fs.InodeOperations.GetFile.
func (f *fullDevice) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
flags.Pread = true
return fs.NewFile(ctx, dirent, flags, &fullFileOperations{}), nil
}
// +stateify savable
type fullFileOperations struct {
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
readZeros `state:"nosave"`
}
var _ fs.FileOperations = (*fullFileOperations)(nil)
// Write implements FileOperations.Write.
func (fullFileOperations) Write(context.Context, *fs.File, usermem.IOSequence, int64) (int64, error) {
return 0, syserror.ENOSPC
}
// DeprecatedPreadv implements fs.InodeOperations.DeprecatedPreadv.
func (f *fullDevice) DeprecatedPreadv(ctx context.Context, dst usermem.IOSequence, _ int64) (int64, error) {
return dst.ZeroOut(ctx, math.MaxInt64)
}
// Truncate should be simply ignored for character devices on linux.
func (f *fullDevice) Truncate(context.Context, *fs.Inode, int64) error {
return nil
}
+57 -31
View File
@@ -15,78 +15,104 @@
package dev
import (
"io"
"math"
"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/memmap"
"gvisor.googlesource.com/gvisor/pkg/sentry/mm"
"gvisor.googlesource.com/gvisor/pkg/sentry/platform"
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
"gvisor.googlesource.com/gvisor/pkg/waiter"
)
// +stateify savable
type nullDevice struct {
ramfs.Entry
fsutil.InodeGenericChecker `state:"nosave"`
fsutil.InodeNoExtendedAttributes `state:"nosave"`
fsutil.InodeNoopRelease `state:"nosave"`
fsutil.InodeNoopTruncate `state:"nosave"`
fsutil.InodeNoopWriteOut `state:"nosave"`
fsutil.InodeNotDirectory `state:"nosave"`
fsutil.InodeNotMappable `state:"nosave"`
fsutil.InodeNotSocket `state:"nosave"`
fsutil.InodeNotSymlink `state:"nosave"`
fsutil.InodeVirtual `state:"nosave"`
fsutil.InodeSimpleAttributes
}
var _ fs.InodeOperations = (*nullDevice)(nil)
func newNullDevice(ctx context.Context, owner fs.FileOwner, mode linux.FileMode) *nullDevice {
n := &nullDevice{}
n.InitEntry(ctx, owner, fs.FilePermsFromMode(mode))
n := &nullDevice{
InodeSimpleAttributes: fsutil.NewInodeSimpleAttributes(ctx, owner, fs.FilePermsFromMode(mode), linux.TMPFS_MAGIC),
}
return n
}
// DeprecatedPreadv reads data from the device.
func (n *nullDevice) DeprecatedPreadv(ctx context.Context, dst usermem.IOSequence, offset int64) (int64, error) {
return 0, io.EOF
// GetFile implements fs.FileOperations.GetFile.
func (n *nullDevice) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
flags.Pread = true
flags.Pwrite = true
return fs.NewFile(ctx, dirent, flags, &nullFileOperations{}), nil
}
// DeprecatedPwritev discards writes.
func (n *nullDevice) DeprecatedPwritev(_ context.Context, src usermem.IOSequence, offset int64) (int64, error) {
return src.NumBytes(), nil
// +stateify savable
type nullFileOperations struct {
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopRead `state:"nosave"`
fsutil.FileNoopWrite `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
}
// Truncate should be simply ignored for character devices on linux.
func (n *nullDevice) Truncate(context.Context, *fs.Inode, int64) error {
return nil
}
var _ fs.FileOperations = (*nullFileOperations)(nil)
// +stateify savable
type zeroDevice struct {
nullDevice
}
var _ fs.InodeOperations = (*zeroDevice)(nil)
func newZeroDevice(ctx context.Context, owner fs.FileOwner, mode linux.FileMode) *zeroDevice {
zd := &zeroDevice{}
zd.InitEntry(ctx, owner, fs.FilePermsFromMode(mode))
zd := &zeroDevice{
nullDevice: nullDevice{
InodeSimpleAttributes: fsutil.NewInodeSimpleAttributes(ctx, owner, fs.FilePermsFromMode(mode), linux.TMPFS_MAGIC),
},
}
return zd
}
// DeprecatedPreadv implements fs.InodeOperations.DeprecatedPreadv.
func (zd *zeroDevice) DeprecatedPreadv(ctx context.Context, dst usermem.IOSequence, offset int64) (int64, error) {
return dst.ZeroOut(ctx, math.MaxInt64)
}
// GetFile overrides ramfs.Entry.GetFile and returns a zeroFile instead.
// GetFile implements fs.FileOperations.GetFile.
func (zd *zeroDevice) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
// Allow pread(2) and pwrite(2) on this file.
flags.Pread = true
flags.Pwrite = true
return fs.NewFile(ctx, dirent, flags, &zeroFileOperations{
FileOperations: &fsutil.Handle{HandleOperations: dirent.Inode.HandleOps()},
}), nil
return fs.NewFile(ctx, dirent, flags, &zeroFileOperations{}), nil
}
// +stateify savable
type zeroFileOperations struct {
fs.FileOperations
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNoopWrite `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
readZeros `state:"nosave"`
}
var _ fs.FileOperations = (*zeroFileOperations)(nil)
// ConfigureMMap implements fs.FileOperations.ConfigureMMap.
func (*zeroFileOperations) ConfigureMMap(ctx context.Context, file *fs.File, opts *memmap.MMapOpts) error {
m, err := mm.NewSharedAnonMappable(opts.Length, platform.FromContext(ctx))
+41 -20
View File
@@ -19,37 +19,58 @@ import (
"gvisor.googlesource.com/gvisor/pkg/rand"
"gvisor.googlesource.com/gvisor/pkg/sentry/context"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs/ramfs"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs/fsutil"
"gvisor.googlesource.com/gvisor/pkg/sentry/safemem"
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
"gvisor.googlesource.com/gvisor/pkg/waiter"
)
// +stateify savable
type randomDevice struct {
ramfs.Entry
fsutil.InodeGenericChecker `state:"nosave"`
fsutil.InodeNoExtendedAttributes `state:"nosave"`
fsutil.InodeNoopRelease `state:"nosave"`
fsutil.InodeNoopTruncate `state:"nosave"`
fsutil.InodeNoopWriteOut `state:"nosave"`
fsutil.InodeNotDirectory `state:"nosave"`
fsutil.InodeNotMappable `state:"nosave"`
fsutil.InodeNotSocket `state:"nosave"`
fsutil.InodeNotSymlink `state:"nosave"`
fsutil.InodeVirtual `state:"nosave"`
fsutil.InodeSimpleAttributes
}
var _ fs.InodeOperations = (*randomDevice)(nil)
func newRandomDevice(ctx context.Context, owner fs.FileOwner, mode linux.FileMode) *randomDevice {
r := &randomDevice{}
r.InitEntry(ctx, owner, fs.FilePermsFromMode(mode))
r := &randomDevice{
InodeSimpleAttributes: fsutil.NewInodeSimpleAttributes(ctx, owner, fs.FilePermsFromMode(mode), linux.TMPFS_MAGIC),
}
return r
}
// DeprecatedPreadv reads random data.
func (*randomDevice) DeprecatedPreadv(ctx context.Context, dst usermem.IOSequence, offset int64) (int64, error) {
// GetFile implements fs.InodeOperations.GetFile.
func (randomDevice) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
return fs.NewFile(ctx, dirent, flags, &randomFileOperations{}), nil
}
// +stateify savable
type randomFileOperations struct {
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNoopWrite `state:"nosave"`
}
var _ fs.FileOperations = (*randomFileOperations)(nil)
// Read implements fs.FileOperations.Read.
func (randomFileOperations) Read(ctx context.Context, _ *fs.File, dst usermem.IOSequence, _ int64) (int64, error) {
return dst.CopyOutFrom(ctx, safemem.FromIOReader{rand.Reader})
}
// DeprecatedPwritev implements fs.HandleOperations.DeprecatedPwritev.
func (*randomDevice) DeprecatedPwritev(ctx context.Context, src usermem.IOSequence, offset int64) (int64, error) {
// On Linux, "Writing to /dev/random or /dev/urandom will update the
// entropy pool with the data written, but this will not result in a higher
// entropy count" - random(4). We don't need to support this, but we do
// need to support the write, so just make it a no-op a la /dev/null.
return src.NumBytes(), nil
}
// Truncate should be simply ignored for character devices on linux.
func (r *randomDevice) Truncate(context.Context, *fs.Inode, int64) error {
return nil
}
+4 -4
View File
@@ -837,8 +837,8 @@ func (d *Dirent) CreateFifo(ctx context.Context, root *Dirent, name string, perm
})
}
// getDotAttrs returns the DentAttrs corresponding to "." and ".." directories.
func (d *Dirent) getDotAttrs(root *Dirent) (DentAttr, DentAttr) {
// GetDotAttrs returns the DentAttrs corresponding to "." and ".." directories.
func (d *Dirent) GetDotAttrs(root *Dirent) (DentAttr, DentAttr) {
// Get '.'.
sattr := d.Inode.StableAttr
dot := DentAttr{
@@ -870,7 +870,7 @@ func (d *Dirent) readdirFrozen(root *Dirent, offset int64, dirCtx *DirCtx) (int6
// Collect attrs for "." and "..".
attrs := make(map[string]DentAttr)
names := []string{".", ".."}
attrs["."], attrs[".."] = d.getDotAttrs(root)
attrs["."], attrs[".."] = d.GetDotAttrs(root)
// Get info from all children.
d.mu.Lock()
@@ -965,7 +965,7 @@ func direntReaddir(ctx context.Context, d *Dirent, it DirIterator, root *Dirent,
}
// Collect attrs for "." and "..".
dot, dotdot := d.getDotAttrs(root)
dot, dotdot := d.GetDotAttrs(root)
// Emit "." and ".." if the offset is low enough.
if offset == 0 {
+7 -7
View File
@@ -37,13 +37,13 @@ import (
//
// +stateify savable
type pipeOperations struct {
fsutil.PipeSeek `state:"nosave"`
fsutil.NotDirReaddir `state:"nosave"`
fsutil.NoFsync `state:"nosave"`
fsutil.NoopFlush `state:"nosave"`
fsutil.NoMMap `state:"nosave"`
fsutil.NoIoctl `state:"nosave"`
waiter.Queue `state:"nosave"`
fsutil.FilePipeSeek `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileNoFsync `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
waiter.Queue `state:"nosave"`
// flags are the flags used to open the pipe.
flags fs.FileFlags `state:".(fs.FileFlags)"`
+1 -1
View File
@@ -91,7 +91,7 @@ type FileOperations interface {
Flush(ctx context.Context, file *File) error
// ConfigureMMap mutates opts to implement mmap(2) for the file. Most
// implementations can either embed fsutil.NoMMap (if they don't support
// implementations can either embed fsutil.FileNoMMap (if they don't support
// memory mapping) or call fsutil.GenericConfigureMMap with the appropriate
// memmap.Mappable.
ConfigureMMap(ctx context.Context, file *File, opts *memmap.MMapOpts) error
+4 -3
View File
@@ -20,7 +20,8 @@ import (
"gvisor.googlesource.com/gvisor/pkg/sentry/context"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
ramfstest "gvisor.googlesource.com/gvisor/pkg/sentry/fs/ramfs/test"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs/fsutil"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs/ramfs"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel/contexttest"
)
@@ -135,7 +136,7 @@ func TestReaddirRevalidation(t *testing.T) {
// Get a handle to the dirent in the upper filesystem so that we can
// modify it without going through the dirent.
upperDir := upper.InodeOperations.(*dir).InodeOperations.(*ramfstest.Dir)
upperDir := upper.InodeOperations.(*dir).InodeOperations.(*ramfs.Dir)
// Check that overlay returns the files from both upper and lower.
openDir, err := overlay.GetFile(ctx, fs.NewDirent(overlay, "stub"), fs.FileFlags{Read: true})
@@ -155,7 +156,7 @@ func TestReaddirRevalidation(t *testing.T) {
if err := upperDir.Remove(ctx, upper, "a"); err != nil {
t.Fatalf("error removing child: %v", err)
}
upperDir.AddChild(ctx, "c", fs.NewInode(ramfstest.NewFile(ctx, fs.FilePermissions{}),
upperDir.AddChild(ctx, "c", fs.NewInode(fsutil.NewSimpleFileInode(ctx, fs.RootOwner, fs.FilePermissions{}, 0),
upper.MountSource, fs.StableAttr{Type: fs.RegularFile}))
// Seek to beginning of the directory and do the readdir again.
+8 -8
View File
@@ -31,14 +31,14 @@ import (
// TestFileOperations is an implementation of the File interface. It provides all
// required methods.
type TestFileOperations struct {
fsutil.NoopRelease `state:"nosave"`
fsutil.PipeSeek `state:"nosave"`
fsutil.NotDirReaddir `state:"nosave"`
fsutil.NoFsync `state:"nosave"`
fsutil.NoopFlush `state:"nosave"`
fsutil.NoMMap `state:"nosave"`
fsutil.NoIoctl `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FilePipeSeek `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileNoFsync `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
}
// NewTestFile creates and initializes a new test file.

Some files were not shown because too many files have changed in this diff Show More