Make PodMountHints more serializable.

Before this CL, `PodMountHints` serialized to nothing, so it was an empty `{}`
in the container state file. However, `runsc start` needs to read this from
the state file when starting new subcontainers that have mounts of their own.

This CL exports `PodMountHints.Mounts` and most fields of `MountHint`, so that
the serialized view of `PodMountHints` contains enough data for `runsc start`
to do its thing.

PiperOrigin-RevId: 561259523
This commit is contained in:
Etienne Perot
2023-08-30 00:55:28 -07:00
committed by gVisor bot
parent 268b43d1b2
commit 8326bcecfc
8 changed files with 121 additions and 104 deletions
+2 -1
View File
@@ -469,7 +469,8 @@ func (cm *containerManager) Restore(o *RestoreOpts, _ *struct{}) error {
// Set up the restore environment.
ctx := k.SupervisorContext()
mntr := newContainerMounter(&cm.l.root, cm.l.k, cm.l.mountHints, cm.l.productName, o.SandboxID)
// TODO(b/298078576): Need to process hints here probably
mntr := newContainerMounter(&cm.l.root, cm.l.k, cm.l.mountHints, cm.l.sharedMounts, cm.l.productName, o.SandboxID)
ctx, err = mntr.configureRestore(ctx)
if err != nil {
return fmt.Errorf("configuring filesystem restore: %v", err)
+6 -2
View File
@@ -158,6 +158,10 @@ type Loader struct {
// apply to the entire pod.
mountHints *PodMountHints
// sharedMountKey holds VFS mounts that may be shared between containers
// within the same pod. It is mapped by mount source.
sharedMounts map[string]*vfs.Mount
// productName is the value to show in
// /sys/devices/virtual/dmi/id/product_name.
productName string
@@ -932,12 +936,12 @@ func (l *Loader) createContainerProcess(root bool, cid string, info *containerIn
}
l.startGoferMonitor(cid, int32(info.goferFDs[0].FD()))
mntr := newContainerMounter(info, l.k, l.mountHints, l.productName, l.sandboxID)
if root {
if err := mntr.processHints(info.conf, info.procArgs.Credentials); err != nil {
if err := l.processHints(info.conf, info.procArgs.Credentials); err != nil {
return nil, nil, err
}
}
mntr := newContainerMounter(info, l.k, l.mountHints, l.sharedMounts, l.productName, l.sandboxID)
if err := setupContainerVFS(ctx, info, mntr, &info.procArgs); err != nil {
return nil, nil, err
}
+2 -2
View File
@@ -475,10 +475,10 @@ func TestCreateMountNamespace(t *testing.T) {
defer l.Destroy()
defer loaderCleanup()
mntr := newContainerMounter(&l.root, l.k, l.mountHints, "", l.sandboxID)
if err := mntr.processHints(l.root.conf, l.root.procArgs.Credentials); err != nil {
if err := l.processHints(l.root.conf, l.root.procArgs.Credentials); err != nil {
t.Fatalf("failed process hints: %v", err)
}
mntr := newContainerMounter(&l.root, l.k, l.mountHints, l.sharedMounts, "", l.sandboxID)
ctx := l.k.SupervisorContext()
creds := auth.NewRootCredentials(l.root.procArgs.Credentials.UserNamespace)
+36 -40
View File
@@ -21,7 +21,6 @@ import (
specs "github.com/opencontainers/runtime-spec/specs-go"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/tmpfs"
"gvisor.dev/gvisor/pkg/sentry/vfs"
"gvisor.dev/gvisor/runsc/config"
"gvisor.dev/gvisor/runsc/specutils"
)
@@ -29,11 +28,11 @@ import (
// MountPrefix is the annotation prefix for mount hints.
const MountPrefix = "dev.gvisor.spec.mount."
// shareType indicates who can access/mutate the volume contents.
type shareType int
// ShareType indicates who can access/mutate the volume contents.
type ShareType int
const (
invalid shareType = iota
invalid ShareType = iota
// container shareType indicates that the mount is used by a single
// container. There are no external observers.
@@ -48,7 +47,7 @@ const (
shared
)
func (s shareType) String() string {
func (s ShareType) String() string {
switch s {
case invalid:
return "invalid"
@@ -63,14 +62,14 @@ func (s shareType) String() string {
}
}
// lifecycleType indicates whether creation/deletion of the volume is tied to
// LifecycleType indicates whether creation/deletion of the volume is tied to
// the pod or container's lifecycle.
type lifecycleType int
type LifecycleType int
const (
// sharedLife indicates that the volume's lifecycle is not tied to the pod.
// The volume persists beyond the pod's life. This is the safe default.
sharedLife lifecycleType = iota
sharedLife LifecycleType = iota
// podLife indicates that the volume's lifecycle is tied to the pod's
// lifecycle. The volume is destroyed with the pod.
@@ -81,7 +80,7 @@ const (
containerLife
)
func (o lifecycleType) String() string {
func (o LifecycleType) String() string {
switch o {
case sharedLife:
return "shared"
@@ -96,7 +95,7 @@ func (o lifecycleType) String() string {
// PodMountHints contains a collection of mountHints for the pod.
type PodMountHints struct {
mounts map[string]*MountHint
Mounts map[string]*MountHint `json:"mounts"`
}
// NewPodMountHints instantiates PodMountHints using spec.
@@ -116,7 +115,7 @@ func NewPodMountHints(spec *specs.Spec) (*PodMountHints, error) {
}
mnt := mnts[name]
if mnt == nil {
mnt = &MountHint{name: name}
mnt = &MountHint{Name: name}
mnts[name] = mnt
}
if err := mnt.setField(parts[1], v); err != nil {
@@ -127,8 +126,8 @@ func NewPodMountHints(spec *specs.Spec) (*PodMountHints, error) {
// Validate all the parsed hints.
for name, m := range mnts {
log.Infof("Mount annotation found, name: %s, source: %q, type: %s, share: %v", name, m.mount.Source, m.mount.Type, m.share)
if m.share == invalid || len(m.mount.Source) == 0 || len(m.mount.Type) == 0 {
log.Infof("Mount annotation found, name: %s, source: %q, type: %s, share: %v", name, m.Mount.Source, m.Mount.Type, m.Share)
if m.Share == invalid || len(m.Mount.Source) == 0 || len(m.Mount.Type) == 0 {
log.Warningf("ignoring mount annotations for %q because of missing required field(s)", name)
delete(mnts, name)
continue
@@ -136,27 +135,24 @@ func NewPodMountHints(spec *specs.Spec) (*PodMountHints, error) {
// Check for duplicate mount sources.
for name2, m2 := range mnts {
if name != name2 && m.mount.Source == m2.mount.Source {
return nil, fmt.Errorf("mounts %q and %q have the same mount source %q", m.name, m2.name, m.mount.Source)
if name != name2 && m.Mount.Source == m2.Mount.Source {
return nil, fmt.Errorf("mounts %q and %q have the same mount source %q", m.Name, m2.Name, m.Mount.Source)
}
}
}
return &PodMountHints{mounts: mnts}, nil
return &PodMountHints{Mounts: mnts}, nil
}
// MountHint represents extra information about mounts that are provided via
// annotations. They can override mount type, and provide sharing information
// so that mounts can be correctly shared inside the pod.
// It is part of the sandbox.Sandbox struct, so it must be serializable.
type MountHint struct {
name string
share shareType
mount specs.Mount
lifecycle lifecycleType
// vfsMount is the master mount for the volume. For mounts with 'pod' share
// the master volume is bind mounted inside the containers.
vfsMount *vfs.Mount
Name string `json:"name"`
Share ShareType `json:"share"`
Mount specs.Mount `json:"mount"`
Lifecycle LifecycleType `json:"lifecycle"`
}
func (m *MountHint) setField(key, val string) error {
@@ -165,13 +161,13 @@ func (m *MountHint) setField(key, val string) error {
if len(val) == 0 {
return fmt.Errorf("source cannot be empty")
}
m.mount.Source = val
m.Mount.Source = val
case "type":
return m.setType(val)
case "share":
return m.setShare(val)
case "options":
m.mount.Options = specutils.FilterMountOptions(strings.Split(val, ","))
m.Mount.Options = specutils.FilterMountOptions(strings.Split(val, ","))
case "lifecycle":
return m.setLifecycle(val)
default:
@@ -183,7 +179,7 @@ func (m *MountHint) setField(key, val string) error {
func (m *MountHint) setType(val string) error {
switch val {
case tmpfs.Name, Bind:
m.mount.Type = val
m.Mount.Type = val
default:
return fmt.Errorf("invalid type %q", val)
}
@@ -193,11 +189,11 @@ func (m *MountHint) setType(val string) error {
func (m *MountHint) setShare(val string) error {
switch val {
case container.String():
m.share = container
m.Share = container
case pod.String():
m.share = pod
m.Share = pod
case shared.String():
m.share = shared
m.Share = shared
default:
return fmt.Errorf("invalid share value %q", val)
}
@@ -207,11 +203,11 @@ func (m *MountHint) setShare(val string) error {
func (m *MountHint) setLifecycle(val string) error {
switch val {
case containerLife.String():
m.lifecycle = containerLife
m.Lifecycle = containerLife
case podLife.String():
m.lifecycle = podLife
m.Lifecycle = podLife
case sharedLife.String():
m.lifecycle = sharedLife
m.Lifecycle = sharedLife
default:
return fmt.Errorf("invalid lifecycle %q", val)
}
@@ -223,21 +219,21 @@ func (m *MountHint) setLifecycle(val string) error {
func (m *MountHint) shouldShareMount() bool {
// TODO(b/142076984): Only support tmpfs for now. Bind mounts require a
// common gofer to mount all shared volumes.
return m.mount.Type == tmpfs.Name && m.share == pod
return m.Mount.Type == tmpfs.Name && m.Share == pod
}
// ShouldOverlay returns true if this mount should be overlaid.
func (m *MountHint) ShouldOverlay() bool {
// TODO(b/142076984): Only support share=container for now. Once shared gofer
// support is added, we can overlay shared bind mounts too.
return m.mount.Type == Bind && m.share == container && m.lifecycle != sharedLife
return m.Mount.Type == Bind && m.Share == container && m.Lifecycle != sharedLife
}
// checkCompatible verifies that shared mount is compatible with master.
// Master options must be the same or less restrictive than the container mount,
// e.g. master can be 'rw' while container mounts as 'ro'.
func (m *MountHint) checkCompatible(replica *specs.Mount) error {
masterOpts := ParseMountOptions(m.mount.Options)
masterOpts := ParseMountOptions(m.Mount.Options)
replicaOpts := ParseMountOptions(replica.Options)
if masterOpts.ReadOnly && !replicaOpts.ReadOnly {
@@ -254,13 +250,13 @@ func (m *MountHint) checkCompatible(replica *specs.Mount) error {
// Precondition: m.mount.Type == Bind.
func (m *MountHint) fileAccessType() config.FileAccessType {
if m.share == shared {
if m.Share == shared {
return config.FileAccessShared
}
if m.shouldShareMount() {
return config.FileAccessExclusive
}
if m.share == container {
if m.Share == container {
return config.FileAccessExclusive
}
return config.FileAccessShared
@@ -268,8 +264,8 @@ func (m *MountHint) fileAccessType() config.FileAccessType {
// FindMount finds the MountHint that applies to this mount.
func (p *PodMountHints) FindMount(mount *specs.Mount) *MountHint {
for _, m := range p.mounts {
if m.mount.Source == mount.Source {
for _, m := range p.Mounts {
if m.Mount.Source == mount.Source {
return m
}
}
+27 -27
View File
@@ -41,38 +41,38 @@ func TestPodMountHintsHappy(t *testing.T) {
}
// Check that fields were set correctly.
mount1 := podHints.mounts["mount1"]
if want := "mount1"; want != mount1.name {
t.Errorf("mount1 name, want: %q, got: %q", want, mount1.name)
mount1 := podHints.Mounts["mount1"]
if want := "mount1"; want != mount1.Name {
t.Errorf("mount1 name, want: %q, got: %q", want, mount1.Name)
}
if want := "foo"; want != mount1.mount.Source {
t.Errorf("mount1 source, want: %q, got: %q", want, mount1.mount.Source)
if want := "foo"; want != mount1.Mount.Source {
t.Errorf("mount1 source, want: %q, got: %q", want, mount1.Mount.Source)
}
if want := "tmpfs"; want != mount1.mount.Type {
t.Errorf("mount1 type, want: %q, got: %q", want, mount1.mount.Type)
if want := "tmpfs"; want != mount1.Mount.Type {
t.Errorf("mount1 type, want: %q, got: %q", want, mount1.Mount.Type)
}
if want := pod; want != mount1.share {
t.Errorf("mount1 type, want: %q, got: %q", want, mount1.share)
if want := pod; want != mount1.Share {
t.Errorf("mount1 type, want: %q, got: %q", want, mount1.Share)
}
if want := []string(nil); !reflect.DeepEqual(want, mount1.mount.Options) {
t.Errorf("mount1 type, want: %q, got: %q", want, mount1.mount.Options)
if want := []string(nil); !reflect.DeepEqual(want, mount1.Mount.Options) {
t.Errorf("mount1 type, want: %q, got: %q", want, mount1.Mount.Options)
}
mount2 := podHints.mounts["mount2"]
if want := "mount2"; want != mount2.name {
t.Errorf("mount2 name, want: %q, got: %q", want, mount2.name)
mount2 := podHints.Mounts["mount2"]
if want := "mount2"; want != mount2.Name {
t.Errorf("mount2 name, want: %q, got: %q", want, mount2.Name)
}
if want := "bar"; want != mount2.mount.Source {
t.Errorf("mount2 source, want: %q, got: %q", want, mount2.mount.Source)
if want := "bar"; want != mount2.Mount.Source {
t.Errorf("mount2 source, want: %q, got: %q", want, mount2.Mount.Source)
}
if want := "bind"; want != mount2.mount.Type {
t.Errorf("mount2 type, want: %q, got: %q", want, mount2.mount.Type)
if want := "bind"; want != mount2.Mount.Type {
t.Errorf("mount2 type, want: %q, got: %q", want, mount2.Mount.Type)
}
if want := container; want != mount2.share {
t.Errorf("mount2 type, want: %q, got: %q", want, mount2.share)
if want := container; want != mount2.Share {
t.Errorf("mount2 type, want: %q, got: %q", want, mount2.Share)
}
if want := []string{"rw", "private"}; !reflect.DeepEqual(want, mount2.mount.Options) {
t.Errorf("mount2 type, want: %q, got: %q", want, mount2.mount.Options)
if want := []string{"rw", "private"}; !reflect.DeepEqual(want, mount2.Mount.Options) {
t.Errorf("mount2 type, want: %q, got: %q", want, mount2.Mount.Options)
}
}
@@ -161,7 +161,7 @@ func TestPodMountHintsIgnore(t *testing.T) {
if err != nil {
t.Errorf("newPodMountHints() failed: %v", err)
} else if podHints != nil {
if hint, ok := podHints.mounts["mount1"]; ok {
if hint, ok := podHints.Mounts["mount1"]; ok {
t.Errorf("hint was provided when it should have been omitted: %+v", hint)
}
}
@@ -182,9 +182,9 @@ func TestIgnoreInvalidMountOptions(t *testing.T) {
if err != nil {
t.Fatalf("newPodMountHints failed: %v", err)
}
mount1 := podHints.mounts["mount1"]
if want := []string{"rw", "private"}; !reflect.DeepEqual(want, mount1.mount.Options) {
t.Errorf("mount2 type, want: %q, got: %q", want, mount1.mount.Options)
mount1 := podHints.Mounts["mount1"]
if want := []string{"rw", "private"}; !reflect.DeepEqual(want, mount1.Mount.Options) {
t.Errorf("mount2 type, want: %q, got: %q", want, mount1.Mount.Options)
}
}
@@ -233,7 +233,7 @@ func TestHintsCheckCompatible(t *testing.T) {
},
} {
t.Run(tc.name, func(t *testing.T) {
master := MountHint{mount: specs.Mount{Options: tc.masterOpts}}
master := MountHint{Mount: specs.Mount{Options: tc.masterOpts}}
replica := specs.Mount{Options: tc.replicaOpts}
if err := master.checkCompatible(&replica); err != nil {
if !strings.Contains(err.Error(), tc.err) {
+45 -28
View File
@@ -388,8 +388,13 @@ type containerMounter struct {
k *kernel.Kernel
// hints is the set of pod mount hints for the sandbox.
hints *PodMountHints
// sharedMounts is a map of shared mounts that can be reused across
// containers.
sharedMounts map[string]*vfs.Mount
// productName is the value to show in
// /sys/devices/virtual/dmi/id/product_name.
productName string
@@ -398,7 +403,7 @@ type containerMounter struct {
sandboxID string
}
func newContainerMounter(info *containerInfo, k *kernel.Kernel, hints *PodMountHints, productName string, sandboxID string) *containerMounter {
func newContainerMounter(info *containerInfo, k *kernel.Kernel, hints *PodMountHints, sharedMounts map[string]*vfs.Mount, productName string, sandboxID string) *containerMounter {
return &containerMounter{
root: info.spec.Root,
mounts: compileMounts(info.spec, info.conf),
@@ -407,6 +412,7 @@ func newContainerMounter(info *containerInfo, k *kernel.Kernel, hints *PodMountH
overlayMediums: info.overlayMediums,
k: k,
hints: hints,
sharedMounts: sharedMounts,
productName: productName,
sandboxID: sandboxID,
}
@@ -419,7 +425,7 @@ func (c *containerMounter) checkDispenser() error {
return nil
}
func (c *containerMounter) getMountAccessType(conf *config.Config, mount *specs.Mount, hint *MountHint) config.FileAccessType {
func getMountAccessType(conf *config.Config, mount *specs.Mount, hint *MountHint) config.FileAccessType {
if hint != nil {
return hint.fileAccessType()
}
@@ -668,9 +674,13 @@ func (c *containerMounter) mountSubmounts(ctx context.Context, conf *config.Conf
)
if submount.hint != nil && submount.hint.shouldShareMount() {
mnt, err = c.mountSharedSubmount(ctx, conf, mns, creds, submount.mount, submount.hint)
sharedMount, ok := c.sharedMounts[submount.hint.Mount.Source]
if !ok {
return fmt.Errorf("shared mount %q not found", submount.hint.Name)
}
mnt, err = c.mountSharedSubmount(ctx, conf, mns, creds, submount.mount, submount.hint, sharedMount)
if err != nil {
return fmt.Errorf("mount shared mount %q to %q: %v", submount.hint.name, submount.mount.Destination, err)
return fmt.Errorf("mount shared mount %q to %q: %v", submount.hint.Name, submount.mount.Destination, err)
}
} else {
mnt, err = c.mountSubmount(ctx, conf, mns, creds, submount)
@@ -752,7 +762,7 @@ func (c *containerMounter) prepareMounts() ([]mountInfo, error) {
}
func (c *containerMounter) mountSubmount(ctx context.Context, conf *config.Config, mns *vfs.MountNamespace, creds *auth.Credentials, submount *mountInfo) (*vfs.Mount, error) {
fsName, opts, err := c.getMountNameAndOptions(conf, submount)
fsName, opts, err := getMountNameAndOptions(conf, submount, c.productName)
if err != nil {
return nil, fmt.Errorf("mountOptions failed: %w", err)
}
@@ -793,7 +803,7 @@ func (c *containerMounter) mountSubmount(ctx context.Context, conf *config.Confi
// getMountNameAndOptions retrieves the fsName, opts, and useOverlay values
// used for mounts.
func (c *containerMounter) getMountNameAndOptions(conf *config.Config, m *mountInfo) (string, *vfs.MountOptions, error) {
func getMountNameAndOptions(conf *config.Config, m *mountInfo, productName string) (string, *vfs.MountOptions, error) {
fsName := m.mount.Type
var (
data []string
@@ -810,8 +820,8 @@ func (c *containerMounter) getMountNameAndOptions(conf *config.Config, m *mountI
case sys.Name:
sysData := &sys.InternalData{EnableAccelSysfs: conf.TPUProxy}
if len(c.productName) > 0 {
sysData.ProductName = c.productName
if len(productName) > 0 {
sysData.ProductName = productName
}
internalData = sysData
@@ -828,7 +838,7 @@ func (c *containerMounter) getMountNameAndOptions(conf *config.Config, m *mountI
// Check that an FD was provided to fails fast.
return "", nil, fmt.Errorf("gofer mount requires a connection FD")
}
data = goferMountData(m.fd, c.getMountAccessType(conf, m.mount, m.hint), conf)
data = goferMountData(m.fd, getMountAccessType(conf, m.mount, m.hint), conf)
internalData = gofer.InternalFilesystemOptions{
UniqueID: m.mount.Destination,
}
@@ -961,55 +971,62 @@ func (c *containerMounter) mountTmp(ctx context.Context, conf *config.Config, cr
}
// processHints processes annotations that container hints about how volumes
// should be mounted (e.g. a volume shared between containers). It must be
// called for the root container only.
func (c *containerMounter) processHints(conf *config.Config, creds *auth.Credentials) error {
ctx := c.k.SupervisorContext()
for _, hint := range c.hints.mounts {
// should be mounted (e.g. a volume shared between containers).
// Precondition: Must be only called once during the loader sequence
// for the root container.
// Postcondition: Initialized l.sharedMounts on success.
func (l *Loader) processHints(conf *config.Config, creds *auth.Credentials) error {
ctx := l.k.SupervisorContext()
var sharedMounts map[string]*vfs.Mount
for _, hint := range l.mountHints.Mounts {
if !hint.shouldShareMount() {
continue
}
log.Infof("Mounting master of shared mount %q from %q type %q", hint.name, hint.mount.Source, hint.mount.Type)
mnt, err := c.mountSharedMaster(ctx, conf, hint, creds)
log.Infof("Mounting master of shared mount %q from %q type %q", hint.Name, hint.Mount.Source, hint.Mount.Type)
mnt, err := l.mountSharedMaster(ctx, conf, hint, creds)
if err != nil {
return fmt.Errorf("mounting shared master %q: %v", hint.name, err)
return fmt.Errorf("mounting shared master %q: %v", hint.Name, err)
}
hint.vfsMount = mnt
if sharedMounts == nil {
sharedMounts = make(map[string]*vfs.Mount)
}
sharedMounts[hint.Mount.Source] = mnt
}
l.sharedMounts = sharedMounts
return nil
}
// mountSharedMaster mounts the master of a volume that is shared among
// containers in a pod.
func (c *containerMounter) mountSharedMaster(ctx context.Context, conf *config.Config, hint *MountHint, creds *auth.Credentials) (*vfs.Mount, error) {
func (l *Loader) mountSharedMaster(ctx context.Context, conf *config.Config, hint *MountHint, creds *auth.Credentials) (*vfs.Mount, error) {
// Map mount type to filesystem name, and parse out the options that we are
// capable of dealing with.
mntInfo := newNonGoferMountInfo(&hint.mount)
fsName, opts, err := c.getMountNameAndOptions(conf, mntInfo)
mntInfo := newNonGoferMountInfo(&hint.Mount)
fsName, opts, err := getMountNameAndOptions(conf, mntInfo, l.productName)
if err != nil {
return nil, err
}
if len(fsName) == 0 {
return nil, fmt.Errorf("mount type not supported %q", hint.mount.Type)
return nil, fmt.Errorf("mount type not supported %q", hint.Mount.Type)
}
return c.k.VFS().MountDisconnected(ctx, creds, "", fsName, opts)
return l.k.VFS().MountDisconnected(ctx, creds, "", fsName, opts)
}
// mountSharedSubmount binds mount to a previously mounted volume that is shared
// among containers in the same pod.
func (c *containerMounter) mountSharedSubmount(ctx context.Context, conf *config.Config, mns *vfs.MountNamespace, creds *auth.Credentials, mount *specs.Mount, source *MountHint) (*vfs.Mount, error) {
if err := source.checkCompatible(mount); err != nil {
func (c *containerMounter) mountSharedSubmount(ctx context.Context, conf *config.Config, mns *vfs.MountNamespace, creds *auth.Credentials, mount *specs.Mount, srcHint *MountHint, srcMount *vfs.Mount) (*vfs.Mount, error) {
if err := srcHint.checkCompatible(mount); err != nil {
return nil, err
}
// Ignore data and useOverlay because these were already applied to
// the master mount.
_, opts, err := c.getMountNameAndOptions(conf, newNonGoferMountInfo(mount))
_, opts, err := getMountNameAndOptions(conf, newNonGoferMountInfo(mount), c.productName)
if err != nil {
return nil, err
}
newMnt := c.k.VFS().NewDisconnectedMount(source.vfsMount.Filesystem(), source.vfsMount.Root(), opts)
newMnt := c.k.VFS().NewDisconnectedMount(srcMount.Filesystem(), srcMount.Root(), opts)
defer newMnt.DecRef(ctx)
root := mns.Root(ctx)
@@ -1027,7 +1044,7 @@ func (c *containerMounter) mountSharedSubmount(ctx context.Context, conf *config
if err := c.k.VFS().ConnectMountAt(ctx, creds, newMnt, target); err != nil {
return nil, err
}
log.Infof("Mounted %q type shared bind to %q", mount.Destination, source.name)
log.Infof("Mounted %q type shared bind to %q", mount.Destination, srcHint.Name)
return newMnt, nil
}
+2 -3
View File
@@ -71,11 +71,10 @@ func TestGetMountAccessType(t *testing.T) {
if err != nil {
t.Fatalf("newPodMountHints failed: %v", err)
}
mounter := containerMounter{hints: podHints}
conf := &config.Config{FileAccessMounts: config.FileAccessShared}
mnt := &specs.Mount{Source: source}
if got := mounter.getMountAccessType(conf, mnt, podHints.FindMount(mnt)); got != tst.want {
t.Errorf("getMountAccessType(), want: %v, got: %v", tst.want, got)
if got := getMountAccessType(conf, mnt, podHints.FindMount(mnt)); got != tst.want {
t.Errorf("getMountAccessType(), got: %v, want: %v", got, tst.want)
}
})
}
+1 -1
View File
@@ -926,7 +926,7 @@ func (c *Container) createOverlayFilestore(conf config.Overlay2, mountSrc string
func (c *Container) createOverlayFilestoreInSelf(mountSrc string) (*os.File, boot.OverlayMedium, error) {
mountSrcInfo, err := os.Stat(mountSrc)
if err != nil {
return nil, boot.NoOverlay, fmt.Errorf("failed to stat mount %q to see if it were a dirctory: %v", mountSrc, err)
return nil, boot.NoOverlay, fmt.Errorf("failed to stat mount %q to see if it were a directory: %v", mountSrc, err)
}
if !mountSrcInfo.IsDir() {
log.Warningf("overlay2 self medium is only supported for directory mounts, but mount %q is not a directory, falling back to memory", mountSrc)