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                return -EINVAL;
  81
  82        fsuid = from_kuid(&init_user_ns, current_fsuid());
  83        fsgid = from_kgid(&init_user_ns, current_fsgid());
  84
  85        gossip_debug(GOSSIP_XATTR_DEBUG,
  86                     "getxattr on inode %pU, name %s "
  87                     "(uid %o, gid %o)\n",
  88                     get_khandle_from_ino(inode),
  89                     name,
  90                     fsuid,
  91                     fsgid);
  92
  93        down_read(&orangefs_inode->xattr_sem);
  94
  95        new_op = op_alloc(ORANGEFS_VFS_OP_GETXATTR);
  96        if (!new_op)
  97                goto out_unlock;
  98
  99        new_op->upcall.req.getxattr.refn = orangefs_inode->refn;
 100        strcpy(new_op->upcall.req.getxattr.key, name);
 101
 102        /*
 103         * NOTE: Although keys are meant to be NULL terminated textual
 104         * strings, I am going to explicitly pass the length just in case
 105         * we change this later on...
 106         */
 107        new_op->upcall.req.getxattr.key_sz = strlen(name) + 1;
 108
 109        ret = service_operation(new_op, "orangefs_inode_getxattr",
 110                                get_interruptible_flag(inode));
 111        if (ret != 0) {
 112                if (ret == -ENOENT) {
 113                        ret = -ENODATA;
 114                        gossip_debug(GOSSIP_XATTR_DEBUG,
 115                                     "orangefs_inode_getxattr: inode %pU key %s"
 116                                     " does not exist!\n",
 117                                     get_khandle_from_ino(inode),
 118                                     (char *)new_op->upcall.req.getxattr.key);
 119                }
 120                goto out_release_op;
 121        }
 122
 123        /*
 124         * Length returned includes null terminator.
 125         */
 126        length = new_op->downcall.resp.getxattr.val_sz;
 127
 128        /*
 129         * Just return the length of the queried attribute.
 130         */
 131        if (size == 0) {
 132                ret = length;
 133                goto out_release_op;
 134        }
 135
 136        /*
 137         * Check to see if key length is > provided buffer size.
 138         */
 139        if (length > size) {
 140                ret = -ERANGE;
 141                goto out_release_op;
 142        }
 143
 144        memcpy(buffer, new_op->downcall.resp.getxattr.val, length);
 145        memset(buffer + length, 0, size - length);
 146        gossip_debug(GOSSIP_XATTR_DEBUG,
 147             "orangefs_inode_getxattr: inode %pU "
 148             "key %s key_sz %d, val_len %d\n",
 149             get_khandle_from_ino(inode),
 150             (char *)new_op->
 151                upcall.req.getxattr.key,
 152                     (int)new_op->
 153                upcall.req.getxattr.key_sz,
 154             (int)ret);
 155
 156        ret = length;
 157
 158out_release_op:
 159        op_release(new_op);
 160out_unlock:
 161        up_read(&orangefs_inode->xattr_sem);
 162        return ret;
 163}
 164
 165static int orangefs_inode_removexattr(struct inode *inode, const char *name,
 166                                      int flags)
 167{
 168        struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
 169        struct orangefs_kernel_op_s *new_op = NULL;
 170        int ret = -ENOMEM;
 171
 172        if (strlen(name) > ORANGEFS_MAX_XATTR_NAMELEN)
 173                return -EINVAL;
 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                return -EINVAL;
 236        if (strlen(name) > ORANGEFS_MAX_XATTR_NAMELEN)
 237                return -EINVAL;
 238
 239        internal_flag = convert_to_internal_xattr_flags(flags);
 240
 241        /* This is equivalent to a removexattr */
 242        if (size == 0 && value == NULL) {
 243                gossip_debug(GOSSIP_XATTR_DEBUG,
 244                             "removing xattr (%s)\n",
 245                             name);
 246                return orangefs_inode_removexattr(inode, name, flags);
 247        }
 248
 249        gossip_debug(GOSSIP_XATTR_DEBUG,
 250                     "setxattr on inode %pU, name %s\n",
 251                     get_khandle_from_ino(inode),
 252                     name);
 253
 254        down_write(&orangefs_inode->xattr_sem);
 255        new_op = op_alloc(ORANGEFS_VFS_OP_SETXATTR);
 256        if (!new_op)
 257                goto out_unlock;
 258
 259
 260        new_op->upcall.req.setxattr.refn = orangefs_inode->refn;
 261        new_op->upcall.req.setxattr.flags = internal_flag;
 262        /*
 263         * NOTE: Although keys are meant to be NULL terminated textual
 264         * strings, I am going to explicitly pass the length just in
 265         * case we change this later on...
 266         */
 267        strcpy(new_op->upcall.req.setxattr.keyval.key, name);
 268        new_op->upcall.req.setxattr.keyval.key_sz = strlen(name) + 1;
 269        memcpy(new_op->upcall.req.setxattr.keyval.val, value, size);
 270        new_op->upcall.req.setxattr.keyval.val_sz = size;
 271
 272        gossip_debug(GOSSIP_XATTR_DEBUG,
 273                     "orangefs_inode_setxattr: key %s, key_sz %d "
 274                     " value size %zd\n",
 275                     (char *)new_op->upcall.req.setxattr.keyval.key,
 276                     (int)new_op->upcall.req.setxattr.keyval.key_sz,
 277                     size);
 278
 279        ret = service_operation(new_op,
 280                                "orangefs_inode_setxattr",
 281                                get_interruptible_flag(inode));
 282
 283        gossip_debug(GOSSIP_XATTR_DEBUG,
 284                     "orangefs_inode_setxattr: returning %d\n",
 285                     ret);
 286
 287        /* when request is serviced properly, free req op struct */
 288        op_release(new_op);
 289out_unlock:
 290        up_write(&orangefs_inode->xattr_sem);
 291        return ret;
 292}
 293
 294/*
 295 * Tries to get a specified object's keys into a user-specified buffer of a
 296 * given size.  Note that like the previous instances of xattr routines, this
 297 * also allows you to pass in a NULL pointer and 0 size to probe the size for
 298 * subsequent memory allocations. Thus our return value is always the size of
 299 * all the keys unless there were errors in fetching the keys!
 300 */
 301ssize_t orangefs_listxattr(struct dentry *dentry, char *buffer, size_t size)
 302{
 303        struct inode *inode = dentry->d_inode;
 304        struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
 305        struct orangefs_kernel_op_s *new_op;
 306        __u64 token = ORANGEFS_ITERATE_START;
 307        ssize_t ret = -ENOMEM;
 308        ssize_t total = 0;
 309        int count_keys = 0;
 310        int key_size;
 311        int i = 0;
 312        int returned_count = 0;
 313
 314        if (size > 0 && buffer == NULL) {
 315                gossip_err("%s: bogus NULL pointers\n", __func__);
 316                return -EINVAL;
 317        }
 318
 319        down_read(&orangefs_inode->xattr_sem);
 320        new_op = op_alloc(ORANGEFS_VFS_OP_LISTXATTR);
 321        if (!new_op)
 322                goto out_unlock;
 323
 324        if (buffer && size > 0)
 325                memset(buffer, 0, size);
 326
 327try_again:
 328        key_size = 0;
 329        new_op->upcall.req.listxattr.refn = orangefs_inode->refn;
 330        new_op->upcall.req.listxattr.token = token;
 331        new_op->upcall.req.listxattr.requested_count =
 332            (size == 0) ? 0 : ORANGEFS_MAX_XATTR_LISTLEN;
 333        ret = service_operation(new_op, __func__,
 334                                get_interruptible_flag(inode));
 335        if (ret != 0)
 336                goto done;
 337
 338        if (size == 0) {
 339                /*
 340                 * This is a bit of a big upper limit, but I did not want to
 341                 * spend too much time getting this correct, since users end
 342                 * up allocating memory rather than us...
 343                 */
 344                total = new_op->downcall.resp.listxattr.returned_count *
 345                        ORANGEFS_MAX_XATTR_NAMELEN;
 346                goto done;
 347        }
 348
 349        returned_count = new_op->downcall.resp.listxattr.returned_count;
 350        if (returned_count < 0 ||
 351            returned_count > ORANGEFS_MAX_XATTR_LISTLEN) {
 352                gossip_err("%s: impossible value for returned_count:%d:\n",
 353                __func__,
 354                returned_count);
 355                ret = -EIO;
 356                goto done;
 357        }
 358
 359        /*
 360         * Check to see how much can be fit in the buffer. Fit only whole keys.
 361         */
 362        for (i = 0; i < returned_count; i++) {
 363                if (new_op->downcall.resp.listxattr.lengths[i] < 0 ||
 364                    new_op->downcall.resp.listxattr.lengths[i] >
 365                    ORANGEFS_MAX_XATTR_NAMELEN) {
 366                        gossip_err("%s: impossible value for lengths[%d]\n",
 367                            __func__,
 368                            new_op->downcall.resp.listxattr.lengths[i]);
 369                        ret = -EIO;
 370                        goto done;
 371                }
 372                if (total + new_op->downcall.resp.listxattr.lengths[i] > size)
 373                        goto done;
 374
 375                /*
 376                 * Since many dumb programs try to setxattr() on our reserved
 377                 * xattrs this is a feeble attempt at defeating those by not
 378                 * listing them in the output of listxattr.. sigh
 379                 */
 380                if (is_reserved_key(new_op->downcall.resp.listxattr.key +
 381                                    key_size,
 382                                    new_op->downcall.resp.
 383                                        listxattr.lengths[i])) {
 384                        gossip_debug(GOSSIP_XATTR_DEBUG, "Copying key %d -> %s\n",
 385                                        i, new_op->downcall.resp.listxattr.key +
 386                                                key_size);
 387                        memcpy(buffer + total,
 388                                new_op->downcall.resp.listxattr.key + key_size,
 389                                new_op->downcall.resp.listxattr.lengths[i]);
 390                        total += new_op->downcall.resp.listxattr.lengths[i];
 391                        count_keys++;
 392                } else {
 393                        gossip_debug(GOSSIP_XATTR_DEBUG, "[RESERVED] key %d -> %s\n",
 394                                        i, new_op->downcall.resp.listxattr.key +
 395                                                key_size);
 396                }
 397                key_size += new_op->downcall.resp.listxattr.lengths[i];
 398        }
 399
 400        /*
 401         * Since the buffer was large enough, we might have to continue
 402         * fetching more keys!
 403         */
 404        token = new_op->downcall.resp.listxattr.token;
 405        if (token != ORANGEFS_ITERATE_END)
 406                goto try_again;
 407
 408done:
 409        gossip_debug(GOSSIP_XATTR_DEBUG, "%s: returning %d"
 410                     " [size of buffer %ld] (filled in %d keys)\n",
 411                     __func__,
 412                     ret ? (int)ret : (int)total,
 413                     (long)size,
 414                     count_keys);
 415        op_release(new_op);
 416        if (ret == 0)
 417                ret = total;
 418out_unlock:
 419        up_read(&orangefs_inode->xattr_sem);
 420        return ret;
 421}
 422
 423static int orangefs_xattr_set_default(const struct xattr_handler *handler,
 424                                      struct dentry *unused,
 425                                      struct inode *inode,
 426                                      const char *name,
 427                                      const void *buffer,
 428                                      size_t size,
 429                                      int flags)
 430{
 431        return orangefs_inode_setxattr(inode, name, buffer, size, flags);
 432}
 433
 434static int orangefs_xattr_get_default(const struct xattr_handler *handler,
 435                                      struct dentry *unused,
 436                                      struct inode *inode,
 437                                      const char *name,
 438                                      void *buffer,
 439                                      size_t size)
 440{
 441        return orangefs_inode_getxattr(inode, name, buffer, size);
 442
 443}
 444
 445static struct xattr_handler orangefs_xattr_default_handler = {
 446        .prefix = "",  /* match any name => handlers called with full name */
 447        .get = orangefs_xattr_get_default,
 448        .set = orangefs_xattr_set_default,
 449};
 450
 451const struct xattr_handler *orangefs_xattr_handlers[] = {
 452        &posix_acl_access_xattr_handler,
 453        &posix_acl_default_xattr_handler,
 454        &orangefs_xattr_default_handler,
 455        NULL
 456};
 457