Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * (C) 2001 Clemson University and The University of Chicago
0004  * Copyright 2018 Omnibond Systems, L.L.C.
0005  *
0006  * See COPYING in top-level directory.
0007  */
0008 
0009 /*
0010  *  Linux VFS extended attribute operations.
0011  */
0012 
0013 #include "protocol.h"
0014 #include "orangefs-kernel.h"
0015 #include "orangefs-bufmap.h"
0016 #include <linux/posix_acl_xattr.h>
0017 #include <linux/xattr.h>
0018 #include <linux/hashtable.h>
0019 
0020 #define SYSTEM_ORANGEFS_KEY "system.pvfs2."
0021 #define SYSTEM_ORANGEFS_KEY_LEN 13
0022 
0023 /*
0024  * this function returns
0025  *   0 if the key corresponding to name is not meant to be printed as part
0026  *     of a listxattr.
0027  *   1 if the key corresponding to name is meant to be returned as part of
0028  *     a listxattr.
0029  * The ones that start SYSTEM_ORANGEFS_KEY are the ones to avoid printing.
0030  */
0031 static int is_reserved_key(const char *key, size_t size)
0032 {
0033 
0034     if (size < SYSTEM_ORANGEFS_KEY_LEN)
0035         return 1;
0036 
0037     return strncmp(key, SYSTEM_ORANGEFS_KEY, SYSTEM_ORANGEFS_KEY_LEN) ?  1 : 0;
0038 }
0039 
0040 static inline int convert_to_internal_xattr_flags(int setxattr_flags)
0041 {
0042     int internal_flag = 0;
0043 
0044     if (setxattr_flags & XATTR_REPLACE) {
0045         /* Attribute must exist! */
0046         internal_flag = ORANGEFS_XATTR_REPLACE;
0047     } else if (setxattr_flags & XATTR_CREATE) {
0048         /* Attribute must not exist */
0049         internal_flag = ORANGEFS_XATTR_CREATE;
0050     }
0051     return internal_flag;
0052 }
0053 
0054 static unsigned int xattr_key(const char *key)
0055 {
0056     unsigned int i = 0;
0057     while (key)
0058         i += *key++;
0059     return i % 16;
0060 }
0061 
0062 static struct orangefs_cached_xattr *find_cached_xattr(struct inode *inode,
0063     const char *key)
0064 {
0065     struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
0066     struct orangefs_cached_xattr *cx;
0067     struct hlist_head *h;
0068     struct hlist_node *tmp;
0069     h = &orangefs_inode->xattr_cache[xattr_key(key)];
0070     if (hlist_empty(h))
0071         return NULL;
0072     hlist_for_each_entry_safe(cx, tmp, h, node) {
0073 /*      if (!time_before(jiffies, cx->timeout)) {
0074             hlist_del(&cx->node);
0075             kfree(cx);
0076             continue;
0077         }*/
0078         if (!strcmp(cx->key, key))
0079             return cx;
0080     }
0081     return NULL;
0082 }
0083 
0084 /*
0085  * Tries to get a specified key's attributes of a given
0086  * file into a user-specified buffer. Note that the getxattr
0087  * interface allows for the users to probe the size of an
0088  * extended attribute by passing in a value of 0 to size.
0089  * Thus our return value is always the size of the attribute
0090  * unless the key does not exist for the file and/or if
0091  * there were errors in fetching the attribute value.
0092  */
0093 ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name,
0094                 void *buffer, size_t size)
0095 {
0096     struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
0097     struct orangefs_kernel_op_s *new_op = NULL;
0098     struct orangefs_cached_xattr *cx;
0099     ssize_t ret = -ENOMEM;
0100     ssize_t length = 0;
0101     int fsuid;
0102     int fsgid;
0103 
0104     gossip_debug(GOSSIP_XATTR_DEBUG,
0105              "%s: name %s, buffer_size %zd\n",
0106              __func__, name, size);
0107 
0108     if (S_ISLNK(inode->i_mode))
0109         return -EOPNOTSUPP;
0110 
0111     if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN)
0112         return -EINVAL;
0113 
0114     fsuid = from_kuid(&init_user_ns, current_fsuid());
0115     fsgid = from_kgid(&init_user_ns, current_fsgid());
0116 
0117     gossip_debug(GOSSIP_XATTR_DEBUG,
0118              "getxattr on inode %pU, name %s "
0119              "(uid %o, gid %o)\n",
0120              get_khandle_from_ino(inode),
0121              name,
0122              fsuid,
0123              fsgid);
0124 
0125     down_read(&orangefs_inode->xattr_sem);
0126 
0127     cx = find_cached_xattr(inode, name);
0128     if (cx && time_before(jiffies, cx->timeout)) {
0129         if (cx->length == -1) {
0130             ret = -ENODATA;
0131             goto out_unlock;
0132         } else {
0133             if (size == 0) {
0134                 ret = cx->length;
0135                 goto out_unlock;
0136             }
0137             if (cx->length > size) {
0138                 ret = -ERANGE;
0139                 goto out_unlock;
0140             }
0141             memcpy(buffer, cx->val, cx->length);
0142             memset(buffer + cx->length, 0, size - cx->length);
0143             ret = cx->length;
0144             goto out_unlock;
0145         }
0146     }
0147 
0148     new_op = op_alloc(ORANGEFS_VFS_OP_GETXATTR);
0149     if (!new_op)
0150         goto out_unlock;
0151 
0152     new_op->upcall.req.getxattr.refn = orangefs_inode->refn;
0153     strcpy(new_op->upcall.req.getxattr.key, name);
0154 
0155     /*
0156      * NOTE: Although keys are meant to be NULL terminated textual
0157      * strings, I am going to explicitly pass the length just in case
0158      * we change this later on...
0159      */
0160     new_op->upcall.req.getxattr.key_sz = strlen(name) + 1;
0161 
0162     ret = service_operation(new_op, "orangefs_inode_getxattr",
0163                 get_interruptible_flag(inode));
0164     if (ret != 0) {
0165         if (ret == -ENOENT) {
0166             ret = -ENODATA;
0167             gossip_debug(GOSSIP_XATTR_DEBUG,
0168                      "orangefs_inode_getxattr: inode %pU key %s"
0169                      " does not exist!\n",
0170                      get_khandle_from_ino(inode),
0171                      (char *)new_op->upcall.req.getxattr.key);
0172             cx = kmalloc(sizeof *cx, GFP_KERNEL);
0173             if (cx) {
0174                 strcpy(cx->key, name);
0175                 cx->length = -1;
0176                 cx->timeout = jiffies +
0177                     orangefs_getattr_timeout_msecs*HZ/1000;
0178                 hash_add(orangefs_inode->xattr_cache, &cx->node,
0179                     xattr_key(cx->key));
0180             }
0181         }
0182         goto out_release_op;
0183     }
0184 
0185     /*
0186      * Length returned includes null terminator.
0187      */
0188     length = new_op->downcall.resp.getxattr.val_sz;
0189 
0190     /*
0191      * Just return the length of the queried attribute.
0192      */
0193     if (size == 0) {
0194         ret = length;
0195         goto out_release_op;
0196     }
0197 
0198     /*
0199      * Check to see if key length is > provided buffer size.
0200      */
0201     if (length > size) {
0202         ret = -ERANGE;
0203         goto out_release_op;
0204     }
0205 
0206     memcpy(buffer, new_op->downcall.resp.getxattr.val, length);
0207     memset(buffer + length, 0, size - length);
0208     gossip_debug(GOSSIP_XATTR_DEBUG,
0209          "orangefs_inode_getxattr: inode %pU "
0210          "key %s key_sz %d, val_len %d\n",
0211          get_khandle_from_ino(inode),
0212          (char *)new_op->
0213         upcall.req.getxattr.key,
0214              (int)new_op->
0215         upcall.req.getxattr.key_sz,
0216          (int)ret);
0217 
0218     ret = length;
0219 
0220     if (cx) {
0221         strcpy(cx->key, name);
0222         memcpy(cx->val, buffer, length);
0223         cx->length = length;
0224         cx->timeout = jiffies + HZ;
0225     } else {
0226         cx = kmalloc(sizeof *cx, GFP_KERNEL);
0227         if (cx) {
0228             strcpy(cx->key, name);
0229             memcpy(cx->val, buffer, length);
0230             cx->length = length;
0231             cx->timeout = jiffies + HZ;
0232             hash_add(orangefs_inode->xattr_cache, &cx->node,
0233                 xattr_key(cx->key));
0234         }
0235     }
0236 
0237 out_release_op:
0238     op_release(new_op);
0239 out_unlock:
0240     up_read(&orangefs_inode->xattr_sem);
0241     return ret;
0242 }
0243 
0244 static int orangefs_inode_removexattr(struct inode *inode, const char *name,
0245                       int flags)
0246 {
0247     struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
0248     struct orangefs_kernel_op_s *new_op = NULL;
0249     struct orangefs_cached_xattr *cx;
0250     struct hlist_head *h;
0251     struct hlist_node *tmp;
0252     int ret = -ENOMEM;
0253 
0254     if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN)
0255         return -EINVAL;
0256 
0257     down_write(&orangefs_inode->xattr_sem);
0258     new_op = op_alloc(ORANGEFS_VFS_OP_REMOVEXATTR);
0259     if (!new_op)
0260         goto out_unlock;
0261 
0262     new_op->upcall.req.removexattr.refn = orangefs_inode->refn;
0263     /*
0264      * NOTE: Although keys are meant to be NULL terminated
0265      * textual strings, I am going to explicitly pass the
0266      * length just in case we change this later on...
0267      */
0268     strcpy(new_op->upcall.req.removexattr.key, name);
0269     new_op->upcall.req.removexattr.key_sz = strlen(name) + 1;
0270 
0271     gossip_debug(GOSSIP_XATTR_DEBUG,
0272              "orangefs_inode_removexattr: key %s, key_sz %d\n",
0273              (char *)new_op->upcall.req.removexattr.key,
0274              (int)new_op->upcall.req.removexattr.key_sz);
0275 
0276     ret = service_operation(new_op,
0277                 "orangefs_inode_removexattr",
0278                 get_interruptible_flag(inode));
0279     if (ret == -ENOENT) {
0280         /*
0281          * Request to replace a non-existent attribute is an error.
0282          */
0283         if (flags & XATTR_REPLACE)
0284             ret = -ENODATA;
0285         else
0286             ret = 0;
0287     }
0288 
0289     gossip_debug(GOSSIP_XATTR_DEBUG,
0290              "orangefs_inode_removexattr: returning %d\n", ret);
0291 
0292     op_release(new_op);
0293 
0294     h = &orangefs_inode->xattr_cache[xattr_key(name)];
0295     hlist_for_each_entry_safe(cx, tmp, h, node) {
0296         if (!strcmp(cx->key, name)) {
0297             hlist_del(&cx->node);
0298             kfree(cx);
0299             break;
0300         }
0301     }
0302 
0303 out_unlock:
0304     up_write(&orangefs_inode->xattr_sem);
0305     return ret;
0306 }
0307 
0308 /*
0309  * Tries to set an attribute for a given key on a file.
0310  *
0311  * Returns a -ve number on error and 0 on success.  Key is text, but value
0312  * can be binary!
0313  */
0314 int orangefs_inode_setxattr(struct inode *inode, const char *name,
0315                 const void *value, size_t size, int flags)
0316 {
0317     struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
0318     struct orangefs_kernel_op_s *new_op;
0319     int internal_flag = 0;
0320     struct orangefs_cached_xattr *cx;
0321     struct hlist_head *h;
0322     struct hlist_node *tmp;
0323     int ret = -ENOMEM;
0324 
0325     gossip_debug(GOSSIP_XATTR_DEBUG,
0326              "%s: name %s, buffer_size %zd\n",
0327              __func__, name, size);
0328 
0329     if (size > ORANGEFS_MAX_XATTR_VALUELEN)
0330         return -EINVAL;
0331     if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN)
0332         return -EINVAL;
0333 
0334     internal_flag = convert_to_internal_xattr_flags(flags);
0335 
0336     /* This is equivalent to a removexattr */
0337     if (size == 0 && !value) {
0338         gossip_debug(GOSSIP_XATTR_DEBUG,
0339                  "removing xattr (%s)\n",
0340                  name);
0341         return orangefs_inode_removexattr(inode, name, flags);
0342     }
0343 
0344     gossip_debug(GOSSIP_XATTR_DEBUG,
0345              "setxattr on inode %pU, name %s\n",
0346              get_khandle_from_ino(inode),
0347              name);
0348 
0349     down_write(&orangefs_inode->xattr_sem);
0350     new_op = op_alloc(ORANGEFS_VFS_OP_SETXATTR);
0351     if (!new_op)
0352         goto out_unlock;
0353 
0354 
0355     new_op->upcall.req.setxattr.refn = orangefs_inode->refn;
0356     new_op->upcall.req.setxattr.flags = internal_flag;
0357     /*
0358      * NOTE: Although keys are meant to be NULL terminated textual
0359      * strings, I am going to explicitly pass the length just in
0360      * case we change this later on...
0361      */
0362     strcpy(new_op->upcall.req.setxattr.keyval.key, name);
0363     new_op->upcall.req.setxattr.keyval.key_sz = strlen(name) + 1;
0364     memcpy(new_op->upcall.req.setxattr.keyval.val, value, size);
0365     new_op->upcall.req.setxattr.keyval.val_sz = size;
0366 
0367     gossip_debug(GOSSIP_XATTR_DEBUG,
0368              "orangefs_inode_setxattr: key %s, key_sz %d "
0369              " value size %zd\n",
0370              (char *)new_op->upcall.req.setxattr.keyval.key,
0371              (int)new_op->upcall.req.setxattr.keyval.key_sz,
0372              size);
0373 
0374     ret = service_operation(new_op,
0375                 "orangefs_inode_setxattr",
0376                 get_interruptible_flag(inode));
0377 
0378     gossip_debug(GOSSIP_XATTR_DEBUG,
0379              "orangefs_inode_setxattr: returning %d\n",
0380              ret);
0381 
0382     /* when request is serviced properly, free req op struct */
0383     op_release(new_op);
0384 
0385     h = &orangefs_inode->xattr_cache[xattr_key(name)];
0386     hlist_for_each_entry_safe(cx, tmp, h, node) {
0387         if (!strcmp(cx->key, name)) {
0388             hlist_del(&cx->node);
0389             kfree(cx);
0390             break;
0391         }
0392     }
0393 
0394 out_unlock:
0395     up_write(&orangefs_inode->xattr_sem);
0396     return ret;
0397 }
0398 
0399 /*
0400  * Tries to get a specified object's keys into a user-specified buffer of a
0401  * given size.  Note that like the previous instances of xattr routines, this
0402  * also allows you to pass in a NULL pointer and 0 size to probe the size for
0403  * subsequent memory allocations. Thus our return value is always the size of
0404  * all the keys unless there were errors in fetching the keys!
0405  */
0406 ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size)
0407 {
0408     struct inode *inode = dentry->d_inode;
0409     struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
0410     struct orangefs_kernel_op_s *new_op;
0411     __u64 token = ORANGEFS_ITERATE_START;
0412     ssize_t ret = -ENOMEM;
0413     ssize_t total = 0;
0414     int count_keys = 0;
0415     int key_size;
0416     int i = 0;
0417     int returned_count = 0;
0418 
0419     if (size > 0 && !buffer) {
0420         gossip_err("%s: bogus NULL pointers\n", __func__);
0421         return -EINVAL;
0422     }
0423 
0424     down_read(&orangefs_inode->xattr_sem);
0425     new_op = op_alloc(ORANGEFS_VFS_OP_LISTXATTR);
0426     if (!new_op)
0427         goto out_unlock;
0428 
0429     if (buffer && size > 0)
0430         memset(buffer, 0, size);
0431 
0432 try_again:
0433     key_size = 0;
0434     new_op->upcall.req.listxattr.refn = orangefs_inode->refn;
0435     new_op->upcall.req.listxattr.token = token;
0436     new_op->upcall.req.listxattr.requested_count =
0437         (size == 0) ? 0 : ORANGEFS_MAX_XATTR_LISTLEN;
0438     ret = service_operation(new_op, __func__,
0439                 get_interruptible_flag(inode));
0440     if (ret != 0)
0441         goto done;
0442 
0443     if (size == 0) {
0444         /*
0445          * This is a bit of a big upper limit, but I did not want to
0446          * spend too much time getting this correct, since users end
0447          * up allocating memory rather than us...
0448          */
0449         total = new_op->downcall.resp.listxattr.returned_count *
0450             ORANGEFS_MAX_XATTR_NAMELEN;
0451         goto done;
0452     }
0453 
0454     returned_count = new_op->downcall.resp.listxattr.returned_count;
0455     if (returned_count < 0 ||
0456         returned_count > ORANGEFS_MAX_XATTR_LISTLEN) {
0457         gossip_err("%s: impossible value for returned_count:%d:\n",
0458         __func__,
0459         returned_count);
0460         ret = -EIO;
0461         goto done;
0462     }
0463 
0464     /*
0465      * Check to see how much can be fit in the buffer. Fit only whole keys.
0466      */
0467     for (i = 0; i < returned_count; i++) {
0468         if (new_op->downcall.resp.listxattr.lengths[i] < 0 ||
0469             new_op->downcall.resp.listxattr.lengths[i] >
0470             ORANGEFS_MAX_XATTR_NAMELEN) {
0471             gossip_err("%s: impossible value for lengths[%d]\n",
0472                 __func__,
0473                 new_op->downcall.resp.listxattr.lengths[i]);
0474             ret = -EIO;
0475             goto done;
0476         }
0477         if (total + new_op->downcall.resp.listxattr.lengths[i] > size)
0478             goto done;
0479 
0480         /*
0481          * Since many dumb programs try to setxattr() on our reserved
0482          * xattrs this is a feeble attempt at defeating those by not
0483          * listing them in the output of listxattr.. sigh
0484          */
0485         if (is_reserved_key(new_op->downcall.resp.listxattr.key +
0486                     key_size,
0487                     new_op->downcall.resp.
0488                     listxattr.lengths[i])) {
0489             gossip_debug(GOSSIP_XATTR_DEBUG, "Copying key %d -> %s\n",
0490                     i, new_op->downcall.resp.listxattr.key +
0491                         key_size);
0492             memcpy(buffer + total,
0493                 new_op->downcall.resp.listxattr.key + key_size,
0494                 new_op->downcall.resp.listxattr.lengths[i]);
0495             total += new_op->downcall.resp.listxattr.lengths[i];
0496             count_keys++;
0497         } else {
0498             gossip_debug(GOSSIP_XATTR_DEBUG, "[RESERVED] key %d -> %s\n",
0499                     i, new_op->downcall.resp.listxattr.key +
0500                         key_size);
0501         }
0502         key_size += new_op->downcall.resp.listxattr.lengths[i];
0503     }
0504 
0505     /*
0506      * Since the buffer was large enough, we might have to continue
0507      * fetching more keys!
0508      */
0509     token = new_op->downcall.resp.listxattr.token;
0510     if (token != ORANGEFS_ITERATE_END)
0511         goto try_again;
0512 
0513 done:
0514     gossip_debug(GOSSIP_XATTR_DEBUG, "%s: returning %d"
0515              " [size of buffer %ld] (filled in %d keys)\n",
0516              __func__,
0517              ret ? (int)ret : (int)total,
0518              (long)size,
0519              count_keys);
0520     op_release(new_op);
0521     if (ret == 0)
0522         ret = total;
0523 out_unlock:
0524     up_read(&orangefs_inode->xattr_sem);
0525     return ret;
0526 }
0527 
0528 static int orangefs_xattr_set_default(const struct xattr_handler *handler,
0529                       struct user_namespace *mnt_userns,
0530                       struct dentry *unused,
0531                       struct inode *inode,
0532                       const char *name,
0533                       const void *buffer,
0534                       size_t size,
0535                       int flags)
0536 {
0537     return orangefs_inode_setxattr(inode, name, buffer, size, flags);
0538 }
0539 
0540 static int orangefs_xattr_get_default(const struct xattr_handler *handler,
0541                       struct dentry *unused,
0542                       struct inode *inode,
0543                       const char *name,
0544                       void *buffer,
0545                       size_t size)
0546 {
0547     return orangefs_inode_getxattr(inode, name, buffer, size);
0548 
0549 }
0550 
0551 static const struct xattr_handler orangefs_xattr_default_handler = {
0552     .prefix = "",  /* match any name => handlers called with full name */
0553     .get = orangefs_xattr_get_default,
0554     .set = orangefs_xattr_set_default,
0555 };
0556 
0557 const struct xattr_handler *orangefs_xattr_handlers[] = {
0558     &posix_acl_access_xattr_handler,
0559     &posix_acl_default_xattr_handler,
0560     &orangefs_xattr_default_handler,
0561     NULL
0562 };