From: James Simmons Date: Sun, 18 Jun 2017 22:21:17 +0000 (-0400) Subject: LU-9183 llite: handle xattr with the xattr_handler infrastructure X-Git-Tag: 2.10.51~84 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=refs%2Fchanges%2F40%2F27240%2F25 LU-9183 llite: handle xattr with the xattr_handler infrastructure In commit fd50ecaddf8372a1d96e0daeaac0f93cf04e4d42 for the linux 4.9 kernel the {get,set,remove}xattr inode operations were removed and all xattr operations are now handled by xattr_handlers. For the upsteam lustre client a port was already done with: Linux-commit: 1e1f9ff406fd5f6003a5dab2ab5a26c4c5bb8cbd Linux-commit: 2c563880ea8fdc900693ae372fa07b3894f8ff63 This patch brings this work to the OpenSFS/Intel branch. The difference is that we also have to support older kernels which means we need to handle the following changes to the struct xattr_handler: Linux-commit: e409de992e3ea3674393465f07cc71c948edd87a Linux-commit: b296821a7c42fa58baa17513b2b7b30ae66f3336 Lastly the xattr_handler api for RHEL6 is too old for proper support, lacks the flags in struct xattr_handler. Since this is the case we have to carry around the pre xattr handler code. Once RHEL6 support is dropped we can remove that code. Test-Parameters: testgroup=review-ldiskfs Test-Parameters: testgroup=review-zfs-part-1 Test-Parameters: testgroup=review-zfs-part-2 Test-Parameters: testgroup=review-dne-part-1 Test-Parameters: testgroup=review-dne-part-2 Test-Parameters: trivial clientselinux testlist=sanity-selinux Change-Id: I7bdeb57c09f4a252f61737dbdbfa76939df7b5eb Signed-off-by: James Simmons Reviewed-on: https://review.whamcloud.com/27240 Reviewed-by: Dmitry Eremin Reviewed-by: Bob Glossman Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Sebastien Buisson Reviewed-by: Oleg Drokin --- diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4 index 4e9850e..1cde867 100644 --- a/lustre/autoconf/lustre-core.m4 +++ b/lustre/autoconf/lustre-core.m4 @@ -414,6 +414,24 @@ blk_queue_max_segments, [ ]) # 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 +],[ + 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 @@ -2211,6 +2229,29 @@ cache_head_has_hlist, [ ]) # 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 +],[ + 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 @@ -2335,6 +2376,30 @@ in_compat_syscall, [ ]) # 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 +],[ + 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 @@ -2432,6 +2497,48 @@ full_name_hash_3args, [ ]) # 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 + #include +],[ + 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 +],[ + 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 @@ -2451,25 +2558,22 @@ group_info_gid, [ ]) # 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 - #include +AC_DEFUN([LC_VFS_SETXATTR], [ +LB_CHECK_COMPILE([if '__vfs_setxattr' helper is available], +vfs_setxattr, [ + #include ],[ - 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 @@ -2530,6 +2634,9 @@ AC_DEFUN([LC_PROG_LINUX], [ # 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 @@ -2683,6 +2790,7 @@ AC_DEFUN([LC_PROG_LINUX], [ # 4.3 LC_HAVE_CACHE_HEAD_HLIST + LC_HAVE_XATTR_HANDLER_SIMPLIFIED # 4.4 LC_HAVE_LOCKS_LOCK_FILE_WAIT @@ -2699,6 +2807,7 @@ AC_DEFUN([LC_PROG_LINUX], [ # 4.6 LC_HAVE_IN_COMPAT_SYSCALL + LC_HAVE_XATTR_HANDLER_INODE_PARAM # 4.7 LC_DIRECTIO_2ARGS @@ -2709,9 +2818,11 @@ AC_DEFUN([LC_PROG_LINUX], [ 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 @@ -3008,6 +3119,7 @@ AM_CONDITIONAL(GSS_PIPEFS, test x$enable_gss_pipefs = xyes) 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 # diff --git a/lustre/include/lustre_compat.h b/lustre/include/lustre_compat.h index 1de5baf..e91be1c 100644 --- a/lustre/include/lustre_compat.h +++ b/lustre/include/lustre_compat.h @@ -443,6 +443,56 @@ static inline void truncate_inode_pages_final(struct address_space *map) # 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) { diff --git a/lustre/llite/Makefile.in b/lustre/llite/Makefile.in index c5555fd..08ca2c2 100644 --- a/lustre/llite/Makefile.in +++ b/lustre/llite/Makefile.in @@ -1,7 +1,9 @@ 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 @@ -12,4 +14,7 @@ lustre-objs += range_lock.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@ diff --git a/lustre/llite/file.c b/lustre/llite/file.c index d6591f5..b5c5390 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -4082,10 +4082,12 @@ struct inode_operations ll_file_inode_operations = { .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, diff --git a/lustre/llite/llite_internal.h b/lustre/llite/llite_internal.h index 4737a27..75d7f1b 100644 --- a/lustre/llite/llite_internal.h +++ b/lustre/llite/llite_internal.h @@ -1113,12 +1113,20 @@ static inline loff_t ll_file_maxbytes(struct inode *inode) } /* 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. @@ -1451,8 +1459,6 @@ int ll_layout_write_intent(struct inode *inode, __u64 start, __u64 end); 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); diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index 10fef55..c6374c3 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -479,6 +479,9 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, 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 @@ -2745,7 +2748,6 @@ static int ll_linkea_decode(struct linkea_data *ldata, unsigned int linkno, */ 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; @@ -2778,7 +2780,13 @@ int ll_getparent(struct file *file, struct getparent __user *arg) 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); diff --git a/lustre/llite/namei.c b/lustre/llite/namei.c index ef60461..a2f2dee 100644 --- a/lustre/llite/namei.c +++ b/lustre/llite/namei.c @@ -1495,10 +1495,12 @@ const struct inode_operations ll_dir_inode_operations = { .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 @@ -1508,11 +1510,13 @@ const struct inode_operations ll_special_inode_operations = { .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 }; diff --git a/lustre/llite/symlink.c b/lustre/llite/symlink.c index 7095955..8e12995 100644 --- a/lustre/llite/symlink.c +++ b/lustre/llite/symlink.c @@ -233,8 +233,10 @@ struct inode_operations ll_fast_symlink_inode_operations = { #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, }; diff --git a/lustre/llite/xattr.c b/lustre/llite/xattr.c index 71fbca5..243219b 100644 --- a/lustre/llite/xattr.c +++ b/lustre/llite/xattr.c @@ -45,143 +45,129 @@ #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, @@ -189,7 +175,7 @@ static int get_hsm_state(struct inode *inode, __u32 *hus_states) 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", @@ -209,14 +195,14 @@ 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 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) { @@ -225,24 +211,31 @@ static int ll_adjust_lum(struct inode *inode, struct lov_user_md *lump) } 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; @@ -255,19 +248,26 @@ static int ll_adjust_lum(struct inode *inode, struct lov_user_md *lump) 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) @@ -278,121 +278,68 @@ int ll_setstripe_ea(struct dentry *dentry, struct lov_user_md *lump, /** * 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; @@ -400,7 +347,7 @@ do_getxattr: 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)) { @@ -414,8 +361,7 @@ do_getxattr: } 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); @@ -448,7 +394,7 @@ getxattr_nocache: 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); @@ -459,20 +405,74 @@ out: 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); @@ -483,20 +483,22 @@ static ssize_t ll_getxattr_lov(struct inode *inode, void *buf, size_t buf_size) 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; @@ -506,16 +508,16 @@ 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) @@ -524,7 +526,7 @@ out_env: memcpy(buf, lmm, lmm_size); GOTO(out_req, rc = lmm_size); out_req: - if (req != NULL) + if (req) ptlrpc_req_finished(req); return rc; @@ -533,28 +535,26 @@ out_req: } } -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); @@ -562,35 +562,42 @@ ssize_t ll_listxattr(struct dentry *dentry, char *buf, size_t buf_size) 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; } @@ -602,10 +609,209 @@ ssize_t ll_listxattr(struct dentry *dentry, char *buf, size_t buf_size) 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, +}; diff --git a/lustre/llite/xattr26.c b/lustre/llite/xattr26.c new file mode 100644 index 0000000..84e9b8b --- /dev/null +++ b/lustre/llite/xattr26.c @@ -0,0 +1,603 @@ +/* + * 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 +#include +#include +#include +#include + +#define DEBUG_SUBSYSTEM S_LLITE + +#include +#include +#include +#include + +#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)); +} diff --git a/lustre/llite/xattr_security.c b/lustre/llite/xattr_security.c index 0ac19f7..82019cc 100644 --- a/lustre/llite/xattr_security.c +++ b/lustre/llite/xattr_security.c @@ -98,26 +98,23 @@ static int 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; } @@ -159,10 +156,11 @@ int 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; @@ -175,16 +173,13 @@ ll_inode_init_security(struct dentry *dentry, struct inode *inode, 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); diff --git a/lustre/obdclass/obd_mount_server.c b/lustre/obdclass/obd_mount_server.c index 839c7a2..8a4883a 100644 --- a/lustre/obdclass/obd_mount_server.c +++ b/lustre/obdclass/obd_mount_server.c @@ -1676,6 +1676,7 @@ static struct super_operations server_ops = { /* * 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) { @@ -1689,6 +1690,7 @@ static int lustre_setxattr(struct dentry *dentry, const char *name, { return -EOPNOTSUPP; } +#endif static ssize_t lustre_listxattr(struct dentry *d_entry, char *name, size_t size) @@ -1697,8 +1699,10 @@ static ssize_t lustre_listxattr(struct dentry *d_entry, char *name, } static const struct inode_operations server_inode_operations = { +#ifdef HAVE_IOP_XATTR .setxattr = lustre_setxattr, .getxattr = lustre_getxattr, +#endif .listxattr = lustre_listxattr, };