[CRIU] [PATCH 1/2] mount: Use path resolving to find mount points

Pavel Emelyanov xemul at parallels.com
Fri Dec 6 02:39:37 PST 2013


On 12/06/2013 12:09 AM, Cyrill Gorcunov wrote:
> Instead of btrfs engine lets use path resolving feature.
> Once we find that there is some device which dev_t doesn't
> match one obtained from stat call we resolve path to a
> mountpoint and if mountpoint is laying on btrfs we use
> mount's dev_t for matching (because subvolumes may be
> not always reachable from chroot'ed environment).
> 
> We use slow lookup here but it will be improved once
> all things settle down.
> 
> Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
> ---
> 
> Pavel, what do you think, what is the preferred way would be
> to speedup the things? Note this patch actually makes btrfs engine
> obsolete ;)
> 
>  files-reg.c     |  2 +-
>  include/mount.h |  2 +-
>  mount.c         | 49 ++++++++++++++++++++++++++++++++++++++++++-------
>  sk-unix.c       |  2 +-
>  4 files changed, 45 insertions(+), 10 deletions(-)
> 
> diff --git a/files-reg.c b/files-reg.c
> index 728979d266d7..715000d06d49 100644
> --- a/files-reg.c
> +++ b/files-reg.c
> @@ -270,7 +270,7 @@ struct file_remap *lookup_ghost_remap(u32 dev, u32 ino)
>  
>  	mutex_lock(ghost_file_mutex);
>  	list_for_each_entry(gf, &ghost_files, list) {
> -		if (phys_stat_dev_match(gf->dev, dev) && gf->ino == ino) {
> +		if (gf->ino == ino && phys_stat_dev_match(gf->dev, dev, gf->remap.path)) {

The gf->dev value came from the image. It's the device we _saw_ at dump time.
Thus we should do the name resolution _then_ and write in the image the phys
device ID instead of volume id.

>  			gf->remap.users++;
>  			mutex_unlock(ghost_file_mutex);
>  			return &gf->remap;
> diff --git a/include/mount.h b/include/mount.h
> index 3e4508715c79..b64673c3801d 100644
> --- a/include/mount.h
> +++ b/include/mount.h
> @@ -22,6 +22,6 @@ extern struct mount_info *lookup_mnt_sdev(unsigned int s_dev);
>  
>  extern struct ns_desc mnt_ns_desc;
>  
> -extern bool phys_stat_dev_match(dev_t st_dev, dev_t phys_dev);
> +extern bool phys_stat_dev_match(dev_t st_dev, dev_t phys_dev, const char *path);
>  
>  #endif /* __CR_MOUNT_H__ */
> diff --git a/mount.c b/mount.c
> index 3c85cb036619..23d62da527e3 100644
> --- a/mount.c
> +++ b/mount.c
> @@ -98,17 +98,52 @@ struct mount_info *lookup_mnt_sdev(unsigned int s_dev)
>  	return NULL;
>  }
>  
> -bool phys_stat_dev_match(dev_t st_dev, dev_t phys_dev)
> +static struct mount_info *mount_resolve_path(const char *path)
>  {
> -	if (st_dev == phys_dev)
> -		return true;
> +	struct mount_info *m, *best = NULL, *root = NULL;
> +	size_t pathlen = strlen(path);
> +	size_t bestlen = PATH_MAX;
>  
>  	/*
> -	 * BTRFS returns subvolume dev-id instead of
> -	 * superblock dev-id so we might need additional
> -	 * tests here.
> +	 * Find suitable mount point for a @path.
> +	 *
> +	 * FIXME We need some fast path resolving algorithm here.
> +	 * For a while stick with stupid matches.
>  	 */
> -	return is_btrfs_subvol(phys_dev, st_dev);
> +	for (m = mntinfo; m; m = m->next) {
> +		size_t n = strlen(m->mountpoint);
> +
> +		if (!strncmp(m->mountpoint, path, min(n, pathlen))) {
> +			if (bestlen > n && !is_root_mount(m)) {
> +				best = m;
> +				bestlen = n;
> +			}
> +			if (is_root_mount(m))
> +				root = m;
> +		}
> +	}

I don't think this resolve fn is correct. You should do careful tree
descending looking at paths. Something like below.

	mi = root;
	sub_path = path;
next_component:
	/* iterate over children mounts and find the beth path match */
	list_for_each_entry(ch, &mi->children, siblings) {
		len = strlen(ch->mountpoint);
		if (strnel(sub_path) < len)
			/* the ch point's mountpoint cannot match the subpath */
			continue;
		if (!strncmp(sub_path, ch->mountpoint, len) {
			/* descend and search for the next mount point */
			sub_path += len;
			mi = ch;
			goto next_component;
		}
	} /* no children match the path -- the current path points to mi */

	return mi;

> +
> +	if (!best) {
> +		BUG_ON(!root);
> +		best = root;
> +	}
> +
> +	pr_debug("Path `%s' resolved to `%s' mountpoint\n", path, best->mountpoint);
> +	return best;
> +}
> +
> +bool phys_stat_dev_match(dev_t st_dev, dev_t phys_dev, const char *path)
> +{
> +	struct mount_info *m;
> +
> +	if (st_dev == phys_dev)
> +		return true;
> +
> +	m = mount_resolve_path(path);
> +
> +	if (!strcmp(m->fstype->name, "btrfs"))
> +		return m->s_dev == phys_dev;
> +	return false;
>  }
>  
>  /*
> diff --git a/sk-unix.c b/sk-unix.c
> index df07999d9aa9..21d2de746454 100644
> --- a/sk-unix.c
> +++ b/sk-unix.c
> @@ -355,7 +355,7 @@ static int unix_collect_one(const struct unix_diag_msg *m,
>  			}
>  
>  			if ((st.st_ino != uv->udiag_vfs_ino) ||
> -			    !phys_stat_dev_match(st.st_dev, kdev_to_odev(uv->udiag_vfs_dev))) {
> +			    !phys_stat_dev_match(st.st_dev, kdev_to_odev(uv->udiag_vfs_dev), name)) {
>  				pr_info("unix: Dropping path %s for "
>  						"unlinked bound "
>  						"sk %#x.%#x real %#x.%#x\n",
> 




More information about the CRIU mailing list