[CRIU] [PATCH 6/7] tty: Add support for multiple devpts instances

Cyrill Gorcunov gorcunov at openvz.org
Sat Jan 21 05:11:26 PST 2017


To support several devpts instances we need to distinguish them
from each other, thus now use use @mnt_id from dump stage to
link tty file entries and tty info entries with each other.

To track if we need to dump particular tty info entry
and test if all peers are present instead of static
bitmaps we use dynamics: one per mount.

Also to be able to create master/slave pty peers
from different mounts the pty_alloc_reg been
reworked and hopefully simplified.

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 criu/tty.c | 239 +++++++++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 170 insertions(+), 69 deletions(-)

diff --git a/criu/tty.c b/criu/tty.c
index bbdb3ca2e071..2560b27a855c 100644
--- a/criu/tty.c
+++ b/criu/tty.c
@@ -28,11 +28,13 @@
 #include "files-reg.h"
 #include "namespaces.h"
 #include "external.h"
+#include "filesystems.h"
 #include "mount.h"
 
 #include "protobuf.h"
 #include "util.h"
 #include "images/tty.pb-c.h"
+#include "images/mnt.pb-c.h"
 
 #include "parasite-syscall.h"
 #include "parasite.h"
@@ -150,9 +152,6 @@ static LIST_HEAD(all_ttys);
 #define STTY_INDEX	1010
 #define INDEX_ERR	(MAX_TTYS + 1)
 
-static DECLARE_BITMAP(tty_bitmap, (MAX_TTYS << 1));
-static DECLARE_BITMAP(tty_active_pairs, (MAX_TTYS << 1));
-
 struct tty_driver {
 	short				type;
 	short				subtype;
@@ -166,6 +165,47 @@ struct tty_driver {
 #define TTY_SUBTYPE_MASTER			0x0001
 #define TTY_SUBTYPE_SLAVE			0x0002
 
+typedef struct tty_bitmap_s {
+	struct tty_bitmap_s		*next;
+	unsigned long			bitmap[BITS_TO_LONGS((MAX_TTYS << 1))];
+	int				mnt_id;
+} tty_bitmap_t;
+
+static tty_bitmap_t *tty_info_id_bitmap;
+static tty_bitmap_t *tty_active_pairs_bitmap;
+
+static void tty_free_bitmap(tty_bitmap_t *root)
+{
+	tty_bitmap_t *t, *next;
+
+	for (t = root; t; t = next) {
+		next = t->next;
+		xfree(t);
+	}
+}
+
+static unsigned long *tty_lookup_bitmap(tty_bitmap_t **root, int mnt_id)
+{
+	tty_bitmap_t *t, *prev;
+
+	for (t = *root, prev = NULL; t; prev = t, t = t->next) {
+		if (t->mnt_id == mnt_id)
+			return t->bitmap;
+	}
+
+	t = xzalloc(sizeof(*t));
+	if (!t)
+		return NULL;
+
+	if (prev)
+		prev->next = t;
+	if (!*root)
+		*root = t;
+
+	t->mnt_id = mnt_id;
+	return t->bitmap;
+}
+
 static int ptm_fd_get_index(int fd, const struct fd_parms *p)
 {
 	int index;
@@ -367,13 +407,13 @@ static int tty_get_index(u32 id)
 }
 
 /* Make sure the active pairs do exist */
-static int tty_verify_active_pairs(void * unused)
+static int __tty_verify_active_pairs(unsigned long *bitmap)
 {
 	unsigned long i, unpaired_slaves = 0;
 
-	for_each_bit(i, tty_active_pairs) {
+	for_each_bit(i, bitmap) {
 		if ((i % 2) == 0) {
-			if (test_bit(i + 1, tty_active_pairs)) {
+			if (test_bit(i + 1, bitmap)) {
 				i++;
 				continue;
 			}
@@ -399,6 +439,18 @@ static int tty_verify_active_pairs(void * unused)
 	return 0;
 }
 
+static int tty_verify_active_pairs(void * unused)
+{
+	tty_bitmap_t *t;
+
+	for (t = tty_active_pairs_bitmap; t; t = t->next) {
+		if (__tty_verify_active_pairs(t->bitmap))
+			return -1;
+	}
+
+	return 0;
+}
+
 static int tty_test_and_set(int bit, unsigned long *bitmap)
 {
 	int ret;
@@ -414,12 +466,41 @@ static int tty_test_and_set(int bit, unsigned long *bitmap)
  * in the image file, ie obsolete interface has been used on
  * checkpoint.
  */
-static struct file_desc *pty_alloc_reg(struct tty_info *info, bool add)
+static struct file_desc *pty_alloc_reg(struct tty_info *info, bool add, bool invert)
 {
 	TtyFileEntry *tfe = info->tfe;
-	const size_t namelen = 64;
 	struct reg_file_info *r;
 	static struct file_desc_ops noops = {};
+	struct mount_info *mi;
+	size_t namelen;
+	bool need_pts;
+
+	mi = lookup_mnt_id(info->tfe->mnt_id);
+	if (!mi) {
+		pr_err("Can't resolve mnt_id %#x\n", info->tfe->mnt_id);
+		return NULL;
+	}
+
+	if ((tty_is_master(info) && !invert) ||
+	    (!tty_is_master(info) && invert)) {
+		need_pts = false;
+	} else {
+		need_pts = true;
+
+		if (info->link) {
+			struct reg_file_info *rfi = container_of(info->link->reg_d,
+								 struct reg_file_info, d);
+			pr_debug("Trying to use link: %s\n", rfi->path);
+			mi = lookup_mnt_id(info->link->tfe->mnt_id);
+			if (!mi) {
+				pr_err("Can't resolve link mnt_id %#x\n", info->tfe->mnt_id);
+				return NULL;
+			}
+			pr_debug("Mount at %s\n", mi->mountpoint);
+		}
+	}
+
+	namelen = strlen(mi->mountpoint) + 64;
 
 	r = xzalloc(sizeof(*r) + sizeof(*r->rfe) + namelen);
 	if (!r)
@@ -429,11 +510,12 @@ static struct file_desc *pty_alloc_reg(struct tty_info *info, bool add)
 	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");
+
+	if (!need_pts)
+		snprintf(r->rfe->name, namelen, "%s/ptmx", mi->mountpoint);
 	else
-		snprintf(r->rfe->name, namelen, "/dev/pts/%u",
-			 info->tie->pty->index);
+		snprintf(r->rfe->name, namelen, "%s/%u",
+			 mi->mountpoint, info->tie->pty->index);
 
 	if (add)
 		file_desc_add(&r->d, tfe->id, &noops);
@@ -464,52 +546,32 @@ static struct file_desc *pty_alloc_reg(struct tty_info *info, bool add)
  */
 static struct reg_file_info *pty_alloc_fake_reg(struct tty_info *info, int subtype)
 {
-	struct reg_file_info *new, *orig;
 	struct file_desc *fake_desc;
-
-	pr_debug("Allocating fake descriptor for %#x (reg_d %p)\n",
-		 info->tfe->id, info->reg_d);
+	struct reg_file_info *rfi;
+	bool invert;
 
 	BUG_ON(!info->reg_d);
 	BUG_ON(!is_pty(info->driver));
 
-	fake_desc = pty_alloc_reg(info, false);
-	if (!fake_desc)
-		return NULL;
+	if ((subtype == TTY_SUBTYPE_MASTER && tty_is_master(info)) ||
+	    (subtype == TTY_SUBTYPE_SLAVE && !tty_is_master(info)))
+		invert = false;
+	else
+		invert = true;
 
-	orig = container_of(info->reg_d, struct reg_file_info, d);
-	new = container_of(fake_desc, struct reg_file_info, d);
+	rfi = container_of(info->reg_d, struct reg_file_info, d);
+	pr_debug("Allocating fake descriptor for %#x (path %s, invert %d)\n",
+		 info->tfe->id, rfi->path, invert);
 
-	if ((subtype == TTY_SUBTYPE_MASTER && tty_is_master(info)) ||
-	    (subtype == TTY_SUBTYPE_SLAVE && !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 + 1);
-		if (subtype == TTY_SUBTYPE_MASTER) {
-			inverted_path[slash_at + 1] = '\0';
-			strcat(inverted_path, "ptmx");
-		} else {
-			if (slash_at >= 3 && strncmp(&inverted_path[slash_at - 3], "pts", 3))
-				snprintf(&inverted_path[slash_at + 1], 10, "pts/%u",
-					 info->tie->pty->index);
-			else
-				snprintf(&inverted_path[slash_at + 1], 10, "%u",
-					 info->tie->pty->index);
-		}
+	fake_desc = pty_alloc_reg(info, false, invert);
+	if (!fake_desc)
+		return NULL;
 
-		new->rfe->name = inverted_path;
-		new->path = &inverted_path[1];
-	}
+	rfi = container_of(fake_desc, struct reg_file_info, d);
+	pr_debug("Allocated fake descriptor for %#x as (path %s, invert %d)\n",
+		 info->tfe->id, rfi->path, invert);
 
-	return new;
+	return rfi;
 }
 
 #define pty_alloc_fake_master(info)	pty_alloc_fake_reg(info, TTY_SUBTYPE_MASTER)
@@ -518,7 +580,6 @@ static struct reg_file_info *pty_alloc_fake_reg(struct tty_info *info, int subty
 static void pty_free_fake_reg(struct reg_file_info **r)
 {
 	if (*r) {
-		xfree((*r)->rfe->name);
 		xfree((*r));
 		*r = NULL;
 	}
@@ -739,12 +800,11 @@ static bool tty_is_hung(struct tty_info *info)
 	return info->tie->termios == NULL;
 }
 
-static bool tty_has_active_pair(struct tty_info *info)
+static bool tty_has_active_pair(struct tty_info *info, unsigned long *bitmap)
 {
 	int d = tty_is_master(info) ? -1 : + 1;
 
-	return test_bit(info->tfe->tty_info_id + d,
-			tty_active_pairs);
+	return test_bit(info->tfe->tty_info_id + d, bitmap);
 }
 
 static void tty_show_pty_info(char *prefix, struct tty_info *info)
@@ -1214,7 +1274,13 @@ static int tty_find_restoring_task(struct tty_info *info)
 
 	if (info->tie->sid) {
 		if (!tty_is_master(info)) {
-			if (tty_has_active_pair(info))
+			unsigned long *bitmap;
+
+			bitmap = tty_lookup_bitmap(&tty_active_pairs_bitmap,
+						   info->tfe->mnt_id);
+			if (!bitmap)
+				goto nobitmap;
+			if (tty_has_active_pair(info, bitmap))
 				return 0;
 			else
 				goto shell_job;
@@ -1244,9 +1310,15 @@ static int tty_find_restoring_task(struct tty_info *info)
 
 		goto notask;
 	} else {
+		unsigned long *bitmap;
+
 		if (tty_is_master(info))
 			return 0;
-		if (tty_has_active_pair(info))
+		bitmap = tty_lookup_bitmap(&tty_active_pairs_bitmap,
+					   info->tfe->mnt_id);
+		if (!bitmap)
+			goto nobitmap;
+		if (tty_has_active_pair(info, bitmap))
 			return 0;
 	}
 
@@ -1260,6 +1332,9 @@ shell_job:
 notask:
 	pr_err("No task found with sid %d\n", info->tie->sid);
 	return -1;
+nobitmap:
+	pr_err("No pairing bitmap for %#x\n", info->tfe->id);
+	return -1;
 }
 
 static int tty_setup_orphan_slavery(void)
@@ -1320,7 +1395,8 @@ static int tty_setup_slavery(void * unused)
 		list_for_each_entry_continue(peer, &all_ttys, list) {
 			if (!is_pty(peer->driver) || peer->link)
 				continue;
-			if (peer->tie->pty->index == info->tie->pty->index) {
+			if (peer->tie->pty->index == info->tie->pty->index &&
+			    peer->tie->mnt_id == info->tie->mnt_id) {
 				info->link = peer;
 				peer->link = info;
 
@@ -1351,7 +1427,8 @@ static int tty_setup_slavery(void * unused)
 			if (!peer->tie->sid || peer->ctl_tty ||
 			    peer->driver->type == TTY_TYPE__CTTY)
 				continue;
-			if (peer->tie->sid == info->tie->sid) {
+			if (peer->tie->sid == info->tie->sid &&
+			    peer->tie->mnt_id == info->tie->mnt_id) {
 				pr_debug(" `- slave %#x\n", peer->tfe->id);
 				peer->ctl_tty = info;
 			}
@@ -1368,7 +1445,8 @@ static int tty_setup_slavery(void * unused)
 		list_for_each_entry_safe_continue(peer, m, &all_ttys, list) {
 			if (!is_pty(peer->driver))
 				continue;
-			if (peer->tie->pty->index != info->tie->pty->index)
+			if (peer->tie->pty->index != info->tie->pty->index ||
+			    peer->tie->mnt_id != info->tie->mnt_id)
 				continue;
 
 			if (tty_find_restoring_task(peer))
@@ -1444,12 +1522,12 @@ static int verify_info(struct tty_info *info)
 	return 0;
 }
 
-static TtyInfoEntry *lookup_tty_info_entry(u32 id)
+static TtyInfoEntry *lookup_tty_info_entry(u32 id, int mnt_id)
 {
 	struct tty_info_entry *e;
 
 	list_for_each_entry(e, &all_tty_info_entries, list) {
-		if (e->tie->id == id)
+		if (e->tie->id == id && e->tie->mnt_id == mnt_id)
 			return e->tie;
 	}
 
@@ -1516,7 +1594,7 @@ static int collect_one_tty(void *obj, ProtobufCMessage *msg, struct cr_img *i)
 		info->tfe->mnt_id = 0;
 	}
 
-	info->tie = lookup_tty_info_entry(info->tfe->tty_info_id);
+	info->tie = lookup_tty_info_entry(info->tfe->tty_info_id, info->tfe->mnt_id);
 	if (!info->tie) {
 		pr_err("No tty-info-id %#x found on id %#x\n",
 		       info->tfe->tty_info_id, info->tfe->id);
@@ -1555,7 +1633,7 @@ static int collect_one_tty(void *obj, ProtobufCMessage *msg, struct cr_img *i)
 				return -1;
 
 			if (is_pty(info->driver)) {
-				info->reg_d = pty_alloc_reg(info, true);
+				info->reg_d = pty_alloc_reg(info, true, false);
 				if (!info->reg_d) {
 					pr_err("Can't generate new reg descriptor for id %#x\n",
 					       info->tfe->id);
@@ -1575,8 +1653,16 @@ static int collect_one_tty(void *obj, ProtobufCMessage *msg, struct cr_img *i)
 	 * can't be used. Most likely they appear if a user has
 	 * dumped program when it was closing a peer.
 	 */
-	if (is_pty(info->driver) && info->tie->termios)
-		tty_test_and_set(info->tfe->tty_info_id, tty_active_pairs);
+	if (is_pty(info->driver) && info->tie->termios) {
+		unsigned long *bitmap = tty_lookup_bitmap(&tty_active_pairs_bitmap,
+							  info->tfe->mnt_id);
+		if (!bitmap) {
+			pr_err("No pairing bitmap for %#x\n", info->tfe->id);
+			return -1;
+		}
+
+		tty_test_and_set(info->tfe->tty_info_id, bitmap);
+	}
 
 	pr_info("Collected tty ID %#x (%s)\n", info->tfe->id, info->driver->name);
 
@@ -1613,7 +1699,8 @@ static int collect_one_tty_data(void *obj, ProtobufCMessage *msg, struct cr_img
 		 tdo->tde->tty_id, (size_t)tdo->tde->data.len);
 
 	list_for_each_entry(info, &all_ttys, list) {
-		if (tdo->tde->tty_id == info->tie->id) {
+		if (tdo->tde->tty_id == info->tie->id &&
+		    tdo->tde->mnt_id == info->tie->mnt_id) {
 			info->tty_data = tdo;
 			return 0;
 		}
@@ -1774,8 +1861,14 @@ static int dump_tty_info(int lfd, u32 id, const struct fd_parms *p, int mnt_id,
 	 * not yet supported by our tool and better to
 	 * inform a user about such situation.
 	 */
-	if (is_pty(driver))
-		tty_test_and_set(id, tty_active_pairs);
+	if (is_pty(driver)) {
+		unsigned long *bitmap = tty_lookup_bitmap(&tty_active_pairs_bitmap, mnt_id);
+		if (!bitmap) {
+			pr_err("No pairing bitmap for %#x\n", id);
+			return -1;
+		}
+		tty_test_and_set(id, bitmap);
+	}
 
 	info.termios		= &termios;
 	info.termios_locked	= &termios_locked;
@@ -1823,6 +1916,7 @@ static int dump_one_tty(int lfd, u32 id, const struct fd_parms *p)
 	TtyFileEntry e = TTY_FILE_ENTRY__INIT;
 	int ret = 0, index = -1, mnt_id;
 	struct tty_driver *driver;
+	unsigned long *bitmap;
 
 	pr_info("Dumping tty %d with id %#x\n", lfd, id);
 
@@ -1877,7 +1971,11 @@ static int dump_one_tty(int lfd, u32 id, const struct fd_parms *p)
 	 * transport anyway.
 	 */
 
-	if (!tty_test_and_set(e.tty_info_id, tty_bitmap))
+	bitmap = tty_lookup_bitmap(&tty_info_id_bitmap, mnt_id);
+	if (!bitmap)
+		return -ENOMEM;
+
+	if (!tty_test_and_set(e.tty_info_id, bitmap))
 		ret = dump_tty_info(lfd, e.tty_info_id, p, mnt_id, driver, index);
 
 	if (!ret)
@@ -2053,7 +2151,8 @@ static int tty_dump_queued_data(void)
 			if (!is_pty(peer->driver) || peer->link)
 				continue;
 
-			if (peer->index == dinfo->index) {
+			if (peer->index == dinfo->index &&
+			    peer->mnt_id == dinfo->mnt_id) {
 				dinfo->link = peer;
 				peer->link = dinfo;
 				pr_debug("Link PTYs (%#x)\n", dinfo->id);
@@ -2121,4 +2220,6 @@ int tty_prep_fds(void)
 void tty_fini_fds(void)
 {
 	close_service_fd(SELF_STDIN_OFF);
+	tty_free_bitmap(tty_info_id_bitmap);
+	tty_free_bitmap(tty_active_pairs_bitmap);
 }
-- 
2.7.4



More information about the CRIU mailing list