Re: [PATCH] ovl: fix inconsistent d_ino for legacy merge dir

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 2017/12/31 17:49, Amir Goldstein Wrote:
> For a merge dir that was copied up before v4.12 or that was hand crafted
> offline (e.g. mkdir {upper/lower}/dir), upper dir does not contain the
> 'trusted.overlay.origin' xattr.  In that case, stat(2) on the merge dir
> returns the lower dir st_ino, but getdents(2) returns the upper dir d_ino.
> 
> After this change, on merge dir lookup, missing origin xattr on upper
> dir will be fixed and 'impure' xattr will be fixed on parent of the legacy
> merge dir.
> 
> Suggested-by: zhangyi (F) <yi.zhang@xxxxxxxxxx>
> Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>
> ---
> 
> Zhangyi,
> 
> Please review/test this patch.
> I ended up applying it at the bottom of verify_dir [1] series,
> so it could be merged to v4.15 and/or easily backported to v4.14
> (where consistent d_ino was merged) if Miklos thinks this is an important
> use case to fix.
> 

Hi Amir,
This patch looks good (one nit below) but still have a case which will lead to problem
we missed in last discussion:
Call getdent(2) before invoke ovl_lookup() after first mount.

eg:
1) mkdir {upper/lower}/dir merge work
2) mount to merge
3) getdent merge
2253114  directory    24          2  dir
4) ls merge
5) getdent merge
2253113  directory    24          2  dir

Strictly speaking, it is a problem ,but not sure it's worth to fix now.

Thanks,
zhangyi.

> Thanks,
> Amir.
> 
> [1] https://github.com/amir73il/linux/commits/ovl-verify-dir
> 
>  fs/overlayfs/namei.c     | 36 +++++++++++++++++++++++++++++++-----
>  fs/overlayfs/overlayfs.h |  2 +-
>  fs/overlayfs/super.c     |  5 +++--
>  3 files changed, 35 insertions(+), 8 deletions(-)
> 
> diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
> index 9cf15463754c..bd7375c05f7d 100644
> --- a/fs/overlayfs/namei.c
> +++ b/fs/overlayfs/namei.c
> @@ -343,13 +343,13 @@ static int ovl_verify_origin_fh(struct dentry *dentry, const struct ovl_fh *fh)
>  /*
>   * Verify that an inode matches the origin file handle stored in upper inode.
>   *
> - * If @set is true and there is no stored file handle, encode and store origin
> - * file handle in OVL_XATTR_ORIGIN.
> + * If @set is non-null and there is no stored file handle, set *@set to true
> + * and try to encode and store origin file handle in OVL_XATTR_ORIGIN.
>   *
> - * Return 0 on match, -ESTALE on mismatch, < 0 on error.
> + * Return 0 on match or successful set, -ESTALE on mismatch, < 0 on error.
>   */
>  int ovl_verify_origin(struct dentry *dentry, struct dentry *origin,
> -		      bool is_upper, bool set)
> +		      bool is_upper, bool *set)
>  {
>  	struct inode *inode;
>  	struct ovl_fh *fh;
> @@ -361,8 +361,13 @@ int ovl_verify_origin(struct dentry *dentry, struct dentry *origin,
>  		goto fail;
>  
>  	err = ovl_verify_origin_fh(dentry, fh);
> -	if (set && err == -ENODATA)
> +	if (set && err == -ENODATA) {
> +		*set = true;
>  		err = ovl_do_setxattr(dentry, OVL_XATTR_ORIGIN, fh, fh->len, 0);
> +		if (err)
> +			goto fail;

Remove this repeated error handle ?

> +	}
> +
>  	if (err)
>  		goto fail;
>  
> @@ -674,6 +679,27 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
>  		if (!this)
>  			continue;
>  
> +		/*
> +		 * If no origin fh is stored in upper of a merge dir, store fh
> +		 * of upper most lower dir and set upper parent "impure".
> +		 */
> +		if (upperdentry && !ctr) {
> +			bool set = false;
> +
> +			err = ovl_verify_origin(upperdentry, this, false, &set);
> +			if (set && !err) {
> +				err = ovl_set_impure(dentry->d_parent,
> +						     upperdentry->d_parent);
> +			}
> +			if (set && err)
> +				goto out_put;
> +
> +			/*
> +			 * Ignore merge dir origin mismatch, which may have
> +			 * been caused by copying layers
> +			 */
> +		}
> +
>  		stack[ctr].dentry = this;
>  		stack[ctr].layer = lower.layer;
>  		ctr++;
> diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
> index b489099ccd49..6620db670afa 100644
> --- a/fs/overlayfs/overlayfs.h
> +++ b/fs/overlayfs/overlayfs.h
> @@ -250,7 +250,7 @@ static inline bool ovl_is_impuredir(struct dentry *dentry)
>  
>  /* namei.c */
>  int ovl_verify_origin(struct dentry *dentry, struct dentry *origin,
> -		      bool is_upper, bool set);
> +		      bool is_upper, bool *set);
>  int ovl_verify_index(struct dentry *index, struct ovl_path *lower,
>  		     unsigned int numlower);
>  int ovl_get_index_name(struct dentry *origin, struct qstr *name);
> diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
> index 76440feb79f6..f548717e3388 100644
> --- a/fs/overlayfs/super.c
> +++ b/fs/overlayfs/super.c
> @@ -1026,11 +1026,12 @@ static int ovl_get_workdir(struct ovl_fs *ofs, struct path *upperpath)
>  static int ovl_get_indexdir(struct ovl_fs *ofs, struct ovl_entry *oe,
>  			    struct path *upperpath)
>  {
> +	bool set;
>  	int err;
>  
>  	/* Verify lower root is upper root origin */
>  	err = ovl_verify_origin(upperpath->dentry, oe->lowerstack[0].dentry,
> -				false, true);
> +				false, &set);
>  	if (err) {
>  		pr_err("overlayfs: failed to verify upper root origin\n");
>  		goto out;
> @@ -1040,7 +1041,7 @@ static int ovl_get_indexdir(struct ovl_fs *ofs, struct ovl_entry *oe,
>  	if (ofs->indexdir) {
>  		/* Verify upper root is index dir origin */
>  		err = ovl_verify_origin(ofs->indexdir, upperpath->dentry,
> -					true, true);
> +					true, &set);
>  		if (err)
>  			pr_err("overlayfs: failed to verify index dir origin\n");
>  
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-unionfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Filesystems Devel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux