linux/fs/afs/xattr.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* Extended attribute handling for AFS.  We use xattrs to get and set metadata
   3 * instead of providing pioctl().
   4 *
   5 * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
   6 * Written by David Howells (dhowells@redhat.com)
   7 */
   8
   9#include <linux/slab.h>
  10#include <linux/fs.h>
  11#include <linux/xattr.h>
  12#include "internal.h"
  13
  14/*
  15 * Deal with the result of a successful fetch ACL operation.
  16 */
  17static void afs_acl_success(struct afs_operation *op)
  18{
  19        afs_vnode_commit_status(op, &op->file[0]);
  20}
  21
  22static void afs_acl_put(struct afs_operation *op)
  23{
  24        kfree(op->acl);
  25}
  26
  27static const struct afs_operation_ops afs_fetch_acl_operation = {
  28        .issue_afs_rpc  = afs_fs_fetch_acl,
  29        .success        = afs_acl_success,
  30        .put            = afs_acl_put,
  31};
  32
  33/*
  34 * Get a file's ACL.
  35 */
  36static int afs_xattr_get_acl(const struct xattr_handler *handler,
  37                             struct dentry *dentry,
  38                             struct inode *inode, const char *name,
  39                             void *buffer, size_t size)
  40{
  41        struct afs_operation *op;
  42        struct afs_vnode *vnode = AFS_FS_I(inode);
  43        struct afs_acl *acl = NULL;
  44        int ret;
  45
  46        op = afs_alloc_operation(NULL, vnode->volume);
  47        if (IS_ERR(op))
  48                return -ENOMEM;
  49
  50        afs_op_set_vnode(op, 0, vnode);
  51        op->ops = &afs_fetch_acl_operation;
  52
  53        afs_begin_vnode_operation(op);
  54        afs_wait_for_operation(op);
  55        acl = op->acl;
  56        op->acl = NULL;
  57        ret = afs_put_operation(op);
  58
  59        if (ret == 0) {
  60                ret = acl->size;
  61                if (size > 0) {
  62                        if (acl->size <= size)
  63                                memcpy(buffer, acl->data, acl->size);
  64                        else
  65                                ret = -ERANGE;
  66                }
  67        }
  68
  69        kfree(acl);
  70        return ret;
  71}
  72
  73static bool afs_make_acl(struct afs_operation *op,
  74                         const void *buffer, size_t size)
  75{
  76        struct afs_acl *acl;
  77
  78        acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
  79        if (!acl) {
  80                afs_op_nomem(op);
  81                return false;
  82        }
  83
  84        acl->size = size;
  85        memcpy(acl->data, buffer, size);
  86        op->acl = acl;
  87        return true;
  88}
  89
  90static const struct afs_operation_ops afs_store_acl_operation = {
  91        .issue_afs_rpc  = afs_fs_store_acl,
  92        .success        = afs_acl_success,
  93        .put            = afs_acl_put,
  94};
  95
  96/*
  97 * Set a file's AFS3 ACL.
  98 */
  99static int afs_xattr_set_acl(const struct xattr_handler *handler,
 100                             struct user_namespace *mnt_userns,
 101                             struct dentry *dentry,
 102                             struct inode *inode, const char *name,
 103                             const void *buffer, size_t size, int flags)
 104{
 105        struct afs_operation *op;
 106        struct afs_vnode *vnode = AFS_FS_I(inode);
 107
 108        if (flags == XATTR_CREATE)
 109                return -EINVAL;
 110
 111        op = afs_alloc_operation(NULL, vnode->volume);
 112        if (IS_ERR(op))
 113                return -ENOMEM;
 114
 115        afs_op_set_vnode(op, 0, vnode);
 116        if (!afs_make_acl(op, buffer, size))
 117                return afs_put_operation(op);
 118
 119        op->ops = &afs_store_acl_operation;
 120        return afs_do_sync_operation(op);
 121}
 122
 123static const struct xattr_handler afs_xattr_afs_acl_handler = {
 124        .name   = "afs.acl",
 125        .get    = afs_xattr_get_acl,
 126        .set    = afs_xattr_set_acl,
 127};
 128
 129static const struct afs_operation_ops yfs_fetch_opaque_acl_operation = {
 130        .issue_yfs_rpc  = yfs_fs_fetch_opaque_acl,
 131        .success        = afs_acl_success,
 132        /* Don't free op->yacl in .put here */
 133};
 134
 135/*
 136 * Get a file's YFS ACL.
 137 */
 138static int afs_xattr_get_yfs(const struct xattr_handler *handler,
 139                             struct dentry *dentry,
 140                             struct inode *inode, const char *name,
 141                             void *buffer, size_t size)
 142{
 143        struct afs_operation *op;
 144        struct afs_vnode *vnode = AFS_FS_I(inode);
 145        struct yfs_acl *yacl = NULL;
 146        char buf[16], *data;
 147        int which = 0, dsize, ret = -ENOMEM;
 148
 149        if (strcmp(name, "acl") == 0)
 150                which = 0;
 151        else if (strcmp(name, "acl_inherited") == 0)
 152                which = 1;
 153        else if (strcmp(name, "acl_num_cleaned") == 0)
 154                which = 2;
 155        else if (strcmp(name, "vol_acl") == 0)
 156                which = 3;
 157        else
 158                return -EOPNOTSUPP;
 159
 160        yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL);
 161        if (!yacl)
 162                goto error;
 163
 164        if (which == 0)
 165                yacl->flags |= YFS_ACL_WANT_ACL;
 166        else if (which == 3)
 167                yacl->flags |= YFS_ACL_WANT_VOL_ACL;
 168
 169        op = afs_alloc_operation(NULL, vnode->volume);
 170        if (IS_ERR(op))
 171                goto error_yacl;
 172
 173        afs_op_set_vnode(op, 0, vnode);
 174        op->yacl = yacl;
 175        op->ops = &yfs_fetch_opaque_acl_operation;
 176
 177        afs_begin_vnode_operation(op);
 178        afs_wait_for_operation(op);
 179        ret = afs_put_operation(op);
 180
 181        if (ret == 0) {
 182                switch (which) {
 183                case 0:
 184                        data = yacl->acl->data;
 185                        dsize = yacl->acl->size;
 186                        break;
 187                case 1:
 188                        data = buf;
 189                        dsize = scnprintf(buf, sizeof(buf), "%u", yacl->inherit_flag);
 190                        break;
 191                case 2:
 192                        data = buf;
 193                        dsize = scnprintf(buf, sizeof(buf), "%u", yacl->num_cleaned);
 194                        break;
 195                case 3:
 196                        data = yacl->vol_acl->data;
 197                        dsize = yacl->vol_acl->size;
 198                        break;
 199                default:
 200                        ret = -EOPNOTSUPP;
 201                        goto error_yacl;
 202                }
 203
 204                ret = dsize;
 205                if (size > 0) {
 206                        if (dsize <= size)
 207                                memcpy(buffer, data, dsize);
 208                        else
 209                                ret = -ERANGE;
 210                }
 211        } else if (ret == -ENOTSUPP) {
 212                ret = -ENODATA;
 213        }
 214
 215error_yacl:
 216        yfs_free_opaque_acl(yacl);
 217error:
 218        return ret;
 219}
 220
 221static const struct afs_operation_ops yfs_store_opaque_acl2_operation = {
 222        .issue_yfs_rpc  = yfs_fs_store_opaque_acl2,
 223        .success        = afs_acl_success,
 224        .put            = afs_acl_put,
 225};
 226
 227/*
 228 * Set a file's YFS ACL.
 229 */
 230static int afs_xattr_set_yfs(const struct xattr_handler *handler,
 231                             struct user_namespace *mnt_userns,
 232                             struct dentry *dentry,
 233                             struct inode *inode, const char *name,
 234                             const void *buffer, size_t size, int flags)
 235{
 236        struct afs_operation *op;
 237        struct afs_vnode *vnode = AFS_FS_I(inode);
 238        int ret;
 239
 240        if (flags == XATTR_CREATE ||
 241            strcmp(name, "acl") != 0)
 242                return -EINVAL;
 243
 244        op = afs_alloc_operation(NULL, vnode->volume);
 245        if (IS_ERR(op))
 246                return -ENOMEM;
 247
 248        afs_op_set_vnode(op, 0, vnode);
 249        if (!afs_make_acl(op, buffer, size))
 250                return afs_put_operation(op);
 251
 252        op->ops = &yfs_store_opaque_acl2_operation;
 253        ret = afs_do_sync_operation(op);
 254        if (ret == -ENOTSUPP)
 255                ret = -ENODATA;
 256        return ret;
 257}
 258
 259static const struct xattr_handler afs_xattr_yfs_handler = {
 260        .prefix = "afs.yfs.",
 261        .get    = afs_xattr_get_yfs,
 262        .set    = afs_xattr_set_yfs,
 263};
 264
 265/*
 266 * Get the name of the cell on which a file resides.
 267 */
 268static int afs_xattr_get_cell(const struct xattr_handler *handler,
 269                              struct dentry *dentry,
 270                              struct inode *inode, const char *name,
 271                              void *buffer, size_t size)
 272{
 273        struct afs_vnode *vnode = AFS_FS_I(inode);
 274        struct afs_cell *cell = vnode->volume->cell;
 275        size_t namelen;
 276
 277        namelen = cell->name_len;
 278        if (size == 0)
 279                return namelen;
 280        if (namelen > size)
 281                return -ERANGE;
 282        memcpy(buffer, cell->name, namelen);
 283        return namelen;
 284}
 285
 286static const struct xattr_handler afs_xattr_afs_cell_handler = {
 287        .name   = "afs.cell",
 288        .get    = afs_xattr_get_cell,
 289};
 290
 291/*
 292 * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of
 293 * hex numbers separated by colons.
 294 */
 295static int afs_xattr_get_fid(const struct xattr_handler *handler,
 296                             struct dentry *dentry,
 297                             struct inode *inode, const char *name,
 298                             void *buffer, size_t size)
 299{
 300        struct afs_vnode *vnode = AFS_FS_I(inode);
 301        char text[16 + 1 + 24 + 1 + 8 + 1];
 302        size_t len;
 303
 304        /* The volume ID is 64-bit, the vnode ID is 96-bit and the
 305         * uniquifier is 32-bit.
 306         */
 307        len = scnprintf(text, sizeof(text), "%llx:", vnode->fid.vid);
 308        if (vnode->fid.vnode_hi)
 309                len += scnprintf(text + len, sizeof(text) - len, "%x%016llx",
 310                                vnode->fid.vnode_hi, vnode->fid.vnode);
 311        else
 312                len += scnprintf(text + len, sizeof(text) - len, "%llx",
 313                                 vnode->fid.vnode);
 314        len += scnprintf(text + len, sizeof(text) - len, ":%x",
 315                         vnode->fid.unique);
 316
 317        if (size == 0)
 318                return len;
 319        if (len > size)
 320                return -ERANGE;
 321        memcpy(buffer, text, len);
 322        return len;
 323}
 324
 325static const struct xattr_handler afs_xattr_afs_fid_handler = {
 326        .name   = "afs.fid",
 327        .get    = afs_xattr_get_fid,
 328};
 329
 330/*
 331 * Get the name of the volume on which a file resides.
 332 */
 333static int afs_xattr_get_volume(const struct xattr_handler *handler,
 334                              struct dentry *dentry,
 335                              struct inode *inode, const char *name,
 336                              void *buffer, size_t size)
 337{
 338        struct afs_vnode *vnode = AFS_FS_I(inode);
 339        const char *volname = vnode->volume->name;
 340        size_t namelen;
 341
 342        namelen = strlen(volname);
 343        if (size == 0)
 344                return namelen;
 345        if (namelen > size)
 346                return -ERANGE;
 347        memcpy(buffer, volname, namelen);
 348        return namelen;
 349}
 350
 351static const struct xattr_handler afs_xattr_afs_volume_handler = {
 352        .name   = "afs.volume",
 353        .get    = afs_xattr_get_volume,
 354};
 355
 356const struct xattr_handler *afs_xattr_handlers[] = {
 357        &afs_xattr_afs_acl_handler,
 358        &afs_xattr_afs_cell_handler,
 359        &afs_xattr_afs_fid_handler,
 360        &afs_xattr_afs_volume_handler,
 361        &afs_xattr_yfs_handler,         /* afs.yfs. prefix */
 362        NULL
 363};
 364