Skip to content

Commit

Permalink
Merge pull request kata-containers#1553 from bergwolf/ro-volumes
Browse files Browse the repository at this point in the history
runtime: fix virtiofsd RO volume sharing
  • Loading branch information
liubin committed Mar 29, 2021
2 parents 6932ac6 + e349244 commit 594c47a
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 23 deletions.
36 changes: 27 additions & 9 deletions src/runtime/virtcontainers/container.go
Expand Up @@ -472,18 +472,36 @@ func (c *Container) shareFiles(ctx context.Context, m Mount, idx int, hostShared
} else {
// These mounts are created in the shared dir
mountDest := filepath.Join(hostMountDir, filename)
if err := bindMount(ctx, m.Source, mountDest, m.ReadOnly, "private"); err != nil {
return "", false, err
}
// Save HostPath mount value into the mount list of the container.
c.mounts[idx].HostPath = mountDest
// bindmount remount event is not propagated to mount subtrees, so we have to remount the shared dir mountpoint directly.
if m.ReadOnly {
mountDest = filepath.Join(hostSharedDir, filename)
if err := remountRo(c.ctx, mountDest); err != nil {
if !m.ReadOnly {
if err := bindMount(c.ctx, m.Source, mountDest, false, "private"); err != nil {
return "", false, err
}
} else {
// For RO mounts, bindmount remount event is not propagated to mount subtrees,
// and it doesn't present in the virtiofsd standalone mount namespace either.
// So we end up a bit tricky:
// 1. make a private bind mount to the mount source
// 2. make another ro bind mount on the private mount
// 3. move the ro bind mount to mountDest
// 4. umount the private bind mount created in step 1
privateDest := filepath.Join(getPrivatePath(c.sandboxID), filename)
if err := bindMount(c.ctx, m.Source, privateDest, false, "private"); err != nil {
return "", false, err
}
defer func() {
syscall.Unmount(privateDest, syscall.MNT_DETACH|UmountNoFollow)
}()
if err := bindMount(c.ctx, privateDest, privateDest, true, "private"); err != nil {
return "", false, err
}
if err := moveMount(c.ctx, privateDest, mountDest); err != nil {
return "", false, err
}

syscall.Unmount(privateDest, syscall.MNT_DETACH|UmountNoFollow)
}
// Save HostPath mount value into the mount list of the container.
c.mounts[idx].HostPath = mountDest
}

return guestDest, false, nil
Expand Down
7 changes: 6 additions & 1 deletion src/runtime/virtcontainers/kata_agent.go
Expand Up @@ -152,9 +152,10 @@ var kataHostSharedDir = func() string {
}

// Shared path handling:
// 1. create two directories for each sandbox:
// 1. create three directories for each sandbox:
// -. /run/kata-containers/shared/sandboxes/$sbx_id/mounts/, a directory to hold all host/guest shared mounts
// -. /run/kata-containers/shared/sandboxes/$sbx_id/shared/, a host/guest shared directory (9pfs/virtiofs source dir)
// -. /run/kata-containers/shared/sandboxes/$sbx_id/private/, a directory to hold all temporary private mounts when creating ro mounts
//
// 2. /run/kata-containers/shared/sandboxes/$sbx_id/mounts/ is bind mounted readonly to /run/kata-containers/shared/sandboxes/$sbx_id/shared/, so guest cannot modify it
//
Expand All @@ -167,6 +168,10 @@ func getMountPath(id string) string {
return filepath.Join(kataHostSharedDir(), id, "mounts")
}

func getPrivatePath(id string) string {
return filepath.Join(kataHostSharedDir(), id, "private")
}

func getSandboxPath(id string) string {
return filepath.Join(kataHostSharedDir(), id)
}
Expand Down
51 changes: 38 additions & 13 deletions src/runtime/virtcontainers/mount.go
Expand Up @@ -212,6 +212,42 @@ func isDeviceMapper(major, minor int) (bool, error) {

const mountPerm = os.FileMode(0755)

func evalMountPath(source, destination string) (string, string, error) {
if source == "" {
return "", "", fmt.Errorf("source must be specified")
}
if destination == "" {
return "", "", fmt.Errorf("destination must be specified")
}

absSource, err := filepath.EvalSymlinks(source)
if err != nil {
return "", "", fmt.Errorf("Could not resolve symlink for source %v", source)
}

if err := ensureDestinationExists(absSource, destination); err != nil {
return "", "", fmt.Errorf("Could not create destination mount point %v: %v", destination, err)
}

return absSource, destination, nil
}

// moveMount moves a mountpoint to another path with some bookkeeping:
// * evaluate all symlinks
// * ensure the source exists
// * recursively create the destination
func moveMount(ctx context.Context, source, destination string) error {
span, _ := trace(ctx, "moveMount")
defer span.End()

source, destination, err := evalMountPath(source, destination)
if err != nil {
return err
}

return syscall.Mount(source, destination, "move", syscall.MS_MOVE, "")
}

// bindMount bind mounts a source in to a destination. This will
// do some bookkeeping:
// * evaluate all symlinks
Expand All @@ -222,20 +258,9 @@ func bindMount(ctx context.Context, source, destination string, readonly bool, p
span, _ := trace(ctx, "bindMount")
defer span.End()

if source == "" {
return fmt.Errorf("source must be specified")
}
if destination == "" {
return fmt.Errorf("destination must be specified")
}

absSource, err := filepath.EvalSymlinks(source)
absSource, destination, err := evalMountPath(source, destination)
if err != nil {
return fmt.Errorf("Could not resolve symlink for source %v", source)
}

if err := ensureDestinationExists(absSource, destination); err != nil {
return fmt.Errorf("Could not create destination mount point %v: %v", destination, err)
return err
}

if err := syscall.Mount(absSource, destination, "bind", syscall.MS_BIND, ""); err != nil {
Expand Down

0 comments on commit 594c47a

Please sign in to comment.