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 <rxrpc/packet.h> 1808e0e7c8SDavid Howells #include "internal.h" 1908e0e7c8SDavid Howells #include "afs_cm.h" 2008e0e7c8SDavid Howells 218324f0bcSDavid Howells struct socket *afs_socket; /* my RxRPC socket */ 2208e0e7c8SDavid Howells static struct workqueue_struct *afs_async_calls; 2300e90712SDavid Howells static struct afs_call *afs_spare_incoming_call; 24341f741fSDavid Howells atomic_t afs_outstanding_calls; 2508e0e7c8SDavid Howells 26d001648eSDavid Howells static void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long); 2708e0e7c8SDavid Howells static int afs_wait_for_call_to_complete(struct afs_call *); 28d001648eSDavid Howells static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long); 29d001648eSDavid Howells static void afs_process_async_call(struct work_struct *); 3000e90712SDavid Howells static void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long); 3100e90712SDavid Howells static void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long); 32d001648eSDavid Howells static int afs_deliver_cm_op_id(struct afs_call *); 3308e0e7c8SDavid Howells 3408e0e7c8SDavid Howells /* asynchronous incoming call initial processing */ 3508e0e7c8SDavid Howells static const struct afs_call_type afs_RXCMxxxx = { 3600d3b7a4SDavid Howells .name = "CB.xxxx", 3708e0e7c8SDavid Howells .deliver = afs_deliver_cm_op_id, 3808e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 3908e0e7c8SDavid Howells }; 4008e0e7c8SDavid Howells 4100e90712SDavid Howells static void afs_charge_preallocation(struct work_struct *); 4208e0e7c8SDavid Howells 4300e90712SDavid Howells static DECLARE_WORK(afs_charge_preallocation_work, afs_charge_preallocation); 4408e0e7c8SDavid Howells 452f02f7aeSDavid Howells static int afs_wait_atomic_t(atomic_t *p) 462f02f7aeSDavid Howells { 472f02f7aeSDavid Howells schedule(); 482f02f7aeSDavid Howells return 0; 492f02f7aeSDavid Howells } 502f02f7aeSDavid Howells 5108e0e7c8SDavid Howells /* 5208e0e7c8SDavid Howells * open an RxRPC socket and bind it to be a server for callback notifications 5308e0e7c8SDavid Howells * - the socket is left in blocking mode and non-blocking ops use MSG_DONTWAIT 5408e0e7c8SDavid Howells */ 5508e0e7c8SDavid Howells int afs_open_socket(void) 5608e0e7c8SDavid Howells { 5708e0e7c8SDavid Howells struct sockaddr_rxrpc srx; 5808e0e7c8SDavid Howells struct socket *socket; 5908e0e7c8SDavid Howells int ret; 6008e0e7c8SDavid Howells 6108e0e7c8SDavid Howells _enter(""); 6208e0e7c8SDavid Howells 630e119b41SDavid Howells ret = -ENOMEM; 6469ad052aSBhaktipriya Shridhar afs_async_calls = alloc_workqueue("kafsd", WQ_MEM_RECLAIM, 0); 650e119b41SDavid Howells if (!afs_async_calls) 660e119b41SDavid Howells goto error_0; 6708e0e7c8SDavid Howells 68eeb1bd5cSEric W. Biederman ret = sock_create_kern(&init_net, AF_RXRPC, SOCK_DGRAM, PF_INET, &socket); 690e119b41SDavid Howells if (ret < 0) 700e119b41SDavid Howells goto error_1; 7108e0e7c8SDavid Howells 7208e0e7c8SDavid Howells socket->sk->sk_allocation = GFP_NOFS; 7308e0e7c8SDavid Howells 7408e0e7c8SDavid Howells /* bind the callback manager's address to make this a server socket */ 7508e0e7c8SDavid Howells srx.srx_family = AF_RXRPC; 7608e0e7c8SDavid Howells srx.srx_service = CM_SERVICE; 7708e0e7c8SDavid Howells srx.transport_type = SOCK_DGRAM; 7808e0e7c8SDavid Howells srx.transport_len = sizeof(srx.transport.sin); 7908e0e7c8SDavid Howells srx.transport.sin.sin_family = AF_INET; 8008e0e7c8SDavid Howells srx.transport.sin.sin_port = htons(AFS_CM_PORT); 8108e0e7c8SDavid Howells memset(&srx.transport.sin.sin_addr, 0, 8208e0e7c8SDavid Howells sizeof(srx.transport.sin.sin_addr)); 8308e0e7c8SDavid Howells 8408e0e7c8SDavid Howells ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); 850e119b41SDavid Howells if (ret < 0) 860e119b41SDavid Howells goto error_2; 870e119b41SDavid Howells 8800e90712SDavid Howells rxrpc_kernel_new_call_notification(socket, afs_rx_new_call, 8900e90712SDavid Howells afs_rx_discard_new_call); 90d001648eSDavid Howells 910e119b41SDavid Howells ret = kernel_listen(socket, INT_MAX); 920e119b41SDavid Howells if (ret < 0) 930e119b41SDavid Howells goto error_2; 9408e0e7c8SDavid Howells 9508e0e7c8SDavid Howells afs_socket = socket; 9600e90712SDavid Howells afs_charge_preallocation(NULL); 9708e0e7c8SDavid Howells _leave(" = 0"); 9808e0e7c8SDavid Howells return 0; 990e119b41SDavid Howells 1000e119b41SDavid Howells error_2: 1010e119b41SDavid Howells sock_release(socket); 1020e119b41SDavid Howells error_1: 1030e119b41SDavid Howells destroy_workqueue(afs_async_calls); 1040e119b41SDavid Howells error_0: 1050e119b41SDavid Howells _leave(" = %d", ret); 1060e119b41SDavid Howells return ret; 10708e0e7c8SDavid Howells } 10808e0e7c8SDavid Howells 10908e0e7c8SDavid Howells /* 11008e0e7c8SDavid Howells * close the RxRPC socket AFS was using 11108e0e7c8SDavid Howells */ 11208e0e7c8SDavid Howells void afs_close_socket(void) 11308e0e7c8SDavid Howells { 11408e0e7c8SDavid Howells _enter(""); 11508e0e7c8SDavid Howells 116341f741fSDavid Howells kernel_listen(afs_socket, 0); 117341f741fSDavid Howells flush_workqueue(afs_async_calls); 118341f741fSDavid Howells 11900e90712SDavid Howells if (afs_spare_incoming_call) { 120341f741fSDavid Howells afs_put_call(afs_spare_incoming_call); 12100e90712SDavid Howells afs_spare_incoming_call = NULL; 12200e90712SDavid Howells } 12300e90712SDavid Howells 124d001648eSDavid Howells _debug("outstanding %u", atomic_read(&afs_outstanding_calls)); 1252f02f7aeSDavid Howells wait_on_atomic_t(&afs_outstanding_calls, afs_wait_atomic_t, 1262f02f7aeSDavid Howells TASK_UNINTERRUPTIBLE); 1272f02f7aeSDavid Howells _debug("no outstanding calls"); 1282f02f7aeSDavid Howells 129248f219cSDavid Howells kernel_sock_shutdown(afs_socket, SHUT_RDWR); 130248f219cSDavid Howells flush_workqueue(afs_async_calls); 13108e0e7c8SDavid Howells sock_release(afs_socket); 13208e0e7c8SDavid Howells 13308e0e7c8SDavid Howells _debug("dework"); 13408e0e7c8SDavid Howells destroy_workqueue(afs_async_calls); 13508e0e7c8SDavid Howells _leave(""); 13608e0e7c8SDavid Howells } 13708e0e7c8SDavid Howells 13808e0e7c8SDavid Howells /* 139341f741fSDavid Howells * Allocate a call. 14000d3b7a4SDavid Howells */ 141341f741fSDavid Howells static struct afs_call *afs_alloc_call(const struct afs_call_type *type, 142341f741fSDavid Howells gfp_t gfp) 14300d3b7a4SDavid Howells { 144341f741fSDavid Howells struct afs_call *call; 145341f741fSDavid Howells int o; 14600d3b7a4SDavid Howells 147341f741fSDavid Howells call = kzalloc(sizeof(*call), gfp); 148341f741fSDavid Howells if (!call) 149341f741fSDavid Howells return NULL; 15000d3b7a4SDavid Howells 151341f741fSDavid Howells call->type = type; 152341f741fSDavid Howells atomic_set(&call->usage, 1); 153341f741fSDavid Howells INIT_WORK(&call->async_work, afs_process_async_call); 154341f741fSDavid Howells init_waitqueue_head(&call->waitq); 1552f02f7aeSDavid Howells 156341f741fSDavid Howells o = atomic_inc_return(&afs_outstanding_calls); 157341f741fSDavid Howells trace_afs_call(call, afs_call_trace_alloc, 1, o, 158341f741fSDavid Howells __builtin_return_address(0)); 159341f741fSDavid Howells return call; 16000d3b7a4SDavid Howells } 16100d3b7a4SDavid Howells 16200d3b7a4SDavid Howells /* 163341f741fSDavid Howells * Dispose of a reference on a call. 1646c67c7c3SDavid Howells */ 165341f741fSDavid Howells void afs_put_call(struct afs_call *call) 1666c67c7c3SDavid Howells { 167341f741fSDavid Howells int n = atomic_dec_return(&call->usage); 168341f741fSDavid Howells int o = atomic_read(&afs_outstanding_calls); 169341f741fSDavid Howells 170341f741fSDavid Howells trace_afs_call(call, afs_call_trace_put, n + 1, o, 171341f741fSDavid Howells __builtin_return_address(0)); 172341f741fSDavid Howells 173341f741fSDavid Howells ASSERTCMP(n, >=, 0); 174341f741fSDavid Howells if (n == 0) { 175341f741fSDavid Howells ASSERT(!work_pending(&call->async_work)); 176341f741fSDavid Howells ASSERT(call->type->name != NULL); 177341f741fSDavid Howells 1786c67c7c3SDavid Howells if (call->rxcall) { 1794de48af6SDavid Howells rxrpc_kernel_end_call(afs_socket, call->rxcall); 1806c67c7c3SDavid Howells call->rxcall = NULL; 1816c67c7c3SDavid Howells } 1826cf12869SNathaniel Wesley Filardo if (call->type->destructor) 1836c67c7c3SDavid Howells call->type->destructor(call); 184341f741fSDavid Howells 185341f741fSDavid Howells kfree(call->request); 186341f741fSDavid Howells kfree(call); 187341f741fSDavid Howells 188341f741fSDavid Howells o = atomic_dec_return(&afs_outstanding_calls); 189341f741fSDavid Howells trace_afs_call(call, afs_call_trace_free, 0, o, 190341f741fSDavid Howells __builtin_return_address(0)); 191341f741fSDavid Howells if (o == 0) 192341f741fSDavid Howells wake_up_atomic_t(&afs_outstanding_calls); 193341f741fSDavid Howells } 1946cf12869SNathaniel Wesley Filardo } 1956cf12869SNathaniel Wesley Filardo 1966cf12869SNathaniel Wesley Filardo /* 197341f741fSDavid Howells * Queue the call for actual work. Returns 0 unconditionally for convenience. 1986cf12869SNathaniel Wesley Filardo */ 199341f741fSDavid Howells int afs_queue_call_work(struct afs_call *call) 2006cf12869SNathaniel Wesley Filardo { 201341f741fSDavid Howells int u = atomic_inc_return(&call->usage); 202341f741fSDavid Howells 203341f741fSDavid Howells trace_afs_call(call, afs_call_trace_work, u, 204341f741fSDavid Howells atomic_read(&afs_outstanding_calls), 205341f741fSDavid Howells __builtin_return_address(0)); 206341f741fSDavid Howells 207341f741fSDavid Howells INIT_WORK(&call->work, call->type->work); 208341f741fSDavid Howells 209341f741fSDavid Howells if (!queue_work(afs_wq, &call->work)) 210341f741fSDavid Howells afs_put_call(call); 211341f741fSDavid Howells return 0; 2126c67c7c3SDavid Howells } 2136c67c7c3SDavid Howells 2146c67c7c3SDavid Howells /* 21508e0e7c8SDavid Howells * allocate a call with flat request and reply buffers 21608e0e7c8SDavid Howells */ 21708e0e7c8SDavid Howells struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type, 218d001648eSDavid Howells size_t request_size, size_t reply_max) 21908e0e7c8SDavid Howells { 22008e0e7c8SDavid Howells struct afs_call *call; 22108e0e7c8SDavid Howells 222341f741fSDavid Howells call = afs_alloc_call(type, GFP_NOFS); 22308e0e7c8SDavid Howells if (!call) 22408e0e7c8SDavid Howells goto nomem_call; 22508e0e7c8SDavid Howells 22600d3b7a4SDavid Howells if (request_size) { 227341f741fSDavid Howells call->request_size = request_size; 22800d3b7a4SDavid Howells call->request = kmalloc(request_size, GFP_NOFS); 22900d3b7a4SDavid Howells if (!call->request) 23000d3b7a4SDavid Howells goto nomem_free; 23100d3b7a4SDavid Howells } 23200d3b7a4SDavid Howells 233d001648eSDavid Howells if (reply_max) { 234341f741fSDavid Howells call->reply_max = reply_max; 235d001648eSDavid Howells call->buffer = kmalloc(reply_max, GFP_NOFS); 23600d3b7a4SDavid Howells if (!call->buffer) 23700d3b7a4SDavid Howells goto nomem_free; 23800d3b7a4SDavid Howells } 23900d3b7a4SDavid Howells 24008e0e7c8SDavid Howells init_waitqueue_head(&call->waitq); 24108e0e7c8SDavid Howells return call; 24208e0e7c8SDavid Howells 24300d3b7a4SDavid Howells nomem_free: 244341f741fSDavid Howells afs_put_call(call); 24508e0e7c8SDavid Howells nomem_call: 24608e0e7c8SDavid Howells return NULL; 24708e0e7c8SDavid Howells } 24808e0e7c8SDavid Howells 24908e0e7c8SDavid Howells /* 25008e0e7c8SDavid Howells * clean up a call with flat buffer 25108e0e7c8SDavid Howells */ 25208e0e7c8SDavid Howells void afs_flat_call_destructor(struct afs_call *call) 25308e0e7c8SDavid Howells { 25408e0e7c8SDavid Howells _enter(""); 25508e0e7c8SDavid Howells 25608e0e7c8SDavid Howells kfree(call->request); 25708e0e7c8SDavid Howells call->request = NULL; 25808e0e7c8SDavid Howells kfree(call->buffer); 25908e0e7c8SDavid Howells call->buffer = NULL; 26008e0e7c8SDavid Howells } 26108e0e7c8SDavid Howells 2622f5705a5SDavid Howells #define AFS_BVEC_MAX 8 2632f5705a5SDavid Howells 2642f5705a5SDavid Howells /* 2652f5705a5SDavid Howells * Load the given bvec with the next few pages. 2662f5705a5SDavid Howells */ 2672f5705a5SDavid Howells static void afs_load_bvec(struct afs_call *call, struct msghdr *msg, 2682f5705a5SDavid Howells struct bio_vec *bv, pgoff_t first, pgoff_t last, 2692f5705a5SDavid Howells unsigned offset) 2702f5705a5SDavid Howells { 2712f5705a5SDavid Howells struct page *pages[AFS_BVEC_MAX]; 2722f5705a5SDavid Howells unsigned int nr, n, i, to, bytes = 0; 2732f5705a5SDavid Howells 2742f5705a5SDavid Howells nr = min_t(pgoff_t, last - first + 1, AFS_BVEC_MAX); 2752f5705a5SDavid Howells n = find_get_pages_contig(call->mapping, first, nr, pages); 2762f5705a5SDavid Howells ASSERTCMP(n, ==, nr); 2772f5705a5SDavid Howells 2782f5705a5SDavid Howells msg->msg_flags |= MSG_MORE; 2792f5705a5SDavid Howells for (i = 0; i < nr; i++) { 2802f5705a5SDavid Howells to = PAGE_SIZE; 2812f5705a5SDavid Howells if (first + i >= last) { 2822f5705a5SDavid Howells to = call->last_to; 2832f5705a5SDavid Howells msg->msg_flags &= ~MSG_MORE; 2842f5705a5SDavid Howells } 2852f5705a5SDavid Howells bv[i].bv_page = pages[i]; 2862f5705a5SDavid Howells bv[i].bv_len = to - offset; 2872f5705a5SDavid Howells bv[i].bv_offset = offset; 2882f5705a5SDavid Howells bytes += to - offset; 2892f5705a5SDavid Howells offset = 0; 2902f5705a5SDavid Howells } 2912f5705a5SDavid Howells 2922f5705a5SDavid Howells iov_iter_bvec(&msg->msg_iter, WRITE | ITER_BVEC, bv, nr, bytes); 2932f5705a5SDavid Howells } 2942f5705a5SDavid Howells 29508e0e7c8SDavid Howells /* 29631143d5dSDavid Howells * attach the data from a bunch of pages on an inode to a call 29731143d5dSDavid Howells */ 29839c6aceaSAl Viro static int afs_send_pages(struct afs_call *call, struct msghdr *msg) 29931143d5dSDavid Howells { 3002f5705a5SDavid Howells struct bio_vec bv[AFS_BVEC_MAX]; 3012f5705a5SDavid Howells unsigned int bytes, nr, loop, offset; 30231143d5dSDavid Howells pgoff_t first = call->first, last = call->last; 30331143d5dSDavid Howells int ret; 30431143d5dSDavid Howells 30531143d5dSDavid Howells offset = call->first_offset; 30631143d5dSDavid Howells call->first_offset = 0; 30731143d5dSDavid Howells 30831143d5dSDavid Howells do { 3092f5705a5SDavid Howells afs_load_bvec(call, msg, bv, first, last, offset); 31031143d5dSDavid Howells offset = 0; 3112f5705a5SDavid Howells bytes = msg->msg_iter.count; 3122f5705a5SDavid Howells nr = msg->msg_iter.nr_segs; 31331143d5dSDavid Howells 3142f5705a5SDavid Howells /* Have to change the state *before* sending the last 31531143d5dSDavid Howells * packet as RxRPC might give us the reply before it 3162f5705a5SDavid Howells * returns from sending the request. 3172f5705a5SDavid Howells */ 318445783d0SDavid Howells if (first + nr - 1 >= last) 31931143d5dSDavid Howells call->state = AFS_CALL_AWAIT_REPLY; 3204de48af6SDavid Howells ret = rxrpc_kernel_send_data(afs_socket, call->rxcall, 3212f5705a5SDavid Howells msg, bytes); 3222f5705a5SDavid Howells for (loop = 0; loop < nr; loop++) 3232f5705a5SDavid Howells put_page(bv[loop].bv_page); 32431143d5dSDavid Howells if (ret < 0) 32531143d5dSDavid Howells break; 32631143d5dSDavid Howells 3272f5705a5SDavid Howells first += nr; 3285bbf5d39SDavid Howells } while (first <= last); 32931143d5dSDavid Howells 33031143d5dSDavid Howells return ret; 33131143d5dSDavid Howells } 33231143d5dSDavid Howells 33331143d5dSDavid Howells /* 33408e0e7c8SDavid Howells * initiate a call 33508e0e7c8SDavid Howells */ 33608e0e7c8SDavid Howells int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, 33756ff9c83SDavid Howells bool async) 33808e0e7c8SDavid Howells { 33908e0e7c8SDavid Howells struct sockaddr_rxrpc srx; 34008e0e7c8SDavid Howells struct rxrpc_call *rxcall; 34108e0e7c8SDavid Howells struct msghdr msg; 34208e0e7c8SDavid Howells struct kvec iov[1]; 34370af0e3bSDavid Howells size_t offset; 34470af0e3bSDavid Howells u32 abort_code; 34508e0e7c8SDavid Howells int ret; 34608e0e7c8SDavid Howells 34708e0e7c8SDavid Howells _enter("%x,{%d},", addr->s_addr, ntohs(call->port)); 34808e0e7c8SDavid Howells 34900d3b7a4SDavid Howells ASSERT(call->type != NULL); 35000d3b7a4SDavid Howells ASSERT(call->type->name != NULL); 35100d3b7a4SDavid Howells 35231143d5dSDavid Howells _debug("____MAKE %p{%s,%x} [%d]____", 35331143d5dSDavid Howells call, call->type->name, key_serial(call->key), 35431143d5dSDavid Howells atomic_read(&afs_outstanding_calls)); 35500d3b7a4SDavid Howells 35656ff9c83SDavid Howells call->async = async; 35708e0e7c8SDavid Howells 35808e0e7c8SDavid Howells memset(&srx, 0, sizeof(srx)); 35908e0e7c8SDavid Howells srx.srx_family = AF_RXRPC; 36008e0e7c8SDavid Howells srx.srx_service = call->service_id; 36108e0e7c8SDavid Howells srx.transport_type = SOCK_DGRAM; 36208e0e7c8SDavid Howells srx.transport_len = sizeof(srx.transport.sin); 36308e0e7c8SDavid Howells srx.transport.sin.sin_family = AF_INET; 36408e0e7c8SDavid Howells srx.transport.sin.sin_port = call->port; 36508e0e7c8SDavid Howells memcpy(&srx.transport.sin.sin_addr, addr, 4); 36608e0e7c8SDavid Howells 36708e0e7c8SDavid Howells /* create a call */ 36808e0e7c8SDavid Howells rxcall = rxrpc_kernel_begin_call(afs_socket, &srx, call->key, 369d001648eSDavid Howells (unsigned long) call, gfp, 37056ff9c83SDavid Howells (async ? 37156ff9c83SDavid Howells afs_wake_up_async_call : 37256ff9c83SDavid Howells afs_wake_up_call_waiter)); 37300d3b7a4SDavid Howells call->key = NULL; 37408e0e7c8SDavid Howells if (IS_ERR(rxcall)) { 37508e0e7c8SDavid Howells ret = PTR_ERR(rxcall); 37608e0e7c8SDavid Howells goto error_kill_call; 37708e0e7c8SDavid Howells } 37808e0e7c8SDavid Howells 37908e0e7c8SDavid Howells call->rxcall = rxcall; 38008e0e7c8SDavid Howells 38108e0e7c8SDavid Howells /* send the request */ 38208e0e7c8SDavid Howells iov[0].iov_base = call->request; 38308e0e7c8SDavid Howells iov[0].iov_len = call->request_size; 38408e0e7c8SDavid Howells 38508e0e7c8SDavid Howells msg.msg_name = NULL; 38608e0e7c8SDavid Howells msg.msg_namelen = 0; 3872e90b1c4SAl Viro iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iov, 1, 388c0371da6SAl Viro call->request_size); 38908e0e7c8SDavid Howells msg.msg_control = NULL; 39008e0e7c8SDavid Howells msg.msg_controllen = 0; 39131143d5dSDavid Howells msg.msg_flags = (call->send_pages ? MSG_MORE : 0); 39208e0e7c8SDavid Howells 39370af0e3bSDavid Howells /* We have to change the state *before* sending the last packet as 39470af0e3bSDavid Howells * rxrpc might give us the reply before it returns from sending the 39570af0e3bSDavid Howells * request. Further, if the send fails, we may already have been given 39670af0e3bSDavid Howells * a notification and may have collected it. 39770af0e3bSDavid Howells */ 39831143d5dSDavid Howells if (!call->send_pages) 39908e0e7c8SDavid Howells call->state = AFS_CALL_AWAIT_REPLY; 4004de48af6SDavid Howells ret = rxrpc_kernel_send_data(afs_socket, rxcall, 4014de48af6SDavid Howells &msg, call->request_size); 40208e0e7c8SDavid Howells if (ret < 0) 40308e0e7c8SDavid Howells goto error_do_abort; 40408e0e7c8SDavid Howells 40531143d5dSDavid Howells if (call->send_pages) { 40639c6aceaSAl Viro ret = afs_send_pages(call, &msg); 40731143d5dSDavid Howells if (ret < 0) 40831143d5dSDavid Howells goto error_do_abort; 40931143d5dSDavid Howells } 41031143d5dSDavid Howells 41108e0e7c8SDavid Howells /* at this point, an async call may no longer exist as it may have 41208e0e7c8SDavid Howells * already completed */ 41356ff9c83SDavid Howells if (call->async) 41456ff9c83SDavid Howells return -EINPROGRESS; 41556ff9c83SDavid Howells 41656ff9c83SDavid Howells return afs_wait_for_call_to_complete(call); 41708e0e7c8SDavid Howells 41808e0e7c8SDavid Howells error_do_abort: 41970af0e3bSDavid Howells call->state = AFS_CALL_COMPLETE; 42070af0e3bSDavid Howells if (ret != -ECONNABORTED) { 42170af0e3bSDavid Howells rxrpc_kernel_abort_call(afs_socket, rxcall, RX_USER_ABORT, 4223a92789aSDavid Howells ret, "KSD"); 42370af0e3bSDavid Howells } else { 42470af0e3bSDavid Howells abort_code = 0; 42570af0e3bSDavid Howells offset = 0; 42670af0e3bSDavid Howells rxrpc_kernel_recv_data(afs_socket, rxcall, NULL, 0, &offset, 42770af0e3bSDavid Howells false, &abort_code); 42870af0e3bSDavid Howells ret = call->type->abort_to_error(abort_code); 42970af0e3bSDavid Howells } 43008e0e7c8SDavid Howells error_kill_call: 431341f741fSDavid Howells afs_put_call(call); 43208e0e7c8SDavid Howells _leave(" = %d", ret); 43308e0e7c8SDavid Howells return ret; 43408e0e7c8SDavid Howells } 43508e0e7c8SDavid Howells 43608e0e7c8SDavid Howells /* 43708e0e7c8SDavid Howells * deliver messages to a call 43808e0e7c8SDavid Howells */ 43908e0e7c8SDavid Howells static void afs_deliver_to_call(struct afs_call *call) 44008e0e7c8SDavid Howells { 44108e0e7c8SDavid Howells u32 abort_code; 44208e0e7c8SDavid Howells int ret; 44308e0e7c8SDavid Howells 444d001648eSDavid Howells _enter("%s", call->type->name); 44508e0e7c8SDavid Howells 446d001648eSDavid Howells while (call->state == AFS_CALL_AWAIT_REPLY || 44708e0e7c8SDavid Howells call->state == AFS_CALL_AWAIT_OP_ID || 44808e0e7c8SDavid Howells call->state == AFS_CALL_AWAIT_REQUEST || 449d001648eSDavid Howells call->state == AFS_CALL_AWAIT_ACK 450d001648eSDavid Howells ) { 451d001648eSDavid Howells if (call->state == AFS_CALL_AWAIT_ACK) { 452d001648eSDavid Howells size_t offset = 0; 453d001648eSDavid Howells ret = rxrpc_kernel_recv_data(afs_socket, call->rxcall, 454d001648eSDavid Howells NULL, 0, &offset, false, 455d001648eSDavid Howells &call->abort_code); 4568e8d7f13SDavid Howells trace_afs_recv_data(call, 0, offset, false, ret); 4578e8d7f13SDavid Howells 458d001648eSDavid Howells if (ret == -EINPROGRESS || ret == -EAGAIN) 459d001648eSDavid Howells return; 4609008f998SDavid Howells if (ret == 1 || ret < 0) { 461d001648eSDavid Howells call->state = AFS_CALL_COMPLETE; 462d001648eSDavid Howells goto done; 463372ee163SDavid Howells } 464d001648eSDavid Howells return; 465d001648eSDavid Howells } 466d001648eSDavid Howells 467d001648eSDavid Howells ret = call->type->deliver(call); 468d001648eSDavid Howells switch (ret) { 46908e0e7c8SDavid Howells case 0: 470372ee163SDavid Howells if (call->state == AFS_CALL_AWAIT_REPLY) 47108e0e7c8SDavid Howells call->state = AFS_CALL_COMPLETE; 472d001648eSDavid Howells goto done; 473d001648eSDavid Howells case -EINPROGRESS: 474d001648eSDavid Howells case -EAGAIN: 475d001648eSDavid Howells goto out; 47670af0e3bSDavid Howells case -ECONNABORTED: 47770af0e3bSDavid Howells goto call_complete; 47808e0e7c8SDavid Howells case -ENOTCONN: 47908e0e7c8SDavid Howells abort_code = RX_CALL_DEAD; 480d001648eSDavid Howells rxrpc_kernel_abort_call(afs_socket, call->rxcall, 4813a92789aSDavid Howells abort_code, ret, "KNC"); 48270af0e3bSDavid Howells goto save_error; 48308e0e7c8SDavid Howells case -ENOTSUPP: 4841157f153SDavid Howells abort_code = RXGEN_OPCODE; 485d001648eSDavid Howells rxrpc_kernel_abort_call(afs_socket, call->rxcall, 4863a92789aSDavid Howells abort_code, ret, "KIV"); 48770af0e3bSDavid Howells goto save_error; 488d001648eSDavid Howells case -ENODATA: 489d001648eSDavid Howells case -EBADMSG: 490d001648eSDavid Howells case -EMSGSIZE: 49108e0e7c8SDavid Howells default: 49208e0e7c8SDavid Howells abort_code = RXGEN_CC_UNMARSHAL; 49308e0e7c8SDavid Howells if (call->state != AFS_CALL_AWAIT_REPLY) 49408e0e7c8SDavid Howells abort_code = RXGEN_SS_UNMARSHAL; 495d001648eSDavid Howells rxrpc_kernel_abort_call(afs_socket, call->rxcall, 4963a92789aSDavid Howells abort_code, -EBADMSG, "KUM"); 49770af0e3bSDavid Howells goto save_error; 49808e0e7c8SDavid Howells } 49908e0e7c8SDavid Howells } 50008e0e7c8SDavid Howells 501d001648eSDavid Howells done: 502d001648eSDavid Howells if (call->state == AFS_CALL_COMPLETE && call->incoming) 503341f741fSDavid Howells afs_put_call(call); 504d001648eSDavid Howells out: 50508e0e7c8SDavid Howells _leave(""); 506d001648eSDavid Howells return; 507d001648eSDavid Howells 50870af0e3bSDavid Howells save_error: 509d001648eSDavid Howells call->error = ret; 51070af0e3bSDavid Howells call_complete: 511d001648eSDavid Howells call->state = AFS_CALL_COMPLETE; 512d001648eSDavid Howells goto done; 51308e0e7c8SDavid Howells } 51408e0e7c8SDavid Howells 51508e0e7c8SDavid Howells /* 51608e0e7c8SDavid Howells * wait synchronously for a call to complete 51708e0e7c8SDavid Howells */ 51808e0e7c8SDavid Howells static int afs_wait_for_call_to_complete(struct afs_call *call) 51908e0e7c8SDavid Howells { 52008e0e7c8SDavid Howells int ret; 52108e0e7c8SDavid Howells 52208e0e7c8SDavid Howells DECLARE_WAITQUEUE(myself, current); 52308e0e7c8SDavid Howells 52408e0e7c8SDavid Howells _enter(""); 52508e0e7c8SDavid Howells 52608e0e7c8SDavid Howells add_wait_queue(&call->waitq, &myself); 52708e0e7c8SDavid Howells for (;;) { 52808e0e7c8SDavid Howells set_current_state(TASK_INTERRUPTIBLE); 52908e0e7c8SDavid Howells 53008e0e7c8SDavid Howells /* deliver any messages that are in the queue */ 531d001648eSDavid Howells if (call->state < AFS_CALL_COMPLETE && call->need_attention) { 532d001648eSDavid Howells call->need_attention = false; 53308e0e7c8SDavid Howells __set_current_state(TASK_RUNNING); 53408e0e7c8SDavid Howells afs_deliver_to_call(call); 53508e0e7c8SDavid Howells continue; 53608e0e7c8SDavid Howells } 53708e0e7c8SDavid Howells 538954cd6dcSDavid Howells if (call->state == AFS_CALL_COMPLETE || 539954cd6dcSDavid Howells signal_pending(current)) 54008e0e7c8SDavid Howells break; 54108e0e7c8SDavid Howells schedule(); 54208e0e7c8SDavid Howells } 54308e0e7c8SDavid Howells 54408e0e7c8SDavid Howells remove_wait_queue(&call->waitq, &myself); 54508e0e7c8SDavid Howells __set_current_state(TASK_RUNNING); 54608e0e7c8SDavid Howells 547954cd6dcSDavid Howells /* Kill off the call if it's still live. */ 54808e0e7c8SDavid Howells if (call->state < AFS_CALL_COMPLETE) { 549954cd6dcSDavid Howells _debug("call interrupted"); 550d001648eSDavid Howells rxrpc_kernel_abort_call(afs_socket, call->rxcall, 551954cd6dcSDavid Howells RX_USER_ABORT, -EINTR, "KWI"); 55208e0e7c8SDavid Howells } 55308e0e7c8SDavid Howells 554954cd6dcSDavid Howells ret = call->error; 55508e0e7c8SDavid Howells _debug("call complete"); 556341f741fSDavid Howells afs_put_call(call); 55708e0e7c8SDavid Howells _leave(" = %d", ret); 55808e0e7c8SDavid Howells return ret; 55908e0e7c8SDavid Howells } 56008e0e7c8SDavid Howells 56108e0e7c8SDavid Howells /* 56208e0e7c8SDavid Howells * wake up a waiting call 56308e0e7c8SDavid Howells */ 564d001648eSDavid Howells static void afs_wake_up_call_waiter(struct sock *sk, struct rxrpc_call *rxcall, 565d001648eSDavid Howells unsigned long call_user_ID) 56608e0e7c8SDavid Howells { 567d001648eSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 568d001648eSDavid Howells 569d001648eSDavid Howells call->need_attention = true; 57008e0e7c8SDavid Howells wake_up(&call->waitq); 57108e0e7c8SDavid Howells } 57208e0e7c8SDavid Howells 57308e0e7c8SDavid Howells /* 57408e0e7c8SDavid Howells * wake up an asynchronous call 57508e0e7c8SDavid Howells */ 576d001648eSDavid Howells static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall, 577d001648eSDavid Howells unsigned long call_user_ID) 57808e0e7c8SDavid Howells { 579d001648eSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 580341f741fSDavid Howells int u; 581d001648eSDavid Howells 5828e8d7f13SDavid Howells trace_afs_notify_call(rxcall, call); 583d001648eSDavid Howells call->need_attention = true; 584341f741fSDavid Howells 585341f741fSDavid Howells u = __atomic_add_unless(&call->usage, 1, 0); 586341f741fSDavid Howells if (u != 0) { 587341f741fSDavid Howells trace_afs_call(call, afs_call_trace_wake, u, 588341f741fSDavid Howells atomic_read(&afs_outstanding_calls), 589341f741fSDavid Howells __builtin_return_address(0)); 590341f741fSDavid Howells 591341f741fSDavid Howells if (!queue_work(afs_async_calls, &call->async_work)) 592341f741fSDavid Howells afs_put_call(call); 593341f741fSDavid Howells } 59408e0e7c8SDavid Howells } 59508e0e7c8SDavid Howells 59608e0e7c8SDavid Howells /* 597341f741fSDavid Howells * Delete an asynchronous call. The work item carries a ref to the call struct 598341f741fSDavid Howells * that we need to release. 59908e0e7c8SDavid Howells */ 600d001648eSDavid Howells static void afs_delete_async_call(struct work_struct *work) 60108e0e7c8SDavid Howells { 602d001648eSDavid Howells struct afs_call *call = container_of(work, struct afs_call, async_work); 603d001648eSDavid Howells 60408e0e7c8SDavid Howells _enter(""); 60508e0e7c8SDavid Howells 606341f741fSDavid Howells afs_put_call(call); 60708e0e7c8SDavid Howells 60808e0e7c8SDavid Howells _leave(""); 60908e0e7c8SDavid Howells } 61008e0e7c8SDavid Howells 61108e0e7c8SDavid Howells /* 612341f741fSDavid Howells * Perform I/O processing on an asynchronous call. The work item carries a ref 613341f741fSDavid Howells * to the call struct that we either need to release or to pass on. 61408e0e7c8SDavid Howells */ 615d001648eSDavid Howells static void afs_process_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 621d001648eSDavid Howells if (call->state < AFS_CALL_COMPLETE && call->need_attention) { 622d001648eSDavid Howells call->need_attention = false; 62308e0e7c8SDavid Howells afs_deliver_to_call(call); 624d001648eSDavid Howells } 62508e0e7c8SDavid Howells 62656ff9c83SDavid Howells if (call->state == AFS_CALL_COMPLETE) { 62708e0e7c8SDavid Howells call->reply = NULL; 62808e0e7c8SDavid Howells 629341f741fSDavid Howells /* We have two refs to release - one from the alloc and one 630341f741fSDavid Howells * queued with the work item - and we can't just deallocate the 631341f741fSDavid Howells * call because the work item may be queued again. 632341f741fSDavid Howells */ 633d001648eSDavid Howells call->async_work.func = afs_delete_async_call; 634341f741fSDavid Howells if (!queue_work(afs_async_calls, &call->async_work)) 635341f741fSDavid Howells afs_put_call(call); 63608e0e7c8SDavid Howells } 63708e0e7c8SDavid Howells 638341f741fSDavid Howells afs_put_call(call); 63908e0e7c8SDavid Howells _leave(""); 64008e0e7c8SDavid Howells } 64108e0e7c8SDavid Howells 64200e90712SDavid Howells static void afs_rx_attach(struct rxrpc_call *rxcall, unsigned long user_call_ID) 64300e90712SDavid Howells { 64400e90712SDavid Howells struct afs_call *call = (struct afs_call *)user_call_ID; 64500e90712SDavid Howells 64600e90712SDavid Howells call->rxcall = rxcall; 64700e90712SDavid Howells } 64800e90712SDavid Howells 64900e90712SDavid Howells /* 65000e90712SDavid Howells * Charge the incoming call preallocation. 65100e90712SDavid Howells */ 65200e90712SDavid Howells static void afs_charge_preallocation(struct work_struct *work) 65300e90712SDavid Howells { 65400e90712SDavid Howells struct afs_call *call = afs_spare_incoming_call; 65500e90712SDavid Howells 65600e90712SDavid Howells for (;;) { 65700e90712SDavid Howells if (!call) { 658341f741fSDavid Howells call = afs_alloc_call(&afs_RXCMxxxx, GFP_KERNEL); 65900e90712SDavid Howells if (!call) 66000e90712SDavid Howells break; 66100e90712SDavid Howells 66256ff9c83SDavid Howells call->async = true; 66300e90712SDavid Howells call->state = AFS_CALL_AWAIT_OP_ID; 66456ff9c83SDavid Howells init_waitqueue_head(&call->waitq); 66500e90712SDavid Howells } 66600e90712SDavid Howells 66700e90712SDavid Howells if (rxrpc_kernel_charge_accept(afs_socket, 66800e90712SDavid Howells afs_wake_up_async_call, 66900e90712SDavid Howells afs_rx_attach, 67000e90712SDavid Howells (unsigned long)call, 67100e90712SDavid Howells GFP_KERNEL) < 0) 67200e90712SDavid Howells break; 67300e90712SDavid Howells call = NULL; 67400e90712SDavid Howells } 67500e90712SDavid Howells afs_spare_incoming_call = call; 67600e90712SDavid Howells } 67700e90712SDavid Howells 67800e90712SDavid Howells /* 67900e90712SDavid Howells * Discard a preallocated call when a socket is shut down. 68000e90712SDavid Howells */ 68100e90712SDavid Howells static void afs_rx_discard_new_call(struct rxrpc_call *rxcall, 68200e90712SDavid Howells unsigned long user_call_ID) 68300e90712SDavid Howells { 68400e90712SDavid Howells struct afs_call *call = (struct afs_call *)user_call_ID; 68500e90712SDavid Howells 68600e90712SDavid Howells call->rxcall = NULL; 687341f741fSDavid Howells afs_put_call(call); 68800e90712SDavid Howells } 68900e90712SDavid Howells 69008e0e7c8SDavid Howells /* 691d001648eSDavid Howells * Notification of an incoming call. 692d001648eSDavid Howells */ 69300e90712SDavid Howells static void afs_rx_new_call(struct sock *sk, struct rxrpc_call *rxcall, 69400e90712SDavid Howells unsigned long user_call_ID) 695d001648eSDavid Howells { 69600e90712SDavid Howells queue_work(afs_wq, &afs_charge_preallocation_work); 697d001648eSDavid Howells } 698d001648eSDavid Howells 699d001648eSDavid Howells /* 700372ee163SDavid Howells * Grab the operation ID from an incoming cache manager call. The socket 701372ee163SDavid Howells * buffer is discarded on error or if we don't yet have sufficient data. 70208e0e7c8SDavid Howells */ 703d001648eSDavid Howells static int afs_deliver_cm_op_id(struct afs_call *call) 70408e0e7c8SDavid Howells { 705d001648eSDavid Howells int ret; 70608e0e7c8SDavid Howells 707d001648eSDavid Howells _enter("{%zu}", call->offset); 70808e0e7c8SDavid Howells 70908e0e7c8SDavid Howells ASSERTCMP(call->offset, <, 4); 71008e0e7c8SDavid Howells 71108e0e7c8SDavid Howells /* the operation ID forms the first four bytes of the request data */ 71250a2c953SDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 713d001648eSDavid Howells if (ret < 0) 714d001648eSDavid Howells return ret; 71508e0e7c8SDavid Howells 71650a2c953SDavid Howells call->operation_ID = ntohl(call->tmp); 71708e0e7c8SDavid Howells call->state = AFS_CALL_AWAIT_REQUEST; 718d001648eSDavid Howells call->offset = 0; 71908e0e7c8SDavid Howells 72008e0e7c8SDavid Howells /* ask the cache manager to route the call (it'll change the call type 72108e0e7c8SDavid Howells * if successful) */ 72208e0e7c8SDavid Howells if (!afs_cm_incoming_call(call)) 72308e0e7c8SDavid Howells return -ENOTSUPP; 72408e0e7c8SDavid Howells 7258e8d7f13SDavid Howells trace_afs_cb_call(call); 7268e8d7f13SDavid Howells 72708e0e7c8SDavid Howells /* pass responsibility for the remainer of this message off to the 72808e0e7c8SDavid Howells * cache manager op */ 729d001648eSDavid Howells return call->type->deliver(call); 73008e0e7c8SDavid Howells } 73108e0e7c8SDavid Howells 73208e0e7c8SDavid Howells /* 73308e0e7c8SDavid Howells * send an empty reply 73408e0e7c8SDavid Howells */ 73508e0e7c8SDavid Howells void afs_send_empty_reply(struct afs_call *call) 73608e0e7c8SDavid Howells { 73708e0e7c8SDavid Howells struct msghdr msg; 73808e0e7c8SDavid Howells 73908e0e7c8SDavid Howells _enter(""); 74008e0e7c8SDavid Howells 74108e0e7c8SDavid Howells msg.msg_name = NULL; 74208e0e7c8SDavid Howells msg.msg_namelen = 0; 743bfd4e956SDavid Howells iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, NULL, 0, 0); 74408e0e7c8SDavid Howells msg.msg_control = NULL; 74508e0e7c8SDavid Howells msg.msg_controllen = 0; 74608e0e7c8SDavid Howells msg.msg_flags = 0; 74708e0e7c8SDavid Howells 74808e0e7c8SDavid Howells call->state = AFS_CALL_AWAIT_ACK; 7494de48af6SDavid Howells switch (rxrpc_kernel_send_data(afs_socket, call->rxcall, &msg, 0)) { 75008e0e7c8SDavid Howells case 0: 75108e0e7c8SDavid Howells _leave(" [replied]"); 75208e0e7c8SDavid Howells return; 75308e0e7c8SDavid Howells 75408e0e7c8SDavid Howells case -ENOMEM: 75508e0e7c8SDavid Howells _debug("oom"); 7564de48af6SDavid Howells rxrpc_kernel_abort_call(afs_socket, call->rxcall, 7573a92789aSDavid Howells RX_USER_ABORT, -ENOMEM, "KOO"); 75808e0e7c8SDavid Howells default: 75908e0e7c8SDavid Howells _leave(" [error]"); 76008e0e7c8SDavid Howells return; 76108e0e7c8SDavid Howells } 76208e0e7c8SDavid Howells } 76308e0e7c8SDavid Howells 76408e0e7c8SDavid Howells /* 765b908fe6bSDavid Howells * send a simple reply 766b908fe6bSDavid Howells */ 767b908fe6bSDavid Howells void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) 768b908fe6bSDavid Howells { 769b908fe6bSDavid Howells struct msghdr msg; 7702e90b1c4SAl Viro struct kvec iov[1]; 771bd6dc742SDavid Howells int n; 772b908fe6bSDavid Howells 773b908fe6bSDavid Howells _enter(""); 774b908fe6bSDavid Howells 775b908fe6bSDavid Howells iov[0].iov_base = (void *) buf; 776b908fe6bSDavid Howells iov[0].iov_len = len; 777b908fe6bSDavid Howells msg.msg_name = NULL; 778b908fe6bSDavid Howells msg.msg_namelen = 0; 7792e90b1c4SAl Viro iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iov, 1, len); 780b908fe6bSDavid Howells msg.msg_control = NULL; 781b908fe6bSDavid Howells msg.msg_controllen = 0; 782b908fe6bSDavid Howells msg.msg_flags = 0; 783b908fe6bSDavid Howells 784b908fe6bSDavid Howells call->state = AFS_CALL_AWAIT_ACK; 7854de48af6SDavid Howells n = rxrpc_kernel_send_data(afs_socket, call->rxcall, &msg, len); 786bd6dc742SDavid Howells if (n >= 0) { 7876c67c7c3SDavid Howells /* Success */ 788b908fe6bSDavid Howells _leave(" [replied]"); 789b908fe6bSDavid Howells return; 790bd6dc742SDavid Howells } 7916c67c7c3SDavid Howells 792bd6dc742SDavid Howells if (n == -ENOMEM) { 793b908fe6bSDavid Howells _debug("oom"); 7944de48af6SDavid Howells rxrpc_kernel_abort_call(afs_socket, call->rxcall, 7953a92789aSDavid Howells RX_USER_ABORT, -ENOMEM, "KOO"); 796bd6dc742SDavid Howells } 797b908fe6bSDavid Howells _leave(" [error]"); 798b908fe6bSDavid Howells } 799b908fe6bSDavid Howells 800b908fe6bSDavid Howells /* 801372ee163SDavid Howells * Extract a piece of data from the received data socket buffers. 80208e0e7c8SDavid Howells */ 803d001648eSDavid Howells int afs_extract_data(struct afs_call *call, void *buf, size_t count, 804d001648eSDavid Howells bool want_more) 80508e0e7c8SDavid Howells { 806d001648eSDavid Howells int ret; 80708e0e7c8SDavid Howells 808d001648eSDavid Howells _enter("{%s,%zu},,%zu,%d", 809d001648eSDavid Howells call->type->name, call->offset, count, want_more); 81008e0e7c8SDavid Howells 811d001648eSDavid Howells ASSERTCMP(call->offset, <=, count); 81208e0e7c8SDavid Howells 813d001648eSDavid Howells ret = rxrpc_kernel_recv_data(afs_socket, call->rxcall, 814d001648eSDavid Howells buf, count, &call->offset, 815d001648eSDavid Howells want_more, &call->abort_code); 8168e8d7f13SDavid Howells trace_afs_recv_data(call, count, call->offset, want_more, ret); 817d001648eSDavid Howells if (ret == 0 || ret == -EAGAIN) 818d001648eSDavid Howells return ret; 81908e0e7c8SDavid Howells 820d001648eSDavid Howells if (ret == 1) { 821d001648eSDavid Howells switch (call->state) { 822d001648eSDavid Howells case AFS_CALL_AWAIT_REPLY: 823d001648eSDavid Howells call->state = AFS_CALL_COMPLETE; 824d001648eSDavid Howells break; 825d001648eSDavid Howells case AFS_CALL_AWAIT_REQUEST: 826d001648eSDavid Howells call->state = AFS_CALL_REPLYING; 827d001648eSDavid Howells break; 828d001648eSDavid Howells default: 829d001648eSDavid Howells break; 83008e0e7c8SDavid Howells } 83108e0e7c8SDavid Howells return 0; 83208e0e7c8SDavid Howells } 833d001648eSDavid Howells 834d001648eSDavid Howells if (ret == -ECONNABORTED) 835d001648eSDavid Howells call->error = call->type->abort_to_error(call->abort_code); 836d001648eSDavid Howells else 837d001648eSDavid Howells call->error = ret; 838d001648eSDavid Howells call->state = AFS_CALL_COMPLETE; 839d001648eSDavid Howells return ret; 840d001648eSDavid Howells } 841