diff options
| author | David Howells <dhowells@redhat.com> | 2019-04-25 09:26:52 -0400 |
|---|---|---|
| committer | David Howells <dhowells@redhat.com> | 2019-05-07 11:48:44 -0400 |
| commit | 260f082bae6dcf70aeae2cc3e24aecb55bdb1c99 (patch) | |
| tree | 128a02382c0b98b01f8c1fce97347a41a2507e40 | |
| parent | a2f611a3dc317d8ea1c98ad6c54b911cf7f93193 (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>
| -rw-r--r-- | fs/afs/afs_fs.h | 1 | ||||
| -rw-r--r-- | fs/afs/fsclient.c | 122 | ||||
| -rw-r--r-- | fs/afs/internal.h | 7 | ||||
| -rw-r--r-- | fs/afs/xattr.c | 53 | ||||
| -rw-r--r-- | include/trace/events/afs.h | 1 |
5 files changed, 184 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 | ||
| 18 | enum AFS_FS_Operations { | 18 | enum 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 | */ | ||
| 2398 | static 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 | |||
| 2462 | static 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 | */ | ||
| 2471 | static 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 | */ | ||
| 2481 | struct 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 | ||
| 980 | struct afs_acl { | ||
| 981 | u32 size; | ||
| 982 | u8 data[]; | ||
| 983 | }; | ||
| 984 | |||
| 985 | extern 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 | ||
| 18 | static const char afs_xattr_list[] = | 18 | static 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 | */ | ||
| 40 | static 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 | |||
| 83 | static 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 | */ |
| 39 | static int afs_xattr_get_cell(const struct xattr_handler *handler, | 91 | static 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 | ||
| 125 | const struct xattr_handler *afs_xattr_handlers[] = { | 177 | const 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, |
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h index f1373c29bf7d..25c2e089c6ea 100644 --- a/include/trace/events/afs.h +++ b/include/trace/events/afs.h | |||
| @@ -33,6 +33,7 @@ enum afs_call_trace { | |||
| 33 | 33 | ||
| 34 | enum afs_fs_operation { | 34 | enum afs_fs_operation { |
| 35 | afs_FS_FetchData = 130, /* AFS Fetch file data */ | 35 | afs_FS_FetchData = 130, /* AFS Fetch file data */ |
| 36 | afs_FS_FetchACL = 131, /* AFS Fetch file ACL */ | ||
| 36 | afs_FS_FetchStatus = 132, /* AFS Fetch file status */ | 37 | afs_FS_FetchStatus = 132, /* AFS Fetch file status */ |
| 37 | afs_FS_StoreData = 133, /* AFS Store file data */ | 38 | afs_FS_StoreData = 133, /* AFS Store file data */ |
| 38 | afs_FS_StoreStatus = 135, /* AFS Store file status */ | 39 | afs_FS_StoreStatus = 135, /* AFS Store file status */ |
