18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * (C) 2001 Clemson University and The University of Chicago 48c2ecf20Sopenharmony_ci * Copyright 2018 Omnibond Systems, L.L.C. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * See COPYING in top-level directory. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci/* 108c2ecf20Sopenharmony_ci * Linux VFS extended attribute operations. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "protocol.h" 148c2ecf20Sopenharmony_ci#include "orangefs-kernel.h" 158c2ecf20Sopenharmony_ci#include "orangefs-bufmap.h" 168c2ecf20Sopenharmony_ci#include <linux/posix_acl_xattr.h> 178c2ecf20Sopenharmony_ci#include <linux/xattr.h> 188c2ecf20Sopenharmony_ci#include <linux/hashtable.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define SYSTEM_ORANGEFS_KEY "system.pvfs2." 218c2ecf20Sopenharmony_ci#define SYSTEM_ORANGEFS_KEY_LEN 13 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* 248c2ecf20Sopenharmony_ci * this function returns 258c2ecf20Sopenharmony_ci * 0 if the key corresponding to name is not meant to be printed as part 268c2ecf20Sopenharmony_ci * of a listxattr. 278c2ecf20Sopenharmony_ci * 1 if the key corresponding to name is meant to be returned as part of 288c2ecf20Sopenharmony_ci * a listxattr. 298c2ecf20Sopenharmony_ci * The ones that start SYSTEM_ORANGEFS_KEY are the ones to avoid printing. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_cistatic int is_reserved_key(const char *key, size_t size) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (size < SYSTEM_ORANGEFS_KEY_LEN) 358c2ecf20Sopenharmony_ci return 1; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci return strncmp(key, SYSTEM_ORANGEFS_KEY, SYSTEM_ORANGEFS_KEY_LEN) ? 1 : 0; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic inline int convert_to_internal_xattr_flags(int setxattr_flags) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci int internal_flag = 0; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (setxattr_flags & XATTR_REPLACE) { 458c2ecf20Sopenharmony_ci /* Attribute must exist! */ 468c2ecf20Sopenharmony_ci internal_flag = ORANGEFS_XATTR_REPLACE; 478c2ecf20Sopenharmony_ci } else if (setxattr_flags & XATTR_CREATE) { 488c2ecf20Sopenharmony_ci /* Attribute must not exist */ 498c2ecf20Sopenharmony_ci internal_flag = ORANGEFS_XATTR_CREATE; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci return internal_flag; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic unsigned int xattr_key(const char *key) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci unsigned int i = 0; 578c2ecf20Sopenharmony_ci while (key) 588c2ecf20Sopenharmony_ci i += *key++; 598c2ecf20Sopenharmony_ci return i % 16; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic struct orangefs_cached_xattr *find_cached_xattr(struct inode *inode, 638c2ecf20Sopenharmony_ci const char *key) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 668c2ecf20Sopenharmony_ci struct orangefs_cached_xattr *cx; 678c2ecf20Sopenharmony_ci struct hlist_head *h; 688c2ecf20Sopenharmony_ci struct hlist_node *tmp; 698c2ecf20Sopenharmony_ci h = &orangefs_inode->xattr_cache[xattr_key(key)]; 708c2ecf20Sopenharmony_ci if (hlist_empty(h)) 718c2ecf20Sopenharmony_ci return NULL; 728c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(cx, tmp, h, node) { 738c2ecf20Sopenharmony_ci/* if (!time_before(jiffies, cx->timeout)) { 748c2ecf20Sopenharmony_ci hlist_del(&cx->node); 758c2ecf20Sopenharmony_ci kfree(cx); 768c2ecf20Sopenharmony_ci continue; 778c2ecf20Sopenharmony_ci }*/ 788c2ecf20Sopenharmony_ci if (!strcmp(cx->key, key)) 798c2ecf20Sopenharmony_ci return cx; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci return NULL; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* 858c2ecf20Sopenharmony_ci * Tries to get a specified key's attributes of a given 868c2ecf20Sopenharmony_ci * file into a user-specified buffer. Note that the getxattr 878c2ecf20Sopenharmony_ci * interface allows for the users to probe the size of an 888c2ecf20Sopenharmony_ci * extended attribute by passing in a value of 0 to size. 898c2ecf20Sopenharmony_ci * Thus our return value is always the size of the attribute 908c2ecf20Sopenharmony_ci * unless the key does not exist for the file and/or if 918c2ecf20Sopenharmony_ci * there were errors in fetching the attribute value. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_cissize_t orangefs_inode_getxattr(struct inode *inode, const char *name, 948c2ecf20Sopenharmony_ci void *buffer, size_t size) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 978c2ecf20Sopenharmony_ci struct orangefs_kernel_op_s *new_op = NULL; 988c2ecf20Sopenharmony_ci struct orangefs_cached_xattr *cx; 998c2ecf20Sopenharmony_ci ssize_t ret = -ENOMEM; 1008c2ecf20Sopenharmony_ci ssize_t length = 0; 1018c2ecf20Sopenharmony_ci int fsuid; 1028c2ecf20Sopenharmony_ci int fsgid; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 1058c2ecf20Sopenharmony_ci "%s: name %s, buffer_size %zd\n", 1068c2ecf20Sopenharmony_ci __func__, name, size); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (S_ISLNK(inode->i_mode)) 1098c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) 1128c2ecf20Sopenharmony_ci return -EINVAL; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci fsuid = from_kuid(&init_user_ns, current_fsuid()); 1158c2ecf20Sopenharmony_ci fsgid = from_kgid(&init_user_ns, current_fsgid()); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 1188c2ecf20Sopenharmony_ci "getxattr on inode %pU, name %s " 1198c2ecf20Sopenharmony_ci "(uid %o, gid %o)\n", 1208c2ecf20Sopenharmony_ci get_khandle_from_ino(inode), 1218c2ecf20Sopenharmony_ci name, 1228c2ecf20Sopenharmony_ci fsuid, 1238c2ecf20Sopenharmony_ci fsgid); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci down_read(&orangefs_inode->xattr_sem); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci cx = find_cached_xattr(inode, name); 1288c2ecf20Sopenharmony_ci if (cx && time_before(jiffies, cx->timeout)) { 1298c2ecf20Sopenharmony_ci if (cx->length == -1) { 1308c2ecf20Sopenharmony_ci ret = -ENODATA; 1318c2ecf20Sopenharmony_ci goto out_unlock; 1328c2ecf20Sopenharmony_ci } else { 1338c2ecf20Sopenharmony_ci if (size == 0) { 1348c2ecf20Sopenharmony_ci ret = cx->length; 1358c2ecf20Sopenharmony_ci goto out_unlock; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci if (cx->length > size) { 1388c2ecf20Sopenharmony_ci ret = -ERANGE; 1398c2ecf20Sopenharmony_ci goto out_unlock; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci memcpy(buffer, cx->val, cx->length); 1428c2ecf20Sopenharmony_ci memset(buffer + cx->length, 0, size - cx->length); 1438c2ecf20Sopenharmony_ci ret = cx->length; 1448c2ecf20Sopenharmony_ci goto out_unlock; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci new_op = op_alloc(ORANGEFS_VFS_OP_GETXATTR); 1498c2ecf20Sopenharmony_ci if (!new_op) 1508c2ecf20Sopenharmony_ci goto out_unlock; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci new_op->upcall.req.getxattr.refn = orangefs_inode->refn; 1538c2ecf20Sopenharmony_ci strcpy(new_op->upcall.req.getxattr.key, name); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* 1568c2ecf20Sopenharmony_ci * NOTE: Although keys are meant to be NULL terminated textual 1578c2ecf20Sopenharmony_ci * strings, I am going to explicitly pass the length just in case 1588c2ecf20Sopenharmony_ci * we change this later on... 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_ci new_op->upcall.req.getxattr.key_sz = strlen(name) + 1; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci ret = service_operation(new_op, "orangefs_inode_getxattr", 1638c2ecf20Sopenharmony_ci get_interruptible_flag(inode)); 1648c2ecf20Sopenharmony_ci if (ret != 0) { 1658c2ecf20Sopenharmony_ci if (ret == -ENOENT) { 1668c2ecf20Sopenharmony_ci ret = -ENODATA; 1678c2ecf20Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 1688c2ecf20Sopenharmony_ci "orangefs_inode_getxattr: inode %pU key %s" 1698c2ecf20Sopenharmony_ci " does not exist!\n", 1708c2ecf20Sopenharmony_ci get_khandle_from_ino(inode), 1718c2ecf20Sopenharmony_ci (char *)new_op->upcall.req.getxattr.key); 1728c2ecf20Sopenharmony_ci cx = kmalloc(sizeof *cx, GFP_KERNEL); 1738c2ecf20Sopenharmony_ci if (cx) { 1748c2ecf20Sopenharmony_ci strcpy(cx->key, name); 1758c2ecf20Sopenharmony_ci cx->length = -1; 1768c2ecf20Sopenharmony_ci cx->timeout = jiffies + 1778c2ecf20Sopenharmony_ci orangefs_getattr_timeout_msecs*HZ/1000; 1788c2ecf20Sopenharmony_ci hash_add(orangefs_inode->xattr_cache, &cx->node, 1798c2ecf20Sopenharmony_ci xattr_key(cx->key)); 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci goto out_release_op; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* 1868c2ecf20Sopenharmony_ci * Length returned includes null terminator. 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_ci length = new_op->downcall.resp.getxattr.val_sz; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* 1918c2ecf20Sopenharmony_ci * Just return the length of the queried attribute. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_ci if (size == 0) { 1948c2ecf20Sopenharmony_ci ret = length; 1958c2ecf20Sopenharmony_ci goto out_release_op; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* 1998c2ecf20Sopenharmony_ci * Check to see if key length is > provided buffer size. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ci if (length > size) { 2028c2ecf20Sopenharmony_ci ret = -ERANGE; 2038c2ecf20Sopenharmony_ci goto out_release_op; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci memcpy(buffer, new_op->downcall.resp.getxattr.val, length); 2078c2ecf20Sopenharmony_ci memset(buffer + length, 0, size - length); 2088c2ecf20Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 2098c2ecf20Sopenharmony_ci "orangefs_inode_getxattr: inode %pU " 2108c2ecf20Sopenharmony_ci "key %s key_sz %d, val_len %d\n", 2118c2ecf20Sopenharmony_ci get_khandle_from_ino(inode), 2128c2ecf20Sopenharmony_ci (char *)new_op-> 2138c2ecf20Sopenharmony_ci upcall.req.getxattr.key, 2148c2ecf20Sopenharmony_ci (int)new_op-> 2158c2ecf20Sopenharmony_ci upcall.req.getxattr.key_sz, 2168c2ecf20Sopenharmony_ci (int)ret); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci ret = length; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (cx) { 2218c2ecf20Sopenharmony_ci strcpy(cx->key, name); 2228c2ecf20Sopenharmony_ci memcpy(cx->val, buffer, length); 2238c2ecf20Sopenharmony_ci cx->length = length; 2248c2ecf20Sopenharmony_ci cx->timeout = jiffies + HZ; 2258c2ecf20Sopenharmony_ci } else { 2268c2ecf20Sopenharmony_ci cx = kmalloc(sizeof *cx, GFP_KERNEL); 2278c2ecf20Sopenharmony_ci if (cx) { 2288c2ecf20Sopenharmony_ci strcpy(cx->key, name); 2298c2ecf20Sopenharmony_ci memcpy(cx->val, buffer, length); 2308c2ecf20Sopenharmony_ci cx->length = length; 2318c2ecf20Sopenharmony_ci cx->timeout = jiffies + HZ; 2328c2ecf20Sopenharmony_ci hash_add(orangefs_inode->xattr_cache, &cx->node, 2338c2ecf20Sopenharmony_ci xattr_key(cx->key)); 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ciout_release_op: 2388c2ecf20Sopenharmony_ci op_release(new_op); 2398c2ecf20Sopenharmony_ciout_unlock: 2408c2ecf20Sopenharmony_ci up_read(&orangefs_inode->xattr_sem); 2418c2ecf20Sopenharmony_ci return ret; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic int orangefs_inode_removexattr(struct inode *inode, const char *name, 2458c2ecf20Sopenharmony_ci int flags) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 2488c2ecf20Sopenharmony_ci struct orangefs_kernel_op_s *new_op = NULL; 2498c2ecf20Sopenharmony_ci struct orangefs_cached_xattr *cx; 2508c2ecf20Sopenharmony_ci struct hlist_head *h; 2518c2ecf20Sopenharmony_ci struct hlist_node *tmp; 2528c2ecf20Sopenharmony_ci int ret = -ENOMEM; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) 2558c2ecf20Sopenharmony_ci return -EINVAL; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci down_write(&orangefs_inode->xattr_sem); 2588c2ecf20Sopenharmony_ci new_op = op_alloc(ORANGEFS_VFS_OP_REMOVEXATTR); 2598c2ecf20Sopenharmony_ci if (!new_op) 2608c2ecf20Sopenharmony_ci goto out_unlock; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci new_op->upcall.req.removexattr.refn = orangefs_inode->refn; 2638c2ecf20Sopenharmony_ci /* 2648c2ecf20Sopenharmony_ci * NOTE: Although keys are meant to be NULL terminated 2658c2ecf20Sopenharmony_ci * textual strings, I am going to explicitly pass the 2668c2ecf20Sopenharmony_ci * length just in case we change this later on... 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_ci strcpy(new_op->upcall.req.removexattr.key, name); 2698c2ecf20Sopenharmony_ci new_op->upcall.req.removexattr.key_sz = strlen(name) + 1; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 2728c2ecf20Sopenharmony_ci "orangefs_inode_removexattr: key %s, key_sz %d\n", 2738c2ecf20Sopenharmony_ci (char *)new_op->upcall.req.removexattr.key, 2748c2ecf20Sopenharmony_ci (int)new_op->upcall.req.removexattr.key_sz); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci ret = service_operation(new_op, 2778c2ecf20Sopenharmony_ci "orangefs_inode_removexattr", 2788c2ecf20Sopenharmony_ci get_interruptible_flag(inode)); 2798c2ecf20Sopenharmony_ci if (ret == -ENOENT) { 2808c2ecf20Sopenharmony_ci /* 2818c2ecf20Sopenharmony_ci * Request to replace a non-existent attribute is an error. 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_ci if (flags & XATTR_REPLACE) 2848c2ecf20Sopenharmony_ci ret = -ENODATA; 2858c2ecf20Sopenharmony_ci else 2868c2ecf20Sopenharmony_ci ret = 0; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 2908c2ecf20Sopenharmony_ci "orangefs_inode_removexattr: returning %d\n", ret); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci op_release(new_op); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci h = &orangefs_inode->xattr_cache[xattr_key(name)]; 2958c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(cx, tmp, h, node) { 2968c2ecf20Sopenharmony_ci if (!strcmp(cx->key, name)) { 2978c2ecf20Sopenharmony_ci hlist_del(&cx->node); 2988c2ecf20Sopenharmony_ci kfree(cx); 2998c2ecf20Sopenharmony_ci break; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ciout_unlock: 3048c2ecf20Sopenharmony_ci up_write(&orangefs_inode->xattr_sem); 3058c2ecf20Sopenharmony_ci return ret; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci/* 3098c2ecf20Sopenharmony_ci * Tries to set an attribute for a given key on a file. 3108c2ecf20Sopenharmony_ci * 3118c2ecf20Sopenharmony_ci * Returns a -ve number on error and 0 on success. Key is text, but value 3128c2ecf20Sopenharmony_ci * can be binary! 3138c2ecf20Sopenharmony_ci */ 3148c2ecf20Sopenharmony_ciint orangefs_inode_setxattr(struct inode *inode, const char *name, 3158c2ecf20Sopenharmony_ci const void *value, size_t size, int flags) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 3188c2ecf20Sopenharmony_ci struct orangefs_kernel_op_s *new_op; 3198c2ecf20Sopenharmony_ci int internal_flag = 0; 3208c2ecf20Sopenharmony_ci struct orangefs_cached_xattr *cx; 3218c2ecf20Sopenharmony_ci struct hlist_head *h; 3228c2ecf20Sopenharmony_ci struct hlist_node *tmp; 3238c2ecf20Sopenharmony_ci int ret = -ENOMEM; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 3268c2ecf20Sopenharmony_ci "%s: name %s, buffer_size %zd\n", 3278c2ecf20Sopenharmony_ci __func__, name, size); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (size > ORANGEFS_MAX_XATTR_VALUELEN) 3308c2ecf20Sopenharmony_ci return -EINVAL; 3318c2ecf20Sopenharmony_ci if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) 3328c2ecf20Sopenharmony_ci return -EINVAL; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci internal_flag = convert_to_internal_xattr_flags(flags); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* This is equivalent to a removexattr */ 3378c2ecf20Sopenharmony_ci if (size == 0 && !value) { 3388c2ecf20Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 3398c2ecf20Sopenharmony_ci "removing xattr (%s)\n", 3408c2ecf20Sopenharmony_ci name); 3418c2ecf20Sopenharmony_ci return orangefs_inode_removexattr(inode, name, flags); 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 3458c2ecf20Sopenharmony_ci "setxattr on inode %pU, name %s\n", 3468c2ecf20Sopenharmony_ci get_khandle_from_ino(inode), 3478c2ecf20Sopenharmony_ci name); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci down_write(&orangefs_inode->xattr_sem); 3508c2ecf20Sopenharmony_ci new_op = op_alloc(ORANGEFS_VFS_OP_SETXATTR); 3518c2ecf20Sopenharmony_ci if (!new_op) 3528c2ecf20Sopenharmony_ci goto out_unlock; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci new_op->upcall.req.setxattr.refn = orangefs_inode->refn; 3568c2ecf20Sopenharmony_ci new_op->upcall.req.setxattr.flags = internal_flag; 3578c2ecf20Sopenharmony_ci /* 3588c2ecf20Sopenharmony_ci * NOTE: Although keys are meant to be NULL terminated textual 3598c2ecf20Sopenharmony_ci * strings, I am going to explicitly pass the length just in 3608c2ecf20Sopenharmony_ci * case we change this later on... 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci strcpy(new_op->upcall.req.setxattr.keyval.key, name); 3638c2ecf20Sopenharmony_ci new_op->upcall.req.setxattr.keyval.key_sz = strlen(name) + 1; 3648c2ecf20Sopenharmony_ci memcpy(new_op->upcall.req.setxattr.keyval.val, value, size); 3658c2ecf20Sopenharmony_ci new_op->upcall.req.setxattr.keyval.val_sz = size; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 3688c2ecf20Sopenharmony_ci "orangefs_inode_setxattr: key %s, key_sz %d " 3698c2ecf20Sopenharmony_ci " value size %zd\n", 3708c2ecf20Sopenharmony_ci (char *)new_op->upcall.req.setxattr.keyval.key, 3718c2ecf20Sopenharmony_ci (int)new_op->upcall.req.setxattr.keyval.key_sz, 3728c2ecf20Sopenharmony_ci size); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci ret = service_operation(new_op, 3758c2ecf20Sopenharmony_ci "orangefs_inode_setxattr", 3768c2ecf20Sopenharmony_ci get_interruptible_flag(inode)); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 3798c2ecf20Sopenharmony_ci "orangefs_inode_setxattr: returning %d\n", 3808c2ecf20Sopenharmony_ci ret); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* when request is serviced properly, free req op struct */ 3838c2ecf20Sopenharmony_ci op_release(new_op); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci h = &orangefs_inode->xattr_cache[xattr_key(name)]; 3868c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(cx, tmp, h, node) { 3878c2ecf20Sopenharmony_ci if (!strcmp(cx->key, name)) { 3888c2ecf20Sopenharmony_ci hlist_del(&cx->node); 3898c2ecf20Sopenharmony_ci kfree(cx); 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ciout_unlock: 3958c2ecf20Sopenharmony_ci up_write(&orangefs_inode->xattr_sem); 3968c2ecf20Sopenharmony_ci return ret; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci/* 4008c2ecf20Sopenharmony_ci * Tries to get a specified object's keys into a user-specified buffer of a 4018c2ecf20Sopenharmony_ci * given size. Note that like the previous instances of xattr routines, this 4028c2ecf20Sopenharmony_ci * also allows you to pass in a NULL pointer and 0 size to probe the size for 4038c2ecf20Sopenharmony_ci * subsequent memory allocations. Thus our return value is always the size of 4048c2ecf20Sopenharmony_ci * all the keys unless there were errors in fetching the keys! 4058c2ecf20Sopenharmony_ci */ 4068c2ecf20Sopenharmony_cissize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci struct inode *inode = dentry->d_inode; 4098c2ecf20Sopenharmony_ci struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 4108c2ecf20Sopenharmony_ci struct orangefs_kernel_op_s *new_op; 4118c2ecf20Sopenharmony_ci __u64 token = ORANGEFS_ITERATE_START; 4128c2ecf20Sopenharmony_ci ssize_t ret = -ENOMEM; 4138c2ecf20Sopenharmony_ci ssize_t total = 0; 4148c2ecf20Sopenharmony_ci int count_keys = 0; 4158c2ecf20Sopenharmony_ci int key_size; 4168c2ecf20Sopenharmony_ci int i = 0; 4178c2ecf20Sopenharmony_ci int returned_count = 0; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (size > 0 && !buffer) { 4208c2ecf20Sopenharmony_ci gossip_err("%s: bogus NULL pointers\n", __func__); 4218c2ecf20Sopenharmony_ci return -EINVAL; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci down_read(&orangefs_inode->xattr_sem); 4258c2ecf20Sopenharmony_ci new_op = op_alloc(ORANGEFS_VFS_OP_LISTXATTR); 4268c2ecf20Sopenharmony_ci if (!new_op) 4278c2ecf20Sopenharmony_ci goto out_unlock; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (buffer && size > 0) 4308c2ecf20Sopenharmony_ci memset(buffer, 0, size); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_citry_again: 4338c2ecf20Sopenharmony_ci key_size = 0; 4348c2ecf20Sopenharmony_ci new_op->upcall.req.listxattr.refn = orangefs_inode->refn; 4358c2ecf20Sopenharmony_ci new_op->upcall.req.listxattr.token = token; 4368c2ecf20Sopenharmony_ci new_op->upcall.req.listxattr.requested_count = 4378c2ecf20Sopenharmony_ci (size == 0) ? 0 : ORANGEFS_MAX_XATTR_LISTLEN; 4388c2ecf20Sopenharmony_ci ret = service_operation(new_op, __func__, 4398c2ecf20Sopenharmony_ci get_interruptible_flag(inode)); 4408c2ecf20Sopenharmony_ci if (ret != 0) 4418c2ecf20Sopenharmony_ci goto done; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (size == 0) { 4448c2ecf20Sopenharmony_ci /* 4458c2ecf20Sopenharmony_ci * This is a bit of a big upper limit, but I did not want to 4468c2ecf20Sopenharmony_ci * spend too much time getting this correct, since users end 4478c2ecf20Sopenharmony_ci * up allocating memory rather than us... 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_ci total = new_op->downcall.resp.listxattr.returned_count * 4508c2ecf20Sopenharmony_ci ORANGEFS_MAX_XATTR_NAMELEN; 4518c2ecf20Sopenharmony_ci goto done; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci returned_count = new_op->downcall.resp.listxattr.returned_count; 4558c2ecf20Sopenharmony_ci if (returned_count < 0 || 4568c2ecf20Sopenharmony_ci returned_count > ORANGEFS_MAX_XATTR_LISTLEN) { 4578c2ecf20Sopenharmony_ci gossip_err("%s: impossible value for returned_count:%d:\n", 4588c2ecf20Sopenharmony_ci __func__, 4598c2ecf20Sopenharmony_ci returned_count); 4608c2ecf20Sopenharmony_ci ret = -EIO; 4618c2ecf20Sopenharmony_ci goto done; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* 4658c2ecf20Sopenharmony_ci * Check to see how much can be fit in the buffer. Fit only whole keys. 4668c2ecf20Sopenharmony_ci */ 4678c2ecf20Sopenharmony_ci for (i = 0; i < returned_count; i++) { 4688c2ecf20Sopenharmony_ci if (new_op->downcall.resp.listxattr.lengths[i] < 0 || 4698c2ecf20Sopenharmony_ci new_op->downcall.resp.listxattr.lengths[i] > 4708c2ecf20Sopenharmony_ci ORANGEFS_MAX_XATTR_NAMELEN) { 4718c2ecf20Sopenharmony_ci gossip_err("%s: impossible value for lengths[%d]\n", 4728c2ecf20Sopenharmony_ci __func__, 4738c2ecf20Sopenharmony_ci new_op->downcall.resp.listxattr.lengths[i]); 4748c2ecf20Sopenharmony_ci ret = -EIO; 4758c2ecf20Sopenharmony_ci goto done; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci if (total + new_op->downcall.resp.listxattr.lengths[i] > size) 4788c2ecf20Sopenharmony_ci goto done; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* 4818c2ecf20Sopenharmony_ci * Since many dumb programs try to setxattr() on our reserved 4828c2ecf20Sopenharmony_ci * xattrs this is a feeble attempt at defeating those by not 4838c2ecf20Sopenharmony_ci * listing them in the output of listxattr.. sigh 4848c2ecf20Sopenharmony_ci */ 4858c2ecf20Sopenharmony_ci if (is_reserved_key(new_op->downcall.resp.listxattr.key + 4868c2ecf20Sopenharmony_ci key_size, 4878c2ecf20Sopenharmony_ci new_op->downcall.resp. 4888c2ecf20Sopenharmony_ci listxattr.lengths[i])) { 4898c2ecf20Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, "Copying key %d -> %s\n", 4908c2ecf20Sopenharmony_ci i, new_op->downcall.resp.listxattr.key + 4918c2ecf20Sopenharmony_ci key_size); 4928c2ecf20Sopenharmony_ci memcpy(buffer + total, 4938c2ecf20Sopenharmony_ci new_op->downcall.resp.listxattr.key + key_size, 4948c2ecf20Sopenharmony_ci new_op->downcall.resp.listxattr.lengths[i]); 4958c2ecf20Sopenharmony_ci total += new_op->downcall.resp.listxattr.lengths[i]; 4968c2ecf20Sopenharmony_ci count_keys++; 4978c2ecf20Sopenharmony_ci } else { 4988c2ecf20Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, "[RESERVED] key %d -> %s\n", 4998c2ecf20Sopenharmony_ci i, new_op->downcall.resp.listxattr.key + 5008c2ecf20Sopenharmony_ci key_size); 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci key_size += new_op->downcall.resp.listxattr.lengths[i]; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* 5068c2ecf20Sopenharmony_ci * Since the buffer was large enough, we might have to continue 5078c2ecf20Sopenharmony_ci * fetching more keys! 5088c2ecf20Sopenharmony_ci */ 5098c2ecf20Sopenharmony_ci token = new_op->downcall.resp.listxattr.token; 5108c2ecf20Sopenharmony_ci if (token != ORANGEFS_ITERATE_END) 5118c2ecf20Sopenharmony_ci goto try_again; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cidone: 5148c2ecf20Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, "%s: returning %d" 5158c2ecf20Sopenharmony_ci " [size of buffer %ld] (filled in %d keys)\n", 5168c2ecf20Sopenharmony_ci __func__, 5178c2ecf20Sopenharmony_ci ret ? (int)ret : (int)total, 5188c2ecf20Sopenharmony_ci (long)size, 5198c2ecf20Sopenharmony_ci count_keys); 5208c2ecf20Sopenharmony_ci op_release(new_op); 5218c2ecf20Sopenharmony_ci if (ret == 0) 5228c2ecf20Sopenharmony_ci ret = total; 5238c2ecf20Sopenharmony_ciout_unlock: 5248c2ecf20Sopenharmony_ci up_read(&orangefs_inode->xattr_sem); 5258c2ecf20Sopenharmony_ci return ret; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic int orangefs_xattr_set_default(const struct xattr_handler *handler, 5298c2ecf20Sopenharmony_ci struct dentry *unused, 5308c2ecf20Sopenharmony_ci struct inode *inode, 5318c2ecf20Sopenharmony_ci const char *name, 5328c2ecf20Sopenharmony_ci const void *buffer, 5338c2ecf20Sopenharmony_ci size_t size, 5348c2ecf20Sopenharmony_ci int flags) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci return orangefs_inode_setxattr(inode, name, buffer, size, flags); 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic int orangefs_xattr_get_default(const struct xattr_handler *handler, 5408c2ecf20Sopenharmony_ci struct dentry *unused, 5418c2ecf20Sopenharmony_ci struct inode *inode, 5428c2ecf20Sopenharmony_ci const char *name, 5438c2ecf20Sopenharmony_ci void *buffer, 5448c2ecf20Sopenharmony_ci size_t size) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci return orangefs_inode_getxattr(inode, name, buffer, size); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic const struct xattr_handler orangefs_xattr_default_handler = { 5518c2ecf20Sopenharmony_ci .prefix = "", /* match any name => handlers called with full name */ 5528c2ecf20Sopenharmony_ci .get = orangefs_xattr_get_default, 5538c2ecf20Sopenharmony_ci .set = orangefs_xattr_set_default, 5548c2ecf20Sopenharmony_ci}; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ciconst struct xattr_handler *orangefs_xattr_handlers[] = { 5578c2ecf20Sopenharmony_ci &posix_acl_access_xattr_handler, 5588c2ecf20Sopenharmony_ci &posix_acl_default_xattr_handler, 5598c2ecf20Sopenharmony_ci &orangefs_xattr_default_handler, 5608c2ecf20Sopenharmony_ci NULL 5618c2ecf20Sopenharmony_ci}; 562