]> git.proxmox.com Git - mirror_lxc.git/commitdiff
add experimental checkpoint and restart commands
authorlegoater <legoater>
Fri, 19 Sep 2008 10:20:04 +0000 (10:20 +0000)
committerlegoater <legoater>
Fri, 19 Sep 2008 10:20:04 +0000 (10:20 +0000)
src/lxc/Makefile.am
src/lxc/checkpoint.c [new file with mode: 0644]
src/lxc/lxc.h
src/lxc/lxc_checkpoint.c [new file with mode: 0644]
src/lxc/lxc_restart.c [new file with mode: 0644]
src/lxc/restart.c [new file with mode: 0644]

index e659b4bd78d5a90891d808c065b3845b167cf475..ea85fb204fbbedfa16de6750624227638cec2334 100644 (file)
@@ -22,6 +22,8 @@ liblxc_la_SOURCES = \
        monitor.c monitor.h \
        kill.c \
        freezer.c \
+       checkpoint.c \
+       restart.c \
        version.c \
        lxc_cgroup.c lxc_cgroup.h \
        lxc.h \
@@ -57,6 +59,8 @@ bin_PROGRAMS = \
        lxc-info \
        lxc-unfreeze \
        lxc-priority \
+       lxc-checkpoint \
+       lxc-restart \
        lxc-version
 
 lxc_create_SOURCES = lxc_create.c lxc_config.c lxc_config.h
@@ -98,5 +102,11 @@ lxc_unfreeze_LDADD = liblxc.la
 lxc_priority_SOURCES = lxc_priority.c
 lxc_priority_LDADD = liblxc.la
 
+lxc_checkpoint_SOURCES = lxc_checkpoint.c
+lxc_checkpoint_LDADD = liblxc.la
+
+lxc_restart_SOURCES = lxc_restart.c
+lxc_restart_LDADD = liblxc.la
+
 lxc_version_SOURCES = lxc_version.c
 lxc_version_LDADD = liblxc.la
diff --git a/src/lxc/checkpoint.c b/src/lxc/checkpoint.c
new file mode 100644 (file)
index 0000000..954ee33
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <lxc.h>
+
+
+#if __i386__
+#    define __NR_checkpoint 334
+#else
+#    error "Architecture not supported"
+#endif
+static inline long sys_checkpoint(pid_t pid, int fd, unsigned long flags)
+{
+       return syscall(__NR_checkpoint, pid, fd, flags);
+}
+
+int lxc_checkpoint(const char *name, int cfd, unsigned long flags)
+{
+       char init[MAXPATHLEN];
+       char val[MAXPIDLEN];
+       int fd, lock, ret = -1;
+       size_t pid;
+
+       lock = lxc_get_lock(name);
+       if (lock > 0) {
+               lxc_log_error("'%s' is not running", name);
+               lxc_put_lock(lock);
+               return -1;
+       }
+
+       if (lock < 0) {
+               lxc_log_error("failed to acquire the lock on '%s':%s", 
+                             name, strerror(-lock));
+               return -1;
+       }
+
+       snprintf(init, MAXPATHLEN, LXCPATH "/%s/init", name);
+       fd = open(init, O_RDONLY);
+       if (fd < 0) {
+               lxc_log_syserror("failed to open init file for %s", name);
+               goto out_unlock;
+       }
+       
+       if (read(fd, val, sizeof(val)) < 0) {
+               lxc_log_syserror("failed to read %s", init);
+               goto out_close;
+       }
+
+       pid = atoi(val);
+
+       if (sys_checkpoint(pid, cfd, flags) < 0) {
+               lxc_log_syserror("failed to checkpoint %zd", pid);
+               goto out_close;
+       }
+
+       ret = 0;
+
+out_close:
+       close(fd);
+out_unlock:
+       lxc_put_lock(lock);
+       return ret;
+}
index 166ab52b963ff75fe3c33b12d774539f743167f9..722d8afde7ca6bd89233a2994c1df67467bc3ac9 100644 (file)
@@ -250,6 +250,24 @@ extern int lxc_cgroup_get_cpuset(const char *name, long *cpumask,
  */
 extern int lxc_cgroup_get_cpu_usage(const char *name, long long *usage);
 
+/*
+ * Checkpoint a container previously frozen
+ * @name : the name of the container being checkpointed
+ * @fd : file descriptor on which the container is checkpointed
+ * @flags : checkpoint flags
+ * Returns 0 on success, < 0 otherwise
+ */
+extern int lxc_checkpoint(const char *name, int fd, unsigned long flags);
+
+/*
+ * Restart a container previously frozen
+ * @name : the name of the container being restarted
+ * @fd : file descriptor from which the container is restarted
+ * @flags : restart flags
+ * Returns 0 on success, < 0 otherwise
+ */
+extern int lxc_restart(const char *name, int fd, unsigned long flags);
+
 /*
  * Returns the version number of the library
  */
diff --git a/src/lxc/lxc_checkpoint.c b/src/lxc/lxc_checkpoint.c
new file mode 100644 (file)
index 0000000..f18864c
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <stdio.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <lxc.h>
+
+void usage(char *cmd)
+{
+       fprintf(stderr, "%s <command>\n", basename(cmd));
+       fprintf(stderr, "\t -n <name>   : name of the container\n");
+       _exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+       char opt;
+       char *name = NULL;
+       int nbargs = 0;
+
+       while ((opt = getopt(argc, argv, "n:")) != -1) {
+               switch (opt) {
+               case 'n':
+                       name = optarg;
+                       break;
+               }
+
+               nbargs++;
+       }
+
+       if (!name)
+               usage(argv[0]);
+
+       if (lxc_checkpoint(name, STDOUT_FILENO, 0)) {
+               fprintf(stderr, "failed to checkpoint %s\n", name);
+               return 1;
+       }
+
+       return 0;
+}
diff --git a/src/lxc/lxc_restart.c b/src/lxc/lxc_restart.c
new file mode 100644 (file)
index 0000000..43c94f1
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <stdio.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <lxc.h>
+
+void usage(char *cmd)
+{
+       fprintf(stderr, "%s <command>\n", basename(cmd));
+       fprintf(stderr, "\t -n <name>   : name of the container\n");
+       _exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+       char opt;
+       char *name = NULL;
+       int nbargs = 0;
+
+       while ((opt = getopt(argc, argv, "n:")) != -1) {
+               switch (opt) {
+               case 'n':
+                       name = optarg;
+                       break;
+               }
+
+               nbargs++;
+       }
+
+       if (!name)
+               usage(argv[0]);
+
+       if (lxc_restart(name, STDIN_FILENO, 0)) {
+               fprintf(stderr, "failed to checkpoint %s\n", name);
+               return 1;
+       }
+
+       return 0;
+}
diff --git a/src/lxc/restart.c b/src/lxc/restart.c
new file mode 100644 (file)
index 0000000..b4ebb68
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <dlezcano at fr.ibm.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+
+#include <lxc/lxc.h>
+
+LXC_TTY_HANDLER(SIGINT);
+LXC_TTY_HANDLER(SIGQUIT);
+
+
+#if __i386__
+#    define __NR_restart 335
+#else
+#    error "Architecture not supported"
+#endif
+static inline long sys_restart(pid_t pid, int fd, unsigned long flags)
+{
+       return syscall(__NR_restart, pid, fd, flags);
+}
+
+int lxc_restart(const char *name, int cfd, unsigned long flags)
+{
+       char *init = NULL, *val = NULL;
+       int fd, lock, sv[2], sync = 0, err = -1;
+       pid_t pid;
+       int clone_flags;
+       
+       lock = lxc_get_lock(name);
+       if (!lock) {
+               lxc_log_error("'%s' is busy", name);
+               return -1;
+       }
+
+       if (lock < 0) {
+               lxc_log_error("failed to acquire lock on '%s':%s",
+                             name, strerror(-lock));
+               return -1;
+       }
+
+       fcntl(lock, F_SETFD, FD_CLOEXEC);
+
+       /* Begin the set the state to STARTING*/
+       if (lxc_setstate(name, STARTING)) {
+               lxc_log_error("failed to set state %s", lxc_state2str(STARTING));
+               goto out;
+       }
+
+       /* Synchro socketpair */
+       if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv)) {
+               lxc_log_syserror("failed to create communication socketpair");
+               goto err;
+       }
+
+       /* Avoid signals from terminal */
+       LXC_TTY_ADD_HANDLER(SIGINT);
+       LXC_TTY_ADD_HANDLER(SIGQUIT);
+
+       clone_flags = CLONE_NEWPID|CLONE_NEWIPC;
+       if (conf_has_fstab(name))
+               clone_flags |= CLONE_NEWNS;
+       if (conf_has_utsname(name))
+               clone_flags |= CLONE_NEWUTS;
+       if (conf_has_network(name))
+               clone_flags |= CLONE_NEWNET;
+
+       /* Create a process in a new set of namespaces */
+       pid = fork_ns(clone_flags);
+       if (pid < 0) {
+               lxc_log_syserror("failed to fork into a new namespace");
+               goto err_fork_ns;
+       }
+
+       if (!pid) {
+
+               close(sv[1]);
+
+               /* Be sure we don't inherit this after the exec */
+               fcntl(sv[0], F_SETFD, FD_CLOEXEC);
+               
+               /* Tell our father he can begin to configure the container */
+               if (write(sv[0], &sync, sizeof(sync)) < 0) {
+                       lxc_log_syserror("failed to write socket");
+                       return 1;
+               }
+
+               /* Wait for the father to finish the configuration */
+               if (read(sv[0], &sync, sizeof(sync)) < 0) {
+                       lxc_log_syserror("failed to read socket");
+                       return 1;
+               }
+
+               /* Setup the container, ip, names, utsname, ... */
+               if (lxc_setup(name)) {
+                       lxc_log_error("failed to setup the container");
+                       if (write(sv[0], &sync, sizeof(sync)) < 0)
+                               lxc_log_syserror("failed to write the socket");
+                       return -1;
+               }
+
+               sys_restart(pid, cfd, flags);
+               lxc_log_syserror("failed to restart");
+
+               /* If the exec fails, tell that to our father */
+               if (write(sv[0], &sync, sizeof(sync)) < 0)
+                       lxc_log_syserror("failed to write the socket");
+               
+               exit(1);
+       }
+
+       close(sv[0]);
+       
+       /* Wait for the child to be ready */
+       if (read(sv[1], &sync, sizeof(sync)) < 0) {
+               lxc_log_syserror("failed to read the socket");
+               goto err_pipe_read;
+       }
+
+       /* Create the network configuration */
+       if (clone_flags & CLONE_NEWNET && conf_create_network(name, pid)) {
+               lxc_log_error("failed to create the configured network");
+               goto err_create_network;
+       }
+
+       /* Tell the child to continue its initialization */
+       if (write(sv[1], &sync, sizeof(sync)) < 0) {
+               lxc_log_syserror("failed to write the socket");
+               goto err_pipe_write;
+       }
+
+       /* Wait for the child to exec or returning an error */
+       err = read(sv[1], &sync, sizeof(sync));
+       if (err < 0) {
+               lxc_log_error("failed to read the socket");
+               goto err_pipe_read2;
+       }
+
+       if (err > 0) {
+               lxc_log_error("something went wrong with %d", pid);
+               /* TODO : check status etc ... */
+               waitpid(pid, NULL, 0);
+               goto err_child_failed;
+       }
+
+       asprintf(&val, "%d\n", pid);
+       asprintf(&init, LXCPATH "/%s/init", name);
+       fd = open(init, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+       if (fd < 0) {
+               lxc_log_syserror("failed to open '%s'", init);
+               goto err_write;
+       }
+       
+       if (write(fd, val, strlen(val)) < 0) {
+               lxc_log_syserror("failed to write the init pid");
+               goto err_write;
+       }
+
+       close(fd);
+
+       if (lxc_link_nsgroup(name, pid))
+               lxc_log_warning("cgroupfs not found: cgroup disabled");
+
+       if (lxc_setstate(name, RUNNING)) {
+               lxc_log_error("failed to set state to %s", 
+                             lxc_state2str(RUNNING));
+               goto err_state_failed;
+       }
+
+wait_again:
+       if (waitpid(pid, NULL, 0) < 0) {
+               if (errno == EINTR) 
+                       goto wait_again;
+               lxc_log_syserror("failed to wait the pid %d", pid);
+               goto err_waitpid_failed;
+       }
+
+       if (lxc_setstate(name, STOPPING))
+               lxc_log_error("failed to set state %s", lxc_state2str(STOPPING));
+
+       if (clone_flags & CLONE_NEWNET && conf_destroy_network(name))
+               lxc_log_error("failed to destroy the network");
+
+       err = 0;
+out:
+       if (lxc_setstate(name, STOPPED))
+               lxc_log_error("failed to set state %s", lxc_state2str(STOPPED));
+
+       lxc_unlink_nsgroup(name);
+       unlink(init);
+       free(init);
+       free(val);
+       lxc_put_lock(lock);
+
+       return err;
+
+err_write:
+       close(fd);
+
+err_state_failed:
+err_child_failed:
+err_pipe_read2:
+err_pipe_write:
+       if (clone_flags & CLONE_NEWNET)
+               conf_destroy_network(name);
+err_create_network:
+err_pipe_read:
+err_waitpid_failed:
+       if (lxc_setstate(name, ABORTING))
+               lxc_log_error("failed to set state %s", lxc_state2str(STOPPED));
+
+       kill(pid, SIGKILL);
+err_fork_ns:
+       LXC_TTY_DEL_HANDLER(SIGQUIT);
+       LXC_TTY_DEL_HANDLER(SIGINT);
+       close(sv[0]);
+       close(sv[1]);
+err:
+       goto out;
+}