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

Pavel Emelyanov xemul at virtuozzo.com
Tue Jan 31 03:34:38 PST 2017


On 01/21/2017 04:11 PM, Cyrill Gorcunov wrote:
> 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));
> -

Split bitmap rework into separate patch, please.

>  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)

Plz, describe the new argument. What is it for?

>  {
>  	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);
>  }
> 



More information about the CRIU mailing list