Sophie

Sophie

distrib > Mageia > 8 > armv7hl > media > core-backports-src > by-pkgid > a0f04899a62bf014683de7d7d5ee81ea > files > 63

kernel-5.12.8-1.mga8.src.rpm

From 85fab2b2001b57d8c9709398223212e27e8a2238 Mon Sep 17 00:00:00 2001
From: "J. R. Okajima" <hooanon05g@gmail.com>
Date: Thu, 4 Mar 2021 11:33:45 +0900
Subject: [PATCH] aufs: v5.12-rc1 idmapper userns 1/2, new parameter

In mainline, by the commit
	549c7297717c3 2021-01-24 fs: make helpers idmap mount aware
and its series, a new parameter 'user_ns' was added to some inode
operations.  Aufs simply follows it, but it is still testing.

Signed-off-by: J. R. Okajima <hooanon05g@gmail.com>
---
 fs/aufs/branch.h    | 11 +++++++++
 fs/aufs/cpup.c      | 34 ++++++++++++++++++---------
 fs/aufs/dentry.c    | 18 +++++++++-----
 fs/aufs/dentry.h    |  3 ++-
 fs/aufs/dir.c       |  4 +++-
 fs/aufs/i_op.c      | 39 ++++++++++++++++++++-----------
 fs/aufs/i_op_add.c  | 21 ++++++++++-------
 fs/aufs/i_op_del.c  |  6 +++--
 fs/aufs/i_op_ren.c  |  3 ++-
 fs/aufs/inode.c     | 10 ++++----
 fs/aufs/inode.h     | 37 +++++++++++++++++------------
 fs/aufs/posix_acl.c |  3 ++-
 fs/aufs/super.c     |  5 +++-
 fs/aufs/vfsub.c     | 57 ++++++++++++++++++++++++++++++++++-----------
 fs/aufs/vfsub.h     | 18 ++++++++------
 fs/aufs/whout.c     | 24 ++++++++++++-------
 fs/aufs/whout.h     |  5 ++--
 fs/aufs/xattr.c     | 34 ++++++++++++++++++---------
 fs/aufs/xino.c      |  2 +-
 19 files changed, 227 insertions(+), 107 deletions(-)

diff --git a/fs/aufs/branch.h b/fs/aufs/branch.h
index 5632781b7bcc4e..ef7e0fb5a9d776 100644
--- a/fs/aufs/branch.h
+++ b/fs/aufs/branch.h
@@ -133,6 +133,11 @@ static inline struct dentry *au_br_dentry(struct au_branch *br)
 	return br->br_path.dentry;
 }
 
+static inline struct user_namespace *au_br_userns(struct au_branch *br)
+{
+	return mnt_user_ns(br->br_path.mnt);
+}
+
 static inline struct super_block *au_br_sb(struct au_branch *br)
 {
 	return au_br_mnt(br)->mnt_sb;
@@ -291,6 +296,12 @@ struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex)
 	return au_br_mnt(au_sbr(sb, bindex));
 }
 
+static inline
+struct user_namespace *au_sbr_userns(struct super_block *sb, aufs_bindex_t bindex)
+{
+	return au_br_userns(au_sbr(sb, bindex));
+}
+
 static inline
 struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex)
 {
diff --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c
index d413ad06ca89e3..5f86875573da10 100644
--- a/fs/aufs/cpup.c
+++ b/fs/aufs/cpup.c
@@ -151,7 +151,7 @@ struct au_cpup_reg_attr {
 };
 
 static noinline_for_stack
-int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src,
+int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct path *h_src,
 	       struct au_cpup_reg_attr *h_src_attr)
 {
 	int err, sbits, icex;
@@ -163,11 +163,11 @@ int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src,
 	struct kstat *h_st;
 	struct au_branch *br;
 
-	h_path.dentry = au_h_dptr(dst, bindex);
-	h_idst = d_inode(h_path.dentry);
 	br = au_sbr(dst->d_sb, bindex);
 	h_path.mnt = au_br_mnt(br);
-	h_isrc = d_inode(h_src);
+	h_path.dentry = au_h_dptr(dst, bindex);
+	h_idst = d_inode(h_path.dentry);
+	h_isrc = d_inode(h_src->dentry);
 	ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID
 		| ATTR_ATIME | ATTR_MTIME
 		| ATTR_ATIME_SET | ATTR_MTIME_SET;
@@ -211,7 +211,7 @@ int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src,
 	if (!err) {
 		mnt_flags = au_mntflags(dst->d_sb);
 		verbose = !!au_opt_test(mnt_flags, VERBOSE);
-		err = au_cpup_xattr(h_path.dentry, h_src, icex, verbose);
+		err = au_cpup_xattr(&h_path, h_src, icex, verbose);
 	}
 
 	return err;
@@ -581,16 +581,18 @@ static int au_reset_acl(struct inode *h_dir, struct path *h_path, umode_t mode)
 	int err;
 	struct dentry *h_dentry;
 	struct inode *h_inode;
+	struct user_namespace *h_userns;
 
+	h_userns = mnt_user_ns(h_path->mnt);
 	h_dentry = h_path->dentry;
 	h_inode = d_inode(h_dentry);
 	/* forget_all_cached_acls(h_inode)); */
-	err = vfsub_removexattr(h_dentry, XATTR_NAME_POSIX_ACL_ACCESS);
+	err = vfsub_removexattr(h_userns, h_dentry, XATTR_NAME_POSIX_ACL_ACCESS);
 	AuTraceErr(err);
 	if (err == -EOPNOTSUPP)
 		err = 0;
 	if (!err)
-		err = vfsub_acl_chmod(h_inode, mode);
+		err = vfsub_acl_chmod(h_userns, h_inode, mode);
 
 	AuTraceErr(err);
 	return err;
@@ -601,8 +603,11 @@ static int au_do_cpup_dir(struct au_cp_generic *cpg, struct dentry *dst_parent,
 {
 	int err;
 	struct inode *dir, *inode;
+	struct user_namespace *h_userns;
 
-	err = vfsub_removexattr(h_path->dentry, XATTR_NAME_POSIX_ACL_DEFAULT);
+	h_userns = mnt_user_ns(h_path->mnt);
+	err = vfsub_removexattr(h_userns, h_path->dentry,
+				XATTR_NAME_POSIX_ACL_DEFAULT);
 	AuTraceErr(err);
 	if (err == -EOPNOTSUPP)
 		err = 0;
@@ -783,6 +788,7 @@ static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent)
 	struct inode *dst_inode, *h_dir, *inode, *delegated, *src_inode;
 	struct super_block *sb;
 	struct au_branch *br;
+	struct path h_src_path;
 	/* to reduce stack size */
 	struct {
 		struct au_dtime dt;
@@ -874,7 +880,9 @@ static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent)
 	/* todo: necessary? */
 	/* au_pin_hdir_unlock(cpg->pin); */
 
-	err = cpup_iattr(cpg->dentry, cpg->bdst, h_src, &a->h_src_attr);
+	h_src_path.dentry = h_src;
+	h_src_path.mnt = au_sbr_mnt(sb, cpg->bsrc);
+	err = cpup_iattr(cpg->dentry, cpg->bdst, &h_src_path, &a->h_src_attr);
 	if (unlikely(err)) {
 		/* todo: necessary? */
 		/* au_pin_hdir_relock(cpg->pin); */ /* ignore an error */
@@ -1076,6 +1084,7 @@ static int au_do_sio_cpup_simple(struct au_cp_generic *cpg)
 	struct dentry *dentry, *parent;
 	struct file *h_file;
 	struct inode *h_dir;
+	struct user_namespace *h_userns;
 
 	dentry = cpg->dentry;
 	h_file = NULL;
@@ -1089,7 +1098,8 @@ static int au_do_sio_cpup_simple(struct au_cp_generic *cpg)
 
 	parent = dget_parent(dentry);
 	h_dir = au_h_iptr(d_inode(parent), cpg->bdst);
-	if (!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE)
+	h_userns = au_sbr_userns(dentry->d_sb, cpg->bdst);
+	if (!au_test_h_perm_sio(h_userns, h_dir, MAY_EXEC | MAY_WRITE)
 	    && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode))
 		err = au_cpup_simple(cpg);
 	else {
@@ -1259,6 +1269,7 @@ int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file)
 	struct inode *dir, *h_dir, *h_tmpdir;
 	struct au_wbr *wbr;
 	struct au_pin wh_pin, *pin_orig;
+	struct user_namespace *h_userns;
 
 	dentry = cpg->dentry;
 	bdst = cpg->bdst;
@@ -1287,7 +1298,8 @@ int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file)
 		cpg->pin = &wh_pin;
 	}
 
-	if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE)
+	h_userns = au_sbr_userns(dentry->d_sb, bdst);
+	if (!au_test_h_perm_sio(h_userns, h_tmpdir, MAY_EXEC | MAY_WRITE)
 	    && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode))
 		err = au_cpup_wh(cpg, file);
 	else {
diff --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c
index 1a029193315a91..2143add96a2de4 100644
--- a/fs/aufs/dentry.c
+++ b/fs/aufs/dentry.c
@@ -22,6 +22,7 @@ au_do_lookup(struct dentry *h_parent, struct dentry *dentry,
 	struct dentry *h_dentry;
 	struct inode *h_inode;
 	struct au_branch *br;
+	struct user_namespace *h_userns;
 	int wh_found, opq;
 	unsigned char wh_able;
 	const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG);
@@ -30,9 +31,11 @@ au_do_lookup(struct dentry *h_parent, struct dentry *dentry,
 
 	wh_found = 0;
 	br = au_sbr(dentry->d_sb, bindex);
+	h_userns = au_br_userns(br);
 	wh_able = !!au_br_whable(br->br_perm);
 	if (wh_able)
-		wh_found = au_wh_test(h_parent, &args->whname, ignore_perm);
+		wh_found = au_wh_test(h_userns, h_parent, &args->whname,
+				      ignore_perm);
 	h_dentry = ERR_PTR(wh_found);
 	if (!wh_found)
 		goto real_lookup;
@@ -49,7 +52,7 @@ au_do_lookup(struct dentry *h_parent, struct dentry *dentry,
 	if (!ignore_perm)
 		h_dentry = vfsub_lkup_one(args->name, h_parent);
 	else
-		h_dentry = au_sio_lkup_one(args->name, h_parent);
+		h_dentry = au_sio_lkup_one(h_userns, args->name, h_parent);
 	if (IS_ERR(h_dentry)) {
 		if (PTR_ERR(h_dentry) == -ENAMETOOLONG
 		    && !allow_neg)
@@ -84,7 +87,7 @@ au_do_lookup(struct dentry *h_parent, struct dentry *dentry,
 		goto out; /* success */
 
 	inode_lock_shared_nested(h_inode, AuLsc_I_CHILD);
-	opq = au_diropq_test(h_dentry);
+	opq = au_diropq_test(h_userns, h_dentry);
 	inode_unlock_shared(h_inode);
 	if (opq > 0)
 		au_set_dbdiropq(dentry, bindex);
@@ -229,12 +232,13 @@ int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t btop,
 	return err;
 }
 
-struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent)
+struct dentry *au_sio_lkup_one(struct user_namespace *userns, struct qstr *name,
+			       struct dentry *parent)
 {
 	struct dentry *dentry;
 	int wkq_err;
 
-	if (!au_test_h_perm_sio(d_inode(parent), MAY_EXEC))
+	if (!au_test_h_perm_sio(userns, d_inode(parent), MAY_EXEC))
 		dentry = vfsub_lkup_one(name, parent);
 	else {
 		struct vfsub_lkup_one_args args = {
@@ -259,14 +263,16 @@ int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh)
 	int err;
 	struct dentry *parent, *h_parent, *h_dentry;
 	struct au_branch *br;
+	struct user_namespace *h_userns;
 
 	parent = dget_parent(dentry);
 	h_parent = au_h_dptr(parent, bindex);
 	br = au_sbr(dentry->d_sb, bindex);
+	h_userns = au_br_userns(br);
 	if (wh)
 		h_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name);
 	else
-		h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent);
+		h_dentry = au_sio_lkup_one(h_userns, &dentry->d_name, h_parent);
 	err = PTR_ERR(h_dentry);
 	if (IS_ERR(h_dentry))
 		goto out;
diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h
index 086f6ccf4b151a..a9068cbb12540e 100644
--- a/fs/aufs/dentry.h
+++ b/fs/aufs/dentry.h
@@ -60,7 +60,8 @@ struct au_do_lookup_args {
 /* dentry.c */
 extern const struct dentry_operations aufs_dop, aufs_dop_noreval;
 struct au_branch;
-struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent);
+struct dentry *au_sio_lkup_one(struct user_namespace *userns, struct qstr *name,
+			       struct dentry *parent);
 int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir,
 		struct dentry *h_parent, struct au_branch *br);
 
diff --git a/fs/aufs/dir.c b/fs/aufs/dir.c
index 44adae19efb1ca..a0206603af125b 100644
--- a/fs/aufs/dir.c
+++ b/fs/aufs/dir.c
@@ -624,12 +624,14 @@ static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg)
 	int err, wkq_err;
 	struct dentry *h_dentry;
 	struct inode *h_inode;
+	struct user_namespace *h_userns;
 
+	h_userns = au_sbr_userns(dentry->d_sb, arg->bindex);
 	h_dentry = au_h_dptr(dentry, arg->bindex);
 	h_inode = d_inode(h_dentry);
 	/* todo: i_mode changes anytime? */
 	inode_lock_shared_nested(h_inode, AuLsc_I_CHILD);
-	err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ);
+	err = au_test_h_perm_sio(h_userns, h_inode, MAY_EXEC | MAY_READ);
 	inode_unlock_shared(h_inode);
 	if (!err)
 		err = do_test_empty(dentry, arg);
diff --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c
index 42bc497e263093..edaae92392f2fc 100644
--- a/fs/aufs/i_op.c
+++ b/fs/aufs/i_op.c
@@ -19,6 +19,7 @@ static int h_permission(struct inode *h_inode, int mask,
 {
 	int err;
 	const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND));
+	struct user_namespace *h_userns;
 
 	err = -EPERM;
 	if (write_mask && IS_IMMUTABLE(h_inode))
@@ -38,19 +39,21 @@ static int h_permission(struct inode *h_inode, int mask,
 	 * - nfs always sets SB_POSIXACL regardless its mount option 'noacl.'
 	 *   in this case, generic_permission() returns -EOPNOTSUPP.
 	 */
+	h_userns = mnt_user_ns(h_path->mnt);
 	if ((write_mask && !au_br_writable(brperm))
 	    || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode)
 		&& write_mask && !(mask & MAY_READ))
 	    || !h_inode->i_op->permission) {
 		/* AuLabel(generic_permission); */
 		/* AuDbg("get_acl %ps\n", h_inode->i_op->get_acl); */
-		err = generic_permission(h_inode, mask);
+		err = generic_permission(h_userns, h_inode, mask);
 		if (err == -EOPNOTSUPP && au_test_nfs_noacl(h_inode))
-			err = h_inode->i_op->permission(h_inode, mask);
+			err = h_inode->i_op->permission(h_userns, h_inode,
+							mask);
 		AuTraceErr(err);
 	} else {
 		/* AuLabel(h_inode->permission); */
-		err = h_inode->i_op->permission(h_inode, mask);
+		err = h_inode->i_op->permission(h_userns, h_inode, mask);
 		AuTraceErr(err);
 	}
 
@@ -63,7 +66,8 @@ static int h_permission(struct inode *h_inode, int mask,
 	return err;
 }
 
-static int aufs_permission(struct inode *inode, int mask)
+static int aufs_permission(struct user_namespace *userns, struct inode *inode,
+			   int mask)
 {
 	int err;
 	aufs_bindex_t bindex, bbot;
@@ -911,18 +915,20 @@ int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia,
 	return err;
 }
 
-static int aufs_setattr(struct dentry *dentry, struct iattr *ia)
+static int aufs_setattr(struct user_namespace *userns, struct dentry *dentry,
+			struct iattr *ia)
 {
 	int err;
 	struct inode *inode, *delegated;
 	struct super_block *sb;
 	struct file *file;
 	struct au_icpup_args *a;
+	struct user_namespace *h_userns;
 
 	inode = d_inode(dentry);
 	IMustLock(inode);
 
-	err = setattr_prepare(dentry, ia);
+	err = setattr_prepare(userns, dentry, ia);
 	if (unlikely(err))
 		goto out;
 
@@ -1015,8 +1021,10 @@ static int aufs_setattr(struct dentry *dentry, struct iattr *ia)
 	 * regardless aufs 'acl' option setting.
 	 * why don't all acl-aware fs call this func from their ->setattr()?
 	 */
-	if (!err && (ia->ia_valid & ATTR_MODE))
-		err = vfsub_acl_chmod(a->h_inode, ia->ia_mode);
+	if (!err && (ia->ia_valid & ATTR_MODE)) {
+		h_userns = mnt_user_ns(a->h_path.mnt);
+		err = vfsub_acl_chmod(h_userns, a->h_inode, ia->ia_mode);
+	}
 	if (!err)
 		au_cpup_attr_changeable(inode);
 
@@ -1078,6 +1086,7 @@ ssize_t au_sxattr(struct dentry *dentry, struct inode *inode,
 	struct super_block *sb;
 	struct au_icpup_args *a;
 	struct inode *h_inode;
+	struct user_namespace *h_userns;
 
 	IMustLock(inode);
 
@@ -1096,23 +1105,25 @@ ssize_t au_sxattr(struct dentry *dentry, struct inode *inode,
 	err = au_h_path_to_set_attr(dentry, a, &h_path);
 	if (unlikely(err))
 		goto out_di;
+	h_userns = mnt_user_ns(h_path.mnt);
 
 	inode_unlock(a->h_inode);
 	switch (arg->type) {
 	case AU_XATTR_SET:
 		AuDebugOn(d_is_negative(h_path.dentry));
-		err = vfsub_setxattr(h_path.dentry,
+		err = vfsub_setxattr(h_userns, h_path.dentry,
 				     arg->u.set.name, arg->u.set.value,
 				     arg->u.set.size, arg->u.set.flags);
 		break;
 	case AU_ACL_SET:
 		err = -EOPNOTSUPP;
 		h_inode = d_inode(h_path.dentry);
-		if (h_inode->i_op->set_acl)
+		if (h_inode->i_op->set_acl) {
 			/* this will call posix_acl_update_mode */
-			err = h_inode->i_op->set_acl(h_inode,
+			err = h_inode->i_op->set_acl(h_userns, h_inode,
 						     arg->u.acl_set.acl,
 						     arg->u.acl_set.type);
+		}
 		break;
 	}
 	if (!err)
@@ -1243,8 +1254,8 @@ int au_h_path_getattr(struct dentry *dentry, struct inode *inode, int force,
 	return err;
 }
 
-static int aufs_getattr(const struct path *path, struct kstat *st,
-			u32 request, unsigned int query)
+static int aufs_getattr(struct user_namespace *userns, const struct path *path,
+			struct kstat *st, u32 request, unsigned int query)
 {
 	int err;
 	unsigned char positive;
@@ -1281,7 +1292,7 @@ static int aufs_getattr(const struct path *path, struct kstat *st,
 	goto out_di;
 
 out_fill:
-	generic_fillattr(inode, st);
+	generic_fillattr(userns, inode, st);
 out_di:
 	di_read_unlock(dentry, AuLock_IR);
 out_si:
diff --git a/fs/aufs/i_op_add.c b/fs/aufs/i_op_add.c
index 853c99e200dadc..b8c8e8cd710cf4 100644
--- a/fs/aufs/i_op_add.c
+++ b/fs/aufs/i_op_add.c
@@ -353,8 +353,8 @@ static int add_simple(struct inode *dir, struct dentry *dentry,
 	return err;
 }
 
-int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
-	       dev_t dev)
+int aufs_mknod(struct user_namespace *userns, struct inode *dir,
+	       struct dentry *dentry, umode_t mode, dev_t dev)
 {
 	struct simple_arg arg = {
 		.type = Mknod,
@@ -366,7 +366,8 @@ int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
 	return add_simple(dir, dentry, &arg);
 }
 
-int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
+int aufs_symlink(struct user_namespace *userns, struct inode *dir,
+		 struct dentry *dentry, const char *symname)
 {
 	struct simple_arg arg = {
 		.type = Symlink,
@@ -375,8 +376,8 @@ int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 	return add_simple(dir, dentry, &arg);
 }
 
-int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		bool want_excl)
+int aufs_create(struct user_namespace *userns, struct inode *dir,
+		struct dentry *dentry, umode_t mode, bool want_excl)
 {
 	struct simple_arg arg = {
 		.type = Creat,
@@ -403,7 +404,8 @@ int au_aopen_or_create(struct inode *dir, struct dentry *dentry,
 	return add_simple(dir, dentry, &arg);
 }
 
-int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+int aufs_tmpfile(struct user_namespace *userns, struct inode *dir,
+		 struct dentry *dentry, umode_t mode)
 {
 	int err;
 	aufs_bindex_t bindex;
@@ -411,6 +413,7 @@ int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
 	struct dentry *parent, *h_parent, *h_dentry;
 	struct inode *h_dir, *inode;
 	struct vfsmount *h_mnt;
+	struct user_namespace *h_userns;
 	struct au_wr_dir_args wr_dir_args = {
 		.force_btgt	= -1,
 		.flags		= AuWrDir_TMPFILE
@@ -457,8 +460,9 @@ int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
 	if (unlikely(err))
 		goto out_parent;
 
+	h_userns = mnt_user_ns(h_mnt);
 	h_parent = au_h_dptr(parent, bindex);
-	h_dentry = vfs_tmpfile(h_parent, mode, /*open_flag*/0);
+	h_dentry = vfs_tmpfile(h_userns, h_parent, mode, /*open_flag*/0);
 	if (IS_ERR(h_dentry)) {
 		err = PTR_ERR(h_dentry);
 		goto out_mnt;
@@ -814,7 +818,8 @@ int aufs_link(struct dentry *src_dentry, struct inode *dir,
 	return err;
 }
 
-int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+int aufs_mkdir(struct user_namespace *userns, struct inode *dir,
+	       struct dentry *dentry, umode_t mode)
 {
 	int err, rerr;
 	aufs_bindex_t bindex;
diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c
index 05f5d4219b414d..b2940e0b329901 100644
--- a/fs/aufs/i_op_del.c
+++ b/fs/aufs/i_op_del.c
@@ -81,6 +81,7 @@ int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
 	umode_t h_mode;
 	struct dentry *h_dentry, *h_latest;
 	struct inode *h_inode;
+	struct user_namespace *h_userns;
 
 	h_dentry = au_h_dptr(dentry, bindex);
 	if (d_really_is_positive(dentry)) {
@@ -118,12 +119,13 @@ int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
 	 * let's try heavy test.
 	 */
 	err = -EACCES;
+	h_userns = au_sbr_userns(dentry->d_sb, bindex);
 	if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1)
-		     && au_test_h_perm(d_inode(h_parent),
+		     && au_test_h_perm(h_userns, d_inode(h_parent),
 				       MAY_EXEC | MAY_WRITE)))
 		goto out;
 
-	h_latest = au_sio_lkup_one(&dentry->d_name, h_parent);
+	h_latest = au_sio_lkup_one(h_userns, &dentry->d_name, h_parent);
 	err = -EIO;
 	if (IS_ERR(h_latest))
 		goto out;
diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c
index 37c52390034a86..54455a762a6175 100644
--- a/fs/aufs/i_op_ren.c
+++ b/fs/aufs/i_op_ren.c
@@ -940,7 +940,8 @@ static void au_ren_rev_dt(int err, struct au_ren_args *a)
 
 /* ---------------------------------------------------------------------- */
 
-int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry,
+int aufs_rename(struct user_namespace *userns,
+		struct inode *_src_dir, struct dentry *_src_dentry,
 		struct inode *_dst_dir, struct dentry *_dst_dentry,
 		unsigned int _flags)
 {
diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c
index c071e525f499a7..b1c846a4ce15b1 100644
--- a/fs/aufs/inode.c
+++ b/fs/aufs/inode.c
@@ -499,18 +499,20 @@ int au_test_ro(struct super_block *sb, aufs_bindex_t bindex,
 	return err;
 }
 
-int au_test_h_perm(struct inode *h_inode, int mask)
+int au_test_h_perm(struct user_namespace *h_userns, struct inode *h_inode,
+		   int mask)
 {
 	if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID))
 		return 0;
-	return inode_permission(h_inode, mask);
+	return inode_permission(h_userns, h_inode, mask);
 }
 
-int au_test_h_perm_sio(struct inode *h_inode, int mask)
+int au_test_h_perm_sio(struct user_namespace *h_userns, struct inode *h_inode,
+		       int mask)
 {
 	if (au_test_nfs(h_inode->i_sb)
 	    && (mask & MAY_WRITE)
 	    && S_ISDIR(h_inode->i_mode))
 		mask |= MAY_READ; /* force permission check */
-	return au_test_h_perm(h_inode, mask);
+	return au_test_h_perm(h_userns, h_inode, mask);
 }
diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h
index 7f1992a3ef5cf2..2c6d710095139f 100644
--- a/fs/aufs/inode.h
+++ b/fs/aufs/inode.h
@@ -124,8 +124,10 @@ int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
 struct inode *au_new_inode(struct dentry *dentry, int must_new);
 int au_test_ro(struct super_block *sb, aufs_bindex_t bindex,
 	       struct inode *inode);
-int au_test_h_perm(struct inode *h_inode, int mask);
-int au_test_h_perm_sio(struct inode *h_inode, int mask);
+int au_test_h_perm(struct user_namespace *h_userns, struct inode *h_inode,
+		   int mask);
+int au_test_h_perm_sio(struct user_namespace *h_userns, struct inode *h_inode,
+		       int mask);
 
 static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex,
 			    ino_t h_ino, unsigned int d_type, ino_t *ino)
@@ -200,18 +202,21 @@ int au_h_path_getattr(struct dentry *dentry, struct inode *inode, int force,
 /* i_op_add.c */
 int au_may_add(struct dentry *dentry, aufs_bindex_t bindex,
 	       struct dentry *h_parent, int isdir);
-int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
-	       dev_t dev);
-int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname);
-int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-		bool want_excl);
+int aufs_mknod(struct user_namespace *userns, struct inode *dir,
+	       struct dentry *dentry, umode_t mode, dev_t dev);
+int aufs_symlink(struct user_namespace *userns, struct inode *dir,
+		 struct dentry *dentry, const char *symname);
+int aufs_create(struct user_namespace *userns, struct inode *dir,
+		struct dentry *dentry, umode_t mode, bool want_excl);
 struct vfsub_aopen_args;
 int au_aopen_or_create(struct inode *dir, struct dentry *dentry,
 		       struct vfsub_aopen_args *args);
-int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode);
+int aufs_tmpfile(struct user_namespace *userns, struct inode *dir,
+		 struct dentry *dentry, umode_t mode);
 int aufs_link(struct dentry *src_dentry, struct inode *dir,
 	      struct dentry *dentry);
-int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
+int aufs_mkdir(struct user_namespace *userns, struct inode *dir,
+	       struct dentry *dentry, umode_t mode);
 
 /* i_op_del.c */
 int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup);
@@ -222,9 +227,10 @@ int aufs_rmdir(struct inode *dir, struct dentry *dentry);
 
 /* i_op_ren.c */
 int au_wbr(struct dentry *dentry, aufs_bindex_t btgt);
-int aufs_rename(struct inode *src_dir, struct dentry *src_dentry,
-		struct inode *dir, struct dentry *dentry,
-		unsigned int flags);
+int aufs_rename(struct user_namespace *userns,
+		struct inode *_src_dir, struct dentry *_src_dentry,
+		struct inode *_dst_dir, struct dentry *_dst_dentry,
+		unsigned int _flags);
 
 /* iinfo.c */
 struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex);
@@ -294,19 +300,20 @@ AuStubVoid(au_plink_half_refresh, struct super_block *sb, aufs_bindex_t br_id);
 
 #ifdef CONFIG_AUFS_XATTR
 /* xattr.c */
-int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags,
+int au_cpup_xattr(struct path *h_dst, struct path *h_src, int ignore_flags,
 		  unsigned int verbose);
 ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size);
 void au_xattr_init(struct super_block *sb);
 #else
-AuStubInt0(au_cpup_xattr, struct dentry *h_dst, struct dentry *h_src,
+AuStubInt0(au_cpup_xattr, struct path *h_dst, struct path *h_src,
 	   int ignore_flags, unsigned int verbose);
 AuStubVoid(au_xattr_init, struct super_block *sb);
 #endif
 
 #ifdef CONFIG_FS_POSIX_ACL
 struct posix_acl *aufs_get_acl(struct inode *inode, int type);
-int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
+int aufs_set_acl(struct user_namespace *userns, struct inode *inode,
+		 struct posix_acl *acl, int type);
 #endif
 
 #if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL)
diff --git a/fs/aufs/posix_acl.c b/fs/aufs/posix_acl.c
index 946c2247e78d11..422315474f8e43 100644
--- a/fs/aufs/posix_acl.c
+++ b/fs/aufs/posix_acl.c
@@ -50,7 +50,8 @@ struct posix_acl *aufs_get_acl(struct inode *inode, int type)
 	return acl;
 }
 
-int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+int aufs_set_acl(struct user_namespace *userns, struct inode *inode,
+		 struct posix_acl *acl, int type)
 {
 	int err;
 	ssize_t ssz;
diff --git a/fs/aufs/super.c b/fs/aufs/super.c
index 589dd01220201b..d252963a87b530 100644
--- a/fs/aufs/super.c
+++ b/fs/aufs/super.c
@@ -1026,7 +1026,10 @@ static void aufs_kill_sb(struct super_block *sb)
 struct file_system_type aufs_fs_type = {
 	.name		= AUFS_FSTYPE,
 	/* a race between rename and others */
-	.fs_flags	= FS_RENAME_DOES_D_MOVE,
+	.fs_flags	= FS_RENAME_DOES_D_MOVE
+				/* untested */
+				/*| FS_ALLOW_IDMAP*/
+				,
 	.mount		= aufs_mount,
 	.kill_sb	= aufs_kill_sb,
 	/* no need to __module_get() and module_put(). */
diff --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c
index fa29c543cc28e3..3d8bb5135f423f 100644
--- a/fs/aufs/vfsub.c
+++ b/fs/aufs/vfsub.c
@@ -231,6 +231,7 @@ int vfsub_create(struct inode *dir, struct path *path, int mode, bool want_excl)
 {
 	int err;
 	struct dentry *d;
+	struct user_namespace *userns;
 
 	IMustLock(dir);
 
@@ -240,9 +241,10 @@ int vfsub_create(struct inode *dir, struct path *path, int mode, bool want_excl)
 	path->dentry = d;
 	if (unlikely(err))
 		goto out;
+	userns = mnt_user_ns(path->mnt);
 
 	lockdep_off();
-	err = vfs_create(dir, path->dentry, mode, want_excl);
+	err = vfs_create(userns, dir, path->dentry, mode, want_excl);
 	lockdep_on();
 	if (!err) {
 		struct path tmp = *path;
@@ -264,6 +266,7 @@ int vfsub_symlink(struct inode *dir, struct path *path, const char *symname)
 {
 	int err;
 	struct dentry *d;
+	struct user_namespace *userns;
 
 	IMustLock(dir);
 
@@ -273,9 +276,10 @@ int vfsub_symlink(struct inode *dir, struct path *path, const char *symname)
 	path->dentry = d;
 	if (unlikely(err))
 		goto out;
+	userns = mnt_user_ns(path->mnt);
 
 	lockdep_off();
-	err = vfs_symlink(dir, path->dentry, symname);
+	err = vfs_symlink(userns, dir, path->dentry, symname);
 	lockdep_on();
 	if (!err) {
 		struct path tmp = *path;
@@ -297,6 +301,7 @@ int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev)
 {
 	int err;
 	struct dentry *d;
+	struct user_namespace *userns;
 
 	IMustLock(dir);
 
@@ -306,9 +311,10 @@ int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev)
 	path->dentry = d;
 	if (unlikely(err))
 		goto out;
+	userns = mnt_user_ns(path->mnt);
 
 	lockdep_off();
-	err = vfs_mknod(dir, path->dentry, mode, dev);
+	err = vfs_mknod(userns, dir, path->dentry, mode, dev);
 	lockdep_on();
 	if (!err) {
 		struct path tmp = *path;
@@ -341,6 +347,7 @@ int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path,
 {
 	int err;
 	struct dentry *d;
+	struct user_namespace *userns;
 
 	IMustLock(dir);
 
@@ -355,9 +362,10 @@ int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path,
 	path->dentry = d;
 	if (unlikely(err))
 		goto out;
+	userns = mnt_user_ns(path->mnt);
 
 	lockdep_off();
-	err = vfs_link(src_dentry, dir, path->dentry, delegated_inode);
+	err = vfs_link(src_dentry, userns, dir, path->dentry, delegated_inode);
 	lockdep_on();
 	if (!err) {
 		struct path tmp = *path;
@@ -383,6 +391,7 @@ int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry,
 		 struct inode **delegated_inode, unsigned int flags)
 {
 	int err;
+	struct renamedata rd;
 	struct path tmp = {
 		.mnt	= path->mnt
 	};
@@ -399,9 +408,16 @@ int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry,
 	if (unlikely(err))
 		goto out;
 
+	rd.old_mnt_userns = mnt_user_ns(path->mnt);
+	rd.old_dir = src_dir;
+	rd.old_dentry = src_dentry;
+	rd.new_mnt_userns = rd.old_mnt_userns;
+	rd.new_dir = dir;
+	rd.new_dentry = path->dentry;
+	rd.delegated_inode = delegated_inode;
+	rd.flags = flags;
 	lockdep_off();
-	err = vfs_rename(src_dir, src_dentry, dir, path->dentry,
-			 delegated_inode, flags);
+	err = vfs_rename(&rd);
 	lockdep_on();
 	if (!err) {
 		int did;
@@ -425,6 +441,7 @@ int vfsub_mkdir(struct inode *dir, struct path *path, int mode)
 {
 	int err;
 	struct dentry *d;
+	struct user_namespace *userns;
 
 	IMustLock(dir);
 
@@ -434,9 +451,10 @@ int vfsub_mkdir(struct inode *dir, struct path *path, int mode)
 	path->dentry = d;
 	if (unlikely(err))
 		goto out;
+	userns = mnt_user_ns(path->mnt);
 
 	lockdep_off();
-	err = vfs_mkdir(dir, path->dentry, mode);
+	err = vfs_mkdir(userns, dir, path->dentry, mode);
 	lockdep_on();
 	if (!err) {
 		struct path tmp = *path;
@@ -458,6 +476,7 @@ int vfsub_rmdir(struct inode *dir, struct path *path)
 {
 	int err;
 	struct dentry *d;
+	struct user_namespace *userns;
 
 	IMustLock(dir);
 
@@ -467,9 +486,10 @@ int vfsub_rmdir(struct inode *dir, struct path *path)
 	path->dentry = d;
 	if (unlikely(err))
 		goto out;
+	userns = mnt_user_ns(path->mnt);
 
 	lockdep_off();
-	err = vfs_rmdir(dir, path->dentry);
+	err = vfs_rmdir(userns, dir, path->dentry);
 	lockdep_on();
 	if (!err) {
 		struct path tmp = {
@@ -627,6 +647,7 @@ int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr,
 	int err;
 	struct inode *h_inode;
 	struct super_block *h_sb;
+	struct user_namespace *h_userns;
 
 	if (!h_file) {
 		err = vfsub_truncate(h_path, length);
@@ -642,8 +663,10 @@ int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr,
 	if (!err)
 		err = security_path_truncate(h_path);
 	if (!err) {
+		h_userns = mnt_user_ns(h_path->mnt);
 		lockdep_off();
-		err = do_truncate(h_path->dentry, length, attr, h_file);
+		err = do_truncate(h_userns, h_path->dentry, length, attr,
+				  h_file);
 		lockdep_on();
 	}
 	lockdep_off();
@@ -672,8 +695,10 @@ static void au_call_vfsub_mkdir(void *args)
 int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode)
 {
 	int err, do_sio, wkq_err;
+	struct user_namespace *userns;
 
-	do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE);
+	userns = mnt_user_ns(path->mnt);
+	do_sio = au_test_h_perm_sio(userns, dir, MAY_EXEC | MAY_WRITE);
 	if (!do_sio) {
 		lockdep_off();
 		err = vfsub_mkdir(dir, path, mode);
@@ -708,8 +733,10 @@ static void au_call_vfsub_rmdir(void *args)
 int vfsub_sio_rmdir(struct inode *dir, struct path *path)
 {
 	int err, do_sio, wkq_err;
+	struct user_namespace *userns;
 
-	do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE);
+	userns = mnt_user_ns(path->mnt);
+	do_sio = au_test_h_perm_sio(userns, dir, MAY_EXEC | MAY_WRITE);
 	if (!do_sio) {
 		lockdep_off();
 		err = vfsub_rmdir(dir, path);
@@ -741,14 +768,16 @@ static void call_notify_change(void *args)
 {
 	struct notify_change_args *a = args;
 	struct inode *h_inode;
+	struct user_namespace *userns;
 
 	h_inode = d_inode(a->path->dentry);
 	IMustLock(h_inode);
 
 	*a->errp = -EPERM;
 	if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) {
+		userns = mnt_user_ns(a->path->mnt);
 		lockdep_off();
-		*a->errp = notify_change(a->path->dentry, a->ia,
+		*a->errp = notify_change(userns, a->path->dentry, a->ia,
 					 a->delegated_inode);
 		lockdep_on();
 		if (!*a->errp)
@@ -805,6 +834,7 @@ static void call_unlink(void *args)
 	struct unlink_args *a = args;
 	struct dentry *d = a->path->dentry;
 	struct inode *h_inode;
+	struct user_namespace *userns;
 	const int stop_sillyrename = (au_test_nfs(d->d_sb)
 				      && au_dcount(d) == 1);
 
@@ -824,8 +854,9 @@ static void call_unlink(void *args)
 		ihold(h_inode);
 	}
 
+	userns = mnt_user_ns(a->path->mnt);
 	lockdep_off();
-	*a->errp = vfs_unlink(a->dir, d, a->delegated_inode);
+	*a->errp = vfs_unlink(userns, a->dir, d, a->delegated_inode);
 	lockdep_on();
 	if (!*a->errp) {
 		struct path tmp = {
diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h
index 7d8993052cd50f..aeed091eca50cd 100644
--- a/fs/aufs/vfsub.h
+++ b/fs/aufs/vfsub.h
@@ -221,17 +221,19 @@ static inline int vfsub_update_time(struct inode *h_inode,
 }
 
 #ifdef CONFIG_FS_POSIX_ACL
-static inline int vfsub_acl_chmod(struct inode *h_inode, umode_t h_mode)
+static inline int vfsub_acl_chmod(struct user_namespace *h_userns,
+				  struct inode *h_inode, umode_t h_mode)
 {
 	int err;
 
-	err = posix_acl_chmod(h_inode, h_mode);
+	err = posix_acl_chmod(h_userns, h_inode, h_mode);
 	if (err == -EOPNOTSUPP)
 		err = 0;
 	return err;
 }
 #else
-AuStubInt0(vfsub_acl_chmod, struct inode *h_inode, umode_t h_mode);
+AuStubInt0(vfsub_acl_chmod, struct user_namespace *h_userns,
+	   struct inode *h_inode, umode_t h_mode);
 #endif
 
 long vfsub_splice_to(struct file *in, loff_t *ppos,
@@ -314,24 +316,26 @@ static inline int vfsub_getattr(const struct path *path, struct kstat *st)
 
 /* ---------------------------------------------------------------------- */
 
-static inline int vfsub_setxattr(struct dentry *dentry, const char *name,
+static inline int vfsub_setxattr(struct user_namespace *userns,
+				 struct dentry *dentry, const char *name,
 				 const void *value, size_t size, int flags)
 {
 	int err;
 
 	lockdep_off();
-	err = vfs_setxattr(dentry, name, value, size, flags);
+	err = vfs_setxattr(userns, dentry, name, value, size, flags);
 	lockdep_on();
 
 	return err;
 }
 
-static inline int vfsub_removexattr(struct dentry *dentry, const char *name)
+static inline int vfsub_removexattr(struct user_namespace *userns,
+				    struct dentry *dentry, const char *name)
 {
 	int err;
 
 	lockdep_off();
-	err = vfs_removexattr(dentry, name);
+	err = vfs_removexattr(userns, dentry, name);
 	lockdep_on();
 
 	return err;
diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c
index 9363954c4b06de..ea28011bc0c3dd 100644
--- a/fs/aufs/whout.c
+++ b/fs/aufs/whout.c
@@ -51,7 +51,8 @@ int au_wh_name_alloc(struct qstr *wh, const struct qstr *name)
  * test if the @wh_name exists under @h_parent.
  * @try_sio specifies the necessary of super-io.
  */
-int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio)
+int au_wh_test(struct user_namespace *h_userns, struct dentry *h_parent,
+	       struct qstr *wh_name, int try_sio)
 {
 	int err;
 	struct dentry *wh_dentry;
@@ -59,7 +60,7 @@ int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio)
 	if (!try_sio)
 		wh_dentry = vfsub_lkup_one(wh_name, h_parent);
 	else
-		wh_dentry = au_sio_lkup_one(wh_name, h_parent);
+		wh_dentry = au_sio_lkup_one(h_userns, wh_name, h_parent);
 	err = PTR_ERR(wh_dentry);
 	if (IS_ERR(wh_dentry)) {
 		if (err == -ENAMETOOLONG)
@@ -88,14 +89,14 @@ int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio)
 /*
  * test if the @h_dentry sets opaque or not.
  */
-int au_diropq_test(struct dentry *h_dentry)
+int au_diropq_test(struct user_namespace *h_userns, struct dentry *h_dentry)
 {
 	int err;
 	struct inode *h_dir;
 
 	h_dir = d_inode(h_dentry);
-	err = au_wh_test(h_dentry, &diropq_name,
-			 au_test_h_perm_sio(h_dir, MAY_EXEC));
+	err = au_wh_test(h_userns, h_dentry, &diropq_name,
+			 au_test_h_perm_sio(h_userns, h_dir, MAY_EXEC));
 	return err;
 }
 
@@ -112,6 +113,7 @@ struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
 	/* strict atomic_t is unnecessary here */
 	static unsigned short cnt;
 	struct qstr qs;
+	struct user_namespace *h_userns;
 
 	BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN);
 
@@ -135,10 +137,11 @@ struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
 	*p++ = '.';
 	AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN);
 
+	h_userns = au_br_userns(br);
 	qs.name = name;
 	for (i = 0; i < 3; i++) {
 		sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++);
-		dentry = au_sio_lkup_one(&qs, h_parent);
+		dentry = au_sio_lkup_one(h_userns, &qs, h_parent);
 		if (IS_ERR(dentry) || d_is_negative(dentry))
 			goto out_name;
 		dput(dentry);
@@ -737,9 +740,12 @@ struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex,
 			     unsigned int flags)
 {
 	struct dentry *diropq, *h_dentry;
+	struct user_namespace *h_userns;
 
+	h_userns = au_sbr_userns(dentry->d_sb, bindex);
 	h_dentry = au_h_dptr(dentry, bindex);
-	if (!au_test_h_perm_sio(d_inode(h_dentry), MAY_EXEC | MAY_WRITE))
+	if (!au_test_h_perm_sio(h_userns, d_inode(h_dentry),
+				MAY_EXEC | MAY_WRITE))
 		diropq = do_diropq(dentry, bindex, flags);
 	else {
 		int wkq_err;
@@ -925,11 +931,13 @@ int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex,
 	struct path h_tmp;
 	struct inode *wh_inode, *h_dir;
 	struct au_branch *br;
+	struct user_namespace *h_userns;
 
 	h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */
 	IMustLock(h_dir);
 
 	br = au_sbr(dir->i_sb, bindex);
+	h_userns = au_br_userns(br);
 	wh_inode = d_inode(wh_dentry);
 	inode_lock_nested(wh_inode, AuLsc_I_CHILD);
 
@@ -937,7 +945,7 @@ int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex,
 	 * someone else might change some whiteouts while we were sleeping.
 	 * it means this whlist may have an obsoleted entry.
 	 */
-	if (!au_test_h_perm_sio(wh_inode, MAY_EXEC | MAY_WRITE))
+	if (!au_test_h_perm_sio(h_userns, wh_inode, MAY_EXEC | MAY_WRITE))
 		err = del_wh_children(wh_dentry, whlist, bindex, br);
 	else {
 		int wkq_err;
diff --git a/fs/aufs/whout.h b/fs/aufs/whout.h
index dc4eb41e70dd34..bc159641173974 100644
--- a/fs/aufs/whout.h
+++ b/fs/aufs/whout.h
@@ -16,8 +16,9 @@
 
 /* whout.c */
 int au_wh_name_alloc(struct qstr *wh, const struct qstr *name);
-int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio);
-int au_diropq_test(struct dentry *h_dentry);
+int au_wh_test(struct user_namespace *h_userns, struct dentry *h_parent,
+	       struct qstr *wh_name, int try_sio);
+int au_diropq_test(struct user_namespace *h_userns, struct dentry *h_dentry);
 struct au_branch;
 struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br,
 			     struct qstr *prefix);
diff --git a/fs/aufs/xattr.c b/fs/aufs/xattr.c
index a71145b741b1a7..cfdd9928c0d242 100644
--- a/fs/aufs/xattr.c
+++ b/fs/aufs/xattr.c
@@ -51,21 +51,26 @@ static int au_xattr_ignore(int err, char *name, unsigned int ignore_flags)
 
 static const int au_xattr_out_of_list = AuBrAttr_ICEX_OTH << 1;
 
-static int au_do_cpup_xattr(struct dentry *h_dst, struct dentry *h_src,
+static int au_do_cpup_xattr(struct path *h_dst, struct path *h_src,
 			    char *name, char **buf, unsigned int ignore_flags,
 			    unsigned int verbose)
 {
 	int err;
 	ssize_t ssz;
 	struct inode *h_idst;
+	struct dentry *h_dst_dentry, *h_src_dentry;
+	struct user_namespace *h_dst_userns, *h_src_userns;
 
-	ssz = vfs_getxattr_alloc(h_src, name, buf, 0, GFP_NOFS);
+	h_src_userns = mnt_user_ns(h_src->mnt);
+	h_src_dentry = h_src->dentry;
+	ssz = vfs_getxattr_alloc(h_src_userns, h_src_dentry, name, buf, 0,
+				 GFP_NOFS);
 	err = ssz;
 	if (unlikely(err <= 0)) {
 		if (err == -ENODATA
 		    || (err == -EOPNOTSUPP
 			&& ((ignore_flags & au_xattr_out_of_list)
-			    || (au_test_nfs_noacl(d_inode(h_src))
+			    || (au_test_nfs_noacl(d_inode(h_src_dentry))
 				&& (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS)
 				    || !strcmp(name,
 					       XATTR_NAME_POSIX_ACL_DEFAULT))))
@@ -77,9 +82,12 @@ static int au_do_cpup_xattr(struct dentry *h_dst, struct dentry *h_src,
 	}
 
 	/* unlock it temporary */
-	h_idst = d_inode(h_dst);
+	h_dst_userns = mnt_user_ns(h_dst->mnt);
+	h_dst_dentry = h_dst->dentry;
+	h_idst = d_inode(h_dst_dentry);
 	inode_unlock(h_idst);
-	err = vfsub_setxattr(h_dst, name, *buf, ssz, /*flags*/0);
+	err = vfsub_setxattr(h_dst_userns, h_dst_dentry, name, *buf, ssz,
+			     /*flags*/0);
 	inode_lock_nested(h_idst, AuLsc_I_CHILD2);
 	if (unlikely(err)) {
 		if (verbose || au_debug_test())
@@ -91,25 +99,28 @@ static int au_do_cpup_xattr(struct dentry *h_dst, struct dentry *h_src,
 	return err;
 }
 
-int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags,
+int au_cpup_xattr(struct path *h_dst, struct path *h_src, int ignore_flags,
 		  unsigned int verbose)
 {
 	int err, unlocked, acl_access, acl_default;
 	ssize_t ssz;
+	struct dentry *h_dst_dentry, *h_src_dentry;
 	struct inode *h_isrc, *h_idst;
 	char *value, *p, *o, *e;
 
 	/* try stopping to update the source inode while we are referencing */
 	/* there should not be the parent-child relationship between them */
-	h_isrc = d_inode(h_src);
-	h_idst = d_inode(h_dst);
+	h_dst_dentry = h_dst->dentry;
+	h_idst = d_inode(h_dst_dentry);
+	h_src_dentry = h_src->dentry;
+	h_isrc = d_inode(h_src_dentry);
 	inode_unlock(h_idst);
 	inode_lock_shared_nested(h_isrc, AuLsc_I_CHILD);
 	inode_lock_nested(h_idst, AuLsc_I_CHILD2);
 	unlocked = 0;
 
 	/* some filesystems don't list POSIX ACL, for example tmpfs */
-	ssz = vfs_listxattr(h_src, NULL, 0);
+	ssz = vfs_listxattr(h_src_dentry, NULL, 0);
 	err = ssz;
 	if (unlikely(err < 0)) {
 		AuTraceErr(err);
@@ -128,7 +139,7 @@ int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags,
 		o = p;
 		if (unlikely(!p))
 			goto out;
-		err = vfs_listxattr(h_src, p, ssz);
+		err = vfs_listxattr(h_src_dentry, p, ssz);
 	}
 	inode_unlock_shared(h_isrc);
 	unlocked = 1;
@@ -242,7 +253,7 @@ static ssize_t au_lgxattr(struct dentry *dentry, struct inode *inode,
 		break;
 	case AU_XATTR_GET:
 		AuDebugOn(d_is_negative(h_path.dentry));
-		err = vfs_getxattr(h_path.dentry,
+		err = vfs_getxattr(mnt_user_ns(h_path.mnt), h_path.dentry,
 				   arg->u.get.name, arg->u.get.value,
 				   arg->u.get.size);
 		break;
@@ -314,6 +325,7 @@ static int au_xattr_get(const struct xattr_handler *handler,
 }
 
 static int au_xattr_set(const struct xattr_handler *handler,
+			struct user_namespace *userns,
 			struct dentry *dentry, struct inode *inode,
 			const char *name, const void *value, size_t size,
 			int flags)
diff --git a/fs/aufs/xino.c b/fs/aufs/xino.c
index 753e92a3d6d784..ee3d3f2e6ac750 100644
--- a/fs/aufs/xino.c
+++ b/fs/aufs/xino.c
@@ -245,7 +245,7 @@ struct file *au_xino_create2(struct super_block *sb, struct path *base,
 	}
 
 	/* no need to mnt_want_write() since we call dentry_open() later */
-	err = vfs_create(dir, path.dentry, 0666, NULL);
+	err = vfs_create(mnt_user_ns(base->mnt), dir, path.dentry, 0666, NULL);
 	if (unlikely(err)) {
 		file = ERR_PTR(err);
 		pr_err("%pd create err %d\n", dentry, err);