From 873ec0c414973e829c1570f21d0d2e2a0df681f4 Mon Sep 17 00:00:00 2001 From: Justine Olshan Date: Mon, 18 Jun 2018 15:19:36 -0700 Subject: [PATCH] Modified boot.go to allow for restores. A file descriptor was added as a flag to boot so a state file can restore a container that was checkpointed. PiperOrigin-RevId: 201068699 Change-Id: I18e96069488ffa3add468861397f3877725544aa --- runsc/boot/BUILD | 1 + runsc/boot/loader.go | 46 ++++++++++++++++++++++++++------------- runsc/boot/loader_test.go | 2 +- runsc/cmd/boot.go | 6 ++++- 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/runsc/boot/BUILD b/runsc/boot/BUILD index 1a81acde5..8b3b09a22 100644 --- a/runsc/boot/BUILD +++ b/runsc/boot/BUILD @@ -51,6 +51,7 @@ go_library( "//pkg/sentry/socket/netlink", "//pkg/sentry/socket/netlink/route", "//pkg/sentry/socket/unix", + "//pkg/sentry/state", "//pkg/sentry/strace", "//pkg/sentry/syscalls/linux", "//pkg/sentry/time", diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go index 89300a953..526e8f8bb 100644 --- a/runsc/boot/loader.go +++ b/runsc/boot/loader.go @@ -18,6 +18,7 @@ package boot import ( "fmt" "math/rand" + "os" "runtime" "sync/atomic" "syscall" @@ -35,6 +36,7 @@ import ( "gvisor.googlesource.com/gvisor/pkg/sentry/platform/kvm" "gvisor.googlesource.com/gvisor/pkg/sentry/platform/ptrace" "gvisor.googlesource.com/gvisor/pkg/sentry/sighandling" + "gvisor.googlesource.com/gvisor/pkg/sentry/state" slinux "gvisor.googlesource.com/gvisor/pkg/sentry/syscalls/linux" "gvisor.googlesource.com/gvisor/pkg/sentry/time" "gvisor.googlesource.com/gvisor/pkg/sentry/watchdog" @@ -90,7 +92,7 @@ func init() { } // New initializes a new kernel loader configured by spec. -func New(spec *specs.Spec, conf *Config, controllerFD int, ioFDs []int, console bool) (*Loader, error) { +func New(spec *specs.Spec, conf *Config, controllerFD, restoreFD int, ioFDs []int, console bool) (*Loader, error) { // Create kernel and platform. p, err := createPlatform(conf) if err != nil { @@ -165,20 +167,34 @@ func New(spec *specs.Spec, conf *Config, controllerFD int, ioFDs []int, console // Run(). networkStack := newEmptyNetworkStack(conf, k) - // Initiate the Kernel object, which is required by the Context passed - // to createVFS in order to mount (among other things) procfs. - if err = k.Init(kernel.InitKernelArgs{ - FeatureSet: cpuid.HostFeatureSet(), - Timekeeper: tk, - RootUserNamespace: creds.UserNamespace, - NetworkStack: networkStack, - // TODO: use number of logical processors from cgroups. - ApplicationCores: uint(runtime.NumCPU()), - Vdso: vdso, - RootUTSNamespace: utsns, - RootIPCNamespace: ipcns, - }); err != nil { - return nil, fmt.Errorf("error initializing kernel: %v", err) + // Check if we need to restore the kernel + if restoreFD != -1 { + restoreFile := os.NewFile(uintptr(restoreFD), "restore_file") + defer restoreFile.Close() + + // Load the state. + loadOpts := state.LoadOpts{ + Source: restoreFile, + } + if err := loadOpts.Load(k, p, networkStack); err != nil { + return nil, err + } + } else { + // Initiate the Kernel object, which is required by the Context passed + // to createVFS in order to mount (among other things) procfs. + if err = k.Init(kernel.InitKernelArgs{ + FeatureSet: cpuid.HostFeatureSet(), + Timekeeper: tk, + RootUserNamespace: creds.UserNamespace, + NetworkStack: networkStack, + // TODO: use number of logical processors from cgroups. + ApplicationCores: uint(runtime.NumCPU()), + Vdso: vdso, + RootUTSNamespace: utsns, + RootIPCNamespace: ipcns, + }); err != nil { + return nil, fmt.Errorf("error initializing kernel: %v", err) + } } // Turn on packet logging if enabled. diff --git a/runsc/boot/loader_test.go b/runsc/boot/loader_test.go index a7f59f775..dab7ad0c5 100644 --- a/runsc/boot/loader_test.go +++ b/runsc/boot/loader_test.go @@ -59,7 +59,7 @@ func createLoader() (*Loader, error) { FileAccess: FileAccessDirect, DisableSeccomp: true, } - return New(testSpec(), conf, fd, nil, false) + return New(testSpec(), conf, fd, -1, nil, false) } // TestRun runs a simple application in a sandbox and checks that it succeeds. diff --git a/runsc/cmd/boot.go b/runsc/cmd/boot.go index 34dd8b3c0..86f597c09 100644 --- a/runsc/cmd/boot.go +++ b/runsc/cmd/boot.go @@ -48,6 +48,9 @@ type Boot struct { // applyCaps determines if capabilities defined in the spec should be applied // to the process. applyCaps bool + + // restoreFD is the file descriptor to the state file to be restored. + restoreFD int } // Name implements subcommands.Command.Name. @@ -72,6 +75,7 @@ func (b *Boot) SetFlags(f *flag.FlagSet) { f.Var(&b.ioFDs, "io-fds", "list of FDs to connect 9P clients. They must follow this order: root first, then mounts as defined in the spec") f.BoolVar(&b.console, "console", false, "set to true if the sandbox should allow terminal ioctl(2) syscalls") f.BoolVar(&b.applyCaps, "apply-caps", false, "if true, apply capabilities defined in the spec to the process") + f.IntVar(&b.restoreFD, "restore-fd", -1, "FD of the state file to be restored") } // Execute implements subcommands.Command.Execute. It starts a sandbox in a @@ -127,7 +131,7 @@ func (b *Boot) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) } // Create the loader. - l, err := boot.New(spec, conf, b.controllerFD, b.ioFDs.GetArray(), b.console) + l, err := boot.New(spec, conf, b.controllerFD, b.restoreFD, b.ioFDs.GetArray(), b.console) if err != nil { Fatalf("error creating loader: %v", err) }