From d8f0db9bcf2ecfaf7fb1b09d7d4cace3a8e40cc7 Mon Sep 17 00:00:00 2001 From: Lantao Liu Date: Tue, 28 Aug 2018 11:52:56 -0700 Subject: runsc: unmount volume mounts when destroy container. PiperOrigin-RevId: 210579178 Change-Id: Iae20639c5186b1a976cbff6d05bda134cd00d0da --- runsc/container/container.go | 12 ++++++++---- runsc/container/fs.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) (limited to 'runsc/container') diff --git a/runsc/container/container.go b/runsc/container/container.go index 16af66d3e..725b4d347 100644 --- a/runsc/container/container.go +++ b/runsc/container/container.go @@ -510,10 +510,6 @@ func (c *Container) Destroy() error { executeHooksBestEffort(c.Spec.Hooks.Poststop, c.State()) } - if err := os.RemoveAll(c.Root); err != nil { - log.Warningf("Failed to delete container root directory %q, err: %v", c.Root, err) - } - // If we are the first container in the sandbox, take the sandbox down // as well. if c.Sandbox != nil && c.Sandbox.IsRootContainer(c.ID) { @@ -532,6 +528,14 @@ func (c *Container) Destroy() error { } } + if err := destroyFS(c.Spec); err != nil { + return fmt.Errorf("error destroying container fs: %v", err) + } + + if err := os.RemoveAll(c.Root); err != nil && !os.IsNotExist(err) { + return fmt.Errorf("error deleting container root directory %q: %v", c.Root, err) + } + c.Status = Stopped return nil } diff --git a/runsc/container/fs.go b/runsc/container/fs.go index c12f5c331..dd8bdf120 100644 --- a/runsc/container/fs.go +++ b/runsc/container/fs.go @@ -134,6 +134,35 @@ func setupFS(spec *specs.Spec, conf *boot.Config, bundleDir string) error { return nil } +// destroyFS unmounts mounts done by runsc under `spec.Root.Path`. This +// recovers the container rootfs into the original state. +func destroyFS(spec *specs.Spec) error { + for _, m := range spec.Mounts { + if m.Type != "bind" || !specutils.IsSupportedDevMount(m) { + continue + } + + // It's possible that 'm.Destination' follows symlinks inside the + // container. + dst, err := resolveSymlinks(spec.Root.Path, m.Destination) + if err != nil { + return err + } + + flags := syscall.MNT_DETACH + log.Infof("Unmounting dst: %q, flags: %#x", dst, flags) + // Do not return error if dst is not a mountpoint. + // Based on http://man7.org/linux/man-pages/man2/umount.2.html + // For kernel version 2.6+ and MNT_DETACH flag, EINVAL means + // the dst is not a mount point. + if err := syscall.Unmount(dst, flags); err != nil && + !os.IsNotExist(err) && err != syscall.EINVAL { + return err + } + } + return nil +} + // resolveSymlinks walks 'rel' having 'root' as the root directory. If there are // symlinks, they are evaluated relative to 'root' to ensure the end result is // the same as if the process was running inside the container. -- cgit v1.2.3