diff options
Diffstat (limited to 'fs/overlayfs')
| -rw-r--r-- | fs/overlayfs/copy_up.c | 2 | ||||
| -rw-r--r-- | fs/overlayfs/export.c | 2 | ||||
| -rw-r--r-- | fs/overlayfs/file.c | 10 | ||||
| -rw-r--r-- | fs/overlayfs/namei.c | 15 | ||||
| -rw-r--r-- | fs/overlayfs/overlayfs.h | 1 | ||||
| -rw-r--r-- | fs/overlayfs/super.c | 73 | 
6 files changed, 63 insertions, 40 deletions
| diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 79dd052c7dbf..5e0cde85bd6b 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -895,7 +895,7 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,  	return err;  } -int ovl_copy_up_flags(struct dentry *dentry, int flags) +static int ovl_copy_up_flags(struct dentry *dentry, int flags)  {  	int err = 0;  	const struct cred *old_cred = ovl_override_creds(dentry->d_sb); diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c index 8f4286450f92..0e696f72cf65 100644 --- a/fs/overlayfs/export.c +++ b/fs/overlayfs/export.c @@ -476,7 +476,7 @@ static struct dentry *ovl_lookup_real_inode(struct super_block *sb,  	if (IS_ERR_OR_NULL(this))  		return this; -	if (WARN_ON(ovl_dentry_real_at(this, layer->idx) != real)) { +	if (ovl_dentry_real_at(this, layer->idx) != real) {  		dput(this);  		this = ERR_PTR(-EIO);  	} diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index 01820e654a21..0d940e29d62b 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c @@ -33,13 +33,16 @@ static char ovl_whatisit(struct inode *inode, struct inode *realinode)  		return 'm';  } +/* No atime modificaton nor notify on underlying */ +#define OVL_OPEN_FLAGS (O_NOATIME | FMODE_NONOTIFY) +  static struct file *ovl_open_realfile(const struct file *file,  				      struct inode *realinode)  {  	struct inode *inode = file_inode(file);  	struct file *realfile;  	const struct cred *old_cred; -	int flags = file->f_flags | O_NOATIME | FMODE_NONOTIFY; +	int flags = file->f_flags | OVL_OPEN_FLAGS;  	int acc_mode = ACC_MODE(flags);  	int err; @@ -72,8 +75,7 @@ static int ovl_change_flags(struct file *file, unsigned int flags)  	struct inode *inode = file_inode(file);  	int err; -	/* No atime modificaton on underlying */ -	flags |= O_NOATIME | FMODE_NONOTIFY; +	flags |= OVL_OPEN_FLAGS;  	/* If some flag changed that cannot be changed then something's amiss */  	if (WARN_ON((file->f_flags ^ flags) & ~OVL_SETFL_MASK)) @@ -126,7 +128,7 @@ static int ovl_real_fdget_meta(const struct file *file, struct fd *real,  	}  	/* Did the flags change since open? */ -	if (unlikely((file->f_flags ^ real->file->f_flags) & ~O_NOATIME)) +	if (unlikely((file->f_flags ^ real->file->f_flags) & ~OVL_OPEN_FLAGS))  		return ovl_change_flags(real->file, file->f_flags);  	return 0; diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index 3566282a9199..f7d4358db637 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -389,7 +389,7 @@ invalid:  }  static int ovl_check_origin(struct ovl_fs *ofs, struct dentry *upperdentry, -			    struct ovl_path **stackp, unsigned int *ctrp) +			    struct ovl_path **stackp)  {  	struct ovl_fh *fh = ovl_get_fh(upperdentry, OVL_XATTR_ORIGIN);  	int err; @@ -406,10 +406,6 @@ static int ovl_check_origin(struct ovl_fs *ofs, struct dentry *upperdentry,  		return err;  	} -	if (WARN_ON(*ctrp)) -		return -EIO; - -	*ctrp = 1;  	return 0;  } @@ -861,8 +857,6 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,  			goto out;  		}  		if (upperdentry && !d.is_dir) { -			unsigned int origin_ctr = 0; -  			/*  			 * Lookup copy up origin by decoding origin file handle.  			 * We may get a disconnected dentry, which is fine, @@ -873,8 +867,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,  			 * number - it's the same as if we held a reference  			 * to a dentry in lower layer that was moved under us.  			 */ -			err = ovl_check_origin(ofs, upperdentry, &origin_path, -					       &origin_ctr); +			err = ovl_check_origin(ofs, upperdentry, &origin_path);  			if (err)  				goto out_put_upper; @@ -1073,6 +1066,10 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,  			upperredirect = NULL;  			goto out_free_oe;  		} +		err = ovl_check_metacopy_xattr(upperdentry); +		if (err < 0) +			goto out_free_oe; +		uppermetacopy = err;  	}  	if (upperdentry || ctr) { diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index b725c7f15ff4..29bc1ec699e7 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -483,7 +483,6 @@ void ovl_aio_request_cache_destroy(void);  /* copy_up.c */  int ovl_copy_up(struct dentry *dentry);  int ovl_copy_up_with_data(struct dentry *dentry); -int ovl_copy_up_flags(struct dentry *dentry, int flags);  int ovl_maybe_copy_up(struct dentry *dentry, int flags);  int ovl_copy_xattr(struct dentry *old, struct dentry *new);  int ovl_set_attr(struct dentry *upper, struct kstat *stat); diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 91476bc422f9..4b38141c2985 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -580,12 +580,19 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)  		}  	} -	/* Workdir is useless in non-upper mount */ -	if (!config->upperdir && config->workdir) { -		pr_info("option \"workdir=%s\" is useless in a non-upper mount, ignore\n", -			config->workdir); -		kfree(config->workdir); -		config->workdir = NULL; +	/* Workdir/index are useless in non-upper mount */ +	if (!config->upperdir) { +		if (config->workdir) { +			pr_info("option \"workdir=%s\" is useless in a non-upper mount, ignore\n", +				config->workdir); +			kfree(config->workdir); +			config->workdir = NULL; +		} +		if (config->index && index_opt) { +			pr_info("option \"index=on\" is useless in a non-upper mount, ignore\n"); +			index_opt = false; +		} +		config->index = false;  	}  	err = ovl_parse_redirect_mode(config, config->redirect_mode); @@ -622,11 +629,13 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)  	/* Resolve nfs_export -> index dependency */  	if (config->nfs_export && !config->index) { -		if (nfs_export_opt && index_opt) { +		if (!config->upperdir && config->redirect_follow) { +			pr_info("NFS export requires \"redirect_dir=nofollow\" on non-upper mount, falling back to nfs_export=off.\n"); +			config->nfs_export = false; +		} else if (nfs_export_opt && index_opt) {  			pr_err("conflicting options: nfs_export=on,index=off\n");  			return -EINVAL; -		} -		if (index_opt) { +		} else if (index_opt) {  			/*  			 * There was an explicit index=off that resulted  			 * in this conflict. @@ -1352,8 +1361,15 @@ static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs,  		goto out;  	} +	/* index dir will act also as workdir */ +	iput(ofs->workdir_trap); +	ofs->workdir_trap = NULL; +	dput(ofs->workdir); +	ofs->workdir = NULL;  	ofs->indexdir = ovl_workdir_create(ofs, OVL_INDEXDIR_NAME, true);  	if (ofs->indexdir) { +		ofs->workdir = dget(ofs->indexdir); +  		err = ovl_setup_trap(sb, ofs->indexdir, &ofs->indexdir_trap,  				     "indexdir");  		if (err) @@ -1396,6 +1412,18 @@ static bool ovl_lower_uuid_ok(struct ovl_fs *ofs, const uuid_t *uuid)  	if (!ofs->config.nfs_export && !ovl_upper_mnt(ofs))  		return true; +	/* +	 * We allow using single lower with null uuid for index and nfs_export +	 * for example to support those features with single lower squashfs. +	 * To avoid regressions in setups of overlay with re-formatted lower +	 * squashfs, do not allow decoding origin with lower null uuid unless +	 * user opted-in to one of the new features that require following the +	 * lower inode of non-dir upper. +	 */ +	if (!ofs->config.index && !ofs->config.metacopy && !ofs->config.xino && +	    uuid_is_null(uuid)) +		return false; +  	for (i = 0; i < ofs->numfs; i++) {  		/*  		 * We use uuid to associate an overlay lower file handle with a @@ -1493,14 +1521,23 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,  		if (err < 0)  			goto out; +		/* +		 * Check if lower root conflicts with this overlay layers before +		 * checking if it is in-use as upperdir/workdir of "another" +		 * mount, because we do not bother to check in ovl_is_inuse() if +		 * the upperdir/workdir is in fact in-use by our +		 * upperdir/workdir. +		 */  		err = ovl_setup_trap(sb, stack[i].dentry, &trap, "lowerdir");  		if (err)  			goto out;  		if (ovl_is_inuse(stack[i].dentry)) {  			err = ovl_report_in_use(ofs, "lowerdir"); -			if (err) +			if (err) { +				iput(trap);  				goto out; +			}  		}  		mnt = clone_private_mount(&stack[i]); @@ -1575,10 +1612,6 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb,  	if (!ofs->config.upperdir && numlower == 1) {  		pr_err("at least 2 lowerdir are needed while upperdir nonexistent\n");  		return ERR_PTR(-EINVAL); -	} else if (!ofs->config.upperdir && ofs->config.nfs_export && -		   ofs->config.redirect_follow) { -		pr_warn("NFS export requires \"redirect_dir=nofollow\" on non-upper mount, falling back to nfs_export=off.\n"); -		ofs->config.nfs_export = false;  	}  	stack = kcalloc(numlower, sizeof(struct path), GFP_KERNEL); @@ -1842,21 +1875,13 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)  	if (!ovl_upper_mnt(ofs))  		sb->s_flags |= SB_RDONLY; -	if (!(ovl_force_readonly(ofs)) && ofs->config.index) { -		/* index dir will act also as workdir */ -		dput(ofs->workdir); -		ofs->workdir = NULL; -		iput(ofs->workdir_trap); -		ofs->workdir_trap = NULL; - +	if (!ovl_force_readonly(ofs) && ofs->config.index) {  		err = ovl_get_indexdir(sb, ofs, oe, &upperpath);  		if (err)  			goto out_free_oe;  		/* Force r/o mount with no index dir */ -		if (ofs->indexdir) -			ofs->workdir = dget(ofs->indexdir); -		else +		if (!ofs->indexdir)  			sb->s_flags |= SB_RDONLY;  	} |