Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

vzctl restore: support old and new interface of cpt lockfiles

The small historical reference about new semantic of wait_p:

commit fd657ab
Author: Kir Kolyshkin <kir@openvz.org>
Date:   Wed Jan 12 16:14:58 2011 +0300

    That "OK to go" signal is closing a specific file descriptor
    without sending anything via it, while "no go" signal is sending some
    error code. The problem is in case the parent segfaults, the kernel closes
    this fd and so the child thinks that everything is fine and runs init.

    This patch changes the logic: now "no go" signal is just closing fd, while
    "good to go" is actually sending something to that fd.

Now, newer kernels add support of wait_p with new semantic, it can
be set by CPT_SET_LOCK2. Use it if possible.

Nevertheless, backward compatibility with old kernels should be retained.
The above commit fd657ab changed sematic of wait_p, but it's sent
to the kernel, which still have old logic (and it broke restore).

This commit also adds back a descriptor with old semantic (old_wait_p),
which is to be used for old kernels (when CPT_SET_LOCK2 is not available).

http://bugzilla.openvz.org/1732

Signed-off-by: Andrey Vagin <avagin@openvz.org>
  • Loading branch information...
commit c4fd52f7301201cb9e439fad0e23b600e058a2ab 1 parent 4c6da8f
@avagin avagin authored kolyshkin committed
View
5 include/env.h
@@ -34,7 +34,7 @@
typedef int (*env_create_FN)(vps_handler *h, envid_t veid, int wait_p,
- int err_p, void *data);
+ int old_wait_p, int err_p, void *data);
/** Stop modes.
*/
@@ -102,7 +102,8 @@ int vps_stop(vps_handler *h, envid_t veid, vps_param *param, int stop_mode,
*/
int vz_chroot(const char *root);
int vz_env_create(vps_handler *h, envid_t veid, vps_res *res,
- int wait_p[2], int err_p[2], env_create_FN fn, void *data);
+ int wait_p[2], int old_wait_p[2], int err_p[2],
+ env_create_FN fn, void *data);
int vz_setluid(envid_t veid);
int vz_env_create_ioctl(vps_handler *h, envid_t veid, int flags);
#endif
View
1  include/linux/cpt_ioctl.h
@@ -45,5 +45,6 @@
#define CPT_SET_ERRORFD _IOW(CPTCTLTYPE, 21, int)
#define CPT_LINKDIR_ADD _IOW(CPTCTLTYPE, 24, int)
#define CPT_HARDLNK_ON _IOW(CPTCTLTYPE, 25, int)
+#define CPT_SET_LOCKFD2 _IOW(CPTCTLTYPE, 27, int)
#endif
View
15 src/lib/cpt.c
@@ -307,10 +307,10 @@ int vps_chkpnt(vps_handler *h, envid_t veid, vps_param *vps_p, int cmd,
return ret;
}
-static int restore_fn(vps_handler *h, envid_t veid, int wait_p, int err_p,
- void *data)
+static int restore_fn(vps_handler *h, envid_t veid, int wait_p,
+ int old_wait_p, int err_p, void *data)
{
- int status, len, len1;
+ int status, len, len1, ret;
cpt_param *param = (cpt_param *) data;
char buf[PIPE_BUF];
int error_pipe[2];
@@ -319,7 +319,7 @@ static int restore_fn(vps_handler *h, envid_t veid, int wait_p, int err_p,
if (param == NULL)
goto err;
/* Close all fds */
- close_fds(0, wait_p, err_p, h->vzfd, param->rst_fd, -1);
+ close_fds(0, wait_p, old_wait_p, err_p, h->vzfd, param->rst_fd, -1);
if (ioctl(param->rst_fd, CPT_SET_VEID, veid) < 0) {
logger(-1, errno, "Can't set CT ID %d", param->rst_fd);
goto err;
@@ -335,10 +335,15 @@ static int restore_fn(vps_handler *h, envid_t veid, int wait_p, int err_p,
goto err;
}
close(error_pipe[1]);
- if (ioctl(param->rst_fd, CPT_SET_LOCKFD, wait_p) < 0) {
+
+ ret = ioctl(param->rst_fd, CPT_SET_LOCKFD2, wait_p);
+ if (ret < 0 && errno == EINVAL)
+ ret = ioctl(param->rst_fd, CPT_SET_LOCKFD, old_wait_p);
+ if (ret < 0) {
logger(-1, errno, "Can't set lockfd");
goto err;
}
+
if (ioctl(param->rst_fd, CPT_SET_STATUSFD, STDIN_FILENO) < 0) {
logger(-1, errno, "Can't set statusfd");
goto err;
View
44 src/lib/env.c
@@ -429,7 +429,7 @@ static int _env_create(vps_handler *h, envid_t veid, int wait_p, int err_p,
}
static int vz_real_env_create(vps_handler *h, envid_t veid, vps_res *res,
- int wait_p, int err_p, env_create_FN fn, void *data)
+ int wait_p, int old_wait_p, int err_p, env_create_FN fn, void *data)
{
int ret, pid;
@@ -449,7 +449,7 @@ static int vz_real_env_create(vps_handler *h, envid_t veid, vps_res *res,
if (fn == NULL) {
ret = _env_create(h, veid, wait_p, err_p, (void *)res);
} else {
- ret = fn(h, veid, wait_p, err_p, data);
+ ret = fn(h, veid, wait_p, old_wait_p, err_p, data);
}
env_err:
if (ret)
@@ -460,9 +460,11 @@ static int vz_real_env_create(vps_handler *h, envid_t veid, vps_res *res,
}
int vz_env_create(vps_handler *h, envid_t veid, vps_res *res,
- int wait_p[2], int err_p[2], env_create_FN fn, void *data)
+ int wait_p[2], int old_wait_p[2], int err_p[2],
+ env_create_FN fn, void *data)
{
int ret, pid, errcode;
+ int old_wait_fd;
int status_p[2];
struct sigaction act, actold;
@@ -493,9 +495,15 @@ int vz_env_create(vps_handler *h, envid_t veid, vps_res *res,
close(err_p[0]);
fcntl(wait_p[0], F_SETFD, FD_CLOEXEC);
close(wait_p[1]);
-
- ret = vz_real_env_create(h, veid, res, wait_p[0], err_p[1], fn,
- data);
+ if (old_wait_p) {
+ fcntl(old_wait_p[0], F_SETFD, FD_CLOEXEC);
+ close(old_wait_p[1]);
+ old_wait_fd = old_wait_p[0];
+ } else
+ old_wait_fd = -1;
+
+ ret = vz_real_env_create(h, veid, res, wait_p[0],
+ old_wait_fd, err_p[1], fn, data);
if (ret)
write(STDIN_FILENO, &ret, sizeof(ret));
exit(ret);
@@ -503,6 +511,8 @@ int vz_env_create(vps_handler *h, envid_t veid, vps_res *res,
/* Wait for environment created */
close(status_p[1]);
close(wait_p[0]);
+ if (old_wait_p)
+ close(old_wait_p[0]);
close(err_p[1]);
ret = read(status_p[0], &errcode, sizeof(errcode));
if (ret > 0) {
@@ -570,6 +580,7 @@ int vps_start_custom(vps_handler *h, envid_t veid, vps_param *param,
env_create_FN fn, void *data)
{
int wait_p[2];
+ int old_wait_p[2];
int err_p[2];
int ret, err;
char buf[64];
@@ -608,6 +619,17 @@ int vps_start_custom(vps_handler *h, envid_t veid, vps_param *param,
logger(-1, errno, "Can not create pipe");
return VZ_RESOURCE_ERROR;
}
+ /* old_wait_p is needed for backward compatibily with old kernels.
+ * Now we use wait_p for this purpose. If old_wait_p is closed without
+ * writing any data, it's "OK to go" signal and if data are received
+ * from old_wait_p it's "no go" signal". It doesn't work if vzctl
+ * segfaults, because in this case the decriptor will be closed without
+ * sending data.
+ */
+ if (pipe(old_wait_p) < 0) {
+ logger(-1, errno, "Can not create pipe");
+ return VZ_RESOURCE_ERROR;
+ }
if (pipe(err_p) < 0) {
close(wait_p[0]);
close(wait_p[1]);
@@ -620,8 +642,12 @@ int vps_start_custom(vps_handler *h, envid_t veid, vps_param *param,
sigaction(SIGPIPE, &act, NULL);
fix_numiptent(&res->ub);
fix_cpu(&res->cpu);
- if ((ret = vz_env_create(h, veid, res, wait_p, err_p, fn, data)))
+
+ ret = vz_env_create(h, veid, res, wait_p,
+ old_wait_p, err_p, fn, data);
+ if (ret)
goto err;
+
if ((ret = vps_setup_res(h, veid, &actions, &res->fs, param,
STATE_STARTING, skip, mod)))
{
@@ -643,6 +669,8 @@ int vps_start_custom(vps_handler *h, envid_t veid, vps_param *param,
err = 0;
if (write(wait_p[1], &err, sizeof(err)) != sizeof(err))
logger(-1, errno, "Unable to write to waitfd to start init");
+ close(wait_p[1]);
+ close(old_wait_p[1]);
err:
free_dist_actions(&actions);
if (ret) {
@@ -654,6 +682,8 @@ int vps_start_custom(vps_handler *h, envid_t veid, vps_param *param,
* the environment, so it should not start /sbin/init
*/
close(wait_p[1]);
+ write(old_wait_p[1], &err, sizeof(err));
+ close(old_wait_p[1]);
} else {
if (!read(err_p[0], &ret, sizeof(ret))) {
if (res->misc.wait == YES) {
View
2  src/lib/exec.c
@@ -471,7 +471,7 @@ int vps_run_script(vps_handler *h, envid_t veid, char *script, vps_param *vps_p)
}
}
if ((ret = vz_env_create(h, veid, &vps_p->res, rd_p, wr_p,
- NULL, NULL)))
+ NULL, NULL, NULL)))
{
return ret;
}
Please sign in to comment.
Something went wrong with that request. Please try again.