[CRIU] [PATCH 2/2] tty: Generate pty paths from mountpoints
Cyrill Gorcunov
gorcunov at openvz.org
Tue Oct 7 03:09:54 PDT 2014
Currently we're using predefined format for master/slave pty peers:
masters are always /dev/ptmx, while slaves are /dev/pts/$index,
where $index is the peer number.
While fitting most of distros this is not always correct and slave peers
might be mounted to an arbitrary place.
The very first solution was to save pty file paths via regular files
engine but this didn't work in case if master peer is closed and
slave peer become a ghost file -- the engine tries to collect such
files and calls for mknod() event before tty code become executing,
leading to errors.
Another option was to carry the path itself as a string inside
tty.img file but in case if (again) master peer is closed the
slave become something like "/dev/pts/2 (deleted)" which of
course can't be used on restore.
Give that another approach is used -- on checkpoint we save
mountpoint and superblock ids. Mountpoint gives us the base
paths to generate correct path on restore (say if mountpoint
is /dev/pts, then slave peer become /dev/pts/$index and such),
in turn superblock id will be needed to support multiple instaces
of devpts (note this is not yet implemented).
Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
protobuf/tty.proto | 3 +
tty.c | 182 ++++++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 157 insertions(+), 28 deletions(-)
diff --git a/protobuf/tty.proto b/protobuf/tty.proto
index 8942965c580b..c6825db6d7ea 100644
--- a/protobuf/tty.proto
+++ b/protobuf/tty.proto
@@ -64,4 +64,7 @@ message tty_file_entry {
required uint32 flags = 3;
required fown_entry fown = 4;
+
+ optional uint32 mnt_id = 5;
+ optional uint32 dev_sb = 6;
}
diff --git a/tty.c b/tty.c
index e86c60f3b91d..9cc334a54c92 100644
--- a/tty.c
+++ b/tty.c
@@ -24,6 +24,7 @@
#include "util.h"
#include "log.h"
#include "list.h"
+#include "mount.h"
#include "util-pie.h"
#include "proc_parse.h"
#include "file-ids.h"
@@ -86,6 +87,7 @@ struct tty_info {
struct list_head sibling;
int major;
int minor;
+ char *path;
bool create;
bool inherit;
@@ -123,6 +125,10 @@ static DECLARE_BITMAP(tty_active_pairs, (MAX_TTYS << 1));
*/
static mutex_t *tty_mutex;
+static char *pty_alloc_path(struct tty_info *info, bool master);
+#define pty_alloc_path_master(info) pty_alloc_path(info, true)
+#define pty_alloc_path_slave(info) pty_alloc_path(info, false)
+
int prepare_shared_tty(void)
{
tty_mutex = shmalloc(sizeof(*tty_mutex));
@@ -245,7 +251,7 @@ static int tty_test_and_set(int bit, unsigned long *bitmap)
return ret;
}
-static int pty_open_ptmx_index(int flags, int index)
+static int pty_open_ptmx_index(char *path, int flags, int index)
{
int fds[32], i, ret = -1, cur_idx;
@@ -254,14 +260,14 @@ static int pty_open_ptmx_index(int flags, int index)
mutex_lock(tty_mutex);
for (i = 0; i < ARRAY_SIZE(fds); i++) {
- fds[i] = open(PTMX_PATH, flags);
+ fds[i] = open(path, flags);
if (fds[i] < 0) {
- pr_perror("Can't open %s", PTMX_PATH);
+ pr_perror("Can't open %s", path);
break;
}
if (ioctl(fds[i], TIOCGPTN, &cur_idx)) {
- pr_perror("Can't obtain current index on %s", PTMX_PATH);
+ pr_perror("Can't obtain current index on %s", path);
break;
}
@@ -281,7 +287,7 @@ static int pty_open_ptmx_index(int flags, int index)
if (cur_idx < index && (index - cur_idx) < ARRAY_SIZE(fds))
continue;
- pr_err("Unable to open %s with specified index %d\n", PTMX_PATH, index);
+ pr_err("Unable to open %s with specified index %d\n", path, index);
break;
}
@@ -347,15 +353,18 @@ static int tty_restore_ctl_terminal(struct file_desc *d, int fd)
{
struct tty_info *info = container_of(d, struct tty_info, d);
int slave, ret = -1;
- char pts_name[64];
+ char *pts_path;
if (!is_service_fd(fd, CTL_TTY_OFF))
return 0;
- snprintf(pts_name, sizeof(pts_name), PTS_FMT, info->tie->pty->index);
- slave = open(pts_name, O_RDONLY);
+ pts_path = pty_alloc_path_slave(info);
+ if (!pts_path)
+ return -1;
+ slave = open(pts_path, O_RDONLY);
if (slave < 0) {
- pr_perror("Can't open %s", pts_name);
+ pr_perror("Can't open %s", pts_path);
+ xfree(pts_path);
return -1;
}
@@ -367,6 +376,7 @@ static int tty_restore_ctl_terminal(struct file_desc *d, int fd)
if (!ret)
ret = tty_set_prgp(slave, info->tie->pgrp);
+ xfree(pts_path);
close(slave);
close(fd);
@@ -458,9 +468,7 @@ static int pty_open_slaves(struct tty_info *info)
int sock = -1, fd = -1, ret = -1;
struct fdinfo_list_entry *fle;
struct tty_info *slave;
- char pts_name[64];
-
- snprintf(pts_name, sizeof(pts_name), PTS_FMT, info->tie->pty->index);
+ char *pts_path = NULL;
sock = socket(PF_UNIX, SOCK_DGRAM, 0);
if (sock < 0) {
@@ -468,12 +476,16 @@ static int pty_open_slaves(struct tty_info *info)
goto err;
}
+ pts_path = pty_alloc_path_slave(info);
+ if (!pts_path)
+ return -1;
+
list_for_each_entry(slave, &info->sibling, sibling) {
BUG_ON(tty_is_master(slave));
- fd = open(pts_name, slave->tfe->flags | O_NOCTTY);
+ fd = open(pts_path, slave->tfe->flags | O_NOCTTY);
if (fd < 0) {
- pr_perror("Can't open slave %s", pts_name);
+ pr_perror("Can't open slave %s", pts_path);
goto err;
}
@@ -483,7 +495,7 @@ static int pty_open_slaves(struct tty_info *info)
fle = file_master(&slave->d);
pr_debug("send slave %#x fd %d connected on %s (pid %d)\n",
- slave->tfe->id, fd, pts_name, fle->pid);
+ slave->tfe->id, fd, pts_path, fle->pid);
if (send_fd_to_peer(fd, fle, sock)) {
pr_perror("Can't send file descriptor");
@@ -496,6 +508,7 @@ static int pty_open_slaves(struct tty_info *info)
ret = 0;
err:
+ xfree(pts_path);
close_safe(&fd);
close_safe(&sock);
return ret;
@@ -525,6 +538,7 @@ static int receive_tty(struct tty_info *info)
static int pty_open_unpaired_slave(struct file_desc *d, struct tty_info *slave)
{
int master = -1, ret = -1, fd = -1;
+ char *ptmx_path = NULL;
/*
* We may have 2 cases here: the slave either need to
@@ -540,22 +554,25 @@ static int pty_open_unpaired_slave(struct file_desc *d, struct tty_info *slave)
pr_info("Migrated slave peer %x -> to fd %d\n",
slave->tfe->id, fd);
} else {
- char pts_name[64];
-
- snprintf(pts_name, sizeof(pts_name), PTS_FMT, slave->tie->pty->index);
+ ptmx_path = pty_alloc_path_master(slave);
+ if (!ptmx_path)
+ goto err;
- master = pty_open_ptmx_index(O_RDONLY, slave->tie->pty->index);
+ master = pty_open_ptmx_index(ptmx_path,
+ O_RDONLY,
+ slave->tie->pty->index);
if (master < 0) {
- pr_perror("Can't open fale %x (index %d)",
- slave->tfe->id, slave->tie->pty->index);
- return -1;
+ pr_perror("Can't open fake %s (id %#x index %d)",
+ ptmx_path, slave->tfe->id,
+ slave->tie->pty->index);
+ goto err;
}
unlock_pty(master);
- fd = open(pts_name, slave->tfe->flags | O_NOCTTY);
+ fd = open(slave->path, slave->tfe->flags | O_NOCTTY);
if (fd < 0) {
- pr_perror("Can't open slave %s", pts_name);
+ pr_perror("Can't open slave %s", slave->path);
goto err;
}
@@ -597,18 +614,26 @@ static int pty_open_unpaired_slave(struct file_desc *d, struct tty_info *slave)
err:
close_safe(&master);
close_safe(&fd);
+ xfree(ptmx_path);
return ret;
}
static int pty_open_ptmx(struct tty_info *info)
{
+ char *ptmx_path = NULL;
int master = -1;
- master = pty_open_ptmx_index(info->tfe->flags, info->tie->pty->index);
- if (master < 0) {
- pr_perror("Can't open %x (index %d)",
- info->tfe->id, info->tie->pty->index);
+ ptmx_path = pty_alloc_path_master(info);
+ if (!ptmx_path)
return -1;
+
+ master = pty_open_ptmx_index(ptmx_path,
+ info->tfe->flags,
+ info->tie->pty->index);
+ if (master < 0) {
+ pr_perror("Can't open %s (id %#x index %d)",
+ ptmx_path, info->tfe->id, info->tie->pty->index);
+ goto err;
}
unlock_pty(master);
@@ -635,9 +660,11 @@ static int pty_open_ptmx(struct tty_info *info)
if (info->tie->locked)
lock_pty(master);
+ xfree(ptmx_path);
return master;
err:
close_safe(&master);
+ xfree(ptmx_path);
return -1;
}
@@ -951,6 +978,85 @@ struct collect_image_info tty_info_cinfo = {
.flags = COLLECT_OPTIONAL,
};
+static int tty_make_path(struct tty_info *info)
+{
+ if (info->tfe->has_mnt_id) {
+ struct mount_info *m;
+ size_t len;
+
+ m = lookup_mnt_id(info->tfe->mnt_id);
+ if (!m) {
+ pr_err("No mount point with mnt_id %#x for %#x\n",
+ info->tfe->mnt_id, info->tfe->id);
+ }
+
+ len = strlen(m->mountpoint);
+ info->path = xmalloc(len + 32);
+ if (!info->path)
+ goto nomem;
+
+ strcpy(info->path, &m->mountpoint[1]);
+ if (tty_is_master(info))
+ strcat(&info->path[len - 1], "/ptmx");
+ else
+ snprintf(&info->path[len - 1], 32, "/%u", info->tie->pty->index);
+ } else {
+ if (tty_is_master(info))
+ info->path = xstrdup("/dev/ptmx");
+ else {
+ info->path = xmalloc(32);
+ if (info->path)
+ snprintf(info->path, 32, "/dev/pts/%u",
+ info->tie->pty->index);
+ }
+ if (!info->path)
+ goto nomem;
+ }
+
+ return 0;
+nomem:
+ return -ENOMEM;
+}
+
+static char *pty_alloc_path(struct tty_info *info, bool master)
+{
+ char *pos, *path;
+ size_t len, slash_at;
+
+ if ((tty_is_master(info) && master) ||
+ (!tty_is_master(info) && !master))
+ return xstrdup(info->path);
+
+ len = strlen(info->path) + 1;
+ pos = strrchr(info->path, '/');
+ slash_at = pos - info->path;
+
+ if (!pos) {
+ pr_err("Malformed path %s for %#x\n",
+ info->path, info->tfe->id);
+ return NULL;
+ }
+
+ path = xmalloc(len + 32);
+ if (!path)
+ return NULL;
+
+ memcpy(path, info->path, slash_at + 1);
+ if (master) {
+ path[slash_at + 1] = '\0';
+ strcat(&path[slash_at + 1], "ptmx");
+ } else {
+ if (slash_at >= 4 && strcmp(&path[slash_at - 4], "pts"))
+ snprintf(&path[slash_at], 10,
+ "/pts/%u", info->tie->pty->index);
+ else
+ snprintf(&path[slash_at], 10,
+ "/%u", info->tie->pty->index);
+ }
+
+ return path;
+}
+
static int collect_one_tty(void *obj, ProtobufCMessage *msg)
{
struct tty_info *info = obj;
@@ -973,6 +1079,9 @@ static int collect_one_tty(void *obj, ProtobufCMessage *msg)
if (verify_info(info))
return -1;
+ if (tty_make_path(info))
+ return -1;
+
/*
* The tty peers which have no @termios are hung up,
* so don't mark them as active, we create them with
@@ -1174,6 +1283,23 @@ static int dump_one_pty(int lfd, u32 id, const struct fd_parms *p, int major, in
e.flags = p->flags;
e.fown = (FownEntry *)&p->fown;
+ e.has_dev_sb = true;
+ e.dev_sb = p->stat.st_dev;
+
+ e.has_mnt_id = true;
+ if (p->mnt_id != -1) {
+ e.mnt_id = p->mnt_id;
+ } else {
+ struct mount_info *m = lookup_mnt_sdev(p->stat.st_dev);
+ if (!m) {
+ pr_err("Can't find mount with st_dev %#x\n",
+ (int)p->stat.st_dev);
+ return -1;
+ }
+
+ e.mnt_id = m->mnt_id;
+ }
+
/*
* FIXME
*
--
1.9.3
More information about the CRIU
mailing list