[CRIU] AUFS Support in CRIU

Pavel Emelyanov xemul at parallels.com
Wed Aug 13 01:13:58 PDT 2014


On 08/13/2014 04:29 AM, Saied Kazemi wrote:

Hi, Saied.

> Here is a new patch.  I rebased to the head (commit ded04267f8) and cleaned up the code a
> bit more.  Please use the attached patch instead of the one I sent yesterday.
> 
> Note that I had to delete 3 lines from cgroup.c for properties that I don't have on my
> Ubuntu 14.04.  Also, please note that you have to add --manage-cgroups to criu command
> line for both dump and restore.

Thank you for looking into this. I'm not familiar with AUFS at all, thus I
only have comments about the way AUFS parsing/fixing code is integrated into
the rest of the criu code.

Please, see my comments inline.

> @@ -197,6 +199,19 @@ int fill_fdlink(int lfd, const struct fd_parms *p, struct fd_link *link)
>  		return -1;
>  	}
>  
> +	/*
> +	 * For AUFS support, we need to replace absolute
> +	 * branch pathnames with relative pathnames from root.
> +	 */
> +	if (opts.aufs) {

At this point we have the statfs() information. Can we rely on the
fs_type being aufs magic to check that the file is aufs one?

> +		int n = sizeof link->name - 1;
> +		n = fixup_aufs_path(&link->name[1], n, true);
> +		if (n < 0)
> +			return -1;
> +		if (n > 0)
> +			len = n;
> +	}
> +
>  	link->len = len + 1;
>  	return 0;

> @@ -450,12 +453,24 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, bool use_map_file
>  			vma_area->st = prev->st;
>  		} else if (vma_area->vm_file_fd >= 0) {
>  			struct stat *st_buf;
> +			char *f;
>  
>  			st_buf = vma_area->st = xmalloc(sizeof(*st_buf));
>  			if (!st_buf)
>  				goto err;
>  
> -			if (fstat(vma_area->vm_file_fd, st_buf) < 0) {
> +			/*
> +			 * For AUFS support, we cannot fstat() file a descriptor that
> +			 * is a symbolic link to a branch.  Instead, we obtain the
> +			 * pathname of the file from the root and use stat().
> +			 */
> +			if (opts.aufs && (f = fixup_aufs_fd_path(vma_area->vm_file_fd))) {

Would this work if the vm_file_fd sits in another mount namespace? Or
the path reported by fixup_aufs_fd_path() is always in the criu's one?

And another question -- do we need the fixed stat buffer that early?
The vma fd is dumped in dump_filemap() and in that place we call
get_fd_mntid() for missing mount ID. Can we fixup the device there too?

> +				if (stat(f, st_buf) < 0) {
> +					pr_perror("Failed fstat on %d's map %lu (%s)",
> +						pid, start, f);
> +					goto err;
> +				}
> +			} else if (fstat(vma_area->vm_file_fd, st_buf) < 0) {
>  				pr_perror("Failed fstat on %d's map %lu", pid, start);
>  				goto err;
>  			}

> @@ -921,6 +942,16 @@ static int parse_mountinfo_ent(char *str, struct mount_info *new)
>  	if (ret != 3)
>  		return -1;
>  
> +	/* see comments in sysfs_parse.c */
> +	if (opts.aufs && !strcmp(new->mountpoint, "./")) {
> +		if (strcmp(fstype, "aufs")) {

Can we reuse the fstype->parse() callback for this? This one gets called
in parse_mountinfo() in a loop after parse_mountinfo_ent().

> +			pr_err("Expected fstype aufs got %s\n", fstype);
> +			return -1;
> +		}
> +		if (fixup_src_opt(&new->source, &opt) < 0)
> +			return -1;
> +	}
> +
>  	ret = -1;
>  	new->fstype = find_fstype_by_name(fstype);
>  

> +/*
> + * Copy the line in process's mountinfo file that corresponds
> + * to the mountpoint specified by the mntpoint argument.  Return
> + * the number of characters parsed in the line, or -1 on error.
> + */
> +int get_mountinfo_by_mountpoint(pid_t pid, char *mntpoint, char *line, int linelen)

I do not fully understand why this mountpoint->something-else parser
is required. Can we put all the code parsing aufs-specific stuff into
the fstype->parse() callback I mentioned above? When criu starts
parsing mount namespaces (it does this before doing anything else)
this info will be parsed and stored into mount_info->private. Later, 
when we need to e.g. fixup file paths we can get file->mnt_id, get 
mount_info by it, then check the fs being aufs and fix the path 
according to the mount_info->private data we have. Would this work?

> +{
> +	char buf[PATH_MAX];
> +	int n, ret;
> +	FILE *f;

> +
> +	snprintf(buf, sizeof buf, "/proc/%d/mountinfo", pid);
> +	f = fopen(buf, "r");
> +	if (!f) {
> +		pr_perror("Cannot fopen %s", buf);
> +		return -1;
> +	}
> +
> +	do {
> +		n = linelen - 2;
> +		line[n] = '\0';		/* detect long input */
> +		if (fgets(line, linelen, f) == NULL) {
> +			ret = 0;
> +			break;
> +		}
> +		if (line[n] && line[n] != '\n') {
> +			pr_err("Line in mountinfo too long\n");
> +			ret = -1;
> +			goto out;
> +		}
> +
> +		ret = sscanf(line, "%*i %*i %*u:%*u %*s %s %*s - %n", buf, &n);

Wow. Doesn't gcc prints a warning about "too few arguments for format"?

> +		if (ret != 1) {
> +			pr_err("Cannot parse mountpoint (%s)\n", line);
> +			ret = -1;
> +			goto out;
> +		}
> +	} while (strcmp(buf, mntpoint));
> +
> +	if (!ret) {
> +		pr_err("Did not find %s in mountinfo\n", mntpoint);
> +		ret = -1;
> +	} else
> +		ret = n;
> +
> +out:
> +	fclose(f);
> +	return ret;
> +}

Thanks,
Pavel



More information about the CRIU mailing list