[CRIU] Re: [PATCH 19/26] pipes: Add c/r for fifo files

Pavel Emelyanov xemul at parallels.com
Tue Jun 19 07:43:19 EDT 2012


On 06/19/2012 12:30 PM, Cyrill Gorcunov wrote:
> 
> Basically pipes are superset over fifos,
> so we integrate fifo c/r into pipes.c.
> 
> There os acatually a trick used to open fifo files --
> since fifo may block on opening we create a fake fifo
> to be able to proceed without sleeping.
> 
> Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
> ---
>  cr-dump.c       |    8 ++-
>  cr-show.c       |   15 ++++-
>  include/image.h |   10 +++
>  include/pipes.h |    3 +
>  pipes.c         |  193 ++++++++++++++++++++++++++++++++++++++++++++++++-------
>  5 files changed, 202 insertions(+), 27 deletions(-)
> 

> @@ -206,9 +207,19 @@ void show_pipes(int fd_pipes, struct cr_options *o)
>  		ret = read_img_eof(fd_pipes, &e);
>  		if (ret <= 0)
>  			goto out;
> -		pr_msg("id: 0x%8x pipeid: 0x%8x flags: 0x%8x ",
> -		       e.id, e.pipe_id, e.flags);
> +		pr_msg("id: 0x%8x pipeid: 0x%8x type: %4s flags: 0x%8x ",
> +		       e.id, e.pipe_id, pipetype2s(e.type), e.flags);
>  		show_fown_cont(&e.fown);
> +
> +		if (e.len) {
> +			int ret = read(fd_pipes, local_buf, e.len);

read_img_buf

> +			if (ret != e.len) {
> +				pr_perror("Can't read %d bytes", e.len);
> +				goto out;
> +			}
> +			local_buf[e.len] = 0;
> +			pr_msg(" --> %s", local_buf);
> +		}
>  		pr_msg("\n");
>  	}
>  

>  struct pipe_entry {
>  	u32	id;
>  	u32	pipe_id;
>  	u32	flags;
>  	fown_t	fown;
> +	u16	type;
> +	u16	len;

namelen

> +	u8	name[0];
>  } __packed;

> -static int dump_one_pipe(int lfd, u32 id, const struct fd_parms *p)
> +static int dump_one_typed_pipe(int type, int lfd, u32 id, const struct fd_parms *p)
>  {
>  	struct pipe_entry pe;
> +	char *path;
>  
> -	pr_info("Dumping pipe %d with id %#x pipe_id %#x\n", lfd, id, p->id);
> +	if (type >= PIPE_TYPE_MAX) {
> +		pr_err("Unknown pipe type %d on %d\n", type, p->fd);
> +		return -1;
> +	}

This check is not required.

> +
> +	pr_info("Dumping %s %d with id %#x pipe_id %#x\n",
> +		pipetype2s(type), lfd, id, p->id);
>  
>  	pe.id		= id;
>  	pe.pipe_id	= p->id;
>  	pe.flags	= p->flags;
>  	pe.fown		= p->fown;
> +	pe.type		= type;
>  
> -	if (write_img(fdset_fd(glob_fdset, CR_FD_PIPES), &pe))
> -		return -1;
> +	switch (type) {
> +	case PIPE_TYPE_ANON:
> +		pe.len = 0;
> +		if (write_img(fdset_fd(glob_fdset, CR_FD_PIPES), &pe))
> +			return -1;
> +		break;
> +	case PIPE_TYPE_FIFO:
> +		path = read_proc_selffd_link(lfd, (int *)&pe.len);
> +		if (!path)
> +			return -1;
> +		if (write_img(fdset_fd(glob_fdset, CR_FD_PIPES), &pe))
> +			return -1;
> +		if (write_img_buf(fdset_fd(glob_fdset, CR_FD_PIPES), path, pe.len))
> +			return -1;

This is wrong. When dumping a file with a path there's _much_ more should be
done rather than reading its path from the proc fd link. Reuse code from
dump_one_reg_file (I'd prefer if you just fix this function and call it).

> +		break;
> +	default:
> +		BUG_ON(1);
> +	}
>  
>  	return dump_one_pipe_data(lfd, id, p);
>  }

> @@ -273,18 +354,38 @@ int collect_pipes(void)
>  		if (pi == NULL)
>  			break;
>  
> +		pi->path = NULL;
> +
>  		ret = read_img_eof(fd, &pi->pe);
>  		if (ret <= 0)
>  			break;
>  
> -		pr_info("Collected pipe entry ID %#x PIPE ID %#x\n",
> -					pi->pe.id, pi->pe.pipe_id);
> +		if (pi->pe.len) {
> +			pi->path = xmalloc(pi->pe.len + 1);
> +			ret = read_img_buf_eof(fd, pi->path, pi->pe.len);
> +			if (ret <= 0) {
> +				ret = -1;
> +				pr_err("Corrupted path in %s %#x\n",
> +				       pipetype2s(pi->pe.type), pi->pe.id);
> +				break;
> +			}
> +			pi->path[pi->pe.len] = '\0';
> +		}
> +
> +		pr_info("Collected %s entry ID %#x PIPE ID %#x\n",
> +			pipetype2s(pi->pe.type), pi->pe.id, pi->pe.pipe_id);
>  
>  		file_desc_add(&pi->d, pi->pe.id, &pipe_desc_ops);
>  
>  		list_for_each_entry(tmp, &pipes, list) {
> -			if (pi->pe.pipe_id == tmp->pe.pipe_id)
> -				break;
> +			/*
> +			 * Only anon pipes are created in one place
> +			 * and sent via SCM, the fifo should be
> +			 * created explicitly.
> +			 */
> +			if (pi->pe.pipe_id == tmp->pe.pipe_id &&
> +			    pi->pe.type == PIPE_TYPE_ANON)

Huh? This will result in a waste of cpu cycles for PIPE_TYPE_FIFO.

> +					break;
>  		}
>  
>  		if (&tmp->list == &pipes)

> +static int open_fifo_fd(struct pipe_info *info, char *path)
> +{
> +	int new_fifo, fake_fifo = -1, where;
> +
> +	/*
> +	 * The fifos (except read-write fifos) do wait until
> +	 * another pipe-end get connected, so to be able to
> +	 * proceed the restoration procedure we open a fake
> +	 * fifo here.
> +	 */
> +	fake_fifo = open(path, O_RDWR);
> +	if (fake_fifo < 0) {
> +		pr_perror("Can't open fake reader on fifo %#08x [%s]",
> +			  info->pe.id, path);
> +		return -1;
> +	}
> +	pr_info("Fake fifo %d created\n", fake_fifo);
> +
> +	new_fifo = open(path, info->pe.flags);
> +	if (new_fifo < 0) {
> +		pr_perror("Can't open fifo %#08x [%s]",
> +			  info->pe.id, path);
> +		goto err_close_fake;
> +	}
> +
> +	/*
> +	 * If this is ro fifo then we need to restore data
> +	 * via fake fifo end.
> +	 */
> +	where = (info->pe.flags & O_ACCMODE) == O_RDONLY ? fake_fifo : new_fifo;

Why not where = fake_fifo always?

> +
> +	if (restore_pipe_data(where, info))

Thus you will push the same fifo data into each fifo's end. Why is this correct?

> +		goto err_close_new;
> +
> +	if (restore_fown(new_fifo, &info->pe.fown) < 0) {
> +		pr_perror("Can't restore owner on fifo %#08x",
> +			  info->pe.id);
> +		goto err_close_new;
> +	}
> +
> +err_close_fake:
> +	close_safe(&fake_fifo);
> +	return new_fifo;
> +
> +err_close_new:
> +	close_safe(&new_fifo);
> +	goto err_close_fake;
> +}
> +



More information about the CRIU mailing list