linux/fs/orangefs/xattr.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * (C) 2001 Clemson University and The University of Chicago
   4 *
   5 * See COPYING in top-level directory.
   6 */
   7
   8/*
   9 *  Linux VFS extended attribute operations.
  10 */
  11
  12#include "protocol.h"
  13#include "orangefs-kernel.h"
  14#include "orangefs-bufmap.h"
  15#include <linux/posix_acl_xattr.h>
  16#include <linux/xattr.h>
  17
  18
  19#define SYSTEM_ORANGEFS_KEY "system.pvfs2."
  20#define SYSTEM_ORANGEFS_KEY_LEN 13
  21
  22/*
  23 * this function returns
  24 *   0 if the key corresponding to name is not meant to be printed as part
  25 *     of a listxattr.
  26 *   1 if the key corresponding to name is meant to be returned as part of
  27 *     a listxattr.
  28 * The ones that start SYSTEM_ORANGEFS_KEY are the ones to avoid printing.
  29 */
  30static int is_reserved_key(const char *key, size_t size)
  31{
  32
  33        if (size < SYSTEM_ORANGEFS_KEY_LEN)
  34                return 1;
  35
  36        return strncmp(key, SYSTEM_ORANGEFS_KEY, SYSTEM_ORANGEFS_KEY_LEN) ?  1 : 0;
  37}
  38
  39static inline int convert_to_internal_xattr_flags(int setxattr_flags)
  40{
  41        int internal_flag = 0;
  42
  43        if (setxattr_flags & XATTR_REPLACE) {
  44                /* Attribute must exist! */
  45                internal_flag = ORANGEFS_XATTR_REPLACE;
  46        } else if (setxattr_flags & XATTR_CREATE) {
  47                /* Attribute must not exist */
  48                internal_flag = ORANGEFS_XATTR_CREATE;
  49        }
  50        return internal_flag;
  51}
  52
  53
  54/*
  55 * Tries to get a specified key's attributes of a given
  56 * file into a user-specified buffer. Note that the getxattr
  57 * interface allows for the users to probe the size of an
  58 * extended attribute by passing in a value of 0 to size.
  59 * Thus our return value is always the size of the attribute
  60 * unless the key does not exist for the file and/or if
  61 * there were errors in fetching the attribute value.
  62 */
  63ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name,
  64                                void *buffer, size_t size)
  65{
  66        struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
  67        struct orangefs_kernel_op_s *new_op = NULL;
  68        ssize_t ret = -ENOMEM;
  69        ssize_t length = 0;
  70        int fsuid;
  71        int fsgid;
  72
  73        gossip_debug(GOSSIP_XATTR_DEBUG,
  74                     "%s: name %s, buffer_size %zd\n",
  75                     __func__, name, size);
  76
  77        if (S_ISLNK(inode->i_mode))
  78                return -EOPNOTSUPP;
  79
  80        if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN)
  81                return -EINVAL;
  82
  83        fsuid = from_kuid(&init_user_ns, current_fsuid());
  84        fsgid = from_kgid(&init_user_ns, current_fsgid());
  85
  86        gossip_debug(GOSSIP_XATTR_DEBUG,
  87                     "getxattr on inode %pU, name %s "
  88                     "(uid %o, gid %o)\n",
  89                     get_khandle_from_ino(inode),
  90                     name,
  91                     fsuid,
  92                     fsgid);
  93
  94        down_read(&orangefs_inode->xattr_sem);
  95
  96        new_op = op_alloc(ORANGEFS_VFS_OP_GETXATTR);
  97        if (!new_op)
  98                goto out_unlock;
  99
 100        new_op->upcall.req.getxattr.refn = orangefs_inode->refn;
 101        strcpy(new_op->upcall.req.getxattr.key, name);
 102
 103        /*
 104         * NOTE: Although keys are meant to be NULL terminated textual
 105         * strings, I am going to explicitly pass the length just in case
 106         * we change this later on...
 107         */
 108        new_op->upcall.req.getxattr.key_sz = strlen(name) + 1;
 109
 110        ret = service_operation(new_op, "orangefs_inode_getxattr",
 111                                get_interruptible_flag(inode));
 112        if (ret != 0) {
 113                if (ret == -ENOENT) {
 114                        ret = -ENODATA;
 115                        gossip_debug(GOSSIP_XATTR_DEBUG,
 116                                     "orangefs_inode_getxattr: inode %pU key %s"
 117                                     " does not exist!\n",
 118                                     get_khandle_from_ino(inode),
 119                                     (char *)new_op->upcall.req.getxattr.key);
 120                }
 121                goto out_release_op;
 122        }
 123
 124        /*
 125         * Length returned includes null terminator.
 126         */
 127        length = new_op->downcall.resp.getxattr.val_sz;
 128
 129        /*
 130         * Just return the length of the queried attribute.
 131         */
 132        if (size == 0) {
 133                ret = length;
 134                goto out_release_op;
 135        }
 136
 137        /*
 138         * Check to see if key length is > provided buffer size.
 139         */
 140        if (length > size) {
 141                ret = -ERANGE;
 142                goto out_release_op;
 143        }
 144
 145        memcpy(buffer, new_op->downcall.resp.getxattr.val, length);
 146        memset(buffer + length, 0, size - length);
 147        gossip_debug(GOSSIP_XATTR_DEBUG,
 148             "orangefs_inode_getxattr: inode %pU "
 149             "key %s key_sz %d, val_len %d\n",
 150             get_khandle_from_ino(inode),
 151             (char *)new_op->
 152                upcall.req.getxattr.key,
 153                     (int)new_op->
 154                upcall.req.getxattr.key_sz,
 155             (int)ret);
 156
 157        ret = length;
 158
 159out_release_op:
 160        op_release(new_op);
 161out_unlock:
 162        up_read(&orangefs_inode->xattr_sem);
 163        return ret;
 164}
 165
 166static int orangefs_inode_removexattr(struct inode *inode, const char *name,
 167                                      int flags)
 168{
 169        struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
 170        struct orangefs_kernel_op_s *new_op = NULL;
 171        int ret = -ENOMEM;
 172
 173        if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN)
 174                return -EINVAL;
 175
 176        down_write(&orangefs_inode->xattr_sem);
 177        new_op = op_alloc(ORANGEFS_VFS_OP_REMOVEXATTR);
 178        if (!new_op)
 179                goto out_unlock;
 180
 181        new_op->upcall.req.removexattr.refn = orangefs_inode->refn;
 182        /*
 183         * NOTE: Although keys are meant to be NULL terminated
 184         * textual strings, I am going to explicitly pass the
 185         * length just in case we change this later on...
 186         */
 187        strcpy(new_op->upcall.req.removexattr.key, name);
 188        new_op->upcall.req.removexattr.key_sz = strlen(name) + 1;
 189
 190        gossip_debug(GOSSIP_XATTR_DEBUG,
 191                     "orangefs_inode_removexattr: key %s, key_sz %d\n",
 192                     (char *)new_op->upcall.req.removexattr.key,
 193                     (int)new_op->upcall.req.removexattr.key_sz);
 194
 195        ret = service_operation(new_op,
 196                                "orangefs_inode_removexattr",
 197                                get_interruptible_flag(inode));
 198        if (ret == -ENOENT) {
 199                /*
 200                 * Request to replace a non-existent attribute is an error.
 201                 */
 202                if (flags & XATTR_REPLACE)
 203                        ret = -ENODATA;
 204                else
 205                        ret = 0;
 206        }
 207
 208        gossip_debug(GOSSIP_XATTR_DEBUG,
 209                     "orangefs_inode_removexattr: returning %d\n", ret);
 210
 211        op_release(new_op);
 212out_unlock:
 213        up_write(&orangefs_inode->xattr_sem);
 214        return ret;
 215}
 216
 217/*
 218 * Tries to set an attribute for a given key on a file.
 219 *
 220 * Returns a -ve number on error and 0 on success.  Key is text, but value
 221 * can be binary!
 222 */
 223int orangefs_inode_setxattr(struct inode *inode, const char *name,
 224                            const void *value, size_t size, int flags)
 225{
 226        struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
 227        struct orangefs_kernel_op_s *new_op;
 228        int internal_flag = 0;
 229        int ret = -ENOMEM;
 230
 231        gossip_debug(GOSSIP_XATTR_DEBUG,
 232                     "%s: name %s, buffer_size %zd\n",
 233                     __func__, name, size);
 234
 235        if (size > ORANGEFS_MAX_XATTR_VALUELEN)
 236                return -EINVAL;
 237        if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN)
 238                return -EINVAL;
 239
 240        internal_flag = convert_to_internal_xattr_flags(flags);
 241
 242        /* This is equivalent to a removexattr */
 243        if (size == 0 && !value) {
 244                gossip_debug(GOSSIP_XATTR_DEBUG,
 245                             "removing xattr (%s)\n",
 246                             name);
 247                return orangefs_inode_removexattr(inode, name, flags);
 248        }
 249
 250        gossip_debug(GOSSIP_XATTR_DEBUG,
 251                     "setxattr on inode %pU, name %s\n",
 252                     get_khandle_from_ino(inode),
 253                     name);
 254
 255        down_write(&orangefs_inode->xattr_sem);
 256        new_op = op_alloc(ORANGEFS_VFS_OP_SETXATTR);
 257        if (!new_op)
 258                goto out_unlock;
 259
 260
 261        new_op->upcall.req.setxattr.refn = orangefs_inode->refn;
 262        new_op->upcall.req.setxattr.flags = internal_flag;
 263        /*
 264         * NOTE: Although keys are meant to be NULL terminated textual
 265         * strings, I am going to explicitly pass the length just in
 266         * case we change this later on...
 267         */
 268        strcpy(new_op->upcall.req.setxattr.keyval.key, name);
 269        new_op->upcall.req.setxattr.keyval.key_sz = strlen(name) + 1;
 270        memcpy(new_op->upcall.req.setxattr.keyval.val, value, size);
 271        new_op->upcall.req.setxattr.keyval.val_sz = size;
 272
 273        gossip_debug(GOSSIP_XATTR_DEBUG,
 274                     "orangefs_inode_setxattr: key %s, key_sz %d "
 275                     " value size %zd\n",
 276                     (char *)new_op->upcall.req.setxattr.keyval.key,
 277                     (int)new_op->upcall.req.setxattr.keyval.key_sz,
 278                     size);
 279
 280        ret = service_operation(new_op,
 281                                "orangefs_inode_setxattr",
 282                                get_interruptible_flag(inode));
 283
 284        gossip_debug(GOSSIP_XATTR_DEBUG,
 285                     "orangefs_inode_setxattr: returning %d\n",
 286                     ret);
 287
 288        /* when request is serviced properly, free req op struct */
 289        op_release(new_op);
 290out_unlock:
 291        up_write(&orangefs_inode->xattr_sem);
 292        return ret;
 293}
 294
 295/*
 296 * Tries to get a specified object's keys into a user-specified buffer of a
 297 * given size.  Note that like the previous instances of xattr routines, this
 298 * also allows you to pass in a NULL pointer and 0 size to probe the size for
 299 * subsequent memory allocations. Thus our return value is always the size of
 300 * all the keys unless there were errors in fetching the keys!
 301 */
 302ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size)
 303{
 304        struct inode *inode = dentry->d_inode;
 305        struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
 306        struct orangefs_kernel_op_s *new_op;
 307        __u64 token = ORANGEFS_ITERATE_START;
 308        ssize_t ret = -ENOMEM;
 309        ssize_t total = 0;
 310        int count_keys = 0;
 311        int key_size;
 312        int i = 0;
 313        int returned_count = 0;
 314
 315        if (size > 0 && !buffer) {
 316                gossip_err("%s: bogus NULL pointers\n", __func__);
 317                return -EINVAL;
 318        }
 319
 320        down_read(&orangefs_inode->xattr_sem);
 321        new_op = op_alloc(ORANGEFS_VFS_OP_LISTXATTR);
 322        if (!new_op)
 323                goto out_unlock;
 324
 325        if (buffer && size > 0)
 326                memset(buffer, 0, size);
 327
 328try_again:
 329        key_size = 0;
 330        new_op->upcall.req.listxattr.refn = orangefs_inode->refn;
 331        new_op->upcall.req.listxattr.token = token;
 332        new_op->upcall.req.listxattr.requested_count =
 333            (size == 0) ? 0 : ORANGEFS_MAX_XATTR_LISTLEN;
 334        ret = service_operation(new_op, __func__,
 335                                get_interruptible_flag(inode));
 336        if (ret != 0)
 337                goto done;
 338
 339        if (size == 0) {
 340                /*
 341                 * This is a bit of a big upper limit, but I did not want to
 342                 * spend too much time getting this correct, since users end
 343                 * up allocating memory rather than us...
 344                 */
 345                total = new_op->downcall.resp.listxattr.returned_count *
 346                        ORANGEFS_MAX_XATTR_NAMELEN;
 347                goto done;
 348        }
 349
 350        returned_count = new_op->downcall.resp.listxattr.returned_count;
 351        if (returned_count < 0 ||
 352            returned_count > ORANGEFS_MAX_XATTR_LISTLEN) {
 353                gossip_err("%s: impossible value for returned_count:%d:\n",
 354                __func__,
 355                returned_count);
 356                ret = -EIO;
 357                goto done;
 358        }
 359
 360        /*
 361         * Check to see how much can be fit in the buffer. Fit only whole keys.
 362         */
 363        for (i = 0; i < returned_count; i++) {
 364                if (new_op->downcall.resp.listxattr.lengths[i] < 0 ||
 365                    new_op->downcall.resp.listxattr.lengths[i] >
 366                    ORANGEFS_MAX_XATTR_NAMELEN) {
 367                        gossip_err("%s: impossible value for lengths[%d]\n",
 368                            __func__,
 369                            new_op->downcall.resp.listxattr.lengths[i]);
 370                        ret = -EIO;
 371                        goto done;
 372                }
 373                if (total + new_op->downcall.resp.listxattr.lengths[i] > size)
 374                        goto done;
 375
 376                /*
 377                 * Since many dumb programs try to setxattr() on our reserved
 378                 * xattrs this is a feeble attempt at defeating those by not
 379                 * listing them in the output of listxattr.. sigh
 380                 */
 381                if (is_reserved_key(new_op->downcall.resp.listxattr.key +
 382                                    key_size,
 383                                    new_op->downcall.resp.
 384                                        listxattr.lengths[i])) {
 385                        gossip_debug(GOSSIP_XATTR_DEBUG, "Copying key %d -> %s\n",
 386                                        i, new_op->downcall.resp.listxattr.key +
 387                                                key_size);
 388                        memcpy(buffer + total,
 389                                new_op->downcall.resp.listxattr.key + key_size,
 390                                new_op->downcall.resp.listxattr.lengths[i]);
 391                        total += new_op->downcall.resp.listxattr.lengths[i];
 392                        count_keys++;
 393                } else {
 394                        gossip_debug(GOSSIP_XATTR_DEBUG, "[RESERVED] key %d -> %s\n",
 395                                        i, new_op->downcall.resp.listxattr.key +
 396                                                key_size);
 397                }
 398                key_size += new_op->downcall.resp.listxattr.lengths[i];
 399        }
 400
 401        /*
 402         * Since the buffer was large enough, we might have to continue
 403         * fetching more keys!
 404         */
 405        token = new_op->downcall.resp.listxattr.token;
 406        if (token != ORANGEFS_ITERATE_END)
 407                goto try_again;
 408
 409done:
 410        gossip_debug(GOSSIP_XATTR_DEBUG, "%s: returning %d"
 411                     " [size of buffer %ld] (filled in %d keys)\n",
 412                     __func__,
 413                     ret ? (int)ret : (int)total,
 414                     (long)size,
 415                     count_keys);
 416        op_release(new_op);
 417        if (ret == 0)
 418                ret = total;
 419out_unlock:
 420        up_read(&orangefs_inode->xattr_sem);
 421        return ret;
 422}
 423
 424static int orangefs_xattr_set_default(const struct xattr_handler *handler,
 425                                      struct dentry *unused,
 426                                      struct inode *inode,
 427                                      const char *name,
 428                                      const void *buffer,
 429                                      size_t size,
 430                                      int flags)
 431{
 432        return orangefs_inode_setxattr(inode, name, buffer, size, flags);
 433}
 434
 435static int orangefs_xattr_get_default(const struct xattr_handler *handler,
 436                                      struct dentry *unused,
 437                                      struct inode *inode,
 438                                      const char *name,
 439                                      void *buffer,
 440                                      size_t size)
 441{
 442        return orangefs_inode_getxattr(inode, name, buffer, size);
 443
 444}
 445
 446static const struct xattr_handler orangefs_xattr_default_handler = {
 447        .prefix = "",  /* match any name => handlers called with full name */
 448        .get = orangefs_xattr_get_default,
 449        .set = orangefs_xattr_set_default,
 450};
 451
 452const struct xattr_handler *orangefs_xattr_handlers[] = {
 453        &posix_acl_access_xattr_handler,
 454        &posix_acl_default_xattr_handler,
 455        &orangefs_xattr_default_handler,
 456        NULL
 457};
 458