[CRIU] [PATCH v4 3/6] files-reg: Create ghost files in first existing parent directory

Pavel Emelyanov xemul at virtuozzo.com
Wed Jan 27 06:06:48 PST 2016


On 01/25/2016 07:39 PM, Kirill Tkhai wrote:
> Since a deleted file may belong to a deleted directory
> (which, in turn, may belong to another deleted, etc),
> it's necessary to recreate all missing dentries in the path.
> 
> Doing this in mkreg_ghost() is not a good idea, because
> another ghost file may need some of the dentries in the path,
> and this requires to do refcouting of recreated directories.
> 
> To avoid this, we restore a ghost file in the first existing
> parent directory of the patch. This guarantees, the ghost file
> will be in the same mount with target file (rfi_remap() needs
> that, because it uses link()).
> ---
>  files-reg.c |   82 +++++++++++++++++++++++++++++++++++++++++++++++------------
>  1 file changed, 65 insertions(+), 17 deletions(-)
> 
> diff --git a/files-reg.c b/files-reg.c
> index 648c8d2..8dbae21 100644
> --- a/files-reg.c
> +++ b/files-reg.c
> @@ -95,6 +95,33 @@ static int note_link_remap(char *path, struct ns_id *nsid)
>  	return -1;
>  }
>  
> +/* Trim "a/b/c/d" to "a/b/d" */
> +static int trim_last_parent(char *path)
> +{
> +	char *fname, *p;
> +
> +	p = strrchr(path, '/');
> +	fname = p + 1;
> +	if (!p || *fname == '\0')
> +		return -1;
> +
> +	while (p >= path && *p == '/')
> +		p--;
> +
> +	if (p < path)
> +		return -1;
> +
> +	while (p >= path && *p != '/')
> +		p--;
> +	p++;
> +
> +	while (*fname != '\0')
> +		*p++ = *fname++;
> +	*p = '\0';
> +
> +	return 0;
> +}
> +
>  static int mkreg_ghost(char *path, u32 mode, struct ghost_file *gf, struct cr_img *img)
>  {
>  	int gfd, ret;
> @@ -111,46 +138,67 @@ static int mkreg_ghost(char *path, u32 mode, struct ghost_file *gf, struct cr_im
>  
>  static int create_ghost(struct ghost_file *gf, GhostFileEntry *gfe, struct cr_img *img)
>  {
> +	int ret, len, root_len, try = 0;
>  	char path[PATH_MAX];
>  	struct timeval tv[2];
> -	int ret;
> +	char *msg;
>  
> -	ret = rst_get_mnt_root(gf->remap.rmnt_id, path, sizeof(path));
> +	root_len = ret = rst_get_mnt_root(gf->remap.rmnt_id, path, sizeof(path));
>  	if (ret < 0) {
>  		pr_err("The %d mount is not found for ghost\n", gf->remap.rmnt_id);
>  		goto err;
>  	}
>  
> -	snprintf(path + ret, sizeof(path) - ret, "/%s", gf->remap.rpath);
> +	len = snprintf(path + ret, sizeof(path) - ret, "/%s", gf->remap.rpath) + ret;
>  	ret = -1;
> -
> +again:
>  	if (S_ISFIFO(gfe->mode)) {
> -		if (mknod(path, gfe->mode, 0)) {
> -			pr_perror("Can't create node for ghost file");
> -			goto err;
> -		}
> +		if ((ret = mknod(path, gfe->mode, 0)) < 0)
> +			msg = "Can't create node for ghost file";
>  	} else if (S_ISCHR(gfe->mode) || S_ISBLK(gfe->mode)) {
>  		if (!gfe->has_rdev) {
>  			pr_err("No rdev for ghost device\n");
>  			goto err;
>  		}
> -
> -		if (mknod(path, gfe->mode, gfe->rdev)) {
> -			pr_perror("Can't create node for ghost dev");
> -			goto err;
> -		}
> +		if ((ret = mknod(path, gfe->mode, gfe->rdev)) < 0)
> +			msg = "Can't create node for ghost dev";
>  	} else if (S_ISDIR(gfe->mode)) {
> -		if (mkdir(path, gfe->mode)) {
> +		if ((ret = mkdir(path, gfe->mode)) < 0) {
>  			pr_perror("Can't make ghost dir");
>  			goto err;
>  		}
>  	} else {
> -		if (mkreg_ghost(path, gfe->mode, gf, img)) {
> -			pr_perror("Can't create ghost regfile\n");
> +		if ((ret = mkreg_ghost(path, gfe->mode, gf, img)) < 0)
> +			msg = "Can't create ghost regfile\n";
> +	}
> +
> +	/* Use grand parent, if parent directory does not exist */
> +	if (ret < 0 && errno == ENOENT) {
> +		if (trim_last_parent(path) < 0) {
> +			pr_err("trim failed: @%s@\n", path);
>  			goto err;
> -               }
> +		}
> +		len = strlen(path);
> +		goto again;
>  	}
>  
> +	/* Use numeric suffix, if a namesake already exists */
> +	if (ret < 0) {
> +		if (errno != EEXIST) {
> +			pr_perror("%s", msg);
> +			goto err;
> +		}
> +		if (++try == INT_MAX) {
> +			pr_err("Can't find available file name\n");
> +			goto err;
> +		}
> +		sprintf(path + len, ".%x", try);
> +		goto again;
> +	}

Collect all if (ret < 0) code under one branch, please.

> +
> +	strcpy(gf->remap.rpath, path + root_len + 1);
> +	pr_debug("Remap rpath is %s\n", gf->remap.rpath);
> +
>  	if (chown(path, gfe->uid, gfe->gid) < 0) {
>  		pr_perror("Can't reset user/group on ghost %s", path);
>  		goto err;
> 
> .
> 



More information about the CRIU mailing list