afs: implement acl setting
authorJoe Gorse <jhgorse@gmail.com>
Thu, 25 Apr 2019 13:26:52 +0000 (14:26 +0100)
committerDavid Howells <dhowells@redhat.com>
Tue, 7 May 2019 15:48:44 +0000 (16:48 +0100)
Implements the setting of ACLs in AFS by means of setting the
afs.acl extended attribute on the file.

Signed-off-by: Joe Gorse <jhgorse@gmail.com>
Signed-off-by: David Howells <dhowells@redhat.com>
fs/afs/afs_fs.h
fs/afs/fsclient.c
fs/afs/internal.h
fs/afs/xattr.c
include/trace/events/afs.h

index 4df1f1eec0abbc53ccdaa9bbf0390ec28a0cd0b9..18a54ca422f8f21e681740e8b82850240adfd044 100644 (file)
@@ -20,6 +20,7 @@ enum AFS_FS_Operations {
        FSFETCHACL              = 131,  /* AFS Fetch file ACL */
        FSFETCHSTATUS           = 132,  /* AFS Fetch file status */
        FSSTOREDATA             = 133,  /* AFS Store file data */
+       FSSTOREACL              = 134,  /* AFS Store file ACL */
        FSSTORESTATUS           = 135,  /* AFS Store file status */
        FSREMOVEFILE            = 136,  /* AFS Remove a file */
        FSCREATEFILE            = 137,  /* AFS Create a file */
index 283f486c59f42ec7b15135a645887e664b6cc5dc..7f1722b9e432b94ae8495b31e6cda2267bdcbe68 100644 (file)
@@ -836,9 +836,10 @@ int afs_fs_create(struct afs_fs_cursor *fc,
 }
 
 /*
- * deliver reply data to an FS.RemoveFile or FS.RemoveDir
+ * Deliver reply data to any operation that returns file status and volume
+ * sync.
  */
-static int afs_deliver_fs_remove(struct afs_call *call)
+static int afs_deliver_fs_status_and_vol(struct afs_call *call)
 {
        struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
@@ -868,14 +869,14 @@ static int afs_deliver_fs_remove(struct afs_call *call)
 static const struct afs_call_type afs_RXFSRemoveFile = {
        .name           = "FS.RemoveFile",
        .op             = afs_FS_RemoveFile,
-       .deliver        = afs_deliver_fs_remove,
+       .deliver        = afs_deliver_fs_status_and_vol,
        .destructor     = afs_flat_call_destructor,
 };
 
 static const struct afs_call_type afs_RXFSRemoveDir = {
        .name           = "FS.RemoveDir",
        .op             = afs_FS_RemoveDir,
-       .deliver        = afs_deliver_fs_remove,
+       .deliver        = afs_deliver_fs_status_and_vol,
        .destructor     = afs_flat_call_destructor,
 };
 
@@ -2513,3 +2514,55 @@ struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc)
        afs_make_call(&fc->ac, call, GFP_KERNEL);
        return (struct afs_acl *)afs_wait_for_call_to_complete(call, &fc->ac);
 }
+
+/*
+ * FS.StoreACL operation type
+ */
+static const struct afs_call_type afs_RXFSStoreACL = {
+       .name           = "FS.StoreACL",
+       .op             = afs_FS_StoreACL,
+       .deliver        = afs_deliver_fs_status_and_vol,
+       .destructor     = afs_flat_call_destructor,
+};
+
+/*
+ * Fetch the ACL for a file.
+ */
+int afs_fs_store_acl(struct afs_fs_cursor *fc, const struct afs_acl *acl)
+{
+       struct afs_vnode *vnode = fc->vnode;
+       struct afs_call *call;
+       struct afs_net *net = afs_v2net(vnode);
+       size_t size;
+       __be32 *bp;
+
+       _enter(",%x,{%llx:%llu},,",
+              key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
+
+       size = round_up(acl->size, 4);
+       call = afs_alloc_flat_call(net, &afs_RXFSStoreACL,
+                                  5 * 4 + size, (21 + 6) * 4);
+       if (!call) {
+               fc->ac.error = -ENOMEM;
+               return -ENOMEM;
+       }
+
+       call->key = fc->key;
+       call->reply[0] = vnode;
+       call->reply[2] = NULL; /* volsync */
+
+       /* marshall the parameters */
+       bp = call->request;
+       bp[0] = htonl(FSSTOREACL);
+       bp[1] = htonl(vnode->fid.vid);
+       bp[2] = htonl(vnode->fid.vnode);
+       bp[3] = htonl(vnode->fid.unique);
+       bp[4] = htonl(acl->size);
+       memcpy(&bp[5], acl->data, acl->size);
+       if (acl->size != size)
+               memset((void *)&bp[5] + acl->size, 0, size - acl->size);
+
+       trace_afs_make_fs_call(call, &vnode->fid);
+       afs_make_call(&fc->ac, call, GFP_KERNEL);
+       return afs_wait_for_call_to_complete(call, &fc->ac);
+}
index 683b802c20ea43dd8240da880164de23410f63cd..5269824244c631f0bb905401053870c36ad4babc 100644 (file)
@@ -983,6 +983,7 @@ struct afs_acl {
 };
 
 extern struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *);
+extern int afs_fs_store_acl(struct afs_fs_cursor *, const struct afs_acl *);
 
 /*
  * fs_probe.c
index b7d3d714d8ff0a1a11c527df9d6218ed5c7305eb..31db360947a6b6168c8204eb9bcfb898f8353ddb 100644 (file)
@@ -80,9 +80,57 @@ static int afs_xattr_get_acl(const struct xattr_handler *handler,
        return ret;
 }
 
+/*
+ * Set a file's AFS3 ACL.
+ */
+static int afs_xattr_set_acl(const struct xattr_handler *handler,
+                             struct dentry *dentry,
+                             struct inode *inode, const char *name,
+                             const void *buffer, size_t size, int flags)
+{
+       struct afs_fs_cursor fc;
+       struct afs_vnode *vnode = AFS_FS_I(inode);
+       struct afs_acl *acl = NULL;
+       struct key *key;
+       int ret;
+
+       if (flags == XATTR_CREATE)
+               return -EINVAL;
+
+       key = afs_request_key(vnode->volume->cell);
+       if (IS_ERR(key))
+               return PTR_ERR(key);
+
+       acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
+       if (!acl) {
+               key_put(key);
+               return -ENOMEM;
+       }
+
+       acl->size = size;
+       memcpy(acl->data, buffer, size);
+
+       ret = -ERESTARTSYS;
+       if (afs_begin_vnode_operation(&fc, vnode, key)) {
+               while (afs_select_fileserver(&fc)) {
+                       fc.cb_break = afs_calc_vnode_cb_break(vnode);
+                       afs_fs_store_acl(&fc, acl);
+               }
+
+               afs_check_for_remote_deletion(&fc, fc.vnode);
+               afs_vnode_commit_status(&fc, vnode, fc.cb_break);
+               ret = afs_end_vnode_operation(&fc);
+       }
+
+       kfree(acl);
+       key_put(key);
+       return ret;
+}
+
 static const struct xattr_handler afs_xattr_afs_acl_handler = {
-       .name   = "afs.acl",
-       .get    = afs_xattr_get_acl,
+       .name   = "afs.acl",
+       .get    = afs_xattr_get_acl,
+       .set    = afs_xattr_set_acl,
 };
 
 /*
index 25c2e089c6eaf1a4321e5443d12f890441c50879..562f854ac4bf64880c40dd27214b7cda39e9a0d3 100644 (file)
@@ -36,6 +36,7 @@ enum afs_fs_operation {
        afs_FS_FetchACL                 = 131,  /* AFS Fetch file ACL */
        afs_FS_FetchStatus              = 132,  /* AFS Fetch file status */
        afs_FS_StoreData                = 133,  /* AFS Store file data */
+       afs_FS_StoreACL                 = 134,  /* AFS Store file ACL */
        afs_FS_StoreStatus              = 135,  /* AFS Store file status */
        afs_FS_RemoveFile               = 136,  /* AFS Remove a file */
        afs_FS_CreateFile               = 137,  /* AFS Create a file */