summaryrefslogtreecommitdiffhomepage
path: root/runsc/boot/controller.go
diff options
context:
space:
mode:
Diffstat (limited to 'runsc/boot/controller.go')
-rw-r--r--runsc/boot/controller.go96
1 files changed, 93 insertions, 3 deletions
diff --git a/runsc/boot/controller.go b/runsc/boot/controller.go
index f5b0d371c..b4594c8b0 100644
--- a/runsc/boot/controller.go
+++ b/runsc/boot/controller.go
@@ -21,8 +21,10 @@ import (
"path"
specs "github.com/opencontainers/runtime-spec/specs-go"
+ "gvisor.googlesource.com/gvisor/pkg/abi/linux"
"gvisor.googlesource.com/gvisor/pkg/control/server"
"gvisor.googlesource.com/gvisor/pkg/log"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/arch"
"gvisor.googlesource.com/gvisor/pkg/sentry/control"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel"
@@ -30,6 +32,7 @@ import (
"gvisor.googlesource.com/gvisor/pkg/sentry/state"
"gvisor.googlesource.com/gvisor/pkg/sentry/time"
"gvisor.googlesource.com/gvisor/pkg/sentry/watchdog"
+ "gvisor.googlesource.com/gvisor/pkg/syserror"
"gvisor.googlesource.com/gvisor/pkg/urpc"
)
@@ -37,6 +40,10 @@ const (
// ContainerCheckpoint checkpoints a container.
ContainerCheckpoint = "containerManager.Checkpoint"
+ // ContainerDestroy is used to stop a non-root container and free all
+ // associated resources in the sandbox.
+ ContainerDestroy = "containerManager.Destroy"
+
// ContainerEvent is the URPC endpoint for getting stats about the
// container used by "runsc events".
ContainerEvent = "containerManager.Event"
@@ -58,9 +65,6 @@ const (
// ContainerResume unpauses the paused container.
ContainerResume = "containerManager.Resume"
- // ContainerWaitForLoader blocks until the container's loader has been created.
- ContainerWaitForLoader = "containerManager.WaitForLoader"
-
// ContainerSignal is used to send a signal to a container.
ContainerSignal = "containerManager.Signal"
@@ -72,6 +76,9 @@ const (
// and return its ExitStatus.
ContainerWait = "containerManager.Wait"
+ // ContainerWaitForLoader blocks until the container's loader has been created.
+ ContainerWaitForLoader = "containerManager.WaitForLoader"
+
// ContainerWaitPID is used to wait on a process with a certain PID in
// the sandbox and return its ExitStatus.
ContainerWaitPID = "containerManager.WaitPID"
@@ -228,6 +235,89 @@ func (cm *containerManager) Start(args *StartArgs, _ *struct{}) error {
return nil
}
+// Destroy stops a container if it is still running and cleans up its
+// filesystem.
+func (cm *containerManager) Destroy(cid *string, _ *struct{}) error {
+ log.Debugf("containerManager.destroy %q", *cid)
+ cm.l.mu.Lock()
+ defer cm.l.mu.Unlock()
+
+ if tg, ok := cm.l.containerRootTGs[*cid]; ok {
+ // Send SIGKILL to threadgroup.
+ if err := tg.SendSignal(&arch.SignalInfo{
+ Signo: int32(linux.SIGKILL),
+ Code: arch.SignalInfoUser,
+ }); err == nil {
+ // SIGKILL sent. Now wait for it to exit.
+ log.Debugf("Waiting for container process to exit.")
+ tg.WaitExited()
+ log.Debugf("Container process exited.")
+ } else if err != syserror.ESRCH {
+ return fmt.Errorf("error sending SIGKILL to container %q: %v", *cid, err)
+ }
+
+ // Remove the container thread group from the map.
+ delete(cm.l.containerRootTGs, *cid)
+ }
+
+ // Clean up the filesystem by unmounting all mounts for this container
+ // and deleting the container root directory.
+
+ // First get a reference to the container root directory.
+ mns := cm.l.k.RootMountNamespace()
+ mnsRoot := mns.Root()
+ defer mnsRoot.DecRef()
+ ctx := cm.l.rootProcArgs.NewContext(cm.l.k)
+ containerRoot := path.Join(ChildContainersDir, *cid)
+ containerRootDirent, err := mns.FindInode(ctx, mnsRoot, nil, containerRoot, linux.MaxSymlinkTraversals)
+ if err == syserror.ENOENT {
+ // Container must have been destroyed already. That's fine.
+ return nil
+ }
+ if err != nil {
+ return fmt.Errorf("error finding container root directory %q: %v", containerRoot, err)
+ }
+ defer containerRootDirent.DecRef()
+
+ // Iterate through all submounts and unmount them. We unmount lazily by
+ // setting detach=true, so we can unmount in any order.
+ for _, m := range containerRootDirent.Inode.MountSource.Submounts() {
+ root := m.Root()
+ defer root.DecRef()
+
+ // Do a best-effort unmount by flushing the refs and unmount
+ // with "detach only = true".
+ log.Debugf("Unmounting container submount %q", root.BaseName())
+ m.FlushDirentRefs()
+ if err := mns.Unmount(ctx, root, true /* detach only */); err != nil {
+ return fmt.Errorf("error unmounting container submount %q: %v", root.BaseName(), err)
+ }
+ }
+
+ // Unmount the container root itself.
+ log.Debugf("Unmounting container root %q", containerRoot)
+ containerRootDirent.Inode.MountSource.FlushDirentRefs()
+ if err := mns.Unmount(ctx, containerRootDirent, true /* detach only */); err != nil {
+ return fmt.Errorf("error unmounting container root mount %q: %v", containerRootDirent.BaseName(), err)
+ }
+
+ // Get a reference to the parent directory and remove the root
+ // container directory.
+ containersDirDirent, err := mns.FindInode(ctx, mnsRoot, nil, ChildContainersDir, linux.MaxSymlinkTraversals)
+ if err != nil {
+ return fmt.Errorf("error finding containers directory %q: %v", ChildContainersDir, err)
+ }
+ defer containersDirDirent.DecRef()
+ log.Debugf("Deleting container root %q", containerRoot)
+ if err := containersDirDirent.RemoveDirectory(ctx, mnsRoot, *cid); err != nil {
+ return fmt.Errorf("error removing directory %q: %v", containerRoot, err)
+ }
+
+ // We made it!
+ log.Debugf("Destroyed container %q", *cid)
+ return nil
+}
+
// ExecArgs contains arguments to Execute.
type ExecArgs struct {
control.ExecArgs