diff options
Diffstat (limited to 'runsc/boot/loader.go')
-rw-r--r-- | runsc/boot/loader.go | 48 |
1 files changed, 31 insertions, 17 deletions
diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go index 8e8c6105b..a8adaf292 100644 --- a/runsc/boot/loader.go +++ b/runsc/boot/loader.go @@ -35,6 +35,7 @@ import ( "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/sentry/arch" "gvisor.dev/gvisor/pkg/sentry/control" + "gvisor.dev/gvisor/pkg/sentry/fs" "gvisor.dev/gvisor/pkg/sentry/fs/host" "gvisor.dev/gvisor/pkg/sentry/inet" "gvisor.dev/gvisor/pkg/sentry/kernel" @@ -525,8 +526,7 @@ func (l *Loader) run() error { } rootCtx := l.rootProcArgs.NewContext(l.k) - rootMns := l.k.RootMountNamespace() - if err := setExecutablePath(rootCtx, rootMns, &l.rootProcArgs); err != nil { + if err := setExecutablePath(rootCtx, &l.rootProcArgs); err != nil { return err } @@ -540,7 +540,7 @@ func (l *Loader) run() error { } } if !hasHomeEnvv { - homeDir, err := getExecUserHome(rootCtx, rootMns, uint32(l.rootProcArgs.Credentials.RealKUID)) + homeDir, err := getExecUserHome(rootCtx, l.rootProcArgs.MountNamespace, uint32(l.rootProcArgs.Credentials.RealKUID)) if err != nil { return fmt.Errorf("error reading exec user: %v", err) } @@ -663,8 +663,7 @@ func (l *Loader) startContainer(spec *specs.Spec, conf *Config, cid string, file return fmt.Errorf("configuring container FS: %v", err) } - mns := l.k.RootMountNamespace() - if err := setExecutablePath(ctx, mns, &procArgs); err != nil { + if err := setExecutablePath(ctx, &procArgs); err != nil { return fmt.Errorf("setting executable path for %+v: %v", procArgs, err) } @@ -689,8 +688,10 @@ func (l *Loader) destroyContainer(cid string) error { defer l.mu.Unlock() // Has the container started? - if _, _, err := l.threadGroupFromIDLocked(execID{cid: cid}); err == nil { - // If the container has started, kill and wait for all processes. + _, _, err := l.threadGroupFromIDLocked(execID{cid: cid}) + + // If the container has started, kill and wait for all processes. + if err == nil { if err := l.signalAllProcesses(cid, int32(linux.SIGKILL)); err != nil { return fmt.Errorf("sending SIGKILL to all container processes: %v", err) } @@ -703,12 +704,17 @@ func (l *Loader) destroyContainer(cid string) error { } } - ctx := l.rootProcArgs.NewContext(l.k) - if err := destroyContainerFS(ctx, cid, l.k); err != nil { - return fmt.Errorf("destroying filesystem for container %q: %v", cid, err) - } + // At this point, all processes inside of the container have exited, + // releasing all references to the container's MountNamespace and + // causing all submounts and overlays to be unmounted. + // + // Since the container's MountNamespace has been released, + // MountNamespace.destroy() will have executed, but that function may + // trigger async close operations. We must wait for those to complete + // before returning, otherwise the caller may kill the gofer before + // they complete, causing a cascade of failing RPCs. + fs.AsyncBarrier() - // We made it! log.Debugf("Container destroyed %q", cid) return nil } @@ -724,14 +730,22 @@ func (l *Loader) executeAsync(args *control.ExecArgs) (kernel.ThreadID, error) { return 0, fmt.Errorf("no such container: %q", args.ContainerID) } - // Get the container Root Dirent from the Task, since we must run this - // process with the same Root. + // Get the container Root Dirent and MountNamespace from the Task. tg.Leader().WithMuLocked(func(t *kernel.Task) { + // FSContext.RootDirectory() will take an extra ref for us. args.Root = t.FSContext().RootDirectory() + + // task.MountNamespace() does not take a ref, so we must do so + // ourselves. + args.MountNamespace = t.MountNamespace() + args.MountNamespace.IncRef() }) - if args.Root != nil { - defer args.Root.DecRef() - } + defer func() { + if args.Root != nil { + args.Root.DecRef() + } + args.MountNamespace.DecRef() + }() // Start the process. proc := control.Proc{Kernel: l.k} |