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); 2308e0e7c8SDavid Howells static int 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 164341f741fSDavid Howells kfree(call->request); 165341f741fSDavid Howells kfree(call); 166341f741fSDavid Howells 167f044c884SDavid Howells o = atomic_dec_return(&net->nr_outstanding_calls); 168341f741fSDavid Howells trace_afs_call(call, afs_call_trace_free, 0, o, 169341f741fSDavid Howells __builtin_return_address(0)); 170341f741fSDavid Howells if (o == 0) 171f044c884SDavid Howells wake_up_atomic_t(&net->nr_outstanding_calls); 172341f741fSDavid Howells } 1736cf12869SNathaniel Wesley Filardo } 1746cf12869SNathaniel Wesley Filardo 1756cf12869SNathaniel Wesley Filardo /* 176341f741fSDavid Howells * Queue the call for actual work. Returns 0 unconditionally for convenience. 1776cf12869SNathaniel Wesley Filardo */ 178341f741fSDavid Howells int afs_queue_call_work(struct afs_call *call) 1796cf12869SNathaniel Wesley Filardo { 180341f741fSDavid Howells int u = atomic_inc_return(&call->usage); 181341f741fSDavid Howells 182341f741fSDavid Howells trace_afs_call(call, afs_call_trace_work, u, 183f044c884SDavid Howells atomic_read(&call->net->nr_outstanding_calls), 184341f741fSDavid Howells __builtin_return_address(0)); 185341f741fSDavid Howells 186341f741fSDavid Howells INIT_WORK(&call->work, call->type->work); 187341f741fSDavid Howells 188341f741fSDavid Howells if (!queue_work(afs_wq, &call->work)) 189341f741fSDavid Howells afs_put_call(call); 190341f741fSDavid Howells return 0; 1916c67c7c3SDavid Howells } 1926c67c7c3SDavid Howells 1936c67c7c3SDavid Howells /* 19408e0e7c8SDavid Howells * allocate a call with flat request and reply buffers 19508e0e7c8SDavid Howells */ 196f044c884SDavid Howells struct afs_call *afs_alloc_flat_call(struct afs_net *net, 197f044c884SDavid Howells const struct afs_call_type *type, 198d001648eSDavid Howells size_t request_size, size_t reply_max) 19908e0e7c8SDavid Howells { 20008e0e7c8SDavid Howells struct afs_call *call; 20108e0e7c8SDavid Howells 202f044c884SDavid Howells call = afs_alloc_call(net, type, GFP_NOFS); 20308e0e7c8SDavid Howells if (!call) 20408e0e7c8SDavid Howells goto nomem_call; 20508e0e7c8SDavid Howells 20600d3b7a4SDavid Howells if (request_size) { 207341f741fSDavid Howells call->request_size = request_size; 20800d3b7a4SDavid Howells call->request = kmalloc(request_size, GFP_NOFS); 20900d3b7a4SDavid Howells if (!call->request) 21000d3b7a4SDavid Howells goto nomem_free; 21100d3b7a4SDavid Howells } 21200d3b7a4SDavid Howells 213d001648eSDavid Howells if (reply_max) { 214341f741fSDavid Howells call->reply_max = reply_max; 215d001648eSDavid Howells call->buffer = kmalloc(reply_max, GFP_NOFS); 21600d3b7a4SDavid Howells if (!call->buffer) 21700d3b7a4SDavid Howells goto nomem_free; 21800d3b7a4SDavid Howells } 21900d3b7a4SDavid Howells 22008e0e7c8SDavid Howells init_waitqueue_head(&call->waitq); 22108e0e7c8SDavid Howells return call; 22208e0e7c8SDavid Howells 22300d3b7a4SDavid Howells nomem_free: 224341f741fSDavid Howells afs_put_call(call); 22508e0e7c8SDavid Howells nomem_call: 22608e0e7c8SDavid Howells return NULL; 22708e0e7c8SDavid Howells } 22808e0e7c8SDavid Howells 22908e0e7c8SDavid Howells /* 23008e0e7c8SDavid Howells * clean up a call with flat buffer 23108e0e7c8SDavid Howells */ 23208e0e7c8SDavid Howells void afs_flat_call_destructor(struct afs_call *call) 23308e0e7c8SDavid Howells { 23408e0e7c8SDavid Howells _enter(""); 23508e0e7c8SDavid Howells 23608e0e7c8SDavid Howells kfree(call->request); 23708e0e7c8SDavid Howells call->request = NULL; 23808e0e7c8SDavid Howells kfree(call->buffer); 23908e0e7c8SDavid Howells call->buffer = NULL; 24008e0e7c8SDavid Howells } 24108e0e7c8SDavid Howells 2422f5705a5SDavid Howells #define AFS_BVEC_MAX 8 2432f5705a5SDavid Howells 2442f5705a5SDavid Howells /* 2452f5705a5SDavid Howells * Load the given bvec with the next few pages. 2462f5705a5SDavid Howells */ 2472f5705a5SDavid Howells static void afs_load_bvec(struct afs_call *call, struct msghdr *msg, 2482f5705a5SDavid Howells struct bio_vec *bv, pgoff_t first, pgoff_t last, 2492f5705a5SDavid Howells unsigned offset) 2502f5705a5SDavid Howells { 2512f5705a5SDavid Howells struct page *pages[AFS_BVEC_MAX]; 2522f5705a5SDavid Howells unsigned int nr, n, i, to, bytes = 0; 2532f5705a5SDavid Howells 2542f5705a5SDavid Howells nr = min_t(pgoff_t, last - first + 1, AFS_BVEC_MAX); 2552f5705a5SDavid Howells n = find_get_pages_contig(call->mapping, first, nr, pages); 2562f5705a5SDavid Howells ASSERTCMP(n, ==, nr); 2572f5705a5SDavid Howells 2582f5705a5SDavid Howells msg->msg_flags |= MSG_MORE; 2592f5705a5SDavid Howells for (i = 0; i < nr; i++) { 2602f5705a5SDavid Howells to = PAGE_SIZE; 2612f5705a5SDavid Howells if (first + i >= last) { 2622f5705a5SDavid Howells to = call->last_to; 2632f5705a5SDavid Howells msg->msg_flags &= ~MSG_MORE; 2642f5705a5SDavid Howells } 2652f5705a5SDavid Howells bv[i].bv_page = pages[i]; 2662f5705a5SDavid Howells bv[i].bv_len = to - offset; 2672f5705a5SDavid Howells bv[i].bv_offset = offset; 2682f5705a5SDavid Howells bytes += to - offset; 2692f5705a5SDavid Howells offset = 0; 2702f5705a5SDavid Howells } 2712f5705a5SDavid Howells 2722f5705a5SDavid Howells iov_iter_bvec(&msg->msg_iter, WRITE | ITER_BVEC, bv, nr, bytes); 2732f5705a5SDavid Howells } 2742f5705a5SDavid Howells 27508e0e7c8SDavid Howells /* 276e833251aSDavid Howells * Advance the AFS call state when the RxRPC call ends the transmit phase. 277e833251aSDavid Howells */ 278e833251aSDavid Howells static void afs_notify_end_request_tx(struct sock *sock, 279e833251aSDavid Howells struct rxrpc_call *rxcall, 280e833251aSDavid Howells unsigned long call_user_ID) 281e833251aSDavid Howells { 282e833251aSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 283e833251aSDavid Howells 284e833251aSDavid Howells if (call->state == AFS_CALL_REQUESTING) 285e833251aSDavid Howells call->state = AFS_CALL_AWAIT_REPLY; 286e833251aSDavid Howells } 287e833251aSDavid Howells 288e833251aSDavid Howells /* 28931143d5dSDavid Howells * attach the data from a bunch of pages on an inode to a call 29031143d5dSDavid Howells */ 29139c6aceaSAl Viro static int afs_send_pages(struct afs_call *call, struct msghdr *msg) 29231143d5dSDavid Howells { 2932f5705a5SDavid Howells struct bio_vec bv[AFS_BVEC_MAX]; 2942f5705a5SDavid Howells unsigned int bytes, nr, loop, offset; 29531143d5dSDavid Howells pgoff_t first = call->first, last = call->last; 29631143d5dSDavid Howells int ret; 29731143d5dSDavid Howells 29831143d5dSDavid Howells offset = call->first_offset; 29931143d5dSDavid Howells call->first_offset = 0; 30031143d5dSDavid Howells 30131143d5dSDavid Howells do { 3022f5705a5SDavid Howells afs_load_bvec(call, msg, bv, first, last, offset); 30331143d5dSDavid Howells offset = 0; 3042f5705a5SDavid Howells bytes = msg->msg_iter.count; 3052f5705a5SDavid Howells nr = msg->msg_iter.nr_segs; 30631143d5dSDavid Howells 307f044c884SDavid Howells ret = rxrpc_kernel_send_data(call->net->socket, call->rxcall, msg, 308e833251aSDavid Howells bytes, afs_notify_end_request_tx); 3092f5705a5SDavid Howells for (loop = 0; loop < nr; loop++) 3102f5705a5SDavid Howells put_page(bv[loop].bv_page); 31131143d5dSDavid Howells if (ret < 0) 31231143d5dSDavid Howells break; 31331143d5dSDavid Howells 3142f5705a5SDavid Howells first += nr; 3155bbf5d39SDavid Howells } while (first <= last); 31631143d5dSDavid Howells 31731143d5dSDavid Howells return ret; 31831143d5dSDavid Howells } 31931143d5dSDavid Howells 32031143d5dSDavid Howells /* 32108e0e7c8SDavid Howells * initiate a call 32208e0e7c8SDavid Howells */ 3234d9df986SDavid Howells int afs_make_call(struct sockaddr_rxrpc *srx, struct afs_call *call, 3244d9df986SDavid Howells gfp_t gfp, bool async) 32508e0e7c8SDavid Howells { 32608e0e7c8SDavid Howells struct rxrpc_call *rxcall; 32708e0e7c8SDavid Howells struct msghdr msg; 32808e0e7c8SDavid Howells struct kvec iov[1]; 32970af0e3bSDavid Howells size_t offset; 330e754eba6SDavid Howells s64 tx_total_len; 33170af0e3bSDavid Howells u32 abort_code; 33208e0e7c8SDavid Howells int ret; 33308e0e7c8SDavid Howells 3344d9df986SDavid Howells _enter(",{%pISp},", &srx->transport); 33508e0e7c8SDavid Howells 33600d3b7a4SDavid Howells ASSERT(call->type != NULL); 33700d3b7a4SDavid Howells ASSERT(call->type->name != NULL); 33800d3b7a4SDavid Howells 33931143d5dSDavid Howells _debug("____MAKE %p{%s,%x} [%d]____", 34031143d5dSDavid Howells call, call->type->name, key_serial(call->key), 341f044c884SDavid Howells atomic_read(&call->net->nr_outstanding_calls)); 34200d3b7a4SDavid Howells 34356ff9c83SDavid Howells call->async = async; 34408e0e7c8SDavid Howells 345e754eba6SDavid Howells /* Work out the length we're going to transmit. This is awkward for 346e754eba6SDavid Howells * calls such as FS.StoreData where there's an extra injection of data 347e754eba6SDavid Howells * after the initial fixed part. 348e754eba6SDavid Howells */ 349e754eba6SDavid Howells tx_total_len = call->request_size; 350e754eba6SDavid Howells if (call->send_pages) { 351e754eba6SDavid Howells tx_total_len += call->last_to - call->first_offset; 352e754eba6SDavid Howells tx_total_len += (call->last - call->first) * PAGE_SIZE; 353e754eba6SDavid Howells } 354e754eba6SDavid Howells 35508e0e7c8SDavid Howells /* create a call */ 3564d9df986SDavid Howells rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key, 357e754eba6SDavid Howells (unsigned long)call, 358e754eba6SDavid Howells tx_total_len, gfp, 35956ff9c83SDavid Howells (async ? 36056ff9c83SDavid Howells afs_wake_up_async_call : 361a68f4a27SDavid Howells afs_wake_up_call_waiter), 362a68f4a27SDavid Howells call->upgrade); 36300d3b7a4SDavid Howells call->key = NULL; 36408e0e7c8SDavid Howells if (IS_ERR(rxcall)) { 36508e0e7c8SDavid Howells ret = PTR_ERR(rxcall); 36608e0e7c8SDavid Howells goto error_kill_call; 36708e0e7c8SDavid Howells } 36808e0e7c8SDavid Howells 36908e0e7c8SDavid Howells call->rxcall = rxcall; 37008e0e7c8SDavid Howells 37108e0e7c8SDavid Howells /* send the request */ 37208e0e7c8SDavid Howells iov[0].iov_base = call->request; 37308e0e7c8SDavid Howells iov[0].iov_len = call->request_size; 37408e0e7c8SDavid Howells 37508e0e7c8SDavid Howells msg.msg_name = NULL; 37608e0e7c8SDavid Howells msg.msg_namelen = 0; 3772e90b1c4SAl Viro iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iov, 1, 378c0371da6SAl Viro call->request_size); 37908e0e7c8SDavid Howells msg.msg_control = NULL; 38008e0e7c8SDavid Howells msg.msg_controllen = 0; 381bc5e3a54SDavid Howells msg.msg_flags = MSG_WAITALL | (call->send_pages ? MSG_MORE : 0); 38208e0e7c8SDavid Howells 38370af0e3bSDavid Howells /* We have to change the state *before* sending the last packet as 38470af0e3bSDavid Howells * rxrpc might give us the reply before it returns from sending the 38570af0e3bSDavid Howells * request. Further, if the send fails, we may already have been given 38670af0e3bSDavid Howells * a notification and may have collected it. 38770af0e3bSDavid Howells */ 38831143d5dSDavid Howells if (!call->send_pages) 38908e0e7c8SDavid Howells call->state = AFS_CALL_AWAIT_REPLY; 390f044c884SDavid Howells ret = rxrpc_kernel_send_data(call->net->socket, rxcall, 391e833251aSDavid Howells &msg, call->request_size, 392e833251aSDavid Howells afs_notify_end_request_tx); 39308e0e7c8SDavid Howells if (ret < 0) 39408e0e7c8SDavid Howells goto error_do_abort; 39508e0e7c8SDavid Howells 39631143d5dSDavid Howells if (call->send_pages) { 39739c6aceaSAl Viro ret = afs_send_pages(call, &msg); 39831143d5dSDavid Howells if (ret < 0) 39931143d5dSDavid Howells goto error_do_abort; 40031143d5dSDavid Howells } 40131143d5dSDavid Howells 40208e0e7c8SDavid Howells /* at this point, an async call may no longer exist as it may have 40308e0e7c8SDavid Howells * already completed */ 40456ff9c83SDavid Howells if (call->async) 40556ff9c83SDavid Howells return -EINPROGRESS; 40656ff9c83SDavid Howells 40756ff9c83SDavid Howells return afs_wait_for_call_to_complete(call); 40808e0e7c8SDavid Howells 40908e0e7c8SDavid Howells error_do_abort: 41070af0e3bSDavid Howells call->state = AFS_CALL_COMPLETE; 41170af0e3bSDavid Howells if (ret != -ECONNABORTED) { 412f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, rxcall, 413f044c884SDavid Howells RX_USER_ABORT, ret, "KSD"); 41470af0e3bSDavid Howells } else { 41570af0e3bSDavid Howells abort_code = 0; 41670af0e3bSDavid Howells offset = 0; 417f044c884SDavid Howells rxrpc_kernel_recv_data(call->net->socket, rxcall, NULL, 418f044c884SDavid Howells 0, &offset, false, &abort_code, 419f044c884SDavid Howells &call->service_id); 420f780c8eaSDavid Howells ret = afs_abort_to_error(abort_code); 42170af0e3bSDavid Howells } 42208e0e7c8SDavid Howells error_kill_call: 423341f741fSDavid Howells afs_put_call(call); 42408e0e7c8SDavid Howells _leave(" = %d", ret); 42508e0e7c8SDavid Howells return ret; 42608e0e7c8SDavid Howells } 42708e0e7c8SDavid Howells 42808e0e7c8SDavid Howells /* 42908e0e7c8SDavid Howells * deliver messages to a call 43008e0e7c8SDavid Howells */ 43108e0e7c8SDavid Howells static void afs_deliver_to_call(struct afs_call *call) 43208e0e7c8SDavid Howells { 43308e0e7c8SDavid Howells u32 abort_code; 43408e0e7c8SDavid Howells int ret; 43508e0e7c8SDavid Howells 436d001648eSDavid Howells _enter("%s", call->type->name); 43708e0e7c8SDavid Howells 438d001648eSDavid Howells while (call->state == AFS_CALL_AWAIT_REPLY || 43908e0e7c8SDavid Howells call->state == AFS_CALL_AWAIT_OP_ID || 44008e0e7c8SDavid Howells call->state == AFS_CALL_AWAIT_REQUEST || 441d001648eSDavid Howells call->state == AFS_CALL_AWAIT_ACK 442d001648eSDavid Howells ) { 443d001648eSDavid Howells if (call->state == AFS_CALL_AWAIT_ACK) { 444d001648eSDavid Howells size_t offset = 0; 445f044c884SDavid Howells ret = rxrpc_kernel_recv_data(call->net->socket, 446f044c884SDavid Howells call->rxcall, 447d001648eSDavid Howells NULL, 0, &offset, false, 448a68f4a27SDavid Howells &call->abort_code, 449a68f4a27SDavid Howells &call->service_id); 4508e8d7f13SDavid Howells trace_afs_recv_data(call, 0, offset, false, ret); 4518e8d7f13SDavid Howells 452d001648eSDavid Howells if (ret == -EINPROGRESS || ret == -EAGAIN) 453d001648eSDavid Howells return; 4549008f998SDavid Howells if (ret == 1 || ret < 0) { 455d001648eSDavid Howells call->state = AFS_CALL_COMPLETE; 456d001648eSDavid Howells goto done; 457372ee163SDavid Howells } 458d001648eSDavid Howells return; 459d001648eSDavid Howells } 460d001648eSDavid Howells 461d001648eSDavid Howells ret = call->type->deliver(call); 462d001648eSDavid Howells switch (ret) { 46308e0e7c8SDavid Howells case 0: 464372ee163SDavid Howells if (call->state == AFS_CALL_AWAIT_REPLY) 46508e0e7c8SDavid Howells call->state = AFS_CALL_COMPLETE; 466d001648eSDavid Howells goto done; 467d001648eSDavid Howells case -EINPROGRESS: 468d001648eSDavid Howells case -EAGAIN: 469d001648eSDavid Howells goto out; 47070af0e3bSDavid Howells case -ECONNABORTED: 47170af0e3bSDavid Howells goto call_complete; 47208e0e7c8SDavid Howells case -ENOTCONN: 47308e0e7c8SDavid Howells abort_code = RX_CALL_DEAD; 474f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 4753a92789aSDavid Howells abort_code, ret, "KNC"); 47670af0e3bSDavid Howells goto save_error; 47708e0e7c8SDavid Howells case -ENOTSUPP: 4781157f153SDavid Howells abort_code = RXGEN_OPCODE; 479f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 4803a92789aSDavid Howells abort_code, ret, "KIV"); 48170af0e3bSDavid Howells goto save_error; 482d001648eSDavid Howells case -ENODATA: 483d001648eSDavid Howells case -EBADMSG: 484d001648eSDavid Howells case -EMSGSIZE: 48508e0e7c8SDavid Howells default: 48608e0e7c8SDavid Howells abort_code = RXGEN_CC_UNMARSHAL; 48708e0e7c8SDavid Howells if (call->state != AFS_CALL_AWAIT_REPLY) 48808e0e7c8SDavid Howells abort_code = RXGEN_SS_UNMARSHAL; 489f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 4903a92789aSDavid Howells abort_code, -EBADMSG, "KUM"); 49170af0e3bSDavid Howells goto save_error; 49208e0e7c8SDavid Howells } 49308e0e7c8SDavid Howells } 49408e0e7c8SDavid Howells 495d001648eSDavid Howells done: 496d001648eSDavid Howells if (call->state == AFS_CALL_COMPLETE && call->incoming) 497341f741fSDavid Howells afs_put_call(call); 498d001648eSDavid Howells out: 49908e0e7c8SDavid Howells _leave(""); 500d001648eSDavid Howells return; 501d001648eSDavid Howells 50270af0e3bSDavid Howells save_error: 503d001648eSDavid Howells call->error = ret; 50470af0e3bSDavid Howells call_complete: 505d001648eSDavid Howells call->state = AFS_CALL_COMPLETE; 506d001648eSDavid Howells goto done; 50708e0e7c8SDavid Howells } 50808e0e7c8SDavid Howells 50908e0e7c8SDavid Howells /* 51008e0e7c8SDavid Howells * wait synchronously for a call to complete 51108e0e7c8SDavid Howells */ 51208e0e7c8SDavid Howells static int afs_wait_for_call_to_complete(struct afs_call *call) 51308e0e7c8SDavid Howells { 514bc5e3a54SDavid Howells signed long rtt2, timeout; 51508e0e7c8SDavid Howells int ret; 516bc5e3a54SDavid Howells u64 rtt; 517bc5e3a54SDavid Howells u32 life, last_life; 51808e0e7c8SDavid Howells 51908e0e7c8SDavid Howells DECLARE_WAITQUEUE(myself, current); 52008e0e7c8SDavid Howells 52108e0e7c8SDavid Howells _enter(""); 52208e0e7c8SDavid Howells 523f044c884SDavid Howells rtt = rxrpc_kernel_get_rtt(call->net->socket, call->rxcall); 524bc5e3a54SDavid Howells rtt2 = nsecs_to_jiffies64(rtt) * 2; 525bc5e3a54SDavid Howells if (rtt2 < 2) 526bc5e3a54SDavid Howells rtt2 = 2; 527bc5e3a54SDavid Howells 528bc5e3a54SDavid Howells timeout = rtt2; 529f044c884SDavid Howells last_life = rxrpc_kernel_check_life(call->net->socket, call->rxcall); 530bc5e3a54SDavid Howells 53108e0e7c8SDavid Howells add_wait_queue(&call->waitq, &myself); 53208e0e7c8SDavid Howells for (;;) { 533bc5e3a54SDavid Howells set_current_state(TASK_UNINTERRUPTIBLE); 53408e0e7c8SDavid Howells 53508e0e7c8SDavid Howells /* deliver any messages that are in the queue */ 536d001648eSDavid Howells if (call->state < AFS_CALL_COMPLETE && call->need_attention) { 537d001648eSDavid Howells call->need_attention = false; 53808e0e7c8SDavid Howells __set_current_state(TASK_RUNNING); 53908e0e7c8SDavid Howells afs_deliver_to_call(call); 54008e0e7c8SDavid Howells continue; 54108e0e7c8SDavid Howells } 54208e0e7c8SDavid Howells 543bc5e3a54SDavid Howells if (call->state == AFS_CALL_COMPLETE) 54408e0e7c8SDavid Howells break; 545bc5e3a54SDavid Howells 546f044c884SDavid Howells life = rxrpc_kernel_check_life(call->net->socket, call->rxcall); 547bc5e3a54SDavid Howells if (timeout == 0 && 548bc5e3a54SDavid Howells life == last_life && signal_pending(current)) 549bc5e3a54SDavid Howells break; 550bc5e3a54SDavid Howells 551bc5e3a54SDavid Howells if (life != last_life) { 552bc5e3a54SDavid Howells timeout = rtt2; 553bc5e3a54SDavid Howells last_life = life; 554bc5e3a54SDavid Howells } 555bc5e3a54SDavid Howells 556bc5e3a54SDavid Howells timeout = schedule_timeout(timeout); 55708e0e7c8SDavid Howells } 55808e0e7c8SDavid Howells 55908e0e7c8SDavid Howells remove_wait_queue(&call->waitq, &myself); 56008e0e7c8SDavid Howells __set_current_state(TASK_RUNNING); 56108e0e7c8SDavid Howells 562954cd6dcSDavid Howells /* Kill off the call if it's still live. */ 56308e0e7c8SDavid Howells if (call->state < AFS_CALL_COMPLETE) { 564954cd6dcSDavid Howells _debug("call interrupted"); 565f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 566954cd6dcSDavid Howells RX_USER_ABORT, -EINTR, "KWI"); 56708e0e7c8SDavid Howells } 56808e0e7c8SDavid Howells 569954cd6dcSDavid Howells ret = call->error; 57008e0e7c8SDavid Howells _debug("call complete"); 571341f741fSDavid Howells afs_put_call(call); 57208e0e7c8SDavid Howells _leave(" = %d", ret); 57308e0e7c8SDavid Howells return ret; 57408e0e7c8SDavid Howells } 57508e0e7c8SDavid Howells 57608e0e7c8SDavid Howells /* 57708e0e7c8SDavid Howells * wake up a waiting call 57808e0e7c8SDavid Howells */ 579d001648eSDavid Howells static void afs_wake_up_call_waiter(struct sock *sk, struct rxrpc_call *rxcall, 580d001648eSDavid Howells unsigned long call_user_ID) 58108e0e7c8SDavid Howells { 582d001648eSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 583d001648eSDavid Howells 584d001648eSDavid Howells call->need_attention = true; 58508e0e7c8SDavid Howells wake_up(&call->waitq); 58608e0e7c8SDavid Howells } 58708e0e7c8SDavid Howells 58808e0e7c8SDavid Howells /* 58908e0e7c8SDavid Howells * wake up an asynchronous call 59008e0e7c8SDavid Howells */ 591d001648eSDavid Howells static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall, 592d001648eSDavid Howells unsigned long call_user_ID) 59308e0e7c8SDavid Howells { 594d001648eSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 595341f741fSDavid Howells int u; 596d001648eSDavid Howells 5978e8d7f13SDavid Howells trace_afs_notify_call(rxcall, call); 598d001648eSDavid Howells call->need_attention = true; 599341f741fSDavid Howells 600341f741fSDavid Howells u = __atomic_add_unless(&call->usage, 1, 0); 601341f741fSDavid Howells if (u != 0) { 602341f741fSDavid Howells trace_afs_call(call, afs_call_trace_wake, u, 603f044c884SDavid Howells atomic_read(&call->net->nr_outstanding_calls), 604341f741fSDavid Howells __builtin_return_address(0)); 605341f741fSDavid Howells 606341f741fSDavid Howells if (!queue_work(afs_async_calls, &call->async_work)) 607341f741fSDavid Howells afs_put_call(call); 608341f741fSDavid Howells } 60908e0e7c8SDavid Howells } 61008e0e7c8SDavid Howells 61108e0e7c8SDavid Howells /* 612341f741fSDavid Howells * Delete an asynchronous call. The work item carries a ref to the call struct 613341f741fSDavid Howells * that we need to release. 61408e0e7c8SDavid Howells */ 615d001648eSDavid Howells static void afs_delete_async_call(struct work_struct *work) 61608e0e7c8SDavid Howells { 617d001648eSDavid Howells struct afs_call *call = container_of(work, struct afs_call, async_work); 618d001648eSDavid Howells 61908e0e7c8SDavid Howells _enter(""); 62008e0e7c8SDavid Howells 621341f741fSDavid Howells afs_put_call(call); 62208e0e7c8SDavid Howells 62308e0e7c8SDavid Howells _leave(""); 62408e0e7c8SDavid Howells } 62508e0e7c8SDavid Howells 62608e0e7c8SDavid Howells /* 627341f741fSDavid Howells * Perform I/O processing on an asynchronous call. The work item carries a ref 628341f741fSDavid Howells * to the call struct that we either need to release or to pass on. 62908e0e7c8SDavid Howells */ 630d001648eSDavid Howells static void afs_process_async_call(struct work_struct *work) 63108e0e7c8SDavid Howells { 632d001648eSDavid Howells struct afs_call *call = container_of(work, struct afs_call, async_work); 633d001648eSDavid Howells 63408e0e7c8SDavid Howells _enter(""); 63508e0e7c8SDavid Howells 636d001648eSDavid Howells if (call->state < AFS_CALL_COMPLETE && call->need_attention) { 637d001648eSDavid Howells call->need_attention = false; 63808e0e7c8SDavid Howells afs_deliver_to_call(call); 639d001648eSDavid Howells } 64008e0e7c8SDavid Howells 64156ff9c83SDavid Howells if (call->state == AFS_CALL_COMPLETE) { 64208e0e7c8SDavid Howells call->reply = NULL; 64308e0e7c8SDavid Howells 644341f741fSDavid Howells /* We have two refs to release - one from the alloc and one 645341f741fSDavid Howells * queued with the work item - and we can't just deallocate the 646341f741fSDavid Howells * call because the work item may be queued again. 647341f741fSDavid Howells */ 648d001648eSDavid Howells call->async_work.func = afs_delete_async_call; 649341f741fSDavid Howells if (!queue_work(afs_async_calls, &call->async_work)) 650341f741fSDavid Howells afs_put_call(call); 65108e0e7c8SDavid Howells } 65208e0e7c8SDavid Howells 653341f741fSDavid Howells afs_put_call(call); 65408e0e7c8SDavid Howells _leave(""); 65508e0e7c8SDavid Howells } 65608e0e7c8SDavid Howells 65700e90712SDavid Howells static void afs_rx_attach(struct rxrpc_call *rxcall, unsigned long user_call_ID) 65800e90712SDavid Howells { 65900e90712SDavid Howells struct afs_call *call = (struct afs_call *)user_call_ID; 66000e90712SDavid Howells 66100e90712SDavid Howells call->rxcall = rxcall; 66200e90712SDavid Howells } 66300e90712SDavid Howells 66400e90712SDavid Howells /* 66500e90712SDavid Howells * Charge the incoming call preallocation. 66600e90712SDavid Howells */ 667f044c884SDavid Howells void afs_charge_preallocation(struct work_struct *work) 66800e90712SDavid Howells { 669f044c884SDavid Howells struct afs_net *net = 670f044c884SDavid Howells container_of(work, struct afs_net, charge_preallocation_work); 671f044c884SDavid Howells struct afs_call *call = net->spare_incoming_call; 67200e90712SDavid Howells 67300e90712SDavid Howells for (;;) { 67400e90712SDavid Howells if (!call) { 675f044c884SDavid Howells call = afs_alloc_call(net, &afs_RXCMxxxx, GFP_KERNEL); 67600e90712SDavid Howells if (!call) 67700e90712SDavid Howells break; 67800e90712SDavid Howells 67956ff9c83SDavid Howells call->async = true; 68000e90712SDavid Howells call->state = AFS_CALL_AWAIT_OP_ID; 68156ff9c83SDavid Howells init_waitqueue_head(&call->waitq); 68200e90712SDavid Howells } 68300e90712SDavid Howells 684f044c884SDavid Howells if (rxrpc_kernel_charge_accept(net->socket, 68500e90712SDavid Howells afs_wake_up_async_call, 68600e90712SDavid Howells afs_rx_attach, 68700e90712SDavid Howells (unsigned long)call, 68800e90712SDavid Howells GFP_KERNEL) < 0) 68900e90712SDavid Howells break; 69000e90712SDavid Howells call = NULL; 69100e90712SDavid Howells } 692f044c884SDavid Howells net->spare_incoming_call = call; 69300e90712SDavid Howells } 69400e90712SDavid Howells 69500e90712SDavid Howells /* 69600e90712SDavid Howells * Discard a preallocated call when a socket is shut down. 69700e90712SDavid Howells */ 69800e90712SDavid Howells static void afs_rx_discard_new_call(struct rxrpc_call *rxcall, 69900e90712SDavid Howells unsigned long user_call_ID) 70000e90712SDavid Howells { 70100e90712SDavid Howells struct afs_call *call = (struct afs_call *)user_call_ID; 70200e90712SDavid Howells 70300e90712SDavid Howells call->rxcall = NULL; 704341f741fSDavid Howells afs_put_call(call); 70500e90712SDavid Howells } 70600e90712SDavid Howells 70708e0e7c8SDavid Howells /* 708d001648eSDavid Howells * Notification of an incoming call. 709d001648eSDavid Howells */ 71000e90712SDavid Howells static void afs_rx_new_call(struct sock *sk, struct rxrpc_call *rxcall, 71100e90712SDavid Howells unsigned long user_call_ID) 712d001648eSDavid Howells { 713f044c884SDavid Howells struct afs_net *net = afs_sock2net(sk); 714f044c884SDavid Howells 715f044c884SDavid Howells queue_work(afs_wq, &net->charge_preallocation_work); 716d001648eSDavid Howells } 717d001648eSDavid Howells 718d001648eSDavid Howells /* 719372ee163SDavid Howells * Grab the operation ID from an incoming cache manager call. The socket 720372ee163SDavid Howells * buffer is discarded on error or if we don't yet have sufficient data. 72108e0e7c8SDavid Howells */ 722d001648eSDavid Howells static int afs_deliver_cm_op_id(struct afs_call *call) 72308e0e7c8SDavid Howells { 724d001648eSDavid Howells int ret; 72508e0e7c8SDavid Howells 726d001648eSDavid Howells _enter("{%zu}", call->offset); 72708e0e7c8SDavid Howells 72808e0e7c8SDavid Howells ASSERTCMP(call->offset, <, 4); 72908e0e7c8SDavid Howells 73008e0e7c8SDavid Howells /* the operation ID forms the first four bytes of the request data */ 73150a2c953SDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 732d001648eSDavid Howells if (ret < 0) 733d001648eSDavid Howells return ret; 73408e0e7c8SDavid Howells 73550a2c953SDavid Howells call->operation_ID = ntohl(call->tmp); 73608e0e7c8SDavid Howells call->state = AFS_CALL_AWAIT_REQUEST; 737d001648eSDavid Howells call->offset = 0; 73808e0e7c8SDavid Howells 73908e0e7c8SDavid Howells /* ask the cache manager to route the call (it'll change the call type 74008e0e7c8SDavid Howells * if successful) */ 74108e0e7c8SDavid Howells if (!afs_cm_incoming_call(call)) 74208e0e7c8SDavid Howells return -ENOTSUPP; 74308e0e7c8SDavid Howells 7448e8d7f13SDavid Howells trace_afs_cb_call(call); 7458e8d7f13SDavid Howells 74608e0e7c8SDavid Howells /* pass responsibility for the remainer of this message off to the 74708e0e7c8SDavid Howells * cache manager op */ 748d001648eSDavid Howells return call->type->deliver(call); 74908e0e7c8SDavid Howells } 75008e0e7c8SDavid Howells 75108e0e7c8SDavid Howells /* 752e833251aSDavid Howells * Advance the AFS call state when an RxRPC service call ends the transmit 753e833251aSDavid Howells * phase. 754e833251aSDavid Howells */ 755e833251aSDavid Howells static void afs_notify_end_reply_tx(struct sock *sock, 756e833251aSDavid Howells struct rxrpc_call *rxcall, 757e833251aSDavid Howells unsigned long call_user_ID) 758e833251aSDavid Howells { 759e833251aSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 760e833251aSDavid Howells 761e833251aSDavid Howells if (call->state == AFS_CALL_REPLYING) 762e833251aSDavid Howells call->state = AFS_CALL_AWAIT_ACK; 763e833251aSDavid Howells } 764e833251aSDavid Howells 765e833251aSDavid Howells /* 76608e0e7c8SDavid Howells * send an empty reply 76708e0e7c8SDavid Howells */ 76808e0e7c8SDavid Howells void afs_send_empty_reply(struct afs_call *call) 76908e0e7c8SDavid Howells { 770f044c884SDavid Howells struct afs_net *net = call->net; 77108e0e7c8SDavid Howells struct msghdr msg; 77208e0e7c8SDavid Howells 77308e0e7c8SDavid Howells _enter(""); 77408e0e7c8SDavid Howells 775f044c884SDavid Howells rxrpc_kernel_set_tx_length(net->socket, call->rxcall, 0); 776e754eba6SDavid Howells 77708e0e7c8SDavid Howells msg.msg_name = NULL; 77808e0e7c8SDavid Howells msg.msg_namelen = 0; 779bfd4e956SDavid Howells iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, NULL, 0, 0); 78008e0e7c8SDavid Howells msg.msg_control = NULL; 78108e0e7c8SDavid Howells msg.msg_controllen = 0; 78208e0e7c8SDavid Howells msg.msg_flags = 0; 78308e0e7c8SDavid Howells 78408e0e7c8SDavid Howells call->state = AFS_CALL_AWAIT_ACK; 785f044c884SDavid Howells switch (rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, 0, 786e833251aSDavid Howells afs_notify_end_reply_tx)) { 78708e0e7c8SDavid Howells case 0: 78808e0e7c8SDavid Howells _leave(" [replied]"); 78908e0e7c8SDavid Howells return; 79008e0e7c8SDavid Howells 79108e0e7c8SDavid Howells case -ENOMEM: 79208e0e7c8SDavid Howells _debug("oom"); 793f044c884SDavid Howells rxrpc_kernel_abort_call(net->socket, call->rxcall, 7943a92789aSDavid Howells RX_USER_ABORT, -ENOMEM, "KOO"); 79508e0e7c8SDavid Howells default: 79608e0e7c8SDavid Howells _leave(" [error]"); 79708e0e7c8SDavid Howells return; 79808e0e7c8SDavid Howells } 79908e0e7c8SDavid Howells } 80008e0e7c8SDavid Howells 80108e0e7c8SDavid Howells /* 802b908fe6bSDavid Howells * send a simple reply 803b908fe6bSDavid Howells */ 804b908fe6bSDavid Howells void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) 805b908fe6bSDavid Howells { 806f044c884SDavid Howells struct afs_net *net = call->net; 807b908fe6bSDavid Howells struct msghdr msg; 8082e90b1c4SAl Viro struct kvec iov[1]; 809bd6dc742SDavid Howells int n; 810b908fe6bSDavid Howells 811b908fe6bSDavid Howells _enter(""); 812b908fe6bSDavid Howells 813f044c884SDavid Howells rxrpc_kernel_set_tx_length(net->socket, call->rxcall, len); 814e754eba6SDavid Howells 815b908fe6bSDavid Howells iov[0].iov_base = (void *) buf; 816b908fe6bSDavid Howells iov[0].iov_len = len; 817b908fe6bSDavid Howells msg.msg_name = NULL; 818b908fe6bSDavid Howells msg.msg_namelen = 0; 8192e90b1c4SAl Viro iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iov, 1, len); 820b908fe6bSDavid Howells msg.msg_control = NULL; 821b908fe6bSDavid Howells msg.msg_controllen = 0; 822b908fe6bSDavid Howells msg.msg_flags = 0; 823b908fe6bSDavid Howells 824b908fe6bSDavid Howells call->state = AFS_CALL_AWAIT_ACK; 825f044c884SDavid Howells n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, len, 826e833251aSDavid Howells afs_notify_end_reply_tx); 827bd6dc742SDavid Howells if (n >= 0) { 8286c67c7c3SDavid Howells /* Success */ 829b908fe6bSDavid Howells _leave(" [replied]"); 830b908fe6bSDavid Howells return; 831bd6dc742SDavid Howells } 8326c67c7c3SDavid Howells 833bd6dc742SDavid Howells if (n == -ENOMEM) { 834b908fe6bSDavid Howells _debug("oom"); 835f044c884SDavid Howells rxrpc_kernel_abort_call(net->socket, call->rxcall, 8363a92789aSDavid Howells RX_USER_ABORT, -ENOMEM, "KOO"); 837bd6dc742SDavid Howells } 838b908fe6bSDavid Howells _leave(" [error]"); 839b908fe6bSDavid Howells } 840b908fe6bSDavid Howells 841b908fe6bSDavid Howells /* 842372ee163SDavid Howells * Extract a piece of data from the received data socket buffers. 84308e0e7c8SDavid Howells */ 844d001648eSDavid Howells int afs_extract_data(struct afs_call *call, void *buf, size_t count, 845d001648eSDavid Howells bool want_more) 84608e0e7c8SDavid Howells { 847f044c884SDavid Howells struct afs_net *net = call->net; 848d001648eSDavid Howells int ret; 84908e0e7c8SDavid Howells 850d001648eSDavid Howells _enter("{%s,%zu},,%zu,%d", 851d001648eSDavid Howells call->type->name, call->offset, count, want_more); 85208e0e7c8SDavid Howells 853d001648eSDavid Howells ASSERTCMP(call->offset, <=, count); 85408e0e7c8SDavid Howells 855f044c884SDavid Howells ret = rxrpc_kernel_recv_data(net->socket, call->rxcall, 856d001648eSDavid Howells buf, count, &call->offset, 857a68f4a27SDavid Howells want_more, &call->abort_code, 858a68f4a27SDavid Howells &call->service_id); 8598e8d7f13SDavid Howells trace_afs_recv_data(call, count, call->offset, want_more, ret); 860d001648eSDavid Howells if (ret == 0 || ret == -EAGAIN) 861d001648eSDavid Howells return ret; 86208e0e7c8SDavid Howells 863d001648eSDavid Howells if (ret == 1) { 864d001648eSDavid Howells switch (call->state) { 865d001648eSDavid Howells case AFS_CALL_AWAIT_REPLY: 866d001648eSDavid Howells call->state = AFS_CALL_COMPLETE; 867d001648eSDavid Howells break; 868d001648eSDavid Howells case AFS_CALL_AWAIT_REQUEST: 869d001648eSDavid Howells call->state = AFS_CALL_REPLYING; 870d001648eSDavid Howells break; 871d001648eSDavid Howells default: 872d001648eSDavid Howells break; 87308e0e7c8SDavid Howells } 87408e0e7c8SDavid Howells return 0; 87508e0e7c8SDavid Howells } 876d001648eSDavid Howells 877d001648eSDavid Howells if (ret == -ECONNABORTED) 878f780c8eaSDavid Howells call->error = afs_abort_to_error(call->abort_code); 879d001648eSDavid Howells else 880d001648eSDavid Howells call->error = ret; 881d001648eSDavid Howells call->state = AFS_CALL_COMPLETE; 882d001648eSDavid Howells return ret; 883d001648eSDavid Howells } 884