Skip to content

Commit

Permalink
Merge tag 'ovl-fixes-5.8-rc6' of git://git.kernel.org/pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/git/mszeredi/vfs into master

Pull overlayfs fixes from Miklos Szeredi:

 - fix a regression introduced in v4.20 in handling a regenerated
   squashfs lower layer

 - two regression fixes for this cycle, one of which is Oops inducing

 - miscellaneous issues

* tag 'ovl-fixes-5.8-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
  ovl: fix lookup of indexed hardlinks with metacopy
  ovl: fix unneeded call to ovl_change_flags()
  ovl: fix mount option checks for nfs_export with no upperdir
  ovl: force read-only sb on failure to create index dir
  ovl: fix regression with re-formatted lower squashfs
  ovl: fix oops in ovl_indexdir_cleanup() with nfs_export=on
  ovl: relax WARN_ON() when decoding lower directory file handle
  ovl: remove not used argument in ovl_check_origin
  ovl: change ovl_copy_up_flags static
  ovl: inode reference leak in ovl_is_inuse true case.
  • Loading branch information
Linus Torvalds committed Jul 17, 2020
2 parents 33b9108 + 4518dfc commit 44fea37
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 42 deletions.
4 changes: 2 additions & 2 deletions Documentation/filesystems/overlayfs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -560,8 +560,8 @@ When the NFS export feature is enabled, all directory index entries are
verified on mount time to check that upper file handles are not stale.
This verification may cause significant overhead in some cases.

Note: the mount options index=off,nfs_export=on are conflicting and will
result in an error.
Note: the mount options index=off,nfs_export=on are conflicting for a
read-write mount and will result in an error.


Testsuite
Expand Down
2 changes: 1 addition & 1 deletion fs/overlayfs/copy_up.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion fs/overlayfs/export.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
10 changes: 6 additions & 4 deletions fs/overlayfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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;
Expand Down
15 changes: 6 additions & 9 deletions fs/overlayfs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, bool connected,
}

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;
Expand All @@ -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;
}

Expand Down Expand Up @@ -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,
Expand All @@ -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;

Expand Down Expand Up @@ -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) {
Expand Down
1 change: 0 additions & 1 deletion fs/overlayfs/overlayfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
73 changes: 49 additions & 24 deletions fs/overlayfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down

0 comments on commit 44fea37

Please sign in to comment.