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); 2333cd7f2bSDavid Howells static long afs_wait_for_call_to_complete(struct afs_call *); 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; 4408e0e7c8SDavid Howells int ret; 4508e0e7c8SDavid Howells 4608e0e7c8SDavid Howells _enter(""); 4708e0e7c8SDavid Howells 483838d3ecSDavid Howells ret = sock_create_kern(&init_net, AF_RXRPC, SOCK_DGRAM, PF_INET6, &socket); 490e119b41SDavid Howells if (ret < 0) 500e119b41SDavid Howells goto error_1; 5108e0e7c8SDavid Howells 5208e0e7c8SDavid Howells socket->sk->sk_allocation = GFP_NOFS; 5308e0e7c8SDavid Howells 5408e0e7c8SDavid Howells /* bind the callback manager's address to make this a server socket */ 553838d3ecSDavid Howells memset(&srx, 0, sizeof(srx)); 5608e0e7c8SDavid Howells srx.srx_family = AF_RXRPC; 5708e0e7c8SDavid Howells srx.srx_service = CM_SERVICE; 5808e0e7c8SDavid Howells srx.transport_type = SOCK_DGRAM; 593838d3ecSDavid Howells srx.transport_len = sizeof(srx.transport.sin6); 603838d3ecSDavid Howells srx.transport.sin6.sin6_family = AF_INET6; 613838d3ecSDavid Howells srx.transport.sin6.sin6_port = htons(AFS_CM_PORT); 6208e0e7c8SDavid Howells 6308e0e7c8SDavid Howells ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); 640e119b41SDavid Howells if (ret < 0) 650e119b41SDavid Howells goto error_2; 660e119b41SDavid Howells 6700e90712SDavid Howells rxrpc_kernel_new_call_notification(socket, afs_rx_new_call, 6800e90712SDavid Howells afs_rx_discard_new_call); 69d001648eSDavid Howells 700e119b41SDavid Howells ret = kernel_listen(socket, INT_MAX); 710e119b41SDavid Howells if (ret < 0) 720e119b41SDavid Howells goto error_2; 7308e0e7c8SDavid Howells 74f044c884SDavid Howells net->socket = socket; 75f044c884SDavid Howells afs_charge_preallocation(&net->charge_preallocation_work); 7608e0e7c8SDavid Howells _leave(" = 0"); 7708e0e7c8SDavid Howells return 0; 780e119b41SDavid Howells 790e119b41SDavid Howells error_2: 800e119b41SDavid Howells sock_release(socket); 810e119b41SDavid Howells error_1: 820e119b41SDavid Howells _leave(" = %d", ret); 830e119b41SDavid Howells return ret; 8408e0e7c8SDavid Howells } 8508e0e7c8SDavid Howells 8608e0e7c8SDavid Howells /* 8708e0e7c8SDavid Howells * close the RxRPC socket AFS was using 8808e0e7c8SDavid Howells */ 89f044c884SDavid Howells void afs_close_socket(struct afs_net *net) 9008e0e7c8SDavid Howells { 9108e0e7c8SDavid Howells _enter(""); 9208e0e7c8SDavid Howells 93f044c884SDavid Howells kernel_listen(net->socket, 0); 94341f741fSDavid Howells flush_workqueue(afs_async_calls); 95341f741fSDavid Howells 96f044c884SDavid Howells if (net->spare_incoming_call) { 97f044c884SDavid Howells afs_put_call(net->spare_incoming_call); 98f044c884SDavid Howells net->spare_incoming_call = NULL; 9900e90712SDavid Howells } 10000e90712SDavid Howells 101f044c884SDavid Howells _debug("outstanding %u", atomic_read(&net->nr_outstanding_calls)); 102f044c884SDavid Howells wait_on_atomic_t(&net->nr_outstanding_calls, atomic_t_wait, 1032f02f7aeSDavid Howells TASK_UNINTERRUPTIBLE); 1042f02f7aeSDavid Howells _debug("no outstanding calls"); 1052f02f7aeSDavid Howells 106f044c884SDavid Howells kernel_sock_shutdown(net->socket, SHUT_RDWR); 107248f219cSDavid Howells flush_workqueue(afs_async_calls); 108f044c884SDavid Howells sock_release(net->socket); 10908e0e7c8SDavid Howells 11008e0e7c8SDavid Howells _debug("dework"); 11108e0e7c8SDavid Howells _leave(""); 11208e0e7c8SDavid Howells } 11308e0e7c8SDavid Howells 11408e0e7c8SDavid Howells /* 115341f741fSDavid Howells * Allocate a call. 11600d3b7a4SDavid Howells */ 117f044c884SDavid Howells static struct afs_call *afs_alloc_call(struct afs_net *net, 118f044c884SDavid Howells const struct afs_call_type *type, 119341f741fSDavid Howells gfp_t gfp) 12000d3b7a4SDavid Howells { 121341f741fSDavid Howells struct afs_call *call; 122341f741fSDavid Howells int o; 12300d3b7a4SDavid Howells 124341f741fSDavid Howells call = kzalloc(sizeof(*call), gfp); 125341f741fSDavid Howells if (!call) 126341f741fSDavid Howells return NULL; 12700d3b7a4SDavid Howells 128341f741fSDavid Howells call->type = type; 129f044c884SDavid Howells call->net = net; 130341f741fSDavid Howells atomic_set(&call->usage, 1); 131341f741fSDavid Howells INIT_WORK(&call->async_work, afs_process_async_call); 132341f741fSDavid Howells init_waitqueue_head(&call->waitq); 1332f02f7aeSDavid Howells 134f044c884SDavid Howells o = atomic_inc_return(&net->nr_outstanding_calls); 135341f741fSDavid Howells trace_afs_call(call, afs_call_trace_alloc, 1, o, 136341f741fSDavid Howells __builtin_return_address(0)); 137341f741fSDavid Howells return call; 13800d3b7a4SDavid Howells } 13900d3b7a4SDavid Howells 14000d3b7a4SDavid Howells /* 141341f741fSDavid Howells * Dispose of a reference on a call. 1426c67c7c3SDavid Howells */ 143341f741fSDavid Howells void afs_put_call(struct afs_call *call) 1446c67c7c3SDavid Howells { 145f044c884SDavid Howells struct afs_net *net = call->net; 146341f741fSDavid Howells int n = atomic_dec_return(&call->usage); 147f044c884SDavid Howells int o = atomic_read(&net->nr_outstanding_calls); 148341f741fSDavid Howells 149341f741fSDavid Howells trace_afs_call(call, afs_call_trace_put, n + 1, o, 150341f741fSDavid Howells __builtin_return_address(0)); 151341f741fSDavid Howells 152341f741fSDavid Howells ASSERTCMP(n, >=, 0); 153341f741fSDavid Howells if (n == 0) { 154341f741fSDavid Howells ASSERT(!work_pending(&call->async_work)); 155341f741fSDavid Howells ASSERT(call->type->name != NULL); 156341f741fSDavid Howells 1576c67c7c3SDavid Howells if (call->rxcall) { 158f044c884SDavid Howells rxrpc_kernel_end_call(net->socket, call->rxcall); 1596c67c7c3SDavid Howells call->rxcall = NULL; 1606c67c7c3SDavid Howells } 1616cf12869SNathaniel Wesley Filardo if (call->type->destructor) 1626c67c7c3SDavid Howells call->type->destructor(call); 163341f741fSDavid Howells 164d0676a16SDavid Howells afs_put_server(call->net, call->cm_server); 165341f741fSDavid Howells kfree(call->request); 166341f741fSDavid Howells kfree(call); 167341f741fSDavid Howells 168f044c884SDavid Howells o = atomic_dec_return(&net->nr_outstanding_calls); 169341f741fSDavid Howells trace_afs_call(call, afs_call_trace_free, 0, o, 170341f741fSDavid Howells __builtin_return_address(0)); 171341f741fSDavid Howells if (o == 0) 172f044c884SDavid Howells wake_up_atomic_t(&net->nr_outstanding_calls); 173341f741fSDavid Howells } 1746cf12869SNathaniel Wesley Filardo } 1756cf12869SNathaniel Wesley Filardo 1766cf12869SNathaniel Wesley Filardo /* 177341f741fSDavid Howells * Queue the call for actual work. Returns 0 unconditionally for convenience. 1786cf12869SNathaniel Wesley Filardo */ 179341f741fSDavid Howells int afs_queue_call_work(struct afs_call *call) 1806cf12869SNathaniel Wesley Filardo { 181341f741fSDavid Howells int u = atomic_inc_return(&call->usage); 182341f741fSDavid Howells 183341f741fSDavid Howells trace_afs_call(call, afs_call_trace_work, u, 184f044c884SDavid Howells atomic_read(&call->net->nr_outstanding_calls), 185341f741fSDavid Howells __builtin_return_address(0)); 186341f741fSDavid Howells 187341f741fSDavid Howells INIT_WORK(&call->work, call->type->work); 188341f741fSDavid Howells 189341f741fSDavid Howells if (!queue_work(afs_wq, &call->work)) 190341f741fSDavid Howells afs_put_call(call); 191341f741fSDavid Howells return 0; 1926c67c7c3SDavid Howells } 1936c67c7c3SDavid Howells 1946c67c7c3SDavid Howells /* 19508e0e7c8SDavid Howells * allocate a call with flat request and reply buffers 19608e0e7c8SDavid Howells */ 197f044c884SDavid Howells struct afs_call *afs_alloc_flat_call(struct afs_net *net, 198f044c884SDavid Howells const struct afs_call_type *type, 199d001648eSDavid Howells size_t request_size, size_t reply_max) 20008e0e7c8SDavid Howells { 20108e0e7c8SDavid Howells struct afs_call *call; 20208e0e7c8SDavid Howells 203f044c884SDavid Howells call = afs_alloc_call(net, type, GFP_NOFS); 20408e0e7c8SDavid Howells if (!call) 20508e0e7c8SDavid Howells goto nomem_call; 20608e0e7c8SDavid Howells 20700d3b7a4SDavid Howells if (request_size) { 208341f741fSDavid Howells call->request_size = request_size; 20900d3b7a4SDavid Howells call->request = kmalloc(request_size, GFP_NOFS); 21000d3b7a4SDavid Howells if (!call->request) 21100d3b7a4SDavid Howells goto nomem_free; 21200d3b7a4SDavid Howells } 21300d3b7a4SDavid Howells 214d001648eSDavid Howells if (reply_max) { 215341f741fSDavid Howells call->reply_max = reply_max; 216d001648eSDavid Howells call->buffer = kmalloc(reply_max, GFP_NOFS); 21700d3b7a4SDavid Howells if (!call->buffer) 21800d3b7a4SDavid Howells goto nomem_free; 21900d3b7a4SDavid Howells } 22000d3b7a4SDavid Howells 22108e0e7c8SDavid Howells init_waitqueue_head(&call->waitq); 22208e0e7c8SDavid Howells return call; 22308e0e7c8SDavid Howells 22400d3b7a4SDavid Howells nomem_free: 225341f741fSDavid Howells afs_put_call(call); 22608e0e7c8SDavid Howells nomem_call: 22708e0e7c8SDavid Howells return NULL; 22808e0e7c8SDavid Howells } 22908e0e7c8SDavid Howells 23008e0e7c8SDavid Howells /* 23108e0e7c8SDavid Howells * clean up a call with flat buffer 23208e0e7c8SDavid Howells */ 23308e0e7c8SDavid Howells void afs_flat_call_destructor(struct afs_call *call) 23408e0e7c8SDavid Howells { 23508e0e7c8SDavid Howells _enter(""); 23608e0e7c8SDavid Howells 23708e0e7c8SDavid Howells kfree(call->request); 23808e0e7c8SDavid Howells call->request = NULL; 23908e0e7c8SDavid Howells kfree(call->buffer); 24008e0e7c8SDavid Howells call->buffer = NULL; 24108e0e7c8SDavid Howells } 24208e0e7c8SDavid Howells 2432f5705a5SDavid Howells #define AFS_BVEC_MAX 8 2442f5705a5SDavid Howells 2452f5705a5SDavid Howells /* 2462f5705a5SDavid Howells * Load the given bvec with the next few pages. 2472f5705a5SDavid Howells */ 2482f5705a5SDavid Howells static void afs_load_bvec(struct afs_call *call, struct msghdr *msg, 2492f5705a5SDavid Howells struct bio_vec *bv, pgoff_t first, pgoff_t last, 2502f5705a5SDavid Howells unsigned offset) 2512f5705a5SDavid Howells { 2522f5705a5SDavid Howells struct page *pages[AFS_BVEC_MAX]; 2532f5705a5SDavid Howells unsigned int nr, n, i, to, bytes = 0; 2542f5705a5SDavid Howells 2552f5705a5SDavid Howells nr = min_t(pgoff_t, last - first + 1, AFS_BVEC_MAX); 2562f5705a5SDavid Howells n = find_get_pages_contig(call->mapping, first, nr, pages); 2572f5705a5SDavid Howells ASSERTCMP(n, ==, nr); 2582f5705a5SDavid Howells 2592f5705a5SDavid Howells msg->msg_flags |= MSG_MORE; 2602f5705a5SDavid Howells for (i = 0; i < nr; i++) { 2612f5705a5SDavid Howells to = PAGE_SIZE; 2622f5705a5SDavid Howells if (first + i >= last) { 2632f5705a5SDavid Howells to = call->last_to; 2642f5705a5SDavid Howells msg->msg_flags &= ~MSG_MORE; 2652f5705a5SDavid Howells } 2662f5705a5SDavid Howells bv[i].bv_page = pages[i]; 2672f5705a5SDavid Howells bv[i].bv_len = to - offset; 2682f5705a5SDavid Howells bv[i].bv_offset = offset; 2692f5705a5SDavid Howells bytes += to - offset; 2702f5705a5SDavid Howells offset = 0; 2712f5705a5SDavid Howells } 2722f5705a5SDavid Howells 2732f5705a5SDavid Howells iov_iter_bvec(&msg->msg_iter, WRITE | ITER_BVEC, bv, nr, bytes); 2742f5705a5SDavid Howells } 2752f5705a5SDavid Howells 27608e0e7c8SDavid Howells /* 277e833251aSDavid Howells * Advance the AFS call state when the RxRPC call ends the transmit phase. 278e833251aSDavid Howells */ 279e833251aSDavid Howells static void afs_notify_end_request_tx(struct sock *sock, 280e833251aSDavid Howells struct rxrpc_call *rxcall, 281e833251aSDavid Howells unsigned long call_user_ID) 282e833251aSDavid Howells { 283e833251aSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 284e833251aSDavid Howells 285e833251aSDavid Howells if (call->state == AFS_CALL_REQUESTING) 286e833251aSDavid Howells call->state = AFS_CALL_AWAIT_REPLY; 287e833251aSDavid Howells } 288e833251aSDavid Howells 289e833251aSDavid Howells /* 29031143d5dSDavid Howells * attach the data from a bunch of pages on an inode to a call 29131143d5dSDavid Howells */ 29239c6aceaSAl Viro static int afs_send_pages(struct afs_call *call, struct msghdr *msg) 29331143d5dSDavid Howells { 2942f5705a5SDavid Howells struct bio_vec bv[AFS_BVEC_MAX]; 2952f5705a5SDavid Howells unsigned int bytes, nr, loop, offset; 29631143d5dSDavid Howells pgoff_t first = call->first, last = call->last; 29731143d5dSDavid Howells int ret; 29831143d5dSDavid Howells 29931143d5dSDavid Howells offset = call->first_offset; 30031143d5dSDavid Howells call->first_offset = 0; 30131143d5dSDavid Howells 30231143d5dSDavid Howells do { 3032f5705a5SDavid Howells afs_load_bvec(call, msg, bv, first, last, offset); 30431143d5dSDavid Howells offset = 0; 3052f5705a5SDavid Howells bytes = msg->msg_iter.count; 3062f5705a5SDavid Howells nr = msg->msg_iter.nr_segs; 30731143d5dSDavid Howells 308f044c884SDavid Howells ret = rxrpc_kernel_send_data(call->net->socket, call->rxcall, msg, 309e833251aSDavid Howells bytes, afs_notify_end_request_tx); 3102f5705a5SDavid Howells for (loop = 0; loop < nr; loop++) 3112f5705a5SDavid Howells put_page(bv[loop].bv_page); 31231143d5dSDavid Howells if (ret < 0) 31331143d5dSDavid Howells break; 31431143d5dSDavid Howells 3152f5705a5SDavid Howells first += nr; 3165bbf5d39SDavid Howells } while (first <= last); 31731143d5dSDavid Howells 31831143d5dSDavid Howells return ret; 31931143d5dSDavid Howells } 32031143d5dSDavid Howells 32131143d5dSDavid Howells /* 32208e0e7c8SDavid Howells * initiate a call 32308e0e7c8SDavid Howells */ 3248b2a464cSDavid Howells long afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, 3254d9df986SDavid Howells gfp_t gfp, bool async) 32608e0e7c8SDavid Howells { 3278b2a464cSDavid Howells struct sockaddr_rxrpc *srx = ac->addr; 32808e0e7c8SDavid Howells struct rxrpc_call *rxcall; 32908e0e7c8SDavid Howells struct msghdr msg; 33008e0e7c8SDavid Howells struct kvec iov[1]; 33170af0e3bSDavid Howells size_t offset; 332e754eba6SDavid Howells s64 tx_total_len; 33370af0e3bSDavid Howells u32 abort_code; 33408e0e7c8SDavid Howells int ret; 33508e0e7c8SDavid Howells 3364d9df986SDavid Howells _enter(",{%pISp},", &srx->transport); 33708e0e7c8SDavid Howells 33800d3b7a4SDavid Howells ASSERT(call->type != NULL); 33900d3b7a4SDavid Howells ASSERT(call->type->name != NULL); 34000d3b7a4SDavid Howells 34131143d5dSDavid Howells _debug("____MAKE %p{%s,%x} [%d]____", 34231143d5dSDavid Howells call, call->type->name, key_serial(call->key), 343f044c884SDavid Howells atomic_read(&call->net->nr_outstanding_calls)); 34400d3b7a4SDavid Howells 34556ff9c83SDavid Howells call->async = async; 34608e0e7c8SDavid Howells 347e754eba6SDavid Howells /* Work out the length we're going to transmit. This is awkward for 348e754eba6SDavid Howells * calls such as FS.StoreData where there's an extra injection of data 349e754eba6SDavid Howells * after the initial fixed part. 350e754eba6SDavid Howells */ 351e754eba6SDavid Howells tx_total_len = call->request_size; 352e754eba6SDavid Howells if (call->send_pages) { 353e754eba6SDavid Howells tx_total_len += call->last_to - call->first_offset; 354e754eba6SDavid Howells tx_total_len += (call->last - call->first) * PAGE_SIZE; 355e754eba6SDavid Howells } 356e754eba6SDavid Howells 35708e0e7c8SDavid Howells /* create a call */ 3584d9df986SDavid Howells rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key, 359e754eba6SDavid Howells (unsigned long)call, 360e754eba6SDavid Howells tx_total_len, gfp, 36156ff9c83SDavid Howells (async ? 36256ff9c83SDavid Howells afs_wake_up_async_call : 363a68f4a27SDavid Howells afs_wake_up_call_waiter), 364a68f4a27SDavid Howells call->upgrade); 36500d3b7a4SDavid Howells call->key = NULL; 36608e0e7c8SDavid Howells if (IS_ERR(rxcall)) { 36708e0e7c8SDavid Howells ret = PTR_ERR(rxcall); 36808e0e7c8SDavid Howells goto error_kill_call; 36908e0e7c8SDavid Howells } 37008e0e7c8SDavid Howells 37108e0e7c8SDavid Howells call->rxcall = rxcall; 37208e0e7c8SDavid Howells 37308e0e7c8SDavid Howells /* send the request */ 37408e0e7c8SDavid Howells iov[0].iov_base = call->request; 37508e0e7c8SDavid Howells iov[0].iov_len = call->request_size; 37608e0e7c8SDavid Howells 37708e0e7c8SDavid Howells msg.msg_name = NULL; 37808e0e7c8SDavid Howells msg.msg_namelen = 0; 3792e90b1c4SAl Viro iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iov, 1, 380c0371da6SAl Viro call->request_size); 38108e0e7c8SDavid Howells msg.msg_control = NULL; 38208e0e7c8SDavid Howells msg.msg_controllen = 0; 383bc5e3a54SDavid Howells msg.msg_flags = MSG_WAITALL | (call->send_pages ? MSG_MORE : 0); 38408e0e7c8SDavid Howells 38570af0e3bSDavid Howells /* We have to change the state *before* sending the last packet as 38670af0e3bSDavid Howells * rxrpc might give us the reply before it returns from sending the 38770af0e3bSDavid Howells * request. Further, if the send fails, we may already have been given 38870af0e3bSDavid Howells * a notification and may have collected it. 38970af0e3bSDavid Howells */ 39031143d5dSDavid Howells if (!call->send_pages) 39108e0e7c8SDavid Howells call->state = AFS_CALL_AWAIT_REPLY; 392f044c884SDavid Howells ret = rxrpc_kernel_send_data(call->net->socket, rxcall, 393e833251aSDavid Howells &msg, call->request_size, 394e833251aSDavid Howells afs_notify_end_request_tx); 39508e0e7c8SDavid Howells if (ret < 0) 39608e0e7c8SDavid Howells goto error_do_abort; 39708e0e7c8SDavid Howells 39831143d5dSDavid Howells if (call->send_pages) { 39939c6aceaSAl Viro ret = afs_send_pages(call, &msg); 40031143d5dSDavid Howells if (ret < 0) 40131143d5dSDavid Howells goto error_do_abort; 40231143d5dSDavid Howells } 40331143d5dSDavid Howells 40408e0e7c8SDavid Howells /* at this point, an async call may no longer exist as it may have 40508e0e7c8SDavid Howells * already completed */ 40656ff9c83SDavid Howells if (call->async) 40756ff9c83SDavid Howells return -EINPROGRESS; 40856ff9c83SDavid Howells 40956ff9c83SDavid Howells return afs_wait_for_call_to_complete(call); 41008e0e7c8SDavid Howells 41108e0e7c8SDavid Howells error_do_abort: 41270af0e3bSDavid Howells call->state = AFS_CALL_COMPLETE; 41370af0e3bSDavid Howells if (ret != -ECONNABORTED) { 414f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, rxcall, 415f044c884SDavid Howells RX_USER_ABORT, ret, "KSD"); 41670af0e3bSDavid Howells } else { 41770af0e3bSDavid Howells abort_code = 0; 41870af0e3bSDavid Howells offset = 0; 419f044c884SDavid Howells rxrpc_kernel_recv_data(call->net->socket, rxcall, NULL, 42033cd7f2bSDavid Howells 0, &offset, false, &call->abort_code, 421f044c884SDavid Howells &call->service_id); 42233cd7f2bSDavid Howells ret = afs_abort_to_error(call->abort_code); 42370af0e3bSDavid Howells } 42408e0e7c8SDavid Howells error_kill_call: 425341f741fSDavid Howells afs_put_call(call); 42608e0e7c8SDavid Howells _leave(" = %d", ret); 42708e0e7c8SDavid Howells return ret; 42808e0e7c8SDavid Howells } 42908e0e7c8SDavid Howells 43008e0e7c8SDavid Howells /* 43108e0e7c8SDavid Howells * deliver messages to a call 43208e0e7c8SDavid Howells */ 43308e0e7c8SDavid Howells static void afs_deliver_to_call(struct afs_call *call) 43408e0e7c8SDavid Howells { 43508e0e7c8SDavid Howells u32 abort_code; 43608e0e7c8SDavid Howells int ret; 43708e0e7c8SDavid Howells 438d001648eSDavid Howells _enter("%s", call->type->name); 43908e0e7c8SDavid Howells 440d001648eSDavid Howells while (call->state == AFS_CALL_AWAIT_REPLY || 44108e0e7c8SDavid Howells call->state == AFS_CALL_AWAIT_OP_ID || 44208e0e7c8SDavid Howells call->state == AFS_CALL_AWAIT_REQUEST || 443d001648eSDavid Howells call->state == AFS_CALL_AWAIT_ACK 444d001648eSDavid Howells ) { 445d001648eSDavid Howells if (call->state == AFS_CALL_AWAIT_ACK) { 446d001648eSDavid Howells size_t offset = 0; 447f044c884SDavid Howells ret = rxrpc_kernel_recv_data(call->net->socket, 448f044c884SDavid Howells call->rxcall, 449d001648eSDavid Howells NULL, 0, &offset, false, 450a68f4a27SDavid Howells &call->abort_code, 451a68f4a27SDavid Howells &call->service_id); 4528e8d7f13SDavid Howells trace_afs_recv_data(call, 0, offset, false, ret); 4538e8d7f13SDavid Howells 454d001648eSDavid Howells if (ret == -EINPROGRESS || ret == -EAGAIN) 455d001648eSDavid Howells return; 4569008f998SDavid Howells if (ret == 1 || ret < 0) { 457d001648eSDavid Howells call->state = AFS_CALL_COMPLETE; 458d001648eSDavid Howells goto done; 459372ee163SDavid Howells } 460d001648eSDavid Howells return; 461d001648eSDavid Howells } 462d001648eSDavid Howells 463d001648eSDavid Howells ret = call->type->deliver(call); 464d001648eSDavid Howells switch (ret) { 46508e0e7c8SDavid Howells case 0: 466372ee163SDavid Howells if (call->state == AFS_CALL_AWAIT_REPLY) 46708e0e7c8SDavid Howells call->state = AFS_CALL_COMPLETE; 468d001648eSDavid Howells goto done; 469d001648eSDavid Howells case -EINPROGRESS: 470d001648eSDavid Howells case -EAGAIN: 471d001648eSDavid Howells goto out; 47270af0e3bSDavid Howells case -ECONNABORTED: 47333cd7f2bSDavid Howells goto save_error; 47408e0e7c8SDavid Howells case -ENOTCONN: 47508e0e7c8SDavid Howells abort_code = RX_CALL_DEAD; 476f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 4773a92789aSDavid Howells abort_code, ret, "KNC"); 47870af0e3bSDavid Howells goto save_error; 47908e0e7c8SDavid Howells case -ENOTSUPP: 4801157f153SDavid Howells abort_code = RXGEN_OPCODE; 481f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 4823a92789aSDavid Howells abort_code, ret, "KIV"); 48370af0e3bSDavid Howells goto save_error; 484d001648eSDavid Howells case -ENODATA: 485d001648eSDavid Howells case -EBADMSG: 486d001648eSDavid Howells case -EMSGSIZE: 48708e0e7c8SDavid Howells default: 48808e0e7c8SDavid Howells abort_code = RXGEN_CC_UNMARSHAL; 48908e0e7c8SDavid Howells if (call->state != AFS_CALL_AWAIT_REPLY) 49008e0e7c8SDavid Howells abort_code = RXGEN_SS_UNMARSHAL; 491f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 4923a92789aSDavid Howells abort_code, -EBADMSG, "KUM"); 49370af0e3bSDavid Howells goto save_error; 49408e0e7c8SDavid Howells } 49508e0e7c8SDavid Howells } 49608e0e7c8SDavid Howells 497d001648eSDavid Howells done: 498d001648eSDavid Howells if (call->state == AFS_CALL_COMPLETE && call->incoming) 499341f741fSDavid Howells afs_put_call(call); 500d001648eSDavid Howells out: 50108e0e7c8SDavid Howells _leave(""); 502d001648eSDavid Howells return; 503d001648eSDavid Howells 50470af0e3bSDavid Howells save_error: 505d001648eSDavid Howells call->error = ret; 506d001648eSDavid Howells call->state = AFS_CALL_COMPLETE; 507d001648eSDavid Howells goto done; 50808e0e7c8SDavid Howells } 50908e0e7c8SDavid Howells 51008e0e7c8SDavid Howells /* 51108e0e7c8SDavid Howells * wait synchronously for a call to complete 51208e0e7c8SDavid Howells */ 51333cd7f2bSDavid Howells static long afs_wait_for_call_to_complete(struct afs_call *call) 51408e0e7c8SDavid Howells { 515bc5e3a54SDavid Howells signed long rtt2, timeout; 51633cd7f2bSDavid Howells long ret; 517bc5e3a54SDavid Howells u64 rtt; 518bc5e3a54SDavid Howells u32 life, last_life; 51908e0e7c8SDavid Howells 52008e0e7c8SDavid Howells DECLARE_WAITQUEUE(myself, current); 52108e0e7c8SDavid Howells 52208e0e7c8SDavid Howells _enter(""); 52308e0e7c8SDavid Howells 524f044c884SDavid Howells rtt = rxrpc_kernel_get_rtt(call->net->socket, call->rxcall); 525bc5e3a54SDavid Howells rtt2 = nsecs_to_jiffies64(rtt) * 2; 526bc5e3a54SDavid Howells if (rtt2 < 2) 527bc5e3a54SDavid Howells rtt2 = 2; 528bc5e3a54SDavid Howells 529bc5e3a54SDavid Howells timeout = rtt2; 530f044c884SDavid Howells last_life = rxrpc_kernel_check_life(call->net->socket, call->rxcall); 531bc5e3a54SDavid Howells 53208e0e7c8SDavid Howells add_wait_queue(&call->waitq, &myself); 53308e0e7c8SDavid Howells for (;;) { 534bc5e3a54SDavid Howells set_current_state(TASK_UNINTERRUPTIBLE); 53508e0e7c8SDavid Howells 53608e0e7c8SDavid Howells /* deliver any messages that are in the queue */ 537d001648eSDavid Howells if (call->state < AFS_CALL_COMPLETE && call->need_attention) { 538d001648eSDavid Howells call->need_attention = false; 53908e0e7c8SDavid Howells __set_current_state(TASK_RUNNING); 54008e0e7c8SDavid Howells afs_deliver_to_call(call); 54108e0e7c8SDavid Howells continue; 54208e0e7c8SDavid Howells } 54308e0e7c8SDavid Howells 544bc5e3a54SDavid Howells if (call->state == AFS_CALL_COMPLETE) 54508e0e7c8SDavid Howells break; 546bc5e3a54SDavid Howells 547f044c884SDavid Howells life = rxrpc_kernel_check_life(call->net->socket, call->rxcall); 548bc5e3a54SDavid Howells if (timeout == 0 && 549bc5e3a54SDavid Howells life == last_life && signal_pending(current)) 550bc5e3a54SDavid Howells break; 551bc5e3a54SDavid Howells 552bc5e3a54SDavid Howells if (life != last_life) { 553bc5e3a54SDavid Howells timeout = rtt2; 554bc5e3a54SDavid Howells last_life = life; 555bc5e3a54SDavid Howells } 556bc5e3a54SDavid Howells 557bc5e3a54SDavid Howells timeout = schedule_timeout(timeout); 55808e0e7c8SDavid Howells } 55908e0e7c8SDavid Howells 56008e0e7c8SDavid Howells remove_wait_queue(&call->waitq, &myself); 56108e0e7c8SDavid Howells __set_current_state(TASK_RUNNING); 56208e0e7c8SDavid Howells 563954cd6dcSDavid Howells /* Kill off the call if it's still live. */ 56408e0e7c8SDavid Howells if (call->state < AFS_CALL_COMPLETE) { 565954cd6dcSDavid Howells _debug("call interrupted"); 566f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 567954cd6dcSDavid Howells RX_USER_ABORT, -EINTR, "KWI"); 56808e0e7c8SDavid Howells } 56908e0e7c8SDavid Howells 570954cd6dcSDavid Howells ret = call->error; 57133cd7f2bSDavid Howells if (ret < 0) { 57233cd7f2bSDavid Howells ret = afs_abort_to_error(call->abort_code); 57333cd7f2bSDavid Howells } else if (ret == 0 && call->ret_reply0) { 57433cd7f2bSDavid Howells ret = (long)call->reply[0]; 57533cd7f2bSDavid Howells call->reply[0] = NULL; 57633cd7f2bSDavid Howells } 57733cd7f2bSDavid Howells 57808e0e7c8SDavid Howells _debug("call complete"); 579341f741fSDavid Howells afs_put_call(call); 58033cd7f2bSDavid Howells _leave(" = %p", (void *)ret); 58108e0e7c8SDavid Howells return ret; 58208e0e7c8SDavid Howells } 58308e0e7c8SDavid Howells 58408e0e7c8SDavid Howells /* 58508e0e7c8SDavid Howells * wake up a waiting call 58608e0e7c8SDavid Howells */ 587d001648eSDavid Howells static void afs_wake_up_call_waiter(struct sock *sk, struct rxrpc_call *rxcall, 588d001648eSDavid Howells unsigned long call_user_ID) 58908e0e7c8SDavid Howells { 590d001648eSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 591d001648eSDavid Howells 592d001648eSDavid Howells call->need_attention = true; 59308e0e7c8SDavid Howells wake_up(&call->waitq); 59408e0e7c8SDavid Howells } 59508e0e7c8SDavid Howells 59608e0e7c8SDavid Howells /* 59708e0e7c8SDavid Howells * wake up an asynchronous call 59808e0e7c8SDavid Howells */ 599d001648eSDavid Howells static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall, 600d001648eSDavid Howells unsigned long call_user_ID) 60108e0e7c8SDavid Howells { 602d001648eSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 603341f741fSDavid Howells int u; 604d001648eSDavid Howells 6058e8d7f13SDavid Howells trace_afs_notify_call(rxcall, call); 606d001648eSDavid Howells call->need_attention = true; 607341f741fSDavid Howells 608341f741fSDavid Howells u = __atomic_add_unless(&call->usage, 1, 0); 609341f741fSDavid Howells if (u != 0) { 610341f741fSDavid Howells trace_afs_call(call, afs_call_trace_wake, u, 611f044c884SDavid Howells atomic_read(&call->net->nr_outstanding_calls), 612341f741fSDavid Howells __builtin_return_address(0)); 613341f741fSDavid Howells 614341f741fSDavid Howells if (!queue_work(afs_async_calls, &call->async_work)) 615341f741fSDavid Howells afs_put_call(call); 616341f741fSDavid Howells } 61708e0e7c8SDavid Howells } 61808e0e7c8SDavid Howells 61908e0e7c8SDavid Howells /* 620341f741fSDavid Howells * Delete an asynchronous call. The work item carries a ref to the call struct 621341f741fSDavid Howells * that we need to release. 62208e0e7c8SDavid Howells */ 623d001648eSDavid Howells static void afs_delete_async_call(struct work_struct *work) 62408e0e7c8SDavid Howells { 625d001648eSDavid Howells struct afs_call *call = container_of(work, struct afs_call, async_work); 626d001648eSDavid Howells 62708e0e7c8SDavid Howells _enter(""); 62808e0e7c8SDavid Howells 629341f741fSDavid Howells afs_put_call(call); 63008e0e7c8SDavid Howells 63108e0e7c8SDavid Howells _leave(""); 63208e0e7c8SDavid Howells } 63308e0e7c8SDavid Howells 63408e0e7c8SDavid Howells /* 635341f741fSDavid Howells * Perform I/O processing on an asynchronous call. The work item carries a ref 636341f741fSDavid Howells * to the call struct that we either need to release or to pass on. 63708e0e7c8SDavid Howells */ 638d001648eSDavid Howells static void afs_process_async_call(struct work_struct *work) 63908e0e7c8SDavid Howells { 640d001648eSDavid Howells struct afs_call *call = container_of(work, struct afs_call, async_work); 641d001648eSDavid Howells 64208e0e7c8SDavid Howells _enter(""); 64308e0e7c8SDavid Howells 644d001648eSDavid Howells if (call->state < AFS_CALL_COMPLETE && call->need_attention) { 645d001648eSDavid Howells call->need_attention = false; 64608e0e7c8SDavid Howells afs_deliver_to_call(call); 647d001648eSDavid Howells } 64808e0e7c8SDavid Howells 64956ff9c83SDavid Howells if (call->state == AFS_CALL_COMPLETE) { 65097e3043aSDavid Howells call->reply[0] = NULL; 65108e0e7c8SDavid Howells 652341f741fSDavid Howells /* We have two refs to release - one from the alloc and one 653341f741fSDavid Howells * queued with the work item - and we can't just deallocate the 654341f741fSDavid Howells * call because the work item may be queued again. 655341f741fSDavid Howells */ 656d001648eSDavid Howells call->async_work.func = afs_delete_async_call; 657341f741fSDavid Howells if (!queue_work(afs_async_calls, &call->async_work)) 658341f741fSDavid Howells afs_put_call(call); 65908e0e7c8SDavid Howells } 66008e0e7c8SDavid Howells 661341f741fSDavid Howells afs_put_call(call); 66208e0e7c8SDavid Howells _leave(""); 66308e0e7c8SDavid Howells } 66408e0e7c8SDavid Howells 66500e90712SDavid Howells static void afs_rx_attach(struct rxrpc_call *rxcall, unsigned long user_call_ID) 66600e90712SDavid Howells { 66700e90712SDavid Howells struct afs_call *call = (struct afs_call *)user_call_ID; 66800e90712SDavid Howells 66900e90712SDavid Howells call->rxcall = rxcall; 67000e90712SDavid Howells } 67100e90712SDavid Howells 67200e90712SDavid Howells /* 67300e90712SDavid Howells * Charge the incoming call preallocation. 67400e90712SDavid Howells */ 675f044c884SDavid Howells void afs_charge_preallocation(struct work_struct *work) 67600e90712SDavid Howells { 677f044c884SDavid Howells struct afs_net *net = 678f044c884SDavid Howells container_of(work, struct afs_net, charge_preallocation_work); 679f044c884SDavid Howells struct afs_call *call = net->spare_incoming_call; 68000e90712SDavid Howells 68100e90712SDavid Howells for (;;) { 68200e90712SDavid Howells if (!call) { 683f044c884SDavid Howells call = afs_alloc_call(net, &afs_RXCMxxxx, GFP_KERNEL); 68400e90712SDavid Howells if (!call) 68500e90712SDavid Howells break; 68600e90712SDavid Howells 68756ff9c83SDavid Howells call->async = true; 68800e90712SDavid Howells call->state = AFS_CALL_AWAIT_OP_ID; 68956ff9c83SDavid Howells init_waitqueue_head(&call->waitq); 69000e90712SDavid Howells } 69100e90712SDavid Howells 692f044c884SDavid Howells if (rxrpc_kernel_charge_accept(net->socket, 69300e90712SDavid Howells afs_wake_up_async_call, 69400e90712SDavid Howells afs_rx_attach, 69500e90712SDavid Howells (unsigned long)call, 69600e90712SDavid Howells GFP_KERNEL) < 0) 69700e90712SDavid Howells break; 69800e90712SDavid Howells call = NULL; 69900e90712SDavid Howells } 700f044c884SDavid Howells net->spare_incoming_call = call; 70100e90712SDavid Howells } 70200e90712SDavid Howells 70300e90712SDavid Howells /* 70400e90712SDavid Howells * Discard a preallocated call when a socket is shut down. 70500e90712SDavid Howells */ 70600e90712SDavid Howells static void afs_rx_discard_new_call(struct rxrpc_call *rxcall, 70700e90712SDavid Howells unsigned long user_call_ID) 70800e90712SDavid Howells { 70900e90712SDavid Howells struct afs_call *call = (struct afs_call *)user_call_ID; 71000e90712SDavid Howells 71100e90712SDavid Howells call->rxcall = NULL; 712341f741fSDavid Howells afs_put_call(call); 71300e90712SDavid Howells } 71400e90712SDavid Howells 71508e0e7c8SDavid Howells /* 716d001648eSDavid Howells * Notification of an incoming call. 717d001648eSDavid Howells */ 71800e90712SDavid Howells static void afs_rx_new_call(struct sock *sk, struct rxrpc_call *rxcall, 71900e90712SDavid Howells unsigned long user_call_ID) 720d001648eSDavid Howells { 721f044c884SDavid Howells struct afs_net *net = afs_sock2net(sk); 722f044c884SDavid Howells 723f044c884SDavid Howells queue_work(afs_wq, &net->charge_preallocation_work); 724d001648eSDavid Howells } 725d001648eSDavid Howells 726d001648eSDavid Howells /* 727372ee163SDavid Howells * Grab the operation ID from an incoming cache manager call. The socket 728372ee163SDavid Howells * buffer is discarded on error or if we don't yet have sufficient data. 72908e0e7c8SDavid Howells */ 730d001648eSDavid Howells static int afs_deliver_cm_op_id(struct afs_call *call) 73108e0e7c8SDavid Howells { 732d001648eSDavid Howells int ret; 73308e0e7c8SDavid Howells 734d001648eSDavid Howells _enter("{%zu}", call->offset); 73508e0e7c8SDavid Howells 73608e0e7c8SDavid Howells ASSERTCMP(call->offset, <, 4); 73708e0e7c8SDavid Howells 73808e0e7c8SDavid Howells /* the operation ID forms the first four bytes of the request data */ 73950a2c953SDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 740d001648eSDavid Howells if (ret < 0) 741d001648eSDavid Howells return ret; 74208e0e7c8SDavid Howells 74350a2c953SDavid Howells call->operation_ID = ntohl(call->tmp); 74408e0e7c8SDavid Howells call->state = AFS_CALL_AWAIT_REQUEST; 745d001648eSDavid Howells call->offset = 0; 74608e0e7c8SDavid Howells 74708e0e7c8SDavid Howells /* ask the cache manager to route the call (it'll change the call type 74808e0e7c8SDavid Howells * if successful) */ 74908e0e7c8SDavid Howells if (!afs_cm_incoming_call(call)) 75008e0e7c8SDavid Howells return -ENOTSUPP; 75108e0e7c8SDavid Howells 7528e8d7f13SDavid Howells trace_afs_cb_call(call); 7538e8d7f13SDavid Howells 75408e0e7c8SDavid Howells /* pass responsibility for the remainer of this message off to the 75508e0e7c8SDavid Howells * cache manager op */ 756d001648eSDavid Howells return call->type->deliver(call); 75708e0e7c8SDavid Howells } 75808e0e7c8SDavid Howells 75908e0e7c8SDavid Howells /* 760e833251aSDavid Howells * Advance the AFS call state when an RxRPC service call ends the transmit 761e833251aSDavid Howells * phase. 762e833251aSDavid Howells */ 763e833251aSDavid Howells static void afs_notify_end_reply_tx(struct sock *sock, 764e833251aSDavid Howells struct rxrpc_call *rxcall, 765e833251aSDavid Howells unsigned long call_user_ID) 766e833251aSDavid Howells { 767e833251aSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 768e833251aSDavid Howells 769e833251aSDavid Howells if (call->state == AFS_CALL_REPLYING) 770e833251aSDavid Howells call->state = AFS_CALL_AWAIT_ACK; 771e833251aSDavid Howells } 772e833251aSDavid Howells 773e833251aSDavid Howells /* 77408e0e7c8SDavid Howells * send an empty reply 77508e0e7c8SDavid Howells */ 77608e0e7c8SDavid Howells void afs_send_empty_reply(struct afs_call *call) 77708e0e7c8SDavid Howells { 778f044c884SDavid Howells struct afs_net *net = call->net; 77908e0e7c8SDavid Howells struct msghdr msg; 78008e0e7c8SDavid Howells 78108e0e7c8SDavid Howells _enter(""); 78208e0e7c8SDavid Howells 783f044c884SDavid Howells rxrpc_kernel_set_tx_length(net->socket, call->rxcall, 0); 784e754eba6SDavid Howells 78508e0e7c8SDavid Howells msg.msg_name = NULL; 78608e0e7c8SDavid Howells msg.msg_namelen = 0; 787bfd4e956SDavid Howells iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, NULL, 0, 0); 78808e0e7c8SDavid Howells msg.msg_control = NULL; 78908e0e7c8SDavid Howells msg.msg_controllen = 0; 79008e0e7c8SDavid Howells msg.msg_flags = 0; 79108e0e7c8SDavid Howells 79208e0e7c8SDavid Howells call->state = AFS_CALL_AWAIT_ACK; 793f044c884SDavid Howells switch (rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, 0, 794e833251aSDavid Howells afs_notify_end_reply_tx)) { 79508e0e7c8SDavid Howells case 0: 79608e0e7c8SDavid Howells _leave(" [replied]"); 79708e0e7c8SDavid Howells return; 79808e0e7c8SDavid Howells 79908e0e7c8SDavid Howells case -ENOMEM: 80008e0e7c8SDavid Howells _debug("oom"); 801f044c884SDavid Howells rxrpc_kernel_abort_call(net->socket, call->rxcall, 8023a92789aSDavid Howells RX_USER_ABORT, -ENOMEM, "KOO"); 80308e0e7c8SDavid Howells default: 80408e0e7c8SDavid Howells _leave(" [error]"); 80508e0e7c8SDavid Howells return; 80608e0e7c8SDavid Howells } 80708e0e7c8SDavid Howells } 80808e0e7c8SDavid Howells 80908e0e7c8SDavid Howells /* 810b908fe6bSDavid Howells * send a simple reply 811b908fe6bSDavid Howells */ 812b908fe6bSDavid Howells void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) 813b908fe6bSDavid Howells { 814f044c884SDavid Howells struct afs_net *net = call->net; 815b908fe6bSDavid Howells struct msghdr msg; 8162e90b1c4SAl Viro struct kvec iov[1]; 817bd6dc742SDavid Howells int n; 818b908fe6bSDavid Howells 819b908fe6bSDavid Howells _enter(""); 820b908fe6bSDavid Howells 821f044c884SDavid Howells rxrpc_kernel_set_tx_length(net->socket, call->rxcall, len); 822e754eba6SDavid Howells 823b908fe6bSDavid Howells iov[0].iov_base = (void *) buf; 824b908fe6bSDavid Howells iov[0].iov_len = len; 825b908fe6bSDavid Howells msg.msg_name = NULL; 826b908fe6bSDavid Howells msg.msg_namelen = 0; 8272e90b1c4SAl Viro iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iov, 1, len); 828b908fe6bSDavid Howells msg.msg_control = NULL; 829b908fe6bSDavid Howells msg.msg_controllen = 0; 830b908fe6bSDavid Howells msg.msg_flags = 0; 831b908fe6bSDavid Howells 832b908fe6bSDavid Howells call->state = AFS_CALL_AWAIT_ACK; 833f044c884SDavid Howells n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, len, 834e833251aSDavid Howells afs_notify_end_reply_tx); 835bd6dc742SDavid Howells if (n >= 0) { 8366c67c7c3SDavid Howells /* Success */ 837b908fe6bSDavid Howells _leave(" [replied]"); 838b908fe6bSDavid Howells return; 839bd6dc742SDavid Howells } 8406c67c7c3SDavid Howells 841bd6dc742SDavid Howells if (n == -ENOMEM) { 842b908fe6bSDavid Howells _debug("oom"); 843f044c884SDavid Howells rxrpc_kernel_abort_call(net->socket, call->rxcall, 8443a92789aSDavid Howells RX_USER_ABORT, -ENOMEM, "KOO"); 845bd6dc742SDavid Howells } 846b908fe6bSDavid Howells _leave(" [error]"); 847b908fe6bSDavid Howells } 848b908fe6bSDavid Howells 849b908fe6bSDavid Howells /* 850372ee163SDavid Howells * Extract a piece of data from the received data socket buffers. 85108e0e7c8SDavid Howells */ 852d001648eSDavid Howells int afs_extract_data(struct afs_call *call, void *buf, size_t count, 853d001648eSDavid Howells bool want_more) 85408e0e7c8SDavid Howells { 855f044c884SDavid Howells struct afs_net *net = call->net; 856d001648eSDavid Howells int ret; 85708e0e7c8SDavid Howells 858d001648eSDavid Howells _enter("{%s,%zu},,%zu,%d", 859d001648eSDavid Howells call->type->name, call->offset, count, want_more); 86008e0e7c8SDavid Howells 861d001648eSDavid Howells ASSERTCMP(call->offset, <=, count); 86208e0e7c8SDavid Howells 863f044c884SDavid Howells ret = rxrpc_kernel_recv_data(net->socket, call->rxcall, 864d001648eSDavid Howells buf, count, &call->offset, 865a68f4a27SDavid Howells want_more, &call->abort_code, 866a68f4a27SDavid Howells &call->service_id); 8678e8d7f13SDavid Howells trace_afs_recv_data(call, count, call->offset, want_more, ret); 868d001648eSDavid Howells if (ret == 0 || ret == -EAGAIN) 869d001648eSDavid Howells return ret; 87008e0e7c8SDavid Howells 871d001648eSDavid Howells if (ret == 1) { 872d001648eSDavid Howells switch (call->state) { 873d001648eSDavid Howells case AFS_CALL_AWAIT_REPLY: 874d001648eSDavid Howells call->state = AFS_CALL_COMPLETE; 875d001648eSDavid Howells break; 876d001648eSDavid Howells case AFS_CALL_AWAIT_REQUEST: 877d001648eSDavid Howells call->state = AFS_CALL_REPLYING; 878d001648eSDavid Howells break; 879d001648eSDavid Howells default: 880d001648eSDavid Howells break; 88108e0e7c8SDavid Howells } 88208e0e7c8SDavid Howells return 0; 88308e0e7c8SDavid Howells } 884d001648eSDavid Howells 885d001648eSDavid Howells if (ret == -ECONNABORTED) 886f780c8eaSDavid Howells call->error = afs_abort_to_error(call->abort_code); 887d001648eSDavid Howells else 888d001648eSDavid Howells call->error = ret; 889d001648eSDavid Howells call->state = AFS_CALL_COMPLETE; 890d001648eSDavid Howells return ret; 891d001648eSDavid Howells } 892