summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJamie Liu <jamieliu@google.com>2020-05-13 18:16:45 -0700
committergVisor bot <gvisor-bot@google.com>2020-05-13 18:18:09 -0700
commit64afaf0e9bb712938f3621b8588840b5398b883c (patch)
tree3323703669f08439c501786e4a77d2352a9cfd4b
parentdb655f020ea556524f0e341e538e81c16d4f95e7 (diff)
Fix runsc association of gofers and FDs on VFS2.
Updates #1487 PiperOrigin-RevId: 311443628
-rw-r--r--runsc/boot/fs.go22
-rw-r--r--runsc/boot/vfs.go90
2 files changed, 95 insertions, 17 deletions
diff --git a/runsc/boot/fs.go b/runsc/boot/fs.go
index 8df5cc989..e1181271a 100644
--- a/runsc/boot/fs.go
+++ b/runsc/boot/fs.go
@@ -770,14 +770,8 @@ func (c *containerMounter) getMountNameAndOptions(conf *Config, m specs.Mount) (
useOverlay bool
)
- for _, opt := range m.Options {
- // When options include either "bind" or "rbind", this behaves as
- // bind mount even if the mount type is equal to a filesystem supported
- // on runsc.
- if opt == "bind" || opt == "rbind" {
- m.Type = bind
- break
- }
+ if isBindMount(m) {
+ m.Type = bind
}
switch m.Type {
@@ -807,6 +801,18 @@ func (c *containerMounter) getMountNameAndOptions(conf *Config, m specs.Mount) (
return fsName, opts, useOverlay, nil
}
+func isBindMount(m specs.Mount) bool {
+ for _, opt := range m.Options {
+ // When options include either "bind" or "rbind", this behaves as
+ // bind mount even if the mount type is equal to a filesystem supported
+ // on runsc.
+ if opt == "bind" || opt == "rbind" {
+ return true
+ }
+ }
+ return false
+}
+
func (c *containerMounter) getMountAccessType(mount specs.Mount) FileAccessType {
if hint := c.hints.findMount(mount); hint != nil {
return hint.fileAccessType()
diff --git a/runsc/boot/vfs.go b/runsc/boot/vfs.go
index 7378fbc95..147c901c4 100644
--- a/runsc/boot/vfs.go
+++ b/runsc/boot/vfs.go
@@ -203,28 +203,61 @@ func (c *containerMounter) createMountNamespaceVFS2(ctx context.Context, conf *C
}
func (c *containerMounter) mountSubmountsVFS2(ctx context.Context, conf *Config, mns *vfs.MountNamespace, creds *auth.Credentials) error {
- c.prepareMountsVFS2()
+ mounts, err := c.prepareMountsVFS2()
+ if err != nil {
+ return err
+ }
- for _, submount := range c.mounts {
+ for i := range mounts {
+ submount := &mounts[i]
log.Debugf("Mounting %q to %q, type: %s, options: %s", submount.Source, submount.Destination, submount.Type, submount.Options)
- if err := c.mountSubmountVFS2(ctx, conf, mns, creds, &submount); err != nil {
+ if err := c.mountSubmountVFS2(ctx, conf, mns, creds, submount); err != nil {
return err
}
}
// TODO(gvisor.dev/issue/1487): implement mountTmp from fs.go.
- return c.checkDispenser()
+ return nil
+}
+
+type mountAndFD struct {
+ specs.Mount
+ fd int
}
-func (c *containerMounter) prepareMountsVFS2() {
+func (c *containerMounter) prepareMountsVFS2() ([]mountAndFD, error) {
+ // Associate bind mounts with their FDs before sorting since there is an
+ // undocumented assumption that FDs are dispensed in the order in which
+ // they are required by mounts.
+ var mounts []mountAndFD
+ for _, m := range c.mounts {
+ fd := -1
+ // Only bind mounts use host FDs; see
+ // containerMounter.getMountNameAndOptionsVFS2.
+ if m.Type == bind || isBindMount(m) {
+ fd = c.fds.remove()
+ }
+ mounts = append(mounts, mountAndFD{
+ Mount: m,
+ fd: fd,
+ })
+ }
+ if err := c.checkDispenser(); err != nil {
+ return nil, err
+ }
+
// Sort the mounts so that we don't place children before parents.
- sort.Slice(c.mounts, func(i, j int) bool { return len(c.mounts[i].Destination) < len(c.mounts[j].Destination) })
+ sort.Slice(mounts, func(i, j int) bool {
+ return len(mounts[i].Destination) < len(mounts[j].Destination)
+ })
+
+ return mounts, nil
}
// TODO(gvisor.dev/issue/1487): Implement submount options similar to the VFS1
-// version.
-func (c *containerMounter) mountSubmountVFS2(ctx context.Context, conf *Config, mns *vfs.MountNamespace, creds *auth.Credentials, submount *specs.Mount) error {
+// version.
+func (c *containerMounter) mountSubmountVFS2(ctx context.Context, conf *Config, mns *vfs.MountNamespace, creds *auth.Credentials, submount *mountAndFD) error {
root := mns.Root()
defer root.DecRef()
target := &vfs.PathOperation{
@@ -233,7 +266,7 @@ func (c *containerMounter) mountSubmountVFS2(ctx context.Context, conf *Config,
Path: fspath.Parse(submount.Destination),
}
- fsName, options, useOverlay, err := c.getMountNameAndOptions(conf, *submount)
+ fsName, options, useOverlay, err := c.getMountNameAndOptionsVFS2(conf, submount)
if err != nil {
return fmt.Errorf("mountOptions failed: %w", err)
}
@@ -263,6 +296,45 @@ func (c *containerMounter) mountSubmountVFS2(ctx context.Context, conf *Config,
return nil
}
+// getMountNameAndOptionsVFS2 retrieves the fsName, opts, and useOverlay values
+// used for mounts.
+func (c *containerMounter) getMountNameAndOptionsVFS2(conf *Config, m *mountAndFD) (string, []string, bool, error) {
+ var (
+ fsName string
+ opts []string
+ useOverlay bool
+ )
+
+ if isBindMount(m.Mount) {
+ m.Type = bind
+ }
+
+ switch m.Type {
+ case devpts.Name, devtmpfs.Name, proc.Name, sys.Name:
+ fsName = m.Type
+ case nonefs:
+ fsName = sys.Name
+ case tmpfs.Name:
+ fsName = m.Type
+
+ var err error
+ opts, err = parseAndFilterOptions(m.Options, tmpfsAllowedOptions...)
+ if err != nil {
+ return "", nil, false, err
+ }
+
+ case bind:
+ fsName = gofer.Name
+ opts = p9MountOptions(m.fd, c.getMountAccessType(m.Mount), true /* vfs2 */)
+ // If configured, add overlay to all writable mounts.
+ useOverlay = conf.Overlay && !mountFlags(m.Options).ReadOnly
+
+ default:
+ log.Warningf("ignoring unknown filesystem type %q", m.Type)
+ }
+ return fsName, opts, useOverlay, nil
+}
+
func (c *containerMounter) makeSyntheticMount(ctx context.Context, currentPath string, root vfs.VirtualDentry, creds *auth.Credentials) error {
target := &vfs.PathOperation{
Root: root,