From af4a5e708a943879c02f7941a1d2e7b845544c66 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Mon, 20 Jul 2015 21:25:22 +0300 Subject: [PATCH] ct: give criu informations about cgroup mounts Actually cgroup mounts are bind-mounts, so they should be handled by the same way. Reported-by: Ross Boucher Signed-off-by: Andrey Vagin --- libcontainer/container_linux.go | 76 +++++++++++++++++++++++---------- libcontainer/rootfs_linux.go | 47 ++++++++++++-------- 2 files changed, 83 insertions(+), 40 deletions(-) diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go index 7d9fa71a..4e4a6a8b 100644 --- a/libcontainer/container_linux.go +++ b/libcontainer/container_linux.go @@ -293,6 +293,19 @@ func (c *linuxContainer) checkCriuVersion() error { const descriptors_filename = "descriptors.json" +func (c *linuxContainer) addCriuDumpMount(req *criurpc.CriuReq, m *configs.Mount) { + mountDest := m.Destination + if strings.HasPrefix(mountDest, c.config.Rootfs) { + mountDest = mountDest[len(c.config.Rootfs):] + } + + extMnt := &criurpc.ExtMountMap{ + Key: proto.String(mountDest), + Val: proto.String(mountDest), + } + req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt) +} + func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { c.m.Lock() defer c.m.Unlock() @@ -356,22 +369,25 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { } t := criurpc.CriuReqType_DUMP - req := criurpc.CriuReq{ + req := &criurpc.CriuReq{ Type: &t, Opts: &rpcOpts, } for _, m := range c.config.Mounts { - if m.Device == "bind" { - mountDest := m.Destination - if strings.HasPrefix(mountDest, c.config.Rootfs) { - mountDest = mountDest[len(c.config.Rootfs):] + switch m.Device { + case "bind": + c.addCriuDumpMount(req, m) + break + case "cgroup": + binds, err := getCgroupMounts(m) + if err != nil { + return err } - - extMnt := new(criurpc.ExtMountMap) - extMnt.Key = proto.String(mountDest) - extMnt.Val = proto.String(mountDest) - req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt) + for _, b := range binds { + c.addCriuDumpMount(req, b) + } + break } } @@ -387,13 +403,26 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { return err } - err = c.criuSwrk(nil, &req, criuOpts) + err = c.criuSwrk(nil, req, criuOpts) if err != nil { return err } return nil } +func (c *linuxContainer) addCriuRestoreMount(req *criurpc.CriuReq, m *configs.Mount) { + mountDest := m.Destination + if strings.HasPrefix(mountDest, c.config.Rootfs) { + mountDest = mountDest[len(c.config.Rootfs):] + } + + extMnt := &criurpc.ExtMountMap{ + Key: proto.String(mountDest), + Val: proto.String(m.Source), + } + req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt) +} + func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { c.m.Lock() defer c.m.Unlock() @@ -449,7 +478,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { defer syscall.Unmount(root, syscall.MNT_DETACH) t := criurpc.CriuReqType_RESTORE - req := criurpc.CriuReq{ + req := &criurpc.CriuReq{ Type: &t, Opts: &criurpc.CriuOpts{ ImagesDirFd: proto.Int32(int32(imageDir.Fd())), @@ -468,16 +497,19 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { }, } for _, m := range c.config.Mounts { - if m.Device == "bind" { - mountDest := m.Destination - if strings.HasPrefix(mountDest, c.config.Rootfs) { - mountDest = mountDest[len(c.config.Rootfs):] + switch m.Device { + case "bind": + c.addCriuRestoreMount(req, m) + break + case "cgroup": + binds, err := getCgroupMounts(m) + if err != nil { + return err } - - extMnt := new(criurpc.ExtMountMap) - extMnt.Key = proto.String(mountDest) - extMnt.Val = proto.String(m.Source) - req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt) + for _, b := range binds { + c.addCriuRestoreMount(req, b) + } + break } } for _, iface := range c.config.Networks { @@ -515,7 +547,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { } } - err = c.criuSwrk(process, &req, criuOpts) + err = c.criuSwrk(process, req, criuOpts) if err != nil { return err } diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go index a211d8de..ace93b77 100644 --- a/libcontainer/rootfs_linux.go +++ b/libcontainer/rootfs_linux.go @@ -170,27 +170,10 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { } } case "cgroup": - mounts, err := cgroups.GetCgroupMounts() + binds, err := getCgroupMounts(m) if err != nil { return err } - var binds []*configs.Mount - for _, mm := range mounts { - dir, err := mm.GetThisCgroupDir() - if err != nil { - return err - } - relDir, err := filepath.Rel(mm.Root, dir) - if err != nil { - return err - } - binds = append(binds, &configs.Mount{ - Device: "bind", - Source: filepath.Join(mm.Mountpoint, relDir), - Destination: filepath.Join(m.Destination, strings.Join(mm.Subsystems, ",")), - Flags: syscall.MS_BIND | syscall.MS_REC | m.Flags, - }) - } tmpfs := &configs.Mount{ Source: "tmpfs", Device: "tmpfs", @@ -211,6 +194,34 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error { return nil } +func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) { + mounts, err := cgroups.GetCgroupMounts() + if err != nil { + return nil, err + } + + var binds []*configs.Mount + + for _, mm := range mounts { + dir, err := mm.GetThisCgroupDir() + if err != nil { + return nil, err + } + relDir, err := filepath.Rel(mm.Root, dir) + if err != nil { + return nil, err + } + binds = append(binds, &configs.Mount{ + Device: "bind", + Source: filepath.Join(mm.Mountpoint, relDir), + Destination: filepath.Join(m.Destination, strings.Join(mm.Subsystems, ",")), + Flags: syscall.MS_BIND | syscall.MS_REC | m.Flags, + }) + } + + return binds, nil +} + // checkMountDestination checks to ensure that the mount destination is not over the // top of /proc or /sys. // dest is required to be an abs path and have any symlinks resolved before calling this function.