[CRIU] [PATCH 11/11] tty: Use regular files engine to save paths to the peers

Cyrill Gorcunov gorcunov at openvz.org
Mon Oct 6 06:15:50 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, so that we need to somehow
carry paths with ourself in image.

Instead of bloating current tty image lets use regular file engine instead
and on checkpoint stage save a path to the link in regfiles set, then on
restore simply fetch it from the image.

Such approach will help in future when we need to support multiple
instances of devpts filesystem.

To support backward compatibility with images where no regfile
records are present we generate new "fake" one on the fly in
pty_alloc_fake_reg_d() helper.

Because of the need to restore dead slave peers and restore of
the controlling terminal we need to generate that named "fake
inverted" ptys in pty_alloc_fake() helper: in particular if
we need to open dead slave peer we generate fake master peer,
open it and the close out. Almost the same situation in
restoring contolling terminal -- we get master peer, generate
appropriate fake slave tty_info object, open it, manipulate,
the close out and free.

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 tty.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 212 insertions(+), 28 deletions(-)

diff --git a/tty.c b/tty.c
index edbe85e7505a..157109bf10f3 100644
--- a/tty.c
+++ b/tty.c
@@ -27,6 +27,7 @@
 #include "util-pie.h"
 #include "proc_parse.h"
 #include "file-ids.h"
+#include "files-reg.h"
 
 #include "protobuf.h"
 #include "protobuf/tty.pb-c.h"
@@ -80,6 +81,8 @@ struct tty_info {
 	struct list_head		list;
 	struct file_desc		d;
 
+	struct file_desc		*reg_d;
+
 	TtyFileEntry			*tfe;
 	TtyInfoEntry			*tie;
 
@@ -123,6 +126,8 @@ static DECLARE_BITMAP(tty_active_pairs, (MAX_TTYS << 1));
  */
 static mutex_t *tty_mutex;
 
+static bool tty_is_master(struct tty_info *info);
+
 int prepare_shared_tty(void)
 {
 	tty_mutex = shmalloc(sizeof(*tty_mutex));
@@ -245,18 +250,185 @@ static int tty_test_and_set(int bit, unsigned long *bitmap)
 	return ret;
 }
 
-static int pty_open_ptmx_index(int flags, int index)
+/*
+ * Generate a regular file object in case if such is missed
+ * in the image file, ie obsolete interface has been used on
+ * checkpoint.
+ */
+static struct file_desc *pty_alloc_fake_reg_d(struct tty_info *info, bool add)
+{
+	TtyFileEntry *tfe = info->tfe;
+	struct reg_file_info *r;
+
+	r = xzalloc(sizeof(*r) + sizeof(*r->rfe) + 64);
+	if (!r)
+		return NULL;
+
+	r->rfe = (void *)r + sizeof(*r);
+	reg_file_entry__init(r->rfe);
+
+	r->rfe->name = (void *)r + sizeof(*r) + sizeof(*r->rfe);
+	if (tty_is_master(info))
+		strcpy(r->rfe->name, "/dev/ptmx");
+	else
+		snprintf(r->rfe->name, 64, "/dev/pts/%u",
+			 info->tie->pty->index);
+
+	if (add)
+		file_desc_add(&r->d, tfe->id, NULL);
+	else {
+		r->d.id = tfe->id;
+		INIT_LIST_HEAD(&r->d.fd_info_head);
+		INIT_HLIST_NODE(&r->d.hash);
+	}
+
+	r->rfe->id	= tfe->id;
+	r->rfe->flags	= tfe->flags;
+	r->rfe->fown	= tfe->fown;
+	r->path		= &r->rfe->name[1];
+
+	return &r->d;
+}
+
+static struct tty_info *pty_alloc_fake(struct tty_info *info, bool master)
+{
+	struct reg_file_info *new, *orig;
+	struct tty_info *p;
+
+	pr_debug("Allocating fake for %#x (reg_d %p)\n",
+		 info->tfe->id, info->reg_d);
+
+	BUG_ON(!info->reg_d);
+	orig = container_of(info->reg_d, struct reg_file_info, d);
+
+	p = xzalloc(sizeof(*p)		+
+		    sizeof(*p->tfe)	+
+		    sizeof(*p->tie)	+
+		    sizeof(*p->tie->pty));
+	if (!p)
+		return NULL;
+
+	p->tfe = (void *)p + sizeof(*p);
+	tty_file_entry__init(p->tfe);
+
+	p->tie = (void *)p->tfe + sizeof(*p->tfe);
+	tty_info_entry__init(p->tie);
+
+	p->tie->pty = (void *)p->tie + sizeof(*p->tie);
+	tty_pty_entry__init(p->tie->pty);
+
+	p->tfe->id	= info->tfe->id;
+	p->tfe->flags	= info->tfe->flags;
+	p->tfe->fown	= info->tfe->fown;
+
+	if (master) {
+		p->major = TTYAUX_MAJOR;
+		p->minor = 0;
+	} else {
+		p->major = UNIX98_PTY_SLAVE_MAJOR;
+		p->minor = 0;
+	}
+
+	p->tie->pty->index = info->tie->pty->index;
+	p->reg_d = pty_alloc_fake_reg_d(p, false);
+	if (!p->reg_d) {
+		xfree(p);
+		return NULL;
+	}
+
+	new = container_of(p->reg_d, struct reg_file_info, d);
+
+	if ((master && tty_is_master(info)) ||
+	    (!master && !tty_is_master(info))) {
+		new->path = xstrdup(orig->path);
+		new->rfe->name = &new->path[1];
+	} else {
+		char *pos = strrchr(orig->rfe->name, '/');
+		size_t len = strlen(orig->rfe->name) + 1;
+		size_t slash_at = pos - orig->rfe->name;
+		char *inverted_path = xmalloc(len + 32);
+
+		BUG_ON(!pos || !inverted_path);
+
+		memcpy(inverted_path, orig->rfe->name, slash_at);
+		if (master)
+			strcat(inverted_path, "ptmx");
+		else {
+			if (slash_at >= 4 && strcmp(&inverted_path[slash_at - 4], "pts"))
+				snprintf(&inverted_path[slash_at], 10, "/pts/%u", p->tie->pty->index);
+			else
+				snprintf(&inverted_path[slash_at], 10, "/%u", p->tie->pty->index);
+		}
+
+		new->rfe->name = inverted_path;
+		new->path = &inverted_path[1];
+	}
+
+	return p;
+}
+
+static void pty_free_fake(struct tty_info **info)
+{
+	if (info) {
+		struct tty_info *p = *info;
+		struct reg_file_info *r;
+
+		r = container_of(p->reg_d, struct reg_file_info, d);
+		xfree(r->rfe->name);
+		xfree(p->reg_d);
+		xfree(p);
+		*info = NULL;
+	}
+}
+
+struct pty_open_args {
+	struct tty_info	*info;
+	unsigned int	flags;
+};
+
+static int do_open_pty_reg(int ns_root_fd, struct reg_file_info *rfi, void *v)
+{
+	struct pty_open_args *args = v;
+	int fd;
+
+	fd = openat(ns_root_fd, rfi->path, args->flags);
+	if (fd < 0) {
+		pr_err("Can't open pty %#x [%s]\n", args->info->tfe->id, rfi->path);
+		return -1;
+	}
+
+	return fd;
+}
+
+static int open_pty_reg(struct tty_info *info, unsigned int flags)
+{
+	struct pty_open_args args = {
+		.info	= info,
+		.flags	= flags,
+	};
+
+	return open_path(info->reg_d, do_open_pty_reg, &args);
+}
+
+static char *path_from_reg(struct file_desc *d)
+{
+	struct reg_file_info *rfi = container_of(d, struct reg_file_info, d);
+	return rfi->path;
+}
+
+static int pty_open_ptmx_index(struct tty_info *info, unsigned int flags)
 {
 	int fds[32], i, ret = -1, cur_idx;
+	int index = info->tie->pty->index;
 
 	memset(fds, 0xff, sizeof(fds));
 
 	mutex_lock(tty_mutex);
 
 	for (i = 0; i < ARRAY_SIZE(fds); i++) {
-		fds[i] = open(PTMX_PATH, flags);
+		fds[i] = open_pty_reg(info, flags);
 		if (fds[i] < 0) {
-			pr_perror("Can't open %s", PTMX_PATH);
+			pr_perror("Can't open %s", path_from_reg(info->reg_d));
 			break;
 		}
 
@@ -346,22 +518,24 @@ static int tty_set_prgp(int fd, int group)
 static int tty_restore_ctl_terminal(struct file_desc *d, int fd)
 {
 	struct tty_info *info = container_of(d, struct tty_info, d);
+	struct tty_info *fake;
 	int slave, ret = -1;
-	char pts_name[64];
 
 	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);
-	if (slave < 0) {
-		pr_perror("Can't open %s", pts_name);
+	fake = pty_alloc_fake(info, false);
+	if (!fake)
 		return -1;
+	slave = open_pty_reg(fake, O_RDONLY);
+	if (slave < 0) {
+		pr_perror("Can't open %s", path_from_reg(fake->reg_d));
+		goto err;
 	}
 
-	pr_info("Restore session %d by %d tty (index %d)\n",
+	pr_info("Restore session %d by %d tty (index %d master %d)\n",
 		 info->tie->sid, (int)getpid(),
-		 info->tie->pty->index);
+		 info->tie->pty->index, tty_is_master(info));
 
 	ret = tty_set_sid(slave);
 	if (!ret)
@@ -370,6 +544,8 @@ static int tty_restore_ctl_terminal(struct file_desc *d, int fd)
 	close(slave);
 	close(fd);
 
+err:
+	pty_free_fake(&fake);
 	return ret;
 }
 
@@ -458,9 +634,6 @@ 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);
 
 	sock = socket(PF_UNIX, SOCK_DGRAM, 0);
 	if (sock < 0) {
@@ -471,9 +644,9 @@ static int pty_open_slaves(struct tty_info *info)
 	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_pty_reg(slave, slave->tfe->flags | O_NOCTTY);
 		if (fd < 0) {
-			pr_perror("Can't open slave %s", pts_name);
+			pr_perror("Can't open slave %s", path_from_reg(slave->reg_d));
 			goto err;
 		}
 
@@ -483,7 +656,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, path_from_reg(slave->reg_d), fle->pid);
 
 		if (send_fd_to_peer(fd, fle, sock)) {
 			pr_perror("Can't send file descriptor");
@@ -525,6 +698,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;
+	struct tty_info *fake = NULL;
 
 	/*
 	 * We may have 2 cases here: the slave either need to
@@ -540,25 +714,24 @@ 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);
+		fake = pty_alloc_fake(slave, true);
+		if (!fake)
+			goto err;
 
-		master = pty_open_ptmx_index(O_RDONLY, slave->tie->pty->index);
+		master = pty_open_ptmx_index(fake, O_RDONLY);
 		if (master < 0) {
 			pr_perror("Can't open fale %x (index %d)",
 				  slave->tfe->id, slave->tie->pty->index);
-			return -1;
+			goto err;
 		}
 
 		unlock_pty(master);
 
-		fd = open(pts_name, slave->tfe->flags | O_NOCTTY);
+		fd = open_pty_reg(slave, slave->tfe->flags | O_NOCTTY);
 		if (fd < 0) {
-			pr_perror("Can't open slave %s", pts_name);
+			pr_perror("Can't open slave %s", path_from_reg(slave->reg_d));
 			goto err;
 		}
-
 	}
 
 	if (restore_tty_params(fd, slave))
@@ -597,6 +770,7 @@ static int pty_open_unpaired_slave(struct file_desc *d, struct tty_info *slave)
 err:
 	close_safe(&master);
 	close_safe(&fd);
+	pty_free_fake(&fake);
 	return ret;
 }
 
@@ -604,7 +778,7 @@ static int pty_open_ptmx(struct tty_info *info)
 {
 	int master = -1;
 
-	master = pty_open_ptmx_index(info->tfe->flags, info->tie->pty->index);
+	master = pty_open_ptmx_index(info, info->tie->pty->index);
 	if (master < 0) {
 		pr_perror("Can't open %x (index %d)",
 			  info->tfe->id, info->tie->pty->index);
@@ -613,9 +787,6 @@ static int pty_open_ptmx(struct tty_info *info)
 
 	unlock_pty(master);
 
-	if (rst_file_params(master, info->tfe->fown, info->tfe->flags))
-		goto err;
-
 	if (restore_tty_params(master, info))
 		goto err;
 
@@ -973,6 +1144,16 @@ static int collect_one_tty(void *obj, ProtobufCMessage *msg)
 	if (verify_info(info))
 		return -1;
 
+	info->reg_d = find_file_desc_raw(FD_TYPES__REG, info->tfe->id);
+	if (!info->reg_d) {
+		info->reg_d = pty_alloc_fake_reg_d(info, true);
+		if (!info->reg_d) {
+			pr_err("Can't generate new reg_d descriptor for id %#x\n",
+			       info->tfe->id);
+			return -1;
+		}
+	}
+
 	/*
 	 * The tty peers which have no @termios are hung up,
 	 * so don't mark them as active, we create them with
@@ -1165,6 +1346,9 @@ static int dump_one_pty(int lfd, u32 id, const struct fd_parms *p, int major, in
 	TtyFileEntry e = TTY_FILE_ENTRY__INIT;
 	int ret = 0, index;
 
+	if (dump_one_reg_file(lfd, id, p))
+		return -1;
+
 	index = parse_pty_index(id, lfd, p, major);
 	if (index < 0)
 		return -1;
-- 
1.9.3



More information about the CRIU mailing list