]) # LC_BLK_QUEUE_MAX_SEGMENTS
#
+# LC_HAVE_XATTR_HANDLER_FLAGS
+#
+# 2.6.33 added a private flag to xattr_handler
+#
+AC_DEFUN([LC_HAVE_XATTR_HANDLER_FLAGS], [
+LB_CHECK_COMPILE([if 'struct xattr_handler' has flags field],
+xattr_handler_flags, [
+ #include <linux/xattr.h>
+],[
+ struct xattr_handler handler;
+
+ handler.flags = 0;
+],[
+ AC_DEFINE(HAVE_XATTR_HANDLER_FLAGS, 1, [flags field exist])
+])
+]) # LC_HAVE_XATTR_HANDLER_FLAGS
+
+#
# LC_HAVE_DQUOT_FS_DISK_QUOTA
#
# 2.6.34 has quotactl_ops->[sg]et_dqblk that take struct fs_disk_quota
]) # LC_HAVE_CACHE_HEAD_HLIST
#
+# LC_HAVE_XATTR_HANDLER_SIMPLIFIED
+#
+# Kernel version 4.3 commit e409de992e3ea3674393465f07cc71c948edd87a
+# simplified xattr_handler handling by passing in the handler pointer
+#
+AC_DEFUN([LC_HAVE_XATTR_HANDLER_SIMPLIFIED], [
+tmp_flags="$EXTRA_KCFLAGS"
+EXTRA_KCFLAGS="-Werror"
+LB_CHECK_COMPILE([if 'struct xattr_handler' functions pass in handler pointer],
+xattr_handler_simplified, [
+ #include <linux/xattr.h>
+],[
+ struct xattr_handler handler;
+
+ ((struct xattr_handler *)0)->get(&handler, NULL, NULL, NULL, 0);
+ ((struct xattr_handler *)0)->set(&handler, NULL, NULL, NULL, 0, 0);
+],[
+ AC_DEFINE(HAVE_XATTR_HANDLER_SIMPLIFIED, 1, [handler pointer is parameter])
+])
+EXTRA_KCFLAGS="$tmp_flags"
+]) # LC_HAVE_XATTR_HANDLER_SIMPLIFIED
+
+#
# LC_HAVE_LOCKS_LOCK_FILE_WAIT
#
# 4.4 kernel have moved locks API users to
]) # LC_HAVE_IN_COMPAT_SYSCALL
#
+# LC_HAVE_XATTR_HANDLER_INODE_PARAM
+#
+# Kernel version 4.6 commit b296821a7c42fa58baa17513b2b7b30ae66f3336
+# and commit 5930122683dff58f0846b0f0405b4bd598a3ba6a added inode parameter
+# to xattr_handler functions
+#
+AC_DEFUN([LC_HAVE_XATTR_HANDLER_INODE_PARAM], [
+tmp_flags="$EXTRA_KCFLAGS"
+EXTRA_KCFLAGS="-Werror"
+LB_CHECK_COMPILE([if 'struct xattr_handler' functions have inode parameter],
+xattr_handler_inode_param, [
+ #include <linux/xattr.h>
+],[
+ const struct xattr_handler handler;
+
+ ((struct xattr_handler *)0)->get(&handler, NULL, NULL, NULL, NULL, 0);
+ ((struct xattr_handler *)0)->set(&handler, NULL, NULL, NULL, NULL, 0, 0);
+],[
+ AC_DEFINE(HAVE_XATTR_HANDLER_INODE_PARAM, 1, [needs inode parameter])
+])
+EXTRA_KCFLAGS="$tmp_flags"
+]) # LC_HAVE_XATTR_HANDLER_INODE_PARAM
+
+#
# LC_DIRECTIO_2ARGS
#
# Kernel version 4.7 commit c8b8e32d700fe943a935e435ae251364d016c497
]) # LC_FULL_NAME_HASH_3ARGS
#
+# LC_STRUCT_POSIX_ACL_XATTR
+#
+# Kernel version 4.8 commit 2211d5ba5c6c4e972ba6dbc912b2897425ea6621
+# posix_acl: xattr representation cleanups
+#
+AC_DEFUN([LC_STRUCT_POSIX_ACL_XATTR], [
+LB_CHECK_COMPILE([if 'struct posix_acl_xattr_{header,entry}' defined],
+struct_posix_acl_xattr, [
+ #include <linux/fs.h>
+ #include <linux/posix_acl_xattr.h>
+],[
+ struct posix_acl_xattr_header *h = NULL;
+ struct posix_acl_xattr_entry *e;
+ e = (void *)(h + 1);
+],[
+ AC_DEFINE(HAVE_STRUCT_POSIX_ACL_XATTR, 1,
+ [struct posix_acl_xattr_{header,entry} defined])
+])
+]) # LC_STRUCT_POSIX_ACL_XATTR
+
+#
+# LC_IOP_XATTR
+#
+# Kernel version 4.8 commit fd50ecaddf8372a1d96e0daeaac0f93cf04e4d42
+# removed {get,set,remove}xattr inode operations
+#
+AC_DEFUN([LC_IOP_XATTR], [
+LB_CHECK_COMPILE([if 'inode_operations' has {get,set,remove}xattr members],
+inode_ops_xattr, [
+ #include <linux/fs.h>
+],[
+ struct inode_operations iop;
+ iop.setxattr = NULL;
+ iop.getxattr = NULL;
+ iop.removexattr = NULL;
+],[
+ AC_DEFINE(HAVE_IOP_XATTR, 1,
+ [inode_operations has {get,set,remove}xattr members])
+])
+]) # LC_IOP_XATTR
+
+#
# LC_GROUP_INFO_GID
#
# Kernel version 4.9 commit 81243eacfa400f5f7b89f4c2323d0de9982bb0fb
]) # LC_GROUP_INFO_GID
#
-# LC_STRUCT_POSIX_ACL_XATTR
+# LC_VFS_SETXATTR
#
-# Kernel version 4.8 commit 2211d5ba5c6c4e972ba6dbc912b2897425ea6621
-# posix_acl: xattr representation cleanups
+# Kernel version 4.9 commit 5d6c31910bc0713e37628dc0ce677dcb13c8ccf4
+# added __vfs_{get,set,remove}xattr helpers
#
-AC_DEFUN([LC_STRUCT_POSIX_ACL_XATTR], [
-LB_CHECK_COMPILE([if 'struct posix_acl_xattr_{header,entry}' defined],
-struct_posix_acl_xattr, [
- #include <linux/fs.h>
- #include <linux/posix_acl_xattr.h>
+AC_DEFUN([LC_VFS_SETXATTR], [
+LB_CHECK_COMPILE([if '__vfs_setxattr' helper is available],
+vfs_setxattr, [
+ #include <linux/xattr.h>
],[
- struct posix_acl_xattr_header *h = NULL;
- struct posix_acl_xattr_entry *e;
- e = (void *)(h + 1);
+ __vfs_setxattr(NULL, NULL, NULL, NULL, 0, 0);
],[
- AC_DEFINE(HAVE_STRUCT_POSIX_ACL_XATTR, 1,
- [struct posix_acl_xattr_{header,entry} defined])
+ AC_DEFINE(HAVE_VFS_SETXATTR, 1,
+ ['__vfs_setxattr is available])
])
-]) # LC_STRUCT_POSIX_ACL_XATTR
+]) # LC_VFS_SETXATTR
#
# LC_IOP_GENERIC_READLINK
# 2.6.32
LC_BLK_QUEUE_MAX_SEGMENTS
+ # 2.6.33
+ LC_HAVE_XATTR_HANDLER_FLAGS
+
# 2.6.34
LC_HAVE_DQUOT_FS_DISK_QUOTA
LC_HAVE_DQUOT_SUSPEND
# 4.3
LC_HAVE_CACHE_HEAD_HLIST
+ LC_HAVE_XATTR_HANDLER_SIMPLIFIED
# 4.4
LC_HAVE_LOCKS_LOCK_FILE_WAIT
# 4.6
LC_HAVE_IN_COMPAT_SYSCALL
+ LC_HAVE_XATTR_HANDLER_INODE_PARAM
# 4.7
LC_DIRECTIO_2ARGS
LC_D_COMPARE_4ARGS
LC_FULL_NAME_HASH_3ARGS
LC_STRUCT_POSIX_ACL_XATTR
+ LC_IOP_XATTR
# 4.9
LC_GROUP_INFO_GID
+ LC_VFS_SETXATTR
# 4.10
LC_IOP_GENERIC_READLINK
AM_CONDITIONAL(GSS_SSK, test x$enable_ssk = xyes)
AM_CONDITIONAL(LIBPTHREAD, test x$enable_libpthread = xyes)
AM_CONDITIONAL(HAVE_SYSTEMD, test "x$with_systemdsystemunitdir" != "xno")
+AM_CONDITIONAL(XATTR_HANDLER, test "x$lb_cv_compile_xattr_handler_flags" = xyes)
]) # LC_CONDITIONALS
#
# define GET_POSIX_ACL_XATTR_ENTRY(head) ((head)->a_entries)
#endif
+#ifdef HAVE_IOP_XATTR
+#ifdef HAVE_XATTR_HANDLER_FLAGS
+#define ll_setxattr generic_setxattr
+#define ll_getxattr generic_getxattr
+#define ll_removexattr generic_removexattr
+#else
+int ll_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags);
+ssize_t ll_getxattr(struct dentry *dentry, const char *name,
+ void *buf, size_t buf_size);
+int ll_removexattr(struct dentry *dentry, const char *name);
+#endif /* ! HAVE_XATTR_HANDLER_FLAGS */
+#endif /* HAVE_IOP_XATTR */
+
+#ifndef HAVE_VFS_SETXATTR
+const struct xattr_handler *get_xattr_type(const char *name);
+
+#ifdef HAVE_XATTR_HANDLER_FLAGS
+static inline int
+__vfs_setxattr(struct dentry *dentry, struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
+{
+ const struct xattr_handler *handler;
+ int rc;
+
+ handler = get_xattr_type(name);
+ if (!handler)
+ return -ENXIO;
+
+#if defined(HAVE_XATTR_HANDLER_INODE_PARAM)
+ rc = handler->set(handler, dentry, inode, name, value, size,
+ XATTR_CREATE);
+#elif defined(HAVE_XATTR_HANDLER_SIMPLIFIED)
+ rc = handler->set(handler, dentry, name, value, size, XATTR_CREATE);
+#else
+ rc = handler->set(dentry, name, value, size, XATTR_CREATE,
+ handler->flags);
+#endif /* !HAVE_XATTR_HANDLER_INODE_PARAM */
+ return rc;
+}
+#else /* !HAVE_XATTR_HANDLER_FLAGS */
+static inline int
+__vfs_setxattr(struct dentry *dentry, struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
+{
+ return ll_setxattr(dentry, name, value, size, flags);
+}
+#endif /* HAVE_XATTR_HANDLER_FLAGS */
+#endif /* HAVE_VFS_SETXATTR */
+
#ifndef HAVE_IOV_ITER_TRUNCATE
static inline void iov_iter_truncate(struct iov_iter *i, u64 count)
{
MODULES := lustre
lustre-objs := dcache.o dir.o file.o llite_lib.o llite_nfs.o
lustre-objs += rw.o lproc_llite.o namei.o symlink.o llite_mmap.o
-lustre-objs += xattr.o xattr_cache.o
+@XATTR_HANDLER_TRUE@lustre-objs += xattr.o
+@XATTR_HANDLER_FALSE@lustre-objs += xattr26.o
+lustre-objs += xattr_cache.o
lustre-objs += rw26.o super25.o statahead.o xattr_security.o
lustre-objs += glimpse.o
lustre-objs += lcommon_cl.o
EXTRA_DIST := $(lustre-objs:.o=.c) llite_internal.h rw26.c super25.c
EXTRA_DIST += vvp_internal.h range_lock.h
+@XATTR_HANDLER_TRUE@EXTRA_DIST += xattr26.c
+@XATTR_HANDLER_FALSE@EXTRA_DIST += xattr.c
+
@INCLUDE_RULES@
.setattr = ll_setattr,
.getattr = ll_getattr,
.permission = ll_inode_permission,
+#ifdef HAVE_IOP_XATTR
.setxattr = ll_setxattr,
.getxattr = ll_getxattr,
- .listxattr = ll_listxattr,
.removexattr = ll_removexattr,
+#endif
+ .listxattr = ll_listxattr,
.fiemap = ll_fiemap,
#ifdef HAVE_IOP_GET_ACL
.get_acl = ll_get_acl,
}
/* llite/xattr.c */
-int ll_setxattr(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags);
-ssize_t ll_getxattr(struct dentry *dentry, const char *name,
- void *buffer, size_t size);
+extern const struct xattr_handler *ll_xattr_handlers[];
+
+#define XATTR_USER_T 1
+#define XATTR_TRUSTED_T 2
+#define XATTR_SECURITY_T 3
+#define XATTR_ACL_ACCESS_T 4
+#define XATTR_ACL_DEFAULT_T 5
+#define XATTR_LUSTRE_T 6
+#define XATTR_OTHER_T 7
+
ssize_t ll_listxattr(struct dentry *dentry, char *buffer, size_t size);
-int ll_removexattr(struct dentry *dentry, const char *name);
+int ll_xattr_list(struct inode *inode, const char *name, int type,
+ void *buffer, size_t size, u64 valid);
+const struct xattr_handler *get_xattr_type(const char *name);
/**
* Common IO arguments for various VFS I/O interfaces.
int ll_xattr_init(void);
void ll_xattr_fini(void);
-int ll_getxattr_common(struct inode *inode, const char *name,
- void *buffer, size_t size, __u64 valid);
int ll_page_sync_io(const struct lu_env *env, struct cl_io *io,
struct cl_page *page, enum cl_req_type crt);
CDEBUG(D_SUPER, "rootfid "DFID"\n", PFID(&sbi->ll_root_fid));
sb->s_op = &lustre_super_operations;
+#ifdef HAVE_XATTR_HANDLER_FLAGS
+ sb->s_xattr = ll_xattr_handlers;
+#endif
#if THREAD_SIZE >= 8192 /*b=17630*/
sb->s_export_op = &lustre_export_operations;
#endif
*/
int ll_getparent(struct file *file, struct getparent __user *arg)
{
- struct dentry *dentry = file_dentry(file);
struct inode *inode = file_inode(file);
struct linkea_data *ldata;
struct lu_buf buf = LU_BUF_NULL;
if (rc < 0)
GOTO(ldata_free, rc);
- rc = ll_getxattr(dentry, XATTR_NAME_LINK, buf.lb_buf, buf.lb_len);
+#ifdef HAVE_XATTR_HANDLER_FLAGS
+ rc = ll_xattr_list(inode, XATTR_NAME_LINK, XATTR_TRUSTED_T, buf.lb_buf,
+ buf.lb_len, OBD_MD_FLXATTR);
+#else
+ rc = ll_getxattr(file_dentry(file), XATTR_NAME_LINK, buf.lb_buf,
+ buf.lb_len);
+#endif /* HAVE_XATTR_HANDLER_FLAGS */
if (rc < 0)
GOTO(lb_free, rc);
.setattr = ll_setattr,
.getattr = ll_getattr,
.permission = ll_inode_permission,
+#ifdef HAVE_IOP_XATTR
.setxattr = ll_setxattr,
.getxattr = ll_getxattr,
- .listxattr = ll_listxattr,
.removexattr = ll_removexattr,
+#endif
+ .listxattr = ll_listxattr,
#ifdef HAVE_IOP_GET_ACL
.get_acl = ll_get_acl,
#endif
.setattr = ll_setattr,
.getattr = ll_getattr,
.permission = ll_inode_permission,
- .setxattr = ll_setxattr,
- .getxattr = ll_getxattr,
- .listxattr = ll_listxattr,
+#ifdef HAVE_IOP_XATTR
+ .setxattr = ll_setxattr,
+ .getxattr = ll_getxattr,
.removexattr = ll_removexattr,
+#endif
+ .listxattr = ll_listxattr,
#ifdef HAVE_IOP_GET_ACL
- .get_acl = ll_get_acl,
+ .get_acl = ll_get_acl,
#endif
};
#endif
.getattr = ll_getattr,
.permission = ll_inode_permission,
+#ifdef HAVE_IOP_XATTR
.setxattr = ll_setxattr,
.getxattr = ll_getxattr,
- .listxattr = ll_listxattr,
.removexattr = ll_removexattr,
+#endif
+ .listxattr = ll_listxattr,
};
#include "llite_internal.h"
-/* xattr related to IMA(Integrity Measurement Architecture) */
-#ifndef XATTR_NAME_IMA
-#define XATTR_NAME_IMA "security.ima"
-#endif
-#ifndef XATTR_NAME_EVM
-#define XATTR_NAME_EVM "security.evm"
-#endif
-
-#define XATTR_USER_T (1)
-#define XATTR_TRUSTED_T (2)
-#define XATTR_SECURITY_T (3)
-#define XATTR_ACL_ACCESS_T (4)
-#define XATTR_ACL_DEFAULT_T (5)
-#define XATTR_LUSTRE_T (6)
-#define XATTR_OTHER_T (7)
-
-static
-int get_xattr_type(const char *name)
+const struct xattr_handler *get_xattr_type(const char *name)
{
- if (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS))
- return XATTR_ACL_ACCESS_T;
-
- if (!strcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT))
- return XATTR_ACL_DEFAULT_T;
-
- if (!strncmp(name, XATTR_USER_PREFIX,
- sizeof(XATTR_USER_PREFIX) - 1))
- return XATTR_USER_T;
+ int i = 0;
- if (!strncmp(name, XATTR_TRUSTED_PREFIX,
- sizeof(XATTR_TRUSTED_PREFIX) - 1))
- return XATTR_TRUSTED_T;
+ while (ll_xattr_handlers[i]) {
+ size_t len = strlen(ll_xattr_handlers[i]->prefix);
- if (!strncmp(name, XATTR_SECURITY_PREFIX,
- sizeof(XATTR_SECURITY_PREFIX) - 1))
- return XATTR_SECURITY_T;
-
- if (!strncmp(name, XATTR_LUSTRE_PREFIX,
- sizeof(XATTR_LUSTRE_PREFIX) - 1))
- return XATTR_LUSTRE_T;
-
- return XATTR_OTHER_T;
+ if (!strncmp(ll_xattr_handlers[i]->prefix, name, len))
+ return ll_xattr_handlers[i];
+ i++;
+ }
+ return NULL;
}
-static
-int xattr_type_filter(struct ll_sb_info *sbi, int xattr_type)
+static int xattr_type_filter(struct ll_sb_info *sbi,
+ const struct xattr_handler *handler)
{
- if ((xattr_type == XATTR_ACL_ACCESS_T ||
- xattr_type == XATTR_ACL_DEFAULT_T) &&
- !(sbi->ll_flags & LL_SBI_ACL))
- return -EOPNOTSUPP;
+ /* No handler means XATTR_OTHER_T */
+ if (!handler)
+ return -EOPNOTSUPP;
- if (xattr_type == XATTR_USER_T && !(sbi->ll_flags & LL_SBI_USER_XATTR))
- return -EOPNOTSUPP;
- if (xattr_type == XATTR_TRUSTED_T && !cfs_capable(CFS_CAP_SYS_ADMIN))
- return -EPERM;
- if (xattr_type == XATTR_OTHER_T)
+ if ((handler->flags == XATTR_ACL_ACCESS_T ||
+ handler->flags == XATTR_ACL_DEFAULT_T) &&
+ !(sbi->ll_flags & LL_SBI_ACL))
return -EOPNOTSUPP;
- return 0;
+ if (handler->flags == XATTR_USER_T &&
+ !(sbi->ll_flags & LL_SBI_USER_XATTR))
+ return -EOPNOTSUPP;
+
+ if (handler->flags == XATTR_TRUSTED_T &&
+ !capable(CFS_CAP_SYS_ADMIN))
+ return -EPERM;
+
+ return 0;
}
-static
-int ll_setxattr_common(struct inode *inode, const char *name,
- const void *value, size_t size,
- int flags, __u64 valid)
+static int ll_xattr_set_common(const struct xattr_handler *handler,
+ struct dentry *dentry, struct inode *inode,
+ const char *name, const void *value, size_t size,
+ int flags)
{
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct ptlrpc_request *req = NULL;
- int xattr_type, rc;
- const char *pv = value;
- ENTRY;
-
- /*FIXME: enable IMA when the conditions are ready */
- if (strncmp(name, XATTR_NAME_IMA,
- sizeof(XATTR_NAME_IMA)) == 0 ||
- strncmp(name, XATTR_NAME_EVM,
- sizeof(XATTR_NAME_EVM)) == 0)
- return -EOPNOTSUPP;
+ const char *pv = value;
+ char *fullname;
+ u64 valid;
+ int rc;
+ ENTRY;
- xattr_type = get_xattr_type(name);
- rc = xattr_type_filter(sbi, xattr_type);
- if (rc)
- RETURN(rc);
+ if (flags == XATTR_REPLACE) {
+ ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_REMOVEXATTR, 1);
+ valid = OBD_MD_FLXATTRRM;
+ } else {
+ ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_SETXATTR, 1);
+ valid = OBD_MD_FLXATTR;
+ }
+
+ /* FIXME: enable IMA when the conditions are ready */
+ if (handler->flags == XATTR_SECURITY_T &&
+ (!strcmp(name, "ima") || !strcmp(name, "evm")))
+ RETURN(-EOPNOTSUPP);
- if ((xattr_type == XATTR_ACL_ACCESS_T ||
- xattr_type == XATTR_ACL_DEFAULT_T) &&
+ rc = xattr_type_filter(sbi, handler);
+ if (rc)
+ RETURN(rc);
+
+ if ((handler->flags == XATTR_ACL_ACCESS_T ||
+ handler->flags == XATTR_ACL_DEFAULT_T) &&
#ifdef HAVE_INODE_OWNER_OR_CAPABLE
!inode_owner_or_capable(inode))
#else
!is_owner_or_cap(inode))
#endif
- return -EPERM;
+ RETURN(-EPERM);
/* b10667: ignore lustre special xattr for now */
- if (strcmp(name, XATTR_NAME_HSM) == 0 ||
- (xattr_type == XATTR_TRUSTED_T &&
- strcmp(name, XATTR_NAME_LOV) == 0) ||
- (xattr_type == XATTR_LUSTRE_T &&
- strcmp(name, "lustre.lov") == 0))
+ if (!strcmp(name, "hsm") ||
+ ((handler->flags == XATTR_TRUSTED_T && !strcmp(name, "lov")) ||
+ (handler->flags == XATTR_LUSTRE_T && !strcmp(name, "lov"))))
RETURN(0);
/* LU-549: Disable security.selinux when selinux is disabled */
- if (xattr_type == XATTR_SECURITY_T && !selinux_is_enabled() &&
- strcmp(name, "security.selinux") == 0)
+ if (handler->flags == XATTR_SECURITY_T && !selinux_is_enabled() &&
+ strcmp(name, "selinux") == 0)
RETURN(-EOPNOTSUPP);
- /* In user.* namespace, only regular files and directories can have
- * extended attributes. */
- if (xattr_type == XATTR_USER_T) {
+ /*
+ * In user.* namespace, only regular files and directories can have
+ * extended attributes.
+ */
+ if (handler->flags == XATTR_USER_T) {
if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
RETURN(-EPERM);
}
- rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode), valid, name, pv,
- size, 0, flags, ll_i2suppgid(inode), &req);
- if (rc) {
- if (rc == -EOPNOTSUPP && xattr_type == XATTR_USER_T) {
- LCONSOLE_INFO("Disabling user_xattr feature because "
- "it is not supported on the server\n");
+ fullname = kasprintf(GFP_KERNEL, "%s%s", handler->prefix, name);
+ if (!fullname)
+ RETURN(-ENOMEM);
+
+ rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode), valid, fullname,
+ pv, size, 0, flags, ll_i2suppgid(inode), &req);
+ kfree(fullname);
+ if (rc) {
+ if (rc == -EOPNOTSUPP && handler->flags == XATTR_USER_T) {
+ LCONSOLE_INFO("Disabling user_xattr feature because it is not supported on the server\n");
sbi->ll_flags &= ~LL_SBI_USER_XATTR;
}
- RETURN(rc);
+ RETURN(rc);
}
ptlrpc_req_finished(req);
- RETURN(0);
+ RETURN(0);
}
-static int get_hsm_state(struct inode *inode, __u32 *hus_states)
+static int get_hsm_state(struct inode *inode, u32 *hus_states)
{
struct md_op_data *op_data;
struct hsm_user_state *hus;
int rc;
OBD_ALLOC_PTR(hus);
- if (hus == NULL)
+ if (!hus)
return -ENOMEM;
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
if (!IS_ERR(op_data)) {
rc = obd_iocontrol(LL_IOC_HSM_STATE_GET, ll_i2mdexp(inode),
sizeof(*op_data), op_data, NULL);
- if (rc == 0)
+ if (!rc)
*hus_states = hus->hus_states;
else
CDEBUG(D_VFSTRACE, "obd_iocontrol failed. rc = %d\n",
{
struct lov_comp_md_v1 *comp_v1 = (struct lov_comp_md_v1 *)lump;
struct lov_user_md *v1 = lump;
- bool release_checked = false;
bool need_clear_release = false;
- __u16 entry_count = 1;
+ bool release_checked = false;
bool is_composite = false;
+ u16 entry_count = 1;
int rc = 0;
int i;
- if (lump == NULL)
+ if (!lump)
return 0;
if (lump->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
}
for (i = 0; i < entry_count; i++) {
- if (lump->lmm_magic == LOV_USER_MAGIC_COMP_V1)
- v1 = (struct lov_user_md *)((char *)comp_v1 +
- comp_v1->lcm_entries[i].lcme_offset);
+ if (lump->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
+ void *ptr = comp_v1;
- /* Attributes that are saved via getxattr will always
- * have the stripe_offset as 0. Instead, the MDS
+ ptr += comp_v1->lcm_entries[i].lcme_offset;
+ v1 = (struct lov_user_md *)ptr;
+ }
+
+ /*
+ * Attributes that are saved via getxattr will always
+ * have the stripe_offset as 0. Instead, the MDS
* should be allowed to pick the starting OST index.
- * b=17846 */
+ * b=17846
+ */
if (!is_composite && v1->lmm_stripe_offset == 0)
v1->lmm_stripe_offset = -1;
/* Avoid anyone directly setting the RELEASED flag. */
if (v1->lmm_pattern & LOV_PATTERN_F_RELEASED) {
if (!release_checked) {
- __u32 state = HS_NONE;
+ u32 state = HS_NONE;
+
rc = get_hsm_state(inode, &state);
if (rc)
return rc;
+
if (!(state & HS_ARCHIVED))
need_clear_release = true;
release_checked = true;
return rc;
}
-int ll_setstripe_ea(struct dentry *dentry, struct lov_user_md *lump,
- size_t size)
+static int ll_setstripe_ea(struct dentry *dentry, struct lov_user_md *lump,
+ size_t size)
{
struct inode *inode = dentry->d_inode;
int rc = 0;
+ /*
+ * It is possible to set an xattr to a "" value of zero size.
+ * For this case we are going to treat it as a removal.
+ */
+ if (!size && lump)
+ lump = NULL;
+
rc = ll_adjust_lum(inode, lump);
if (rc)
return rc;
- if (lump != NULL && S_ISREG(inode->i_mode)) {
- __u64 it_flags = FMODE_WRITE;
- int lum_size;
+ if (lump && S_ISREG(inode->i_mode)) {
+ u64 it_flags = FMODE_WRITE;
+ ssize_t lum_size;
lum_size = ll_lov_user_md_size(lump);
if (lum_size < 0 || size < lum_size)
/**
* b=10667: ignore -EEXIST.
* Silently eat error on setting trusted.lov/lustre.lov
- * attribute for SuSE 9, it added default option to copy
- * all attributes in 'cp' command. rsync, tar --xattrs
- * also will try to set LOVEA for existing files.
+ * attribute for platforms that added the default option
+ * to copy all attributes in 'cp' command. Both rsync and
+ * tar --xattrs also will try to set LOVEA for existing
+ * files.
*/
if (rc == -EEXIST)
rc = 0;
} else if (S_ISDIR(inode->i_mode)) {
+ if (size != 0 && size < sizeof(struct lov_user_md))
+ return -EINVAL;
+
rc = ll_dir_setstripe(inode, lump, 0);
}
return rc;
}
-int ll_setxattr(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags)
+static int ll_xattr_set(const struct xattr_handler *handler,
+ struct dentry *dentry, struct inode *inode,
+ const char *name, const void *value, size_t size,
+ int flags)
{
- struct inode *inode = dentry->d_inode;
-
LASSERT(inode);
LASSERT(name);
- CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), xattr %s\n",
+ CDEBUG(D_VFSTRACE, "VFS Op:inode=" DFID "(%p), xattr %s\n",
PFID(ll_inode2fid(inode)), inode, name);
- ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_SETXATTR, 1);
-
/* lustre/trusted.lov.xxx would be passed through xattr API */
- if (strcmp(name, XATTR_NAME_LOV) == 0 ||
- strcmp(name, XATTR_LUSTRE_LOV) == 0)
- return ll_setstripe_ea(dentry, (struct lov_user_md *)value,
- size);
- else if (strcmp(name, XATTR_NAME_LMA) == 0 ||
- strcmp(name, XATTR_NAME_LINK) == 0)
- return 0;
-
- return ll_setxattr_common(inode, name, value, size, flags,
- OBD_MD_FLXATTR);
-}
+ if (!strcmp(name, "lov")) {
+ int op_type = flags == XATTR_REPLACE ? LPROC_LL_REMOVEXATTR :
+ LPROC_LL_SETXATTR;
-int ll_removexattr(struct dentry *dentry, const char *name)
-{
- struct inode *inode = dentry->d_inode;
+ ll_stats_ops_tally(ll_i2sbi(inode), op_type, 1);
- LASSERT(inode);
- LASSERT(name);
+ return ll_setstripe_ea(dentry, (struct lov_user_md *)value,
+ size);
+ } else if (!strcmp(name, "lma") || !strcmp(name, "link")) {
+ int op_type = flags == XATTR_REPLACE ? LPROC_LL_REMOVEXATTR :
+ LPROC_LL_SETXATTR;
- CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), xattr %s\n",
- PFID(ll_inode2fid(inode)), inode, name);
+ ll_stats_ops_tally(ll_i2sbi(inode), op_type, 1);
+ return 0;
+ }
- ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_REMOVEXATTR, 1);
- return ll_setxattr_common(inode, name, NULL, 0, 0,
- OBD_MD_FLXATTRRM);
+ return ll_xattr_set_common(handler, dentry, inode, name, value, size,
+ flags);
}
-int ll_getxattr_common(struct inode *inode, const char *name,
- void *buffer, size_t size, __u64 valid)
+int ll_xattr_list(struct inode *inode, const char *name, int type, void *buffer,
+ size_t size, u64 valid)
{
+ struct ll_inode_info *lli = ll_i2info(inode);
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct ptlrpc_request *req = NULL;
struct mdt_body *body;
- int xattr_type, rc;
void *xdata;
- struct ll_inode_info *lli = ll_i2info(inode);
- ENTRY;
-
- CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n",
- PFID(ll_inode2fid(inode)), inode);
-
- /* listxattr have slightly different behavior from of ext3:
- * without 'user_xattr' ext3 will list all xattr names but
- * filtered out "^user..*"; we list them all for simplicity.
- */
- if (!name) {
- xattr_type = XATTR_OTHER_T;
- goto do_getxattr;
- }
-
- xattr_type = get_xattr_type(name);
- rc = xattr_type_filter(sbi, xattr_type);
- if (rc)
- RETURN(rc);
-
- /* LU-549: Disable security.selinux when selinux is disabled */
- if (xattr_type == XATTR_SECURITY_T && !selinux_is_enabled() &&
- strcmp(name, "security.selinux") == 0)
- RETURN(-EOPNOTSUPP);
-
-#ifdef CONFIG_FS_POSIX_ACL
- /* posix acl is under protection of LOOKUP lock. when calling to this,
- * we just have path resolution to the target inode, so we have great
- * chance that cached ACL is uptodate.
- */
- if (xattr_type == XATTR_ACL_ACCESS_T) {
- struct posix_acl *acl;
-
- spin_lock(&lli->lli_lock);
- acl = posix_acl_dup(lli->lli_posix_acl);
- spin_unlock(&lli->lli_lock);
-
- if (!acl)
- RETURN(-ENODATA);
-
- rc = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
- posix_acl_release(acl);
- RETURN(rc);
- }
- if (xattr_type == XATTR_ACL_DEFAULT_T && !S_ISDIR(inode->i_mode))
- RETURN(-ENODATA);
-#endif
+ int rc;
+ ENTRY;
-do_getxattr:
- if (sbi->ll_xattr_cache_enabled &&
- xattr_type != XATTR_ACL_ACCESS_T &&
- (xattr_type != XATTR_SECURITY_T ||
- strcmp(name, "security.selinux") != 0)) {
+ if (sbi->ll_xattr_cache_enabled && type != XATTR_ACL_ACCESS_T &&
+ (type != XATTR_SECURITY_T || strcmp(name, "security.selinux"))) {
rc = ll_xattr_cache_get(inode, name, buffer, size, valid);
if (rc == -EAGAIN)
goto getxattr_nocache;
GOTO(out_xattr, rc);
/* Add "system.posix_acl_access" to the list */
- if (lli->lli_posix_acl != NULL && valid & OBD_MD_FLXATTRLS) {
+ if (lli->lli_posix_acl && valid & OBD_MD_FLXATTRLS) {
if (size == 0) {
rc += sizeof(XATTR_NAME_ACL_ACCESS);
} else if (size - rc >= sizeof(XATTR_NAME_ACL_ACCESS)) {
} else {
getxattr_nocache:
rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode),
- valid, name, NULL, 0, size, 0, &req);
-
+ valid, name, NULL, 0, size, 0, &req);
if (rc < 0)
GOTO(out_xattr, rc);
EXIT;
out_xattr:
- if (rc == -EOPNOTSUPP && xattr_type == XATTR_USER_T) {
+ if (rc == -EOPNOTSUPP && type == XATTR_USER_T) {
LCONSOLE_INFO("%s: disabling user_xattr feature because "
"it is not supported on the server: rc = %d\n",
ll_get_fsname(inode->i_sb, NULL, 0), rc);
return rc;
}
+static int ll_xattr_get_common(const struct xattr_handler *handler,
+ struct dentry *dentry,
+ struct inode *inode,
+ const char *name, void *buffer, size_t size)
+{
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+ char *fullname;
+ int rc;
+
+ ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_GETXATTR, 1);
+
+ rc = xattr_type_filter(sbi, handler);
+ if (rc)
+ RETURN(rc);
+
+ /* LU-549: Disable security.selinux when selinux is disabled */
+ if (handler->flags == XATTR_SECURITY_T && !selinux_is_enabled() &&
+ !strcmp(name, "selinux"))
+ RETURN(-EOPNOTSUPP);
+
+#ifdef CONFIG_FS_POSIX_ACL
+ /* posix acl is under protection of LOOKUP lock. when calling to this,
+ * we just have path resolution to the target inode, so we have great
+ * chance that cached ACL is uptodate.
+ */
+ if (handler->flags == XATTR_ACL_ACCESS_T) {
+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct posix_acl *acl;
+
+ spin_lock(&lli->lli_lock);
+ acl = posix_acl_dup(lli->lli_posix_acl);
+ spin_unlock(&lli->lli_lock);
+
+ if (!acl)
+ RETURN(-ENODATA);
+
+ rc = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
+ posix_acl_release(acl);
+ RETURN(rc);
+ }
+ if (handler->flags == XATTR_ACL_DEFAULT_T && !S_ISDIR(inode->i_mode))
+ RETURN(-ENODATA);
+#endif
+
+ fullname = kasprintf(GFP_KERNEL, "%s%s", handler->prefix, name);
+ if (!fullname)
+ RETURN(-ENOMEM);
+
+ rc = ll_xattr_list(inode, fullname, handler->flags, buffer, size,
+ OBD_MD_FLXATTR);
+ kfree(fullname);
+ return rc;
+}
+
static ssize_t ll_getxattr_lov(struct inode *inode, void *buf, size_t buf_size)
{
ssize_t rc;
if (S_ISREG(inode->i_mode)) {
struct cl_object *obj = ll_i2info(inode)->lli_clob;
- struct lu_env *env;
struct cl_layout cl = {
.cl_buf.lb_buf = buf,
.cl_buf.lb_len = buf_size,
};
- __u16 refcheck;
+ struct lu_env *env;
+ u16 refcheck;
- if (obj == NULL)
+ if (!obj)
RETURN(-ENODATA);
env = cl_env_get(&refcheck);
if (rc < 0)
GOTO(out_env, rc);
- if (cl.cl_size == 0)
+ if (!cl.cl_size)
GOTO(out_env, rc = -ENODATA);
rc = cl.cl_size;
- if (buf_size == 0)
+ if (!buf_size)
GOTO(out_env, rc);
- LASSERT(buf != NULL && rc <= buf_size);
+ LASSERT(buf && rc <= buf_size);
- /* Do not return layout gen for getxattr() since
+ /*
+ * Do not return layout gen for getxattr() since
* otherwise it would confuse tar --xattr by
* recognizing layout gen as stripe offset when the
- * file is restored. See LU-2809. */
+ * file is restored. See LU-2809.
+ */
if (((struct lov_mds_md *)buf)->lmm_magic == LOV_MAGIC_COMP_V1)
goto out_env;
RETURN(rc);
} else if (S_ISDIR(inode->i_mode)) {
+ struct ptlrpc_request *req = NULL;
struct lov_mds_md *lmm = NULL;
int lmm_size = 0;
- struct ptlrpc_request *req = NULL;
rc = ll_dir_getstripe(inode, (void **)&lmm, &lmm_size,
&req, 0);
if (rc < 0)
GOTO(out_req, rc);
- if (buf_size == 0)
+ if (!buf_size)
GOTO(out_req, rc = lmm_size);
if (buf_size < lmm_size)
memcpy(buf, lmm, lmm_size);
GOTO(out_req, rc = lmm_size);
out_req:
- if (req != NULL)
+ if (req)
ptlrpc_req_finished(req);
return rc;
}
}
-ssize_t ll_getxattr(struct dentry *dentry, const char *name, void *buf,
- size_t buf_size)
+static int ll_xattr_get(const struct xattr_handler *handler,
+ struct dentry *dentry, struct inode *inode,
+ const char *name, void *buffer, size_t size)
{
- struct inode *inode = dentry->d_inode;
-
LASSERT(inode);
LASSERT(name);
CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), xattr %s\n",
PFID(ll_inode2fid(inode)), inode, name);
- ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_GETXATTR, 1);
+ if (!strcmp(name, "lov")) {
+ ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_GETXATTR, 1);
- if (strcmp(name, XATTR_LUSTRE_LOV) == 0 ||
- strcmp(name, XATTR_NAME_LOV) == 0)
- return ll_getxattr_lov(inode, buf, buf_size);
- else
- return ll_getxattr_common(inode, name, buf, buf_size,
- OBD_MD_FLXATTR);
+ return ll_getxattr_lov(inode, buffer, size);
+ }
+
+ return ll_xattr_get_common(handler, dentry, inode, name, buffer, size);
}
-ssize_t ll_listxattr(struct dentry *dentry, char *buf, size_t buf_size)
+ssize_t ll_listxattr(struct dentry *dentry, char *buffer, size_t size)
{
struct inode *inode = dentry->d_inode;
struct ll_sb_info *sbi = ll_i2sbi(inode);
ssize_t rc, rc2;
size_t len, rem;
+ LASSERT(inode);
+
CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n",
PFID(ll_inode2fid(inode)), inode);
ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_LISTXATTR, 1);
- rc = ll_getxattr_common(inode, NULL, buf, buf_size, OBD_MD_FLXATTRLS);
+ rc = ll_xattr_list(inode, NULL, XATTR_OTHER_T, buffer, size,
+ OBD_MD_FLXATTRLS);
if (rc < 0)
RETURN(rc);
- /* If we're being called to get the size of the xattr list
- * (buf_size == 0) then just assume that a lustre.lov xattr
- * exists. */
- if (buf_size == 0)
+ /*
+ * If we're being called to get the size of the xattr list
+ * (size == 0) then just assume that a lustre.lov xattr
+ * exists.
+ */
+ if (!size)
RETURN(rc + sizeof(XATTR_LUSTRE_LOV));
- xattr_name = buf;
+ xattr_name = buffer;
rem = rc;
while (rem > 0) {
len = strnlen(xattr_name, rem - 1) + 1;
rem -= len;
- if (xattr_type_filter(sbi, get_xattr_type(xattr_name)) == 0) {
+ if (!xattr_type_filter(sbi, get_xattr_type(xattr_name))) {
/* Skip OK xattr type, leave it in buffer. */
xattr_name += len;
continue;
}
- /* Move up remaining xattrs in buffer removing the
- * xattr that is not OK. */
+ /*
+ * Move up remaining xattrs in buffer
+ * removing the xattr that is not OK.
+ */
memmove(xattr_name, xattr_name + len, rem);
rc -= len;
}
if (rc2 < 0)
RETURN(rc2);
- if (buf_size < rc + sizeof(XATTR_LUSTRE_LOV))
+ if (size < rc + sizeof(XATTR_LUSTRE_LOV))
RETURN(-ERANGE);
- memcpy(buf + rc, XATTR_LUSTRE_LOV, sizeof(XATTR_LUSTRE_LOV));
+ memcpy(buffer + rc, XATTR_LUSTRE_LOV, sizeof(XATTR_LUSTRE_LOV));
RETURN(rc + sizeof(XATTR_LUSTRE_LOV));
}
+
+#ifdef HAVE_XATTR_HANDLER_SIMPLIFIED
+static int ll_xattr_get_common_4_3(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
+{
+ return ll_xattr_get_common(handler, dentry, dentry->d_inode, name,
+ buffer, size);
+}
+
+static int ll_xattr_get_4_3(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
+{
+ return ll_xattr_get(handler, dentry, dentry->d_inode, name, buffer,
+ size);
+}
+
+static int ll_xattr_set_common_4_3(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
+{
+ return ll_xattr_set_common(handler, dentry, dentry->d_inode, name,
+ value, size, flags);
+}
+
+static int ll_xattr_set_4_3(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
+{
+ return ll_xattr_set(handler, dentry, dentry->d_inode, name, value,
+ size, flags);
+}
+
+#elif !defined(HAVE_XATTR_HANDLER_INODE_PARAM)
+const struct xattr_handler *get_xattr_handler(int handler_flag)
+{
+ int i = 0;
+
+ while (ll_xattr_handlers[i]) {
+ if (ll_xattr_handlers[i]->flags == handler_flag)
+ return ll_xattr_handlers[i];
+ i++;
+ }
+ return NULL;
+}
+
+static int ll_xattr_get_common_3_11(struct dentry *dentry, const char *name,
+ void *buffer, size_t size, int handler_flags)
+{
+ const struct xattr_handler *handler = get_xattr_handler(handler_flags);
+
+ if (!handler)
+ return -ENXIO;
+
+ return ll_xattr_get_common(handler, dentry, dentry->d_inode, name,
+ buffer, size);
+}
+
+static int ll_xattr_get_3_11(struct dentry *dentry, const char *name,
+ void *buffer, size_t size, int handler_flags)
+{
+ const struct xattr_handler *handler = get_xattr_handler(handler_flags);
+
+ if (!handler)
+ return -ENXIO;
+
+ return ll_xattr_get(handler, dentry, dentry->d_inode, name, buffer,
+ size);
+}
+
+static int ll_xattr_set_common_3_11(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags,
+ int handler_flags)
+{
+ const struct xattr_handler *handler = get_xattr_handler(handler_flags);
+
+ if (!handler)
+ return -ENXIO;
+
+ return ll_xattr_set_common(handler, dentry, dentry->d_inode, name,
+ value, size, flags);
+}
+
+static int ll_xattr_set_3_11(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags,
+ int handler_flags)
+{
+ const struct xattr_handler *handler = get_xattr_handler(handler_flags);
+
+ if (!handler)
+ return -ENXIO;
+
+ return ll_xattr_set(handler, dentry, dentry->d_inode, name, value,
+ size, flags);
+}
+#endif
+
+static const struct xattr_handler ll_user_xattr_handler = {
+ .prefix = XATTR_USER_PREFIX,
+ .flags = XATTR_USER_T,
+#if defined(HAVE_XATTR_HANDLER_SIMPLIFIED)
+ .get = ll_xattr_get_common_4_3,
+ .set = ll_xattr_set_common_4_3,
+#elif !defined(HAVE_XATTR_HANDLER_INODE_PARAM)
+ .get = ll_xattr_get_common_3_11,
+ .set = ll_xattr_set_common_3_11,
+#else
+ .get = ll_xattr_get_common,
+ .set = ll_xattr_set_common,
+#endif
+};
+
+static const struct xattr_handler ll_trusted_xattr_handler = {
+ .prefix = XATTR_TRUSTED_PREFIX,
+ .flags = XATTR_TRUSTED_T,
+#if defined(HAVE_XATTR_HANDLER_SIMPLIFIED)
+ .get = ll_xattr_get_4_3,
+ .set = ll_xattr_set_4_3,
+#elif !defined(HAVE_XATTR_HANDLER_INODE_PARAM)
+ .get = ll_xattr_get_3_11,
+ .set = ll_xattr_set_3_11,
+#else
+ .get = ll_xattr_get,
+ .set = ll_xattr_set,
+#endif
+};
+
+static const struct xattr_handler ll_security_xattr_handler = {
+ .prefix = XATTR_SECURITY_PREFIX,
+ .flags = XATTR_SECURITY_T,
+#if defined(HAVE_XATTR_HANDLER_SIMPLIFIED)
+ .get = ll_xattr_get_common_4_3,
+ .set = ll_xattr_set_common_4_3,
+#elif !defined(HAVE_XATTR_HANDLER_INODE_PARAM)
+ .get = ll_xattr_get_common_3_11,
+ .set = ll_xattr_set_common_3_11,
+#else
+ .get = ll_xattr_get_common,
+ .set = ll_xattr_set_common,
+#endif
+};
+
+static const struct xattr_handler ll_acl_access_xattr_handler = {
+ .prefix = XATTR_NAME_POSIX_ACL_ACCESS,
+ .flags = XATTR_ACL_ACCESS_T,
+#if defined(HAVE_XATTR_HANDLER_SIMPLIFIED)
+ .get = ll_xattr_get_common_4_3,
+ .set = ll_xattr_set_common_4_3,
+#elif !defined(HAVE_XATTR_HANDLER_INODE_PARAM)
+ .get = ll_xattr_get_common_3_11,
+ .set = ll_xattr_set_common_3_11,
+#else
+ .get = ll_xattr_get_common,
+ .set = ll_xattr_set_common,
+#endif
+};
+
+static const struct xattr_handler ll_acl_default_xattr_handler = {
+ .prefix = XATTR_NAME_POSIX_ACL_DEFAULT,
+ .flags = XATTR_ACL_DEFAULT_T,
+#if defined(HAVE_XATTR_HANDLER_SIMPLIFIED)
+ .get = ll_xattr_get_common_4_3,
+ .set = ll_xattr_set_common_4_3,
+#elif !defined(HAVE_XATTR_HANDLER_INODE_PARAM)
+ .get = ll_xattr_get_common_3_11,
+ .set = ll_xattr_set_common_3_11,
+#else
+ .get = ll_xattr_get_common,
+ .set = ll_xattr_set_common,
+#endif
+};
+
+static const struct xattr_handler ll_lustre_xattr_handler = {
+ .prefix = XATTR_LUSTRE_PREFIX,
+ .flags = XATTR_LUSTRE_T,
+#if defined(HAVE_XATTR_HANDLER_SIMPLIFIED)
+ .get = ll_xattr_get_4_3,
+ .set = ll_xattr_set_4_3,
+#elif !defined(HAVE_XATTR_HANDLER_INODE_PARAM)
+ .get = ll_xattr_get_3_11,
+ .set = ll_xattr_set_3_11,
+#else
+ .get = ll_xattr_get,
+ .set = ll_xattr_set,
+#endif
+};
+
+const struct xattr_handler *ll_xattr_handlers[] = {
+ &ll_user_xattr_handler,
+ &ll_trusted_xattr_handler,
+ &ll_security_xattr_handler,
+#ifdef CONFIG_FS_POSIX_ACL
+ &ll_acl_access_xattr_handler,
+ &ll_acl_default_xattr_handler,
+#endif
+ &ll_lustre_xattr_handler,
+ NULL,
+};
--- /dev/null
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 2011, 2016, Intel Corporation.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
+ */
+
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/xattr.h>
+#include <linux/selinux.h>
+
+#define DEBUG_SUBSYSTEM S_LLITE
+
+#include <obd_support.h>
+#include <lustre_dlm.h>
+#include <lustre_ver.h>
+#include <lustre_eacl.h>
+
+#include "llite_internal.h"
+
+/* xattr related to IMA(Integrity Measurement Architecture) */
+#ifndef XATTR_NAME_IMA
+#define XATTR_NAME_IMA "security.ima"
+#endif
+#ifndef XATTR_NAME_EVM
+#define XATTR_NAME_EVM "security.evm"
+#endif
+
+static
+int get_xattr26_type(const char *name)
+{
+ if (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS))
+ return XATTR_ACL_ACCESS_T;
+
+ if (!strcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT))
+ return XATTR_ACL_DEFAULT_T;
+
+ if (!strncmp(name, XATTR_USER_PREFIX,
+ sizeof(XATTR_USER_PREFIX) - 1))
+ return XATTR_USER_T;
+
+ if (!strncmp(name, XATTR_TRUSTED_PREFIX,
+ sizeof(XATTR_TRUSTED_PREFIX) - 1))
+ return XATTR_TRUSTED_T;
+
+ if (!strncmp(name, XATTR_SECURITY_PREFIX,
+ sizeof(XATTR_SECURITY_PREFIX) - 1))
+ return XATTR_SECURITY_T;
+
+ if (!strncmp(name, XATTR_LUSTRE_PREFIX,
+ sizeof(XATTR_LUSTRE_PREFIX) - 1))
+ return XATTR_LUSTRE_T;
+
+ return XATTR_OTHER_T;
+}
+
+static
+int xattr_type_filter(struct ll_sb_info *sbi, int xattr_type)
+{
+ if ((xattr_type == XATTR_ACL_ACCESS_T ||
+ xattr_type == XATTR_ACL_DEFAULT_T) &&
+ !(sbi->ll_flags & LL_SBI_ACL))
+ return -EOPNOTSUPP;
+
+ if (xattr_type == XATTR_USER_T && !(sbi->ll_flags & LL_SBI_USER_XATTR))
+ return -EOPNOTSUPP;
+ if (xattr_type == XATTR_TRUSTED_T && !cfs_capable(CFS_CAP_SYS_ADMIN))
+ return -EPERM;
+ if (xattr_type == XATTR_OTHER_T)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static
+int ll_setxattr_common(struct inode *inode, const char *name,
+ const void *value, size_t size,
+ int flags, __u64 valid)
+{
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+ struct ptlrpc_request *req = NULL;
+ int xattr_type, rc;
+ const char *pv = value;
+ ENTRY;
+
+ /*FIXME: enable IMA when the conditions are ready */
+ if (strncmp(name, XATTR_NAME_IMA,
+ sizeof(XATTR_NAME_IMA)) == 0 ||
+ strncmp(name, XATTR_NAME_EVM,
+ sizeof(XATTR_NAME_EVM)) == 0)
+ return -EOPNOTSUPP;
+
+ xattr_type = get_xattr26_type(name);
+ rc = xattr_type_filter(sbi, xattr_type);
+ if (rc)
+ RETURN(rc);
+
+ if ((xattr_type == XATTR_ACL_ACCESS_T ||
+ xattr_type == XATTR_ACL_DEFAULT_T) &&
+#ifdef HAVE_INODE_OWNER_OR_CAPABLE
+ !inode_owner_or_capable(inode))
+#else
+ !is_owner_or_cap(inode))
+#endif
+ return -EPERM;
+
+ /* b10667: ignore lustre special xattr for now */
+ if (strcmp(name, XATTR_NAME_HSM) == 0 ||
+ (xattr_type == XATTR_TRUSTED_T &&
+ strcmp(name, XATTR_NAME_LOV) == 0) ||
+ (xattr_type == XATTR_LUSTRE_T &&
+ strcmp(name, "lustre.lov") == 0))
+ RETURN(0);
+
+ /* LU-549: Disable security.selinux when selinux is disabled */
+ if (xattr_type == XATTR_SECURITY_T && !selinux_is_enabled() &&
+ strcmp(name, "security.selinux") == 0)
+ RETURN(-EOPNOTSUPP);
+
+ /* In user.* namespace, only regular files and directories can have
+ * extended attributes. */
+ if (xattr_type == XATTR_USER_T) {
+ if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
+ RETURN(-EPERM);
+ }
+
+ rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode), valid, name, pv,
+ size, 0, flags, ll_i2suppgid(inode), &req);
+ if (rc) {
+ if (rc == -EOPNOTSUPP && xattr_type == XATTR_USER_T) {
+ LCONSOLE_INFO("Disabling user_xattr feature because "
+ "it is not supported on the server\n");
+ sbi->ll_flags &= ~LL_SBI_USER_XATTR;
+ }
+ RETURN(rc);
+ }
+
+ ptlrpc_req_finished(req);
+ RETURN(0);
+}
+
+static int get_hsm_state(struct inode *inode, __u32 *hus_states)
+{
+ struct md_op_data *op_data;
+ struct hsm_user_state *hus;
+ int rc;
+
+ OBD_ALLOC_PTR(hus);
+ if (hus == NULL)
+ return -ENOMEM;
+
+ op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
+ LUSTRE_OPC_ANY, hus);
+ if (!IS_ERR(op_data)) {
+ rc = obd_iocontrol(LL_IOC_HSM_STATE_GET, ll_i2mdexp(inode),
+ sizeof(*op_data), op_data, NULL);
+ if (rc == 0)
+ *hus_states = hus->hus_states;
+ else
+ CDEBUG(D_VFSTRACE, "obd_iocontrol failed. rc = %d\n",
+ rc);
+
+ ll_finish_md_op_data(op_data);
+ } else {
+ rc = PTR_ERR(op_data);
+ CDEBUG(D_VFSTRACE, "Could not prepare the opdata. rc = %d\n",
+ rc);
+ }
+ OBD_FREE_PTR(hus);
+ return rc;
+}
+
+static int ll_adjust_lum(struct inode *inode, struct lov_user_md *lump)
+{
+ struct lov_comp_md_v1 *comp_v1 = (struct lov_comp_md_v1 *)lump;
+ struct lov_user_md *v1 = lump;
+ bool release_checked = false;
+ bool need_clear_release = false;
+ __u16 entry_count = 1;
+ bool is_composite = false;
+ int rc = 0;
+ int i;
+
+ if (lump == NULL)
+ return 0;
+
+ if (lump->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
+ entry_count = comp_v1->lcm_entry_count;
+ is_composite = true;
+ }
+
+ for (i = 0; i < entry_count; i++) {
+ if (lump->lmm_magic == LOV_USER_MAGIC_COMP_V1)
+ v1 = (struct lov_user_md *)((char *)comp_v1 +
+ comp_v1->lcm_entries[i].lcme_offset);
+
+ /* Attributes that are saved via getxattr will always
+ * have the stripe_offset as 0. Instead, the MDS
+ * should be allowed to pick the starting OST index.
+ * b=17846 */
+ if (!is_composite && v1->lmm_stripe_offset == 0)
+ v1->lmm_stripe_offset = -1;
+
+ /* Avoid anyone directly setting the RELEASED flag. */
+ if (v1->lmm_pattern & LOV_PATTERN_F_RELEASED) {
+ if (!release_checked) {
+ __u32 state = HS_NONE;
+ rc = get_hsm_state(inode, &state);
+ if (rc)
+ return rc;
+ if (!(state & HS_ARCHIVED))
+ need_clear_release = true;
+ release_checked = true;
+ }
+ if (need_clear_release)
+ v1->lmm_pattern ^= LOV_PATTERN_F_RELEASED;
+ }
+ }
+
+ return rc;
+}
+
+static int ll_setstripe_ea(struct dentry *dentry, struct lov_user_md *lump,
+ size_t size)
+{
+ struct inode *inode = dentry->d_inode;
+ int rc = 0;
+
+ rc = ll_adjust_lum(inode, lump);
+ if (rc)
+ return rc;
+
+ if (lump != NULL && S_ISREG(inode->i_mode)) {
+ u64 it_flags = FMODE_WRITE;
+ int lum_size;
+
+ lum_size = ll_lov_user_md_size(lump);
+ if (lum_size < 0 || size < lum_size)
+ return -ERANGE;
+
+ rc = ll_lov_setstripe_ea_info(inode, dentry, it_flags, lump,
+ lum_size);
+ /**
+ * b=10667: ignore -EEXIST.
+ * Silently eat error on setting trusted.lov/lustre.lov
+ * attribute for SuSE 9, it added default option to copy
+ * all attributes in 'cp' command. rsync, tar --xattrs
+ * also will try to set LOVEA for existing files.
+ */
+ if (rc == -EEXIST)
+ rc = 0;
+ } else if (S_ISDIR(inode->i_mode)) {
+ rc = ll_dir_setstripe(inode, lump, 0);
+ }
+
+ return rc;
+}
+
+int ll_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
+{
+ struct inode *inode = dentry->d_inode;
+
+ LASSERT(inode);
+ LASSERT(name);
+
+ CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), xattr %s\n",
+ PFID(ll_inode2fid(inode)), inode, name);
+
+ ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_SETXATTR, 1);
+
+ /* lustre/trusted.lov.xxx would be passed through xattr API */
+ if (strcmp(name, XATTR_NAME_LOV) == 0 ||
+ strcmp(name, XATTR_LUSTRE_LOV) == 0)
+ return ll_setstripe_ea(dentry, (struct lov_user_md *)value,
+ size);
+ else if (strcmp(name, XATTR_NAME_LMA) == 0 ||
+ strcmp(name, XATTR_NAME_LINK) == 0)
+ return 0;
+
+ return ll_setxattr_common(inode, name, value, size, flags,
+ OBD_MD_FLXATTR);
+}
+
+int ll_removexattr(struct dentry *dentry, const char *name)
+{
+ struct inode *inode = dentry->d_inode;
+
+ LASSERT(inode);
+ LASSERT(name);
+
+ CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), xattr %s\n",
+ PFID(ll_inode2fid(inode)), inode, name);
+
+ ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_REMOVEXATTR, 1);
+ return ll_setxattr_common(inode, name, NULL, 0, 0,
+ OBD_MD_FLXATTRRM);
+}
+
+int ll_getxattr_common(struct inode *inode, const char *name,
+ void *buffer, size_t size, __u64 valid)
+{
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+ struct ptlrpc_request *req = NULL;
+ struct mdt_body *body;
+ int xattr_type, rc;
+ void *xdata;
+ struct ll_inode_info *lli = ll_i2info(inode);
+ ENTRY;
+
+ CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n",
+ PFID(ll_inode2fid(inode)), inode);
+
+ /* listxattr have slightly different behavior from of ext3:
+ * without 'user_xattr' ext3 will list all xattr names but
+ * filtered out "^user..*"; we list them all for simplicity.
+ */
+ if (!name) {
+ xattr_type = XATTR_OTHER_T;
+ goto do_getxattr;
+ }
+
+ xattr_type = get_xattr26_type(name);
+ rc = xattr_type_filter(sbi, xattr_type);
+ if (rc)
+ RETURN(rc);
+
+ /* LU-549: Disable security.selinux when selinux is disabled */
+ if (xattr_type == XATTR_SECURITY_T && !selinux_is_enabled() &&
+ strcmp(name, "security.selinux") == 0)
+ RETURN(-EOPNOTSUPP);
+
+#ifdef CONFIG_FS_POSIX_ACL
+ /* posix acl is under protection of LOOKUP lock. when calling to this,
+ * we just have path resolution to the target inode, so we have great
+ * chance that cached ACL is uptodate.
+ */
+ if (xattr_type == XATTR_ACL_ACCESS_T) {
+ struct posix_acl *acl;
+
+ spin_lock(&lli->lli_lock);
+ acl = posix_acl_dup(lli->lli_posix_acl);
+ spin_unlock(&lli->lli_lock);
+
+ if (!acl)
+ RETURN(-ENODATA);
+
+ rc = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
+ posix_acl_release(acl);
+ RETURN(rc);
+ }
+ if (xattr_type == XATTR_ACL_DEFAULT_T && !S_ISDIR(inode->i_mode))
+ RETURN(-ENODATA);
+#endif
+
+do_getxattr:
+ if (sbi->ll_xattr_cache_enabled &&
+ xattr_type != XATTR_ACL_ACCESS_T &&
+ (xattr_type != XATTR_SECURITY_T ||
+ strcmp(name, "security.selinux") != 0)) {
+ rc = ll_xattr_cache_get(inode, name, buffer, size, valid);
+ if (rc == -EAGAIN)
+ goto getxattr_nocache;
+ if (rc < 0)
+ GOTO(out_xattr, rc);
+
+ /* Add "system.posix_acl_access" to the list */
+ if (lli->lli_posix_acl != NULL && valid & OBD_MD_FLXATTRLS) {
+ if (size == 0) {
+ rc += sizeof(XATTR_NAME_ACL_ACCESS);
+ } else if (size - rc >= sizeof(XATTR_NAME_ACL_ACCESS)) {
+ memcpy(buffer + rc, XATTR_NAME_ACL_ACCESS,
+ sizeof(XATTR_NAME_ACL_ACCESS));
+ rc += sizeof(XATTR_NAME_ACL_ACCESS);
+ } else {
+ GOTO(out_xattr, rc = -ERANGE);
+ }
+ }
+ } else {
+getxattr_nocache:
+ rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode),
+ valid, name, NULL, 0, size, 0, &req);
+
+ if (rc < 0)
+ GOTO(out_xattr, rc);
+
+ body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
+ LASSERT(body);
+
+ /* only detect the xattr size */
+ if (size == 0)
+ GOTO(out, rc = body->mbo_eadatasize);
+
+ if (size < body->mbo_eadatasize) {
+ CERROR("server bug: replied size %u > %u\n",
+ body->mbo_eadatasize, (int)size);
+ GOTO(out, rc = -ERANGE);
+ }
+
+ if (body->mbo_eadatasize == 0)
+ GOTO(out, rc = -ENODATA);
+
+ /* do not need swab xattr data */
+ xdata = req_capsule_server_sized_get(&req->rq_pill, &RMF_EADATA,
+ body->mbo_eadatasize);
+ if (!xdata)
+ GOTO(out, rc = -EFAULT);
+
+ memcpy(buffer, xdata, body->mbo_eadatasize);
+ rc = body->mbo_eadatasize;
+ }
+
+ EXIT;
+
+out_xattr:
+ if (rc == -EOPNOTSUPP && xattr_type == XATTR_USER_T) {
+ LCONSOLE_INFO("%s: disabling user_xattr feature because "
+ "it is not supported on the server: rc = %d\n",
+ ll_get_fsname(inode->i_sb, NULL, 0), rc);
+ sbi->ll_flags &= ~LL_SBI_USER_XATTR;
+ }
+out:
+ ptlrpc_req_finished(req);
+ return rc;
+}
+
+static ssize_t ll_getxattr_lov(struct inode *inode, void *buf, size_t buf_size)
+{
+ ssize_t rc;
+
+ if (S_ISREG(inode->i_mode)) {
+ struct cl_object *obj = ll_i2info(inode)->lli_clob;
+ struct lu_env *env;
+ struct cl_layout cl = {
+ .cl_buf.lb_buf = buf,
+ .cl_buf.lb_len = buf_size,
+ };
+ __u16 refcheck;
+
+ if (obj == NULL)
+ RETURN(-ENODATA);
+
+ env = cl_env_get(&refcheck);
+ if (IS_ERR(env))
+ RETURN(PTR_ERR(env));
+
+ rc = cl_object_layout_get(env, obj, &cl);
+ if (rc < 0)
+ GOTO(out_env, rc);
+
+ if (cl.cl_size == 0)
+ GOTO(out_env, rc = -ENODATA);
+
+ rc = cl.cl_size;
+
+ if (buf_size == 0)
+ GOTO(out_env, rc);
+
+ LASSERT(buf != NULL && rc <= buf_size);
+
+ /* Do not return layout gen for getxattr() since
+ * otherwise it would confuse tar --xattr by
+ * recognizing layout gen as stripe offset when the
+ * file is restored. See LU-2809. */
+ if (((struct lov_mds_md *)buf)->lmm_magic == LOV_MAGIC_COMP_V1)
+ goto out_env;
+
+ ((struct lov_mds_md *)buf)->lmm_layout_gen = 0;
+out_env:
+ cl_env_put(env, &refcheck);
+
+ RETURN(rc);
+ } else if (S_ISDIR(inode->i_mode)) {
+ struct lov_mds_md *lmm = NULL;
+ int lmm_size = 0;
+ struct ptlrpc_request *req = NULL;
+
+ rc = ll_dir_getstripe(inode, (void **)&lmm, &lmm_size,
+ &req, 0);
+ if (rc < 0)
+ GOTO(out_req, rc);
+
+ if (buf_size == 0)
+ GOTO(out_req, rc = lmm_size);
+
+ if (buf_size < lmm_size)
+ GOTO(out_req, rc = -ERANGE);
+
+ memcpy(buf, lmm, lmm_size);
+ GOTO(out_req, rc = lmm_size);
+out_req:
+ if (req != NULL)
+ ptlrpc_req_finished(req);
+
+ return rc;
+ } else {
+ RETURN(-ENODATA);
+ }
+}
+
+ssize_t ll_getxattr(struct dentry *dentry, const char *name, void *buf,
+ size_t buf_size)
+{
+ struct inode *inode = dentry->d_inode;
+
+ LASSERT(inode);
+ LASSERT(name);
+
+ CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), xattr %s\n",
+ PFID(ll_inode2fid(inode)), inode, name);
+
+ ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_GETXATTR, 1);
+
+ if (strcmp(name, XATTR_LUSTRE_LOV) == 0 ||
+ strcmp(name, XATTR_NAME_LOV) == 0)
+ return ll_getxattr_lov(inode, buf, buf_size);
+ else
+ return ll_getxattr_common(inode, name, buf, buf_size,
+ OBD_MD_FLXATTR);
+}
+
+ssize_t ll_listxattr(struct dentry *dentry, char *buf, size_t buf_size)
+{
+ struct inode *inode = dentry->d_inode;
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+ char *xattr_name;
+ ssize_t rc, rc2;
+ size_t len, rem;
+
+ CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n",
+ PFID(ll_inode2fid(inode)), inode);
+
+ ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_LISTXATTR, 1);
+
+ rc = ll_getxattr_common(inode, NULL, buf, buf_size, OBD_MD_FLXATTRLS);
+ if (rc < 0)
+ RETURN(rc);
+
+ /* If we're being called to get the size of the xattr list
+ * (buf_size == 0) then just assume that a lustre.lov xattr
+ * exists. */
+ if (buf_size == 0)
+ RETURN(rc + sizeof(XATTR_LUSTRE_LOV));
+
+ xattr_name = buf;
+ rem = rc;
+
+ while (rem > 0) {
+ len = strnlen(xattr_name, rem - 1) + 1;
+ rem -= len;
+ if (xattr_type_filter(sbi, get_xattr26_type(xattr_name)) == 0) {
+ /* Skip OK xattr type, leave it in buffer. */
+ xattr_name += len;
+ continue;
+ }
+
+ /* Move up remaining xattrs in buffer removing the
+ * xattr that is not OK. */
+ memmove(xattr_name, xattr_name + len, rem);
+ rc -= len;
+ }
+
+ rc2 = ll_getxattr_lov(inode, NULL, 0);
+ if (rc2 == -ENODATA)
+ RETURN(rc);
+
+ if (rc2 < 0)
+ RETURN(rc2);
+
+ if (buf_size < rc + sizeof(XATTR_LUSTRE_LOV))
+ RETURN(-ERANGE);
+
+ memcpy(buf + rc, XATTR_LUSTRE_LOV, sizeof(XATTR_LUSTRE_LOV));
+
+ RETURN(rc + sizeof(XATTR_LUSTRE_LOV));
+}
ll_initxattrs(struct inode *inode, const struct xattr *xattr_array,
void *fs_info)
{
- const struct xattr *xattr;
struct dentry *dentry = fs_info;
- size_t name_len;
- char *full_name;
+ const struct xattr *xattr;
int err = 0;
- for (xattr = xattr_array; xattr->name != NULL; xattr++) {
- name_len = strlen(XATTR_SECURITY_PREFIX) + strlen(xattr->name)
- + 1;
- OBD_ALLOC(full_name, name_len);
- if (full_name == NULL)
- return -ENOMEM;
- strlcpy(full_name, XATTR_SECURITY_PREFIX, name_len);
- strlcat(full_name, xattr->name, name_len);
+ for (xattr = xattr_array; xattr->name; xattr++) {
+ char *full_name;
- err = ll_setxattr(dentry, full_name, xattr->value,
- xattr->value_len, 0);
-
- OBD_FREE(full_name, name_len);
+ full_name = kasprintf(GFP_KERNEL, "%s%s",
+ XATTR_SECURITY_PREFIX, xattr->name);
+ if (!full_name) {
+ err = -ENOMEM;
+ break;
+ }
+ err = __vfs_setxattr(dentry, inode, full_name, xattr->value,
+ xattr->value_len, XATTR_CREATE);
+ kfree(full_name);
if (err < 0)
break;
}
ll_inode_init_security(struct dentry *dentry, struct inode *inode,
struct inode *dir)
{
- int err;
- size_t len, name_len;
+ char *full_name;
void *value;
- char *name, *full_name;
+ char *name;
+ size_t len;
+ int err;
if (!selinux_is_enabled())
return 0;
return err;
}
- name_len = strlen(XATTR_SECURITY_PREFIX) + strlen(name) + 1;
- OBD_ALLOC(full_name, name_len);
- if (full_name == NULL)
+ full_name = kasprintf(GFP_KERNEL, "%s%s", XATTR_SECURITY_PREFIX, name);
+ if (!full_name)
GOTO(out_free, err = -ENOMEM);
- strlcpy(full_name, XATTR_SECURITY_PREFIX, name_len);
- strlcat(full_name, name, name_len);
-
- err = ll_setxattr(dentry, full_name, value, len, 0);
- OBD_FREE(full_name, name_len);
+ err = __vfs_setxattr(dentry, inode, full_name, value, len,
+ XATTR_CREATE);
+ kfree(full_name);
out_free:
kfree(name);
kfree(value);
/*
* Xattr support for Lustre servers
*/
+#ifdef HAVE_IOP_XATTR
static ssize_t lustre_getxattr(struct dentry *dentry, const char *name,
void *buffer, size_t size)
{
{
return -EOPNOTSUPP;
}
+#endif
static ssize_t lustre_listxattr(struct dentry *d_entry, char *name,
size_t size)
}
static const struct inode_operations server_inode_operations = {
+#ifdef HAVE_IOP_XATTR
.setxattr = lustre_setxattr,
.getxattr = lustre_getxattr,
+#endif
.listxattr = lustre_listxattr,
};