diff options
Diffstat (limited to 'pkg/sentry/fs/ext/ext.go')
-rw-r--r-- | pkg/sentry/fs/ext/ext.go | 70 |
1 files changed, 61 insertions, 9 deletions
diff --git a/pkg/sentry/fs/ext/ext.go b/pkg/sentry/fs/ext/ext.go index 7f4287b01..c8b554f4d 100644 --- a/pkg/sentry/fs/ext/ext.go +++ b/pkg/sentry/fs/ext/ext.go @@ -16,17 +16,34 @@ package ext import ( + "errors" + "fmt" "io" + "os" "sync" "gvisor.dev/gvisor/pkg/abi/linux" + "gvisor.dev/gvisor/pkg/sentry/context" "gvisor.dev/gvisor/pkg/sentry/fs/ext/disklayout" + "gvisor.dev/gvisor/pkg/sentry/kernel/auth" + "gvisor.dev/gvisor/pkg/sentry/vfs" "gvisor.dev/gvisor/pkg/syserror" ) +// filesystemType implements vfs.FilesystemType. +type filesystemType struct{} + +// Compiles only if filesystemType implements vfs.FilesystemType. +var _ vfs.FilesystemType = (*filesystemType)(nil) + // filesystem implements vfs.FilesystemImpl. type filesystem struct { - // mu serializes changes to the Dentry tree and the usage of the read seeker. + // TODO(b/134676337): Remove when all methods have been implemented. + vfs.FilesystemImpl + + vfsfs vfs.Filesystem + + // mu serializes changes to the dentry tree and the usage of the read seeker. mu sync.Mutex // dev is the ReadSeeker for the underlying fs device. It is protected by mu. @@ -58,28 +75,63 @@ type filesystem struct { bgs []disklayout.BlockGroup } -// newFilesystem is the filesystem constructor. -func newFilesystem(dev io.ReadSeeker) (*filesystem, error) { - fs := filesystem{dev: dev, inodeCache: make(map[uint32]*inode)} - var err error +// Compiles only if filesystem implements vfs.FilesystemImpl. +var _ vfs.FilesystemImpl = (*filesystem)(nil) + +// getDeviceFd returns the read seeker to the underlying device. +// Currently there are two ways of mounting an ext(2/3/4) fs: +// 1. Specify a mount with our internal special MountType in the OCI spec. +// 2. Expose the device to the container and mount it from application layer. +func getDeviceFd(source string, opts vfs.NewFilesystemOptions) (io.ReadSeeker, error) { + if opts.InternalData == nil { + // User mount call. + // TODO(b/134676337): Open the device specified by `source` and return that. + panic("unimplemented") + } + + // NewFilesystem call originated from within the sentry. + fd, ok := opts.InternalData.(uintptr) + if !ok { + return nil, errors.New("internal data for ext fs must be a uintptr containing the file descriptor to device") + } + + // We do not close this file because that would close the underlying device + // file descriptor (which is required for reading the fs from disk). + // TODO(b/134676337): Use pkg/fd instead. + deviceFile := os.NewFile(fd, source) + if deviceFile == nil { + return nil, fmt.Errorf("ext4 device file descriptor is not valid: %d", fd) + } + + return deviceFile, nil +} +// 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) { + dev, err := getDeviceFd(source, opts) + if err != nil { + return nil, nil, err + } + + fs := filesystem{dev: dev, inodeCache: make(map[uint32]*inode)} + fs.vfsfs.Init(&fs) fs.sb, err = readSuperBlock(dev) if err != nil { - return nil, err + return nil, nil, err } if fs.sb.Magic() != linux.EXT_SUPER_MAGIC { // mount(2) specifies that EINVAL should be returned if the superblock is // invalid. - return nil, syserror.EINVAL + return nil, nil, syserror.EINVAL } fs.bgs, err = readBlockGroups(dev, fs.sb) if err != nil { - return nil, err + return nil, nil, err } - return &fs, nil + return &fs.vfsfs, nil, nil } // getOrCreateInode gets the inode corresponding to the inode number passed in. |