projects/linux·commit ff0f962c

Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs

ff0f962c · Linus Torvalds <[email protected]> · 2016-12-16 10:58:12 -08:00

Pull overlayfs updates from Miklos Szeredi:
 "This update contains:

   - try to clone on copy-up

   - allow renaming a directory

   - split source into managable chunks

   - misc cleanups and fixes

  It does not contain the read-only fd data inconsistency fix, which Al
  didn't like. I'll leave that to the next year..."

* 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: (36 commits)
  ovl: fix reStructuredText syntax errors in documentation
  ovl: fix return value of ovl_fill_super
  ovl: clean up kstat usage
  ovl: fold ovl_copy_up_truncate() into ovl_copy_up()
  ovl: create directories inside merged parent opaque
  ovl: opaque cleanup
  ovl: show redirect_dir mount option
  ovl: allow setting max size of redirect
  ovl: allow redirect_dir to default to "on"
  ovl: check for emptiness of redirect dir
  ovl: redirect on rename-dir
  ovl: lookup redirects
  ovl: consolidate lookup for underlying layers
  ovl: fix nested overlayfs mount
  ovl: check namelen
  ovl: split super.c
  ovl: use d_is_dir()
  ovl: simplify lookup
  ovl: check lower existence of rename target
  ovl: rename: simplify handling of lower/merged directory
  ...
Commit
ff0f962ca3c38239b299a70e7eea27abfbb979c3
Parents
087a76d3 · c3c86996

Merge commit. Changes below are compared with the first parent: 087a76d3.

Changes

17 files changed · +1139 −812

Only the first 600 diff lines are shown. Download the complete patch.

Documentation/filesystems/overlayfs.txt

View file
diff --git a/Documentation/filesystems/overlayfs.txt b/Documentation/filesystems/overlayfs.txt
index bcbf971..634d03e 100644
--- a/Documentation/filesystems/overlayfs.txt
+++ b/Documentation/filesystems/overlayfs.txt
@@ -66,7 +66,7 @@ At mount time, the two directories given as mount options "lowerdir" and
"upperdir" are combined into a merged directory:
mount -t overlay overlay -olowerdir=/lower,upperdir=/upper,\
-workdir=/work /merged
+ workdir=/work /merged
The "workdir" needs to be an empty directory on the same filesystem
as upperdir.
@@ -118,6 +118,7 @@ programs.
seek offsets are assigned sequentially when the directories are read.
Thus if
+
- read part of a directory
- remember an offset, and close the directory
- re-open the directory some time later
@@ -130,6 +131,23 @@ directory.
Readdir on directories that are not merged is simply handled by the
underlying directory (upper or lower).
+renaming directories
+--------------------
+
+When renaming a directory that is on the lower layer or merged (i.e. the
+directory was not created on the upper layer to start with) overlayfs can
+handle it in two different ways:
+
+1. return EXDEV error: this error is returned by rename(2) when trying to
+ move a file or directory across filesystem boundaries. Hence
+ applications are usually prepared to hande this error (mv(1) for example
+ recursively copies the directory tree). This is the default behavior.
+
+2. If the "redirect_dir" feature is enabled, then the directory will be
+ copied up (but not the contents). Then the "trusted.overlay.redirect"
+ extended attribute is set to the path of the original location from the
+ root of the overlay. Finally the directory is moved to the new
+ location.
Non-directories
---------------
@@ -185,13 +203,13 @@ filesystem, so both st_dev and st_ino of the file may change.
Any open files referring to this inode will access the old data.
-Any file locks (and leases) obtained before copy_up will not apply
-to the copied up file.
-
If a file with multiple hard links is copied up, then this will
"break" the link. Changes will not be propagated to other names
referring to the same inode.
+Unless "redirect_dir" feature is enabled, rename(2) on a lower or merged
+directory will fail with EXDEV.
+
Changes to underlying filesystems
---------------------------------

fs/ioctl.c

View file
diff --git a/fs/ioctl.c b/fs/ioctl.c
index c415668..cb9b029 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -223,7 +223,11 @@ static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd,
if (!src_file.file)
return -EBADF;
- ret = vfs_clone_file_range(src_file.file, off, dst_file, destoff, olen);
+ ret = -EXDEV;
+ if (src_file.file->f_path.mnt != dst_file->f_path.mnt)
+ goto fdput;
+ ret = do_clone_file_range(src_file.file, off, dst_file, destoff, olen);
+fdput:
fdput(src_file);
return ret;
}

fs/namei.c

View file
diff --git a/fs/namei.c b/fs/namei.c
index 092ac56..2b55ea1 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4306,11 +4306,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
bool new_is_dir = false;
unsigned max_links = new_dir->i_sb->s_max_links;
- /*
- * Check source == target.
- * On overlayfs need to look at underlying inodes.
- */
- if (d_real_inode(old_dentry) == d_real_inode(new_dentry))
+ if (source == target)
return 0;
error = may_delete(old_dir, old_dentry, is_dir);

fs/nfsd/vfs.c

View file
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 8ca642f..357e844 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -509,8 +509,7 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
__be32 nfsd4_clone_file_range(struct file *src, u64 src_pos, struct file *dst,
u64 dst_pos, u64 count)
{
- return nfserrno(vfs_clone_file_range(src, src_pos, dst, dst_pos,
- count));
+ return nfserrno(do_clone_file_range(src, src_pos, dst, dst_pos, count));
}
ssize_t nfsd_copy_file_range(struct file *src, u64 src_pos, struct file *dst,

fs/overlayfs/Kconfig

View file
diff --git a/fs/overlayfs/Kconfig b/fs/overlayfs/Kconfig
index 3435581..0daac51 100644
--- a/fs/overlayfs/Kconfig
+++ b/fs/overlayfs/Kconfig
@@ -8,3 +8,17 @@ config OVERLAY_FS
merged with the 'upper' object.
For more information see Documentation/filesystems/overlayfs.txt
+
+config OVERLAY_FS_REDIRECT_DIR
+ bool "Overlayfs: turn on redirect dir feature by default"
+ depends on OVERLAY_FS
+ help
+ If this config option is enabled then overlay filesystems will use
+ redirects when renaming directories by default. In this case it is
+ still possible to turn off redirects globally with the
+ "redirect_dir=off" module option or on a filesystem instance basis
+ with the "redirect_dir=off" mount option.
+
+ Note, that redirects are not backward compatible. That is, mounting
+ an overlay which has redirects on a kernel that doesn't support this
+ feature will have unexpected results.

fs/overlayfs/Makefile

View file
diff --git a/fs/overlayfs/Makefile b/fs/overlayfs/Makefile
index 900daed..99373bb 100644
--- a/fs/overlayfs/Makefile
+++ b/fs/overlayfs/Makefile
@@ -4,4 +4,4 @@
obj-$(CONFIG_OVERLAY_FS) += overlay.o
-overlay-objs := super.o inode.o dir.o readdir.o copy_up.o
+overlay-objs := super.o namei.o util.o inode.o dir.o readdir.o copy_up.o

fs/overlayfs/copy_up.c

View file
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 2838bdd..f57043d 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -153,6 +153,13 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
goto out_fput;
}
+ /* Try to use clone_file_range to clone up within the same fs */
+ error = vfs_clone_file_range(old_file, 0, new_file, 0, len);
+ if (!error)
+ goto out;
+ /* Couldn't clone, so now we try to copy the data */
+ error = 0;
+
/* FIXME: copy up sparse files efficiently */
while (len) {
size_t this_len = OVL_COPY_UP_CHUNK_SIZE;
@@ -177,7 +184,7 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
len -= bytes;
}
-
+out:
if (!error)
error = vfs_fsync(new_file, 0);
fput(new_file);
@@ -231,10 +238,15 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
struct inode *udir = upperdir->d_inode;
struct dentry *newdentry = NULL;
struct dentry *upper = NULL;
- umode_t mode = stat->mode;
int err;
const struct cred *old_creds = NULL;
struct cred *new_creds = NULL;
+ struct cattr cattr = {
+ /* Can't properly set mode on creation because of the umask */
+ .mode = stat->mode & S_IFMT,
+ .rdev = stat->rdev,
+ .link = link
+ };
newdentry = ovl_lookup_temp(workdir, dentry);
err = PTR_ERR(newdentry);
@@ -254,10 +266,7 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
if (new_creds)
old_creds = override_creds(new_creds);
- /* Can't properly set mode on creation because of the umask */
- stat->mode &= S_IFMT;
- err = ovl_create_real(wdir, newdentry, stat, link, NULL, true);
- stat->mode = mode;
+ err = ovl_create_real(wdir, newdentry, &cattr, NULL, true);
if (new_creds) {
revert_creds(old_creds);
@@ -296,12 +305,6 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
ovl_dentry_update(dentry, newdentry);
ovl_inode_update(d_inode(dentry), d_inode(newdentry));
newdentry = NULL;
-
- /*
- * Non-directores become opaque when copied up.
- */
- if (!S_ISDIR(stat->mode))
- ovl_dentry_set_opaque(dentry, true);
out2:
dput(upper);
out1:
@@ -317,20 +320,14 @@ out_cleanup:
/*
* Copy up a single dentry
*
- * Directory renames only allowed on "pure upper" (already created on
- * upper filesystem, never copied up). Directories which are on lower or
- * are merged may not be renamed. For these -EXDEV is returned and
- * userspace has to deal with it. This means, when copying up a
- * directory we can rely on it and ancestors being stable.
- *
- * Non-directory renames start with copy up of source if necessary. The
- * actual rename will only proceed once the copy up was successful. Copy
- * up uses upper parent i_mutex for exclusion. Since rename can change
- * d_parent it is possible that the copy up will lock the old parent. At
- * that point the file will have already been copied up anyway.
+ * All renames start with copy up of source if necessary. The actual
+ * rename will only proceed once the copy up was successful. Copy up uses
+ * upper parent i_mutex for exclusion. Since rename can change d_parent it
+ * is possible that the copy up will lock the old parent. At that point
+ * the file will have already been copied up anyway.
*/
-int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
- struct path *lowerpath, struct kstat *stat)
+static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
+ struct path *lowerpath, struct kstat *stat)
{
DEFINE_DELAYED_CALL(done);
struct dentry *workdir = ovl_workdir(dentry);
@@ -339,7 +336,6 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
struct path parentpath;
struct dentry *lowerdentry = lowerpath->dentry;
struct dentry *upperdir;
- struct dentry *upperdentry;
const char *link = NULL;
if (WARN_ON(!workdir))
@@ -365,8 +361,7 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
pr_err("overlayfs: failed to lock workdir+upperdir\n");
goto out_unlock;
}
- upperdentry = ovl_dentry_upper(dentry);
- if (upperdentry) {
+ if (ovl_dentry_upper(dentry)) {
/* Raced with another copy-up? Nothing to do, then... */
err = 0;
goto out_unlock;
@@ -385,7 +380,7 @@ out_unlock:
return err;
}
-int ovl_copy_up(struct dentry *dentry)
+int ovl_copy_up_flags(struct dentry *dentry, int flags)
{
int err = 0;
const struct cred *old_cred = ovl_override_creds(dentry->d_sb);
@@ -415,6 +410,9 @@ int ovl_copy_up(struct dentry *dentry)
ovl_path_lower(next, &lowerpath);
err = vfs_getattr(&lowerpath, &stat);
+ /* maybe truncate regular file. this has no effect on dirs */
+ if (flags & O_TRUNC)
+ stat.size = 0;
if (!err)
err = ovl_copy_up_one(parent, next, &lowerpath, &stat);
@@ -425,3 +423,8 @@ int ovl_copy_up(struct dentry *dentry)
return err;
}
+
+int ovl_copy_up(struct dentry *dentry)
+{
+ return ovl_copy_up_flags(dentry, 0);
+}

fs/overlayfs/dir.c

View file
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 306b6c1..16e06dd 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -12,11 +12,18 @@
#include <linux/xattr.h>
#include <linux/security.h>
#include <linux/cred.h>
+#include <linux/module.h>
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
#include <linux/atomic.h>
+#include <linux/ratelimit.h>
#include "overlayfs.h"
+static unsigned short ovl_redirect_max = 256;
+module_param_named(redirect_max, ovl_redirect_max, ushort, 0644);
+MODULE_PARM_DESC(ovl_redirect_max,
+ "Maximum length of absolute redirect xattr value");
+
void ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
{
int err;
@@ -75,8 +82,7 @@ static struct dentry *ovl_whiteout(struct dentry *workdir,
}
int ovl_create_real(struct inode *dir, struct dentry *newdentry,
- struct kstat *stat, const char *link,
- struct dentry *hardlink, bool debug)
+ struct cattr *attr, struct dentry *hardlink, bool debug)
{
int err;
@@ -86,13 +92,13 @@ int ovl_create_real(struct inode *dir, struct dentry *newdentry,
if (hardlink) {
err = ovl_do_link(hardlink, dir, newdentry, debug);
} else {
- switch (stat->mode & S_IFMT) {
+ switch (attr->mode & S_IFMT) {
case S_IFREG:
- err = ovl_do_create(dir, newdentry, stat->mode, debug);
+ err = ovl_do_create(dir, newdentry, attr->mode, debug);
break;
case S_IFDIR:
- err = ovl_do_mkdir(dir, newdentry, stat->mode, debug);
+ err = ovl_do_mkdir(dir, newdentry, attr->mode, debug);
break;
case S_IFCHR:
@@ -100,11 +106,11 @@ int ovl_create_real(struct inode *dir, struct dentry *newdentry,
case S_IFIFO:
case S_IFSOCK:
err = ovl_do_mknod(dir, newdentry,
- stat->mode, stat->rdev, debug);
+ attr->mode, attr->rdev, debug);
break;
case S_IFLNK:
- err = ovl_do_symlink(dir, newdentry, link, debug);
+ err = ovl_do_symlink(dir, newdentry, attr->link, debug);
break;
default:
@@ -121,20 +127,15 @@ int ovl_create_real(struct inode *dir, struct dentry *newdentry,
return err;
}
-static int ovl_set_opaque(struct dentry *upperdentry)
-{
- return ovl_do_setxattr(upperdentry, OVL_XATTR_OPAQUE, "y", 1, 0);
-}
-
-static void ovl_remove_opaque(struct dentry *upperdentry)
+static int ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry)
{
int err;
- err = ovl_do_removexattr(upperdentry, OVL_XATTR_OPAQUE);
- if (err) {
- pr_warn("overlayfs: failed to remove opaque from '%s' (%i)\n",
- upperdentry->d_name.name, err);
- }
+ err = ovl_do_setxattr(upperdentry, OVL_XATTR_OPAQUE, "y", 1, 0);
+ if (!err)
+ ovl_dentry_set_opaque(dentry);
+
+ return err;
}
static int ovl_dir_getattr(struct vfsmount *mnt, struct dentry *dentry,
@@ -182,9 +183,13 @@ static void ovl_instantiate(struct dentry *dentry, struct inode *inode,
d_instantiate(dentry, inode);
}
+static bool ovl_type_merge(struct dentry *dentry)
+{
+ return OVL_TYPE_MERGE(ovl_path_type(dentry));
+}
+
static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
- struct kstat *stat, const char *link,
- struct dentry *hardlink)
+ struct cattr *attr, struct dentry *hardlink)
{
struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
struct inode *udir = upperdir->d_inode;
@@ -192,7 +197,7 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
int err;
if (!hardlink && !IS_POSIXACL(udir))
- stat->mode &= ~current_umask();
+ attr->mode &= ~current_umask();
inode_lock_nested(udir, I_MUTEX_PARENT);
newdentry = lookup_one_len(dentry->d_name.name, upperdir,
@@ -200,10 +205,15 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
err = PTR_ERR(newdentry);
if (IS_ERR(newdentry))
goto out_unlock;
- err = ovl_create_real(udir, newdentry, stat, link, hardlink, false);
+ err = ovl_create_real(udir, newdentry, attr, hardlink, false);
if (err)
goto out_dput;
+ if (ovl_type_merge(dentry->d_parent)) {
+ /* Setting opaque here is just an optimization, allow to fail */
+ ovl_set_opaque(dentry, newdentry);
+ }
+
ovl_instantiate(dentry, inode, newdentry, !!hardlink);
newdentry = NULL;
out_dput:
@@ -270,7 +280,8 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
if (IS_ERR(opaquedir))
goto out_unlock;
- err = ovl_create_real(wdir, opaquedir, &stat, NULL, NULL, true);
+ err = ovl_create_real(wdir, opaquedir,
+ &(struct cattr){.mode = stat.mode}, NULL, true);
if (err)
goto out_dput;
@@ -278,7 +289,7 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
if (err)
goto out_cleanup;
- err = ovl_set_opaque(opaquedir);
+ err = ovl_set_opaque(dentry, opaquedir);
if (err)
goto out_cleanup;
@@ -370,7 +381,7 @@ out_free:
}
static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
- struct kstat *stat, const char *link,
+ struct cattr *cattr,
struct dentry *hardlink)
{
struct dentry *workdir = ovl_workdir(dentry);
@@ -387,7 +398,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
if (!hardlink) {
err = posix_acl_create(dentry->d_parent->d_inode,
- &stat->mode, &default_acl, &acl);
+ &cattr->mode, &default_acl, &acl);
if (err)
return err;
}
@@ -407,7 +418,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
if (IS_ERR(upper))
goto out_dput;
- err = ovl_create_real(wdir, newdentry, stat, link, hardlink, true);
+ err = ovl_create_real(wdir, newdentry, cattr, hardlink, true);
if (err)
goto out_dput2;
@@ -415,10 +426,11 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
* mode could have been mutilated due to umask (e.g. sgid directory)
*/
if (!hardlink &&
- !S_ISLNK(stat->mode) && newdentry->d_inode->i_mode != stat->mode) {
+ !S_ISLNK(cattr->mode) &&
+ newdentry->d_inode->i_mode != cattr->mode) {
struct iattr attr = {
.ia_valid = ATTR_MODE,
- .ia_mode = stat->mode,
+ .ia_mode = cattr->mode,
};
inode_lock(newdentry->d_inode);
err = notify_change(newdentry, &attr, NULL);
@@ -438,8 +450,8 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
goto out_cleanup;
}
- if (!hardlink && S_ISDIR(stat->mode)) {
- err = ovl_set_opaque(newdentry);
+ if (!hardlink && S_ISDIR(cattr->mode)) {
+ err = ovl_set_opaque(dentry, newdentry);
if (err)
goto out_cleanup;
@@ -475,8 +487,7 @@ out_cleanup:
}
static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
- struct kstat *stat, const char *link,
- struct dentry *hardlink)
+ struct cattr *attr, struct dentry *hardlink)
{
int err;
const struct cred *old_cred;
@@ -494,7 +505,7 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
override_cred->fsgid = inode->i_gid;
if (!hardlink) {
err = security_dentry_create_files_as(dentry,
- stat->mode, &dentry->d_name, old_cred,
+ attr->mode, &dentry->d_name, old_cred,
override_cred);
if (err) {
put_cred(override_cred);
@@ -504,12 +515,12 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
put_cred(override_creds(override_cred));
put_cred(override_cred);
- if (!ovl_dentry_is_opaque(dentry))
- err = ovl_create_upper(dentry, inode, stat, link,
+ if (!ovl_dentry_is_whiteout(dentry))
+ err = ovl_create_upper(dentry, inode, attr,
hardlink);
else
- err = ovl_create_over_whiteout(dentry, inode, stat,
- link, hardlink);
+ err = ovl_create_over_whiteout(dentry, inode, attr,
+ hardlink);
}
out_revert_creds:
revert_creds(old_cred);
@@ -528,8 +539,9 @@ static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev,
{
int err;
struct inode *inode;
- struct kstat stat = {
+ struct cattr attr = {
.rdev = rdev,
+ .link = link,
};
err = ovl_want_write(dentry);
@@ -537,14 +549,14 @@ static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev,
goto out;
err = -ENOMEM;
- inode = ovl_new_inode(dentry->d_sb, mode);
+ inode = ovl_new_inode(dentry->d_sb, mode, rdev);
if (!inode)
goto out_drop_write;
inode_init_owner(inode, dentry->d_parent->d_inode, mode);
- stat.mode = inode->i_mode;
+ attr.mode = inode->i_mode;
- err = ovl_create_or_link(dentry, inode, &stat, link, NULL);
+ err = ovl_create_or_link(dentry, inode, &attr, NULL);
if (err)
iput(inode);
@@ -598,7 +610,7 @@ static int ovl_link(struct dentry *old, struct inode *newdir,
inode = d_inode(old);
ihold(inode);
- err = ovl_create_or_link(new, inode, NULL, NULL, ovl_dentry_upper(old));
+ err = ovl_create_or_link(new, inode, NULL, ovl_dentry_upper(old));
if (err)
iput(inode);
@@ -684,8 +696,17 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir)
struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
struct inode *dir = upperdir->d_inode;
struct dentry *upper;
+ struct dentry *opaquedir = NULL;
int err;
+ /* Redirect dir can be !ovl_lower_positive && OVL_TYPE_MERGE */
+ if (is_dir && ovl_dentry_get_redirect(dentry)) {
+ opaquedir = ovl_check_empty_and_clear(dentry);
+ err = PTR_ERR(opaquedir);
+ if (IS_ERR(opaquedir))
+ goto out;
+ }
+
inode_lock_nested(dir, I_MUTEX_PARENT);
upper = lookup_one_len(dentry->d_name.name, upperdir,
dentry->d_name.len);
@@ -694,14 +715,15 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir)
goto out_unlock;
err = -ESTALE;
- if (upper == ovl_dentry_upper(dentry)) {
- if (is_dir)
- err = vfs_rmdir(dir, upper);
- else
- err = vfs_unlink(dir, upper, NULL);
- ovl_dentry_version_inc(dentry->d_parent);
- }
- dput(upper);
+ if ((opaquedir && upper != opaquedir) ||
+ (!opaquedir && upper != ovl_dentry_upper(dentry)))
+ goto out_dput_upper;
+
+ if (is_dir)
+ err = vfs_rmdir(dir, upper);
+ else

This diff is incomplete. Download the complete patch.

fs/overlayfs/inode.c

View file

This diff is incomplete. Download the complete patch.

fs/overlayfs/namei.c

View file

This diff is incomplete. Download the complete patch.

fs/overlayfs/overlayfs.h

View file

This diff is incomplete. Download the complete patch.

fs/overlayfs/ovl_entry.h

View file

This diff is incomplete. Download the complete patch.

fs/overlayfs/super.c

View file

This diff is incomplete. Download the complete patch.

fs/overlayfs/util.c

View file

This diff is incomplete. Download the complete patch.

fs/read_write.c

View file

This diff is incomplete. Download the complete patch.

include/linux/fs.h

View file

This diff is incomplete. Download the complete patch.

net/unix/af_unix.c

View file

This diff is incomplete. Download the complete patch.