Commit 52435c86 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull overlayfs updates from Miklos Szeredi:
 "Fixes:

   - Resolve mount option conflicts consistently

   - Sync before remount R/O

   - Fix file handle encoding corner cases

   - Fix metacopy related issues

   - Fix an unintialized return value

   - Add missing permission checks for underlying layers

  Optimizations:

   - Allow multipe whiteouts to share an inode

   - Optimize small writes by inheriting SB_NOSEC from upper layer

   - Do not call ->syncfs() multiple times for sync(2)

   - Do not cache negative lookups on upper layer

   - Make private internal mounts longterm"

* tag 'ovl-update-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: (27 commits)
  ovl: remove unnecessary lock check
  ovl: make oip->index bool
  ovl: only pass ->ki_flags to ovl_iocb_to_rwf()
  ovl: make private mounts longterm
  ovl: get rid of redundant members in struct ovl_fs
  ovl: add accessor for ofs->upper_mnt
  ovl: initialize error in ovl_copy_xattr
  ovl: drop negative dentry in upper layer
  ovl: check permission to open real file
  ovl: call secutiry hook in ovl_real_ioctl()
  ovl: verify permissions in ovl_path_open()
  ovl: switch to mounter creds in readdir
  ovl: pass correct flags for opening real directory
  ovl: fix redirect traversal on metacopy dentries
  ovl: initialize OVL_UPPERDATA in ovl_lookup()
  ovl: use only uppermetacopy state in ovl_lookup()
  ovl: simplify setting of origin for index lookup
  ovl: fix out of bounds access warning in ovl_check_fb_len()
  ovl: return required buffer size for file handles
  ovl: sync dirty data when remounting to ro mode
  ...
parents 4964dd29 2068cf7d
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -365,8 +365,8 @@ pointed by REDIRECT. This should not be possible on local system as setting
"trusted." xattrs will require CAP_SYS_ADMIN. But it should be possible
for untrusted layers like from a pen drive.

Note: redirect_dir={off|nofollow|follow[*]} conflicts with metacopy=on, and
results in an error.
Note: redirect_dir={off|nofollow|follow[*]} and nfs_export=on mount options
conflict with metacopy=on, and will result in an error.

[*] redirect_dir=follow only conflicts with metacopy=on if upperdir=... is
given.
@@ -560,6 +560,9 @@ 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.


Testsuite
---------
+7 −0
Original line number Diff line number Diff line
@@ -858,3 +858,10 @@ be misspelled d_alloc_anon().
[should've been added in 2016] stale comment in finish_open() nonwithstanding,
failure exits in ->atomic_open() instances should *NOT* fput() the file,
no matter what.  Everything is handled by the caller.

---

**mandatory**

clone_private_mount() returns a longterm mount now, so the proper destructor of
its result is kern_unmount() or kern_unmount_array().
+16 −0
Original line number Diff line number Diff line
@@ -1937,6 +1937,9 @@ struct vfsmount *clone_private_mount(const struct path *path)
	if (IS_ERR(new_mnt))
		return ERR_CAST(new_mnt);

	/* Longterm mount to be removed by kern_unmount*() */
	new_mnt->mnt_ns = MNT_NS_INTERNAL;

	return &new_mnt->mnt;
}
EXPORT_SYMBOL_GPL(clone_private_mount);
@@ -3863,6 +3866,19 @@ void kern_unmount(struct vfsmount *mnt)
}
EXPORT_SYMBOL(kern_unmount);

void kern_unmount_array(struct vfsmount *mnt[], unsigned int num)
{
	unsigned int i;

	for (i = 0; i < num; i++)
		if (mnt[i])
			real_mount(mnt[i])->mnt_ns = NULL;
	synchronize_rcu_expedited();
	for (i = 0; i < num; i++)
		mntput(mnt[i]);
}
EXPORT_SYMBOL(kern_unmount_array);

bool our_mnt(struct vfsmount *mnt)
{
	return check_mnt(real_mount(mnt));
+5 −4
Original line number Diff line number Diff line
@@ -47,7 +47,7 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
{
	ssize_t list_size, size, value_size = 0;
	char *buf, *name, *value = NULL;
	int uninitialized_var(error);
	int error = 0;
	size_t slen;

	if (!(old->d_inode->i_opflags & IOP_XATTR) ||
@@ -584,9 +584,10 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
		.link = c->link
	};

	err = ovl_lock_rename_workdir(c->workdir, c->destdir);
	if (err)
		return err;
	/* workdir and destdir could be the same when copying up to indexdir */
	err = -EIO;
	if (lock_rename(c->workdir, c->destdir) != NULL)
		goto unlock;

	err = ovl_prep_cu_creds(c->dentry, &cc);
	if (err)
+39 −12
Original line number Diff line number Diff line
@@ -62,35 +62,59 @@ struct dentry *ovl_lookup_temp(struct dentry *workdir)
}

/* caller holds i_mutex on workdir */
static struct dentry *ovl_whiteout(struct dentry *workdir)
static struct dentry *ovl_whiteout(struct ovl_fs *ofs)
{
	int err;
	struct dentry *whiteout;
	struct dentry *workdir = ofs->workdir;
	struct inode *wdir = workdir->d_inode;

	if (!ofs->whiteout) {
		whiteout = ovl_lookup_temp(workdir);
		if (IS_ERR(whiteout))
		return whiteout;
			goto out;

		err = ovl_do_whiteout(wdir, whiteout);
		if (err) {
			dput(whiteout);
			whiteout = ERR_PTR(err);
			goto out;
		}
		ofs->whiteout = whiteout;
	}

	if (ofs->share_whiteout) {
		whiteout = ovl_lookup_temp(workdir);
		if (IS_ERR(whiteout))
			goto out;

		err = ovl_do_link(ofs->whiteout, wdir, whiteout);
		if (!err)
			goto out;

		if (err != -EMLINK) {
			pr_warn("Failed to link whiteout - disabling whiteout inode sharing(nlink=%u, err=%i)\n",
				ofs->whiteout->d_inode->i_nlink, err);
			ofs->share_whiteout = false;
		}
		dput(whiteout);
	}
	whiteout = ofs->whiteout;
	ofs->whiteout = NULL;
out:
	return whiteout;
}

/* Caller must hold i_mutex on both workdir and dir */
int ovl_cleanup_and_whiteout(struct dentry *workdir, struct inode *dir,
int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct inode *dir,
			     struct dentry *dentry)
{
	struct inode *wdir = workdir->d_inode;
	struct inode *wdir = ofs->workdir->d_inode;
	struct dentry *whiteout;
	int err;
	int flags = 0;

	whiteout = ovl_whiteout(workdir);
	whiteout = ovl_whiteout(ofs);
	err = PTR_ERR(whiteout);
	if (IS_ERR(whiteout))
		return err;
@@ -262,6 +286,8 @@ static int ovl_instantiate(struct dentry *dentry, struct inode *inode,
		inode = ovl_get_inode(dentry->d_sb, &oip);
		if (IS_ERR(inode))
			return PTR_ERR(inode);
		if (inode == oip.newinode)
			ovl_set_flag(OVL_UPPERDATA, inode);
	} else {
		WARN_ON(ovl_inode_real(inode) != d_inode(newdentry));
		dput(newdentry);
@@ -715,6 +741,7 @@ static bool ovl_matches_upper(struct dentry *dentry, struct dentry *upper)
static int ovl_remove_and_whiteout(struct dentry *dentry,
				   struct list_head *list)
{
	struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
	struct dentry *workdir = ovl_workdir(dentry);
	struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
	struct dentry *upper;
@@ -748,7 +775,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
		goto out_dput_upper;
	}

	err = ovl_cleanup_and_whiteout(workdir, d_inode(upperdir), upper);
	err = ovl_cleanup_and_whiteout(ofs, d_inode(upperdir), upper);
	if (err)
		goto out_d_drop;

Loading