summaryrefslogtreecommitdiffhomepage
path: root/runsc
diff options
context:
space:
mode:
authorLantao Liu <lantaol@google.com>2018-08-28 11:52:56 -0700
committerShentubot <shentubot@google.com>2018-08-28 11:54:07 -0700
commitd8f0db9bcf2ecfaf7fb1b09d7d4cace3a8e40cc7 (patch)
treea9ba2668b904a383d9c7bfe931999afecfe91db8 /runsc
parentf7366e4e6465530ecc1641312011fd82a94f55f8 (diff)
runsc: unmount volume mounts when destroy container.
PiperOrigin-RevId: 210579178 Change-Id: Iae20639c5186b1a976cbff6d05bda134cd00d0da
Diffstat (limited to 'runsc')
-rw-r--r--runsc/container/container.go12
-rw-r--r--runsc/container/fs.go29
2 files changed, 37 insertions, 4 deletions
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.