162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * (C) 2001 Clemson University and The University of Chicago 462306a36Sopenharmony_ci * Copyright 2018 Omnibond Systems, L.L.C. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * See COPYING in top-level directory. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/* 1062306a36Sopenharmony_ci * Linux VFS extended attribute operations. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "protocol.h" 1462306a36Sopenharmony_ci#include "orangefs-kernel.h" 1562306a36Sopenharmony_ci#include "orangefs-bufmap.h" 1662306a36Sopenharmony_ci#include <linux/posix_acl_xattr.h> 1762306a36Sopenharmony_ci#include <linux/xattr.h> 1862306a36Sopenharmony_ci#include <linux/hashtable.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define SYSTEM_ORANGEFS_KEY "system.pvfs2." 2162306a36Sopenharmony_ci#define SYSTEM_ORANGEFS_KEY_LEN 13 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* 2462306a36Sopenharmony_ci * this function returns 2562306a36Sopenharmony_ci * 0 if the key corresponding to name is not meant to be printed as part 2662306a36Sopenharmony_ci * of a listxattr. 2762306a36Sopenharmony_ci * 1 if the key corresponding to name is meant to be returned as part of 2862306a36Sopenharmony_ci * a listxattr. 2962306a36Sopenharmony_ci * The ones that start SYSTEM_ORANGEFS_KEY are the ones to avoid printing. 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_cistatic int is_reserved_key(const char *key, size_t size) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (size < SYSTEM_ORANGEFS_KEY_LEN) 3562306a36Sopenharmony_ci return 1; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci return strncmp(key, SYSTEM_ORANGEFS_KEY, SYSTEM_ORANGEFS_KEY_LEN) ? 1 : 0; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic inline int convert_to_internal_xattr_flags(int setxattr_flags) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci int internal_flag = 0; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (setxattr_flags & XATTR_REPLACE) { 4562306a36Sopenharmony_ci /* Attribute must exist! */ 4662306a36Sopenharmony_ci internal_flag = ORANGEFS_XATTR_REPLACE; 4762306a36Sopenharmony_ci } else if (setxattr_flags & XATTR_CREATE) { 4862306a36Sopenharmony_ci /* Attribute must not exist */ 4962306a36Sopenharmony_ci internal_flag = ORANGEFS_XATTR_CREATE; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci return internal_flag; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic unsigned int xattr_key(const char *key) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci unsigned int i = 0; 5762306a36Sopenharmony_ci while (key) 5862306a36Sopenharmony_ci i += *key++; 5962306a36Sopenharmony_ci return i % 16; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic struct orangefs_cached_xattr *find_cached_xattr(struct inode *inode, 6362306a36Sopenharmony_ci const char *key) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 6662306a36Sopenharmony_ci struct orangefs_cached_xattr *cx; 6762306a36Sopenharmony_ci struct hlist_head *h; 6862306a36Sopenharmony_ci struct hlist_node *tmp; 6962306a36Sopenharmony_ci h = &orangefs_inode->xattr_cache[xattr_key(key)]; 7062306a36Sopenharmony_ci if (hlist_empty(h)) 7162306a36Sopenharmony_ci return NULL; 7262306a36Sopenharmony_ci hlist_for_each_entry_safe(cx, tmp, h, node) { 7362306a36Sopenharmony_ci/* if (!time_before(jiffies, cx->timeout)) { 7462306a36Sopenharmony_ci hlist_del(&cx->node); 7562306a36Sopenharmony_ci kfree(cx); 7662306a36Sopenharmony_ci continue; 7762306a36Sopenharmony_ci }*/ 7862306a36Sopenharmony_ci if (!strcmp(cx->key, key)) 7962306a36Sopenharmony_ci return cx; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci return NULL; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* 8562306a36Sopenharmony_ci * Tries to get a specified key's attributes of a given 8662306a36Sopenharmony_ci * file into a user-specified buffer. Note that the getxattr 8762306a36Sopenharmony_ci * interface allows for the users to probe the size of an 8862306a36Sopenharmony_ci * extended attribute by passing in a value of 0 to size. 8962306a36Sopenharmony_ci * Thus our return value is always the size of the attribute 9062306a36Sopenharmony_ci * unless the key does not exist for the file and/or if 9162306a36Sopenharmony_ci * there were errors in fetching the attribute value. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_cissize_t orangefs_inode_getxattr(struct inode *inode, const char *name, 9462306a36Sopenharmony_ci void *buffer, size_t size) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 9762306a36Sopenharmony_ci struct orangefs_kernel_op_s *new_op = NULL; 9862306a36Sopenharmony_ci struct orangefs_cached_xattr *cx; 9962306a36Sopenharmony_ci ssize_t ret = -ENOMEM; 10062306a36Sopenharmony_ci ssize_t length = 0; 10162306a36Sopenharmony_ci int fsuid; 10262306a36Sopenharmony_ci int fsgid; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 10562306a36Sopenharmony_ci "%s: name %s, buffer_size %zd\n", 10662306a36Sopenharmony_ci __func__, name, size); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (S_ISLNK(inode->i_mode)) 10962306a36Sopenharmony_ci return -EOPNOTSUPP; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) 11262306a36Sopenharmony_ci return -EINVAL; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci fsuid = from_kuid(&init_user_ns, current_fsuid()); 11562306a36Sopenharmony_ci fsgid = from_kgid(&init_user_ns, current_fsgid()); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 11862306a36Sopenharmony_ci "getxattr on inode %pU, name %s " 11962306a36Sopenharmony_ci "(uid %o, gid %o)\n", 12062306a36Sopenharmony_ci get_khandle_from_ino(inode), 12162306a36Sopenharmony_ci name, 12262306a36Sopenharmony_ci fsuid, 12362306a36Sopenharmony_ci fsgid); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci down_read(&orangefs_inode->xattr_sem); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci cx = find_cached_xattr(inode, name); 12862306a36Sopenharmony_ci if (cx && time_before(jiffies, cx->timeout)) { 12962306a36Sopenharmony_ci if (cx->length == -1) { 13062306a36Sopenharmony_ci ret = -ENODATA; 13162306a36Sopenharmony_ci goto out_unlock; 13262306a36Sopenharmony_ci } else { 13362306a36Sopenharmony_ci if (size == 0) { 13462306a36Sopenharmony_ci ret = cx->length; 13562306a36Sopenharmony_ci goto out_unlock; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci if (cx->length > size) { 13862306a36Sopenharmony_ci ret = -ERANGE; 13962306a36Sopenharmony_ci goto out_unlock; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci memcpy(buffer, cx->val, cx->length); 14262306a36Sopenharmony_ci memset(buffer + cx->length, 0, size - cx->length); 14362306a36Sopenharmony_ci ret = cx->length; 14462306a36Sopenharmony_ci goto out_unlock; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci new_op = op_alloc(ORANGEFS_VFS_OP_GETXATTR); 14962306a36Sopenharmony_ci if (!new_op) 15062306a36Sopenharmony_ci goto out_unlock; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci new_op->upcall.req.getxattr.refn = orangefs_inode->refn; 15362306a36Sopenharmony_ci strcpy(new_op->upcall.req.getxattr.key, name); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* 15662306a36Sopenharmony_ci * NOTE: Although keys are meant to be NULL terminated textual 15762306a36Sopenharmony_ci * strings, I am going to explicitly pass the length just in case 15862306a36Sopenharmony_ci * we change this later on... 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_ci new_op->upcall.req.getxattr.key_sz = strlen(name) + 1; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci ret = service_operation(new_op, "orangefs_inode_getxattr", 16362306a36Sopenharmony_ci get_interruptible_flag(inode)); 16462306a36Sopenharmony_ci if (ret != 0) { 16562306a36Sopenharmony_ci if (ret == -ENOENT) { 16662306a36Sopenharmony_ci ret = -ENODATA; 16762306a36Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 16862306a36Sopenharmony_ci "orangefs_inode_getxattr: inode %pU key %s" 16962306a36Sopenharmony_ci " does not exist!\n", 17062306a36Sopenharmony_ci get_khandle_from_ino(inode), 17162306a36Sopenharmony_ci (char *)new_op->upcall.req.getxattr.key); 17262306a36Sopenharmony_ci cx = kmalloc(sizeof *cx, GFP_KERNEL); 17362306a36Sopenharmony_ci if (cx) { 17462306a36Sopenharmony_ci strcpy(cx->key, name); 17562306a36Sopenharmony_ci cx->length = -1; 17662306a36Sopenharmony_ci cx->timeout = jiffies + 17762306a36Sopenharmony_ci orangefs_getattr_timeout_msecs*HZ/1000; 17862306a36Sopenharmony_ci hash_add(orangefs_inode->xattr_cache, &cx->node, 17962306a36Sopenharmony_ci xattr_key(cx->key)); 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci goto out_release_op; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* 18662306a36Sopenharmony_ci * Length returned includes null terminator. 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_ci length = new_op->downcall.resp.getxattr.val_sz; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* 19162306a36Sopenharmony_ci * Just return the length of the queried attribute. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci if (size == 0) { 19462306a36Sopenharmony_ci ret = length; 19562306a36Sopenharmony_ci goto out_release_op; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* 19962306a36Sopenharmony_ci * Check to see if key length is > provided buffer size. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci if (length > size) { 20262306a36Sopenharmony_ci ret = -ERANGE; 20362306a36Sopenharmony_ci goto out_release_op; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci memcpy(buffer, new_op->downcall.resp.getxattr.val, length); 20762306a36Sopenharmony_ci memset(buffer + length, 0, size - length); 20862306a36Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 20962306a36Sopenharmony_ci "orangefs_inode_getxattr: inode %pU " 21062306a36Sopenharmony_ci "key %s key_sz %d, val_len %d\n", 21162306a36Sopenharmony_ci get_khandle_from_ino(inode), 21262306a36Sopenharmony_ci (char *)new_op-> 21362306a36Sopenharmony_ci upcall.req.getxattr.key, 21462306a36Sopenharmony_ci (int)new_op-> 21562306a36Sopenharmony_ci upcall.req.getxattr.key_sz, 21662306a36Sopenharmony_ci (int)ret); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci ret = length; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (cx) { 22162306a36Sopenharmony_ci strcpy(cx->key, name); 22262306a36Sopenharmony_ci memcpy(cx->val, buffer, length); 22362306a36Sopenharmony_ci cx->length = length; 22462306a36Sopenharmony_ci cx->timeout = jiffies + HZ; 22562306a36Sopenharmony_ci } else { 22662306a36Sopenharmony_ci cx = kmalloc(sizeof *cx, GFP_KERNEL); 22762306a36Sopenharmony_ci if (cx) { 22862306a36Sopenharmony_ci strcpy(cx->key, name); 22962306a36Sopenharmony_ci memcpy(cx->val, buffer, length); 23062306a36Sopenharmony_ci cx->length = length; 23162306a36Sopenharmony_ci cx->timeout = jiffies + HZ; 23262306a36Sopenharmony_ci hash_add(orangefs_inode->xattr_cache, &cx->node, 23362306a36Sopenharmony_ci xattr_key(cx->key)); 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ciout_release_op: 23862306a36Sopenharmony_ci op_release(new_op); 23962306a36Sopenharmony_ciout_unlock: 24062306a36Sopenharmony_ci up_read(&orangefs_inode->xattr_sem); 24162306a36Sopenharmony_ci return ret; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic int orangefs_inode_removexattr(struct inode *inode, const char *name, 24562306a36Sopenharmony_ci int flags) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 24862306a36Sopenharmony_ci struct orangefs_kernel_op_s *new_op = NULL; 24962306a36Sopenharmony_ci struct orangefs_cached_xattr *cx; 25062306a36Sopenharmony_ci struct hlist_head *h; 25162306a36Sopenharmony_ci struct hlist_node *tmp; 25262306a36Sopenharmony_ci int ret = -ENOMEM; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) 25562306a36Sopenharmony_ci return -EINVAL; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci down_write(&orangefs_inode->xattr_sem); 25862306a36Sopenharmony_ci new_op = op_alloc(ORANGEFS_VFS_OP_REMOVEXATTR); 25962306a36Sopenharmony_ci if (!new_op) 26062306a36Sopenharmony_ci goto out_unlock; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci new_op->upcall.req.removexattr.refn = orangefs_inode->refn; 26362306a36Sopenharmony_ci /* 26462306a36Sopenharmony_ci * NOTE: Although keys are meant to be NULL terminated 26562306a36Sopenharmony_ci * textual strings, I am going to explicitly pass the 26662306a36Sopenharmony_ci * length just in case we change this later on... 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_ci strcpy(new_op->upcall.req.removexattr.key, name); 26962306a36Sopenharmony_ci new_op->upcall.req.removexattr.key_sz = strlen(name) + 1; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 27262306a36Sopenharmony_ci "orangefs_inode_removexattr: key %s, key_sz %d\n", 27362306a36Sopenharmony_ci (char *)new_op->upcall.req.removexattr.key, 27462306a36Sopenharmony_ci (int)new_op->upcall.req.removexattr.key_sz); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci ret = service_operation(new_op, 27762306a36Sopenharmony_ci "orangefs_inode_removexattr", 27862306a36Sopenharmony_ci get_interruptible_flag(inode)); 27962306a36Sopenharmony_ci if (ret == -ENOENT) { 28062306a36Sopenharmony_ci /* 28162306a36Sopenharmony_ci * Request to replace a non-existent attribute is an error. 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_ci if (flags & XATTR_REPLACE) 28462306a36Sopenharmony_ci ret = -ENODATA; 28562306a36Sopenharmony_ci else 28662306a36Sopenharmony_ci ret = 0; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 29062306a36Sopenharmony_ci "orangefs_inode_removexattr: returning %d\n", ret); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci op_release(new_op); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci h = &orangefs_inode->xattr_cache[xattr_key(name)]; 29562306a36Sopenharmony_ci hlist_for_each_entry_safe(cx, tmp, h, node) { 29662306a36Sopenharmony_ci if (!strcmp(cx->key, name)) { 29762306a36Sopenharmony_ci hlist_del(&cx->node); 29862306a36Sopenharmony_ci kfree(cx); 29962306a36Sopenharmony_ci break; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ciout_unlock: 30462306a36Sopenharmony_ci up_write(&orangefs_inode->xattr_sem); 30562306a36Sopenharmony_ci return ret; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci/* 30962306a36Sopenharmony_ci * Tries to set an attribute for a given key on a file. 31062306a36Sopenharmony_ci * 31162306a36Sopenharmony_ci * Returns a -ve number on error and 0 on success. Key is text, but value 31262306a36Sopenharmony_ci * can be binary! 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_ciint orangefs_inode_setxattr(struct inode *inode, const char *name, 31562306a36Sopenharmony_ci const void *value, size_t size, int flags) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 31862306a36Sopenharmony_ci struct orangefs_kernel_op_s *new_op; 31962306a36Sopenharmony_ci int internal_flag = 0; 32062306a36Sopenharmony_ci struct orangefs_cached_xattr *cx; 32162306a36Sopenharmony_ci struct hlist_head *h; 32262306a36Sopenharmony_ci struct hlist_node *tmp; 32362306a36Sopenharmony_ci int ret = -ENOMEM; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 32662306a36Sopenharmony_ci "%s: name %s, buffer_size %zd\n", 32762306a36Sopenharmony_ci __func__, name, size); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (size > ORANGEFS_MAX_XATTR_VALUELEN) 33062306a36Sopenharmony_ci return -EINVAL; 33162306a36Sopenharmony_ci if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) 33262306a36Sopenharmony_ci return -EINVAL; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci internal_flag = convert_to_internal_xattr_flags(flags); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* This is equivalent to a removexattr */ 33762306a36Sopenharmony_ci if (size == 0 && !value) { 33862306a36Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 33962306a36Sopenharmony_ci "removing xattr (%s)\n", 34062306a36Sopenharmony_ci name); 34162306a36Sopenharmony_ci return orangefs_inode_removexattr(inode, name, flags); 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 34562306a36Sopenharmony_ci "setxattr on inode %pU, name %s\n", 34662306a36Sopenharmony_ci get_khandle_from_ino(inode), 34762306a36Sopenharmony_ci name); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci down_write(&orangefs_inode->xattr_sem); 35062306a36Sopenharmony_ci new_op = op_alloc(ORANGEFS_VFS_OP_SETXATTR); 35162306a36Sopenharmony_ci if (!new_op) 35262306a36Sopenharmony_ci goto out_unlock; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci new_op->upcall.req.setxattr.refn = orangefs_inode->refn; 35662306a36Sopenharmony_ci new_op->upcall.req.setxattr.flags = internal_flag; 35762306a36Sopenharmony_ci /* 35862306a36Sopenharmony_ci * NOTE: Although keys are meant to be NULL terminated textual 35962306a36Sopenharmony_ci * strings, I am going to explicitly pass the length just in 36062306a36Sopenharmony_ci * case we change this later on... 36162306a36Sopenharmony_ci */ 36262306a36Sopenharmony_ci strcpy(new_op->upcall.req.setxattr.keyval.key, name); 36362306a36Sopenharmony_ci new_op->upcall.req.setxattr.keyval.key_sz = strlen(name) + 1; 36462306a36Sopenharmony_ci memcpy(new_op->upcall.req.setxattr.keyval.val, value, size); 36562306a36Sopenharmony_ci new_op->upcall.req.setxattr.keyval.val_sz = size; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 36862306a36Sopenharmony_ci "orangefs_inode_setxattr: key %s, key_sz %d " 36962306a36Sopenharmony_ci " value size %zd\n", 37062306a36Sopenharmony_ci (char *)new_op->upcall.req.setxattr.keyval.key, 37162306a36Sopenharmony_ci (int)new_op->upcall.req.setxattr.keyval.key_sz, 37262306a36Sopenharmony_ci size); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci ret = service_operation(new_op, 37562306a36Sopenharmony_ci "orangefs_inode_setxattr", 37662306a36Sopenharmony_ci get_interruptible_flag(inode)); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, 37962306a36Sopenharmony_ci "orangefs_inode_setxattr: returning %d\n", 38062306a36Sopenharmony_ci ret); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* when request is serviced properly, free req op struct */ 38362306a36Sopenharmony_ci op_release(new_op); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci h = &orangefs_inode->xattr_cache[xattr_key(name)]; 38662306a36Sopenharmony_ci hlist_for_each_entry_safe(cx, tmp, h, node) { 38762306a36Sopenharmony_ci if (!strcmp(cx->key, name)) { 38862306a36Sopenharmony_ci hlist_del(&cx->node); 38962306a36Sopenharmony_ci kfree(cx); 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ciout_unlock: 39562306a36Sopenharmony_ci up_write(&orangefs_inode->xattr_sem); 39662306a36Sopenharmony_ci return ret; 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci/* 40062306a36Sopenharmony_ci * Tries to get a specified object's keys into a user-specified buffer of a 40162306a36Sopenharmony_ci * given size. Note that like the previous instances of xattr routines, this 40262306a36Sopenharmony_ci * also allows you to pass in a NULL pointer and 0 size to probe the size for 40362306a36Sopenharmony_ci * subsequent memory allocations. Thus our return value is always the size of 40462306a36Sopenharmony_ci * all the keys unless there were errors in fetching the keys! 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_cissize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct inode *inode = dentry->d_inode; 40962306a36Sopenharmony_ci struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 41062306a36Sopenharmony_ci struct orangefs_kernel_op_s *new_op; 41162306a36Sopenharmony_ci __u64 token = ORANGEFS_ITERATE_START; 41262306a36Sopenharmony_ci ssize_t ret = -ENOMEM; 41362306a36Sopenharmony_ci ssize_t total = 0; 41462306a36Sopenharmony_ci int count_keys = 0; 41562306a36Sopenharmony_ci int key_size; 41662306a36Sopenharmony_ci int i = 0; 41762306a36Sopenharmony_ci int returned_count = 0; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (size > 0 && !buffer) { 42062306a36Sopenharmony_ci gossip_err("%s: bogus NULL pointers\n", __func__); 42162306a36Sopenharmony_ci return -EINVAL; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci down_read(&orangefs_inode->xattr_sem); 42562306a36Sopenharmony_ci new_op = op_alloc(ORANGEFS_VFS_OP_LISTXATTR); 42662306a36Sopenharmony_ci if (!new_op) 42762306a36Sopenharmony_ci goto out_unlock; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (buffer && size > 0) 43062306a36Sopenharmony_ci memset(buffer, 0, size); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_citry_again: 43362306a36Sopenharmony_ci key_size = 0; 43462306a36Sopenharmony_ci new_op->upcall.req.listxattr.refn = orangefs_inode->refn; 43562306a36Sopenharmony_ci new_op->upcall.req.listxattr.token = token; 43662306a36Sopenharmony_ci new_op->upcall.req.listxattr.requested_count = 43762306a36Sopenharmony_ci (size == 0) ? 0 : ORANGEFS_MAX_XATTR_LISTLEN; 43862306a36Sopenharmony_ci ret = service_operation(new_op, __func__, 43962306a36Sopenharmony_ci get_interruptible_flag(inode)); 44062306a36Sopenharmony_ci if (ret != 0) 44162306a36Sopenharmony_ci goto done; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (size == 0) { 44462306a36Sopenharmony_ci /* 44562306a36Sopenharmony_ci * This is a bit of a big upper limit, but I did not want to 44662306a36Sopenharmony_ci * spend too much time getting this correct, since users end 44762306a36Sopenharmony_ci * up allocating memory rather than us... 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_ci total = new_op->downcall.resp.listxattr.returned_count * 45062306a36Sopenharmony_ci ORANGEFS_MAX_XATTR_NAMELEN; 45162306a36Sopenharmony_ci goto done; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci returned_count = new_op->downcall.resp.listxattr.returned_count; 45562306a36Sopenharmony_ci if (returned_count < 0 || 45662306a36Sopenharmony_ci returned_count > ORANGEFS_MAX_XATTR_LISTLEN) { 45762306a36Sopenharmony_ci gossip_err("%s: impossible value for returned_count:%d:\n", 45862306a36Sopenharmony_ci __func__, 45962306a36Sopenharmony_ci returned_count); 46062306a36Sopenharmony_ci ret = -EIO; 46162306a36Sopenharmony_ci goto done; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* 46562306a36Sopenharmony_ci * Check to see how much can be fit in the buffer. Fit only whole keys. 46662306a36Sopenharmony_ci */ 46762306a36Sopenharmony_ci for (i = 0; i < returned_count; i++) { 46862306a36Sopenharmony_ci if (new_op->downcall.resp.listxattr.lengths[i] < 0 || 46962306a36Sopenharmony_ci new_op->downcall.resp.listxattr.lengths[i] > 47062306a36Sopenharmony_ci ORANGEFS_MAX_XATTR_NAMELEN) { 47162306a36Sopenharmony_ci gossip_err("%s: impossible value for lengths[%d]\n", 47262306a36Sopenharmony_ci __func__, 47362306a36Sopenharmony_ci new_op->downcall.resp.listxattr.lengths[i]); 47462306a36Sopenharmony_ci ret = -EIO; 47562306a36Sopenharmony_ci goto done; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci if (total + new_op->downcall.resp.listxattr.lengths[i] > size) 47862306a36Sopenharmony_ci goto done; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* 48162306a36Sopenharmony_ci * Since many dumb programs try to setxattr() on our reserved 48262306a36Sopenharmony_ci * xattrs this is a feeble attempt at defeating those by not 48362306a36Sopenharmony_ci * listing them in the output of listxattr.. sigh 48462306a36Sopenharmony_ci */ 48562306a36Sopenharmony_ci if (is_reserved_key(new_op->downcall.resp.listxattr.key + 48662306a36Sopenharmony_ci key_size, 48762306a36Sopenharmony_ci new_op->downcall.resp. 48862306a36Sopenharmony_ci listxattr.lengths[i])) { 48962306a36Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, "Copying key %d -> %s\n", 49062306a36Sopenharmony_ci i, new_op->downcall.resp.listxattr.key + 49162306a36Sopenharmony_ci key_size); 49262306a36Sopenharmony_ci memcpy(buffer + total, 49362306a36Sopenharmony_ci new_op->downcall.resp.listxattr.key + key_size, 49462306a36Sopenharmony_ci new_op->downcall.resp.listxattr.lengths[i]); 49562306a36Sopenharmony_ci total += new_op->downcall.resp.listxattr.lengths[i]; 49662306a36Sopenharmony_ci count_keys++; 49762306a36Sopenharmony_ci } else { 49862306a36Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, "[RESERVED] key %d -> %s\n", 49962306a36Sopenharmony_ci i, new_op->downcall.resp.listxattr.key + 50062306a36Sopenharmony_ci key_size); 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci key_size += new_op->downcall.resp.listxattr.lengths[i]; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* 50662306a36Sopenharmony_ci * Since the buffer was large enough, we might have to continue 50762306a36Sopenharmony_ci * fetching more keys! 50862306a36Sopenharmony_ci */ 50962306a36Sopenharmony_ci token = new_op->downcall.resp.listxattr.token; 51062306a36Sopenharmony_ci if (token != ORANGEFS_ITERATE_END) 51162306a36Sopenharmony_ci goto try_again; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cidone: 51462306a36Sopenharmony_ci gossip_debug(GOSSIP_XATTR_DEBUG, "%s: returning %d" 51562306a36Sopenharmony_ci " [size of buffer %ld] (filled in %d keys)\n", 51662306a36Sopenharmony_ci __func__, 51762306a36Sopenharmony_ci ret ? (int)ret : (int)total, 51862306a36Sopenharmony_ci (long)size, 51962306a36Sopenharmony_ci count_keys); 52062306a36Sopenharmony_ci op_release(new_op); 52162306a36Sopenharmony_ci if (ret == 0) 52262306a36Sopenharmony_ci ret = total; 52362306a36Sopenharmony_ciout_unlock: 52462306a36Sopenharmony_ci up_read(&orangefs_inode->xattr_sem); 52562306a36Sopenharmony_ci return ret; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic int orangefs_xattr_set_default(const struct xattr_handler *handler, 52962306a36Sopenharmony_ci struct mnt_idmap *idmap, 53062306a36Sopenharmony_ci struct dentry *unused, 53162306a36Sopenharmony_ci struct inode *inode, 53262306a36Sopenharmony_ci const char *name, 53362306a36Sopenharmony_ci const void *buffer, 53462306a36Sopenharmony_ci size_t size, 53562306a36Sopenharmony_ci int flags) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci return orangefs_inode_setxattr(inode, name, buffer, size, flags); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic int orangefs_xattr_get_default(const struct xattr_handler *handler, 54162306a36Sopenharmony_ci struct dentry *unused, 54262306a36Sopenharmony_ci struct inode *inode, 54362306a36Sopenharmony_ci const char *name, 54462306a36Sopenharmony_ci void *buffer, 54562306a36Sopenharmony_ci size_t size) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci return orangefs_inode_getxattr(inode, name, buffer, size); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic const struct xattr_handler orangefs_xattr_default_handler = { 55262306a36Sopenharmony_ci .prefix = "", /* match any name => handlers called with full name */ 55362306a36Sopenharmony_ci .get = orangefs_xattr_get_default, 55462306a36Sopenharmony_ci .set = orangefs_xattr_set_default, 55562306a36Sopenharmony_ci}; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ciconst struct xattr_handler *orangefs_xattr_handlers[] = { 55862306a36Sopenharmony_ci &orangefs_xattr_default_handler, 55962306a36Sopenharmony_ci NULL 56062306a36Sopenharmony_ci}; 561