Re: [RFC 00/10] container-based checkpoint/restart prototype

From: Nathan Lynch
Date: Mon Feb 28 2011 - 20:09:20 EST


On Mon, 2011-02-28 at 17:40 -0600, ntl@xxxxxxxxx wrote:
> This is the tradeoff we ask users
> to make - the ability to C/R and migrate is provided in exchange for
> accepting some isolation and slightly reduced ease of use. A tool
> such as lxc (http://lxc.sourceforge.net) can be used to isolate jobs.
> A patch against lxc is available which adds C/R capability.

Below is that patch (against the lxc-0.7.3 tag) and a usage example.

# export LXC_CMD_SOCK_ABSTRACT=test
# lxc-execute -n foo -- /bin/cat </dev/zero &>/dev/null &
# ps
PID TTY TIME CMD
8736 pts/1 00:00:00 bash
8842 pts/1 00:00:00 lxc-execute
8843 pts/1 00:00:00 lxc-init
8844 pts/1 00:00:01 cat
8845 pts/1 00:00:00 ps
# lxc-checkpoint -S /tmp/ckpt.img -n foo -k
[1]+ Exit 137 lxc-execute -n foo -- /bin/cat < /dev/zero &>/dev/null
# ps
PID TTY TIME CMD
8736 pts/1 00:00:00 bash
8849 pts/1 00:00:00 ps
# lxc-restart -n foo -S /tmp/ckpt.img

[whee, watch resurrected /bin/cat eat cpu]

doc/rootfs/Makefile.am | 2 +-
lxc.spec.in | 2 +-
src/lxc/Makefile.am | 3 +-
src/lxc/checkpoint.c | 59 ++++++-
src/lxc/cr.h | 71 ++++++++
src/lxc/lxc_init.c | 459 ++++++++++++++++++++++++++++++++++++++----------
src/lxc/lxc_restart.c | 25 ++-
src/lxc/restart.c | 77 --------
src/lxc/start.c | 3 +-
templates/Makefile.am | 2 +-
10 files changed, 515 insertions(+), 188 deletions(-)

diff --git a/doc/rootfs/Makefile.am b/doc/rootfs/Makefile.am
index 98fb0e0..832bb4a 100644
--- a/doc/rootfs/Makefile.am
+++ b/doc/rootfs/Makefile.am
@@ -1,3 +1,3 @@
-READMEdir=@LXCROOTFSMOUNT@
+READMEdir=$(pkglibdir)/rootfs

README_DATA=README
\ No newline at end of file
diff --git a/lxc.spec.in b/lxc.spec.in
index 379b53d..1ca6326 100644
--- a/lxc.spec.in
+++ b/lxc.spec.in
@@ -57,7 +57,7 @@ development of the linux containers.
%setup
%build
PATH=$PATH:/usr/sbin:/sbin %configure
-make %{?_smp_mflags}
+make %{?_smp_mflags} CFLAGS='-Wall -Werror -g'

%install
%makeinstall
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index d2ee4d9..9e4d4c9 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -25,8 +25,7 @@ liblxc_so_SOURCES = \
monitor.c monitor.h \
console.c \
freezer.c \
- checkpoint.c \
- restart.c \
+ checkpoint.c cr.h\
error.h error.c \
parse.c parse.h \
cgroup.c cgroup.h \
diff --git a/src/lxc/checkpoint.c b/src/lxc/checkpoint.c
index a2d0d8a..b0c62a8 100644
--- a/src/lxc/checkpoint.c
+++ b/src/lxc/checkpoint.c
@@ -22,11 +22,64 @@
*/
#include <lxc/lxc.h>
#include <lxc/log.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "af_unix.h"
+#include "cr.h"

lxc_log_define(lxc_checkpoint, lxc);

-int lxc_checkpoint(const char *name, int sfd, int flags)
+int lxc_checkpoint(const char *name, int statefd, int flags)
{
- ERROR("'checkpoint' function not implemented");
- return -1;
+ struct lxc_cr_cmd cmd = { .code = LXC_COMMAND_CHECKPOINT, };
+ struct lxc_cr_response response;
+ const char *cmd_sock_path;
+ char sun_path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
+ ssize_t ret;
+ int sockfd;
+
+ cmd_sock_path = getenv("LXC_CMD_SOCK_ABSTRACT");
+ if (!cmd_sock_path) {
+ ERROR("LXC_CMD_SOCK_ABSTRACT not set");
+ return -1;
+ }
+
+ strncpy(&sun_path[1], cmd_sock_path, sizeof(sun_path) - 2);
+
+ sockfd = lxc_af_unix_connect(sun_path);
+ if (sockfd == -1) {
+ ERROR("sock connect");
+ return -1;
+ }
+
+ ret = lxc_af_unix_send_fd(sockfd, statefd, &cmd, sizeof(cmd));
+ if (ret != sizeof(cmd)) {
+ ERROR("send fd");
+ return -1;
+ }
+
+ ret = recv(sockfd, &response, sizeof(response), 0);
+ if (ret != sizeof(response)) {
+ ERROR("recv");
+ return -1;
+ }
+
+ close(sockfd);
+
+ if (response.code != LXC_RESPONSE_SUCCESS) {
+ ERROR("checkpoint command failed (%u)", response.code);
+ return -1;
+ }
+
+ /* This is racy - we'd rather the container have no chance to
+ * run between checkpoint and the stop request - but hopefully
+ * it will do for now.
+ */
+ if (flags & LXC_FLAG_HALT)
+ return lxc_stop(name);
+
+ return 0;
}
diff --git a/src/lxc/cr.h b/src/lxc/cr.h
new file mode 100644
index 0000000..244c8f9
--- /dev/null
+++ b/src/lxc/cr.h
@@ -0,0 +1,71 @@
+/*
+ * lxc: Linux Container library
+ *
+ * Copyright IBM Corp. 2011
+ * 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
+ */
+
+#ifndef _LXC_CR_H
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+enum {
+ LXC_COMMAND_CHECKPOINT = 1,
+};
+
+enum {
+ LXC_RESPONSE_SUCCESS,
+ LXC_RESPONSE_FAILURE,
+};
+
+struct lxc_cr_cmd { unsigned int code; };
+struct lxc_cr_response { unsigned int code; };
+
+#ifndef SYS_checkpoint
+#if defined(__i386__)
+#define SYS_checkpoint 341
+#elif defined(__x86_64__)
+#define SYS_checkpoint 303
+#else
+#warning SYS_checkpoint not defined for this architecture
+#define SYS_checkpoint -1
+#endif
+#endif
+
+static inline int checkpoint(int fd, unsigned int flags)
+{
+ return syscall(SYS_checkpoint, fd, flags);
+}
+
+#ifndef SYS_restart
+#if defined(__i386__)
+#define SYS_restart 342
+#elif defined(__x86_64__)
+#define SYS_restart 304
+#else
+#warning SYS_restart not defined for this architecture
+#define SYS_restart -1
+#endif
+#endif
+
+static inline int restart(int fd, unsigned int flags)
+{
+ return syscall(SYS_restart, fd, flags);
+}
+
+#endif /* _LXC_CR_H */
diff --git a/src/lxc/lxc_init.c b/src/lxc/lxc_init.c
index a534b51..2e8f08a 100644
--- a/src/lxc/lxc_init.c
+++ b/src/lxc/lxc_init.c
@@ -1,10 +1,11 @@
/*
* lxc: linux Container library
*
- * (C) Copyright IBM Corp. 2007, 2008
+ * (C) Copyright IBM Corp. 2007, 2008, 2011
*
* Authors:
* Daniel Lezcano <dlezcano at fr.ibm.com>
+ * Nathan Lynch
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,21 +22,29 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
+#define _GNU_SOURCE
+#include <assert.h>
#include <errno.h>
-#include <signal.h>
+#include <getopt.h>
#include <libgen.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/signalfd.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/un.h>
#include <sys/wait.h>
-#define _GNU_SOURCE
-#include <getopt.h>

-#include "log.h"
+#include "af_unix.h"
#include "caps.h"
+#include "cr.h"
#include "error.h"
+#include "log.h"
#include "utils.h"

lxc_log_define(lxc_init, lxc);
@@ -47,23 +56,305 @@ static struct option options[] = {
{ 0, 0, 0, 0 },
};

-static int was_interrupted = 0;
+static bool pidns_is_empty(void)
+{
+ assert(getpid() == (pid_t)1);
+
+ if (kill(-1, 0) == 0)
+ return false;
+ assert(errno == ESRCH);
+ return true;
+}

-int main(int argc, char *argv[])
+static struct lxc_init_state {
+ pid_t child_pid; /* the child we initially created */
+ bool shutting_down; /* we've received a request to exit */
+ bool child_status_collected; /* we've retrieved child_pid's status */
+ int exit_code; /* status code to return from main() */
+ size_t nr_waited; /* # children waited post-restart */
+} state;
+
+static void handle_sigterm(struct lxc_init_state *state)
{
+ if (state->shutting_down)
+ return;
+
+ state->shutting_down = true;
+ kill(-1, SIGTERM);
+ alarm(1);
+}
+
+static void handle_sigalrm(struct lxc_init_state *state)
+{
+ kill(-1, SIGKILL);
+}
+
+static void handle_sigchld(struct lxc_init_state *state)
+{
+ pid_t pid;
+ int status;
+
+ while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
+
+ if (pid == (pid_t)-1)
+ return;
+
+ /* reset timer each time a process exits */
+ if (state->shutting_down)
+ alarm(1);
+
+ ERROR("collected pid %lu\n", (unsigned long)pid);
+
+ state->nr_waited++; /* for restart */
+
+ if (state->child_status_collected)
+ continue; /* don't care */
+
+ if (pid != state->child_pid)
+ continue; /* don't care */
+
+ state->child_status_collected = true;
+ state->exit_code = lxc_error_set_and_log(pid, status);
+ }
+}
+
+typedef void (*sigfd_handler_t)(struct lxc_init_state *);
+
+static const sigfd_handler_t sig_dispatch_table[NSIG] =
+{
+ [SIGTERM] = handle_sigterm,
+ [SIGALRM] = handle_sigalrm,
+ [SIGCHLD] = handle_sigchld,
+};
+
+static int epoll_sigfd_handler(struct lxc_init_state *state, int fd, uint32_t events)
+{
+ struct signalfd_siginfo siginfo;
+ int ret;
+
+ ret = read(fd, &siginfo, sizeof(struct signalfd_siginfo));
+ if (ret != sizeof(struct signalfd_siginfo)) {
+ ERROR("read signalfd");
+ return -1;
+ }
+
+ if (sig_dispatch_table[siginfo.ssi_signo] != NULL)
+ sig_dispatch_table[siginfo.ssi_signo](state);
+ else
+ kill(state->child_pid, siginfo.ssi_signo);
+
+ return 0;
+}
+
+static int epoll_cmd_handler(struct lxc_init_state *state, int listenfd, uint32_t events)
+{
+ struct lxc_cr_response response = { .code = LXC_RESPONSE_FAILURE, };
+ struct lxc_cr_cmd cmd;
+ int saved_errno;
+ ssize_t bytes;
+ int acceptfd;
+ int statefd;
+ int flags;
+ int rc;
+
+ acceptfd = accept(listenfd, NULL, NULL);
+ if (acceptfd == -1) {
+ ERROR("accept");
+ goto out;
+ }
+
+ statefd = -1;
+ bytes = lxc_af_unix_recv_fd(acceptfd, &statefd, &cmd, sizeof(cmd));
+
+ if (bytes == -1) {
+ ERROR("recv fd");
+ goto out;
+ }
+
+ if (cmd.code != LXC_COMMAND_CHECKPOINT) {
+ ERROR("unknown command %i", cmd.code);
+ goto out;
+ }
+
+ flags = 0;
+ rc = checkpoint(statefd, flags);
+ saved_errno = errno;
+ close(statefd);
+
+ if (rc == 0)
+ response.code = LXC_RESPONSE_SUCCESS;
+ else
+ ERROR("checkpoint error: %s", strerror(saved_errno));
+
+ bytes = send(acceptfd, &response, sizeof(response), 0);
+ if (bytes != sizeof(response))
+ ERROR("send (bytes = %zd)", bytes);
+out:
+ close(acceptfd);
+ return 0;
+}
+
+typedef int (*epoll_handler_t)(struct lxc_init_state *, int fd, uint32_t events);
+
+struct epoll_info;
+typedef int (*epoll_info_ctor_t)(struct epoll_info *);
+
+struct epoll_info {
+ const char *desc; /* human-friendly string for debug/logging */
+ epoll_info_ctor_t ctor; /* initializes fd */
+ epoll_handler_t handler; /* handles events from epoll_wait */
+ int fd; /* fd passed to epoll_ctl */
+ uint32_t events; /* events relevant for this resource */
+};
+
+static int sigfd_ctor(struct epoll_info *info)
+{
+ sigset_t mask;
+
+ sigfillset(&mask);
+
+ return signalfd(-1, &mask, SFD_CLOEXEC);
+}
+
+static int cmd_sock_ctor(struct epoll_info *info)
+{
+ char sun_path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
+ const char *cmd_sock_path;
+ int fd;
+
+ cmd_sock_path = getenv("LXC_CMD_SOCK_ABSTRACT");
+ if (!cmd_sock_path) {
+ ERROR("LXC_CMD_SOCK_ABSTRACT not set");
+ return -1;
+ }
+
+ strncpy(&sun_path[1], cmd_sock_path, sizeof(sun_path) - 2);
+
+ fd = lxc_af_unix_open(sun_path, SOCK_STREAM, 0);
+ if (fd == -1)
+ return -1;

- void interrupt_handler(int sig)
+ return fd;
+}
+
+static struct epoll_info epoll_info_table[] = {
+ {
+ .desc = "signalfd",
+ .ctor = sigfd_ctor,
+ .handler = epoll_sigfd_handler,
+ .events = EPOLLIN,
+ },
{
- if (!was_interrupted)
- was_interrupted = sig;
+ .desc = "command socket",
+ .ctor = cmd_sock_ctor,
+ .handler = epoll_cmd_handler,
+ .events = EPOLLIN | EPOLLPRI,
+ },
+};
+
+static const size_t epoll_info_table_size =
+ sizeof(epoll_info_table) / sizeof(epoll_info_table[0]);
+
+static int epoll_info_init_one(struct epoll_info *info, int epollfd)
+{
+ struct epoll_event event;
+
+ info->fd = info->ctor(info);
+ if (info->fd == -1)
+ return -1;
+
+ event.events = info->events;
+ event.data.ptr = info;
+
+ if (epoll_ctl(epollfd, EPOLL_CTL_ADD, info->fd, &event) == -1) {
+ ERROR("epoll_ctl");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int epoll_setup(void)
+{
+ int epollfd;
+ int i;
+
+ epollfd = epoll_create1(O_CLOEXEC);
+ if (epollfd == -1) {
+ ERROR("epoll_create1");
+ return epollfd;
+ }
+
+ for (i = 0; i < epoll_info_table_size; i++) {
+ struct epoll_info *info = &epoll_info_table[i];
+
+ if (epoll_info_init_one(info, epollfd) == -1) {
+ ERROR("%s failed", info->desc);
+ return -EINVAL;
+ }
}

+ return epollfd;
+}
+
+static int epoll_loop(int epollfd)
+{
+ do {
+ struct epoll_info *info;
+ struct epoll_event event;
+ int epollrc;
+
+ epollrc = epoll_wait(epollfd, &event, 1, -1);
+ if (epollrc == -1) {
+ /* e.g. SIGCONT from ptrace attach */
+ assert(errno == EINTR);
+ continue;
+ }
+
+ assert(event.data.ptr != NULL);
+
+ info = event.data.ptr;
+
+ assert(event.events & info->events);
+
+ if (info->handler(&state, info->fd, event.events) == -1)
+ return -1;
+ } while (!pidns_is_empty());
+
+ return 0;
+}
+
+static int get_restart_fd(void)
+{
+ const char *str;
+ int fd = -1;
+
+ str = getenv("LXC_RESTART_FD");
+ if (str) {
+ errno = 0;
+ fd = strtol(str, NULL, 0);
+ if (errno) {
+ ERROR("LXC_RESTART_FD has bad value '%s'", str);
+ fd = -1;
+ }
+ }
+
+ return fd;
+}
+
+int main(int argc, char *argv[])
+{
+ int restartfd;
+ int epollfd;
pid_t pid;
int nbargs = 0;
int err = -1;
char **aargv;
sigset_t mask, omask;
- int i, shutdown = 0;
+ int i;
+
+ state.exit_code = EXIT_FAILURE;
+ state.nr_waited = 0;

while (1) {
int ret = getopt_long_only(argc, argv, "", options, NULL);
@@ -82,7 +373,9 @@ int main(int argc, char *argv[])
if (lxc_log_init(NULL, 0, basename(argv[0]), quiet))
exit(err);

- if (!argv[optind]) {
+ restartfd = get_restart_fd();
+
+ if (!argv[optind] && restartfd == -1) {
ERROR("missing command to launch");
exit(err);
}
@@ -91,113 +384,89 @@ int main(int argc, char *argv[])
argc -= nbargs;

/*
- * mask all the signals so we are safe to install a
+ * mask most signals so we are safe to install a
* signal handler and to fork
*/
sigfillset(&mask);
+ sigdelset(&mask, SIGILL);
+ sigdelset(&mask, SIGSEGV);
+ sigdelset(&mask, SIGBUS);
+ sigdelset(&mask, SIGFPE);
sigprocmask(SIG_SETMASK, &mask, &omask);

- for (i = 1; i < NSIG; i++) {
- struct sigaction act;
-
- sigfillset(&act.sa_mask);
- sigdelset(&mask, SIGILL);
- sigdelset(&mask, SIGSEGV);
- sigdelset(&mask, SIGBUS);
- act.sa_flags = 0;
- act.sa_handler = interrupt_handler;
- sigaction(i, &act, NULL);
- }
-
if (lxc_setup_fs())
exit(err);

if (lxc_caps_reset())
exit(err);

- pid = fork();
-
- if (pid < 0)
- exit(err);
-
- if (!pid) {
+ assert(pidns_is_empty());

- /* restore default signal handlers */
- for (i = 1; i < NSIG; i++)
- signal(i, SIG_DFL);
+ /* restart */
+ if (restartfd != -1) {
+ unsigned int flags;
+ int ret;

- sigprocmask(SIG_SETMASK, &omask, NULL);
+ epollfd = epoll_setup();
+ if (epollfd < 0)
+ exit(err);

- NOTICE("about to exec '%s'", aargv[0]);
+ flags = 0;
+ ret = restart(restartfd, flags);
+ if (ret != 0) {
+ ERROR("restart: %s", strerror(errno));
+ goto out;
+ }

- execvp(aargv[0], aargv);
- ERROR("failed to exec: '%s' : %m", aargv[0]);
- exit(err);
- }
+ state.exit_code = epoll_loop(epollfd);

- /* let's process the signals now */
- sigdelset(&omask, SIGALRM);
- sigprocmask(SIG_SETMASK, &omask, NULL);
+ /* FIXME: we don't know which pid's status should be
+ * lxc-init's exit code
+ */

- /* no need of other inherited fds but stderr */
- close(fileno(stdin));
- close(fileno(stdout));
+ if (state.nr_waited > 1) {
+ ERROR("multiple task restart not supported yet");
+ state.exit_code = EXIT_FAILURE;
+ } else if (state.nr_waited == 0) {
+ ERROR("no tasks restarted?");
+ state.exit_code = EXIT_FAILURE;
+ }

- err = 0;
- for (;;) {
- int status;
- int orphan = 0;
- pid_t waited_pid;
+ goto out;
+ } else { /* initial startup e.g. lxc-execute */
+ pid = fork();

- switch (was_interrupted) {
+ if (pid < 0)
+ exit(err);

- case 0:
- break;
+ if (!pid) {
+ /* restore default signal handlers */
+ for (i = 1; i < NSIG; i++)
+ signal(i, SIG_DFL);

- case SIGTERM:
- if (!shutdown) {
- shutdown = 1;
- kill(-1, SIGTERM);
- alarm(1);
- }
- break;
+ sigprocmask(SIG_SETMASK, &omask, NULL);

- case SIGALRM:
- kill(-1, SIGKILL);
- break;
+ NOTICE("about to exec '%s'", aargv[0]);

- default:
- kill(pid, was_interrupted);
- break;
+ execvp(aargv[0], aargv);
+ ERROR("failed to exec: '%s' : %m", aargv[0]);
+ exit(err);
}

- was_interrupted = 0;
- waited_pid = wait(&status);
- if (waited_pid < 0) {
- if (errno == ECHILD)
- goto out;
- if (errno == EINTR)
- continue;
+ epollfd = epoll_setup();
+ if (epollfd < 0)
+ exit(err);

- ERROR("failed to wait child : %s",
- strerror(errno));
- goto out;
- }
+ state.child_pid = pid;
+ }

- /* reset timer each time a process exited */
- if (shutdown)
- alarm(1);
+/* wait: */
+ /* no need of other inherited fds but stderr */
+ close(fileno(stdin));
+ close(fileno(stdout));
+
+ epoll_loop(epollfd);

- /*
- * keep the exit code of started application
- * (not wrapped pid) and continue to wait for
- * the end of the orphan group.
- */
- if ((waited_pid != pid) || (orphan ==1))
- continue;
- orphan = 1;
- err = lxc_error_set_and_log(waited_pid, status);
- }
out:
- return err;
+ return state.exit_code;
}
diff --git a/src/lxc/lxc_restart.c b/src/lxc/lxc_restart.c
index 7548682..3687429 100644
--- a/src/lxc/lxc_restart.c
+++ b/src/lxc/lxc_restart.c
@@ -37,7 +37,7 @@
#include "confile.h"
#include "arguments.h"

-lxc_log_define(lxc_restart_ui, lxc_restart);
+lxc_log_define(lxc_restart, lxc);

static struct lxc_list defines;

@@ -109,8 +109,9 @@ Options :\n\

int main(int argc, char *argv[])
{
+ char *envstr;
+ static char **args;
int sfd = -1;
- int ret;
char *rcfile = NULL;
struct lxc_conf *conf;

@@ -126,6 +127,10 @@ int main(int argc, char *argv[])
my_args.progname, my_args.quiet))
return -1;

+ args = lxc_arguments_dup(LXCINITDIR "/lxc-init", &my_args);
+ if (!args)
+ return -1;
+
/* rcfile is specified in the cli option */
if (my_args.rcfile)
rcfile = (char *)my_args.rcfile;
@@ -162,7 +167,7 @@ int main(int argc, char *argv[])
if (my_args.statefd != -1)
sfd = my_args.statefd;

-#define OPEN_READ_MODE O_RDONLY | O_CLOEXEC | O_LARGEFILE
+#define OPEN_READ_MODE (O_RDONLY | O_LARGEFILE)
if (my_args.statefile) {
sfd = open(my_args.statefile, OPEN_READ_MODE, 0);
if (sfd < 0) {
@@ -171,9 +176,15 @@ int main(int argc, char *argv[])
}
}

- ret = lxc_restart(my_args.name, sfd, conf, my_args.flags);
+ if (asprintf(&envstr, "LXC_RESTART_FD=%i", sfd) == -1) {
+ SYSERROR("asprintf: %s", strerror(errno));
+ return -1;
+ }
+
+ if (putenv(envstr) != 0) {
+ SYSERROR("putenv: %s", strerror(errno));
+ return -1;
+ }

- if (my_args.statefile)
- close(sfd);
- return ret;
+ return lxc_start(my_args.name, args, conf);
}
diff --git a/src/lxc/restart.c b/src/lxc/restart.c
deleted file mode 100644
index c947b81..0000000
--- a/src/lxc/restart.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2010
- *
- * 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 "../config.h"
-#include <stdio.h>
-#undef _GNU_SOURCE
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include <lxc/log.h>
-#include <lxc/start.h> /* for struct lxc_handler */
-#include <lxc/utils.h>
-#include <lxc/error.h>
-
-lxc_log_define(lxc_restart, lxc);
-
-struct restart_args {
- int sfd;
- int flags;
-};
-
-static int restart(struct lxc_handler *handler, void* data)
-{
- struct restart_args *arg __attribute__ ((unused)) = data;
-
- ERROR("'restart' function not implemented");
- return -1;
-}
-
-static int post_restart(struct lxc_handler *handler, void* data)
-{
- struct restart_args *arg __attribute__ ((unused)) = data;
-
- NOTICE("'%s' container restarting with pid '%d'", handler->name,
- handler->pid);
- return 0;
-}
-
-static struct lxc_operations restart_ops = {
- .start = restart,
- .post_start = post_restart
-};
-
-int lxc_restart(const char *name, int sfd, struct lxc_conf *conf, int flags)
-{
- struct restart_args restart_arg = {
- .sfd = sfd,
- .flags = flags
- };
-
- if (lxc_check_inherited(sfd))
- return -1;
-
- return __lxc_start(name, conf, &restart_ops, &restart_arg);
-}
diff --git a/src/lxc/start.c b/src/lxc/start.c
index b963b85..8ff738f 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -629,8 +629,9 @@ int lxc_start(const char *name, char *const argv[], struct lxc_conf *conf)
.argv = argv,
};

+ /* At restart we allow lxc-init to inherit the fd for the image */
if (lxc_check_inherited(-1))
- return -1;
+ ERROR("lxc_check_inherited failed; proceeding anyway");

return __lxc_start(name, conf, &start_ops, &start_arg);
}
diff --git a/templates/Makefile.am b/templates/Makefile.am
index d55f53a..31de984 100644
--- a/templates/Makefile.am
+++ b/templates/Makefile.am
@@ -1,4 +1,4 @@
-templatesdir=@LXCTEMPLATEDIR@
+templatesdir=$(pkglibdir)

templates_SCRIPTS = \
lxc-debian \


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/