Fix runsc association of gofers and FDs on VFS2.

Updates #1487

PiperOrigin-RevId: 311443628
This commit is contained in:
Jamie Liu
2020-05-13 18:18:09 -07:00
committed by gVisor bot
parent db655f020e
commit 64afaf0e9b
2 changed files with 95 additions and 17 deletions
+14 -8
View File
@@ -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()
+81 -9
View File
@@ -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
}
func (c *containerMounter) prepareMountsVFS2() {
type mountAndFD struct {
specs.Mount
fd int
}
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,