afs: Implement YFS ACL setting
authorDavid Howells <dhowells@redhat.com>
Wed, 1 May 2019 13:05:27 +0000 (14:05 +0100)
committerDavid Howells <dhowells@redhat.com>
Tue, 7 May 2019 15:48:44 +0000 (16:48 +0100)
Implement the setting of YFS ACLs in AFS through the interface of setting
the afs.yfs.acl extended attribute on the file.

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

index b800b4e..b3cd6e8 100644 (file)
@@ -1383,6 +1383,7 @@ struct yfs_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);
+extern int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *, const struct afs_acl *);
 
 /*
  * Miscellaneous inline functions.
index a5c82b0..c81f850 100644 (file)
@@ -226,9 +226,58 @@ out:
        return ret;
 }
 
+/*
+ * Set a file's YFS ACL.
+ */
+static int afs_xattr_set_yfs(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 ||
+           strcmp(name, "acl") != 0)
+               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);
+                       yfs_fs_store_opaque_acl2(&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_yfs_handler = {
        .prefix = "afs.yfs.",
        .get    = afs_xattr_get_yfs,
+       .set    = afs_xattr_set_yfs,
 };
 
 /*
index 13eafa7..6d5af09 100644 (file)
@@ -1768,9 +1768,10 @@ int yfs_fs_get_volume_status(struct afs_fs_cursor *fc,
 }
 
 /*
- * Deliver reply data to an YFS.SetLock, YFS.ExtendLock or YFS.ReleaseLock
+ * Deliver reply data to operations that just return a file status and a volume
+ * sync record.
  */
-static int yfs_deliver_fs_xxxx_lock(struct afs_call *call)
+static int yfs_deliver_status_and_volsync(struct afs_call *call)
 {
        struct afs_vnode *vnode = call->reply[0];
        const __be32 *bp;
@@ -1800,7 +1801,7 @@ static int yfs_deliver_fs_xxxx_lock(struct afs_call *call)
 static const struct afs_call_type yfs_RXYFSSetLock = {
        .name           = "YFS.SetLock",
        .op             = yfs_FS_SetLock,
-       .deliver        = yfs_deliver_fs_xxxx_lock,
+       .deliver        = yfs_deliver_status_and_volsync,
        .done           = afs_lock_op_done,
        .destructor     = afs_flat_call_destructor,
 };
@@ -1811,7 +1812,7 @@ static const struct afs_call_type yfs_RXYFSSetLock = {
 static const struct afs_call_type yfs_RXYFSExtendLock = {
        .name           = "YFS.ExtendLock",
        .op             = yfs_FS_ExtendLock,
-       .deliver        = yfs_deliver_fs_xxxx_lock,
+       .deliver        = yfs_deliver_status_and_volsync,
        .done           = afs_lock_op_done,
        .destructor     = afs_flat_call_destructor,
 };
@@ -1822,7 +1823,7 @@ static const struct afs_call_type yfs_RXYFSExtendLock = {
 static const struct afs_call_type yfs_RXYFSReleaseLock = {
        .name           = "YFS.ReleaseLock",
        .op             = yfs_FS_ReleaseLock,
-       .deliver        = yfs_deliver_fs_xxxx_lock,
+       .deliver        = yfs_deliver_status_and_volsync,
        .destructor     = afs_flat_call_destructor,
 };
 
@@ -2392,3 +2393,59 @@ nomem:
        fc->ac.error = -ENOMEM;
        return ERR_PTR(-ENOMEM);
 }
+
+/*
+ * YFS.StoreOpaqueACL2 operation type
+ */
+static const struct afs_call_type yfs_RXYFSStoreOpaqueACL2 = {
+       .name           = "YFS.StoreOpaqueACL2",
+       .op             = yfs_FS_StoreOpaqueACL2,
+       .deliver        = yfs_deliver_status_and_volsync,
+       .destructor     = afs_flat_call_destructor,
+};
+
+/*
+ * Fetch the YFS ACL for a file.
+ */
+int yfs_fs_store_opaque_acl2(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, &yfs_RXYFSStoreStatus,
+                                  sizeof(__be32) * 2 +
+                                  sizeof(struct yfs_xdr_YFSFid) +
+                                  sizeof(__be32) + size,
+                                  sizeof(struct yfs_xdr_YFSFetchStatus) +
+                                  sizeof(struct yfs_xdr_YFSVolSync));
+       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 = xdr_encode_u32(bp, YFSSTOREOPAQUEACL2);
+       bp = xdr_encode_u32(bp, 0); /* RPC flags */
+       bp = xdr_encode_YFSFid(bp, &vnode->fid);
+       bp = xdr_encode_u32(bp, acl->size);
+       memcpy(bp, acl->data, acl->size);
+       if (acl->size != size)
+               memset((void *)bp + acl->size, 0, size - acl->size);
+       yfs_check_req(call, bp);
+
+       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);
+}