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
  14static const char afs_xattr_list[] =
  15        "afs.acl\0"
  16        "afs.cell\0"
  17        "afs.fid\0"
  18        "afs.volume\0"
  19        "afs.yfs.acl\0"
  20        "afs.yfs.acl_inherited\0"
  21        "afs.yfs.acl_num_cleaned\0"
  22        "afs.yfs.vol_acl";
  23
  24/*
  25 * Retrieve a list of the supported xattrs.
  26 */
  27ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size)
  28{
  29        if (size == 0)
  30                return sizeof(afs_xattr_list);
  31        if (size < sizeof(afs_xattr_list))
  32                return -ERANGE;
  33        memcpy(buffer, afs_xattr_list, sizeof(afs_xattr_list));
  34        return sizeof(afs_xattr_list);
  35}
  36
  37/*
  38 * Get a file's ACL.
  39 */
  40static int afs_xattr_get_acl(const struct xattr_handler *handler,
  41                             struct dentry *dentry,
  42                             struct inode *inode, const char *name,
  43                             void *buffer, size_t size)
  44{
  45        struct afs_fs_cursor fc;
  46        struct afs_status_cb *scb;
  47        struct afs_vnode *vnode = AFS_FS_I(inode);
  48        struct afs_acl *acl = NULL;
  49        struct key *key;
  50        int ret = -ENOMEM;
  51
  52        scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
  53        if (!scb)
  54                goto error;
  55
  56        key = afs_request_key(vnode->volume->cell);
  57        if (IS_ERR(key)) {
  58                ret = PTR_ERR(key);
  59                goto error_scb;
  60        }
  61
  62        ret = -ERESTARTSYS;
  63        if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
  64                afs_dataversion_t data_version = vnode->status.data_version;
  65
  66                while (afs_select_fileserver(&fc)) {
  67                        fc.cb_break = afs_calc_vnode_cb_break(vnode);
  68                        acl = afs_fs_fetch_acl(&fc, scb);
  69                }
  70
  71                afs_check_for_remote_deletion(&fc, fc.vnode);
  72                afs_vnode_commit_status(&fc, vnode, fc.cb_break,
  73                                        &data_version, scb);
  74                ret = afs_end_vnode_operation(&fc);
  75        }
  76
  77        if (ret == 0) {
  78                ret = acl->size;
  79                if (size > 0) {
  80                        if (acl->size <= size)
  81                                memcpy(buffer, acl->data, acl->size);
  82                        else
  83                                ret = -ERANGE;
  84                }
  85                kfree(acl);
  86        }
  87
  88        key_put(key);
  89error_scb:
  90        kfree(scb);
  91error:
  92        return ret;
  93}
  94
  95/*
  96 * Set a file's AFS3 ACL.
  97 */
  98static int afs_xattr_set_acl(const struct xattr_handler *handler,
  99                             struct dentry *dentry,
 100                             struct inode *inode, const char *name,
 101                             const void *buffer, size_t size, int flags)
 102{
 103        struct afs_fs_cursor fc;
 104        struct afs_status_cb *scb;
 105        struct afs_vnode *vnode = AFS_FS_I(inode);
 106        struct afs_acl *acl = NULL;
 107        struct key *key;
 108        int ret = -ENOMEM;
 109
 110        if (flags == XATTR_CREATE)
 111                return -EINVAL;
 112
 113        scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
 114        if (!scb)
 115                goto error;
 116
 117        acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
 118        if (!acl)
 119                goto error_scb;
 120
 121        key = afs_request_key(vnode->volume->cell);
 122        if (IS_ERR(key)) {
 123                ret = PTR_ERR(key);
 124                goto error_acl;
 125        }
 126
 127        acl->size = size;
 128        memcpy(acl->data, buffer, size);
 129
 130        ret = -ERESTARTSYS;
 131        if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
 132                afs_dataversion_t data_version = vnode->status.data_version;
 133
 134                while (afs_select_fileserver(&fc)) {
 135                        fc.cb_break = afs_calc_vnode_cb_break(vnode);
 136                        afs_fs_store_acl(&fc, acl, scb);
 137                }
 138
 139                afs_check_for_remote_deletion(&fc, fc.vnode);
 140                afs_vnode_commit_status(&fc, vnode, fc.cb_break,
 141                                        &data_version, scb);
 142                ret = afs_end_vnode_operation(&fc);
 143        }
 144
 145        key_put(key);
 146error_acl:
 147        kfree(acl);
 148error_scb:
 149        kfree(scb);
 150error:
 151        return ret;
 152}
 153
 154static const struct xattr_handler afs_xattr_afs_acl_handler = {
 155        .name   = "afs.acl",
 156        .get    = afs_xattr_get_acl,
 157        .set    = afs_xattr_set_acl,
 158};
 159
 160/*
 161 * Get a file's YFS ACL.
 162 */
 163static int afs_xattr_get_yfs(const struct xattr_handler *handler,
 164                             struct dentry *dentry,
 165                             struct inode *inode, const char *name,
 166                             void *buffer, size_t size)
 167{
 168        struct afs_fs_cursor fc;
 169        struct afs_status_cb *scb;
 170        struct afs_vnode *vnode = AFS_FS_I(inode);
 171        struct yfs_acl *yacl = NULL;
 172        struct key *key;
 173        char buf[16], *data;
 174        int which = 0, dsize, ret = -ENOMEM;
 175
 176        if (strcmp(name, "acl") == 0)
 177                which = 0;
 178        else if (strcmp(name, "acl_inherited") == 0)
 179                which = 1;
 180        else if (strcmp(name, "acl_num_cleaned") == 0)
 181                which = 2;
 182        else if (strcmp(name, "vol_acl") == 0)
 183                which = 3;
 184        else
 185                return -EOPNOTSUPP;
 186
 187        yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL);
 188        if (!yacl)
 189                goto error;
 190
 191        if (which == 0)
 192                yacl->flags |= YFS_ACL_WANT_ACL;
 193        else if (which == 3)
 194                yacl->flags |= YFS_ACL_WANT_VOL_ACL;
 195
 196        scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
 197        if (!scb)
 198                goto error_yacl;
 199
 200        key = afs_request_key(vnode->volume->cell);
 201        if (IS_ERR(key)) {
 202                ret = PTR_ERR(key);
 203                goto error_scb;
 204        }
 205
 206        ret = -ERESTARTSYS;
 207        if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
 208                afs_dataversion_t data_version = vnode->status.data_version;
 209
 210                while (afs_select_fileserver(&fc)) {
 211                        fc.cb_break = afs_calc_vnode_cb_break(vnode);
 212                        yfs_fs_fetch_opaque_acl(&fc, yacl, scb);
 213                }
 214
 215                afs_check_for_remote_deletion(&fc, fc.vnode);
 216                afs_vnode_commit_status(&fc, vnode, fc.cb_break,
 217                                        &data_version, scb);
 218                ret = afs_end_vnode_operation(&fc);
 219        }
 220
 221        if (ret < 0)
 222                goto error_key;
 223
 224        switch (which) {
 225        case 0:
 226                data = yacl->acl->data;
 227                dsize = yacl->acl->size;
 228                break;
 229        case 1:
 230                data = buf;
 231                dsize = snprintf(buf, sizeof(buf), "%u", yacl->inherit_flag);
 232                break;
 233        case 2:
 234                data = buf;
 235                dsize = snprintf(buf, sizeof(buf), "%u", yacl->num_cleaned);
 236                break;
 237        case 3:
 238                data = yacl->vol_acl->data;
 239                dsize = yacl->vol_acl->size;
 240                break;
 241        default:
 242                ret = -EOPNOTSUPP;
 243                goto error_key;
 244        }
 245
 246        ret = dsize;
 247        if (size > 0) {
 248                if (dsize > size) {
 249                        ret = -ERANGE;
 250                        goto error_key;
 251                }
 252                memcpy(buffer, data, dsize);
 253        }
 254
 255error_key:
 256        key_put(key);
 257error_scb:
 258        kfree(scb);
 259error_yacl:
 260        yfs_free_opaque_acl(yacl);
 261error:
 262        return ret;
 263}
 264
 265/*
 266 * Set a file's YFS ACL.
 267 */
 268static int afs_xattr_set_yfs(const struct xattr_handler *handler,
 269                             struct dentry *dentry,
 270                             struct inode *inode, const char *name,
 271                             const void *buffer, size_t size, int flags)
 272{
 273        struct afs_fs_cursor fc;
 274        struct afs_status_cb *scb;
 275        struct afs_vnode *vnode = AFS_FS_I(inode);
 276        struct afs_acl *acl = NULL;
 277        struct key *key;
 278        int ret = -ENOMEM;
 279
 280        if (flags == XATTR_CREATE ||
 281            strcmp(name, "acl") != 0)
 282                return -EINVAL;
 283
 284        scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
 285        if (!scb)
 286                goto error;
 287
 288        acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
 289        if (!acl)
 290                goto error_scb;
 291
 292        acl->size = size;
 293        memcpy(acl->data, buffer, size);
 294
 295        key = afs_request_key(vnode->volume->cell);
 296        if (IS_ERR(key)) {
 297                ret = PTR_ERR(key);
 298                goto error_acl;
 299        }
 300
 301        ret = -ERESTARTSYS;
 302        if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
 303                afs_dataversion_t data_version = vnode->status.data_version;
 304
 305                while (afs_select_fileserver(&fc)) {
 306                        fc.cb_break = afs_calc_vnode_cb_break(vnode);
 307                        yfs_fs_store_opaque_acl2(&fc, acl, scb);
 308                }
 309
 310                afs_check_for_remote_deletion(&fc, fc.vnode);
 311                afs_vnode_commit_status(&fc, vnode, fc.cb_break,
 312                                        &data_version, scb);
 313                ret = afs_end_vnode_operation(&fc);
 314        }
 315
 316error_acl:
 317        kfree(acl);
 318        key_put(key);
 319error_scb:
 320        kfree(scb);
 321error:
 322        return ret;
 323}
 324
 325static const struct xattr_handler afs_xattr_yfs_handler = {
 326        .prefix = "afs.yfs.",
 327        .get    = afs_xattr_get_yfs,
 328        .set    = afs_xattr_set_yfs,
 329};
 330
 331/*
 332 * Get the name of the cell on which a file resides.
 333 */
 334static int afs_xattr_get_cell(const struct xattr_handler *handler,
 335                              struct dentry *dentry,
 336                              struct inode *inode, const char *name,
 337                              void *buffer, size_t size)
 338{
 339        struct afs_vnode *vnode = AFS_FS_I(inode);
 340        struct afs_cell *cell = vnode->volume->cell;
 341        size_t namelen;
 342
 343        namelen = cell->name_len;
 344        if (size == 0)
 345                return namelen;
 346        if (namelen > size)
 347                return -ERANGE;
 348        memcpy(buffer, cell->name, namelen);
 349        return namelen;
 350}
 351
 352static const struct xattr_handler afs_xattr_afs_cell_handler = {
 353        .name   = "afs.cell",
 354        .get    = afs_xattr_get_cell,
 355};
 356
 357/*
 358 * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of
 359 * hex numbers separated by colons.
 360 */
 361static int afs_xattr_get_fid(const struct xattr_handler *handler,
 362                             struct dentry *dentry,
 363                             struct inode *inode, const char *name,
 364                             void *buffer, size_t size)
 365{
 366        struct afs_vnode *vnode = AFS_FS_I(inode);
 367        char text[16 + 1 + 24 + 1 + 8 + 1];
 368        size_t len;
 369
 370        /* The volume ID is 64-bit, the vnode ID is 96-bit and the
 371         * uniquifier is 32-bit.
 372         */
 373        len = sprintf(text, "%llx:", vnode->fid.vid);
 374        if (vnode->fid.vnode_hi)
 375                len += sprintf(text + len, "%x%016llx",
 376                               vnode->fid.vnode_hi, vnode->fid.vnode);
 377        else
 378                len += sprintf(text + len, "%llx", vnode->fid.vnode);
 379        len += sprintf(text + len, ":%x", vnode->fid.unique);
 380
 381        if (size == 0)
 382                return len;
 383        if (len > size)
 384                return -ERANGE;
 385        memcpy(buffer, text, len);
 386        return len;
 387}
 388
 389static const struct xattr_handler afs_xattr_afs_fid_handler = {
 390        .name   = "afs.fid",
 391        .get    = afs_xattr_get_fid,
 392};
 393
 394/*
 395 * Get the name of the volume on which a file resides.
 396 */
 397static int afs_xattr_get_volume(const struct xattr_handler *handler,
 398                              struct dentry *dentry,
 399                              struct inode *inode, const char *name,
 400                              void *buffer, size_t size)
 401{
 402        struct afs_vnode *vnode = AFS_FS_I(inode);
 403        const char *volname = vnode->volume->name;
 404        size_t namelen;
 405
 406        namelen = strlen(volname);
 407        if (size == 0)
 408                return namelen;
 409        if (namelen > size)
 410                return -ERANGE;
 411        memcpy(buffer, volname, namelen);
 412        return namelen;
 413}
 414
 415static const struct xattr_handler afs_xattr_afs_volume_handler = {
 416        .name   = "afs.volume",
 417        .get    = afs_xattr_get_volume,
 418};
 419
 420const struct xattr_handler *afs_xattr_handlers[] = {
 421        &afs_xattr_afs_acl_handler,
 422        &afs_xattr_afs_cell_handler,
 423        &afs_xattr_afs_fid_handler,
 424        &afs_xattr_afs_volume_handler,
 425        &afs_xattr_yfs_handler,         /* afs.yfs. prefix */
 426        NULL
 427};
 428