On Thu, Jul 21, 2016 at 03:37:25PM +0000, Katerina Koukiou wrote: > This patch adds some helper functions for checkpointing/restoring > linux containers. We use CRIU binary. > > Signed-off-by: Katerina Koukiou <k.koukiou@xxxxxxxxx> > --- > po/POTFILES.in | 1 + > src/Makefile.am | 3 +- > src/lxc/lxc_criu.c | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > src/lxc/lxc_criu.h | 34 +++++++ > 4 files changed, 310 insertions(+), 1 deletion(-) > 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 a6b6c9c..718b11d 100644 > --- a/po/POTFILES.in > +++ b/po/POTFILES.in > @@ -95,6 +95,7 @@ src/lxc/lxc_cgroup.c > src/lxc/lxc_conf.c > src/lxc/lxc_container.c > src/lxc/lxc_controller.c > +src/lxc/lxc_criu.c > src/lxc/lxc_domain.c > src/lxc/lxc_driver.c > src/lxc/lxc_fuse.c > diff --git a/src/Makefile.am b/src/Makefile.am > index 78c493c..64a7680 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -750,7 +750,8 @@ LXC_DRIVER_SOURCES = \ > lxc/lxc_process.c lxc/lxc_process.h \ > lxc/lxc_fuse.c lxc/lxc_fuse.h \ > lxc/lxc_native.c lxc/lxc_native.h \ > - lxc/lxc_driver.c lxc/lxc_driver.h > + lxc/lxc_driver.c lxc/lxc_driver.h \ > + lxc/lxc_criu.c lxc/lxc_criu.h > > LXC_CONTROLLER_SOURCES = \ > $(LXC_MONITOR_PROTOCOL_GENERATED) \ > diff --git a/src/lxc/lxc_criu.c b/src/lxc/lxc_criu.c > new file mode 100644 > index 0000000..6944223 > --- /dev/null > +++ b/src/lxc/lxc_criu.c > @@ -0,0 +1,273 @@ > +/* > + * lxc_criu.c: wrapper functions for CRIU C API to be used for lxc migration > + * > + * Copyright (C) 2016 Katerina Koukiou > + * > + * 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/>. > + * > + * Author: Katerina Koukiou <k.koukiou@xxxxxxxxx> > + */ > + > +#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) For dumping a container we should be creating a single file containing all the data, not creating multiple files spread across a directory. Take a look at what we do with the QEMU driver where we have a magic header, then the XML description and the the actual dumped state from QEMU. We should do the same kind of thing with LXC. > +{ > + int fd; > + int ret = -1; > + virLXCDomainObjPrivatePtr priv; > + virCommandPtr cmd; > + struct stat sb; > + char *path = NULL; > + char *tty_info_path = NULL; > + char *ttyinfo = NULL; > + int status; > + > + 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"); > + > + virCommandAddArgList(cmd, "--images-dir", checkpointdir, NULL); > + > + virCommandAddArgList(cmd, "--log-file", "dump.log", NULL); > + > + virCommandAddArgList(cmd, "-vvvv", NULL); > + > + priv = vm->privateData; > + virCommandAddArg(cmd, "--tree"); > + virCommandAddArgFormat(cmd, "%d", priv->initpid); > + > + virCommandAddArgList(cmd, "--tcp-established", "--file-locks", > + "--link-remap", "--force-irmap", NULL); > + > + virCommandAddArgList(cmd, "--manage-cgroup", NULL); > + > + virCommandAddArgList(cmd, "--enable-external-sharing", > + "--enable-external-masters", NULL); > + > + virCommandAddArgList(cmd, "--enable-fs", "hugetlbfs", > + "--enable-fs", "tracefs", NULL); > + > + /* Add support for FUSE */ > + virCommandAddArgList(cmd, "--ext-mount-map", "/proc/meminfo:fuse", NULL); > + virCommandAddArgList(cmd, "--ghost-limit", "10000000", NULL); > + > + virCommandAddArgList(cmd, "--ext-mount-map", "/dev/console:console", NULL); > + virCommandAddArgList(cmd, "--ext-mount-map", "/dev/tty1:tty1", NULL); > + virCommandAddArgList(cmd, "--ext-mount-map", "auto", 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", priv->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[%x:%x]", > + (unsigned int)sb.st_rdev, (unsigned int)sb.st_dev) < 0) > + goto cleanup; > + > + if (virFileWriteStr(tty_info_path, ttyinfo, 0666) < 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("Failed to write tty info to %s"), tty_info_path); > + goto cleanup; > + } > + > + VIR_DEBUG("tty.info: tty[%x:%x]", > + (unsigned int)sb.st_dev, (unsigned int)sb.st_rdev); > + virCommandAddArg(cmd, "--external"); > + virCommandAddArgFormat(cmd, "tty[%x:%x]", > + (unsigned int)sb.st_rdev, (unsigned int)sb.st_dev); > + > + VIR_DEBUG("About to checkpoint domain %s (pid = %d)", > + vm->def->name, priv->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); > + > + if (ret < 0) > + return ret; > + return 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; > + char *rootfs_mount = NULL; > + > + 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; > + } > + > + /* CRIU needs the container's root bind mounted so that it is the root of > + * some mount. > + */ > + if (virAsprintf(&rootfs_mount, "/tmp/%s", def->name) < 0) { If this is a directory on the host filesysten, then this is a security flaw. You must never create predictable filenames in /tmp. Ideally files would be under one of the private directores libvirt already uses in /var/run/libvirt or /var/lib/libvirt Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :| -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list