Merge 0fac198def ("Merge tag 'fs.idmapped.overlay.acl.v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux") into android-mainline

Steps on the way to 6.0-rc1

Resolves merge conflicts in:
	fs/overlayfs/inode.c

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: I382394f56b40b1dd317004e1c42a51ebc11a09bb
This commit is contained in:
Greg Kroah-Hartman
2022-08-03 16:27:38 +02:00
13 changed files with 273 additions and 113 deletions

View File

@@ -490,10 +490,6 @@ overlay filesystem and the value of st_ino for filesystem objects may not be
persistent and could change even while the overlay filesystem is mounted, as
summarized in the `Inode properties`_ table above.
4) "idmapped mounts"
When the upper or lower layers are idmapped mounts overlayfs will be mounted
without support for POSIX Access Control Lists (ACLs). This limitation will
eventually be lifted.
Changes to underlying filesystems
---------------------------------

View File

@@ -9620,6 +9620,7 @@ F: drivers/input/misc/ideapad_slidebar.c
IDMAPPED MOUNTS
M: Christian Brauner <brauner@kernel.org>
M: Seth Forshee <sforshee@kernel.org>
L: linux-fsdevel@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git

View File

@@ -963,7 +963,7 @@ ssize_t ksmbd_vfs_getxattr(struct user_namespace *user_ns,
*/
int ksmbd_vfs_setxattr(struct user_namespace *user_ns,
struct dentry *dentry, const char *attr_name,
const void *attr_value, size_t attr_size, int flags)
void *attr_value, size_t attr_size, int flags)
{
int err;

View File

@@ -109,7 +109,7 @@ ssize_t ksmbd_vfs_casexattr_len(struct user_namespace *user_ns,
int attr_name_len);
int ksmbd_vfs_setxattr(struct user_namespace *user_ns,
struct dentry *dentry, const char *attr_name,
const void *attr_value, size_t attr_size, int flags);
void *attr_value, size_t attr_size, int flags);
int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name,
size_t *xattr_stream_name_size, int s_type);
int ksmbd_vfs_remove_xattr(struct user_namespace *user_ns,

View File

@@ -454,23 +454,94 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
return res;
}
/*
* Apply the idmapping of the layer to POSIX ACLs. The caller must pass a clone
* of the POSIX ACLs retrieved from the lower layer to this function to not
* alter the POSIX ACLs for the underlying filesystem.
*/
static void ovl_idmap_posix_acl(struct user_namespace *mnt_userns,
struct posix_acl *acl)
{
for (unsigned int i = 0; i < acl->a_count; i++) {
vfsuid_t vfsuid;
vfsgid_t vfsgid;
struct posix_acl_entry *e = &acl->a_entries[i];
switch (e->e_tag) {
case ACL_USER:
vfsuid = make_vfsuid(mnt_userns, &init_user_ns, e->e_uid);
e->e_uid = vfsuid_into_kuid(vfsuid);
break;
case ACL_GROUP:
vfsgid = make_vfsgid(mnt_userns, &init_user_ns, e->e_gid);
e->e_gid = vfsgid_into_kgid(vfsgid);
break;
}
}
}
/*
* When the relevant layer is an idmapped mount we need to take the idmapping
* of the layer into account and translate any ACL_{GROUP,USER} values
* according to the idmapped mount.
*
* We cannot alter the ACLs returned from the relevant layer as that would
* alter the cached values filesystem wide for the lower filesystem. Instead we
* can clone the ACLs and then apply the relevant idmapping of the layer.
*
* This is obviously only relevant when idmapped layers are used.
*/
struct posix_acl *ovl_get_acl(struct inode *inode, int type, bool rcu)
{
struct inode *realinode = ovl_inode_real(inode);
const struct cred *old_cred;
struct posix_acl *acl;
struct posix_acl *acl, *clone;
struct path realpath;
if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !IS_POSIXACL(realinode))
return NULL;
/* Careful in RCU walk mode */
ovl_i_path_real(inode, &realpath);
if (!realpath.dentry) {
WARN_ON(!rcu);
return ERR_PTR(-ECHILD);
}
if (rcu) {
acl = get_cached_acl_rcu(realinode, type);
} else {
const struct cred *old_cred;
old_cred = ovl_override_creds(inode->i_sb);
acl = get_acl(realinode, type);
ovl_revert_creds(inode->i_sb, old_cred);
}
/*
* If there are no POSIX ACLs, or we encountered an error,
* or the layer isn't idmapped we don't need to do anything.
*/
if (!is_idmapped_mnt(realpath.mnt) || IS_ERR_OR_NULL(acl))
return acl;
/*
* We only get here if the layer is idmapped. So drop out of RCU path
* walk so we can clone the ACLs. There's no need to release the ACLs
* since get_cached_acl_rcu() doesn't take a reference on the ACLs.
*/
if (rcu)
return get_cached_acl_rcu(realinode, type);
return ERR_PTR(-ECHILD);
old_cred = ovl_override_creds(inode->i_sb);
acl = get_acl(realinode, type);
ovl_revert_creds(inode->i_sb, old_cred);
return acl;
clone = posix_acl_clone(acl, GFP_KERNEL);
if (!clone)
clone = ERR_PTR(-ENOMEM);
else
ovl_idmap_posix_acl(mnt_user_ns(realpath.mnt), clone);
/*
* Since we're not in RCU path walk we always need to release the
* original ACLs.
*/
posix_acl_release(acl);
return clone;
}
int ovl_update_time(struct inode *inode, struct timespec64 *ts, int flags)

View File

@@ -249,7 +249,8 @@ static inline int ovl_do_setxattr(struct ovl_fs *ofs, struct dentry *dentry,
const char *name, const void *value,
size_t size, int flags)
{
int err = vfs_setxattr(ovl_upper_mnt_userns(ofs), dentry, name, value, size, flags);
int err = vfs_setxattr(ovl_upper_mnt_userns(ofs), dentry, name,
(void *)value, size, flags);
pr_debug("setxattr(%pd2, \"%s\", \"%*pE\", %zu, %d) = %i\n",
dentry, name, min((int)size, 48), value, size, flags, err);

View File

@@ -1024,9 +1024,6 @@ ovl_posix_acl_xattr_get(const struct xattr_handler *handler,
struct dentry *dentry, struct inode *inode,
const char *name, void *buffer, size_t size)
{
if (!IS_POSIXACL(inode))
return -EOPNOTSUPP;
return ovl_xattr_get(dentry, inode, handler->name, buffer, size);
}
@@ -1042,9 +1039,6 @@ ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
struct posix_acl *acl = NULL;
int err;
if (!IS_POSIXACL(inode))
return -EOPNOTSUPP;
/* Check that everything is OK before copy-up */
if (value) {
acl = posix_acl_from_xattr(&init_user_ns, value, size);
@@ -1987,20 +1981,6 @@ static struct dentry *ovl_get_root(struct super_block *sb,
return root;
}
static bool ovl_has_idmapped_layers(struct ovl_fs *ofs)
{
unsigned int i;
const struct vfsmount *mnt;
for (i = 0; i < ofs->numlayer; i++) {
mnt = ofs->layers[i].mnt;
if (mnt && is_idmapped_mnt(mnt))
return true;
}
return false;
}
static int ovl_fill_super(struct super_block *sb, void *data, int silent)
{
struct path upperpath = { };
@@ -2170,10 +2150,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
sb->s_xattr = ofs->config.userxattr ? ovl_user_xattr_handlers :
ovl_trusted_xattr_handlers;
sb->s_fs_info = ofs;
if (ovl_has_idmapped_layers(ofs))
pr_warn("POSIX ACLs are not yet supported with idmapped layers, mounting without ACL support.\n");
else
sb->s_flags |= SB_POSIXACL;
sb->s_flags |= SB_POSIXACL;
sb->s_iflags |= SB_I_SKIP_SYNC;
err = -ENOMEM;

View File

@@ -199,7 +199,7 @@ EXPORT_SYMBOL(posix_acl_alloc);
/*
* Clone an ACL.
*/
static struct posix_acl *
struct posix_acl *
posix_acl_clone(const struct posix_acl *acl, gfp_t flags)
{
struct posix_acl *clone = NULL;
@@ -213,6 +213,7 @@ posix_acl_clone(const struct posix_acl *acl, gfp_t flags)
}
return clone;
}
EXPORT_SYMBOL_GPL(posix_acl_clone);
/*
* Check if an acl is valid. Returns 0 if it is, or -E... otherwise.
@@ -361,8 +362,8 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode,
{
const struct posix_acl_entry *pa, *pe, *mask_obj;
int found = 0;
kuid_t uid;
kgid_t gid;
vfsuid_t vfsuid;
vfsgid_t vfsgid;
want &= MAY_READ | MAY_WRITE | MAY_EXEC;
@@ -370,30 +371,28 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode,
switch(pa->e_tag) {
case ACL_USER_OBJ:
/* (May have been checked already) */
uid = i_uid_into_mnt(mnt_userns, inode);
if (uid_eq(uid, current_fsuid()))
vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
if (vfsuid_eq_kuid(vfsuid, current_fsuid()))
goto check_perm;
break;
case ACL_USER:
uid = mapped_kuid_fs(mnt_userns,
i_user_ns(inode),
vfsuid = make_vfsuid(mnt_userns, &init_user_ns,
pa->e_uid);
if (uid_eq(uid, current_fsuid()))
if (vfsuid_eq_kuid(vfsuid, current_fsuid()))
goto mask;
break;
case ACL_GROUP_OBJ:
gid = i_gid_into_mnt(mnt_userns, inode);
if (in_group_p(gid)) {
vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
if (vfsgid_in_group_p(vfsgid)) {
found = 1;
if ((pa->e_perm & want) == want)
goto mask;
}
break;
case ACL_GROUP:
gid = mapped_kgid_fs(mnt_userns,
i_user_ns(inode),
vfsgid = make_vfsgid(mnt_userns, &init_user_ns,
pa->e_gid);
if (in_group_p(gid)) {
if (vfsgid_in_group_p(vfsgid)) {
found = 1;
if ((pa->e_perm & want) == want)
goto mask;
@@ -699,7 +698,7 @@ int posix_acl_update_mode(struct user_namespace *mnt_userns,
return error;
if (error == 0)
*acl = NULL;
if (!in_group_p(i_gid_into_mnt(mnt_userns, inode)) &&
if (!vfsgid_in_group_p(i_gid_into_vfsgid(mnt_userns, inode)) &&
!capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))
mode &= ~S_ISGID;
*mode_p = mode;
@@ -710,10 +709,108 @@ EXPORT_SYMBOL(posix_acl_update_mode);
/*
* Fix up the uids and gids in posix acl extended attributes in place.
*/
static int posix_acl_fix_xattr_common(void *value, size_t size)
{
struct posix_acl_xattr_header *header = value;
int count;
if (!header)
return -EINVAL;
if (size < sizeof(struct posix_acl_xattr_header))
return -EINVAL;
if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
return -EINVAL;
count = posix_acl_xattr_count(size);
if (count < 0)
return -EINVAL;
if (count == 0)
return -EINVAL;
return count;
}
void posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,
const struct inode *inode,
void *value, size_t size)
{
struct posix_acl_xattr_header *header = value;
struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
int count;
vfsuid_t vfsuid;
vfsgid_t vfsgid;
kuid_t uid;
kgid_t gid;
if (no_idmapping(mnt_userns, i_user_ns(inode)))
return;
count = posix_acl_fix_xattr_common(value, size);
if (count < 0)
return;
for (end = entry + count; entry != end; entry++) {
switch (le16_to_cpu(entry->e_tag)) {
case ACL_USER:
uid = make_kuid(&init_user_ns, le32_to_cpu(entry->e_id));
vfsuid = make_vfsuid(mnt_userns, &init_user_ns, uid);
entry->e_id = cpu_to_le32(from_kuid(&init_user_ns,
vfsuid_into_kuid(vfsuid)));
break;
case ACL_GROUP:
gid = make_kgid(&init_user_ns, le32_to_cpu(entry->e_id));
vfsgid = make_vfsgid(mnt_userns, &init_user_ns, gid);
entry->e_id = cpu_to_le32(from_kgid(&init_user_ns,
vfsgid_into_kgid(vfsgid)));
break;
default:
break;
}
}
}
void posix_acl_setxattr_idmapped_mnt(struct user_namespace *mnt_userns,
const struct inode *inode,
void *value, size_t size)
{
struct posix_acl_xattr_header *header = value;
struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
int count;
vfsuid_t vfsuid;
vfsgid_t vfsgid;
kuid_t uid;
kgid_t gid;
if (no_idmapping(mnt_userns, i_user_ns(inode)))
return;
count = posix_acl_fix_xattr_common(value, size);
if (count < 0)
return;
for (end = entry + count; entry != end; entry++) {
switch (le16_to_cpu(entry->e_tag)) {
case ACL_USER:
uid = make_kuid(&init_user_ns, le32_to_cpu(entry->e_id));
vfsuid = VFSUIDT_INIT(uid);
uid = from_vfsuid(mnt_userns, &init_user_ns, vfsuid);
entry->e_id = cpu_to_le32(from_kuid(&init_user_ns, uid));
break;
case ACL_GROUP:
gid = make_kgid(&init_user_ns, le32_to_cpu(entry->e_id));
vfsgid = VFSGIDT_INIT(gid);
gid = from_vfsgid(mnt_userns, &init_user_ns, vfsgid);
entry->e_id = cpu_to_le32(from_kgid(&init_user_ns, gid));
break;
default:
break;
}
}
}
static void posix_acl_fix_xattr_userns(
struct user_namespace *to, struct user_namespace *from,
struct user_namespace *mnt_userns,
void *value, size_t size, bool from_user)
void *value, size_t size)
{
struct posix_acl_xattr_header *header = value;
struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
@@ -721,35 +818,18 @@ static void posix_acl_fix_xattr_userns(
kuid_t uid;
kgid_t gid;
if (!value)
return;
if (size < sizeof(struct posix_acl_xattr_header))
return;
if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
return;
count = posix_acl_xattr_count(size);
count = posix_acl_fix_xattr_common(value, size);
if (count < 0)
return;
if (count == 0)
return;
for (end = entry + count; entry != end; entry++) {
switch(le16_to_cpu(entry->e_tag)) {
case ACL_USER:
uid = make_kuid(from, le32_to_cpu(entry->e_id));
if (from_user)
uid = mapped_kuid_user(mnt_userns, &init_user_ns, uid);
else
uid = mapped_kuid_fs(mnt_userns, &init_user_ns, uid);
entry->e_id = cpu_to_le32(from_kuid(to, uid));
break;
case ACL_GROUP:
gid = make_kgid(from, le32_to_cpu(entry->e_id));
if (from_user)
gid = mapped_kgid_user(mnt_userns, &init_user_ns, gid);
else
gid = mapped_kgid_fs(mnt_userns, &init_user_ns, gid);
entry->e_id = cpu_to_le32(from_kgid(to, gid));
break;
default:
@@ -758,34 +838,20 @@ static void posix_acl_fix_xattr_userns(
}
}
void posix_acl_fix_xattr_from_user(struct user_namespace *mnt_userns,
struct inode *inode,
void *value, size_t size)
void posix_acl_fix_xattr_from_user(void *value, size_t size)
{
struct user_namespace *user_ns = current_user_ns();
/* Leave ids untouched on non-idmapped mounts. */
if (no_idmapping(mnt_userns, i_user_ns(inode)))
mnt_userns = &init_user_ns;
if ((user_ns == &init_user_ns) && (mnt_userns == &init_user_ns))
if (user_ns == &init_user_ns)
return;
posix_acl_fix_xattr_userns(&init_user_ns, user_ns, mnt_userns, value,
size, true);
posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size);
}
void posix_acl_fix_xattr_to_user(struct user_namespace *mnt_userns,
struct inode *inode,
void *value, size_t size)
void posix_acl_fix_xattr_to_user(void *value, size_t size)
{
struct user_namespace *user_ns = current_user_ns();
/* Leave ids untouched on non-idmapped mounts. */
if (no_idmapping(mnt_userns, i_user_ns(inode)))
mnt_userns = &init_user_ns;
if ((user_ns == &init_user_ns) && (mnt_userns == &init_user_ns))
if (user_ns == &init_user_ns)
return;
posix_acl_fix_xattr_userns(user_ns, &init_user_ns, mnt_userns, value,
size, false);
posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size);
}
/*

View File

@@ -282,9 +282,15 @@ out:
}
EXPORT_SYMBOL_GPL(__vfs_setxattr_locked);
static inline bool is_posix_acl_xattr(const char *name)
{
return (strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
(strcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0);
}
int
vfs_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
const char *name, const void *value, size_t size, int flags)
const char *name, void *value, size_t size, int flags)
{
struct inode *inode = dentry->d_inode;
struct inode *delegated_inode = NULL;
@@ -292,12 +298,16 @@ vfs_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
int error;
if (size && strcmp(name, XATTR_NAME_CAPS) == 0) {
error = cap_convert_nscap(mnt_userns, dentry, &value, size);
error = cap_convert_nscap(mnt_userns, dentry,
(const void **)&value, size);
if (error < 0)
return error;
size = error;
}
if (size && is_posix_acl_xattr(name))
posix_acl_setxattr_idmapped_mnt(mnt_userns, inode, value, size);
retry_deleg:
inode_lock(inode);
error = __vfs_setxattr_locked(mnt_userns, dentry, name, value, size,
@@ -431,7 +441,10 @@ vfs_getxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
return ret;
}
nolsm:
return __vfs_getxattr(dentry, inode, name, value, size);
error = __vfs_getxattr(dentry, inode, name, value, size);
if (error > 0 && is_posix_acl_xattr(name))
posix_acl_getxattr_idmapped_mnt(mnt_userns, inode, value, size);
return error;
}
EXPORT_SYMBOL_GPL(vfs_getxattr);
@@ -577,8 +590,7 @@ static void setxattr_convert(struct user_namespace *mnt_userns,
if (ctx->size &&
((strcmp(ctx->kname->name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
(strcmp(ctx->kname->name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)))
posix_acl_fix_xattr_from_user(mnt_userns, d_inode(d),
ctx->kvalue, ctx->size);
posix_acl_fix_xattr_from_user(ctx->kvalue, ctx->size);
}
int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
@@ -695,8 +707,7 @@ do_getxattr(struct user_namespace *mnt_userns, struct dentry *d,
if (error > 0) {
if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
(strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
posix_acl_fix_xattr_to_user(mnt_userns, d_inode(d),
ctx->kvalue, error);
posix_acl_fix_xattr_to_user(ctx->kvalue, error);
if (ctx->size && copy_to_user(ctx->value, ctx->kvalue, error))
error = -EFAULT;
} else if (error == -ERANGE && ctx->size >= XATTR_SIZE_MAX) {

View File

@@ -333,6 +333,19 @@ static inline bool vfsuid_has_fsmapping(struct user_namespace *mnt_userns,
return uid_valid(from_vfsuid(mnt_userns, fs_userns, vfsuid));
}
/**
* vfsuid_into_kuid - convert vfsuid into kuid
* @vfsuid: the vfsuid to convert
*
* This can be used when a vfsuid is committed as a kuid.
*
* Return: a kuid with the value of @vfsuid
*/
static inline kuid_t vfsuid_into_kuid(vfsuid_t vfsuid)
{
return AS_KUIDT(vfsuid);
}
/**
* from_vfsgid - map a vfsgid into the filesystem idmapping
* @mnt_userns: the mount's idmapping
@@ -406,6 +419,19 @@ static inline bool vfsgid_has_fsmapping(struct user_namespace *mnt_userns,
return gid_valid(from_vfsgid(mnt_userns, fs_userns, vfsgid));
}
/**
* vfsgid_into_kgid - convert vfsgid into kgid
* @vfsgid: the vfsgid to convert
*
* This can be used when a vfsgid is committed as a kgid.
*
* Return: a kgid with the value of @vfsgid
*/
static inline kgid_t vfsgid_into_kgid(vfsgid_t vfsgid)
{
return AS_KGIDT(vfsgid);
}
/**
* mapped_fsuid - return caller's fsuid mapped up into a mnt_userns
* @mnt_userns: the mount's idmapping

View File

@@ -73,6 +73,7 @@ extern int set_posix_acl(struct user_namespace *, struct inode *, int,
struct posix_acl *);
struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type);
struct posix_acl *posix_acl_clone(const struct posix_acl *acl, gfp_t flags);
#ifdef CONFIG_FS_POSIX_ACL
int posix_acl_chmod(struct user_namespace *, struct inode *, umode_t);

View File

@@ -33,21 +33,31 @@ posix_acl_xattr_count(size_t size)
}
#ifdef CONFIG_FS_POSIX_ACL
void posix_acl_fix_xattr_from_user(struct user_namespace *mnt_userns,
struct inode *inode,
void *value, size_t size);
void posix_acl_fix_xattr_to_user(struct user_namespace *mnt_userns,
struct inode *inode,
void *value, size_t size);
void posix_acl_fix_xattr_from_user(void *value, size_t size);
void posix_acl_fix_xattr_to_user(void *value, size_t size);
void posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,
const struct inode *inode,
void *value, size_t size);
void posix_acl_setxattr_idmapped_mnt(struct user_namespace *mnt_userns,
const struct inode *inode,
void *value, size_t size);
#else
static inline void posix_acl_fix_xattr_from_user(struct user_namespace *mnt_userns,
struct inode *inode,
void *value, size_t size)
static inline void posix_acl_fix_xattr_from_user(void *value, size_t size)
{
}
static inline void posix_acl_fix_xattr_to_user(struct user_namespace *mnt_userns,
struct inode *inode,
void *value, size_t size)
static inline void posix_acl_fix_xattr_to_user(void *value, size_t size)
{
}
static inline void
posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,
const struct inode *inode, void *value,
size_t size)
{
}
static inline void
posix_acl_setxattr_idmapped_mnt(struct user_namespace *mnt_userns,
const struct inode *inode, void *value,
size_t size)
{
}
#endif

View File

@@ -61,7 +61,7 @@ int __vfs_setxattr_locked(struct user_namespace *, struct dentry *,
const char *, const void *, size_t, int,
struct inode **);
int vfs_setxattr(struct user_namespace *, struct dentry *, const char *,
const void *, size_t, int);
void *, size_t, int);
int __vfs_removexattr(struct user_namespace *, struct dentry *, const char *);
int __vfs_removexattr_locked(struct user_namespace *, struct dentry *,
const char *, struct inode **);