aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-04-25 09:26:52 -0400
committerDavid Howells <dhowells@redhat.com>2019-05-07 11:48:44 -0400
commit260f082bae6dcf70aeae2cc3e24aecb55bdb1c99 (patch)
tree128a02382c0b98b01f8c1fce97347a41a2507e40 /fs/afs
parenta2f611a3dc317d8ea1c98ad6c54b911cf7f93193 (diff)
afs: Get an AFS3 ACL as an xattr
Implement an xattr on AFS files called "afs.acl" that retrieves a file's ACL. It returns the raw AFS3 ACL from the result of calling FS.FetchACL, leaving any interpretation to userspace. Note that whilst YFS servers will respond to FS.FetchACL, this will render a more-advanced YFS ACL down. Use "afs.yfs.acl" instead for that. Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/afs')
-rw-r--r--fs/afs/afs_fs.h1
-rw-r--r--fs/afs/fsclient.c122
-rw-r--r--fs/afs/internal.h7
-rw-r--r--fs/afs/xattr.c53
4 files changed, 183 insertions, 0 deletions
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h
index ddfa88a7a9c0..4df1f1eec0ab 100644
--- a/fs/afs/afs_fs.h
+++ b/fs/afs/afs_fs.h
@@ -17,6 +17,7 @@
17 17
18enum AFS_FS_Operations { 18enum AFS_FS_Operations {
19 FSFETCHDATA = 130, /* AFS Fetch file data */ 19 FSFETCHDATA = 130, /* AFS Fetch file data */
20 FSFETCHACL = 131, /* AFS Fetch file ACL */
20 FSFETCHSTATUS = 132, /* AFS Fetch file status */ 21 FSFETCHSTATUS = 132, /* AFS Fetch file status */
21 FSSTOREDATA = 133, /* AFS Store file data */ 22 FSSTOREDATA = 133, /* AFS Store file data */
22 FSSTORESTATUS = 135, /* AFS Store file status */ 23 FSSTORESTATUS = 135, /* AFS Store file status */
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index 9b73a57aa5cb..283f486c59f4 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -2391,3 +2391,125 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
2391 afs_make_call(&fc->ac, call, GFP_NOFS); 2391 afs_make_call(&fc->ac, call, GFP_NOFS);
2392 return afs_wait_for_call_to_complete(call, &fc->ac); 2392 return afs_wait_for_call_to_complete(call, &fc->ac);
2393} 2393}
2394
2395/*
2396 * deliver reply data to an FS.FetchACL
2397 */
2398static int afs_deliver_fs_fetch_acl(struct afs_call *call)
2399{
2400 struct afs_vnode *vnode = call->reply[1];
2401 struct afs_acl *acl;
2402 const __be32 *bp;
2403 unsigned int size;
2404 int ret;
2405
2406 _enter("{%u}", call->unmarshall);
2407
2408 switch (call->unmarshall) {
2409 case 0:
2410 afs_extract_to_tmp(call);
2411 call->unmarshall++;
2412
2413 /* extract the returned data length */
2414 case 1:
2415 ret = afs_extract_data(call, true);
2416 if (ret < 0)
2417 return ret;
2418
2419 size = call->count2 = ntohl(call->tmp);
2420 size = round_up(size, 4);
2421
2422 acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
2423 if (!acl)
2424 return -ENOMEM;
2425 call->reply[0] = acl;
2426 acl->size = call->count2;
2427 afs_extract_begin(call, acl->data, size);
2428 call->unmarshall++;
2429
2430 /* extract the returned data */
2431 case 2:
2432 ret = afs_extract_data(call, true);
2433 if (ret < 0)
2434 return ret;
2435
2436 afs_extract_to_buf(call, (21 + 6) * 4);
2437 call->unmarshall++;
2438
2439 /* extract the metadata */
2440 case 3:
2441 ret = afs_extract_data(call, false);
2442 if (ret < 0)
2443 return ret;
2444
2445 bp = call->buffer;
2446 ret = afs_decode_status(call, &bp, &vnode->status, vnode,
2447 &vnode->status.data_version, NULL);
2448 if (ret < 0)
2449 return ret;
2450 xdr_decode_AFSVolSync(&bp, call->reply[2]);
2451
2452 call->unmarshall++;
2453
2454 case 4:
2455 break;
2456 }
2457
2458 _leave(" = 0 [done]");
2459 return 0;
2460}
2461
2462static void afs_destroy_fs_fetch_acl(struct afs_call *call)
2463{
2464 kfree(call->reply[0]);
2465 afs_flat_call_destructor(call);
2466}
2467
2468/*
2469 * FS.FetchACL operation type
2470 */
2471static const struct afs_call_type afs_RXFSFetchACL = {
2472 .name = "FS.FetchACL",
2473 .op = afs_FS_FetchACL,
2474 .deliver = afs_deliver_fs_fetch_acl,
2475 .destructor = afs_destroy_fs_fetch_acl,
2476};
2477
2478/*
2479 * Fetch the ACL for a file.
2480 */
2481struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc)
2482{
2483 struct afs_vnode *vnode = fc->vnode;
2484 struct afs_call *call;
2485 struct afs_net *net = afs_v2net(vnode);
2486 __be32 *bp;
2487
2488 _enter(",%x,{%llx:%llu},,",
2489 key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
2490
2491 call = afs_alloc_flat_call(net, &afs_RXFSFetchACL, 16, (21 + 6) * 4);
2492 if (!call) {
2493 fc->ac.error = -ENOMEM;
2494 return ERR_PTR(-ENOMEM);
2495 }
2496
2497 call->key = fc->key;
2498 call->reply[0] = NULL;
2499 call->reply[1] = vnode;
2500 call->reply[2] = NULL; /* volsync */
2501 call->ret_reply0 = true;
2502
2503 /* marshall the parameters */
2504 bp = call->request;
2505 bp[0] = htonl(FSFETCHACL);
2506 bp[1] = htonl(vnode->fid.vid);
2507 bp[2] = htonl(vnode->fid.vnode);
2508 bp[3] = htonl(vnode->fid.unique);
2509
2510 call->cb_break = fc->cb_break;
2511 afs_use_fs_server(call, fc->cbi);
2512 trace_afs_make_fs_call(call, &vnode->fid);
2513 afs_make_call(&fc->ac, call, GFP_KERNEL);
2514 return (struct afs_acl *)afs_wait_for_call_to_complete(call, &fc->ac);
2515}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 585a5952f608..683b802c20ea 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -977,6 +977,13 @@ extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *,
977 struct afs_fid *, struct afs_file_status *, 977 struct afs_fid *, struct afs_file_status *,
978 struct afs_callback *, struct afs_volsync *); 978 struct afs_callback *, struct afs_volsync *);
979 979
980struct afs_acl {
981 u32 size;
982 u8 data[];
983};
984
985extern struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *);
986
980/* 987/*
981 * fs_probe.c 988 * fs_probe.c
982 */ 989 */
diff --git a/fs/afs/xattr.c b/fs/afs/xattr.c
index e729ee3d4b02..b7d3d714d8ff 100644
--- a/fs/afs/xattr.c
+++ b/fs/afs/xattr.c
@@ -16,6 +16,7 @@
16#include "internal.h" 16#include "internal.h"
17 17
18static const char afs_xattr_list[] = 18static const char afs_xattr_list[] =
19 "afs.acl\0"
19 "afs.cell\0" 20 "afs.cell\0"
20 "afs.fid\0" 21 "afs.fid\0"
21 "afs.volume"; 22 "afs.volume";
@@ -34,6 +35,57 @@ ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size)
34} 35}
35 36
36/* 37/*
38 * Get a file's ACL.
39 */
40static int afs_xattr_get_acl(const struct xattr_handler *handler,
41 struct dentry *dentry,
42 struct inode *inode, const char *name,
43 void *buffer, size_t size)
44{
45 struct afs_fs_cursor fc;
46 struct afs_vnode *vnode = AFS_FS_I(inode);
47 struct afs_acl *acl = NULL;
48 struct key *key;
49 int ret;
50
51 key = afs_request_key(vnode->volume->cell);
52 if (IS_ERR(key))
53 return PTR_ERR(key);
54
55 ret = -ERESTARTSYS;
56 if (afs_begin_vnode_operation(&fc, vnode, key)) {
57 while (afs_select_fileserver(&fc)) {
58 fc.cb_break = afs_calc_vnode_cb_break(vnode);
59 acl = afs_fs_fetch_acl(&fc);
60 }
61
62 afs_check_for_remote_deletion(&fc, fc.vnode);
63 afs_vnode_commit_status(&fc, vnode, fc.cb_break);
64 ret = afs_end_vnode_operation(&fc);
65 }
66
67 if (ret == 0) {
68 ret = acl->size;
69 if (size > 0) {
70 ret = -ERANGE;
71 if (acl->size > size)
72 return -ERANGE;
73 memcpy(buffer, acl->data, acl->size);
74 ret = acl->size;
75 }
76 kfree(acl);
77 }
78
79 key_put(key);
80 return ret;
81}
82
83static const struct xattr_handler afs_xattr_afs_acl_handler = {
84 .name = "afs.acl",
85 .get = afs_xattr_get_acl,
86};
87
88/*
37 * Get the name of the cell on which a file resides. 89 * Get the name of the cell on which a file resides.
38 */ 90 */
39static int afs_xattr_get_cell(const struct xattr_handler *handler, 91static int afs_xattr_get_cell(const struct xattr_handler *handler,
@@ -123,6 +175,7 @@ static const struct xattr_handler afs_xattr_afs_volume_handler = {
123}; 175};
124 176
125const struct xattr_handler *afs_xattr_handlers[] = { 177const struct xattr_handler *afs_xattr_handlers[] = {
178 &afs_xattr_afs_acl_handler,
126 &afs_xattr_afs_cell_handler, 179 &afs_xattr_afs_cell_handler,
127 &afs_xattr_afs_fid_handler, 180 &afs_xattr_afs_fid_handler,
128 &afs_xattr_afs_volume_handler, 181 &afs_xattr_afs_volume_handler,