2
0
mirror of git://github.com/lxc/lxc synced 2025-08-31 23:15:03 +00:00

Merge pull request #1270 from tych0/save-dump-state-too

c/r: save dump stdout too
This commit is contained in:
Christian Brauner
2016-11-02 12:05:15 -06:00
committed by GitHub

View File

@@ -62,6 +62,9 @@
lxc_log_define(lxc_criu, lxc); lxc_log_define(lxc_criu, lxc);
struct criu_opts { struct criu_opts {
/* the thing to hook to stdout and stderr for logging */
int pipefd;
/* The type of criu invocation, one of "dump" or "restore" */ /* The type of criu invocation, one of "dump" or "restore" */
char *action; char *action;
@@ -134,6 +137,7 @@ static void exec_criu(struct criu_opts *opts)
char buf[4096], tty_info[32]; char buf[4096], tty_info[32];
size_t pos; size_t pos;
/* If we are currently in a cgroup /foo/bar, and the container is in a /* If we are currently in a cgroup /foo/bar, and the container is in a
* cgroup /lxc/foo, lxcfs will give us an ENOENT if some task in the * cgroup /lxc/foo, lxcfs will give us an ENOENT if some task in the
* container has an open fd that points to one of the cgroup files * container has an open fd that points to one of the cgroup files
@@ -212,7 +216,7 @@ static void exec_criu(struct criu_opts *opts)
ret = snprintf(log, PATH_MAX, "%s/%s.log", opts->user->directory, opts->action); ret = snprintf(log, PATH_MAX, "%s/%s.log", opts->user->directory, opts->action);
if (ret < 0 || ret >= PATH_MAX) { if (ret < 0 || ret >= PATH_MAX) {
ERROR("logfile name too long\n"); ERROR("logfile name too long");
return; return;
} }
@@ -235,7 +239,7 @@ static void exec_criu(struct criu_opts *opts)
argv[argc++] = on_path("criu", NULL); argv[argc++] = on_path("criu", NULL);
if (!argv[argc-1]) { if (!argv[argc-1]) {
ERROR("Couldn't find criu binary\n"); ERROR("Couldn't find criu binary");
goto err; goto err;
} }
@@ -502,7 +506,7 @@ static void exec_criu(struct criu_opts *opts)
break; break;
case LXC_NET_MACVLAN: case LXC_NET_MACVLAN:
if (!n->link) { if (!n->link) {
ERROR("no host interface for macvlan %s\n", n->name); ERROR("no host interface for macvlan %s", n->name);
goto err; goto err;
} }
@@ -515,7 +519,7 @@ static void exec_criu(struct criu_opts *opts)
break; break;
default: default:
/* we have screened for this earlier... */ /* we have screened for this earlier... */
ERROR("unexpected network type %d\n", n->type); ERROR("unexpected network type %d", n->type);
goto err; goto err;
} }
@@ -541,6 +545,21 @@ static void exec_criu(struct criu_opts *opts)
INFO("execing: %s", buf); INFO("execing: %s", buf);
/* before criu inits its log, it sometimes prints things to stdout/err;
* let's be sure we capture that.
*/
if (dup2(opts->pipefd, STDOUT_FILENO) < 0) {
SYSERROR("dup2 stdout failed");
goto err;
}
if (dup2(opts->pipefd, STDERR_FILENO) < 0) {
SYSERROR("dup2 stderr failed");
goto err;
}
close(opts->pipefd);
#undef DECLARE_ARG #undef DECLARE_ARG
execv(argv[0], argv); execv(argv[0], argv);
err: err:
@@ -651,7 +670,7 @@ version_match:
version_error: version_error:
fclose(f); fclose(f);
free(tmp); free(tmp);
ERROR("must have criu " CRIU_VERSION " or greater to checkpoint/restore\n"); ERROR("must have criu " CRIU_VERSION " or greater to checkpoint/restore");
return false; return false;
} }
} }
@@ -666,7 +685,7 @@ static bool criu_ok(struct lxc_container *c, char **criu_version)
return false; return false;
if (geteuid()) { if (geteuid()) {
ERROR("Must be root to checkpoint\n"); ERROR("Must be root to checkpoint");
return false; return false;
} }
@@ -680,7 +699,7 @@ static bool criu_ok(struct lxc_container *c, char **criu_version)
case LXC_NET_MACVLAN: case LXC_NET_MACVLAN:
break; break;
default: default:
ERROR("Found un-dumpable network: %s (%s)\n", lxc_net_type_to_str(n->type), n->name); ERROR("Found un-dumpable network: %s (%s)", lxc_net_type_to_str(n->type), n->name);
return false; return false;
} }
} }
@@ -781,15 +800,6 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
close(pipes[0]); close(pipes[0]);
pipes[0] = -1; pipes[0] = -1;
if (dup2(pipes[1], STDERR_FILENO) < 0) {
SYSERROR("dup2 failed");
goto out_fini_handler;
}
if (dup2(pipes[1], STDOUT_FILENO) < 0) {
SYSERROR("dup2 failed");
goto out_fini_handler;
}
if (unshare(CLONE_NEWNS)) if (unshare(CLONE_NEWNS))
goto out_fini_handler; goto out_fini_handler;
@@ -816,6 +826,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
} }
} }
os.pipefd = pipes[1];
os.action = "restore"; os.action = "restore";
os.user = opts; os.user = opts;
os.c = c; os.c = c;
@@ -872,9 +883,11 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
goto out_fini_handler; goto out_fini_handler;
} }
if (n == sizeof(buf))
n--;
buf[n] = 0; buf[n] = 0;
ERROR("criu process exited %d, output:\n%s\n", WEXITSTATUS(status), buf); ERROR("criu process exited %d, output:\n%s", WEXITSTATUS(status), buf);
goto out_fini_handler; goto out_fini_handler;
} else { } else {
ret = snprintf(buf, sizeof(buf), "/proc/self/task/%lu/children", (unsigned long)syscall(__NR_gettid)); ret = snprintf(buf, sizeof(buf), "/proc/self/task/%lu/children", (unsigned long)syscall(__NR_gettid));
@@ -885,7 +898,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
FILE *f = fopen(buf, "r"); FILE *f = fopen(buf, "r");
if (!f) { if (!f) {
SYSERROR("couldn't read restore's children file %s\n", buf); SYSERROR("couldn't read restore's children file %s", buf);
goto out_fini_handler; goto out_fini_handler;
} }
@@ -902,7 +915,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
} }
} }
} else { } else {
ERROR("CRIU was killed with signal %d\n", WTERMSIG(status)); ERROR("CRIU was killed with signal %d", WTERMSIG(status));
goto out_fini_handler; goto out_fini_handler;
} }
@@ -1013,29 +1026,38 @@ static bool do_dump(struct lxc_container *c, char *mode, struct migrate_opts *op
{ {
pid_t pid; pid_t pid;
char *criu_version = NULL; char *criu_version = NULL;
int criuout[2];
if (!criu_ok(c, &criu_version)) if (!criu_ok(c, &criu_version))
return false; return false;
if (mkdir_p(opts->directory, 0700) < 0) if (pipe(criuout) < 0) {
SYSERROR("pipe() failed");
return false; return false;
}
if (mkdir_p(opts->directory, 0700) < 0)
goto fail;
pid = fork(); pid = fork();
if (pid < 0) { if (pid < 0) {
SYSERROR("fork failed"); SYSERROR("fork failed");
return false; goto fail;
} }
if (pid == 0) { if (pid == 0) {
struct criu_opts os; struct criu_opts os;
struct lxc_handler h; struct lxc_handler h;
close(criuout[0]);
h.name = c->name; h.name = c->name;
if (!cgroup_init(&h)) { if (!cgroup_init(&h)) {
ERROR("failed to cgroup_init()"); ERROR("failed to cgroup_init()");
exit(1); exit(1);
} }
os.pipefd = criuout[1];
os.action = mode; os.action = mode;
os.user = opts; os.user = opts;
os.c = c; os.c = c;
@@ -1050,27 +1072,51 @@ static bool do_dump(struct lxc_container *c, char *mode, struct migrate_opts *op
exit(1); exit(1);
} else { } else {
int status; int status;
ssize_t n;
char buf[4096];
bool ret;
close(criuout[1]);
pid_t w = waitpid(pid, &status, 0); pid_t w = waitpid(pid, &status, 0);
if (w == -1) { if (w == -1) {
SYSERROR("waitpid"); SYSERROR("waitpid");
close(criuout[0]);
return false; return false;
} }
n = read(criuout[0], buf, sizeof(buf));
close(criuout[0]);
if (n < 0) {
SYSERROR("read");
n = 0;
}
buf[n] = 0;
if (WIFEXITED(status)) { if (WIFEXITED(status)) {
if (WEXITSTATUS(status)) { if (WEXITSTATUS(status)) {
ERROR("dump failed with %d\n", WEXITSTATUS(status)); ERROR("dump failed with %d", WEXITSTATUS(status));
return false; ret = false;
} else {
ret = true;
}
} else if (WIFSIGNALED(status)) {
ERROR("dump signaled with %d", WTERMSIG(status));
ret = false;
} else {
ERROR("unknown dump exit %d", status);
ret = false;
} }
return true; if (!ret)
} else if (WIFSIGNALED(status)) { ERROR("criu output: %s", buf);
ERROR("dump signaled with %d\n", WTERMSIG(status)); return ret;
return false;
} else {
ERROR("unknown dump exit %d\n", status);
return false;
}
} }
fail:
close(criuout[0]);
close(criuout[1]);
rmdir(opts->directory);
return false;
} }
bool __criu_pre_dump(struct lxc_container *c, struct migrate_opts *opts) bool __criu_pre_dump(struct lxc_container *c, struct migrate_opts *opts)
@@ -1088,7 +1134,7 @@ bool __criu_dump(struct lxc_container *c, struct migrate_opts *opts)
return false; return false;
if (access(path, F_OK) == 0) { if (access(path, F_OK) == 0) {
ERROR("please use a fresh directory for the dump directory\n"); ERROR("please use a fresh directory for the dump directory");
return false; return false;
} }
@@ -1106,7 +1152,7 @@ bool __criu_restore(struct lxc_container *c, struct migrate_opts *opts)
return false; return false;
if (geteuid()) { if (geteuid()) {
ERROR("Must be root to restore\n"); ERROR("Must be root to restore");
return false; return false;
} }