Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Extended attribute handling for AFS.  We use xattrs to get and set metadata
0003  * instead of providing pioctl().
0004  *
0005  * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
0006  * Written by David Howells (dhowells@redhat.com)
0007  */
0008 
0009 #include <linux/slab.h>
0010 #include <linux/fs.h>
0011 #include <linux/xattr.h>
0012 #include "internal.h"
0013 
0014 /*
0015  * Deal with the result of a successful fetch ACL operation.
0016  */
0017 static void afs_acl_success(struct afs_operation *op)
0018 {
0019     afs_vnode_commit_status(op, &op->file[0]);
0020 }
0021 
0022 static void afs_acl_put(struct afs_operation *op)
0023 {
0024     kfree(op->acl);
0025 }
0026 
0027 static const struct afs_operation_ops afs_fetch_acl_operation = {
0028     .issue_afs_rpc  = afs_fs_fetch_acl,
0029     .success    = afs_acl_success,
0030     .put        = afs_acl_put,
0031 };
0032 
0033 /*
0034  * Get a file's ACL.
0035  */
0036 static int afs_xattr_get_acl(const struct xattr_handler *handler,
0037                  struct dentry *dentry,
0038                  struct inode *inode, const char *name,
0039                  void *buffer, size_t size)
0040 {
0041     struct afs_operation *op;
0042     struct afs_vnode *vnode = AFS_FS_I(inode);
0043     struct afs_acl *acl = NULL;
0044     int ret;
0045 
0046     op = afs_alloc_operation(NULL, vnode->volume);
0047     if (IS_ERR(op))
0048         return -ENOMEM;
0049 
0050     afs_op_set_vnode(op, 0, vnode);
0051     op->ops = &afs_fetch_acl_operation;
0052 
0053     afs_begin_vnode_operation(op);
0054     afs_wait_for_operation(op);
0055     acl = op->acl;
0056     op->acl = NULL;
0057     ret = afs_put_operation(op);
0058 
0059     if (ret == 0) {
0060         ret = acl->size;
0061         if (size > 0) {
0062             if (acl->size <= size)
0063                 memcpy(buffer, acl->data, acl->size);
0064             else
0065                 ret = -ERANGE;
0066         }
0067     }
0068 
0069     kfree(acl);
0070     return ret;
0071 }
0072 
0073 static bool afs_make_acl(struct afs_operation *op,
0074              const void *buffer, size_t size)
0075 {
0076     struct afs_acl *acl;
0077 
0078     acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
0079     if (!acl) {
0080         afs_op_nomem(op);
0081         return false;
0082     }
0083 
0084     acl->size = size;
0085     memcpy(acl->data, buffer, size);
0086     op->acl = acl;
0087     return true;
0088 }
0089 
0090 static const struct afs_operation_ops afs_store_acl_operation = {
0091     .issue_afs_rpc  = afs_fs_store_acl,
0092     .success    = afs_acl_success,
0093     .put        = afs_acl_put,
0094 };
0095 
0096 /*
0097  * Set a file's AFS3 ACL.
0098  */
0099 static int afs_xattr_set_acl(const struct xattr_handler *handler,
0100                  struct user_namespace *mnt_userns,
0101                              struct dentry *dentry,
0102                              struct inode *inode, const char *name,
0103                              const void *buffer, size_t size, int flags)
0104 {
0105     struct afs_operation *op;
0106     struct afs_vnode *vnode = AFS_FS_I(inode);
0107 
0108     if (flags == XATTR_CREATE)
0109         return -EINVAL;
0110 
0111     op = afs_alloc_operation(NULL, vnode->volume);
0112     if (IS_ERR(op))
0113         return -ENOMEM;
0114 
0115     afs_op_set_vnode(op, 0, vnode);
0116     if (!afs_make_acl(op, buffer, size))
0117         return afs_put_operation(op);
0118 
0119     op->ops = &afs_store_acl_operation;
0120     return afs_do_sync_operation(op);
0121 }
0122 
0123 static const struct xattr_handler afs_xattr_afs_acl_handler = {
0124     .name   = "afs.acl",
0125     .get    = afs_xattr_get_acl,
0126     .set    = afs_xattr_set_acl,
0127 };
0128 
0129 static const struct afs_operation_ops yfs_fetch_opaque_acl_operation = {
0130     .issue_yfs_rpc  = yfs_fs_fetch_opaque_acl,
0131     .success    = afs_acl_success,
0132     /* Don't free op->yacl in .put here */
0133 };
0134 
0135 /*
0136  * Get a file's YFS ACL.
0137  */
0138 static int afs_xattr_get_yfs(const struct xattr_handler *handler,
0139                  struct dentry *dentry,
0140                  struct inode *inode, const char *name,
0141                  void *buffer, size_t size)
0142 {
0143     struct afs_operation *op;
0144     struct afs_vnode *vnode = AFS_FS_I(inode);
0145     struct yfs_acl *yacl = NULL;
0146     char buf[16], *data;
0147     int which = 0, dsize, ret = -ENOMEM;
0148 
0149     if (strcmp(name, "acl") == 0)
0150         which = 0;
0151     else if (strcmp(name, "acl_inherited") == 0)
0152         which = 1;
0153     else if (strcmp(name, "acl_num_cleaned") == 0)
0154         which = 2;
0155     else if (strcmp(name, "vol_acl") == 0)
0156         which = 3;
0157     else
0158         return -EOPNOTSUPP;
0159 
0160     yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL);
0161     if (!yacl)
0162         goto error;
0163 
0164     if (which == 0)
0165         yacl->flags |= YFS_ACL_WANT_ACL;
0166     else if (which == 3)
0167         yacl->flags |= YFS_ACL_WANT_VOL_ACL;
0168 
0169     op = afs_alloc_operation(NULL, vnode->volume);
0170     if (IS_ERR(op))
0171         goto error_yacl;
0172 
0173     afs_op_set_vnode(op, 0, vnode);
0174     op->yacl = yacl;
0175     op->ops = &yfs_fetch_opaque_acl_operation;
0176 
0177     afs_begin_vnode_operation(op);
0178     afs_wait_for_operation(op);
0179     ret = afs_put_operation(op);
0180 
0181     if (ret == 0) {
0182         switch (which) {
0183         case 0:
0184             data = yacl->acl->data;
0185             dsize = yacl->acl->size;
0186             break;
0187         case 1:
0188             data = buf;
0189             dsize = scnprintf(buf, sizeof(buf), "%u", yacl->inherit_flag);
0190             break;
0191         case 2:
0192             data = buf;
0193             dsize = scnprintf(buf, sizeof(buf), "%u", yacl->num_cleaned);
0194             break;
0195         case 3:
0196             data = yacl->vol_acl->data;
0197             dsize = yacl->vol_acl->size;
0198             break;
0199         default:
0200             ret = -EOPNOTSUPP;
0201             goto error_yacl;
0202         }
0203 
0204         ret = dsize;
0205         if (size > 0) {
0206             if (dsize <= size)
0207                 memcpy(buffer, data, dsize);
0208             else
0209                 ret = -ERANGE;
0210         }
0211     } else if (ret == -ENOTSUPP) {
0212         ret = -ENODATA;
0213     }
0214 
0215 error_yacl:
0216     yfs_free_opaque_acl(yacl);
0217 error:
0218     return ret;
0219 }
0220 
0221 static const struct afs_operation_ops yfs_store_opaque_acl2_operation = {
0222     .issue_yfs_rpc  = yfs_fs_store_opaque_acl2,
0223     .success    = afs_acl_success,
0224     .put        = afs_acl_put,
0225 };
0226 
0227 /*
0228  * Set a file's YFS ACL.
0229  */
0230 static int afs_xattr_set_yfs(const struct xattr_handler *handler,
0231                  struct user_namespace *mnt_userns,
0232                              struct dentry *dentry,
0233                              struct inode *inode, const char *name,
0234                              const void *buffer, size_t size, int flags)
0235 {
0236     struct afs_operation *op;
0237     struct afs_vnode *vnode = AFS_FS_I(inode);
0238     int ret;
0239 
0240     if (flags == XATTR_CREATE ||
0241         strcmp(name, "acl") != 0)
0242         return -EINVAL;
0243 
0244     op = afs_alloc_operation(NULL, vnode->volume);
0245     if (IS_ERR(op))
0246         return -ENOMEM;
0247 
0248     afs_op_set_vnode(op, 0, vnode);
0249     if (!afs_make_acl(op, buffer, size))
0250         return afs_put_operation(op);
0251 
0252     op->ops = &yfs_store_opaque_acl2_operation;
0253     ret = afs_do_sync_operation(op);
0254     if (ret == -ENOTSUPP)
0255         ret = -ENODATA;
0256     return ret;
0257 }
0258 
0259 static const struct xattr_handler afs_xattr_yfs_handler = {
0260     .prefix = "afs.yfs.",
0261     .get    = afs_xattr_get_yfs,
0262     .set    = afs_xattr_set_yfs,
0263 };
0264 
0265 /*
0266  * Get the name of the cell on which a file resides.
0267  */
0268 static int afs_xattr_get_cell(const struct xattr_handler *handler,
0269                   struct dentry *dentry,
0270                   struct inode *inode, const char *name,
0271                   void *buffer, size_t size)
0272 {
0273     struct afs_vnode *vnode = AFS_FS_I(inode);
0274     struct afs_cell *cell = vnode->volume->cell;
0275     size_t namelen;
0276 
0277     namelen = cell->name_len;
0278     if (size == 0)
0279         return namelen;
0280     if (namelen > size)
0281         return -ERANGE;
0282     memcpy(buffer, cell->name, namelen);
0283     return namelen;
0284 }
0285 
0286 static const struct xattr_handler afs_xattr_afs_cell_handler = {
0287     .name   = "afs.cell",
0288     .get    = afs_xattr_get_cell,
0289 };
0290 
0291 /*
0292  * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of
0293  * hex numbers separated by colons.
0294  */
0295 static int afs_xattr_get_fid(const struct xattr_handler *handler,
0296                  struct dentry *dentry,
0297                  struct inode *inode, const char *name,
0298                  void *buffer, size_t size)
0299 {
0300     struct afs_vnode *vnode = AFS_FS_I(inode);
0301     char text[16 + 1 + 24 + 1 + 8 + 1];
0302     size_t len;
0303 
0304     /* The volume ID is 64-bit, the vnode ID is 96-bit and the
0305      * uniquifier is 32-bit.
0306      */
0307     len = scnprintf(text, sizeof(text), "%llx:", vnode->fid.vid);
0308     if (vnode->fid.vnode_hi)
0309         len += scnprintf(text + len, sizeof(text) - len, "%x%016llx",
0310                 vnode->fid.vnode_hi, vnode->fid.vnode);
0311     else
0312         len += scnprintf(text + len, sizeof(text) - len, "%llx",
0313                  vnode->fid.vnode);
0314     len += scnprintf(text + len, sizeof(text) - len, ":%x",
0315              vnode->fid.unique);
0316 
0317     if (size == 0)
0318         return len;
0319     if (len > size)
0320         return -ERANGE;
0321     memcpy(buffer, text, len);
0322     return len;
0323 }
0324 
0325 static const struct xattr_handler afs_xattr_afs_fid_handler = {
0326     .name   = "afs.fid",
0327     .get    = afs_xattr_get_fid,
0328 };
0329 
0330 /*
0331  * Get the name of the volume on which a file resides.
0332  */
0333 static int afs_xattr_get_volume(const struct xattr_handler *handler,
0334                   struct dentry *dentry,
0335                   struct inode *inode, const char *name,
0336                   void *buffer, size_t size)
0337 {
0338     struct afs_vnode *vnode = AFS_FS_I(inode);
0339     const char *volname = vnode->volume->name;
0340     size_t namelen;
0341 
0342     namelen = strlen(volname);
0343     if (size == 0)
0344         return namelen;
0345     if (namelen > size)
0346         return -ERANGE;
0347     memcpy(buffer, volname, namelen);
0348     return namelen;
0349 }
0350 
0351 static const struct xattr_handler afs_xattr_afs_volume_handler = {
0352     .name   = "afs.volume",
0353     .get    = afs_xattr_get_volume,
0354 };
0355 
0356 const struct xattr_handler *afs_xattr_handlers[] = {
0357     &afs_xattr_afs_acl_handler,
0358     &afs_xattr_afs_cell_handler,
0359     &afs_xattr_afs_fid_handler,
0360     &afs_xattr_afs_volume_handler,
0361     &afs_xattr_yfs_handler,     /* afs.yfs. prefix */
0362     NULL
0363 };