summaryrefslogtreecommitdiffstats
path: root/fs/afs
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-05-01 14:05:27 +0100
committerDavid Howells <dhowells@redhat.com>2019-05-07 16:48:44 +0100
commitf5e4546347bc847be30b3cf904db5fc874b3c5dc (patch)
tree5485e81921604b15abcb6f916fcd39baef339f60 /fs/afs
parentae46578b963f6daa9853791ab4c6ac1d6375937c (diff)
downloadlinux-f5e4546347bc847be30b3cf904db5fc874b3c5dc.tar.gz
linux-f5e4546347bc847be30b3cf904db5fc874b3c5dc.tar.bz2
linux-f5e4546347bc847be30b3cf904db5fc874b3c5dc.zip
afs: Implement YFS ACL setting
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>
Diffstat (limited to 'fs/afs')
-rw-r--r--fs/afs/internal.h1
-rw-r--r--fs/afs/xattr.c49
-rw-r--r--fs/afs/yfsclient.c67
3 files changed, 112 insertions, 5 deletions
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index b800b4e286d3..b3cd6e8ad59d 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -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.
diff --git a/fs/afs/xattr.c b/fs/afs/xattr.c
index a5c82b0ad539..c81f85003fc7 100644
--- a/fs/afs/xattr.c
+++ b/fs/afs/xattr.c
@@ -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,
};
/*
diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c
index 13eafa764d71..6d5af09e3f19 100644
--- a/fs/afs/yfsclient.c
+++ b/fs/afs/yfsclient.c
@@ -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);
+}