1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21182fca3SMike Marshall /* 31182fca3SMike Marshall * (C) 2001 Clemson University and The University of Chicago 4fc2e2e9cSMartin Brandenburg * Copyright 2018 Omnibond Systems, L.L.C. 51182fca3SMike Marshall * 61182fca3SMike Marshall * See COPYING in top-level directory. 71182fca3SMike Marshall */ 81182fca3SMike Marshall 91182fca3SMike Marshall /* 101182fca3SMike Marshall * Linux VFS extended attribute operations. 111182fca3SMike Marshall */ 121182fca3SMike Marshall 131182fca3SMike Marshall #include "protocol.h" 14575e9461SMike Marshall #include "orangefs-kernel.h" 15575e9461SMike Marshall #include "orangefs-bufmap.h" 161182fca3SMike Marshall #include <linux/posix_acl_xattr.h> 171182fca3SMike Marshall #include <linux/xattr.h> 18fc2e2e9cSMartin Brandenburg #include <linux/hashtable.h> 191182fca3SMike Marshall 208bb8aefdSYi Liu #define SYSTEM_ORANGEFS_KEY "system.pvfs2." 218bb8aefdSYi Liu #define SYSTEM_ORANGEFS_KEY_LEN 13 221182fca3SMike Marshall 231182fca3SMike Marshall /* 241182fca3SMike Marshall * this function returns 251182fca3SMike Marshall * 0 if the key corresponding to name is not meant to be printed as part 261182fca3SMike Marshall * of a listxattr. 271182fca3SMike Marshall * 1 if the key corresponding to name is meant to be returned as part of 281182fca3SMike Marshall * a listxattr. 298bb8aefdSYi Liu * The ones that start SYSTEM_ORANGEFS_KEY are the ones to avoid printing. 301182fca3SMike Marshall */ 311182fca3SMike Marshall static int is_reserved_key(const char *key, size_t size) 321182fca3SMike Marshall { 331182fca3SMike Marshall 348bb8aefdSYi Liu if (size < SYSTEM_ORANGEFS_KEY_LEN) 351182fca3SMike Marshall return 1; 361182fca3SMike Marshall 378bb8aefdSYi Liu return strncmp(key, SYSTEM_ORANGEFS_KEY, SYSTEM_ORANGEFS_KEY_LEN) ? 1 : 0; 381182fca3SMike Marshall } 391182fca3SMike Marshall 401182fca3SMike Marshall static inline int convert_to_internal_xattr_flags(int setxattr_flags) 411182fca3SMike Marshall { 421182fca3SMike Marshall int internal_flag = 0; 431182fca3SMike Marshall 441182fca3SMike Marshall if (setxattr_flags & XATTR_REPLACE) { 451182fca3SMike Marshall /* Attribute must exist! */ 468bb8aefdSYi Liu internal_flag = ORANGEFS_XATTR_REPLACE; 471182fca3SMike Marshall } else if (setxattr_flags & XATTR_CREATE) { 481182fca3SMike Marshall /* Attribute must not exist */ 498bb8aefdSYi Liu internal_flag = ORANGEFS_XATTR_CREATE; 501182fca3SMike Marshall } 511182fca3SMike Marshall return internal_flag; 521182fca3SMike Marshall } 531182fca3SMike Marshall 54fc2e2e9cSMartin Brandenburg static unsigned int xattr_key(const char *key) 55fc2e2e9cSMartin Brandenburg { 56fc2e2e9cSMartin Brandenburg unsigned int i = 0; 57fc2e2e9cSMartin Brandenburg while (key) 58fc2e2e9cSMartin Brandenburg i += *key++; 59fc2e2e9cSMartin Brandenburg return i % 16; 60fc2e2e9cSMartin Brandenburg } 61fc2e2e9cSMartin Brandenburg 62fc2e2e9cSMartin Brandenburg static struct orangefs_cached_xattr *find_cached_xattr(struct inode *inode, 63fc2e2e9cSMartin Brandenburg const char *key) 64fc2e2e9cSMartin Brandenburg { 65fc2e2e9cSMartin Brandenburg struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 66fc2e2e9cSMartin Brandenburg struct orangefs_cached_xattr *cx; 67fc2e2e9cSMartin Brandenburg struct hlist_head *h; 68fc2e2e9cSMartin Brandenburg struct hlist_node *tmp; 69fc2e2e9cSMartin Brandenburg h = &orangefs_inode->xattr_cache[xattr_key(key)]; 70fc2e2e9cSMartin Brandenburg if (hlist_empty(h)) 71fc2e2e9cSMartin Brandenburg return NULL; 72fc2e2e9cSMartin Brandenburg hlist_for_each_entry_safe(cx, tmp, h, node) { 73fc2e2e9cSMartin Brandenburg /* if (!time_before(jiffies, cx->timeout)) { 74fc2e2e9cSMartin Brandenburg hlist_del(&cx->node); 75fc2e2e9cSMartin Brandenburg kfree(cx); 76fc2e2e9cSMartin Brandenburg continue; 77fc2e2e9cSMartin Brandenburg }*/ 78fc2e2e9cSMartin Brandenburg if (!strcmp(cx->key, key)) 79fc2e2e9cSMartin Brandenburg return cx; 80fc2e2e9cSMartin Brandenburg } 81fc2e2e9cSMartin Brandenburg return NULL; 82fc2e2e9cSMartin Brandenburg } 831182fca3SMike Marshall 841182fca3SMike Marshall /* 851182fca3SMike Marshall * Tries to get a specified key's attributes of a given 861182fca3SMike Marshall * file into a user-specified buffer. Note that the getxattr 871182fca3SMike Marshall * interface allows for the users to probe the size of an 881182fca3SMike Marshall * extended attribute by passing in a value of 0 to size. 891182fca3SMike Marshall * Thus our return value is always the size of the attribute 901182fca3SMike Marshall * unless the key does not exist for the file and/or if 911182fca3SMike Marshall * there were errors in fetching the attribute value. 921182fca3SMike Marshall */ 93d373a712SAndreas Gruenbacher ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name, 94d373a712SAndreas Gruenbacher void *buffer, size_t size) 951182fca3SMike Marshall { 968bb8aefdSYi Liu struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 978bb8aefdSYi Liu struct orangefs_kernel_op_s *new_op = NULL; 98fc2e2e9cSMartin Brandenburg struct orangefs_cached_xattr *cx; 991182fca3SMike Marshall ssize_t ret = -ENOMEM; 1001182fca3SMike Marshall ssize_t length = 0; 1011182fca3SMike Marshall int fsuid; 1021182fca3SMike Marshall int fsgid; 1031182fca3SMike Marshall 1041182fca3SMike Marshall gossip_debug(GOSSIP_XATTR_DEBUG, 105d373a712SAndreas Gruenbacher "%s: name %s, buffer_size %zd\n", 106d373a712SAndreas Gruenbacher __func__, name, size); 1071182fca3SMike Marshall 1086c6ef9f2SAndreas Gruenbacher if (S_ISLNK(inode->i_mode)) 1096c6ef9f2SAndreas Gruenbacher return -EOPNOTSUPP; 1106c6ef9f2SAndreas Gruenbacher 1115f13e587SDan Carpenter if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) 1121182fca3SMike Marshall return -EINVAL; 1131182fca3SMike Marshall 11478fee0b6SJann Horn fsuid = from_kuid(&init_user_ns, current_fsuid()); 11578fee0b6SJann Horn fsgid = from_kgid(&init_user_ns, current_fsgid()); 1161182fca3SMike Marshall 1171182fca3SMike Marshall gossip_debug(GOSSIP_XATTR_DEBUG, 1181182fca3SMike Marshall "getxattr on inode %pU, name %s " 1191182fca3SMike Marshall "(uid %o, gid %o)\n", 1201182fca3SMike Marshall get_khandle_from_ino(inode), 1211182fca3SMike Marshall name, 1221182fca3SMike Marshall fsuid, 1231182fca3SMike Marshall fsgid); 1241182fca3SMike Marshall 1258bb8aefdSYi Liu down_read(&orangefs_inode->xattr_sem); 1261182fca3SMike Marshall 127fc2e2e9cSMartin Brandenburg cx = find_cached_xattr(inode, name); 128fc2e2e9cSMartin Brandenburg if (cx && time_before(jiffies, cx->timeout)) { 129fc2e2e9cSMartin Brandenburg if (cx->length == -1) { 130fc2e2e9cSMartin Brandenburg ret = -ENODATA; 131fc2e2e9cSMartin Brandenburg goto out_unlock; 132fc2e2e9cSMartin Brandenburg } else { 133fc2e2e9cSMartin Brandenburg if (size == 0) { 134fc2e2e9cSMartin Brandenburg ret = cx->length; 135fc2e2e9cSMartin Brandenburg goto out_unlock; 136fc2e2e9cSMartin Brandenburg } 137fc2e2e9cSMartin Brandenburg if (cx->length > size) { 138fc2e2e9cSMartin Brandenburg ret = -ERANGE; 139fc2e2e9cSMartin Brandenburg goto out_unlock; 140fc2e2e9cSMartin Brandenburg } 141fc2e2e9cSMartin Brandenburg memcpy(buffer, cx->val, cx->length); 142fc2e2e9cSMartin Brandenburg memset(buffer + cx->length, 0, size - cx->length); 143fc2e2e9cSMartin Brandenburg ret = cx->length; 144fc2e2e9cSMartin Brandenburg goto out_unlock; 145fc2e2e9cSMartin Brandenburg } 146fc2e2e9cSMartin Brandenburg } 147fc2e2e9cSMartin Brandenburg 1488bb8aefdSYi Liu new_op = op_alloc(ORANGEFS_VFS_OP_GETXATTR); 1491182fca3SMike Marshall if (!new_op) 1501182fca3SMike Marshall goto out_unlock; 1511182fca3SMike Marshall 1528bb8aefdSYi Liu new_op->upcall.req.getxattr.refn = orangefs_inode->refn; 153d373a712SAndreas Gruenbacher strcpy(new_op->upcall.req.getxattr.key, name); 1541182fca3SMike Marshall 1551182fca3SMike Marshall /* 1561182fca3SMike Marshall * NOTE: Although keys are meant to be NULL terminated textual 1571182fca3SMike Marshall * strings, I am going to explicitly pass the length just in case 1581182fca3SMike Marshall * we change this later on... 1591182fca3SMike Marshall */ 160d373a712SAndreas Gruenbacher new_op->upcall.req.getxattr.key_sz = strlen(name) + 1; 1611182fca3SMike Marshall 1628bb8aefdSYi Liu ret = service_operation(new_op, "orangefs_inode_getxattr", 1631182fca3SMike Marshall get_interruptible_flag(inode)); 1641182fca3SMike Marshall if (ret != 0) { 1651182fca3SMike Marshall if (ret == -ENOENT) { 1661182fca3SMike Marshall ret = -ENODATA; 1671182fca3SMike Marshall gossip_debug(GOSSIP_XATTR_DEBUG, 1688bb8aefdSYi Liu "orangefs_inode_getxattr: inode %pU key %s" 1691182fca3SMike Marshall " does not exist!\n", 1701182fca3SMike Marshall get_khandle_from_ino(inode), 1711182fca3SMike Marshall (char *)new_op->upcall.req.getxattr.key); 172fc2e2e9cSMartin Brandenburg cx = kmalloc(sizeof *cx, GFP_KERNEL); 173fc2e2e9cSMartin Brandenburg if (cx) { 174fc2e2e9cSMartin Brandenburg strcpy(cx->key, name); 175fc2e2e9cSMartin Brandenburg cx->length = -1; 176fc2e2e9cSMartin Brandenburg cx->timeout = jiffies + 177fc2e2e9cSMartin Brandenburg orangefs_getattr_timeout_msecs*HZ/1000; 178fc2e2e9cSMartin Brandenburg hash_add(orangefs_inode->xattr_cache, &cx->node, 179fc2e2e9cSMartin Brandenburg xattr_key(cx->key)); 180fc2e2e9cSMartin Brandenburg } 1811182fca3SMike Marshall } 1821182fca3SMike Marshall goto out_release_op; 1831182fca3SMike Marshall } 1841182fca3SMike Marshall 1851182fca3SMike Marshall /* 1861182fca3SMike Marshall * Length returned includes null terminator. 1871182fca3SMike Marshall */ 1881182fca3SMike Marshall length = new_op->downcall.resp.getxattr.val_sz; 1891182fca3SMike Marshall 1901182fca3SMike Marshall /* 1911182fca3SMike Marshall * Just return the length of the queried attribute. 1921182fca3SMike Marshall */ 1931182fca3SMike Marshall if (size == 0) { 1941182fca3SMike Marshall ret = length; 1951182fca3SMike Marshall goto out_release_op; 1961182fca3SMike Marshall } 1971182fca3SMike Marshall 1981182fca3SMike Marshall /* 1991182fca3SMike Marshall * Check to see if key length is > provided buffer size. 2001182fca3SMike Marshall */ 2011182fca3SMike Marshall if (length > size) { 2021182fca3SMike Marshall ret = -ERANGE; 2031182fca3SMike Marshall goto out_release_op; 2041182fca3SMike Marshall } 2051182fca3SMike Marshall 2061182fca3SMike Marshall memcpy(buffer, new_op->downcall.resp.getxattr.val, length); 207a9bb3ba8SMike Marshall memset(buffer + length, 0, size - length); 2081182fca3SMike Marshall gossip_debug(GOSSIP_XATTR_DEBUG, 2098bb8aefdSYi Liu "orangefs_inode_getxattr: inode %pU " 2101182fca3SMike Marshall "key %s key_sz %d, val_len %d\n", 2111182fca3SMike Marshall get_khandle_from_ino(inode), 2121182fca3SMike Marshall (char *)new_op-> 2131182fca3SMike Marshall upcall.req.getxattr.key, 2141182fca3SMike Marshall (int)new_op-> 2151182fca3SMike Marshall upcall.req.getxattr.key_sz, 2161182fca3SMike Marshall (int)ret); 2171182fca3SMike Marshall 2181182fca3SMike Marshall ret = length; 2191182fca3SMike Marshall 220fc2e2e9cSMartin Brandenburg if (cx) { 221fc2e2e9cSMartin Brandenburg strcpy(cx->key, name); 222fc2e2e9cSMartin Brandenburg memcpy(cx->val, buffer, length); 223fc2e2e9cSMartin Brandenburg cx->length = length; 224fc2e2e9cSMartin Brandenburg cx->timeout = jiffies + HZ; 225fc2e2e9cSMartin Brandenburg } else { 226fc2e2e9cSMartin Brandenburg cx = kmalloc(sizeof *cx, GFP_KERNEL); 227fc2e2e9cSMartin Brandenburg if (cx) { 228fc2e2e9cSMartin Brandenburg strcpy(cx->key, name); 229fc2e2e9cSMartin Brandenburg memcpy(cx->val, buffer, length); 230fc2e2e9cSMartin Brandenburg cx->length = length; 231fc2e2e9cSMartin Brandenburg cx->timeout = jiffies + HZ; 232fc2e2e9cSMartin Brandenburg hash_add(orangefs_inode->xattr_cache, &cx->node, 233fc2e2e9cSMartin Brandenburg xattr_key(cx->key)); 234fc2e2e9cSMartin Brandenburg } 235fc2e2e9cSMartin Brandenburg } 236fc2e2e9cSMartin Brandenburg 2371182fca3SMike Marshall out_release_op: 2381182fca3SMike Marshall op_release(new_op); 2391182fca3SMike Marshall out_unlock: 2408bb8aefdSYi Liu up_read(&orangefs_inode->xattr_sem); 2411182fca3SMike Marshall return ret; 2421182fca3SMike Marshall } 2431182fca3SMike Marshall 244d373a712SAndreas Gruenbacher static int orangefs_inode_removexattr(struct inode *inode, const char *name, 2451182fca3SMike Marshall int flags) 2461182fca3SMike Marshall { 2478bb8aefdSYi Liu struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 2488bb8aefdSYi Liu struct orangefs_kernel_op_s *new_op = NULL; 249fc2e2e9cSMartin Brandenburg struct orangefs_cached_xattr *cx; 250fc2e2e9cSMartin Brandenburg struct hlist_head *h; 251fc2e2e9cSMartin Brandenburg struct hlist_node *tmp; 2521182fca3SMike Marshall int ret = -ENOMEM; 2531182fca3SMike Marshall 2545f13e587SDan Carpenter if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) 255e675c5ecSMartin Brandenburg return -EINVAL; 256e675c5ecSMartin Brandenburg 2578bb8aefdSYi Liu down_write(&orangefs_inode->xattr_sem); 2588bb8aefdSYi Liu new_op = op_alloc(ORANGEFS_VFS_OP_REMOVEXATTR); 2591182fca3SMike Marshall if (!new_op) 2601182fca3SMike Marshall goto out_unlock; 2611182fca3SMike Marshall 2628bb8aefdSYi Liu new_op->upcall.req.removexattr.refn = orangefs_inode->refn; 2631182fca3SMike Marshall /* 2641182fca3SMike Marshall * NOTE: Although keys are meant to be NULL terminated 2651182fca3SMike Marshall * textual strings, I am going to explicitly pass the 2661182fca3SMike Marshall * length just in case we change this later on... 2671182fca3SMike Marshall */ 268d373a712SAndreas Gruenbacher strcpy(new_op->upcall.req.removexattr.key, name); 269d373a712SAndreas Gruenbacher new_op->upcall.req.removexattr.key_sz = strlen(name) + 1; 2701182fca3SMike Marshall 2711182fca3SMike Marshall gossip_debug(GOSSIP_XATTR_DEBUG, 2728bb8aefdSYi Liu "orangefs_inode_removexattr: key %s, key_sz %d\n", 2731182fca3SMike Marshall (char *)new_op->upcall.req.removexattr.key, 2741182fca3SMike Marshall (int)new_op->upcall.req.removexattr.key_sz); 2751182fca3SMike Marshall 2761182fca3SMike Marshall ret = service_operation(new_op, 2778bb8aefdSYi Liu "orangefs_inode_removexattr", 2781182fca3SMike Marshall get_interruptible_flag(inode)); 2791182fca3SMike Marshall if (ret == -ENOENT) { 2801182fca3SMike Marshall /* 2811182fca3SMike Marshall * Request to replace a non-existent attribute is an error. 2821182fca3SMike Marshall */ 2831182fca3SMike Marshall if (flags & XATTR_REPLACE) 2841182fca3SMike Marshall ret = -ENODATA; 2851182fca3SMike Marshall else 2861182fca3SMike Marshall ret = 0; 2871182fca3SMike Marshall } 2881182fca3SMike Marshall 2891182fca3SMike Marshall gossip_debug(GOSSIP_XATTR_DEBUG, 2908bb8aefdSYi Liu "orangefs_inode_removexattr: returning %d\n", ret); 2911182fca3SMike Marshall 2921182fca3SMike Marshall op_release(new_op); 293fc2e2e9cSMartin Brandenburg 294fc2e2e9cSMartin Brandenburg h = &orangefs_inode->xattr_cache[xattr_key(name)]; 295fc2e2e9cSMartin Brandenburg hlist_for_each_entry_safe(cx, tmp, h, node) { 296fc2e2e9cSMartin Brandenburg if (!strcmp(cx->key, name)) { 297fc2e2e9cSMartin Brandenburg hlist_del(&cx->node); 298fc2e2e9cSMartin Brandenburg kfree(cx); 299fc2e2e9cSMartin Brandenburg break; 300fc2e2e9cSMartin Brandenburg } 301fc2e2e9cSMartin Brandenburg } 302fc2e2e9cSMartin Brandenburg 3031182fca3SMike Marshall out_unlock: 3048bb8aefdSYi Liu up_write(&orangefs_inode->xattr_sem); 3051182fca3SMike Marshall return ret; 3061182fca3SMike Marshall } 3071182fca3SMike Marshall 3081182fca3SMike Marshall /* 3091182fca3SMike Marshall * Tries to set an attribute for a given key on a file. 3101182fca3SMike Marshall * 3111182fca3SMike Marshall * Returns a -ve number on error and 0 on success. Key is text, but value 3121182fca3SMike Marshall * can be binary! 3131182fca3SMike Marshall */ 314d373a712SAndreas Gruenbacher int orangefs_inode_setxattr(struct inode *inode, const char *name, 315d373a712SAndreas Gruenbacher const void *value, size_t size, int flags) 3161182fca3SMike Marshall { 3178bb8aefdSYi Liu struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 3188bb8aefdSYi Liu struct orangefs_kernel_op_s *new_op; 3191182fca3SMike Marshall int internal_flag = 0; 320fc2e2e9cSMartin Brandenburg struct orangefs_cached_xattr *cx; 321fc2e2e9cSMartin Brandenburg struct hlist_head *h; 322fc2e2e9cSMartin Brandenburg struct hlist_node *tmp; 3231182fca3SMike Marshall int ret = -ENOMEM; 3241182fca3SMike Marshall 3251182fca3SMike Marshall gossip_debug(GOSSIP_XATTR_DEBUG, 326d373a712SAndreas Gruenbacher "%s: name %s, buffer_size %zd\n", 327d373a712SAndreas Gruenbacher __func__, name, size); 3281182fca3SMike Marshall 329e675c5ecSMartin Brandenburg if (size > ORANGEFS_MAX_XATTR_VALUELEN) 3301182fca3SMike Marshall return -EINVAL; 3315f13e587SDan Carpenter if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) 332e675c5ecSMartin Brandenburg return -EINVAL; 3331182fca3SMike Marshall 3341182fca3SMike Marshall internal_flag = convert_to_internal_xattr_flags(flags); 3351182fca3SMike Marshall 3361182fca3SMike Marshall /* This is equivalent to a removexattr */ 3370b08273cSMarkus Elfring if (size == 0 && !value) { 3381182fca3SMike Marshall gossip_debug(GOSSIP_XATTR_DEBUG, 339d373a712SAndreas Gruenbacher "removing xattr (%s)\n", 3401182fca3SMike Marshall name); 341d373a712SAndreas Gruenbacher return orangefs_inode_removexattr(inode, name, flags); 3421182fca3SMike Marshall } 3431182fca3SMike Marshall 3441182fca3SMike Marshall gossip_debug(GOSSIP_XATTR_DEBUG, 3451182fca3SMike Marshall "setxattr on inode %pU, name %s\n", 3461182fca3SMike Marshall get_khandle_from_ino(inode), 3471182fca3SMike Marshall name); 3481182fca3SMike Marshall 3498bb8aefdSYi Liu down_write(&orangefs_inode->xattr_sem); 3508bb8aefdSYi Liu new_op = op_alloc(ORANGEFS_VFS_OP_SETXATTR); 3511182fca3SMike Marshall if (!new_op) 3521182fca3SMike Marshall goto out_unlock; 3531182fca3SMike Marshall 3541182fca3SMike Marshall 3558bb8aefdSYi Liu new_op->upcall.req.setxattr.refn = orangefs_inode->refn; 3561182fca3SMike Marshall new_op->upcall.req.setxattr.flags = internal_flag; 3571182fca3SMike Marshall /* 3581182fca3SMike Marshall * NOTE: Although keys are meant to be NULL terminated textual 3591182fca3SMike Marshall * strings, I am going to explicitly pass the length just in 3601182fca3SMike Marshall * case we change this later on... 3611182fca3SMike Marshall */ 362d373a712SAndreas Gruenbacher strcpy(new_op->upcall.req.setxattr.keyval.key, name); 363d373a712SAndreas Gruenbacher new_op->upcall.req.setxattr.keyval.key_sz = strlen(name) + 1; 3641182fca3SMike Marshall memcpy(new_op->upcall.req.setxattr.keyval.val, value, size); 3651182fca3SMike Marshall new_op->upcall.req.setxattr.keyval.val_sz = size; 3661182fca3SMike Marshall 3671182fca3SMike Marshall gossip_debug(GOSSIP_XATTR_DEBUG, 3688bb8aefdSYi Liu "orangefs_inode_setxattr: key %s, key_sz %d " 3691182fca3SMike Marshall " value size %zd\n", 3701182fca3SMike Marshall (char *)new_op->upcall.req.setxattr.keyval.key, 3711182fca3SMike Marshall (int)new_op->upcall.req.setxattr.keyval.key_sz, 3721182fca3SMike Marshall size); 3731182fca3SMike Marshall 3741182fca3SMike Marshall ret = service_operation(new_op, 3758bb8aefdSYi Liu "orangefs_inode_setxattr", 3761182fca3SMike Marshall get_interruptible_flag(inode)); 3771182fca3SMike Marshall 3781182fca3SMike Marshall gossip_debug(GOSSIP_XATTR_DEBUG, 3798bb8aefdSYi Liu "orangefs_inode_setxattr: returning %d\n", 3801182fca3SMike Marshall ret); 3811182fca3SMike Marshall 3821182fca3SMike Marshall /* when request is serviced properly, free req op struct */ 3831182fca3SMike Marshall op_release(new_op); 384fc2e2e9cSMartin Brandenburg 385fc2e2e9cSMartin Brandenburg h = &orangefs_inode->xattr_cache[xattr_key(name)]; 386fc2e2e9cSMartin Brandenburg hlist_for_each_entry_safe(cx, tmp, h, node) { 387fc2e2e9cSMartin Brandenburg if (!strcmp(cx->key, name)) { 388fc2e2e9cSMartin Brandenburg hlist_del(&cx->node); 389fc2e2e9cSMartin Brandenburg kfree(cx); 390fc2e2e9cSMartin Brandenburg break; 391fc2e2e9cSMartin Brandenburg } 392fc2e2e9cSMartin Brandenburg } 393fc2e2e9cSMartin Brandenburg 3941182fca3SMike Marshall out_unlock: 3958bb8aefdSYi Liu up_write(&orangefs_inode->xattr_sem); 3961182fca3SMike Marshall return ret; 3971182fca3SMike Marshall } 3981182fca3SMike Marshall 3991182fca3SMike Marshall /* 4001182fca3SMike Marshall * Tries to get a specified object's keys into a user-specified buffer of a 4011182fca3SMike Marshall * given size. Note that like the previous instances of xattr routines, this 4021182fca3SMike Marshall * also allows you to pass in a NULL pointer and 0 size to probe the size for 4031182fca3SMike Marshall * subsequent memory allocations. Thus our return value is always the size of 4041182fca3SMike Marshall * all the keys unless there were errors in fetching the keys! 4051182fca3SMike Marshall */ 4068bb8aefdSYi Liu ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size) 4071182fca3SMike Marshall { 4081182fca3SMike Marshall struct inode *inode = dentry->d_inode; 4098bb8aefdSYi Liu struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode); 4108bb8aefdSYi Liu struct orangefs_kernel_op_s *new_op; 4118bb8aefdSYi Liu __u64 token = ORANGEFS_ITERATE_START; 4121182fca3SMike Marshall ssize_t ret = -ENOMEM; 4131182fca3SMike Marshall ssize_t total = 0; 4141182fca3SMike Marshall int count_keys = 0; 4151182fca3SMike Marshall int key_size; 4161182fca3SMike Marshall int i = 0; 41762441fa5SMike Marshall int returned_count = 0; 4181182fca3SMike Marshall 4190b08273cSMarkus Elfring if (size > 0 && !buffer) { 4201182fca3SMike Marshall gossip_err("%s: bogus NULL pointers\n", __func__); 4211182fca3SMike Marshall return -EINVAL; 4221182fca3SMike Marshall } 4231182fca3SMike Marshall 4248bb8aefdSYi Liu down_read(&orangefs_inode->xattr_sem); 4258bb8aefdSYi Liu new_op = op_alloc(ORANGEFS_VFS_OP_LISTXATTR); 4261182fca3SMike Marshall if (!new_op) 4271182fca3SMike Marshall goto out_unlock; 4281182fca3SMike Marshall 4291182fca3SMike Marshall if (buffer && size > 0) 4301182fca3SMike Marshall memset(buffer, 0, size); 4311182fca3SMike Marshall 4321182fca3SMike Marshall try_again: 4331182fca3SMike Marshall key_size = 0; 4348bb8aefdSYi Liu new_op->upcall.req.listxattr.refn = orangefs_inode->refn; 4351182fca3SMike Marshall new_op->upcall.req.listxattr.token = token; 4361182fca3SMike Marshall new_op->upcall.req.listxattr.requested_count = 4378bb8aefdSYi Liu (size == 0) ? 0 : ORANGEFS_MAX_XATTR_LISTLEN; 4381182fca3SMike Marshall ret = service_operation(new_op, __func__, 4391182fca3SMike Marshall get_interruptible_flag(inode)); 4401182fca3SMike Marshall if (ret != 0) 4411182fca3SMike Marshall goto done; 4421182fca3SMike Marshall 4431182fca3SMike Marshall if (size == 0) { 4441182fca3SMike Marshall /* 4451182fca3SMike Marshall * This is a bit of a big upper limit, but I did not want to 4461182fca3SMike Marshall * spend too much time getting this correct, since users end 4471182fca3SMike Marshall * up allocating memory rather than us... 4481182fca3SMike Marshall */ 4491182fca3SMike Marshall total = new_op->downcall.resp.listxattr.returned_count * 4508bb8aefdSYi Liu ORANGEFS_MAX_XATTR_NAMELEN; 4511182fca3SMike Marshall goto done; 4521182fca3SMike Marshall } 4531182fca3SMike Marshall 45462441fa5SMike Marshall returned_count = new_op->downcall.resp.listxattr.returned_count; 45562441fa5SMike Marshall if (returned_count < 0 || 456a956af33SMartin Brandenburg returned_count > ORANGEFS_MAX_XATTR_LISTLEN) { 45762441fa5SMike Marshall gossip_err("%s: impossible value for returned_count:%d:\n", 45862441fa5SMike Marshall __func__, 45962441fa5SMike Marshall returned_count); 46002a5cc53SMartin Brandenburg ret = -EIO; 46162441fa5SMike Marshall goto done; 46262441fa5SMike Marshall } 46362441fa5SMike Marshall 4641182fca3SMike Marshall /* 4651182fca3SMike Marshall * Check to see how much can be fit in the buffer. Fit only whole keys. 4661182fca3SMike Marshall */ 46762441fa5SMike Marshall for (i = 0; i < returned_count; i++) { 46802a5cc53SMartin Brandenburg if (new_op->downcall.resp.listxattr.lengths[i] < 0 || 46902a5cc53SMartin Brandenburg new_op->downcall.resp.listxattr.lengths[i] > 47002a5cc53SMartin Brandenburg ORANGEFS_MAX_XATTR_NAMELEN) { 47102a5cc53SMartin Brandenburg gossip_err("%s: impossible value for lengths[%d]\n", 47202a5cc53SMartin Brandenburg __func__, 47302a5cc53SMartin Brandenburg new_op->downcall.resp.listxattr.lengths[i]); 47402a5cc53SMartin Brandenburg ret = -EIO; 47502a5cc53SMartin Brandenburg goto done; 47602a5cc53SMartin Brandenburg } 4771182fca3SMike Marshall if (total + new_op->downcall.resp.listxattr.lengths[i] > size) 4781182fca3SMike Marshall goto done; 4791182fca3SMike Marshall 4801182fca3SMike Marshall /* 4811182fca3SMike Marshall * Since many dumb programs try to setxattr() on our reserved 4821182fca3SMike Marshall * xattrs this is a feeble attempt at defeating those by not 4831182fca3SMike Marshall * listing them in the output of listxattr.. sigh 4841182fca3SMike Marshall */ 4851182fca3SMike Marshall if (is_reserved_key(new_op->downcall.resp.listxattr.key + 4861182fca3SMike Marshall key_size, 4871182fca3SMike Marshall new_op->downcall.resp. 4881182fca3SMike Marshall listxattr.lengths[i])) { 4891182fca3SMike Marshall gossip_debug(GOSSIP_XATTR_DEBUG, "Copying key %d -> %s\n", 4901182fca3SMike Marshall i, new_op->downcall.resp.listxattr.key + 4911182fca3SMike Marshall key_size); 4921182fca3SMike Marshall memcpy(buffer + total, 4931182fca3SMike Marshall new_op->downcall.resp.listxattr.key + key_size, 4941182fca3SMike Marshall new_op->downcall.resp.listxattr.lengths[i]); 4951182fca3SMike Marshall total += new_op->downcall.resp.listxattr.lengths[i]; 4961182fca3SMike Marshall count_keys++; 4971182fca3SMike Marshall } else { 4981182fca3SMike Marshall gossip_debug(GOSSIP_XATTR_DEBUG, "[RESERVED] key %d -> %s\n", 4991182fca3SMike Marshall i, new_op->downcall.resp.listxattr.key + 5001182fca3SMike Marshall key_size); 5011182fca3SMike Marshall } 5021182fca3SMike Marshall key_size += new_op->downcall.resp.listxattr.lengths[i]; 5031182fca3SMike Marshall } 5041182fca3SMike Marshall 5051182fca3SMike Marshall /* 5061182fca3SMike Marshall * Since the buffer was large enough, we might have to continue 5071182fca3SMike Marshall * fetching more keys! 5081182fca3SMike Marshall */ 5091182fca3SMike Marshall token = new_op->downcall.resp.listxattr.token; 5108bb8aefdSYi Liu if (token != ORANGEFS_ITERATE_END) 5111182fca3SMike Marshall goto try_again; 5121182fca3SMike Marshall 5131182fca3SMike Marshall done: 5141182fca3SMike Marshall gossip_debug(GOSSIP_XATTR_DEBUG, "%s: returning %d" 5151182fca3SMike Marshall " [size of buffer %ld] (filled in %d keys)\n", 5161182fca3SMike Marshall __func__, 5171182fca3SMike Marshall ret ? (int)ret : (int)total, 5181182fca3SMike Marshall (long)size, 5191182fca3SMike Marshall count_keys); 5201182fca3SMike Marshall op_release(new_op); 5211182fca3SMike Marshall if (ret == 0) 5221182fca3SMike Marshall ret = total; 5231182fca3SMike Marshall out_unlock: 5248bb8aefdSYi Liu up_read(&orangefs_inode->xattr_sem); 5251182fca3SMike Marshall return ret; 5261182fca3SMike Marshall } 5271182fca3SMike Marshall 5288bb8aefdSYi Liu static int orangefs_xattr_set_default(const struct xattr_handler *handler, 52959301226SAl Viro struct dentry *unused, 53059301226SAl Viro struct inode *inode, 5311182fca3SMike Marshall const char *name, 5321182fca3SMike Marshall const void *buffer, 5331182fca3SMike Marshall size_t size, 534555fa0faSAl Viro int flags) 5351182fca3SMike Marshall { 536d373a712SAndreas Gruenbacher return orangefs_inode_setxattr(inode, name, buffer, size, flags); 5371182fca3SMike Marshall } 5381182fca3SMike Marshall 5398bb8aefdSYi Liu static int orangefs_xattr_get_default(const struct xattr_handler *handler, 540b296821aSAl Viro struct dentry *unused, 541b296821aSAl Viro struct inode *inode, 5421182fca3SMike Marshall const char *name, 5431182fca3SMike Marshall void *buffer, 544555fa0faSAl Viro size_t size) 5451182fca3SMike Marshall { 546d373a712SAndreas Gruenbacher return orangefs_inode_getxattr(inode, name, buffer, size); 5471182fca3SMike Marshall 5481182fca3SMike Marshall } 5491182fca3SMike Marshall 55012174444SJulia Lawall static const struct xattr_handler orangefs_xattr_default_handler = { 551972a7344SAndreas Gruenbacher .prefix = "", /* match any name => handlers called with full name */ 5528bb8aefdSYi Liu .get = orangefs_xattr_get_default, 5538bb8aefdSYi Liu .set = orangefs_xattr_set_default, 5541182fca3SMike Marshall }; 5551182fca3SMike Marshall 5568bb8aefdSYi Liu const struct xattr_handler *orangefs_xattr_handlers[] = { 5571182fca3SMike Marshall &posix_acl_access_xattr_handler, 5581182fca3SMike Marshall &posix_acl_default_xattr_handler, 5598bb8aefdSYi Liu &orangefs_xattr_default_handler, 5601182fca3SMike Marshall NULL 5611182fca3SMike Marshall }; 562