diff options
Diffstat (limited to 'fs/overlayfs/util.c')
| -rw-r--r-- | fs/overlayfs/util.c | 91 | 
1 files changed, 78 insertions, 13 deletions
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index 6e610a205e15..809048913889 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -40,6 +40,13 @@ const struct cred *ovl_override_creds(struct super_block *sb)  	return override_creds(ofs->creator_cred);  } +struct super_block *ovl_same_sb(struct super_block *sb) +{ +	struct ovl_fs *ofs = sb->s_fs_info; + +	return ofs->same_sb; +} +  struct ovl_entry *ovl_alloc_entry(unsigned int numlower)  {  	size_t size = offsetof(struct ovl_entry, lowerstack[numlower]); @@ -75,11 +82,13 @@ enum ovl_path_type ovl_path_type(struct dentry *dentry)  		type = __OVL_PATH_UPPER;  		/* -		 * Non-dir dentry can hold lower dentry from previous -		 * location. +		 * Non-dir dentry can hold lower dentry of its copy up origin.  		 */ -		if (oe->numlower && d_is_dir(dentry)) -			type |= __OVL_PATH_MERGE; +		if (oe->numlower) { +			type |= __OVL_PATH_ORIGIN; +			if (d_is_dir(dentry)) +				type |= __OVL_PATH_MERGE; +		}  	} else {  		if (oe->numlower > 1)  			type |= __OVL_PATH_MERGE; @@ -100,7 +109,7 @@ void ovl_path_lower(struct dentry *dentry, struct path *path)  {  	struct ovl_entry *oe = dentry->d_fsdata; -	*path = oe->numlower ? oe->lowerstack[0] : (struct path) { NULL, NULL }; +	*path = oe->numlower ? oe->lowerstack[0] : (struct path) { };  }  enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path) @@ -166,6 +175,13 @@ bool ovl_dentry_is_opaque(struct dentry *dentry)  	return oe->opaque;  } +bool ovl_dentry_is_impure(struct dentry *dentry) +{ +	struct ovl_entry *oe = dentry->d_fsdata; + +	return oe->impure; +} +  bool ovl_dentry_is_whiteout(struct dentry *dentry)  {  	return !dentry->d_inode && ovl_dentry_is_opaque(dentry); @@ -182,14 +198,7 @@ bool ovl_redirect_dir(struct super_block *sb)  {  	struct ovl_fs *ofs = sb->s_fs_info; -	return ofs->config.redirect_dir; -} - -void ovl_clear_redirect_dir(struct super_block *sb) -{ -	struct ovl_fs *ofs = sb->s_fs_info; - -	ofs->config.redirect_dir = false; +	return ofs->config.redirect_dir && !ofs->noxattr;  }  const char *ovl_dentry_get_redirect(struct dentry *dentry) @@ -294,3 +303,59 @@ void ovl_copy_up_end(struct dentry *dentry)  	wake_up_locked(&ofs->copyup_wq);  	spin_unlock(&ofs->copyup_wq.lock);  } + +bool ovl_check_dir_xattr(struct dentry *dentry, const char *name) +{ +	int res; +	char val; + +	if (!d_is_dir(dentry)) +		return false; + +	res = vfs_getxattr(dentry, name, &val, 1); +	if (res == 1 && val == 'y') +		return true; + +	return false; +} + +int ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry, +		       const char *name, const void *value, size_t size, +		       int xerr) +{ +	int err; +	struct ovl_fs *ofs = dentry->d_sb->s_fs_info; + +	if (ofs->noxattr) +		return xerr; + +	err = ovl_do_setxattr(upperdentry, name, value, size, 0); + +	if (err == -EOPNOTSUPP) { +		pr_warn("overlayfs: cannot set %s xattr on upper\n", name); +		ofs->noxattr = true; +		return xerr; +	} + +	return err; +} + +int ovl_set_impure(struct dentry *dentry, struct dentry *upperdentry) +{ +	int err; +	struct ovl_entry *oe = dentry->d_fsdata; + +	if (oe->impure) +		return 0; + +	/* +	 * Do not fail when upper doesn't support xattrs. +	 * Upper inodes won't have origin nor redirect xattr anyway. +	 */ +	err = ovl_check_setxattr(dentry, upperdentry, OVL_XATTR_IMPURE, +				 "y", 1, 0); +	if (!err) +		oe->impure = true; + +	return err; +}  |