18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* Maintain an RxRPC server socket to do AFS communications through 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <net/sock.h> 128c2ecf20Sopenharmony_ci#include <net/af_rxrpc.h> 138c2ecf20Sopenharmony_ci#include "internal.h" 148c2ecf20Sopenharmony_ci#include "afs_cm.h" 158c2ecf20Sopenharmony_ci#include "protocol_yfs.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistruct workqueue_struct *afs_async_calls; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long); 208c2ecf20Sopenharmony_cistatic void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long); 218c2ecf20Sopenharmony_cistatic void afs_process_async_call(struct work_struct *); 228c2ecf20Sopenharmony_cistatic void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long); 238c2ecf20Sopenharmony_cistatic void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long); 248c2ecf20Sopenharmony_cistatic int afs_deliver_cm_op_id(struct afs_call *); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* asynchronous incoming call initial processing */ 278c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXCMxxxx = { 288c2ecf20Sopenharmony_ci .name = "CB.xxxx", 298c2ecf20Sopenharmony_ci .deliver = afs_deliver_cm_op_id, 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * open an RxRPC socket and bind it to be a server for callback notifications 348c2ecf20Sopenharmony_ci * - the socket is left in blocking mode and non-blocking ops use MSG_DONTWAIT 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ciint afs_open_socket(struct afs_net *net) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct sockaddr_rxrpc srx; 398c2ecf20Sopenharmony_ci struct socket *socket; 408c2ecf20Sopenharmony_ci int ret; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci _enter(""); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci ret = sock_create_kern(net->net, AF_RXRPC, SOCK_DGRAM, PF_INET6, &socket); 458c2ecf20Sopenharmony_ci if (ret < 0) 468c2ecf20Sopenharmony_ci goto error_1; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci socket->sk->sk_allocation = GFP_NOFS; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci /* bind the callback manager's address to make this a server socket */ 518c2ecf20Sopenharmony_ci memset(&srx, 0, sizeof(srx)); 528c2ecf20Sopenharmony_ci srx.srx_family = AF_RXRPC; 538c2ecf20Sopenharmony_ci srx.srx_service = CM_SERVICE; 548c2ecf20Sopenharmony_ci srx.transport_type = SOCK_DGRAM; 558c2ecf20Sopenharmony_ci srx.transport_len = sizeof(srx.transport.sin6); 568c2ecf20Sopenharmony_ci srx.transport.sin6.sin6_family = AF_INET6; 578c2ecf20Sopenharmony_ci srx.transport.sin6.sin6_port = htons(AFS_CM_PORT); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci ret = rxrpc_sock_set_min_security_level(socket->sk, 608c2ecf20Sopenharmony_ci RXRPC_SECURITY_ENCRYPT); 618c2ecf20Sopenharmony_ci if (ret < 0) 628c2ecf20Sopenharmony_ci goto error_2; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); 658c2ecf20Sopenharmony_ci if (ret == -EADDRINUSE) { 668c2ecf20Sopenharmony_ci srx.transport.sin6.sin6_port = 0; 678c2ecf20Sopenharmony_ci ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci if (ret < 0) 708c2ecf20Sopenharmony_ci goto error_2; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci srx.srx_service = YFS_CM_SERVICE; 738c2ecf20Sopenharmony_ci ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); 748c2ecf20Sopenharmony_ci if (ret < 0) 758c2ecf20Sopenharmony_ci goto error_2; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* Ideally, we'd turn on service upgrade here, but we can't because 788c2ecf20Sopenharmony_ci * OpenAFS is buggy and leaks the userStatus field from packet to 798c2ecf20Sopenharmony_ci * packet and between FS packets and CB packets - so if we try to do an 808c2ecf20Sopenharmony_ci * upgrade on an FS packet, OpenAFS will leak that into the CB packet 818c2ecf20Sopenharmony_ci * it sends back to us. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci rxrpc_kernel_new_call_notification(socket, afs_rx_new_call, 858c2ecf20Sopenharmony_ci afs_rx_discard_new_call); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci ret = kernel_listen(socket, INT_MAX); 888c2ecf20Sopenharmony_ci if (ret < 0) 898c2ecf20Sopenharmony_ci goto error_2; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci net->socket = socket; 928c2ecf20Sopenharmony_ci afs_charge_preallocation(&net->charge_preallocation_work); 938c2ecf20Sopenharmony_ci _leave(" = 0"); 948c2ecf20Sopenharmony_ci return 0; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cierror_2: 978c2ecf20Sopenharmony_ci sock_release(socket); 988c2ecf20Sopenharmony_cierror_1: 998c2ecf20Sopenharmony_ci _leave(" = %d", ret); 1008c2ecf20Sopenharmony_ci return ret; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/* 1048c2ecf20Sopenharmony_ci * close the RxRPC socket AFS was using 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_civoid afs_close_socket(struct afs_net *net) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci _enter(""); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci kernel_listen(net->socket, 0); 1118c2ecf20Sopenharmony_ci flush_workqueue(afs_async_calls); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (net->spare_incoming_call) { 1148c2ecf20Sopenharmony_ci afs_put_call(net->spare_incoming_call); 1158c2ecf20Sopenharmony_ci net->spare_incoming_call = NULL; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci _debug("outstanding %u", atomic_read(&net->nr_outstanding_calls)); 1198c2ecf20Sopenharmony_ci wait_var_event(&net->nr_outstanding_calls, 1208c2ecf20Sopenharmony_ci !atomic_read(&net->nr_outstanding_calls)); 1218c2ecf20Sopenharmony_ci _debug("no outstanding calls"); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci kernel_sock_shutdown(net->socket, SHUT_RDWR); 1248c2ecf20Sopenharmony_ci flush_workqueue(afs_async_calls); 1258c2ecf20Sopenharmony_ci sock_release(net->socket); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci _debug("dework"); 1288c2ecf20Sopenharmony_ci _leave(""); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/* 1328c2ecf20Sopenharmony_ci * Allocate a call. 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_cistatic struct afs_call *afs_alloc_call(struct afs_net *net, 1358c2ecf20Sopenharmony_ci const struct afs_call_type *type, 1368c2ecf20Sopenharmony_ci gfp_t gfp) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct afs_call *call; 1398c2ecf20Sopenharmony_ci int o; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci call = kzalloc(sizeof(*call), gfp); 1428c2ecf20Sopenharmony_ci if (!call) 1438c2ecf20Sopenharmony_ci return NULL; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci call->type = type; 1468c2ecf20Sopenharmony_ci call->net = net; 1478c2ecf20Sopenharmony_ci call->debug_id = atomic_inc_return(&rxrpc_debug_id); 1488c2ecf20Sopenharmony_ci atomic_set(&call->usage, 1); 1498c2ecf20Sopenharmony_ci INIT_WORK(&call->async_work, afs_process_async_call); 1508c2ecf20Sopenharmony_ci init_waitqueue_head(&call->waitq); 1518c2ecf20Sopenharmony_ci spin_lock_init(&call->state_lock); 1528c2ecf20Sopenharmony_ci call->iter = &call->def_iter; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci o = atomic_inc_return(&net->nr_outstanding_calls); 1558c2ecf20Sopenharmony_ci trace_afs_call(call, afs_call_trace_alloc, 1, o, 1568c2ecf20Sopenharmony_ci __builtin_return_address(0)); 1578c2ecf20Sopenharmony_ci return call; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/* 1618c2ecf20Sopenharmony_ci * Dispose of a reference on a call. 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_civoid afs_put_call(struct afs_call *call) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct afs_net *net = call->net; 1668c2ecf20Sopenharmony_ci int n = atomic_dec_return(&call->usage); 1678c2ecf20Sopenharmony_ci int o = atomic_read(&net->nr_outstanding_calls); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci trace_afs_call(call, afs_call_trace_put, n, o, 1708c2ecf20Sopenharmony_ci __builtin_return_address(0)); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci ASSERTCMP(n, >=, 0); 1738c2ecf20Sopenharmony_ci if (n == 0) { 1748c2ecf20Sopenharmony_ci ASSERT(!work_pending(&call->async_work)); 1758c2ecf20Sopenharmony_ci ASSERT(call->type->name != NULL); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (call->rxcall) { 1788c2ecf20Sopenharmony_ci rxrpc_kernel_end_call(net->socket, call->rxcall); 1798c2ecf20Sopenharmony_ci call->rxcall = NULL; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci if (call->type->destructor) 1828c2ecf20Sopenharmony_ci call->type->destructor(call); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci afs_unuse_server_notime(call->net, call->server, afs_server_trace_put_call); 1858c2ecf20Sopenharmony_ci afs_put_addrlist(call->alist); 1868c2ecf20Sopenharmony_ci kfree(call->request); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci trace_afs_call(call, afs_call_trace_free, 0, o, 1898c2ecf20Sopenharmony_ci __builtin_return_address(0)); 1908c2ecf20Sopenharmony_ci kfree(call); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci o = atomic_dec_return(&net->nr_outstanding_calls); 1938c2ecf20Sopenharmony_ci if (o == 0) 1948c2ecf20Sopenharmony_ci wake_up_var(&net->nr_outstanding_calls); 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic struct afs_call *afs_get_call(struct afs_call *call, 1998c2ecf20Sopenharmony_ci enum afs_call_trace why) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci int u = atomic_inc_return(&call->usage); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci trace_afs_call(call, why, u, 2048c2ecf20Sopenharmony_ci atomic_read(&call->net->nr_outstanding_calls), 2058c2ecf20Sopenharmony_ci __builtin_return_address(0)); 2068c2ecf20Sopenharmony_ci return call; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci/* 2108c2ecf20Sopenharmony_ci * Queue the call for actual work. 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_cistatic void afs_queue_call_work(struct afs_call *call) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci if (call->type->work) { 2158c2ecf20Sopenharmony_ci INIT_WORK(&call->work, call->type->work); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci afs_get_call(call, afs_call_trace_work); 2188c2ecf20Sopenharmony_ci if (!queue_work(afs_wq, &call->work)) 2198c2ecf20Sopenharmony_ci afs_put_call(call); 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/* 2248c2ecf20Sopenharmony_ci * allocate a call with flat request and reply buffers 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_cistruct afs_call *afs_alloc_flat_call(struct afs_net *net, 2278c2ecf20Sopenharmony_ci const struct afs_call_type *type, 2288c2ecf20Sopenharmony_ci size_t request_size, size_t reply_max) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct afs_call *call; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci call = afs_alloc_call(net, type, GFP_NOFS); 2338c2ecf20Sopenharmony_ci if (!call) 2348c2ecf20Sopenharmony_ci goto nomem_call; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (request_size) { 2378c2ecf20Sopenharmony_ci call->request_size = request_size; 2388c2ecf20Sopenharmony_ci call->request = kmalloc(request_size, GFP_NOFS); 2398c2ecf20Sopenharmony_ci if (!call->request) 2408c2ecf20Sopenharmony_ci goto nomem_free; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (reply_max) { 2448c2ecf20Sopenharmony_ci call->reply_max = reply_max; 2458c2ecf20Sopenharmony_ci call->buffer = kmalloc(reply_max, GFP_NOFS); 2468c2ecf20Sopenharmony_ci if (!call->buffer) 2478c2ecf20Sopenharmony_ci goto nomem_free; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci afs_extract_to_buf(call, call->reply_max); 2518c2ecf20Sopenharmony_ci call->operation_ID = type->op; 2528c2ecf20Sopenharmony_ci init_waitqueue_head(&call->waitq); 2538c2ecf20Sopenharmony_ci return call; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cinomem_free: 2568c2ecf20Sopenharmony_ci afs_put_call(call); 2578c2ecf20Sopenharmony_cinomem_call: 2588c2ecf20Sopenharmony_ci return NULL; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/* 2628c2ecf20Sopenharmony_ci * clean up a call with flat buffer 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_civoid afs_flat_call_destructor(struct afs_call *call) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci _enter(""); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci kfree(call->request); 2698c2ecf20Sopenharmony_ci call->request = NULL; 2708c2ecf20Sopenharmony_ci kfree(call->buffer); 2718c2ecf20Sopenharmony_ci call->buffer = NULL; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci#define AFS_BVEC_MAX 8 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/* 2778c2ecf20Sopenharmony_ci * Load the given bvec with the next few pages. 2788c2ecf20Sopenharmony_ci */ 2798c2ecf20Sopenharmony_cistatic void afs_load_bvec(struct afs_call *call, struct msghdr *msg, 2808c2ecf20Sopenharmony_ci struct bio_vec *bv, pgoff_t first, pgoff_t last, 2818c2ecf20Sopenharmony_ci unsigned offset) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct afs_operation *op = call->op; 2848c2ecf20Sopenharmony_ci struct page *pages[AFS_BVEC_MAX]; 2858c2ecf20Sopenharmony_ci unsigned int nr, n, i, to, bytes = 0; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci nr = min_t(pgoff_t, last - first + 1, AFS_BVEC_MAX); 2888c2ecf20Sopenharmony_ci n = find_get_pages_contig(op->store.mapping, first, nr, pages); 2898c2ecf20Sopenharmony_ci ASSERTCMP(n, ==, nr); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci msg->msg_flags |= MSG_MORE; 2928c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 2938c2ecf20Sopenharmony_ci to = PAGE_SIZE; 2948c2ecf20Sopenharmony_ci if (first + i >= last) { 2958c2ecf20Sopenharmony_ci to = op->store.last_to; 2968c2ecf20Sopenharmony_ci msg->msg_flags &= ~MSG_MORE; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci bv[i].bv_page = pages[i]; 2998c2ecf20Sopenharmony_ci bv[i].bv_len = to - offset; 3008c2ecf20Sopenharmony_ci bv[i].bv_offset = offset; 3018c2ecf20Sopenharmony_ci bytes += to - offset; 3028c2ecf20Sopenharmony_ci offset = 0; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci iov_iter_bvec(&msg->msg_iter, WRITE, bv, nr, bytes); 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci/* 3098c2ecf20Sopenharmony_ci * Advance the AFS call state when the RxRPC call ends the transmit phase. 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_cistatic void afs_notify_end_request_tx(struct sock *sock, 3128c2ecf20Sopenharmony_ci struct rxrpc_call *rxcall, 3138c2ecf20Sopenharmony_ci unsigned long call_user_ID) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct afs_call *call = (struct afs_call *)call_user_ID; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci afs_set_call_state(call, AFS_CALL_CL_REQUESTING, AFS_CALL_CL_AWAIT_REPLY); 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci/* 3218c2ecf20Sopenharmony_ci * attach the data from a bunch of pages on an inode to a call 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_cistatic int afs_send_pages(struct afs_call *call, struct msghdr *msg) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct afs_operation *op = call->op; 3268c2ecf20Sopenharmony_ci struct bio_vec bv[AFS_BVEC_MAX]; 3278c2ecf20Sopenharmony_ci unsigned int bytes, nr, loop, offset; 3288c2ecf20Sopenharmony_ci pgoff_t first = op->store.first, last = op->store.last; 3298c2ecf20Sopenharmony_ci int ret; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci offset = op->store.first_offset; 3328c2ecf20Sopenharmony_ci op->store.first_offset = 0; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci do { 3358c2ecf20Sopenharmony_ci afs_load_bvec(call, msg, bv, first, last, offset); 3368c2ecf20Sopenharmony_ci trace_afs_send_pages(call, msg, first, last, offset); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci offset = 0; 3398c2ecf20Sopenharmony_ci bytes = msg->msg_iter.count; 3408c2ecf20Sopenharmony_ci nr = msg->msg_iter.nr_segs; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci ret = rxrpc_kernel_send_data(op->net->socket, call->rxcall, msg, 3438c2ecf20Sopenharmony_ci bytes, afs_notify_end_request_tx); 3448c2ecf20Sopenharmony_ci for (loop = 0; loop < nr; loop++) 3458c2ecf20Sopenharmony_ci put_page(bv[loop].bv_page); 3468c2ecf20Sopenharmony_ci if (ret < 0) 3478c2ecf20Sopenharmony_ci break; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci first += nr; 3508c2ecf20Sopenharmony_ci } while (first <= last); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci trace_afs_sent_pages(call, op->store.first, last, first, ret); 3538c2ecf20Sopenharmony_ci return ret; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci/* 3578c2ecf20Sopenharmony_ci * Initiate a call and synchronously queue up the parameters for dispatch. Any 3588c2ecf20Sopenharmony_ci * error is stored into the call struct, which the caller must check for. 3598c2ecf20Sopenharmony_ci */ 3608c2ecf20Sopenharmony_civoid afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct sockaddr_rxrpc *srx = &ac->alist->addrs[ac->index]; 3638c2ecf20Sopenharmony_ci struct rxrpc_call *rxcall; 3648c2ecf20Sopenharmony_ci struct msghdr msg; 3658c2ecf20Sopenharmony_ci struct kvec iov[1]; 3668c2ecf20Sopenharmony_ci s64 tx_total_len; 3678c2ecf20Sopenharmony_ci int ret; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci _enter(",{%pISp},", &srx->transport); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci ASSERT(call->type != NULL); 3728c2ecf20Sopenharmony_ci ASSERT(call->type->name != NULL); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci _debug("____MAKE %p{%s,%x} [%d]____", 3758c2ecf20Sopenharmony_ci call, call->type->name, key_serial(call->key), 3768c2ecf20Sopenharmony_ci atomic_read(&call->net->nr_outstanding_calls)); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci call->addr_ix = ac->index; 3798c2ecf20Sopenharmony_ci call->alist = afs_get_addrlist(ac->alist); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Work out the length we're going to transmit. This is awkward for 3828c2ecf20Sopenharmony_ci * calls such as FS.StoreData where there's an extra injection of data 3838c2ecf20Sopenharmony_ci * after the initial fixed part. 3848c2ecf20Sopenharmony_ci */ 3858c2ecf20Sopenharmony_ci tx_total_len = call->request_size; 3868c2ecf20Sopenharmony_ci if (call->send_pages) { 3878c2ecf20Sopenharmony_ci struct afs_operation *op = call->op; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (op->store.last == op->store.first) { 3908c2ecf20Sopenharmony_ci tx_total_len += op->store.last_to - op->store.first_offset; 3918c2ecf20Sopenharmony_ci } else { 3928c2ecf20Sopenharmony_ci /* It looks mathematically like you should be able to 3938c2ecf20Sopenharmony_ci * combine the following lines with the ones above, but 3948c2ecf20Sopenharmony_ci * unsigned arithmetic is fun when it wraps... 3958c2ecf20Sopenharmony_ci */ 3968c2ecf20Sopenharmony_ci tx_total_len += PAGE_SIZE - op->store.first_offset; 3978c2ecf20Sopenharmony_ci tx_total_len += op->store.last_to; 3988c2ecf20Sopenharmony_ci tx_total_len += (op->store.last - op->store.first - 1) * PAGE_SIZE; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci /* If the call is going to be asynchronous, we need an extra ref for 4038c2ecf20Sopenharmony_ci * the call to hold itself so the caller need not hang on to its ref. 4048c2ecf20Sopenharmony_ci */ 4058c2ecf20Sopenharmony_ci if (call->async) { 4068c2ecf20Sopenharmony_ci afs_get_call(call, afs_call_trace_get); 4078c2ecf20Sopenharmony_ci call->drop_ref = true; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci /* create a call */ 4118c2ecf20Sopenharmony_ci rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key, 4128c2ecf20Sopenharmony_ci (unsigned long)call, 4138c2ecf20Sopenharmony_ci tx_total_len, gfp, 4148c2ecf20Sopenharmony_ci (call->async ? 4158c2ecf20Sopenharmony_ci afs_wake_up_async_call : 4168c2ecf20Sopenharmony_ci afs_wake_up_call_waiter), 4178c2ecf20Sopenharmony_ci call->upgrade, 4188c2ecf20Sopenharmony_ci (call->intr ? RXRPC_PREINTERRUPTIBLE : 4198c2ecf20Sopenharmony_ci RXRPC_UNINTERRUPTIBLE), 4208c2ecf20Sopenharmony_ci call->debug_id); 4218c2ecf20Sopenharmony_ci if (IS_ERR(rxcall)) { 4228c2ecf20Sopenharmony_ci ret = PTR_ERR(rxcall); 4238c2ecf20Sopenharmony_ci call->error = ret; 4248c2ecf20Sopenharmony_ci goto error_kill_call; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci call->rxcall = rxcall; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (call->max_lifespan) 4308c2ecf20Sopenharmony_ci rxrpc_kernel_set_max_life(call->net->socket, rxcall, 4318c2ecf20Sopenharmony_ci call->max_lifespan); 4328c2ecf20Sopenharmony_ci call->issue_time = ktime_get_real(); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* send the request */ 4358c2ecf20Sopenharmony_ci iov[0].iov_base = call->request; 4368c2ecf20Sopenharmony_ci iov[0].iov_len = call->request_size; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci msg.msg_name = NULL; 4398c2ecf20Sopenharmony_ci msg.msg_namelen = 0; 4408c2ecf20Sopenharmony_ci iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, call->request_size); 4418c2ecf20Sopenharmony_ci msg.msg_control = NULL; 4428c2ecf20Sopenharmony_ci msg.msg_controllen = 0; 4438c2ecf20Sopenharmony_ci msg.msg_flags = MSG_WAITALL | (call->send_pages ? MSG_MORE : 0); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci ret = rxrpc_kernel_send_data(call->net->socket, rxcall, 4468c2ecf20Sopenharmony_ci &msg, call->request_size, 4478c2ecf20Sopenharmony_ci afs_notify_end_request_tx); 4488c2ecf20Sopenharmony_ci if (ret < 0) 4498c2ecf20Sopenharmony_ci goto error_do_abort; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (call->send_pages) { 4528c2ecf20Sopenharmony_ci ret = afs_send_pages(call, &msg); 4538c2ecf20Sopenharmony_ci if (ret < 0) 4548c2ecf20Sopenharmony_ci goto error_do_abort; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* Note that at this point, we may have received the reply or an abort 4588c2ecf20Sopenharmony_ci * - and an asynchronous call may already have completed. 4598c2ecf20Sopenharmony_ci * 4608c2ecf20Sopenharmony_ci * afs_wait_for_call_to_complete(call, ac) 4618c2ecf20Sopenharmony_ci * must be called to synchronously clean up. 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_ci return; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cierror_do_abort: 4668c2ecf20Sopenharmony_ci if (ret != -ECONNABORTED) { 4678c2ecf20Sopenharmony_ci rxrpc_kernel_abort_call(call->net->socket, rxcall, 4688c2ecf20Sopenharmony_ci RX_USER_ABORT, ret, "KSD"); 4698c2ecf20Sopenharmony_ci } else { 4708c2ecf20Sopenharmony_ci iov_iter_kvec(&msg.msg_iter, READ, NULL, 0, 0); 4718c2ecf20Sopenharmony_ci rxrpc_kernel_recv_data(call->net->socket, rxcall, 4728c2ecf20Sopenharmony_ci &msg.msg_iter, false, 4738c2ecf20Sopenharmony_ci &call->abort_code, &call->service_id); 4748c2ecf20Sopenharmony_ci ac->abort_code = call->abort_code; 4758c2ecf20Sopenharmony_ci ac->responded = true; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci call->error = ret; 4788c2ecf20Sopenharmony_ci trace_afs_call_done(call); 4798c2ecf20Sopenharmony_cierror_kill_call: 4808c2ecf20Sopenharmony_ci if (call->type->done) 4818c2ecf20Sopenharmony_ci call->type->done(call); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* We need to dispose of the extra ref we grabbed for an async call. 4848c2ecf20Sopenharmony_ci * The call, however, might be queued on afs_async_calls and we need to 4858c2ecf20Sopenharmony_ci * make sure we don't get any more notifications that might requeue it. 4868c2ecf20Sopenharmony_ci */ 4878c2ecf20Sopenharmony_ci if (call->rxcall) { 4888c2ecf20Sopenharmony_ci rxrpc_kernel_end_call(call->net->socket, call->rxcall); 4898c2ecf20Sopenharmony_ci call->rxcall = NULL; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci if (call->async) { 4928c2ecf20Sopenharmony_ci if (cancel_work_sync(&call->async_work)) 4938c2ecf20Sopenharmony_ci afs_put_call(call); 4948c2ecf20Sopenharmony_ci afs_set_call_complete(call, ret, 0); 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci ac->error = ret; 4988c2ecf20Sopenharmony_ci call->state = AFS_CALL_COMPLETE; 4998c2ecf20Sopenharmony_ci _leave(" = %d", ret); 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci/* 5038c2ecf20Sopenharmony_ci * deliver messages to a call 5048c2ecf20Sopenharmony_ci */ 5058c2ecf20Sopenharmony_cistatic void afs_deliver_to_call(struct afs_call *call) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci enum afs_call_state state; 5088c2ecf20Sopenharmony_ci u32 abort_code, remote_abort = 0; 5098c2ecf20Sopenharmony_ci int ret; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci _enter("%s", call->type->name); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci while (state = READ_ONCE(call->state), 5148c2ecf20Sopenharmony_ci state == AFS_CALL_CL_AWAIT_REPLY || 5158c2ecf20Sopenharmony_ci state == AFS_CALL_SV_AWAIT_OP_ID || 5168c2ecf20Sopenharmony_ci state == AFS_CALL_SV_AWAIT_REQUEST || 5178c2ecf20Sopenharmony_ci state == AFS_CALL_SV_AWAIT_ACK 5188c2ecf20Sopenharmony_ci ) { 5198c2ecf20Sopenharmony_ci if (state == AFS_CALL_SV_AWAIT_ACK) { 5208c2ecf20Sopenharmony_ci iov_iter_kvec(&call->def_iter, READ, NULL, 0, 0); 5218c2ecf20Sopenharmony_ci ret = rxrpc_kernel_recv_data(call->net->socket, 5228c2ecf20Sopenharmony_ci call->rxcall, &call->def_iter, 5238c2ecf20Sopenharmony_ci false, &remote_abort, 5248c2ecf20Sopenharmony_ci &call->service_id); 5258c2ecf20Sopenharmony_ci trace_afs_receive_data(call, &call->def_iter, false, ret); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if (ret == -EINPROGRESS || ret == -EAGAIN) 5288c2ecf20Sopenharmony_ci return; 5298c2ecf20Sopenharmony_ci if (ret < 0 || ret == 1) { 5308c2ecf20Sopenharmony_ci if (ret == 1) 5318c2ecf20Sopenharmony_ci ret = 0; 5328c2ecf20Sopenharmony_ci goto call_complete; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci return; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci ret = call->type->deliver(call); 5388c2ecf20Sopenharmony_ci state = READ_ONCE(call->state); 5398c2ecf20Sopenharmony_ci if (ret == 0 && call->unmarshalling_error) 5408c2ecf20Sopenharmony_ci ret = -EBADMSG; 5418c2ecf20Sopenharmony_ci switch (ret) { 5428c2ecf20Sopenharmony_ci case 0: 5438c2ecf20Sopenharmony_ci afs_queue_call_work(call); 5448c2ecf20Sopenharmony_ci if (state == AFS_CALL_CL_PROC_REPLY) { 5458c2ecf20Sopenharmony_ci if (call->op) 5468c2ecf20Sopenharmony_ci set_bit(AFS_SERVER_FL_MAY_HAVE_CB, 5478c2ecf20Sopenharmony_ci &call->op->server->flags); 5488c2ecf20Sopenharmony_ci goto call_complete; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci ASSERTCMP(state, >, AFS_CALL_CL_PROC_REPLY); 5518c2ecf20Sopenharmony_ci goto done; 5528c2ecf20Sopenharmony_ci case -EINPROGRESS: 5538c2ecf20Sopenharmony_ci case -EAGAIN: 5548c2ecf20Sopenharmony_ci goto out; 5558c2ecf20Sopenharmony_ci case -ECONNABORTED: 5568c2ecf20Sopenharmony_ci ASSERTCMP(state, ==, AFS_CALL_COMPLETE); 5578c2ecf20Sopenharmony_ci goto done; 5588c2ecf20Sopenharmony_ci case -ENOTSUPP: 5598c2ecf20Sopenharmony_ci abort_code = RXGEN_OPCODE; 5608c2ecf20Sopenharmony_ci rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 5618c2ecf20Sopenharmony_ci abort_code, ret, "KIV"); 5628c2ecf20Sopenharmony_ci goto local_abort; 5638c2ecf20Sopenharmony_ci case -EIO: 5648c2ecf20Sopenharmony_ci pr_err("kAFS: Call %u in bad state %u\n", 5658c2ecf20Sopenharmony_ci call->debug_id, state); 5668c2ecf20Sopenharmony_ci fallthrough; 5678c2ecf20Sopenharmony_ci case -ENODATA: 5688c2ecf20Sopenharmony_ci case -EBADMSG: 5698c2ecf20Sopenharmony_ci case -EMSGSIZE: 5708c2ecf20Sopenharmony_ci case -ENOMEM: 5718c2ecf20Sopenharmony_ci case -EFAULT: 5728c2ecf20Sopenharmony_ci abort_code = RXGEN_CC_UNMARSHAL; 5738c2ecf20Sopenharmony_ci if (state != AFS_CALL_CL_AWAIT_REPLY) 5748c2ecf20Sopenharmony_ci abort_code = RXGEN_SS_UNMARSHAL; 5758c2ecf20Sopenharmony_ci rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 5768c2ecf20Sopenharmony_ci abort_code, ret, "KUM"); 5778c2ecf20Sopenharmony_ci goto local_abort; 5788c2ecf20Sopenharmony_ci default: 5798c2ecf20Sopenharmony_ci abort_code = RX_CALL_DEAD; 5808c2ecf20Sopenharmony_ci rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 5818c2ecf20Sopenharmony_ci abort_code, ret, "KER"); 5828c2ecf20Sopenharmony_ci goto local_abort; 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cidone: 5878c2ecf20Sopenharmony_ci if (call->type->done) 5888c2ecf20Sopenharmony_ci call->type->done(call); 5898c2ecf20Sopenharmony_ciout: 5908c2ecf20Sopenharmony_ci _leave(""); 5918c2ecf20Sopenharmony_ci return; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cilocal_abort: 5948c2ecf20Sopenharmony_ci abort_code = 0; 5958c2ecf20Sopenharmony_cicall_complete: 5968c2ecf20Sopenharmony_ci afs_set_call_complete(call, ret, remote_abort); 5978c2ecf20Sopenharmony_ci state = AFS_CALL_COMPLETE; 5988c2ecf20Sopenharmony_ci goto done; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci/* 6028c2ecf20Sopenharmony_ci * Wait synchronously for a call to complete and clean up the call struct. 6038c2ecf20Sopenharmony_ci */ 6048c2ecf20Sopenharmony_cilong afs_wait_for_call_to_complete(struct afs_call *call, 6058c2ecf20Sopenharmony_ci struct afs_addr_cursor *ac) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci long ret; 6088c2ecf20Sopenharmony_ci bool rxrpc_complete = false; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci DECLARE_WAITQUEUE(myself, current); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci _enter(""); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci ret = call->error; 6158c2ecf20Sopenharmony_ci if (ret < 0) 6168c2ecf20Sopenharmony_ci goto out; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci add_wait_queue(&call->waitq, &myself); 6198c2ecf20Sopenharmony_ci for (;;) { 6208c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci /* deliver any messages that are in the queue */ 6238c2ecf20Sopenharmony_ci if (!afs_check_call_state(call, AFS_CALL_COMPLETE) && 6248c2ecf20Sopenharmony_ci call->need_attention) { 6258c2ecf20Sopenharmony_ci call->need_attention = false; 6268c2ecf20Sopenharmony_ci __set_current_state(TASK_RUNNING); 6278c2ecf20Sopenharmony_ci afs_deliver_to_call(call); 6288c2ecf20Sopenharmony_ci continue; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (afs_check_call_state(call, AFS_CALL_COMPLETE)) 6328c2ecf20Sopenharmony_ci break; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci if (!rxrpc_kernel_check_life(call->net->socket, call->rxcall)) { 6358c2ecf20Sopenharmony_ci /* rxrpc terminated the call. */ 6368c2ecf20Sopenharmony_ci rxrpc_complete = true; 6378c2ecf20Sopenharmony_ci break; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci schedule(); 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci remove_wait_queue(&call->waitq, &myself); 6448c2ecf20Sopenharmony_ci __set_current_state(TASK_RUNNING); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (!afs_check_call_state(call, AFS_CALL_COMPLETE)) { 6478c2ecf20Sopenharmony_ci if (rxrpc_complete) { 6488c2ecf20Sopenharmony_ci afs_set_call_complete(call, call->error, call->abort_code); 6498c2ecf20Sopenharmony_ci } else { 6508c2ecf20Sopenharmony_ci /* Kill off the call if it's still live. */ 6518c2ecf20Sopenharmony_ci _debug("call interrupted"); 6528c2ecf20Sopenharmony_ci if (rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 6538c2ecf20Sopenharmony_ci RX_USER_ABORT, -EINTR, "KWI")) 6548c2ecf20Sopenharmony_ci afs_set_call_complete(call, -EINTR, 0); 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci spin_lock_bh(&call->state_lock); 6598c2ecf20Sopenharmony_ci ac->abort_code = call->abort_code; 6608c2ecf20Sopenharmony_ci ac->error = call->error; 6618c2ecf20Sopenharmony_ci spin_unlock_bh(&call->state_lock); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci ret = ac->error; 6648c2ecf20Sopenharmony_ci switch (ret) { 6658c2ecf20Sopenharmony_ci case 0: 6668c2ecf20Sopenharmony_ci ret = call->ret0; 6678c2ecf20Sopenharmony_ci call->ret0 = 0; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci fallthrough; 6708c2ecf20Sopenharmony_ci case -ECONNABORTED: 6718c2ecf20Sopenharmony_ci ac->responded = true; 6728c2ecf20Sopenharmony_ci break; 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ciout: 6768c2ecf20Sopenharmony_ci _debug("call complete"); 6778c2ecf20Sopenharmony_ci afs_put_call(call); 6788c2ecf20Sopenharmony_ci _leave(" = %p", (void *)ret); 6798c2ecf20Sopenharmony_ci return ret; 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci/* 6838c2ecf20Sopenharmony_ci * wake up a waiting call 6848c2ecf20Sopenharmony_ci */ 6858c2ecf20Sopenharmony_cistatic void afs_wake_up_call_waiter(struct sock *sk, struct rxrpc_call *rxcall, 6868c2ecf20Sopenharmony_ci unsigned long call_user_ID) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci struct afs_call *call = (struct afs_call *)call_user_ID; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci call->need_attention = true; 6918c2ecf20Sopenharmony_ci wake_up(&call->waitq); 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci/* 6958c2ecf20Sopenharmony_ci * wake up an asynchronous call 6968c2ecf20Sopenharmony_ci */ 6978c2ecf20Sopenharmony_cistatic void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall, 6988c2ecf20Sopenharmony_ci unsigned long call_user_ID) 6998c2ecf20Sopenharmony_ci{ 7008c2ecf20Sopenharmony_ci struct afs_call *call = (struct afs_call *)call_user_ID; 7018c2ecf20Sopenharmony_ci int u; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci trace_afs_notify_call(rxcall, call); 7048c2ecf20Sopenharmony_ci call->need_attention = true; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci u = atomic_fetch_add_unless(&call->usage, 1, 0); 7078c2ecf20Sopenharmony_ci if (u != 0) { 7088c2ecf20Sopenharmony_ci trace_afs_call(call, afs_call_trace_wake, u + 1, 7098c2ecf20Sopenharmony_ci atomic_read(&call->net->nr_outstanding_calls), 7108c2ecf20Sopenharmony_ci __builtin_return_address(0)); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (!queue_work(afs_async_calls, &call->async_work)) 7138c2ecf20Sopenharmony_ci afs_put_call(call); 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci/* 7188c2ecf20Sopenharmony_ci * Perform I/O processing on an asynchronous call. The work item carries a ref 7198c2ecf20Sopenharmony_ci * to the call struct that we either need to release or to pass on. 7208c2ecf20Sopenharmony_ci */ 7218c2ecf20Sopenharmony_cistatic void afs_process_async_call(struct work_struct *work) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci struct afs_call *call = container_of(work, struct afs_call, async_work); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci _enter(""); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci if (call->state < AFS_CALL_COMPLETE && call->need_attention) { 7288c2ecf20Sopenharmony_ci call->need_attention = false; 7298c2ecf20Sopenharmony_ci afs_deliver_to_call(call); 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci afs_put_call(call); 7338c2ecf20Sopenharmony_ci _leave(""); 7348c2ecf20Sopenharmony_ci} 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic void afs_rx_attach(struct rxrpc_call *rxcall, unsigned long user_call_ID) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci struct afs_call *call = (struct afs_call *)user_call_ID; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci call->rxcall = rxcall; 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci/* 7448c2ecf20Sopenharmony_ci * Charge the incoming call preallocation. 7458c2ecf20Sopenharmony_ci */ 7468c2ecf20Sopenharmony_civoid afs_charge_preallocation(struct work_struct *work) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci struct afs_net *net = 7498c2ecf20Sopenharmony_ci container_of(work, struct afs_net, charge_preallocation_work); 7508c2ecf20Sopenharmony_ci struct afs_call *call = net->spare_incoming_call; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci for (;;) { 7538c2ecf20Sopenharmony_ci if (!call) { 7548c2ecf20Sopenharmony_ci call = afs_alloc_call(net, &afs_RXCMxxxx, GFP_KERNEL); 7558c2ecf20Sopenharmony_ci if (!call) 7568c2ecf20Sopenharmony_ci break; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci call->drop_ref = true; 7598c2ecf20Sopenharmony_ci call->async = true; 7608c2ecf20Sopenharmony_ci call->state = AFS_CALL_SV_AWAIT_OP_ID; 7618c2ecf20Sopenharmony_ci init_waitqueue_head(&call->waitq); 7628c2ecf20Sopenharmony_ci afs_extract_to_tmp(call); 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci if (rxrpc_kernel_charge_accept(net->socket, 7668c2ecf20Sopenharmony_ci afs_wake_up_async_call, 7678c2ecf20Sopenharmony_ci afs_rx_attach, 7688c2ecf20Sopenharmony_ci (unsigned long)call, 7698c2ecf20Sopenharmony_ci GFP_KERNEL, 7708c2ecf20Sopenharmony_ci call->debug_id) < 0) 7718c2ecf20Sopenharmony_ci break; 7728c2ecf20Sopenharmony_ci call = NULL; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci net->spare_incoming_call = call; 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci/* 7788c2ecf20Sopenharmony_ci * Discard a preallocated call when a socket is shut down. 7798c2ecf20Sopenharmony_ci */ 7808c2ecf20Sopenharmony_cistatic void afs_rx_discard_new_call(struct rxrpc_call *rxcall, 7818c2ecf20Sopenharmony_ci unsigned long user_call_ID) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci struct afs_call *call = (struct afs_call *)user_call_ID; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci call->rxcall = NULL; 7868c2ecf20Sopenharmony_ci afs_put_call(call); 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci/* 7908c2ecf20Sopenharmony_ci * Notification of an incoming call. 7918c2ecf20Sopenharmony_ci */ 7928c2ecf20Sopenharmony_cistatic void afs_rx_new_call(struct sock *sk, struct rxrpc_call *rxcall, 7938c2ecf20Sopenharmony_ci unsigned long user_call_ID) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci struct afs_net *net = afs_sock2net(sk); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci queue_work(afs_wq, &net->charge_preallocation_work); 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci/* 8018c2ecf20Sopenharmony_ci * Grab the operation ID from an incoming cache manager call. The socket 8028c2ecf20Sopenharmony_ci * buffer is discarded on error or if we don't yet have sufficient data. 8038c2ecf20Sopenharmony_ci */ 8048c2ecf20Sopenharmony_cistatic int afs_deliver_cm_op_id(struct afs_call *call) 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci int ret; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci _enter("{%zu}", iov_iter_count(call->iter)); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci /* the operation ID forms the first four bytes of the request data */ 8118c2ecf20Sopenharmony_ci ret = afs_extract_data(call, true); 8128c2ecf20Sopenharmony_ci if (ret < 0) 8138c2ecf20Sopenharmony_ci return ret; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci call->operation_ID = ntohl(call->tmp); 8168c2ecf20Sopenharmony_ci afs_set_call_state(call, AFS_CALL_SV_AWAIT_OP_ID, AFS_CALL_SV_AWAIT_REQUEST); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci /* ask the cache manager to route the call (it'll change the call type 8198c2ecf20Sopenharmony_ci * if successful) */ 8208c2ecf20Sopenharmony_ci if (!afs_cm_incoming_call(call)) 8218c2ecf20Sopenharmony_ci return -ENOTSUPP; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci trace_afs_cb_call(call); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci /* pass responsibility for the remainer of this message off to the 8268c2ecf20Sopenharmony_ci * cache manager op */ 8278c2ecf20Sopenharmony_ci return call->type->deliver(call); 8288c2ecf20Sopenharmony_ci} 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci/* 8318c2ecf20Sopenharmony_ci * Advance the AFS call state when an RxRPC service call ends the transmit 8328c2ecf20Sopenharmony_ci * phase. 8338c2ecf20Sopenharmony_ci */ 8348c2ecf20Sopenharmony_cistatic void afs_notify_end_reply_tx(struct sock *sock, 8358c2ecf20Sopenharmony_ci struct rxrpc_call *rxcall, 8368c2ecf20Sopenharmony_ci unsigned long call_user_ID) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci struct afs_call *call = (struct afs_call *)call_user_ID; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci afs_set_call_state(call, AFS_CALL_SV_REPLYING, AFS_CALL_SV_AWAIT_ACK); 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci/* 8448c2ecf20Sopenharmony_ci * send an empty reply 8458c2ecf20Sopenharmony_ci */ 8468c2ecf20Sopenharmony_civoid afs_send_empty_reply(struct afs_call *call) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci struct afs_net *net = call->net; 8498c2ecf20Sopenharmony_ci struct msghdr msg; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci _enter(""); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci rxrpc_kernel_set_tx_length(net->socket, call->rxcall, 0); 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci msg.msg_name = NULL; 8568c2ecf20Sopenharmony_ci msg.msg_namelen = 0; 8578c2ecf20Sopenharmony_ci iov_iter_kvec(&msg.msg_iter, WRITE, NULL, 0, 0); 8588c2ecf20Sopenharmony_ci msg.msg_control = NULL; 8598c2ecf20Sopenharmony_ci msg.msg_controllen = 0; 8608c2ecf20Sopenharmony_ci msg.msg_flags = 0; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci switch (rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, 0, 8638c2ecf20Sopenharmony_ci afs_notify_end_reply_tx)) { 8648c2ecf20Sopenharmony_ci case 0: 8658c2ecf20Sopenharmony_ci _leave(" [replied]"); 8668c2ecf20Sopenharmony_ci return; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci case -ENOMEM: 8698c2ecf20Sopenharmony_ci _debug("oom"); 8708c2ecf20Sopenharmony_ci rxrpc_kernel_abort_call(net->socket, call->rxcall, 8718c2ecf20Sopenharmony_ci RXGEN_SS_MARSHAL, -ENOMEM, "KOO"); 8728c2ecf20Sopenharmony_ci fallthrough; 8738c2ecf20Sopenharmony_ci default: 8748c2ecf20Sopenharmony_ci _leave(" [error]"); 8758c2ecf20Sopenharmony_ci return; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci} 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci/* 8808c2ecf20Sopenharmony_ci * send a simple reply 8818c2ecf20Sopenharmony_ci */ 8828c2ecf20Sopenharmony_civoid afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci struct afs_net *net = call->net; 8858c2ecf20Sopenharmony_ci struct msghdr msg; 8868c2ecf20Sopenharmony_ci struct kvec iov[1]; 8878c2ecf20Sopenharmony_ci int n; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci _enter(""); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci rxrpc_kernel_set_tx_length(net->socket, call->rxcall, len); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci iov[0].iov_base = (void *) buf; 8948c2ecf20Sopenharmony_ci iov[0].iov_len = len; 8958c2ecf20Sopenharmony_ci msg.msg_name = NULL; 8968c2ecf20Sopenharmony_ci msg.msg_namelen = 0; 8978c2ecf20Sopenharmony_ci iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len); 8988c2ecf20Sopenharmony_ci msg.msg_control = NULL; 8998c2ecf20Sopenharmony_ci msg.msg_controllen = 0; 9008c2ecf20Sopenharmony_ci msg.msg_flags = 0; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, len, 9038c2ecf20Sopenharmony_ci afs_notify_end_reply_tx); 9048c2ecf20Sopenharmony_ci if (n >= 0) { 9058c2ecf20Sopenharmony_ci /* Success */ 9068c2ecf20Sopenharmony_ci _leave(" [replied]"); 9078c2ecf20Sopenharmony_ci return; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci if (n == -ENOMEM) { 9118c2ecf20Sopenharmony_ci _debug("oom"); 9128c2ecf20Sopenharmony_ci rxrpc_kernel_abort_call(net->socket, call->rxcall, 9138c2ecf20Sopenharmony_ci RXGEN_SS_MARSHAL, -ENOMEM, "KOO"); 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci _leave(" [error]"); 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci/* 9198c2ecf20Sopenharmony_ci * Extract a piece of data from the received data socket buffers. 9208c2ecf20Sopenharmony_ci */ 9218c2ecf20Sopenharmony_ciint afs_extract_data(struct afs_call *call, bool want_more) 9228c2ecf20Sopenharmony_ci{ 9238c2ecf20Sopenharmony_ci struct afs_net *net = call->net; 9248c2ecf20Sopenharmony_ci struct iov_iter *iter = call->iter; 9258c2ecf20Sopenharmony_ci enum afs_call_state state; 9268c2ecf20Sopenharmony_ci u32 remote_abort = 0; 9278c2ecf20Sopenharmony_ci int ret; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci _enter("{%s,%zu},%d", call->type->name, iov_iter_count(iter), want_more); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci ret = rxrpc_kernel_recv_data(net->socket, call->rxcall, iter, 9328c2ecf20Sopenharmony_ci want_more, &remote_abort, 9338c2ecf20Sopenharmony_ci &call->service_id); 9348c2ecf20Sopenharmony_ci if (ret == 0 || ret == -EAGAIN) 9358c2ecf20Sopenharmony_ci return ret; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci state = READ_ONCE(call->state); 9388c2ecf20Sopenharmony_ci if (ret == 1) { 9398c2ecf20Sopenharmony_ci switch (state) { 9408c2ecf20Sopenharmony_ci case AFS_CALL_CL_AWAIT_REPLY: 9418c2ecf20Sopenharmony_ci afs_set_call_state(call, state, AFS_CALL_CL_PROC_REPLY); 9428c2ecf20Sopenharmony_ci break; 9438c2ecf20Sopenharmony_ci case AFS_CALL_SV_AWAIT_REQUEST: 9448c2ecf20Sopenharmony_ci afs_set_call_state(call, state, AFS_CALL_SV_REPLYING); 9458c2ecf20Sopenharmony_ci break; 9468c2ecf20Sopenharmony_ci case AFS_CALL_COMPLETE: 9478c2ecf20Sopenharmony_ci kdebug("prem complete %d", call->error); 9488c2ecf20Sopenharmony_ci return afs_io_error(call, afs_io_error_extract); 9498c2ecf20Sopenharmony_ci default: 9508c2ecf20Sopenharmony_ci break; 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci return 0; 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci afs_set_call_complete(call, ret, remote_abort); 9568c2ecf20Sopenharmony_ci return ret; 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci/* 9608c2ecf20Sopenharmony_ci * Log protocol error production. 9618c2ecf20Sopenharmony_ci */ 9628c2ecf20Sopenharmony_cinoinline int afs_protocol_error(struct afs_call *call, 9638c2ecf20Sopenharmony_ci enum afs_eproto_cause cause) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci trace_afs_protocol_error(call, cause); 9668c2ecf20Sopenharmony_ci if (call) 9678c2ecf20Sopenharmony_ci call->unmarshalling_error = true; 9688c2ecf20Sopenharmony_ci return -EBADMSG; 9698c2ecf20Sopenharmony_ci} 970