summaryrefslogtreecommitdiffhomepage
path: root/runsc/boot
diff options
context:
space:
mode:
Diffstat (limited to 'runsc/boot')
-rw-r--r--runsc/boot/config.go9
-rw-r--r--runsc/boot/fs.go62
-rw-r--r--runsc/boot/loader_test.go36
3 files changed, 68 insertions, 39 deletions
diff --git a/runsc/boot/config.go b/runsc/boot/config.go
index 074cd6a63..6c69a7c38 100644
--- a/runsc/boot/config.go
+++ b/runsc/boot/config.go
@@ -64,6 +64,11 @@ const (
// requests and forwards them to the host.
FileAccessProxy FileAccessType = iota
+ // FileAccessProxyExclusive is the same as FileAccessProxy, but enables
+ // extra caching for improved performance. It should only be used if
+ // the sandbox has exclusive access to the filesystem.
+ FileAccessProxyExclusive
+
// FileAccessDirect connects the sandbox directly to the host filesystem.
FileAccessDirect
)
@@ -73,6 +78,8 @@ func MakeFileAccessType(s string) (FileAccessType, error) {
switch s {
case "proxy":
return FileAccessProxy, nil
+ case "proxy-exclusive":
+ return FileAccessProxyExclusive, nil
case "direct":
return FileAccessDirect, nil
default:
@@ -84,6 +91,8 @@ func (f FileAccessType) String() string {
switch f {
case FileAccessProxy:
return "proxy"
+ case FileAccessProxyExclusive:
+ return "proxy-exclusive"
case FileAccessDirect:
return "direct"
default:
diff --git a/runsc/boot/fs.go b/runsc/boot/fs.go
index e596c739f..eea2ec1f5 100644
--- a/runsc/boot/fs.go
+++ b/runsc/boot/fs.go
@@ -17,6 +17,7 @@ package boot
import (
"fmt"
"path/filepath"
+ "strconv"
"strings"
// Include filesystem types that OCI spec might mount.
@@ -54,6 +55,9 @@ type fdDispenser struct {
}
func (f *fdDispenser) remove() int {
+ if f.empty() {
+ panic("fdDispenser out of fds")
+ }
rv := f.fds[0]
f.fds = f.fds[1:]
return rv
@@ -160,8 +164,6 @@ func compileMounts(spec *specs.Spec) []specs.Mount {
// setMounts iterates over mounts and mounts them in the specified
// mount namespace.
func setMounts(ctx context.Context, conf *Config, mns *fs.MountNamespace, fds *fdDispenser, mounts []specs.Mount) error {
-
- // Mount all submounts from mounts.
for _, m := range mounts {
if err := mountSubmount(ctx, conf, mns, fds, m, mounts); err != nil {
return err
@@ -181,11 +183,12 @@ func createRootMount(ctx context.Context, spec *specs.Spec, conf *Config, fds *f
)
switch conf.FileAccess {
- case FileAccessProxy:
+ case FileAccessProxy, FileAccessProxyExclusive:
fd := fds.remove()
log.Infof("Mounting root over 9P, ioFD: %d", fd)
hostFS := mustFindFilesystem("9p")
- rootInode, err = hostFS.Mount(ctx, rootDevice, mf, fmt.Sprintf("trans=fd,rfdno=%d,wfdno=%d,privateunixsocket=true", fd, fd))
+ opts := p9MountOptions(conf, fd)
+ rootInode, err = hostFS.Mount(ctx, rootDevice, mf, strings.Join(opts, ","))
if err != nil {
return nil, fmt.Errorf("failed to generate root mount point: %v", err)
}
@@ -242,13 +245,16 @@ func addOverlay(ctx context.Context, conf *Config, lower *fs.Inode, name string,
return fs.NewOverlayRoot(ctx, upper, lower, lowerFlags)
}
-// getMountNameAndOptions retrieves the fsName, data, and useOverlay values
+// getMountNameAndOptions retrieves the fsName, opts, and useOverlay values
// used for mounts.
func getMountNameAndOptions(conf *Config, m specs.Mount, fds *fdDispenser) (string, []string, bool, error) {
- var fsName string
- var data []string
- var useOverlay bool
- var err error
+ var (
+ fsName string
+ opts []string
+ useOverlay bool
+ err error
+ )
+
switch m.Type {
case "devpts", "devtmpfs", "proc", "sysfs":
fsName = m.Type
@@ -258,17 +264,17 @@ func getMountNameAndOptions(conf *Config, m specs.Mount, fds *fdDispenser) (stri
fsName = m.Type
// tmpfs has some extra supported options that we must pass through.
- data, err = parseAndFilterOptions(m.Options, "mode", "uid", "gid")
+ opts, err = parseAndFilterOptions(m.Options, "mode", "uid", "gid")
case "bind":
switch conf.FileAccess {
- case FileAccessProxy:
+ case FileAccessProxy, FileAccessProxyExclusive:
fd := fds.remove()
fsName = "9p"
- data = []string{"trans=fd", fmt.Sprintf("rfdno=%d", fd), fmt.Sprintf("wfdno=%d", fd), "privateunixsocket=true"}
+ opts = p9MountOptions(conf, fd)
case FileAccessDirect:
fsName = "whitelistfs"
- data = []string{"root=" + m.Source, "dont_translate_ownership=true"}
+ opts = []string{"root=" + m.Source, "dont_translate_ownership=true"}
default:
err = fmt.Errorf("invalid file access type: %v", conf.FileAccess)
}
@@ -282,13 +288,13 @@ func getMountNameAndOptions(conf *Config, m specs.Mount, fds *fdDispenser) (stri
// we do not support.
log.Warningf("ignoring unknown filesystem type %q", m.Type)
}
- return fsName, data, useOverlay, err
+ return fsName, opts, useOverlay, err
}
func mountSubmount(ctx context.Context, conf *Config, mns *fs.MountNamespace, fds *fdDispenser, m specs.Mount, mounts []specs.Mount) error {
// Map mount type to filesystem name, and parse out the options that we are
// capable of dealing with.
- fsName, data, useOverlay, err := getMountNameAndOptions(conf, m, fds)
+ fsName, opts, useOverlay, err := getMountNameAndOptions(conf, m, fds)
// Return the error or nil that corresponds to the default case in getMountNameAndOptions.
if err != nil {
@@ -307,7 +313,7 @@ func mountSubmount(ctx context.Context, conf *Config, mns *fs.MountNamespace, fd
mf.ReadOnly = true
}
- inode, err := filesystem.Mount(ctx, mountDevice(m), mf, strings.Join(data, ","))
+ inode, err := filesystem.Mount(ctx, mountDevice(m), mf, strings.Join(opts, ","))
if err != nil {
return fmt.Errorf("failed to create mount with source %q: %v", m.Source, err)
}
@@ -387,6 +393,20 @@ func mkdirAll(ctx context.Context, mns *fs.MountNamespace, path string) error {
return nil
}
+// p9MountOptions creates a slice of options for a p9 mount.
+func p9MountOptions(conf *Config, fd int) []string {
+ opts := []string{
+ "trans=fd",
+ "rfdno=" + strconv.Itoa(fd),
+ "wfdno=" + strconv.Itoa(fd),
+ "privateunixsocket=true",
+ }
+ if conf.FileAccess == FileAccessProxy {
+ opts = append(opts, "cache=remote_revalidating")
+ }
+ return opts
+}
+
// parseAndFilterOptions parses a MountOptions slice and filters by the allowed
// keys.
func parseAndFilterOptions(opts []string, allowedKeys ...string) ([]string, error) {
@@ -436,8 +456,7 @@ func mountDevice(m specs.Mount) string {
// addRestoreMount adds a mount to the MountSources map used for restoring a
// checkpointed container.
func addRestoreMount(conf *Config, renv *fs.RestoreEnvironment, m specs.Mount, fds *fdDispenser) error {
- fsName, data, _, err := getMountNameAndOptions(conf, m, fds)
- dataString := strings.Join(data, ",")
+ fsName, opts, _, err := getMountNameAndOptions(conf, m, fds)
// Return the error or nil that corresponds to the default case in getMountNameAndOptions.
if err != nil {
@@ -452,7 +471,7 @@ func addRestoreMount(conf *Config, renv *fs.RestoreEnvironment, m specs.Mount, f
newMount := fs.MountArgs{
Dev: mountDevice(m),
Flags: mountFlags(m.Options),
- Data: dataString,
+ Data: strings.Join(opts, ","),
}
renv.MountSources[fsName] = append(renv.MountSources[fsName], newMount)
log.Infof("Added mount at %q: %+v", fsName, newMount)
@@ -473,7 +492,8 @@ func createRestoreEnvironment(spec *specs.Spec, conf *Config, fds *fdDispenser)
// Add root mount.
fd := fds.remove()
- dataString := strings.Join([]string{"trans=fd", fmt.Sprintf("rfdno=%d", fd), fmt.Sprintf("wfdno=%d", fd), "privateunixsocket=true"}, ",")
+ opts := p9MountOptions(conf, fd)
+
mf := fs.MountSourceFlags{}
if spec.Root.Readonly {
mf.ReadOnly = true
@@ -482,7 +502,7 @@ func createRestoreEnvironment(spec *specs.Spec, conf *Config, fds *fdDispenser)
rootMount := fs.MountArgs{
Dev: rootDevice,
Flags: mf,
- Data: dataString,
+ Data: strings.Join(opts, ","),
}
renv.MountSources[rootFsName] = append(renv.MountSources[rootFsName], rootMount)
diff --git a/runsc/boot/loader_test.go b/runsc/boot/loader_test.go
index 7ea2e1ee5..f2f690b5d 100644
--- a/runsc/boot/loader_test.go
+++ b/runsc/boot/loader_test.go
@@ -398,7 +398,7 @@ func TestRestoreEnvironment(t *testing.T) {
{
Dev: "9pfs-/",
Flags: fs.MountSourceFlags{ReadOnly: true},
- Data: "trans=fd,rfdno=0,wfdno=0,privateunixsocket=true",
+ Data: "trans=fd,rfdno=0,wfdno=0,privateunixsocket=true,cache=remote_revalidating",
},
},
"tmpfs": {
@@ -458,11 +458,11 @@ func TestRestoreEnvironment(t *testing.T) {
{
Dev: "9pfs-/",
Flags: fs.MountSourceFlags{ReadOnly: true},
- Data: "trans=fd,rfdno=0,wfdno=0,privateunixsocket=true",
+ Data: "trans=fd,rfdno=0,wfdno=0,privateunixsocket=true,cache=remote_revalidating",
},
{
Dev: "9pfs-/dev/fd-foo",
- Data: "trans=fd,rfdno=1,wfdno=1,privateunixsocket=true",
+ Data: "trans=fd,rfdno=1,wfdno=1,privateunixsocket=true,cache=remote_revalidating",
},
},
"tmpfs": {
@@ -522,7 +522,7 @@ func TestRestoreEnvironment(t *testing.T) {
{
Dev: "9pfs-/",
Flags: fs.MountSourceFlags{ReadOnly: true},
- Data: "trans=fd,rfdno=0,wfdno=0,privateunixsocket=true",
+ Data: "trans=fd,rfdno=0,wfdno=0,privateunixsocket=true,cache=remote_revalidating",
},
},
"tmpfs": {
@@ -606,21 +606,21 @@ func TestRestoreEnvironment(t *testing.T) {
errorExpected: true,
},
}
-
for _, tc := range testCases {
- fds := &fdDispenser{fds: tc.ioFDs}
-
- actualRenv, err := createRestoreEnvironment(tc.spec, tc.conf, fds)
- if !tc.errorExpected && err != nil {
- t.Fatalf("could not create restore environment for test:%s", tc.name)
- } else if tc.errorExpected {
- if err == nil {
- t.Fatalf("expected an error, but no error occurred.")
+ t.Run(tc.name, func(t *testing.T) {
+ fds := &fdDispenser{fds: tc.ioFDs}
+ actualRenv, err := createRestoreEnvironment(tc.spec, tc.conf, fds)
+ if !tc.errorExpected && err != nil {
+ t.Fatalf("could not create restore environment for test:%s", tc.name)
+ } else if tc.errorExpected {
+ if err == nil {
+ t.Errorf("expected an error, but no error occurred.")
+ }
+ } else {
+ if !reflect.DeepEqual(*actualRenv, tc.expectedRenv) {
+ t.Errorf("restore environments did not match for test:%s\ngot:%+v\nwant:%+v\n", tc.name, *actualRenv, tc.expectedRenv)
+ }
}
- } else {
- if !reflect.DeepEqual(*actualRenv, tc.expectedRenv) {
- t.Fatalf("restore environments did not match for test:%s\ngot:%+v\nwant:%+v\n", tc.name, *actualRenv, tc.expectedRenv)
- }
- }
+ })
}
}