[CRIU] [PATCH 2/3] mount: allow to dump content even if a part of fs is overmounted

Pavel Emelyanov xemul at parallels.com
Wed Jul 31 05:41:51 EDT 2013


On 07/29/2013 06:34 PM, Andrey Vagin wrote:
> for that the mount point is bind-mounted in a temporary place.
> 
> Signed-off-by: Andrey Vagin <avagin at openvz.org>
> ---
>  mount.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 96 insertions(+), 6 deletions(-)
> 
> diff --git a/mount.c b/mount.c
> index 68965bb..58ecf21 100644
> --- a/mount.c
> +++ b/mount.c
> @@ -197,18 +197,13 @@ static struct mount_info *mnt_build_tree(struct mount_info *list)
>  	return tree;
>  }
>  
> -static DIR *open_mountpoint(struct mount_info *pm)
> +static DIR *__open_mountpoint(struct mount_info *pm)
>  {
>  	int fd, ret;
>  	char path[PATH_MAX + 1];
>  	struct stat st;
>  	DIR *fdir;
>  
> -	if (!list_empty(&pm->children)) {
> -		pr_err("Something is mounted on top of %s\n", pm->fstype->name);
> -		return NULL;
> -	}
> -
>  	snprintf(path, sizeof(path), ".%s", pm->mountpoint);
>  	fd = openat(mntns_root, path, O_RDONLY);
>  	if (fd < 0) {
> @@ -249,6 +244,101 @@ static int close_mountpoint(DIR *dfd)
>  	return 0;
>  }
>  
> +static DIR *open_mountpoint(struct mount_info *pm)
> +{
> +	int fd = -1, ns_old = -1;
> +	DIR *fdir = NULL;
> +	char buf[PATH_MAX];
> +	char mnt_path[] = "/tmp/cr-tmpfs.XXXXXX";
> +
> +	/*
> +	 * If a mount doesn't have children, we can open a mount point,
> +	 * otherwise we need to create a "private" copy.
> +	 */
> +	if (list_empty(&pm->children))
> +		return __open_mountpoint(pm);
> +
> +	pr_info("Something is mounted on top of %s\n", pm->mountpoint);
> +
> +	/*
> +	 * To create a "private" copy, the target mount is bind-mounted
> +	 * in a temporary place w/o MS_REC (non-recursively).
> +	 * A mount point can't be bind-mounted in criu's namespace, it will be
> +	 * mounted in a target namespace. The sequence of actions is
> +	 * mkdtemp, setns(tgt), mount, open, detach, setns(old).
> +	 */
> +
> +	ns_old = open("/proc/self/ns/mnt", O_RDONLY);
> +	if (ns_old == -1) {
> +		pr_perror("Can't open own mount namespace");
> +		goto out;
> +	}
> +
> +	snprintf(buf, sizeof(buf), "/proc/%d/ns/mnt", root_item->pid.real);
> +	fd = open(buf, O_RDONLY);
> +	if (fd == -1) {
> +		pr_perror("Can't open the target mount namespace");
> +		goto out;
> +	}
> +
> +	if (setns(fd, CLONE_NEWNS) == -1) {
> +		pr_perror("Can't enter into the target mount namespace");
> +		goto out;
> +	}

We have switch_ns/restore_ns helpers for that.

> +	close_safe(&fd);
> +
> +	if (mkdtemp(mnt_path) == NULL) {
> +		pr_perror("Can't create a temporary directory");
> +		goto out;
> +	}
> +
> +	snprintf(buf, sizeof(buf), "/proc/self/root/%s", pm->mountpoint);
> +	if (mount(buf, mnt_path, NULL, MS_BIND, NULL)) {
> +		pr_perror("Can't bind-mount %d:%s to %s",
> +				pm->mnt_id, pm->mountpoint, mnt_path);
> +		rmdir(mnt_path);
> +		goto out;
> +	}
> +
> +	fd = open(mnt_path, O_RDONLY | O_DIRECTORY);
> +	if (fd < 0)
> +		pr_perror("Can't open %s\n", mnt_path);
> +
> +	if (umount2(mnt_path, MNT_DETACH)) {
> +		pr_perror("Can't umount %s", mnt_path);
> +		goto out;
> +	}
> +
> +	if (rmdir(mnt_path)) {
> +		pr_perror("Can't remove the directory %s", mnt_path);
> +		goto out;
> +	}
> +
> +	if (fd < 0)
> +		goto out;
> +
> +	if (setns(ns_old, CLONE_NEWNS)) {
> +		pr_perror("Can't return into the origin mount namespace");
> +		goto out;
> +	}
> +	close_safe(&ns_old);
> +
> +	fdir = fdopendir(fd);

You need to check, that the fs you get access to at the end is _really_ the
one you wanted to.

> +	if (fdir == NULL) {
> +		close(fd);
> +		pr_perror("Can't open %s", pm->mountpoint);
> +		return NULL;
> +	}
> +
> +	return fdir;
> +out:
> +	if (ns_old >= 0 && setns(ns_old, CLONE_NEWNS) == -1)
> +		pr_perror("Can't return into the origin mount namespace");
> +	close_safe(&ns_old);
> +	close_safe(&fd);
> +	return NULL;
> +}
> +
>  static int tmpfs_dump(struct mount_info *pm)
>  {
>  	int ret = -1;
> 




More information about the CRIU mailing list