diff options
author | legoater <legoater> | 2008-09-19 10:20:04 +0000 |
---|---|---|
committer | legoater <legoater> | 2008-09-19 10:20:04 +0000 |
commit | 925aaa312480da5584b2e5e8f963ce1d85b97232 (patch) | |
tree | 4f8b9bc9239247afda2af00a4b5b1adef3f6cf26 | |
parent | If no configuration file is specified or the container was not created before. (diff) | |
download | lxc-925aaa312480da5584b2e5e8f963ce1d85b97232.tar.gz lxc-925aaa312480da5584b2e5e8f963ce1d85b97232.tar.bz2 lxc-925aaa312480da5584b2e5e8f963ce1d85b97232.zip |
add experimental checkpoint and restart commands
-rw-r--r-- | src/lxc/Makefile.am | 10 | ||||
-rw-r--r-- | src/lxc/checkpoint.c | 98 | ||||
-rw-r--r-- | src/lxc/lxc.h | 18 | ||||
-rw-r--r-- | src/lxc/lxc_checkpoint.c | 62 | ||||
-rw-r--r-- | src/lxc/lxc_restart.c | 62 | ||||
-rw-r--r-- | src/lxc/restart.c | 252 |
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; +} |