]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
afs: Get YFS ACLs and information through xattrs
authorDavid Howells <dhowells@redhat.com>
Tue, 30 Apr 2019 17:30:21 +0000 (18:30 +0100)
committerDavid Howells <dhowells@redhat.com>
Tue, 7 May 2019 15:48:44 +0000 (16:48 +0100)
The YFS/AuriStor variant of AFS provides more capable ACLs and provides
per-volume ACLs and per-file ACLs as well as per-directory ACLs.  It also
provides some extra information that can be retrieved through four ACLs:

 (1) afs.yfs.acl

     The YFS file ACL (not the same format as afs.acl).

 (2) afs.yfs.vol_acl

     The YFS volume ACL.

 (3) afs.yfs.acl_inherited

     "1" if a file's ACL is inherited from its parent directory, "0"
     otherwise.

 (4) afs.yfs.acl_num_cleaned

     The number of of ACEs removed from the ACL by the server because the
     PT entries were removed from the PTS database (ie. the subject is no
     longer known).

Signed-off-by: David Howells <dhowells@redhat.com>
fs/afs/internal.h
fs/afs/protocol_yfs.h
fs/afs/xattr.c
fs/afs/yfsclient.c

index 5269824244c631f0bb905401053870c36ad4babc..b800b4e286d378d3f5ff7a1f1cbe84f42faff4b1 100644 (file)
@@ -1371,6 +1371,19 @@ extern int yfs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *,
                                     struct afs_callback *, unsigned int,
                                     struct afs_volsync *);
 
+struct yfs_acl {
+       struct afs_acl  *acl;           /* Dir/file/symlink ACL */
+       struct afs_acl  *vol_acl;       /* Whole volume ACL */
+       u32             inherit_flag;   /* True if ACL is inherited from parent dir */
+       u32             num_cleaned;    /* Number of ACEs removed due to subject removal */
+       unsigned int    flags;
+#define YFS_ACL_WANT_ACL       0x01    /* Set if caller wants ->acl */
+#define YFS_ACL_WANT_VOL_ACL   0x02    /* Set if caller wants ->vol_acl */
+};
+
+extern void yfs_free_opaque_acl(struct yfs_acl *);
+extern struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *, unsigned int);
+
 /*
  * Miscellaneous inline functions.
  */
index d443e2bfa0946e5845ea65af121a5e34ea3f2270..915b9d10cdf33a0dbd65dcc0e40bb6743f320ae6 100644 (file)
@@ -31,9 +31,9 @@ enum YFS_CM_Operations {
 };
 
 enum YFS_FS_Operations {
-       YFSFETCHACL             = 64131, /* YFS Fetch file ACL */
+       YFSFETCHACL             = 64131, /* YFS Fetch file AFS3 ACL */
        YFSFETCHSTATUS          = 64132, /* YFS Fetch file status */
-       YFSSTOREACL             = 64134, /* YFS Store file ACL */
+       YFSSTOREACL             = 64134, /* YFS Store file AFS3 ACL */
        YFSSTORESTATUS          = 64135, /* YFS Store file status */
        YFSREMOVEFILE           = 64136, /* YFS Remove a file */
        YFSCREATEFILE           = 64137, /* YFS Create a file */
@@ -49,7 +49,7 @@ enum YFS_FS_Operations {
        YFSRELEASELOCK          = 64158, /* YFS Release a file lock */
        YFSLOOKUP               = 64161, /* YFS lookup file in directory */
        YFSFLUSHCPS             = 64165,
-       YFSFETCHOPAQUEACL       = 64168,
+       YFSFETCHOPAQUEACL       = 64168, /* YFS Fetch file YFS ACL */
        YFSWHOAMI               = 64170,
        YFSREMOVEACL            = 64171,
        YFSREMOVEFILE2          = 64173,
index 31db360947a6b6168c8204eb9bcfb898f8353ddb..a5c82b0ad5397565856eda7327d04cd3fa880425 100644 (file)
@@ -19,7 +19,11 @@ static const char afs_xattr_list[] =
        "afs.acl\0"
        "afs.cell\0"
        "afs.fid\0"
-       "afs.volume";
+       "afs.volume\0"
+       "afs.yfs.acl\0"
+       "afs.yfs.acl_inherited\0"
+       "afs.yfs.acl_num_cleaned\0"
+       "afs.yfs.vol_acl";
 
 /*
  * Retrieve a list of the supported xattrs.
@@ -133,6 +137,100 @@ static const struct xattr_handler afs_xattr_afs_acl_handler = {
        .set    = afs_xattr_set_acl,
 };
 
+/*
+ * Get a file's YFS ACL.
+ */
+static int afs_xattr_get_yfs(const struct xattr_handler *handler,
+                            struct dentry *dentry,
+                            struct inode *inode, const char *name,
+                            void *buffer, size_t size)
+{
+       struct afs_fs_cursor fc;
+       struct afs_vnode *vnode = AFS_FS_I(inode);
+       struct yfs_acl *yacl = NULL;
+       struct key *key;
+       unsigned int flags = 0;
+       char buf[16], *data;
+       int which = 0, dsize, ret;
+
+       if (strcmp(name, "acl") == 0)
+               which = 0;
+       else if (strcmp(name, "acl_inherited") == 0)
+               which = 1;
+       else if (strcmp(name, "acl_num_cleaned") == 0)
+               which = 2;
+       else if (strcmp(name, "vol_acl") == 0)
+               which = 3;
+       else
+               return -EOPNOTSUPP;
+
+       if (which == 0)
+               flags |= YFS_ACL_WANT_ACL;
+       else if (which == 3)
+               flags |= YFS_ACL_WANT_VOL_ACL;
+
+       key = afs_request_key(vnode->volume->cell);
+       if (IS_ERR(key))
+               return PTR_ERR(key);
+
+       ret = -ERESTARTSYS;
+       if (afs_begin_vnode_operation(&fc, vnode, key)) {
+               while (afs_select_fileserver(&fc)) {
+                       fc.cb_break = afs_calc_vnode_cb_break(vnode);
+                       yacl = yfs_fs_fetch_opaque_acl(&fc, flags);
+               }
+
+               afs_check_for_remote_deletion(&fc, fc.vnode);
+               afs_vnode_commit_status(&fc, vnode, fc.cb_break);
+               ret = afs_end_vnode_operation(&fc);
+       }
+
+       if (ret == 0) {
+               switch (which) {
+               case 0:
+                       data = yacl->acl->data;
+                       dsize = yacl->acl->size;
+                       break;
+               case 1:
+                       data = buf;
+                       dsize = snprintf(buf, sizeof(buf), "%u",
+                                        yacl->inherit_flag);
+                       break;
+               case 2:
+                       data = buf;
+                       dsize = snprintf(buf, sizeof(buf), "%u",
+                                        yacl->num_cleaned);
+                       break;
+               case 3:
+                       data = yacl->vol_acl->data;
+                       dsize = yacl->vol_acl->size;
+                       break;
+               default:
+                       ret = -EOPNOTSUPP;
+                       goto out;
+               }
+
+               ret = dsize;
+               if (size > 0) {
+                       if (dsize > size) {
+                               ret = -ERANGE;
+                               goto out;
+                       }
+                       memcpy(buffer, data, dsize);
+               }
+       }
+
+out:
+       yfs_free_opaque_acl(yacl);
+       key_put(key);
+       return ret;
+}
+
+static const struct xattr_handler afs_xattr_yfs_handler = {
+       .prefix = "afs.yfs.",
+       .get    = afs_xattr_get_yfs,
+};
+
 /*
  * Get the name of the cell on which a file resides.
  */
@@ -227,5 +325,6 @@ const struct xattr_handler *afs_xattr_handlers[] = {
        &afs_xattr_afs_cell_handler,
        &afs_xattr_afs_fid_handler,
        &afs_xattr_afs_volume_handler,
+       &afs_xattr_yfs_handler,         /* afs.yfs. prefix */
        NULL
 };
index 055840aa07f63ba56a8c798e13bb0beca343820e..13eafa764d71c00212edd922f545b9e7d87d0941 100644 (file)
@@ -2204,3 +2204,191 @@ int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
        afs_make_call(&fc->ac, call, GFP_NOFS);
        return afs_wait_for_call_to_complete(call, &fc->ac);
 }
+
+/*
+ * Deliver reply data to an YFS.FetchOpaqueACL.
+ */
+static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call)
+{
+       struct afs_volsync *volsync = call->reply[2];
+       struct afs_vnode *vnode = call->reply[1];
+       struct yfs_acl *yacl =  call->reply[0];
+       struct afs_acl *acl;
+       const __be32 *bp;
+       unsigned int size;
+       int ret;
+
+       _enter("{%u}", call->unmarshall);
+
+       switch (call->unmarshall) {
+       case 0:
+               afs_extract_to_tmp(call);
+               call->unmarshall++;
+
+               /* Extract the file ACL length */
+       case 1:
+               ret = afs_extract_data(call, true);
+               if (ret < 0)
+                       return ret;
+
+               size = call->count2 = ntohl(call->tmp);
+               size = round_up(size, 4);
+
+               if (yacl->flags & YFS_ACL_WANT_ACL) {
+                       acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
+                       if (!acl)
+                               return -ENOMEM;
+                       yacl->acl = acl;
+                       acl->size = call->count2;
+                       afs_extract_begin(call, acl->data, size);
+               } else {
+                       iov_iter_discard(&call->iter, READ, size);
+               }
+               call->unmarshall++;
+
+               /* Extract the file ACL */
+       case 2:
+               ret = afs_extract_data(call, true);
+               if (ret < 0)
+                       return ret;
+
+               afs_extract_to_tmp(call);
+               call->unmarshall++;
+
+               /* Extract the volume ACL length */
+       case 3:
+               ret = afs_extract_data(call, true);
+               if (ret < 0)
+                       return ret;
+
+               size = call->count2 = ntohl(call->tmp);
+               size = round_up(size, 4);
+
+               if (yacl->flags & YFS_ACL_WANT_VOL_ACL) {
+                       acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
+                       if (!acl)
+                               return -ENOMEM;
+                       yacl->vol_acl = acl;
+                       acl->size = call->count2;
+                       afs_extract_begin(call, acl->data, size);
+               } else {
+                       iov_iter_discard(&call->iter, READ, size);
+               }
+               call->unmarshall++;
+
+               /* Extract the volume ACL */
+       case 4:
+               ret = afs_extract_data(call, true);
+               if (ret < 0)
+                       return ret;
+
+               afs_extract_to_buf(call,
+                                  sizeof(__be32) * 2 +
+                                  sizeof(struct yfs_xdr_YFSFetchStatus) +
+                                  sizeof(struct yfs_xdr_YFSVolSync));
+               call->unmarshall++;
+
+               /* extract the metadata */
+       case 5:
+               ret = afs_extract_data(call, false);
+               if (ret < 0)
+                       return ret;
+
+               bp = call->buffer;
+               yacl->inherit_flag = ntohl(*bp++);
+               yacl->num_cleaned = ntohl(*bp++);
+               ret = yfs_decode_status(call, &bp, &vnode->status, vnode,
+                                       &call->expected_version, NULL);
+               if (ret < 0)
+                       return ret;
+               xdr_decode_YFSVolSync(&bp, volsync);
+
+               call->unmarshall++;
+
+       case 6:
+               break;
+       }
+
+       _leave(" = 0 [done]");
+       return 0;
+}
+
+void yfs_free_opaque_acl(struct yfs_acl *yacl)
+{
+       if (yacl) {
+               kfree(yacl->acl);
+               kfree(yacl->vol_acl);
+               kfree(yacl);
+       }
+}
+
+static void yfs_destroy_fs_fetch_opaque_acl(struct afs_call *call)
+{
+       yfs_free_opaque_acl(call->reply[0]);
+       afs_flat_call_destructor(call);
+}
+
+/*
+ * YFS.FetchOpaqueACL operation type
+ */
+static const struct afs_call_type yfs_RXYFSFetchOpaqueACL = {
+       .name           = "YFS.FetchOpaqueACL",
+       .op             = yfs_FS_FetchOpaqueACL,
+       .deliver        = yfs_deliver_fs_fetch_opaque_acl,
+       .destructor     = yfs_destroy_fs_fetch_opaque_acl,
+};
+
+/*
+ * Fetch the YFS advanced ACLs for a file.
+ */
+struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *fc,
+                                       unsigned int flags)
+{
+       struct afs_vnode *vnode = fc->vnode;
+       struct afs_call *call;
+       struct yfs_acl *yacl;
+       struct afs_net *net = afs_v2net(vnode);
+       __be32 *bp;
+
+       _enter(",%x,{%llx:%llu},,",
+              key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
+
+       call = afs_alloc_flat_call(net, &yfs_RXYFSFetchOpaqueACL,
+                                  sizeof(__be32) * 2 +
+                                  sizeof(struct yfs_xdr_YFSFid),
+                                  sizeof(__be32) * 2 +
+                                  sizeof(struct yfs_xdr_YFSFetchStatus) +
+                                  sizeof(struct yfs_xdr_YFSVolSync));
+       if (!call)
+               goto nomem;
+
+       yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL);
+       if (!yacl)
+               goto nomem_call;
+
+       yacl->flags = flags;
+       call->key = fc->key;
+       call->reply[0] = yacl;
+       call->reply[1] = vnode;
+       call->reply[2] = NULL; /* volsync */
+       call->ret_reply0 = true;
+
+       /* marshall the parameters */
+       bp = call->request;
+       bp = xdr_encode_u32(bp, YFSFETCHOPAQUEACL);
+       bp = xdr_encode_u32(bp, 0); /* RPC flags */
+       bp = xdr_encode_YFSFid(bp, &vnode->fid);
+       yfs_check_req(call, bp);
+
+       call->cb_break = fc->cb_break;
+       afs_use_fs_server(call, fc->cbi);
+       trace_afs_make_fs_call(call, &vnode->fid);
+       afs_make_call(&fc->ac, call, GFP_KERNEL);
+       return (struct yfs_acl *)afs_wait_for_call_to_complete(call, &fc->ac);
+
+nomem_call:
+       afs_put_call(call);
+nomem:
+       fc->ac.error = -ENOMEM;
+       return ERR_PTR(-ENOMEM);
+}