Add helper functions for checkpoint/restore of linux containers using CRIU.
Signed-off-by: Radostin Stoyanov <rstoyan...@gmail.com> --- po/POTFILES.in | 1 + src/lxc/Makefile.inc.am | 4 + src/lxc/lxc_criu.c | 253 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_criu.h | 36 +++++++ 4 files changed, 294 insertions(+) create mode 100644 src/lxc/lxc_criu.c create mode 100644 src/lxc/lxc_criu.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 0dcd1cab2..a6d3a5743 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -106,6 +106,7 @@ src/lxc/lxc_fuse.c src/lxc/lxc_hostdev.c src/lxc/lxc_native.c src/lxc/lxc_process.c +src/lxc/lxc_criu.c src/network/bridge_driver.c src/network/bridge_driver_linux.c src/network/leaseshelper.c diff --git a/src/lxc/Makefile.inc.am b/src/lxc/Makefile.inc.am index 8dd2e9ea9..fbdc87b24 100644 --- a/src/lxc/Makefile.inc.am +++ b/src/lxc/Makefile.inc.am @@ -42,6 +42,8 @@ LXC_DRIVER_SOURCES = \ lxc/lxc_native.h \ lxc/lxc_driver.c \ lxc/lxc_driver.h \ + lxc/lxc_criu.c \ + lxc/lxc_criu.h \ $(NULL) LXC_CONTROLLER_SOURCES = \ @@ -58,6 +60,8 @@ LXC_CONTROLLER_SOURCES = \ lxc/lxc_fuse.c \ lxc/lxc_fuse.h \ lxc/lxc_controller.c \ + lxc/lxc_criu.c \ + lxc/lxc_criu.h \ $(NULL) diff --git a/src/lxc/lxc_criu.c b/src/lxc/lxc_criu.c new file mode 100644 index 000000000..b45f9b9f3 --- /dev/null +++ b/src/lxc/lxc_criu.c @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2016 Katerina Koukiou + * + * lxc_criu.c: Helper functions for checkpoint/restore of linux containers + * + * Authors: + * Katerina Koukiou <k.kouk...@gmail.com> + * Radostin Stoyanov <r.stoyanov...@aberdeen.ac.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/mount.h> + +#include "virobject.h" +#include "virerror.h" +#include "virlog.h" +#include "virfile.h" +#include "vircommand.h" +#include "virstring.h" +#include "viralloc.h" + +#include "lxc_domain.h" +#include "lxc_driver.h" +#include "lxc_criu.h" + +#define VIR_FROM_THIS VIR_FROM_LXC + +VIR_LOG_INIT("lxc.lxc_criu"); + +#ifdef CRIU + +int lxcCriuDump(virLXCDriverPtr driver ATTRIBUTE_UNUSED, + virDomainObjPtr vm, + const char *checkpointdir) +{ + int fd; + int ret = -1; + pid_t initpid; + virCommandPtr cmd; + struct stat sb; + char *path = NULL; + char *tty_info_path = NULL; + char *ttyinfo = NULL; + int status; + + initpid = ((virLXCDomainObjPrivatePtr) vm->privateData)->initpid; + + if (virFileMakePath(checkpointdir) < 0) { + virReportSystemError(errno, _("Failed to mkdir %s"), checkpointdir); + return -1; + } + + fd = open(checkpointdir, O_DIRECTORY); + if (fd < 0) { + virReportSystemError(errno, + _("Failed to open directory %s"), checkpointdir); + return -1; + } + + cmd = virCommandNew(CRIU); + virCommandAddArg(cmd, "dump"); + virCommandAddArg(cmd, "--tree"); + virCommandAddArgFormat(cmd, "%d", initpid); + virCommandAddArgList(cmd, + "--images-dir", checkpointdir, + "--tcp-established", + "--log-file", "dump.log", + "-v4", + "--file-locks", + "--link-remap", + "--force-irmap", + "--manage-cgroups=full", + "--enable-fs", "hugetlbfs", + "--enable-fs", "tracefs", + "--external", "mnt[]{:ms}", + "--external", "mnt[/proc/meminfo]:fuse", + "--external", "mnt[/dev/console]:console", + "--external", "mnt[/dev/tty1]:tty1", + NULL + ); + + /* The master pair of the /dev/pts device lives outside from what is dumped + * inside the libvirt-lxc process. Add the slave pair as an external tty + * otherwise criu will fail. + */ + if (virAsprintf(&path, "/proc/%d/root/dev/pts/0", initpid) < 0) + goto cleanup; + + if (stat(path, &sb) < 0) { + virReportSystemError(errno, _("Unable to stat %s"), path); + goto cleanup; + } + + if (virAsprintf(&tty_info_path, "%s/tty.info", checkpointdir) < 0) + goto cleanup; + + if (virAsprintf(&ttyinfo, "tty[%llx:%llx]", + (long long unsigned) sb.st_rdev, + (long long unsigned) sb.st_dev) < 0) + goto cleanup; + + if (virFileWriteStr(tty_info_path, ttyinfo, 0600) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to write tty info to %s"), tty_info_path); + goto cleanup; + } + + virCommandAddArg(cmd, "--external"); + virCommandAddArgFormat(cmd, "tty[%llx:%llx]", + (long long unsigned) sb.st_rdev, + (long long unsigned) sb.st_dev); + + virCommandAddEnvString(cmd, "PATH=/bin:/sbin"); + + VIR_DEBUG("About to checkpoint domain %s (pid = %d)", + vm->def->name, initpid); + virCommandRawStatus(cmd); + if (virCommandRun(cmd, &status) < 0) + goto cleanup; + + ret = 0; + + cleanup: + VIR_FORCE_CLOSE(fd); + VIR_FREE(path); + VIR_FREE(tty_info_path); + VIR_FREE(ttyinfo); + virCommandFree(cmd); + + return (ret < 0) ? ret : status; +} + + +int lxcCriuRestore(virDomainDefPtr def, int restorefd, + int ttyfd) +{ + int ret = -1; + virCommandPtr cmd; + char *ttyinfo = NULL; + char *inheritfd = NULL; + char *tty_info_path = NULL; + char *checkpointfd = NULL; + char *checkpointdir = NULL; + virDomainFSDefPtr root; + gid_t *groups = NULL; + int ngroups; + + cmd = virCommandNew(CRIU); + virCommandAddArg(cmd, "restore"); + + if (virAsprintf(&checkpointfd, "/proc/self/fd/%d", restorefd) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to write checkpoint dir path")); + goto cleanup; + } + + if (virFileResolveLink(checkpointfd, &checkpointdir) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to readlink checkpoint dir path")); + goto cleanup; + } + + virCommandAddArgList(cmd, + "--pidfile", "pidfile", + "--restore-detached", + "--restore-sibling", + "--tcp-established", + "--file-locks", + "--link-remap", + "--manage-cgroups=full", + "--enable-fs", "hugetlbfs", + "--enable-fs", "tracefs", + "--images-dir", checkpointdir, + "--log-file", "restore.log", + "-v4", + "--external", "mnt[]{:ms}", + "--external", "mnt[fuse]:/proc/meminfo", + "--external", "mnt[console]:/dev/console", + "--external", "mnt[tty1]:/dev/tty1", + NULL + ); + + /* Restore external tty from tty.info file */ + if (virAsprintf(&tty_info_path, "%s/tty.info", checkpointdir) < 0) + goto cleanup; + + if (virFileReadAll(tty_info_path, 1024, &ttyinfo) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to read tty info from %s"), tty_info_path); + goto cleanup; + } + if (virAsprintf(&inheritfd, "fd[%d]:%s", ttyfd, ttyinfo) < 0) + goto cleanup; + + virCommandAddArgList(cmd, "--inherit-fd", inheritfd, NULL); + + root = virDomainGetFilesystemForTarget(def, "/"); + virCommandAddArgList(cmd, "--root", root->src->path, NULL); + + virCommandAddEnvString(cmd, "PATH=/bin:/sbin"); + + if ((ngroups = virGetGroupList(virCommandGetUID(cmd), virCommandGetGID(cmd), &groups)) < 0) + goto cleanup; + + /* If virCommandExec returns here we have an error */ + ignore_value(virCommandExec(cmd, groups, ngroups)); + + ret = -1; + + cleanup: + VIR_FREE(tty_info_path); + VIR_FREE(ttyinfo); + VIR_FREE(inheritfd); + VIR_FREE(checkpointdir); + VIR_FREE(checkpointfd); + virCommandFree(cmd); + + return ret; +} +#else +int lxcCriuDump(virLXCDriverPtr driver ATTRIBUTE_UNUSED, + virDomainObjPtr vm ATTRIBUTE_UNUSED, + const char *checkpointdir ATTRIBUTE_UNUSED) +{ + virReportUnsupportedError(); + return -1; +} + +int lxcCriuRestore(virDomainDefPtr def ATTRIBUTE_UNUSED, + int fd ATTRIBUTE_UNUSED, + int ttyfd ATTRIBUTE_UNUSED) +{ + virReportUnsupportedError(); + return -1; +} +#endif diff --git a/src/lxc/lxc_criu.h b/src/lxc/lxc_criu.h new file mode 100644 index 000000000..aadc3ac34 --- /dev/null +++ b/src/lxc/lxc_criu.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016 Katerina Koukiou + * + * lxc_criu.h: Helper functions for checkpoint/restore of linux containers + * + * Authors: + * Katerina Koukiou <k.kouk...@gmail.com> + * Radostin Stoyanov <r.stoyanov...@aberdeen.ac.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + */ + +#ifndef LXC_CRIU_H +# define LXC_CRIU_H + +# include "virobject.h" + +int lxcCriuDump(virLXCDriverPtr driver, + virDomainObjPtr vm, + const char *checkpointdir); + +int lxcCriuRestore(virDomainDefPtr def, int fd, + int ttyfd); +#endif /* LXC_CRIU_H */ -- 2.14.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list