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