Viewing: acl.c
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
* Copyright (c) 2011, 2017, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
*
* Author: Peter Braam <braam@clusterfs.com>
* Author: Phil Schwan <phil@clusterfs.com>
* Author: Andreas Dilger <adilger@clusterfs.com>
*/
#include "llite_internal.h"
static struct posix_acl *
ll_get_acl_common(struct inode *inode, int type, bool rcu)
{
struct ll_inode_info *lli = ll_i2info(inode);
struct posix_acl *acl = NULL;
char *value = NULL;
int len, xtype;
char buf[200];
char *xname;
ENTRY;
if (rcu)
return ERR_PTR(-ECHILD);
if (type == ACL_TYPE_ACCESS &&
test_bit(LLIF_ACL_VALID, &lli->lli_flags))
goto lli_acl;
switch (type) {
case ACL_TYPE_ACCESS:
xname = XATTR_NAME_ACL_ACCESS;
xtype = XATTR_ACL_ACCESS_T;
break;
case ACL_TYPE_DEFAULT:
xname = XATTR_NAME_ACL_DEFAULT;
xtype = XATTR_ACL_DEFAULT_T;
break;
default:
return ERR_PTR(-EINVAL);
}
len = ll_xattr_list(inode, xname, xtype, NULL, 0, OBD_MD_FLXATTR);
if (len > 0) {
if (len > sizeof(buf))
value = kmalloc(len, GFP_NOFS);
else
value = buf;
if (!value)
return ERR_PTR(-ENOMEM);
len = ll_xattr_list(inode, xname, xtype, value, len,
OBD_MD_FLXATTR);
}
if (len > 0)
acl = posix_acl_from_xattr(&init_user_ns, value, len);
else if (len == -ENODATA || len == -ENOSYS || len == -EOPNOTSUPP)
acl = NULL;
else
acl = ERR_PTR(len);
if (value && value != buf)
kfree(value);
if (IS_ERR_OR_NULL(acl))
goto out;
if (type == ACL_TYPE_DEFAULT)
goto out;
if (type == ACL_TYPE_ACCESS)
lli_replace_acl(lli, acl);
lli_acl:
read_lock(&lli->lli_lock);
/* VFS' acl_permission_check->check_acl will release the refcount */
acl = posix_acl_dup(lli->lli_posix_acl);
read_unlock(&lli->lli_lock);
out:
RETURN(acl);
}
/* v6.1-rc1-3-gcac2f8b8d8b5 */
struct posix_acl *ll_get_inode_acl(struct inode *inode, int type, bool rcu)
{
return ll_get_acl_common(inode, type, rcu);
}
struct posix_acl *ll_get_acl(
#ifdef HAVE_ACL_WITH_DENTRY
struct mnt_idmap *map, struct dentry *dentry, int type)
#elif defined HAVE_GET_ACL_RCU_ARG
struct inode *inode, int type, bool rcu)
#else
struct inode *inode, int type)
#endif /* HAVE_GET_ACL_RCU_ARG */
{
#ifdef HAVE_ACL_WITH_DENTRY
struct inode *inode = dentry->d_inode;
#endif
#ifndef HAVE_GET_ACL_RCU_ARG
bool rcu = false;
#endif
return ll_get_acl_common(inode, type, rcu);
}
int ll_set_acl(struct mnt_idmap *map,
#ifdef HAVE_ACL_WITH_DENTRY
struct dentry *dentry,
#else
struct inode *inode,
#endif
struct posix_acl *acl, int type)
{
#ifdef HAVE_ACL_WITH_DENTRY
struct inode *inode = dentry->d_inode;
#endif
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct ptlrpc_request *req = NULL;
const char *name = NULL;
char *value = NULL;
size_t value_size = 0;
int rc = 0;
ENTRY;
switch (type) {
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
break;
case ACL_TYPE_DEFAULT:
name = XATTR_NAME_POSIX_ACL_DEFAULT;
if (!S_ISDIR(inode->i_mode))
rc = acl ? -EACCES : 0;
break;
default:
rc = -EINVAL;
break;
}
if (rc)
return rc;
if (acl) {
value = posix_acl_to_xattr(&init_user_ns, acl, &value_size,
GFP_NOFS);
if (!value)
GOTO(out, rc = -ENOMEM);
}
rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode),
value ? OBD_MD_FLXATTR : OBD_MD_FLXATTRRM,
name, value, value_size, 0, 0, ll_i2projid(inode),
&req);
if (!rc) {
struct ll_inode_info *lli = ll_i2info(inode);
CDEBUG(D_INODE, "inode %p need_sync_to_mds "DFID"\n",
inode, PFID(&lli->lli_fid));
lli->lli_need_sync_to_mds = true;
}
ptlrpc_req_put(req);
out:
kfree(value);
if (rc) {
forget_cached_acl(inode, type);
RETURN(rc);
}
set_cached_acl(inode, type, acl);
if (type == ACL_TYPE_ACCESS)
lli_install_acl(ll_i2info(inode), posix_acl_dup(acl));
RETURN(0);
}