diff options
author | David Howells <dhowells@redhat.com> | 2019-05-01 14:05:27 +0100 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2019-05-07 16:48:44 +0100 |
commit | f5e4546347bc847be30b3cf904db5fc874b3c5dc (patch) | |
tree | 5485e81921604b15abcb6f916fcd39baef339f60 /fs/afs | |
parent | ae46578b963f6daa9853791ab4c6ac1d6375937c (diff) | |
download | linux-f5e4546347bc847be30b3cf904db5fc874b3c5dc.tar.bz2 |
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.h | 1 | ||||
-rw-r--r-- | fs/afs/xattr.c | 49 | ||||
-rw-r--r-- | fs/afs/yfsclient.c | 67 |
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); +} |