[CRIU] [PATCH 5/9] mounts: if a mount can't be mounted, it is queued in postpone list (v2)

Pavel Emelyanov xemul at parallels.com
Thu Jul 25 07:07:12 EDT 2013


On 07/24/2013 12:10 PM, Andrey Vagin wrote:
> Try to restore mounts while a postpone list isn't empty and check
> that each iteration has some progress, otherwice it will fails for
> preventing infinite loops
> 
> v2: rework logic about postpone list
>     add more comments
> 
> Signed-off-by: Andrey Vagin <avagin at openvz.org>
> ---
>  include/proc_parse.h |  2 ++
>  mount.c              | 62 ++++++++++++++++++++++++++++++++++++++++++++++++----
>  2 files changed, 60 insertions(+), 4 deletions(-)
> 
> diff --git a/include/proc_parse.h b/include/proc_parse.h
> index 99255c4..1a2a579 100644
> --- a/include/proc_parse.h
> +++ b/include/proc_parse.h
> @@ -121,6 +121,8 @@ struct mount_info {
>  	struct list_head mnt_slave_list;/* list of slave mounts */
>  	struct list_head mnt_slave;	/* slave list entry */
>  	struct mount_info *mnt_master;	/* slave is on master->mnt_slave_list */
> +
> +	struct list_head postpone;
>  };
>  
>  struct proc_posix_timer {
> diff --git a/mount.c b/mount.c
> index 11358af..39d909e 100644
> --- a/mount.c
> +++ b/mount.c
> @@ -510,12 +510,32 @@ int dump_mnt_ns(int ns_pid, struct cr_fdset *fdset)
>  	return 0;
>  }
>  
> -#define MNT_TREE_WALK(_r, _el, _fn_f, _fn_r) do {				\
> +static int mount_progress;
> +
> +/*
> + * _fn_f  - pre-order traversal function
> + * _fn_f  - post-order traversal function
> + * _plist - a postpone list. _el is added to this list, if _fn_f returns
> + *	    a positive value, and all lower elements are not enumirated.
> + */
> +#define MNT_TREE_WALK(_r, _el, _fn_f, _fn_r, _plist) do {			\
>  		struct mount_info *_mi = _r;					\
>  										\
>  		while (1) {							\
> -			if (_fn_f(_mi))						\
> +			int ret;						\
> +										\
> +			list_del_init(&_mi->postpone);				\
> +										\
> +			ret = _fn_f(_mi);					\
> +			if (ret < 0)						\
>  				return -1;					\
> +			else if (ret > 0) {					\
> +				list_add_tail(&_mi->postpone, _plist);		\
> +				goto up;					\
> +			}							\
> +										\
> +			mount_progress++;					\
> +										\
>  			if (!list_empty(&_mi->children)) {			\
>  				_mi = list_entry(_mi->children._el,		\
>  						struct mount_info, siblings);	\
> @@ -541,7 +561,40 @@ int dump_mnt_ns(int ns_pid, struct cr_fdset *fdset)
>  static int mnt_tree_for_each(struct mount_info *m,
>  		int (*fn)(struct mount_info *))
>  {
> -	MNT_TREE_WALK(m, next, fn, MNT_WALK_NONE);
> +	static LIST_HEAD(postpone);
> +	struct mount_info *pm = NULL;
> +	int old;
> +
> +again:
> +	old = mount_progress;
> +
> +	MNT_TREE_WALK(m, next, fn, MNT_WALK_NONE, &postpone);
> +
> +	/*
> +	 * pm contains the first elemnt, which processed without progress,
> +	 * so if all intermediate steps are handled w/o progress, here is
> +	 * a infinite loop.
> +	 */
> +	if (old == mount_progress) {
> +		if (pm == m) {
> +			pr_err("A few mount points can't be mounted");
> +			list_for_each_entry(m, &postpone, postpone) {
> +				pr_err("%d:%d %s %s %s\n", m->mnt_id,
> +					m->parent_mnt_id, m->root,
> +					m->mountpoint, m->source);
> +			}
> +			return -1;
> +		}
> +		if (pm == NULL)
> +			pm = m;

The thing above is effectively loop-detection. It's unclean from the
code, plz, rework.

> +	} else
> +		pm = NULL;
> +
> +	if (!list_empty(&postpone)) {
> +		m = list_first_entry(&postpone, struct mount_info, postpone);
> +		pr_debug("Start with %d:%s\n", m->mnt_id, m->mountpoint);
> +		goto again;
> +	}
>  
>  	return 0;
>  }
> @@ -549,7 +602,7 @@ static int mnt_tree_for_each(struct mount_info *m,
>  static int mnt_tree_for_each_reverse(struct mount_info *m,
>  		int (*fn)(struct mount_info *))
>  {
> -	MNT_TREE_WALK(m, prev, MNT_WALK_NONE, fn);
> +	MNT_TREE_WALK(m, prev, MNT_WALK_NONE, fn, (struct list_head *) NULL);
>  
>  	return 0;
>  }
> @@ -710,6 +763,7 @@ struct mount_info *mnt_entry_alloc()
>  		INIT_LIST_HEAD(&new->siblings);
>  		INIT_LIST_HEAD(&new->mnt_slave_list);
>  		INIT_LIST_HEAD(&new->mnt_share);
> +		INIT_LIST_HEAD(&new->postpone);
>  		new->mnt_master = NULL;
>  	}
>  	return new;
> 




More information about the CRIU mailing list