summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fs/ext/ext.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/sentry/fs/ext/ext.go')
-rw-r--r--pkg/sentry/fs/ext/ext.go70
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.