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 <rboucher@gmail.com>
Signed-off-by: Andrey Vagin <avagin@openvz.org>
This commit is contained in:
Andrey Vagin 2015-07-20 21:25:22 +03:00
parent 1eeb86fbf2
commit af4a5e708a
2 changed files with 83 additions and 40 deletions

View File

@ -293,6 +293,19 @@ func (c *linuxContainer) checkCriuVersion() error {
const descriptors_filename = "descriptors.json" 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 { func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
c.m.Lock() c.m.Lock()
defer c.m.Unlock() defer c.m.Unlock()
@ -356,22 +369,25 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
} }
t := criurpc.CriuReqType_DUMP t := criurpc.CriuReqType_DUMP
req := criurpc.CriuReq{ req := &criurpc.CriuReq{
Type: &t, Type: &t,
Opts: &rpcOpts, Opts: &rpcOpts,
} }
for _, m := range c.config.Mounts { for _, m := range c.config.Mounts {
if m.Device == "bind" { switch m.Device {
mountDest := m.Destination case "bind":
if strings.HasPrefix(mountDest, c.config.Rootfs) { c.addCriuDumpMount(req, m)
mountDest = mountDest[len(c.config.Rootfs):] break
case "cgroup":
binds, err := getCgroupMounts(m)
if err != nil {
return err
} }
for _, b := range binds {
extMnt := new(criurpc.ExtMountMap) c.addCriuDumpMount(req, b)
extMnt.Key = proto.String(mountDest) }
extMnt.Val = proto.String(mountDest) break
req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt)
} }
} }
@ -387,13 +403,26 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
return err return err
} }
err = c.criuSwrk(nil, &req, criuOpts) err = c.criuSwrk(nil, req, criuOpts)
if err != nil { if err != nil {
return err return err
} }
return nil 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 { func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
c.m.Lock() c.m.Lock()
defer c.m.Unlock() defer c.m.Unlock()
@ -449,7 +478,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
defer syscall.Unmount(root, syscall.MNT_DETACH) defer syscall.Unmount(root, syscall.MNT_DETACH)
t := criurpc.CriuReqType_RESTORE t := criurpc.CriuReqType_RESTORE
req := criurpc.CriuReq{ req := &criurpc.CriuReq{
Type: &t, Type: &t,
Opts: &criurpc.CriuOpts{ Opts: &criurpc.CriuOpts{
ImagesDirFd: proto.Int32(int32(imageDir.Fd())), 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 { for _, m := range c.config.Mounts {
if m.Device == "bind" { switch m.Device {
mountDest := m.Destination case "bind":
if strings.HasPrefix(mountDest, c.config.Rootfs) { c.addCriuRestoreMount(req, m)
mountDest = mountDest[len(c.config.Rootfs):] break
case "cgroup":
binds, err := getCgroupMounts(m)
if err != nil {
return err
} }
for _, b := range binds {
extMnt := new(criurpc.ExtMountMap) c.addCriuRestoreMount(req, b)
extMnt.Key = proto.String(mountDest) }
extMnt.Val = proto.String(m.Source) break
req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt)
} }
} }
for _, iface := range c.config.Networks { 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 { if err != nil {
return err return err
} }

View File

@ -170,27 +170,10 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
} }
} }
case "cgroup": case "cgroup":
mounts, err := cgroups.GetCgroupMounts() binds, err := getCgroupMounts(m)
if err != nil { if err != nil {
return err 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{ tmpfs := &configs.Mount{
Source: "tmpfs", Source: "tmpfs",
Device: "tmpfs", Device: "tmpfs",
@ -211,6 +194,34 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
return nil 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 // checkMountDestination checks to ensure that the mount destination is not over the
// top of /proc or /sys. // top of /proc or /sys.
// dest is required to be an abs path and have any symlinks resolved before calling this function. // dest is required to be an abs path and have any symlinks resolved before calling this function.