aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlegoater <legoater>2008-09-19 10:20:04 +0000
committerlegoater <legoater>2008-09-19 10:20:04 +0000
commit925aaa312480da5584b2e5e8f963ce1d85b97232 (patch)
tree4f8b9bc9239247afda2af00a4b5b1adef3f6cf26
parentIf no configuration file is specified or the container was not created before. (diff)
downloadlxc-925aaa312480da5584b2e5e8f963ce1d85b97232.tar.gz
lxc-925aaa312480da5584b2e5e8f963ce1d85b97232.tar.bz2
lxc-925aaa312480da5584b2e5e8f963ce1d85b97232.zip
add experimental checkpoint and restart commands
-rw-r--r--src/lxc/Makefile.am10
-rw-r--r--src/lxc/checkpoint.c98
-rw-r--r--src/lxc/lxc.h18
-rw-r--r--src/lxc/lxc_checkpoint.c62
-rw-r--r--src/lxc/lxc_restart.c62
-rw-r--r--src/lxc/restart.c252
6 files changed, 502 insertions, 0 deletions
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index e659b4b..ea85fb2 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -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
index 0000000..954ee33
--- /dev/null
+++ b/src/lxc/checkpoint.c
@@ -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;
+}
diff --git a/src/lxc/lxc.h b/src/lxc/lxc.h
index 166ab52..722d8af 100644
--- a/src/lxc/lxc.h
+++ b/src/lxc/lxc.h
@@ -251,6 +251,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
*/
extern const char const *lxc_version(void);
diff --git a/src/lxc/lxc_checkpoint.c b/src/lxc/lxc_checkpoint.c
new file mode 100644
index 0000000..f18864c
--- /dev/null
+++ b/src/lxc/lxc_checkpoint.c
@@ -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
index 0000000..43c94f1
--- /dev/null
+++ b/src/lxc/lxc_restart.c
@@ -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
index 0000000..b4ebb68
--- /dev/null
+++ b/src/lxc/restart.c
@@ -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;
+}