108e0e7c8SDavid Howells /* Maintain an RxRPC server socket to do AFS communications through 208e0e7c8SDavid Howells * 308e0e7c8SDavid Howells * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 408e0e7c8SDavid Howells * Written by David Howells (dhowells@redhat.com) 508e0e7c8SDavid Howells * 608e0e7c8SDavid Howells * This program is free software; you can redistribute it and/or 708e0e7c8SDavid Howells * modify it under the terms of the GNU General Public License 808e0e7c8SDavid Howells * as published by the Free Software Foundation; either version 908e0e7c8SDavid Howells * 2 of the License, or (at your option) any later version. 1008e0e7c8SDavid Howells */ 1108e0e7c8SDavid Howells 125a0e3ad6STejun Heo #include <linux/slab.h> 13174cd4b1SIngo Molnar #include <linux/sched/signal.h> 14174cd4b1SIngo Molnar 1508e0e7c8SDavid Howells #include <net/sock.h> 1608e0e7c8SDavid Howells #include <net/af_rxrpc.h> 1708e0e7c8SDavid Howells #include "internal.h" 1808e0e7c8SDavid Howells #include "afs_cm.h" 1908e0e7c8SDavid Howells 20f044c884SDavid Howells struct workqueue_struct *afs_async_calls; 2108e0e7c8SDavid Howells 22d001648eSDavid Howells static void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long); 23d2ddc776SDavid Howells static long afs_wait_for_call_to_complete(struct afs_call *, struct afs_addr_cursor *); 24d001648eSDavid Howells static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long); 25d001648eSDavid Howells static void afs_process_async_call(struct work_struct *); 2600e90712SDavid Howells static void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long); 2700e90712SDavid Howells static void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long); 28d001648eSDavid Howells static int afs_deliver_cm_op_id(struct afs_call *); 2908e0e7c8SDavid Howells 3008e0e7c8SDavid Howells /* asynchronous incoming call initial processing */ 3108e0e7c8SDavid Howells static const struct afs_call_type afs_RXCMxxxx = { 3200d3b7a4SDavid Howells .name = "CB.xxxx", 3308e0e7c8SDavid Howells .deliver = afs_deliver_cm_op_id, 3408e0e7c8SDavid Howells }; 3508e0e7c8SDavid Howells 3608e0e7c8SDavid Howells /* 3708e0e7c8SDavid Howells * open an RxRPC socket and bind it to be a server for callback notifications 3808e0e7c8SDavid Howells * - the socket is left in blocking mode and non-blocking ops use MSG_DONTWAIT 3908e0e7c8SDavid Howells */ 40f044c884SDavid Howells int afs_open_socket(struct afs_net *net) 4108e0e7c8SDavid Howells { 4208e0e7c8SDavid Howells struct sockaddr_rxrpc srx; 4308e0e7c8SDavid Howells struct socket *socket; 444776cab4SDavid Howells unsigned int min_level; 4508e0e7c8SDavid Howells int ret; 4608e0e7c8SDavid Howells 4708e0e7c8SDavid Howells _enter(""); 4808e0e7c8SDavid Howells 495b86d4ffSDavid Howells ret = sock_create_kern(net->net, AF_RXRPC, SOCK_DGRAM, PF_INET6, &socket); 500e119b41SDavid Howells if (ret < 0) 510e119b41SDavid Howells goto error_1; 5208e0e7c8SDavid Howells 5308e0e7c8SDavid Howells socket->sk->sk_allocation = GFP_NOFS; 5408e0e7c8SDavid Howells 5508e0e7c8SDavid Howells /* bind the callback manager's address to make this a server socket */ 563838d3ecSDavid Howells memset(&srx, 0, sizeof(srx)); 5708e0e7c8SDavid Howells srx.srx_family = AF_RXRPC; 5808e0e7c8SDavid Howells srx.srx_service = CM_SERVICE; 5908e0e7c8SDavid Howells srx.transport_type = SOCK_DGRAM; 603838d3ecSDavid Howells srx.transport_len = sizeof(srx.transport.sin6); 613838d3ecSDavid Howells srx.transport.sin6.sin6_family = AF_INET6; 623838d3ecSDavid Howells srx.transport.sin6.sin6_port = htons(AFS_CM_PORT); 6308e0e7c8SDavid Howells 644776cab4SDavid Howells min_level = RXRPC_SECURITY_ENCRYPT; 654776cab4SDavid Howells ret = kernel_setsockopt(socket, SOL_RXRPC, RXRPC_MIN_SECURITY_LEVEL, 664776cab4SDavid Howells (void *)&min_level, sizeof(min_level)); 674776cab4SDavid Howells if (ret < 0) 684776cab4SDavid Howells goto error_2; 694776cab4SDavid Howells 7008e0e7c8SDavid Howells ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); 7183732ec5SMarc Dionne if (ret == -EADDRINUSE) { 7283732ec5SMarc Dionne srx.transport.sin6.sin6_port = 0; 7383732ec5SMarc Dionne ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); 7483732ec5SMarc Dionne } 750e119b41SDavid Howells if (ret < 0) 760e119b41SDavid Howells goto error_2; 770e119b41SDavid Howells 7800e90712SDavid Howells rxrpc_kernel_new_call_notification(socket, afs_rx_new_call, 7900e90712SDavid Howells afs_rx_discard_new_call); 80d001648eSDavid Howells 810e119b41SDavid Howells ret = kernel_listen(socket, INT_MAX); 820e119b41SDavid Howells if (ret < 0) 830e119b41SDavid Howells goto error_2; 8408e0e7c8SDavid Howells 85f044c884SDavid Howells net->socket = socket; 86f044c884SDavid Howells afs_charge_preallocation(&net->charge_preallocation_work); 8708e0e7c8SDavid Howells _leave(" = 0"); 8808e0e7c8SDavid Howells return 0; 890e119b41SDavid Howells 900e119b41SDavid Howells error_2: 910e119b41SDavid Howells sock_release(socket); 920e119b41SDavid Howells error_1: 930e119b41SDavid Howells _leave(" = %d", ret); 940e119b41SDavid Howells return ret; 9508e0e7c8SDavid Howells } 9608e0e7c8SDavid Howells 9708e0e7c8SDavid Howells /* 9808e0e7c8SDavid Howells * close the RxRPC socket AFS was using 9908e0e7c8SDavid Howells */ 100f044c884SDavid Howells void afs_close_socket(struct afs_net *net) 10108e0e7c8SDavid Howells { 10208e0e7c8SDavid Howells _enter(""); 10308e0e7c8SDavid Howells 104f044c884SDavid Howells kernel_listen(net->socket, 0); 105341f741fSDavid Howells flush_workqueue(afs_async_calls); 106341f741fSDavid Howells 107f044c884SDavid Howells if (net->spare_incoming_call) { 108f044c884SDavid Howells afs_put_call(net->spare_incoming_call); 109f044c884SDavid Howells net->spare_incoming_call = NULL; 11000e90712SDavid Howells } 11100e90712SDavid Howells 112f044c884SDavid Howells _debug("outstanding %u", atomic_read(&net->nr_outstanding_calls)); 113ab1fbe32SPeter Zijlstra wait_var_event(&net->nr_outstanding_calls, 114ab1fbe32SPeter Zijlstra !atomic_read(&net->nr_outstanding_calls)); 1152f02f7aeSDavid Howells _debug("no outstanding calls"); 1162f02f7aeSDavid Howells 117f044c884SDavid Howells kernel_sock_shutdown(net->socket, SHUT_RDWR); 118248f219cSDavid Howells flush_workqueue(afs_async_calls); 119f044c884SDavid Howells sock_release(net->socket); 12008e0e7c8SDavid Howells 12108e0e7c8SDavid Howells _debug("dework"); 12208e0e7c8SDavid Howells _leave(""); 12308e0e7c8SDavid Howells } 12408e0e7c8SDavid Howells 12508e0e7c8SDavid Howells /* 126341f741fSDavid Howells * Allocate a call. 12700d3b7a4SDavid Howells */ 128f044c884SDavid Howells static struct afs_call *afs_alloc_call(struct afs_net *net, 129f044c884SDavid Howells const struct afs_call_type *type, 130341f741fSDavid Howells gfp_t gfp) 13100d3b7a4SDavid Howells { 132341f741fSDavid Howells struct afs_call *call; 133341f741fSDavid Howells int o; 13400d3b7a4SDavid Howells 135341f741fSDavid Howells call = kzalloc(sizeof(*call), gfp); 136341f741fSDavid Howells if (!call) 137341f741fSDavid Howells return NULL; 13800d3b7a4SDavid Howells 139341f741fSDavid Howells call->type = type; 140f044c884SDavid Howells call->net = net; 141a25e21f0SDavid Howells call->debug_id = atomic_inc_return(&rxrpc_debug_id); 142341f741fSDavid Howells atomic_set(&call->usage, 1); 143341f741fSDavid Howells INIT_WORK(&call->async_work, afs_process_async_call); 144341f741fSDavid Howells init_waitqueue_head(&call->waitq); 14598bf40cdSDavid Howells spin_lock_init(&call->state_lock); 1462f02f7aeSDavid Howells 147f044c884SDavid Howells o = atomic_inc_return(&net->nr_outstanding_calls); 148341f741fSDavid Howells trace_afs_call(call, afs_call_trace_alloc, 1, o, 149341f741fSDavid Howells __builtin_return_address(0)); 150341f741fSDavid Howells return call; 15100d3b7a4SDavid Howells } 15200d3b7a4SDavid Howells 15300d3b7a4SDavid Howells /* 154341f741fSDavid Howells * Dispose of a reference on a call. 1556c67c7c3SDavid Howells */ 156341f741fSDavid Howells void afs_put_call(struct afs_call *call) 1576c67c7c3SDavid Howells { 158f044c884SDavid Howells struct afs_net *net = call->net; 159341f741fSDavid Howells int n = atomic_dec_return(&call->usage); 160f044c884SDavid Howells int o = atomic_read(&net->nr_outstanding_calls); 161341f741fSDavid Howells 162341f741fSDavid Howells trace_afs_call(call, afs_call_trace_put, n + 1, o, 163341f741fSDavid Howells __builtin_return_address(0)); 164341f741fSDavid Howells 165341f741fSDavid Howells ASSERTCMP(n, >=, 0); 166341f741fSDavid Howells if (n == 0) { 167341f741fSDavid Howells ASSERT(!work_pending(&call->async_work)); 168341f741fSDavid Howells ASSERT(call->type->name != NULL); 169341f741fSDavid Howells 1706c67c7c3SDavid Howells if (call->rxcall) { 171f044c884SDavid Howells rxrpc_kernel_end_call(net->socket, call->rxcall); 1726c67c7c3SDavid Howells call->rxcall = NULL; 1736c67c7c3SDavid Howells } 1746cf12869SNathaniel Wesley Filardo if (call->type->destructor) 1756c67c7c3SDavid Howells call->type->destructor(call); 176341f741fSDavid Howells 177d0676a16SDavid Howells afs_put_server(call->net, call->cm_server); 178d2ddc776SDavid Howells afs_put_cb_interest(call->net, call->cbi); 179341f741fSDavid Howells kfree(call->request); 180a25e21f0SDavid Howells 181a25e21f0SDavid Howells trace_afs_call(call, afs_call_trace_free, 0, o, 182a25e21f0SDavid Howells __builtin_return_address(0)); 183341f741fSDavid Howells kfree(call); 184341f741fSDavid Howells 185f044c884SDavid Howells o = atomic_dec_return(&net->nr_outstanding_calls); 186341f741fSDavid Howells if (o == 0) 187ab1fbe32SPeter Zijlstra wake_up_var(&net->nr_outstanding_calls); 188341f741fSDavid Howells } 1896cf12869SNathaniel Wesley Filardo } 1906cf12869SNathaniel Wesley Filardo 1916cf12869SNathaniel Wesley Filardo /* 192341f741fSDavid Howells * Queue the call for actual work. Returns 0 unconditionally for convenience. 1936cf12869SNathaniel Wesley Filardo */ 194341f741fSDavid Howells int afs_queue_call_work(struct afs_call *call) 1956cf12869SNathaniel Wesley Filardo { 196341f741fSDavid Howells int u = atomic_inc_return(&call->usage); 197341f741fSDavid Howells 198341f741fSDavid Howells trace_afs_call(call, afs_call_trace_work, u, 199f044c884SDavid Howells atomic_read(&call->net->nr_outstanding_calls), 200341f741fSDavid Howells __builtin_return_address(0)); 201341f741fSDavid Howells 202341f741fSDavid Howells INIT_WORK(&call->work, call->type->work); 203341f741fSDavid Howells 204341f741fSDavid Howells if (!queue_work(afs_wq, &call->work)) 205341f741fSDavid Howells afs_put_call(call); 206341f741fSDavid Howells return 0; 2076c67c7c3SDavid Howells } 2086c67c7c3SDavid Howells 2096c67c7c3SDavid Howells /* 21008e0e7c8SDavid Howells * allocate a call with flat request and reply buffers 21108e0e7c8SDavid Howells */ 212f044c884SDavid Howells struct afs_call *afs_alloc_flat_call(struct afs_net *net, 213f044c884SDavid Howells const struct afs_call_type *type, 214d001648eSDavid Howells size_t request_size, size_t reply_max) 21508e0e7c8SDavid Howells { 21608e0e7c8SDavid Howells struct afs_call *call; 21708e0e7c8SDavid Howells 218f044c884SDavid Howells call = afs_alloc_call(net, type, GFP_NOFS); 21908e0e7c8SDavid Howells if (!call) 22008e0e7c8SDavid Howells goto nomem_call; 22108e0e7c8SDavid Howells 22200d3b7a4SDavid Howells if (request_size) { 223341f741fSDavid Howells call->request_size = request_size; 22400d3b7a4SDavid Howells call->request = kmalloc(request_size, GFP_NOFS); 22500d3b7a4SDavid Howells if (!call->request) 22600d3b7a4SDavid Howells goto nomem_free; 22700d3b7a4SDavid Howells } 22800d3b7a4SDavid Howells 229d001648eSDavid Howells if (reply_max) { 230341f741fSDavid Howells call->reply_max = reply_max; 231d001648eSDavid Howells call->buffer = kmalloc(reply_max, GFP_NOFS); 23200d3b7a4SDavid Howells if (!call->buffer) 23300d3b7a4SDavid Howells goto nomem_free; 23400d3b7a4SDavid Howells } 23500d3b7a4SDavid Howells 236025db80cSDavid Howells call->operation_ID = type->op; 23708e0e7c8SDavid Howells init_waitqueue_head(&call->waitq); 23808e0e7c8SDavid Howells return call; 23908e0e7c8SDavid Howells 24000d3b7a4SDavid Howells nomem_free: 241341f741fSDavid Howells afs_put_call(call); 24208e0e7c8SDavid Howells nomem_call: 24308e0e7c8SDavid Howells return NULL; 24408e0e7c8SDavid Howells } 24508e0e7c8SDavid Howells 24608e0e7c8SDavid Howells /* 24708e0e7c8SDavid Howells * clean up a call with flat buffer 24808e0e7c8SDavid Howells */ 24908e0e7c8SDavid Howells void afs_flat_call_destructor(struct afs_call *call) 25008e0e7c8SDavid Howells { 25108e0e7c8SDavid Howells _enter(""); 25208e0e7c8SDavid Howells 25308e0e7c8SDavid Howells kfree(call->request); 25408e0e7c8SDavid Howells call->request = NULL; 25508e0e7c8SDavid Howells kfree(call->buffer); 25608e0e7c8SDavid Howells call->buffer = NULL; 25708e0e7c8SDavid Howells } 25808e0e7c8SDavid Howells 2592f5705a5SDavid Howells #define AFS_BVEC_MAX 8 2602f5705a5SDavid Howells 2612f5705a5SDavid Howells /* 2622f5705a5SDavid Howells * Load the given bvec with the next few pages. 2632f5705a5SDavid Howells */ 2642f5705a5SDavid Howells static void afs_load_bvec(struct afs_call *call, struct msghdr *msg, 2652f5705a5SDavid Howells struct bio_vec *bv, pgoff_t first, pgoff_t last, 2662f5705a5SDavid Howells unsigned offset) 2672f5705a5SDavid Howells { 2682f5705a5SDavid Howells struct page *pages[AFS_BVEC_MAX]; 2692f5705a5SDavid Howells unsigned int nr, n, i, to, bytes = 0; 2702f5705a5SDavid Howells 2712f5705a5SDavid Howells nr = min_t(pgoff_t, last - first + 1, AFS_BVEC_MAX); 2722f5705a5SDavid Howells n = find_get_pages_contig(call->mapping, first, nr, pages); 2732f5705a5SDavid Howells ASSERTCMP(n, ==, nr); 2742f5705a5SDavid Howells 2752f5705a5SDavid Howells msg->msg_flags |= MSG_MORE; 2762f5705a5SDavid Howells for (i = 0; i < nr; i++) { 2772f5705a5SDavid Howells to = PAGE_SIZE; 2782f5705a5SDavid Howells if (first + i >= last) { 2792f5705a5SDavid Howells to = call->last_to; 2802f5705a5SDavid Howells msg->msg_flags &= ~MSG_MORE; 2812f5705a5SDavid Howells } 2822f5705a5SDavid Howells bv[i].bv_page = pages[i]; 2832f5705a5SDavid Howells bv[i].bv_len = to - offset; 2842f5705a5SDavid Howells bv[i].bv_offset = offset; 2852f5705a5SDavid Howells bytes += to - offset; 2862f5705a5SDavid Howells offset = 0; 2872f5705a5SDavid Howells } 2882f5705a5SDavid Howells 289aa563d7bSDavid Howells iov_iter_bvec(&msg->msg_iter, WRITE, bv, nr, bytes); 2902f5705a5SDavid Howells } 2912f5705a5SDavid Howells 29208e0e7c8SDavid Howells /* 293e833251aSDavid Howells * Advance the AFS call state when the RxRPC call ends the transmit phase. 294e833251aSDavid Howells */ 295e833251aSDavid Howells static void afs_notify_end_request_tx(struct sock *sock, 296e833251aSDavid Howells struct rxrpc_call *rxcall, 297e833251aSDavid Howells unsigned long call_user_ID) 298e833251aSDavid Howells { 299e833251aSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 300e833251aSDavid Howells 30198bf40cdSDavid Howells afs_set_call_state(call, AFS_CALL_CL_REQUESTING, AFS_CALL_CL_AWAIT_REPLY); 302e833251aSDavid Howells } 303e833251aSDavid Howells 304e833251aSDavid Howells /* 30531143d5dSDavid Howells * attach the data from a bunch of pages on an inode to a call 30631143d5dSDavid Howells */ 30739c6aceaSAl Viro static int afs_send_pages(struct afs_call *call, struct msghdr *msg) 30831143d5dSDavid Howells { 3092f5705a5SDavid Howells struct bio_vec bv[AFS_BVEC_MAX]; 3102f5705a5SDavid Howells unsigned int bytes, nr, loop, offset; 31131143d5dSDavid Howells pgoff_t first = call->first, last = call->last; 31231143d5dSDavid Howells int ret; 31331143d5dSDavid Howells 31431143d5dSDavid Howells offset = call->first_offset; 31531143d5dSDavid Howells call->first_offset = 0; 31631143d5dSDavid Howells 31731143d5dSDavid Howells do { 3182f5705a5SDavid Howells afs_load_bvec(call, msg, bv, first, last, offset); 3192c099014SDavid Howells trace_afs_send_pages(call, msg, first, last, offset); 3202c099014SDavid Howells 32131143d5dSDavid Howells offset = 0; 3222f5705a5SDavid Howells bytes = msg->msg_iter.count; 3232f5705a5SDavid Howells nr = msg->msg_iter.nr_segs; 32431143d5dSDavid Howells 325f044c884SDavid Howells ret = rxrpc_kernel_send_data(call->net->socket, call->rxcall, msg, 326e833251aSDavid Howells bytes, afs_notify_end_request_tx); 3272f5705a5SDavid Howells for (loop = 0; loop < nr; loop++) 3282f5705a5SDavid Howells put_page(bv[loop].bv_page); 32931143d5dSDavid Howells if (ret < 0) 33031143d5dSDavid Howells break; 33131143d5dSDavid Howells 3322f5705a5SDavid Howells first += nr; 3335bbf5d39SDavid Howells } while (first <= last); 33431143d5dSDavid Howells 3352c099014SDavid Howells trace_afs_sent_pages(call, call->first, last, first, ret); 33631143d5dSDavid Howells return ret; 33731143d5dSDavid Howells } 33831143d5dSDavid Howells 33931143d5dSDavid Howells /* 34008e0e7c8SDavid Howells * initiate a call 34108e0e7c8SDavid Howells */ 3428b2a464cSDavid Howells long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, 3434d9df986SDavid Howells gfp_t gfp, bool async) 34408e0e7c8SDavid Howells { 3458b2a464cSDavid Howells struct sockaddr_rxrpc *srx = ac->addr; 34608e0e7c8SDavid Howells struct rxrpc_call *rxcall; 34708e0e7c8SDavid Howells struct msghdr msg; 34808e0e7c8SDavid Howells struct kvec iov[1]; 349e754eba6SDavid Howells s64 tx_total_len; 35008e0e7c8SDavid Howells int ret; 35108e0e7c8SDavid Howells 3524d9df986SDavid Howells _enter(",{%pISp},", &srx->transport); 35308e0e7c8SDavid Howells 35400d3b7a4SDavid Howells ASSERT(call->type != NULL); 35500d3b7a4SDavid Howells ASSERT(call->type->name != NULL); 35600d3b7a4SDavid Howells 35731143d5dSDavid Howells _debug("____MAKE %p{%s,%x} [%d]____", 35831143d5dSDavid Howells call, call->type->name, key_serial(call->key), 359f044c884SDavid Howells atomic_read(&call->net->nr_outstanding_calls)); 36000d3b7a4SDavid Howells 36156ff9c83SDavid Howells call->async = async; 36208e0e7c8SDavid Howells 363e754eba6SDavid Howells /* Work out the length we're going to transmit. This is awkward for 364e754eba6SDavid Howells * calls such as FS.StoreData where there's an extra injection of data 365e754eba6SDavid Howells * after the initial fixed part. 366e754eba6SDavid Howells */ 367e754eba6SDavid Howells tx_total_len = call->request_size; 368e754eba6SDavid Howells if (call->send_pages) { 3691199db60SDavid Howells if (call->last == call->first) { 370e754eba6SDavid Howells tx_total_len += call->last_to - call->first_offset; 3711199db60SDavid Howells } else { 3721199db60SDavid Howells /* It looks mathematically like you should be able to 3731199db60SDavid Howells * combine the following lines with the ones above, but 3741199db60SDavid Howells * unsigned arithmetic is fun when it wraps... 3751199db60SDavid Howells */ 3761199db60SDavid Howells tx_total_len += PAGE_SIZE - call->first_offset; 3771199db60SDavid Howells tx_total_len += call->last_to; 3781199db60SDavid Howells tx_total_len += (call->last - call->first - 1) * PAGE_SIZE; 3791199db60SDavid Howells } 380e754eba6SDavid Howells } 381e754eba6SDavid Howells 38208e0e7c8SDavid Howells /* create a call */ 3834d9df986SDavid Howells rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key, 384e754eba6SDavid Howells (unsigned long)call, 385e754eba6SDavid Howells tx_total_len, gfp, 38656ff9c83SDavid Howells (async ? 38756ff9c83SDavid Howells afs_wake_up_async_call : 388a68f4a27SDavid Howells afs_wake_up_call_waiter), 389a25e21f0SDavid Howells call->upgrade, 390a25e21f0SDavid Howells call->debug_id); 39108e0e7c8SDavid Howells if (IS_ERR(rxcall)) { 39208e0e7c8SDavid Howells ret = PTR_ERR(rxcall); 39308e0e7c8SDavid Howells goto error_kill_call; 39408e0e7c8SDavid Howells } 39508e0e7c8SDavid Howells 39608e0e7c8SDavid Howells call->rxcall = rxcall; 39708e0e7c8SDavid Howells 39808e0e7c8SDavid Howells /* send the request */ 39908e0e7c8SDavid Howells iov[0].iov_base = call->request; 40008e0e7c8SDavid Howells iov[0].iov_len = call->request_size; 40108e0e7c8SDavid Howells 40208e0e7c8SDavid Howells msg.msg_name = NULL; 40308e0e7c8SDavid Howells msg.msg_namelen = 0; 404aa563d7bSDavid Howells iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, call->request_size); 40508e0e7c8SDavid Howells msg.msg_control = NULL; 40608e0e7c8SDavid Howells msg.msg_controllen = 0; 407bc5e3a54SDavid Howells msg.msg_flags = MSG_WAITALL | (call->send_pages ? MSG_MORE : 0); 40808e0e7c8SDavid Howells 409f044c884SDavid Howells ret = rxrpc_kernel_send_data(call->net->socket, rxcall, 410e833251aSDavid Howells &msg, call->request_size, 411e833251aSDavid Howells afs_notify_end_request_tx); 41208e0e7c8SDavid Howells if (ret < 0) 41308e0e7c8SDavid Howells goto error_do_abort; 41408e0e7c8SDavid Howells 41531143d5dSDavid Howells if (call->send_pages) { 41639c6aceaSAl Viro ret = afs_send_pages(call, &msg); 41731143d5dSDavid Howells if (ret < 0) 41831143d5dSDavid Howells goto error_do_abort; 41931143d5dSDavid Howells } 42031143d5dSDavid Howells 42108e0e7c8SDavid Howells /* at this point, an async call may no longer exist as it may have 42208e0e7c8SDavid Howells * already completed */ 42356ff9c83SDavid Howells if (call->async) 42456ff9c83SDavid Howells return -EINPROGRESS; 42556ff9c83SDavid Howells 426d2ddc776SDavid Howells return afs_wait_for_call_to_complete(call, ac); 42708e0e7c8SDavid Howells 42808e0e7c8SDavid Howells error_do_abort: 42970af0e3bSDavid Howells call->state = AFS_CALL_COMPLETE; 43070af0e3bSDavid Howells if (ret != -ECONNABORTED) { 431f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, rxcall, 432f044c884SDavid Howells RX_USER_ABORT, ret, "KSD"); 43370af0e3bSDavid Howells } else { 434aa563d7bSDavid Howells iov_iter_kvec(&msg.msg_iter, READ, NULL, 0, 0); 435eb9950ebSDavid Howells rxrpc_kernel_recv_data(call->net->socket, rxcall, 436eb9950ebSDavid Howells &msg.msg_iter, false, 437eb9950ebSDavid Howells &call->abort_code, &call->service_id); 438d2ddc776SDavid Howells ac->abort_code = call->abort_code; 439d2ddc776SDavid Howells ac->responded = true; 44070af0e3bSDavid Howells } 441025db80cSDavid Howells call->error = ret; 442025db80cSDavid Howells trace_afs_call_done(call); 44308e0e7c8SDavid Howells error_kill_call: 444341f741fSDavid Howells afs_put_call(call); 445d2ddc776SDavid Howells ac->error = ret; 44608e0e7c8SDavid Howells _leave(" = %d", ret); 44708e0e7c8SDavid Howells return ret; 44808e0e7c8SDavid Howells } 44908e0e7c8SDavid Howells 45008e0e7c8SDavid Howells /* 45108e0e7c8SDavid Howells * deliver messages to a call 45208e0e7c8SDavid Howells */ 45308e0e7c8SDavid Howells static void afs_deliver_to_call(struct afs_call *call) 45408e0e7c8SDavid Howells { 45598bf40cdSDavid Howells enum afs_call_state state; 45698bf40cdSDavid Howells u32 abort_code, remote_abort = 0; 45708e0e7c8SDavid Howells int ret; 45808e0e7c8SDavid Howells 459d001648eSDavid Howells _enter("%s", call->type->name); 46008e0e7c8SDavid Howells 46198bf40cdSDavid Howells while (state = READ_ONCE(call->state), 46298bf40cdSDavid Howells state == AFS_CALL_CL_AWAIT_REPLY || 46398bf40cdSDavid Howells state == AFS_CALL_SV_AWAIT_OP_ID || 46498bf40cdSDavid Howells state == AFS_CALL_SV_AWAIT_REQUEST || 46598bf40cdSDavid Howells state == AFS_CALL_SV_AWAIT_ACK 466d001648eSDavid Howells ) { 46798bf40cdSDavid Howells if (state == AFS_CALL_SV_AWAIT_ACK) { 468eb9950ebSDavid Howells struct iov_iter iter; 469eb9950ebSDavid Howells 470aa563d7bSDavid Howells iov_iter_kvec(&iter, READ, NULL, 0, 0); 471f044c884SDavid Howells ret = rxrpc_kernel_recv_data(call->net->socket, 472eb9950ebSDavid Howells call->rxcall, &iter, false, 47398bf40cdSDavid Howells &remote_abort, 474a68f4a27SDavid Howells &call->service_id); 475eb9950ebSDavid Howells trace_afs_recv_data(call, 0, 0, false, ret); 4768e8d7f13SDavid Howells 477d001648eSDavid Howells if (ret == -EINPROGRESS || ret == -EAGAIN) 478d001648eSDavid Howells return; 47998bf40cdSDavid Howells if (ret < 0 || ret == 1) { 48098bf40cdSDavid Howells if (ret == 1) 48198bf40cdSDavid Howells ret = 0; 482025db80cSDavid Howells goto call_complete; 48398bf40cdSDavid Howells } 484d001648eSDavid Howells return; 485d001648eSDavid Howells } 486d001648eSDavid Howells 487d001648eSDavid Howells ret = call->type->deliver(call); 48898bf40cdSDavid Howells state = READ_ONCE(call->state); 489d001648eSDavid Howells switch (ret) { 49008e0e7c8SDavid Howells case 0: 491f2686b09SDavid Howells if (state == AFS_CALL_CL_PROC_REPLY) { 492f2686b09SDavid Howells if (call->cbi) 493f2686b09SDavid Howells set_bit(AFS_SERVER_FL_MAY_HAVE_CB, 494f2686b09SDavid Howells &call->cbi->server->flags); 495025db80cSDavid Howells goto call_complete; 496f2686b09SDavid Howells } 49798bf40cdSDavid Howells ASSERTCMP(state, >, AFS_CALL_CL_PROC_REPLY); 498d001648eSDavid Howells goto done; 499d001648eSDavid Howells case -EINPROGRESS: 500d001648eSDavid Howells case -EAGAIN: 501d001648eSDavid Howells goto out; 50298bf40cdSDavid Howells case -EIO: 50370af0e3bSDavid Howells case -ECONNABORTED: 50498bf40cdSDavid Howells ASSERTCMP(state, ==, AFS_CALL_COMPLETE); 50598bf40cdSDavid Howells goto done; 50608e0e7c8SDavid Howells case -ENOTSUPP: 5071157f153SDavid Howells abort_code = RXGEN_OPCODE; 508f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 5093a92789aSDavid Howells abort_code, ret, "KIV"); 51098bf40cdSDavid Howells goto local_abort; 511d001648eSDavid Howells case -ENODATA: 512d001648eSDavid Howells case -EBADMSG: 513d001648eSDavid Howells case -EMSGSIZE: 51408e0e7c8SDavid Howells default: 51508e0e7c8SDavid Howells abort_code = RXGEN_CC_UNMARSHAL; 51698bf40cdSDavid Howells if (state != AFS_CALL_CL_AWAIT_REPLY) 51708e0e7c8SDavid Howells abort_code = RXGEN_SS_UNMARSHAL; 518f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 5193a92789aSDavid Howells abort_code, -EBADMSG, "KUM"); 52098bf40cdSDavid Howells goto local_abort; 52108e0e7c8SDavid Howells } 52208e0e7c8SDavid Howells } 52308e0e7c8SDavid Howells 524d001648eSDavid Howells done: 52598bf40cdSDavid Howells if (state == AFS_CALL_COMPLETE && call->incoming) 526341f741fSDavid Howells afs_put_call(call); 527d001648eSDavid Howells out: 52808e0e7c8SDavid Howells _leave(""); 529d001648eSDavid Howells return; 530d001648eSDavid Howells 53198bf40cdSDavid Howells local_abort: 53298bf40cdSDavid Howells abort_code = 0; 533025db80cSDavid Howells call_complete: 53498bf40cdSDavid Howells afs_set_call_complete(call, ret, remote_abort); 53598bf40cdSDavid Howells state = AFS_CALL_COMPLETE; 536d001648eSDavid Howells goto done; 53708e0e7c8SDavid Howells } 53808e0e7c8SDavid Howells 53908e0e7c8SDavid Howells /* 54008e0e7c8SDavid Howells * wait synchronously for a call to complete 54108e0e7c8SDavid Howells */ 542d2ddc776SDavid Howells static long afs_wait_for_call_to_complete(struct afs_call *call, 543d2ddc776SDavid Howells struct afs_addr_cursor *ac) 54408e0e7c8SDavid Howells { 545bc5e3a54SDavid Howells signed long rtt2, timeout; 54633cd7f2bSDavid Howells long ret; 547bc5e3a54SDavid Howells u64 rtt; 548bc5e3a54SDavid Howells u32 life, last_life; 54908e0e7c8SDavid Howells 55008e0e7c8SDavid Howells DECLARE_WAITQUEUE(myself, current); 55108e0e7c8SDavid Howells 55208e0e7c8SDavid Howells _enter(""); 55308e0e7c8SDavid Howells 554f044c884SDavid Howells rtt = rxrpc_kernel_get_rtt(call->net->socket, call->rxcall); 555bc5e3a54SDavid Howells rtt2 = nsecs_to_jiffies64(rtt) * 2; 556bc5e3a54SDavid Howells if (rtt2 < 2) 557bc5e3a54SDavid Howells rtt2 = 2; 558bc5e3a54SDavid Howells 559bc5e3a54SDavid Howells timeout = rtt2; 560f044c884SDavid Howells last_life = rxrpc_kernel_check_life(call->net->socket, call->rxcall); 561bc5e3a54SDavid Howells 56208e0e7c8SDavid Howells add_wait_queue(&call->waitq, &myself); 56308e0e7c8SDavid Howells for (;;) { 564bc5e3a54SDavid Howells set_current_state(TASK_UNINTERRUPTIBLE); 56508e0e7c8SDavid Howells 56608e0e7c8SDavid Howells /* deliver any messages that are in the queue */ 56798bf40cdSDavid Howells if (!afs_check_call_state(call, AFS_CALL_COMPLETE) && 56898bf40cdSDavid Howells call->need_attention) { 569d001648eSDavid Howells call->need_attention = false; 57008e0e7c8SDavid Howells __set_current_state(TASK_RUNNING); 57108e0e7c8SDavid Howells afs_deliver_to_call(call); 57208e0e7c8SDavid Howells continue; 57308e0e7c8SDavid Howells } 57408e0e7c8SDavid Howells 57598bf40cdSDavid Howells if (afs_check_call_state(call, AFS_CALL_COMPLETE)) 57608e0e7c8SDavid Howells break; 577bc5e3a54SDavid Howells 578f044c884SDavid Howells life = rxrpc_kernel_check_life(call->net->socket, call->rxcall); 579bc5e3a54SDavid Howells if (timeout == 0 && 580bc5e3a54SDavid Howells life == last_life && signal_pending(current)) 581bc5e3a54SDavid Howells break; 582bc5e3a54SDavid Howells 583bc5e3a54SDavid Howells if (life != last_life) { 584bc5e3a54SDavid Howells timeout = rtt2; 585bc5e3a54SDavid Howells last_life = life; 586bc5e3a54SDavid Howells } 587bc5e3a54SDavid Howells 588bc5e3a54SDavid Howells timeout = schedule_timeout(timeout); 58908e0e7c8SDavid Howells } 59008e0e7c8SDavid Howells 59108e0e7c8SDavid Howells remove_wait_queue(&call->waitq, &myself); 59208e0e7c8SDavid Howells __set_current_state(TASK_RUNNING); 59308e0e7c8SDavid Howells 594954cd6dcSDavid Howells /* Kill off the call if it's still live. */ 59598bf40cdSDavid Howells if (!afs_check_call_state(call, AFS_CALL_COMPLETE)) { 596954cd6dcSDavid Howells _debug("call interrupted"); 597d2ddc776SDavid Howells if (rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 59898bf40cdSDavid Howells RX_USER_ABORT, -EINTR, "KWI")) 59998bf40cdSDavid Howells afs_set_call_complete(call, -EINTR, 0); 60008e0e7c8SDavid Howells } 60108e0e7c8SDavid Howells 60298bf40cdSDavid Howells spin_lock_bh(&call->state_lock); 603d2ddc776SDavid Howells ac->abort_code = call->abort_code; 604d2ddc776SDavid Howells ac->error = call->error; 60598bf40cdSDavid Howells spin_unlock_bh(&call->state_lock); 606d2ddc776SDavid Howells 607d2ddc776SDavid Howells ret = ac->error; 608d2ddc776SDavid Howells switch (ret) { 609d2ddc776SDavid Howells case 0: 610d2ddc776SDavid Howells if (call->ret_reply0) { 61133cd7f2bSDavid Howells ret = (long)call->reply[0]; 61233cd7f2bSDavid Howells call->reply[0] = NULL; 61333cd7f2bSDavid Howells } 614d2ddc776SDavid Howells /* Fall through */ 615d2ddc776SDavid Howells case -ECONNABORTED: 616d2ddc776SDavid Howells ac->responded = true; 617d2ddc776SDavid Howells break; 618d2ddc776SDavid Howells } 61933cd7f2bSDavid Howells 62008e0e7c8SDavid Howells _debug("call complete"); 621341f741fSDavid Howells afs_put_call(call); 62233cd7f2bSDavid Howells _leave(" = %p", (void *)ret); 62308e0e7c8SDavid Howells return ret; 62408e0e7c8SDavid Howells } 62508e0e7c8SDavid Howells 62608e0e7c8SDavid Howells /* 62708e0e7c8SDavid Howells * wake up a waiting call 62808e0e7c8SDavid Howells */ 629d001648eSDavid Howells static void afs_wake_up_call_waiter(struct sock *sk, struct rxrpc_call *rxcall, 630d001648eSDavid Howells unsigned long call_user_ID) 63108e0e7c8SDavid Howells { 632d001648eSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 633d001648eSDavid Howells 634d001648eSDavid Howells call->need_attention = true; 63508e0e7c8SDavid Howells wake_up(&call->waitq); 63608e0e7c8SDavid Howells } 63708e0e7c8SDavid Howells 63808e0e7c8SDavid Howells /* 63908e0e7c8SDavid Howells * wake up an asynchronous call 64008e0e7c8SDavid Howells */ 641d001648eSDavid Howells static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall, 642d001648eSDavid Howells unsigned long call_user_ID) 64308e0e7c8SDavid Howells { 644d001648eSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 645341f741fSDavid Howells int u; 646d001648eSDavid Howells 6478e8d7f13SDavid Howells trace_afs_notify_call(rxcall, call); 648d001648eSDavid Howells call->need_attention = true; 649341f741fSDavid Howells 650bfc18e38SMark Rutland u = atomic_fetch_add_unless(&call->usage, 1, 0); 651341f741fSDavid Howells if (u != 0) { 652341f741fSDavid Howells trace_afs_call(call, afs_call_trace_wake, u, 653f044c884SDavid Howells atomic_read(&call->net->nr_outstanding_calls), 654341f741fSDavid Howells __builtin_return_address(0)); 655341f741fSDavid Howells 656341f741fSDavid Howells if (!queue_work(afs_async_calls, &call->async_work)) 657341f741fSDavid Howells afs_put_call(call); 658341f741fSDavid Howells } 65908e0e7c8SDavid Howells } 66008e0e7c8SDavid Howells 66108e0e7c8SDavid Howells /* 662341f741fSDavid Howells * Delete an asynchronous call. The work item carries a ref to the call struct 663341f741fSDavid Howells * that we need to release. 66408e0e7c8SDavid Howells */ 665d001648eSDavid Howells static void afs_delete_async_call(struct work_struct *work) 66608e0e7c8SDavid Howells { 667d001648eSDavid Howells struct afs_call *call = container_of(work, struct afs_call, async_work); 668d001648eSDavid Howells 66908e0e7c8SDavid Howells _enter(""); 67008e0e7c8SDavid Howells 671341f741fSDavid Howells afs_put_call(call); 67208e0e7c8SDavid Howells 67308e0e7c8SDavid Howells _leave(""); 67408e0e7c8SDavid Howells } 67508e0e7c8SDavid Howells 67608e0e7c8SDavid Howells /* 677341f741fSDavid Howells * Perform I/O processing on an asynchronous call. The work item carries a ref 678341f741fSDavid Howells * to the call struct that we either need to release or to pass on. 67908e0e7c8SDavid Howells */ 680d001648eSDavid Howells static void afs_process_async_call(struct work_struct *work) 68108e0e7c8SDavid Howells { 682d001648eSDavid Howells struct afs_call *call = container_of(work, struct afs_call, async_work); 683d001648eSDavid Howells 68408e0e7c8SDavid Howells _enter(""); 68508e0e7c8SDavid Howells 686d001648eSDavid Howells if (call->state < AFS_CALL_COMPLETE && call->need_attention) { 687d001648eSDavid Howells call->need_attention = false; 68808e0e7c8SDavid Howells afs_deliver_to_call(call); 689d001648eSDavid Howells } 69008e0e7c8SDavid Howells 69156ff9c83SDavid Howells if (call->state == AFS_CALL_COMPLETE) { 692341f741fSDavid Howells /* We have two refs to release - one from the alloc and one 693341f741fSDavid Howells * queued with the work item - and we can't just deallocate the 694341f741fSDavid Howells * call because the work item may be queued again. 695341f741fSDavid Howells */ 696d001648eSDavid Howells call->async_work.func = afs_delete_async_call; 697341f741fSDavid Howells if (!queue_work(afs_async_calls, &call->async_work)) 698341f741fSDavid Howells afs_put_call(call); 69908e0e7c8SDavid Howells } 70008e0e7c8SDavid Howells 701341f741fSDavid Howells afs_put_call(call); 70208e0e7c8SDavid Howells _leave(""); 70308e0e7c8SDavid Howells } 70408e0e7c8SDavid Howells 70500e90712SDavid Howells static void afs_rx_attach(struct rxrpc_call *rxcall, unsigned long user_call_ID) 70600e90712SDavid Howells { 70700e90712SDavid Howells struct afs_call *call = (struct afs_call *)user_call_ID; 70800e90712SDavid Howells 70900e90712SDavid Howells call->rxcall = rxcall; 71000e90712SDavid Howells } 71100e90712SDavid Howells 71200e90712SDavid Howells /* 71300e90712SDavid Howells * Charge the incoming call preallocation. 71400e90712SDavid Howells */ 715f044c884SDavid Howells void afs_charge_preallocation(struct work_struct *work) 71600e90712SDavid Howells { 717f044c884SDavid Howells struct afs_net *net = 718f044c884SDavid Howells container_of(work, struct afs_net, charge_preallocation_work); 719f044c884SDavid Howells struct afs_call *call = net->spare_incoming_call; 72000e90712SDavid Howells 72100e90712SDavid Howells for (;;) { 72200e90712SDavid Howells if (!call) { 723f044c884SDavid Howells call = afs_alloc_call(net, &afs_RXCMxxxx, GFP_KERNEL); 72400e90712SDavid Howells if (!call) 72500e90712SDavid Howells break; 72600e90712SDavid Howells 72756ff9c83SDavid Howells call->async = true; 72898bf40cdSDavid Howells call->state = AFS_CALL_SV_AWAIT_OP_ID; 72956ff9c83SDavid Howells init_waitqueue_head(&call->waitq); 73000e90712SDavid Howells } 73100e90712SDavid Howells 732f044c884SDavid Howells if (rxrpc_kernel_charge_accept(net->socket, 73300e90712SDavid Howells afs_wake_up_async_call, 73400e90712SDavid Howells afs_rx_attach, 73500e90712SDavid Howells (unsigned long)call, 736a25e21f0SDavid Howells GFP_KERNEL, 737a25e21f0SDavid Howells call->debug_id) < 0) 73800e90712SDavid Howells break; 73900e90712SDavid Howells call = NULL; 74000e90712SDavid Howells } 741f044c884SDavid Howells net->spare_incoming_call = call; 74200e90712SDavid Howells } 74300e90712SDavid Howells 74400e90712SDavid Howells /* 74500e90712SDavid Howells * Discard a preallocated call when a socket is shut down. 74600e90712SDavid Howells */ 74700e90712SDavid Howells static void afs_rx_discard_new_call(struct rxrpc_call *rxcall, 74800e90712SDavid Howells unsigned long user_call_ID) 74900e90712SDavid Howells { 75000e90712SDavid Howells struct afs_call *call = (struct afs_call *)user_call_ID; 75100e90712SDavid Howells 75200e90712SDavid Howells call->rxcall = NULL; 753341f741fSDavid Howells afs_put_call(call); 75400e90712SDavid Howells } 75500e90712SDavid Howells 75608e0e7c8SDavid Howells /* 757d001648eSDavid Howells * Notification of an incoming call. 758d001648eSDavid Howells */ 75900e90712SDavid Howells static void afs_rx_new_call(struct sock *sk, struct rxrpc_call *rxcall, 76000e90712SDavid Howells unsigned long user_call_ID) 761d001648eSDavid Howells { 762f044c884SDavid Howells struct afs_net *net = afs_sock2net(sk); 763f044c884SDavid Howells 764f044c884SDavid Howells queue_work(afs_wq, &net->charge_preallocation_work); 765d001648eSDavid Howells } 766d001648eSDavid Howells 767d001648eSDavid Howells /* 768372ee163SDavid Howells * Grab the operation ID from an incoming cache manager call. The socket 769372ee163SDavid Howells * buffer is discarded on error or if we don't yet have sufficient data. 77008e0e7c8SDavid Howells */ 771d001648eSDavid Howells static int afs_deliver_cm_op_id(struct afs_call *call) 77208e0e7c8SDavid Howells { 773d001648eSDavid Howells int ret; 77408e0e7c8SDavid Howells 775d001648eSDavid Howells _enter("{%zu}", call->offset); 77608e0e7c8SDavid Howells 77708e0e7c8SDavid Howells ASSERTCMP(call->offset, <, 4); 77808e0e7c8SDavid Howells 77908e0e7c8SDavid Howells /* the operation ID forms the first four bytes of the request data */ 78050a2c953SDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 781d001648eSDavid Howells if (ret < 0) 782d001648eSDavid Howells return ret; 78308e0e7c8SDavid Howells 78450a2c953SDavid Howells call->operation_ID = ntohl(call->tmp); 78598bf40cdSDavid Howells afs_set_call_state(call, AFS_CALL_SV_AWAIT_OP_ID, AFS_CALL_SV_AWAIT_REQUEST); 786d001648eSDavid Howells call->offset = 0; 78708e0e7c8SDavid Howells 78808e0e7c8SDavid Howells /* ask the cache manager to route the call (it'll change the call type 78908e0e7c8SDavid Howells * if successful) */ 79008e0e7c8SDavid Howells if (!afs_cm_incoming_call(call)) 79108e0e7c8SDavid Howells return -ENOTSUPP; 79208e0e7c8SDavid Howells 7938e8d7f13SDavid Howells trace_afs_cb_call(call); 7948e8d7f13SDavid Howells 79508e0e7c8SDavid Howells /* pass responsibility for the remainer of this message off to the 79608e0e7c8SDavid Howells * cache manager op */ 797d001648eSDavid Howells return call->type->deliver(call); 79808e0e7c8SDavid Howells } 79908e0e7c8SDavid Howells 80008e0e7c8SDavid Howells /* 801e833251aSDavid Howells * Advance the AFS call state when an RxRPC service call ends the transmit 802e833251aSDavid Howells * phase. 803e833251aSDavid Howells */ 804e833251aSDavid Howells static void afs_notify_end_reply_tx(struct sock *sock, 805e833251aSDavid Howells struct rxrpc_call *rxcall, 806e833251aSDavid Howells unsigned long call_user_ID) 807e833251aSDavid Howells { 808e833251aSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 809e833251aSDavid Howells 81098bf40cdSDavid Howells afs_set_call_state(call, AFS_CALL_SV_REPLYING, AFS_CALL_SV_AWAIT_ACK); 811e833251aSDavid Howells } 812e833251aSDavid Howells 813e833251aSDavid Howells /* 81408e0e7c8SDavid Howells * send an empty reply 81508e0e7c8SDavid Howells */ 81608e0e7c8SDavid Howells void afs_send_empty_reply(struct afs_call *call) 81708e0e7c8SDavid Howells { 818f044c884SDavid Howells struct afs_net *net = call->net; 81908e0e7c8SDavid Howells struct msghdr msg; 82008e0e7c8SDavid Howells 82108e0e7c8SDavid Howells _enter(""); 82208e0e7c8SDavid Howells 823f044c884SDavid Howells rxrpc_kernel_set_tx_length(net->socket, call->rxcall, 0); 824e754eba6SDavid Howells 82508e0e7c8SDavid Howells msg.msg_name = NULL; 82608e0e7c8SDavid Howells msg.msg_namelen = 0; 827aa563d7bSDavid Howells iov_iter_kvec(&msg.msg_iter, WRITE, NULL, 0, 0); 82808e0e7c8SDavid Howells msg.msg_control = NULL; 82908e0e7c8SDavid Howells msg.msg_controllen = 0; 83008e0e7c8SDavid Howells msg.msg_flags = 0; 83108e0e7c8SDavid Howells 832f044c884SDavid Howells switch (rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, 0, 833e833251aSDavid Howells afs_notify_end_reply_tx)) { 83408e0e7c8SDavid Howells case 0: 83508e0e7c8SDavid Howells _leave(" [replied]"); 83608e0e7c8SDavid Howells return; 83708e0e7c8SDavid Howells 83808e0e7c8SDavid Howells case -ENOMEM: 83908e0e7c8SDavid Howells _debug("oom"); 840f044c884SDavid Howells rxrpc_kernel_abort_call(net->socket, call->rxcall, 8413a92789aSDavid Howells RX_USER_ABORT, -ENOMEM, "KOO"); 84208e0e7c8SDavid Howells default: 84308e0e7c8SDavid Howells _leave(" [error]"); 84408e0e7c8SDavid Howells return; 84508e0e7c8SDavid Howells } 84608e0e7c8SDavid Howells } 84708e0e7c8SDavid Howells 84808e0e7c8SDavid Howells /* 849b908fe6bSDavid Howells * send a simple reply 850b908fe6bSDavid Howells */ 851b908fe6bSDavid Howells void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) 852b908fe6bSDavid Howells { 853f044c884SDavid Howells struct afs_net *net = call->net; 854b908fe6bSDavid Howells struct msghdr msg; 8552e90b1c4SAl Viro struct kvec iov[1]; 856bd6dc742SDavid Howells int n; 857b908fe6bSDavid Howells 858b908fe6bSDavid Howells _enter(""); 859b908fe6bSDavid Howells 860f044c884SDavid Howells rxrpc_kernel_set_tx_length(net->socket, call->rxcall, len); 861e754eba6SDavid Howells 862b908fe6bSDavid Howells iov[0].iov_base = (void *) buf; 863b908fe6bSDavid Howells iov[0].iov_len = len; 864b908fe6bSDavid Howells msg.msg_name = NULL; 865b908fe6bSDavid Howells msg.msg_namelen = 0; 866aa563d7bSDavid Howells iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len); 867b908fe6bSDavid Howells msg.msg_control = NULL; 868b908fe6bSDavid Howells msg.msg_controllen = 0; 869b908fe6bSDavid Howells msg.msg_flags = 0; 870b908fe6bSDavid Howells 871f044c884SDavid Howells n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, len, 872e833251aSDavid Howells afs_notify_end_reply_tx); 873bd6dc742SDavid Howells if (n >= 0) { 8746c67c7c3SDavid Howells /* Success */ 875b908fe6bSDavid Howells _leave(" [replied]"); 876b908fe6bSDavid Howells return; 877bd6dc742SDavid Howells } 8786c67c7c3SDavid Howells 879bd6dc742SDavid Howells if (n == -ENOMEM) { 880b908fe6bSDavid Howells _debug("oom"); 881f044c884SDavid Howells rxrpc_kernel_abort_call(net->socket, call->rxcall, 8823a92789aSDavid Howells RX_USER_ABORT, -ENOMEM, "KOO"); 883bd6dc742SDavid Howells } 884b908fe6bSDavid Howells _leave(" [error]"); 885b908fe6bSDavid Howells } 886b908fe6bSDavid Howells 887b908fe6bSDavid Howells /* 888372ee163SDavid Howells * Extract a piece of data from the received data socket buffers. 88908e0e7c8SDavid Howells */ 890d001648eSDavid Howells int afs_extract_data(struct afs_call *call, void *buf, size_t count, 891d001648eSDavid Howells bool want_more) 89208e0e7c8SDavid Howells { 893f044c884SDavid Howells struct afs_net *net = call->net; 894eb9950ebSDavid Howells struct iov_iter iter; 895eb9950ebSDavid Howells struct kvec iov; 89698bf40cdSDavid Howells enum afs_call_state state; 8977888da95SDan Carpenter u32 remote_abort = 0; 898d001648eSDavid Howells int ret; 89908e0e7c8SDavid Howells 900d001648eSDavid Howells _enter("{%s,%zu},,%zu,%d", 901d001648eSDavid Howells call->type->name, call->offset, count, want_more); 90208e0e7c8SDavid Howells 903d001648eSDavid Howells ASSERTCMP(call->offset, <=, count); 90408e0e7c8SDavid Howells 905eb9950ebSDavid Howells iov.iov_base = buf + call->offset; 906eb9950ebSDavid Howells iov.iov_len = count - call->offset; 907aa563d7bSDavid Howells iov_iter_kvec(&iter, READ, &iov, 1, count - call->offset); 908eb9950ebSDavid Howells 909eb9950ebSDavid Howells ret = rxrpc_kernel_recv_data(net->socket, call->rxcall, &iter, 91098bf40cdSDavid Howells want_more, &remote_abort, 911a68f4a27SDavid Howells &call->service_id); 912eb9950ebSDavid Howells call->offset += (count - call->offset) - iov_iter_count(&iter); 9138e8d7f13SDavid Howells trace_afs_recv_data(call, count, call->offset, want_more, ret); 914d001648eSDavid Howells if (ret == 0 || ret == -EAGAIN) 915d001648eSDavid Howells return ret; 91608e0e7c8SDavid Howells 91798bf40cdSDavid Howells state = READ_ONCE(call->state); 918d001648eSDavid Howells if (ret == 1) { 91998bf40cdSDavid Howells switch (state) { 92098bf40cdSDavid Howells case AFS_CALL_CL_AWAIT_REPLY: 92198bf40cdSDavid Howells afs_set_call_state(call, state, AFS_CALL_CL_PROC_REPLY); 922d001648eSDavid Howells break; 92398bf40cdSDavid Howells case AFS_CALL_SV_AWAIT_REQUEST: 92498bf40cdSDavid Howells afs_set_call_state(call, state, AFS_CALL_SV_REPLYING); 925d001648eSDavid Howells break; 92698bf40cdSDavid Howells case AFS_CALL_COMPLETE: 92798bf40cdSDavid Howells kdebug("prem complete %d", call->error); 92898bf40cdSDavid Howells return -EIO; 929d001648eSDavid Howells default: 930d001648eSDavid Howells break; 93108e0e7c8SDavid Howells } 93208e0e7c8SDavid Howells return 0; 93308e0e7c8SDavid Howells } 934d001648eSDavid Howells 93598bf40cdSDavid Howells afs_set_call_complete(call, ret, remote_abort); 936d001648eSDavid Howells return ret; 937d001648eSDavid Howells } 9385f702c8eSDavid Howells 9395f702c8eSDavid Howells /* 9405f702c8eSDavid Howells * Log protocol error production. 9415f702c8eSDavid Howells */ 9425f702c8eSDavid Howells noinline int afs_protocol_error(struct afs_call *call, int error) 9435f702c8eSDavid Howells { 9445f702c8eSDavid Howells trace_afs_protocol_error(call, error, __builtin_return_address(0)); 9455f702c8eSDavid Howells return error; 9465f702c8eSDavid Howells } 947