12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 208e0e7c8SDavid Howells /* Maintain an RxRPC server socket to do AFS communications through 308e0e7c8SDavid Howells * 408e0e7c8SDavid Howells * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 508e0e7c8SDavid Howells * Written by David Howells (dhowells@redhat.com) 608e0e7c8SDavid Howells */ 708e0e7c8SDavid Howells 85a0e3ad6STejun Heo #include <linux/slab.h> 9174cd4b1SIngo Molnar #include <linux/sched/signal.h> 10174cd4b1SIngo Molnar 1108e0e7c8SDavid Howells #include <net/sock.h> 1208e0e7c8SDavid Howells #include <net/af_rxrpc.h> 1308e0e7c8SDavid Howells #include "internal.h" 1408e0e7c8SDavid Howells #include "afs_cm.h" 1535dbfba3SDavid Howells #include "protocol_yfs.h" 1608e0e7c8SDavid Howells 17f044c884SDavid Howells struct workqueue_struct *afs_async_calls; 1808e0e7c8SDavid Howells 19d001648eSDavid Howells static void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long); 20d001648eSDavid Howells static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long); 2134fa4761SDavid Howells static void afs_delete_async_call(struct work_struct *); 22d001648eSDavid Howells static void afs_process_async_call(struct work_struct *); 2300e90712SDavid Howells static void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long); 2400e90712SDavid Howells static void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long); 25d001648eSDavid Howells static int afs_deliver_cm_op_id(struct afs_call *); 2608e0e7c8SDavid Howells 2708e0e7c8SDavid Howells /* asynchronous incoming call initial processing */ 2808e0e7c8SDavid Howells static const struct afs_call_type afs_RXCMxxxx = { 2900d3b7a4SDavid Howells .name = "CB.xxxx", 3008e0e7c8SDavid Howells .deliver = afs_deliver_cm_op_id, 3108e0e7c8SDavid Howells }; 3208e0e7c8SDavid Howells 3308e0e7c8SDavid Howells /* 3408e0e7c8SDavid Howells * open an RxRPC socket and bind it to be a server for callback notifications 3508e0e7c8SDavid Howells * - the socket is left in blocking mode and non-blocking ops use MSG_DONTWAIT 3608e0e7c8SDavid Howells */ 37f044c884SDavid Howells int afs_open_socket(struct afs_net *net) 3808e0e7c8SDavid Howells { 3908e0e7c8SDavid Howells struct sockaddr_rxrpc srx; 4008e0e7c8SDavid Howells struct socket *socket; 414776cab4SDavid Howells unsigned int min_level; 4208e0e7c8SDavid Howells int ret; 4308e0e7c8SDavid Howells 4408e0e7c8SDavid Howells _enter(""); 4508e0e7c8SDavid Howells 465b86d4ffSDavid Howells ret = sock_create_kern(net->net, AF_RXRPC, SOCK_DGRAM, PF_INET6, &socket); 470e119b41SDavid Howells if (ret < 0) 480e119b41SDavid Howells goto error_1; 4908e0e7c8SDavid Howells 5008e0e7c8SDavid Howells socket->sk->sk_allocation = GFP_NOFS; 5108e0e7c8SDavid Howells 5208e0e7c8SDavid Howells /* bind the callback manager's address to make this a server socket */ 533838d3ecSDavid Howells memset(&srx, 0, sizeof(srx)); 5408e0e7c8SDavid Howells srx.srx_family = AF_RXRPC; 5508e0e7c8SDavid Howells srx.srx_service = CM_SERVICE; 5608e0e7c8SDavid Howells srx.transport_type = SOCK_DGRAM; 573838d3ecSDavid Howells srx.transport_len = sizeof(srx.transport.sin6); 583838d3ecSDavid Howells srx.transport.sin6.sin6_family = AF_INET6; 593838d3ecSDavid Howells srx.transport.sin6.sin6_port = htons(AFS_CM_PORT); 6008e0e7c8SDavid Howells 614776cab4SDavid Howells min_level = RXRPC_SECURITY_ENCRYPT; 624776cab4SDavid Howells ret = kernel_setsockopt(socket, SOL_RXRPC, RXRPC_MIN_SECURITY_LEVEL, 634776cab4SDavid Howells (void *)&min_level, sizeof(min_level)); 644776cab4SDavid Howells if (ret < 0) 654776cab4SDavid Howells goto error_2; 664776cab4SDavid Howells 6708e0e7c8SDavid Howells ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); 6883732ec5SMarc Dionne if (ret == -EADDRINUSE) { 6983732ec5SMarc Dionne srx.transport.sin6.sin6_port = 0; 7083732ec5SMarc Dionne ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); 7183732ec5SMarc Dionne } 720e119b41SDavid Howells if (ret < 0) 730e119b41SDavid Howells goto error_2; 740e119b41SDavid Howells 7535dbfba3SDavid Howells srx.srx_service = YFS_CM_SERVICE; 7635dbfba3SDavid Howells ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); 7735dbfba3SDavid Howells if (ret < 0) 7835dbfba3SDavid Howells goto error_2; 7935dbfba3SDavid Howells 803bf0fb6fSDavid Howells /* Ideally, we'd turn on service upgrade here, but we can't because 813bf0fb6fSDavid Howells * OpenAFS is buggy and leaks the userStatus field from packet to 823bf0fb6fSDavid Howells * packet and between FS packets and CB packets - so if we try to do an 833bf0fb6fSDavid Howells * upgrade on an FS packet, OpenAFS will leak that into the CB packet 843bf0fb6fSDavid Howells * it sends back to us. 853bf0fb6fSDavid Howells */ 8635dbfba3SDavid Howells 8700e90712SDavid Howells rxrpc_kernel_new_call_notification(socket, afs_rx_new_call, 8800e90712SDavid Howells afs_rx_discard_new_call); 89d001648eSDavid Howells 900e119b41SDavid Howells ret = kernel_listen(socket, INT_MAX); 910e119b41SDavid Howells if (ret < 0) 920e119b41SDavid Howells goto error_2; 9308e0e7c8SDavid Howells 94f044c884SDavid Howells net->socket = socket; 95f044c884SDavid Howells afs_charge_preallocation(&net->charge_preallocation_work); 9608e0e7c8SDavid Howells _leave(" = 0"); 9708e0e7c8SDavid Howells return 0; 980e119b41SDavid Howells 990e119b41SDavid Howells error_2: 1000e119b41SDavid Howells sock_release(socket); 1010e119b41SDavid Howells error_1: 1020e119b41SDavid Howells _leave(" = %d", ret); 1030e119b41SDavid Howells return ret; 10408e0e7c8SDavid Howells } 10508e0e7c8SDavid Howells 10608e0e7c8SDavid Howells /* 10708e0e7c8SDavid Howells * close the RxRPC socket AFS was using 10808e0e7c8SDavid Howells */ 109f044c884SDavid Howells void afs_close_socket(struct afs_net *net) 11008e0e7c8SDavid Howells { 11108e0e7c8SDavid Howells _enter(""); 11208e0e7c8SDavid Howells 113f044c884SDavid Howells kernel_listen(net->socket, 0); 114341f741fSDavid Howells flush_workqueue(afs_async_calls); 115341f741fSDavid Howells 116f044c884SDavid Howells if (net->spare_incoming_call) { 117f044c884SDavid Howells afs_put_call(net->spare_incoming_call); 118f044c884SDavid Howells net->spare_incoming_call = NULL; 11900e90712SDavid Howells } 12000e90712SDavid Howells 121f044c884SDavid Howells _debug("outstanding %u", atomic_read(&net->nr_outstanding_calls)); 122ab1fbe32SPeter Zijlstra wait_var_event(&net->nr_outstanding_calls, 123ab1fbe32SPeter Zijlstra !atomic_read(&net->nr_outstanding_calls)); 1242f02f7aeSDavid Howells _debug("no outstanding calls"); 1252f02f7aeSDavid Howells 126f044c884SDavid Howells kernel_sock_shutdown(net->socket, SHUT_RDWR); 127248f219cSDavid Howells flush_workqueue(afs_async_calls); 128f044c884SDavid Howells sock_release(net->socket); 12908e0e7c8SDavid Howells 13008e0e7c8SDavid Howells _debug("dework"); 13108e0e7c8SDavid Howells _leave(""); 13208e0e7c8SDavid Howells } 13308e0e7c8SDavid Howells 13408e0e7c8SDavid Howells /* 135341f741fSDavid Howells * Allocate a call. 13600d3b7a4SDavid Howells */ 137f044c884SDavid Howells static struct afs_call *afs_alloc_call(struct afs_net *net, 138f044c884SDavid Howells const struct afs_call_type *type, 139341f741fSDavid Howells gfp_t gfp) 14000d3b7a4SDavid Howells { 141341f741fSDavid Howells struct afs_call *call; 142341f741fSDavid Howells int o; 14300d3b7a4SDavid Howells 144341f741fSDavid Howells call = kzalloc(sizeof(*call), gfp); 145341f741fSDavid Howells if (!call) 146341f741fSDavid Howells return NULL; 14700d3b7a4SDavid Howells 148341f741fSDavid Howells call->type = type; 149f044c884SDavid Howells call->net = net; 150a25e21f0SDavid Howells call->debug_id = atomic_inc_return(&rxrpc_debug_id); 151341f741fSDavid Howells atomic_set(&call->usage, 1); 152341f741fSDavid Howells INIT_WORK(&call->async_work, afs_process_async_call); 153341f741fSDavid Howells init_waitqueue_head(&call->waitq); 15498bf40cdSDavid Howells spin_lock_init(&call->state_lock); 155fc276122SDavid Howells call->iter = &call->def_iter; 1562f02f7aeSDavid Howells 157f044c884SDavid Howells o = atomic_inc_return(&net->nr_outstanding_calls); 158341f741fSDavid Howells trace_afs_call(call, afs_call_trace_alloc, 1, o, 159341f741fSDavid Howells __builtin_return_address(0)); 160341f741fSDavid Howells return call; 16100d3b7a4SDavid Howells } 16200d3b7a4SDavid Howells 16300d3b7a4SDavid Howells /* 164341f741fSDavid Howells * Dispose of a reference on a call. 1656c67c7c3SDavid Howells */ 166341f741fSDavid Howells void afs_put_call(struct afs_call *call) 1676c67c7c3SDavid Howells { 168f044c884SDavid Howells struct afs_net *net = call->net; 169341f741fSDavid Howells int n = atomic_dec_return(&call->usage); 170f044c884SDavid Howells int o = atomic_read(&net->nr_outstanding_calls); 171341f741fSDavid Howells 172341f741fSDavid Howells trace_afs_call(call, afs_call_trace_put, n + 1, o, 173341f741fSDavid Howells __builtin_return_address(0)); 174341f741fSDavid Howells 175341f741fSDavid Howells ASSERTCMP(n, >=, 0); 176341f741fSDavid Howells if (n == 0) { 177341f741fSDavid Howells ASSERT(!work_pending(&call->async_work)); 178341f741fSDavid Howells ASSERT(call->type->name != NULL); 179341f741fSDavid Howells 1806c67c7c3SDavid Howells if (call->rxcall) { 181f044c884SDavid Howells rxrpc_kernel_end_call(net->socket, call->rxcall); 1826c67c7c3SDavid Howells call->rxcall = NULL; 1836c67c7c3SDavid Howells } 1846cf12869SNathaniel Wesley Filardo if (call->type->destructor) 1856c67c7c3SDavid Howells call->type->destructor(call); 186341f741fSDavid Howells 18745218193SDavid Howells afs_put_server(call->net, call->server, afs_server_trace_put_call); 188d2ddc776SDavid Howells afs_put_cb_interest(call->net, call->cbi); 1893bf0fb6fSDavid Howells afs_put_addrlist(call->alist); 190341f741fSDavid Howells kfree(call->request); 191a25e21f0SDavid Howells 192a25e21f0SDavid Howells trace_afs_call(call, afs_call_trace_free, 0, o, 193a25e21f0SDavid Howells __builtin_return_address(0)); 194341f741fSDavid Howells kfree(call); 195341f741fSDavid Howells 196f044c884SDavid Howells o = atomic_dec_return(&net->nr_outstanding_calls); 197341f741fSDavid Howells if (o == 0) 198ab1fbe32SPeter Zijlstra wake_up_var(&net->nr_outstanding_calls); 199341f741fSDavid Howells } 2006cf12869SNathaniel Wesley Filardo } 2016cf12869SNathaniel Wesley Filardo 2027a75b007SDavid Howells static struct afs_call *afs_get_call(struct afs_call *call, 2037a75b007SDavid Howells enum afs_call_trace why) 2047a75b007SDavid Howells { 2057a75b007SDavid Howells int u = atomic_inc_return(&call->usage); 2067a75b007SDavid Howells 2077a75b007SDavid Howells trace_afs_call(call, why, u, 2087a75b007SDavid Howells atomic_read(&call->net->nr_outstanding_calls), 2097a75b007SDavid Howells __builtin_return_address(0)); 2107a75b007SDavid Howells return call; 2117a75b007SDavid Howells } 2127a75b007SDavid Howells 2136cf12869SNathaniel Wesley Filardo /* 2143bf0fb6fSDavid Howells * Queue the call for actual work. 2156cf12869SNathaniel Wesley Filardo */ 2163bf0fb6fSDavid Howells static void afs_queue_call_work(struct afs_call *call) 2176cf12869SNathaniel Wesley Filardo { 2183bf0fb6fSDavid Howells if (call->type->work) { 219341f741fSDavid Howells INIT_WORK(&call->work, call->type->work); 220341f741fSDavid Howells 2217a75b007SDavid Howells afs_get_call(call, afs_call_trace_work); 222341f741fSDavid Howells if (!queue_work(afs_wq, &call->work)) 223341f741fSDavid Howells afs_put_call(call); 2243bf0fb6fSDavid Howells } 2256c67c7c3SDavid Howells } 2266c67c7c3SDavid Howells 2276c67c7c3SDavid Howells /* 22808e0e7c8SDavid Howells * allocate a call with flat request and reply buffers 22908e0e7c8SDavid Howells */ 230f044c884SDavid Howells struct afs_call *afs_alloc_flat_call(struct afs_net *net, 231f044c884SDavid Howells const struct afs_call_type *type, 232d001648eSDavid Howells size_t request_size, size_t reply_max) 23308e0e7c8SDavid Howells { 23408e0e7c8SDavid Howells struct afs_call *call; 23508e0e7c8SDavid Howells 236f044c884SDavid Howells call = afs_alloc_call(net, type, GFP_NOFS); 23708e0e7c8SDavid Howells if (!call) 23808e0e7c8SDavid Howells goto nomem_call; 23908e0e7c8SDavid Howells 24000d3b7a4SDavid Howells if (request_size) { 241341f741fSDavid Howells call->request_size = request_size; 24200d3b7a4SDavid Howells call->request = kmalloc(request_size, GFP_NOFS); 24300d3b7a4SDavid Howells if (!call->request) 24400d3b7a4SDavid Howells goto nomem_free; 24500d3b7a4SDavid Howells } 24600d3b7a4SDavid Howells 247d001648eSDavid Howells if (reply_max) { 248341f741fSDavid Howells call->reply_max = reply_max; 249d001648eSDavid Howells call->buffer = kmalloc(reply_max, GFP_NOFS); 25000d3b7a4SDavid Howells if (!call->buffer) 25100d3b7a4SDavid Howells goto nomem_free; 25200d3b7a4SDavid Howells } 25300d3b7a4SDavid Howells 25412bdcf33SDavid Howells afs_extract_to_buf(call, call->reply_max); 255025db80cSDavid Howells call->operation_ID = type->op; 25608e0e7c8SDavid Howells init_waitqueue_head(&call->waitq); 25708e0e7c8SDavid Howells return call; 25808e0e7c8SDavid Howells 25900d3b7a4SDavid Howells nomem_free: 260341f741fSDavid Howells afs_put_call(call); 26108e0e7c8SDavid Howells nomem_call: 26208e0e7c8SDavid Howells return NULL; 26308e0e7c8SDavid Howells } 26408e0e7c8SDavid Howells 26508e0e7c8SDavid Howells /* 26608e0e7c8SDavid Howells * clean up a call with flat buffer 26708e0e7c8SDavid Howells */ 26808e0e7c8SDavid Howells void afs_flat_call_destructor(struct afs_call *call) 26908e0e7c8SDavid Howells { 27008e0e7c8SDavid Howells _enter(""); 27108e0e7c8SDavid Howells 27208e0e7c8SDavid Howells kfree(call->request); 27308e0e7c8SDavid Howells call->request = NULL; 27408e0e7c8SDavid Howells kfree(call->buffer); 27508e0e7c8SDavid Howells call->buffer = NULL; 27608e0e7c8SDavid Howells } 27708e0e7c8SDavid Howells 2782f5705a5SDavid Howells #define AFS_BVEC_MAX 8 2792f5705a5SDavid Howells 2802f5705a5SDavid Howells /* 2812f5705a5SDavid Howells * Load the given bvec with the next few pages. 2822f5705a5SDavid Howells */ 2832f5705a5SDavid Howells static void afs_load_bvec(struct afs_call *call, struct msghdr *msg, 2842f5705a5SDavid Howells struct bio_vec *bv, pgoff_t first, pgoff_t last, 2852f5705a5SDavid Howells unsigned offset) 2862f5705a5SDavid Howells { 2872f5705a5SDavid Howells struct page *pages[AFS_BVEC_MAX]; 2882f5705a5SDavid Howells unsigned int nr, n, i, to, bytes = 0; 2892f5705a5SDavid Howells 2902f5705a5SDavid Howells nr = min_t(pgoff_t, last - first + 1, AFS_BVEC_MAX); 2912f5705a5SDavid Howells n = find_get_pages_contig(call->mapping, first, nr, pages); 2922f5705a5SDavid Howells ASSERTCMP(n, ==, nr); 2932f5705a5SDavid Howells 2942f5705a5SDavid Howells msg->msg_flags |= MSG_MORE; 2952f5705a5SDavid Howells for (i = 0; i < nr; i++) { 2962f5705a5SDavid Howells to = PAGE_SIZE; 2972f5705a5SDavid Howells if (first + i >= last) { 2982f5705a5SDavid Howells to = call->last_to; 2992f5705a5SDavid Howells msg->msg_flags &= ~MSG_MORE; 3002f5705a5SDavid Howells } 3012f5705a5SDavid Howells bv[i].bv_page = pages[i]; 3022f5705a5SDavid Howells bv[i].bv_len = to - offset; 3032f5705a5SDavid Howells bv[i].bv_offset = offset; 3042f5705a5SDavid Howells bytes += to - offset; 3052f5705a5SDavid Howells offset = 0; 3062f5705a5SDavid Howells } 3072f5705a5SDavid Howells 308aa563d7bSDavid Howells iov_iter_bvec(&msg->msg_iter, WRITE, bv, nr, bytes); 3092f5705a5SDavid Howells } 3102f5705a5SDavid Howells 31108e0e7c8SDavid Howells /* 312e833251aSDavid Howells * Advance the AFS call state when the RxRPC call ends the transmit phase. 313e833251aSDavid Howells */ 314e833251aSDavid Howells static void afs_notify_end_request_tx(struct sock *sock, 315e833251aSDavid Howells struct rxrpc_call *rxcall, 316e833251aSDavid Howells unsigned long call_user_ID) 317e833251aSDavid Howells { 318e833251aSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 319e833251aSDavid Howells 32098bf40cdSDavid Howells afs_set_call_state(call, AFS_CALL_CL_REQUESTING, AFS_CALL_CL_AWAIT_REPLY); 321e833251aSDavid Howells } 322e833251aSDavid Howells 323e833251aSDavid Howells /* 32431143d5dSDavid Howells * attach the data from a bunch of pages on an inode to a call 32531143d5dSDavid Howells */ 32639c6aceaSAl Viro static int afs_send_pages(struct afs_call *call, struct msghdr *msg) 32731143d5dSDavid Howells { 3282f5705a5SDavid Howells struct bio_vec bv[AFS_BVEC_MAX]; 3292f5705a5SDavid Howells unsigned int bytes, nr, loop, offset; 33031143d5dSDavid Howells pgoff_t first = call->first, last = call->last; 33131143d5dSDavid Howells int ret; 33231143d5dSDavid Howells 33331143d5dSDavid Howells offset = call->first_offset; 33431143d5dSDavid Howells call->first_offset = 0; 33531143d5dSDavid Howells 33631143d5dSDavid Howells do { 3372f5705a5SDavid Howells afs_load_bvec(call, msg, bv, first, last, offset); 3382c099014SDavid Howells trace_afs_send_pages(call, msg, first, last, offset); 3392c099014SDavid Howells 34031143d5dSDavid Howells offset = 0; 3412f5705a5SDavid Howells bytes = msg->msg_iter.count; 3422f5705a5SDavid Howells nr = msg->msg_iter.nr_segs; 34331143d5dSDavid Howells 344f044c884SDavid Howells ret = rxrpc_kernel_send_data(call->net->socket, call->rxcall, msg, 345e833251aSDavid Howells bytes, afs_notify_end_request_tx); 3462f5705a5SDavid Howells for (loop = 0; loop < nr; loop++) 3472f5705a5SDavid Howells put_page(bv[loop].bv_page); 34831143d5dSDavid Howells if (ret < 0) 34931143d5dSDavid Howells break; 35031143d5dSDavid Howells 3512f5705a5SDavid Howells first += nr; 3525bbf5d39SDavid Howells } while (first <= last); 35331143d5dSDavid Howells 3542c099014SDavid Howells trace_afs_sent_pages(call, call->first, last, first, ret); 35531143d5dSDavid Howells return ret; 35631143d5dSDavid Howells } 35731143d5dSDavid Howells 35831143d5dSDavid Howells /* 3590b9bf381SDavid Howells * Initiate a call and synchronously queue up the parameters for dispatch. Any 3600b9bf381SDavid Howells * error is stored into the call struct, which the caller must check for. 36108e0e7c8SDavid Howells */ 3620b9bf381SDavid Howells void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) 36308e0e7c8SDavid Howells { 3642feeaf84SDavid Howells struct sockaddr_rxrpc *srx = &ac->alist->addrs[ac->index]; 36508e0e7c8SDavid Howells struct rxrpc_call *rxcall; 36608e0e7c8SDavid Howells struct msghdr msg; 36708e0e7c8SDavid Howells struct kvec iov[1]; 368e754eba6SDavid Howells s64 tx_total_len; 36908e0e7c8SDavid Howells int ret; 37008e0e7c8SDavid Howells 3714d9df986SDavid Howells _enter(",{%pISp},", &srx->transport); 37208e0e7c8SDavid Howells 37300d3b7a4SDavid Howells ASSERT(call->type != NULL); 37400d3b7a4SDavid Howells ASSERT(call->type->name != NULL); 37500d3b7a4SDavid Howells 37631143d5dSDavid Howells _debug("____MAKE %p{%s,%x} [%d]____", 37731143d5dSDavid Howells call, call->type->name, key_serial(call->key), 378f044c884SDavid Howells atomic_read(&call->net->nr_outstanding_calls)); 37900d3b7a4SDavid Howells 3803bf0fb6fSDavid Howells call->addr_ix = ac->index; 3813bf0fb6fSDavid Howells call->alist = afs_get_addrlist(ac->alist); 38208e0e7c8SDavid Howells 383e754eba6SDavid Howells /* Work out the length we're going to transmit. This is awkward for 384e754eba6SDavid Howells * calls such as FS.StoreData where there's an extra injection of data 385e754eba6SDavid Howells * after the initial fixed part. 386e754eba6SDavid Howells */ 387e754eba6SDavid Howells tx_total_len = call->request_size; 388e754eba6SDavid Howells if (call->send_pages) { 3891199db60SDavid Howells if (call->last == call->first) { 390e754eba6SDavid Howells tx_total_len += call->last_to - call->first_offset; 3911199db60SDavid Howells } else { 3921199db60SDavid Howells /* It looks mathematically like you should be able to 3931199db60SDavid Howells * combine the following lines with the ones above, but 3941199db60SDavid Howells * unsigned arithmetic is fun when it wraps... 3951199db60SDavid Howells */ 3961199db60SDavid Howells tx_total_len += PAGE_SIZE - call->first_offset; 3971199db60SDavid Howells tx_total_len += call->last_to; 3981199db60SDavid Howells tx_total_len += (call->last - call->first - 1) * PAGE_SIZE; 3991199db60SDavid Howells } 400e754eba6SDavid Howells } 401e754eba6SDavid Howells 40234fa4761SDavid Howells /* If the call is going to be asynchronous, we need an extra ref for 40334fa4761SDavid Howells * the call to hold itself so the caller need not hang on to its ref. 40434fa4761SDavid Howells */ 40534fa4761SDavid Howells if (call->async) 40634fa4761SDavid Howells afs_get_call(call, afs_call_trace_get); 40734fa4761SDavid Howells 40808e0e7c8SDavid Howells /* create a call */ 4094d9df986SDavid Howells rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key, 410e754eba6SDavid Howells (unsigned long)call, 411e754eba6SDavid Howells tx_total_len, gfp, 4120b9bf381SDavid Howells (call->async ? 41356ff9c83SDavid Howells afs_wake_up_async_call : 414a68f4a27SDavid Howells afs_wake_up_call_waiter), 415a25e21f0SDavid Howells call->upgrade, 41620b8391fSDavid Howells call->intr, 417a25e21f0SDavid Howells call->debug_id); 41808e0e7c8SDavid Howells if (IS_ERR(rxcall)) { 41908e0e7c8SDavid Howells ret = PTR_ERR(rxcall); 4203bf0fb6fSDavid Howells call->error = ret; 42108e0e7c8SDavid Howells goto error_kill_call; 42208e0e7c8SDavid Howells } 42308e0e7c8SDavid Howells 42408e0e7c8SDavid Howells call->rxcall = rxcall; 42508e0e7c8SDavid Howells 42694f699c9SDavid Howells if (call->max_lifespan) 42794f699c9SDavid Howells rxrpc_kernel_set_max_life(call->net->socket, rxcall, 42894f699c9SDavid Howells call->max_lifespan); 42994f699c9SDavid Howells 43008e0e7c8SDavid Howells /* send the request */ 43108e0e7c8SDavid Howells iov[0].iov_base = call->request; 43208e0e7c8SDavid Howells iov[0].iov_len = call->request_size; 43308e0e7c8SDavid Howells 43408e0e7c8SDavid Howells msg.msg_name = NULL; 43508e0e7c8SDavid Howells msg.msg_namelen = 0; 436aa563d7bSDavid Howells iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, call->request_size); 43708e0e7c8SDavid Howells msg.msg_control = NULL; 43808e0e7c8SDavid Howells msg.msg_controllen = 0; 439bc5e3a54SDavid Howells msg.msg_flags = MSG_WAITALL | (call->send_pages ? MSG_MORE : 0); 44008e0e7c8SDavid Howells 441f044c884SDavid Howells ret = rxrpc_kernel_send_data(call->net->socket, rxcall, 442e833251aSDavid Howells &msg, call->request_size, 443e833251aSDavid Howells afs_notify_end_request_tx); 44408e0e7c8SDavid Howells if (ret < 0) 44508e0e7c8SDavid Howells goto error_do_abort; 44608e0e7c8SDavid Howells 44731143d5dSDavid Howells if (call->send_pages) { 44839c6aceaSAl Viro ret = afs_send_pages(call, &msg); 44931143d5dSDavid Howells if (ret < 0) 45031143d5dSDavid Howells goto error_do_abort; 45131143d5dSDavid Howells } 45231143d5dSDavid Howells 45334fa4761SDavid Howells /* Note that at this point, we may have received the reply or an abort 45434fa4761SDavid Howells * - and an asynchronous call may already have completed. 4550b9bf381SDavid Howells * 4560b9bf381SDavid Howells * afs_wait_for_call_to_complete(call, ac) 4570b9bf381SDavid Howells * must be called to synchronously clean up. 45834fa4761SDavid Howells */ 4590b9bf381SDavid Howells return; 46008e0e7c8SDavid Howells 46108e0e7c8SDavid Howells error_do_abort: 46270af0e3bSDavid Howells if (ret != -ECONNABORTED) { 463f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, rxcall, 464f044c884SDavid Howells RX_USER_ABORT, ret, "KSD"); 46570af0e3bSDavid Howells } else { 466aa563d7bSDavid Howells iov_iter_kvec(&msg.msg_iter, READ, NULL, 0, 0); 467eb9950ebSDavid Howells rxrpc_kernel_recv_data(call->net->socket, rxcall, 468eb9950ebSDavid Howells &msg.msg_iter, false, 469eb9950ebSDavid Howells &call->abort_code, &call->service_id); 470d2ddc776SDavid Howells ac->abort_code = call->abort_code; 471d2ddc776SDavid Howells ac->responded = true; 47270af0e3bSDavid Howells } 473025db80cSDavid Howells call->error = ret; 474025db80cSDavid Howells trace_afs_call_done(call); 47508e0e7c8SDavid Howells error_kill_call: 4763bf0fb6fSDavid Howells if (call->type->done) 4773bf0fb6fSDavid Howells call->type->done(call); 47834fa4761SDavid Howells 47934fa4761SDavid Howells /* We need to dispose of the extra ref we grabbed for an async call. 48034fa4761SDavid Howells * The call, however, might be queued on afs_async_calls and we need to 48134fa4761SDavid Howells * make sure we don't get any more notifications that might requeue it. 48234fa4761SDavid Howells */ 48334fa4761SDavid Howells if (call->rxcall) { 48434fa4761SDavid Howells rxrpc_kernel_end_call(call->net->socket, call->rxcall); 48534fa4761SDavid Howells call->rxcall = NULL; 48634fa4761SDavid Howells } 48734fa4761SDavid Howells if (call->async) { 48834fa4761SDavid Howells if (cancel_work_sync(&call->async_work)) 489341f741fSDavid Howells afs_put_call(call); 49034fa4761SDavid Howells afs_put_call(call); 49134fa4761SDavid Howells } 49234fa4761SDavid Howells 493d2ddc776SDavid Howells ac->error = ret; 49434fa4761SDavid Howells call->state = AFS_CALL_COMPLETE; 49508e0e7c8SDavid Howells _leave(" = %d", ret); 49608e0e7c8SDavid Howells } 49708e0e7c8SDavid Howells 49808e0e7c8SDavid Howells /* 49908e0e7c8SDavid Howells * deliver messages to a call 50008e0e7c8SDavid Howells */ 50108e0e7c8SDavid Howells static void afs_deliver_to_call(struct afs_call *call) 50208e0e7c8SDavid Howells { 50398bf40cdSDavid Howells enum afs_call_state state; 50498bf40cdSDavid Howells u32 abort_code, remote_abort = 0; 50508e0e7c8SDavid Howells int ret; 50608e0e7c8SDavid Howells 507d001648eSDavid Howells _enter("%s", call->type->name); 50808e0e7c8SDavid Howells 50998bf40cdSDavid Howells while (state = READ_ONCE(call->state), 51098bf40cdSDavid Howells state == AFS_CALL_CL_AWAIT_REPLY || 51198bf40cdSDavid Howells state == AFS_CALL_SV_AWAIT_OP_ID || 51298bf40cdSDavid Howells state == AFS_CALL_SV_AWAIT_REQUEST || 51398bf40cdSDavid Howells state == AFS_CALL_SV_AWAIT_ACK 514d001648eSDavid Howells ) { 51598bf40cdSDavid Howells if (state == AFS_CALL_SV_AWAIT_ACK) { 516fc276122SDavid Howells iov_iter_kvec(&call->def_iter, READ, NULL, 0, 0); 517f044c884SDavid Howells ret = rxrpc_kernel_recv_data(call->net->socket, 518fc276122SDavid Howells call->rxcall, &call->def_iter, 51912bdcf33SDavid Howells false, &remote_abort, 520a68f4a27SDavid Howells &call->service_id); 521fc276122SDavid Howells trace_afs_receive_data(call, &call->def_iter, false, ret); 5228e8d7f13SDavid Howells 523d001648eSDavid Howells if (ret == -EINPROGRESS || ret == -EAGAIN) 524d001648eSDavid Howells return; 52598bf40cdSDavid Howells if (ret < 0 || ret == 1) { 52698bf40cdSDavid Howells if (ret == 1) 52798bf40cdSDavid Howells ret = 0; 528025db80cSDavid Howells goto call_complete; 52998bf40cdSDavid Howells } 530d001648eSDavid Howells return; 531d001648eSDavid Howells } 532d001648eSDavid Howells 5334571577fSDavid Howells if (!call->have_reply_time && 53412d8e95aSDavid Howells rxrpc_kernel_get_reply_time(call->net->socket, 53512d8e95aSDavid Howells call->rxcall, 53612d8e95aSDavid Howells &call->reply_time)) 5374571577fSDavid Howells call->have_reply_time = true; 53812d8e95aSDavid Howells 539d001648eSDavid Howells ret = call->type->deliver(call); 54098bf40cdSDavid Howells state = READ_ONCE(call->state); 541d001648eSDavid Howells switch (ret) { 54208e0e7c8SDavid Howells case 0: 5433bf0fb6fSDavid Howells afs_queue_call_work(call); 544f2686b09SDavid Howells if (state == AFS_CALL_CL_PROC_REPLY) { 545f2686b09SDavid Howells if (call->cbi) 546f2686b09SDavid Howells set_bit(AFS_SERVER_FL_MAY_HAVE_CB, 547f2686b09SDavid Howells &call->cbi->server->flags); 548025db80cSDavid Howells goto call_complete; 549f2686b09SDavid Howells } 55098bf40cdSDavid Howells ASSERTCMP(state, >, AFS_CALL_CL_PROC_REPLY); 551d001648eSDavid Howells goto done; 552d001648eSDavid Howells case -EINPROGRESS: 553d001648eSDavid Howells case -EAGAIN: 554d001648eSDavid Howells goto out; 55570af0e3bSDavid Howells case -ECONNABORTED: 55698bf40cdSDavid Howells ASSERTCMP(state, ==, AFS_CALL_COMPLETE); 55798bf40cdSDavid Howells goto done; 55808e0e7c8SDavid Howells case -ENOTSUPP: 5591157f153SDavid Howells abort_code = RXGEN_OPCODE; 560f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 5613a92789aSDavid Howells abort_code, ret, "KIV"); 56298bf40cdSDavid Howells goto local_abort; 5634ac15ea5SDavid Howells case -EIO: 5644ac15ea5SDavid Howells pr_err("kAFS: Call %u in bad state %u\n", 5654ac15ea5SDavid Howells call->debug_id, state); 5664ac15ea5SDavid Howells /* Fall through */ 567d001648eSDavid Howells case -ENODATA: 568d001648eSDavid Howells case -EBADMSG: 569d001648eSDavid Howells case -EMSGSIZE: 57008e0e7c8SDavid Howells abort_code = RXGEN_CC_UNMARSHAL; 57198bf40cdSDavid Howells if (state != AFS_CALL_CL_AWAIT_REPLY) 57208e0e7c8SDavid Howells abort_code = RXGEN_SS_UNMARSHAL; 573f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 57412bdcf33SDavid Howells abort_code, ret, "KUM"); 57598bf40cdSDavid Howells goto local_abort; 5768022c4b9SDavid Howells default: 5778022c4b9SDavid Howells abort_code = RX_USER_ABORT; 5788022c4b9SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 5798022c4b9SDavid Howells abort_code, ret, "KER"); 5808022c4b9SDavid Howells goto local_abort; 58108e0e7c8SDavid Howells } 58208e0e7c8SDavid Howells } 58308e0e7c8SDavid Howells 584d001648eSDavid Howells done: 5853bf0fb6fSDavid Howells if (call->type->done) 5863bf0fb6fSDavid Howells call->type->done(call); 58798bf40cdSDavid Howells if (state == AFS_CALL_COMPLETE && call->incoming) 588341f741fSDavid Howells afs_put_call(call); 589d001648eSDavid Howells out: 59008e0e7c8SDavid Howells _leave(""); 591d001648eSDavid Howells return; 592d001648eSDavid Howells 59398bf40cdSDavid Howells local_abort: 59498bf40cdSDavid Howells abort_code = 0; 595025db80cSDavid Howells call_complete: 59698bf40cdSDavid Howells afs_set_call_complete(call, ret, remote_abort); 59798bf40cdSDavid Howells state = AFS_CALL_COMPLETE; 598d001648eSDavid Howells goto done; 59908e0e7c8SDavid Howells } 60008e0e7c8SDavid Howells 60108e0e7c8SDavid Howells /* 6020b9bf381SDavid Howells * Wait synchronously for a call to complete and clean up the call struct. 60308e0e7c8SDavid Howells */ 6040b9bf381SDavid Howells long afs_wait_for_call_to_complete(struct afs_call *call, 605d2ddc776SDavid Howells struct afs_addr_cursor *ac) 60608e0e7c8SDavid Howells { 607bc5e3a54SDavid Howells signed long rtt2, timeout; 60833cd7f2bSDavid Howells long ret; 6097150ceaaSDavid Howells bool stalled = false; 610bc5e3a54SDavid Howells u64 rtt; 611bc5e3a54SDavid Howells u32 life, last_life; 612f7f1dd31SMarc Dionne bool rxrpc_complete = false; 61308e0e7c8SDavid Howells 61408e0e7c8SDavid Howells DECLARE_WAITQUEUE(myself, current); 61508e0e7c8SDavid Howells 61608e0e7c8SDavid Howells _enter(""); 61708e0e7c8SDavid Howells 6180b9bf381SDavid Howells ret = call->error; 6190b9bf381SDavid Howells if (ret < 0) 6200b9bf381SDavid Howells goto out; 6210b9bf381SDavid Howells 622f044c884SDavid Howells rtt = rxrpc_kernel_get_rtt(call->net->socket, call->rxcall); 623bc5e3a54SDavid Howells rtt2 = nsecs_to_jiffies64(rtt) * 2; 624bc5e3a54SDavid Howells if (rtt2 < 2) 625bc5e3a54SDavid Howells rtt2 = 2; 626bc5e3a54SDavid Howells 627bc5e3a54SDavid Howells timeout = rtt2; 6284611da30SMarc Dionne rxrpc_kernel_check_life(call->net->socket, call->rxcall, &last_life); 629bc5e3a54SDavid Howells 63008e0e7c8SDavid Howells add_wait_queue(&call->waitq, &myself); 63108e0e7c8SDavid Howells for (;;) { 632bc5e3a54SDavid Howells set_current_state(TASK_UNINTERRUPTIBLE); 63308e0e7c8SDavid Howells 63408e0e7c8SDavid Howells /* deliver any messages that are in the queue */ 63598bf40cdSDavid Howells if (!afs_check_call_state(call, AFS_CALL_COMPLETE) && 63698bf40cdSDavid Howells call->need_attention) { 637d001648eSDavid Howells call->need_attention = false; 63808e0e7c8SDavid Howells __set_current_state(TASK_RUNNING); 63908e0e7c8SDavid Howells afs_deliver_to_call(call); 64008e0e7c8SDavid Howells continue; 64108e0e7c8SDavid Howells } 64208e0e7c8SDavid Howells 64398bf40cdSDavid Howells if (afs_check_call_state(call, AFS_CALL_COMPLETE)) 64408e0e7c8SDavid Howells break; 645bc5e3a54SDavid Howells 646f7f1dd31SMarc Dionne if (!rxrpc_kernel_check_life(call->net->socket, call->rxcall, &life)) { 647f7f1dd31SMarc Dionne /* rxrpc terminated the call. */ 648f7f1dd31SMarc Dionne rxrpc_complete = true; 649f7f1dd31SMarc Dionne break; 650f7f1dd31SMarc Dionne } 651f7f1dd31SMarc Dionne 65220b8391fSDavid Howells if (call->intr && timeout == 0 && 6537150ceaaSDavid Howells life == last_life && signal_pending(current)) { 6547150ceaaSDavid Howells if (stalled) 655bc5e3a54SDavid Howells break; 6567150ceaaSDavid Howells __set_current_state(TASK_RUNNING); 6577150ceaaSDavid Howells rxrpc_kernel_probe_life(call->net->socket, call->rxcall); 6587150ceaaSDavid Howells timeout = rtt2; 6597150ceaaSDavid Howells stalled = true; 6607150ceaaSDavid Howells continue; 6617150ceaaSDavid Howells } 662bc5e3a54SDavid Howells 663bc5e3a54SDavid Howells if (life != last_life) { 664bc5e3a54SDavid Howells timeout = rtt2; 665bc5e3a54SDavid Howells last_life = life; 6667150ceaaSDavid Howells stalled = false; 667bc5e3a54SDavid Howells } 668bc5e3a54SDavid Howells 669bc5e3a54SDavid Howells timeout = schedule_timeout(timeout); 67008e0e7c8SDavid Howells } 67108e0e7c8SDavid Howells 67208e0e7c8SDavid Howells remove_wait_queue(&call->waitq, &myself); 67308e0e7c8SDavid Howells __set_current_state(TASK_RUNNING); 67408e0e7c8SDavid Howells 67598bf40cdSDavid Howells if (!afs_check_call_state(call, AFS_CALL_COMPLETE)) { 676f7f1dd31SMarc Dionne if (rxrpc_complete) { 677f7f1dd31SMarc Dionne afs_set_call_complete(call, call->error, call->abort_code); 678f7f1dd31SMarc Dionne } else { 679f7f1dd31SMarc Dionne /* Kill off the call if it's still live. */ 680954cd6dcSDavid Howells _debug("call interrupted"); 681d2ddc776SDavid Howells if (rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 68298bf40cdSDavid Howells RX_USER_ABORT, -EINTR, "KWI")) 68398bf40cdSDavid Howells afs_set_call_complete(call, -EINTR, 0); 68408e0e7c8SDavid Howells } 685f7f1dd31SMarc Dionne } 68608e0e7c8SDavid Howells 68798bf40cdSDavid Howells spin_lock_bh(&call->state_lock); 688d2ddc776SDavid Howells ac->abort_code = call->abort_code; 689d2ddc776SDavid Howells ac->error = call->error; 69098bf40cdSDavid Howells spin_unlock_bh(&call->state_lock); 691d2ddc776SDavid Howells 692d2ddc776SDavid Howells ret = ac->error; 693d2ddc776SDavid Howells switch (ret) { 694d2ddc776SDavid Howells case 0: 695ffba718eSDavid Howells ret = call->ret0; 696ffba718eSDavid Howells call->ret0 = 0; 697ffba718eSDavid Howells 698d2ddc776SDavid Howells /* Fall through */ 699d2ddc776SDavid Howells case -ECONNABORTED: 700d2ddc776SDavid Howells ac->responded = true; 701d2ddc776SDavid Howells break; 702d2ddc776SDavid Howells } 70333cd7f2bSDavid Howells 7040b9bf381SDavid Howells out: 70508e0e7c8SDavid Howells _debug("call complete"); 706341f741fSDavid Howells afs_put_call(call); 70733cd7f2bSDavid Howells _leave(" = %p", (void *)ret); 70808e0e7c8SDavid Howells return ret; 70908e0e7c8SDavid Howells } 71008e0e7c8SDavid Howells 71108e0e7c8SDavid Howells /* 71208e0e7c8SDavid Howells * wake up a waiting call 71308e0e7c8SDavid Howells */ 714d001648eSDavid Howells static void afs_wake_up_call_waiter(struct sock *sk, struct rxrpc_call *rxcall, 715d001648eSDavid Howells unsigned long call_user_ID) 71608e0e7c8SDavid Howells { 717d001648eSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 718d001648eSDavid Howells 719d001648eSDavid Howells call->need_attention = true; 72008e0e7c8SDavid Howells wake_up(&call->waitq); 72108e0e7c8SDavid Howells } 72208e0e7c8SDavid Howells 72308e0e7c8SDavid Howells /* 72408e0e7c8SDavid Howells * wake up an asynchronous call 72508e0e7c8SDavid Howells */ 726d001648eSDavid Howells static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall, 727d001648eSDavid Howells unsigned long call_user_ID) 72808e0e7c8SDavid Howells { 729d001648eSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 730341f741fSDavid Howells int u; 731d001648eSDavid Howells 7328e8d7f13SDavid Howells trace_afs_notify_call(rxcall, call); 733d001648eSDavid Howells call->need_attention = true; 734341f741fSDavid Howells 735bfc18e38SMark Rutland u = atomic_fetch_add_unless(&call->usage, 1, 0); 736341f741fSDavid Howells if (u != 0) { 737341f741fSDavid Howells trace_afs_call(call, afs_call_trace_wake, u, 738f044c884SDavid Howells atomic_read(&call->net->nr_outstanding_calls), 739341f741fSDavid Howells __builtin_return_address(0)); 740341f741fSDavid Howells 741341f741fSDavid Howells if (!queue_work(afs_async_calls, &call->async_work)) 742341f741fSDavid Howells afs_put_call(call); 743341f741fSDavid Howells } 74408e0e7c8SDavid Howells } 74508e0e7c8SDavid Howells 74608e0e7c8SDavid Howells /* 747341f741fSDavid Howells * Delete an asynchronous call. The work item carries a ref to the call struct 748341f741fSDavid Howells * that we need to release. 74908e0e7c8SDavid Howells */ 750d001648eSDavid Howells static void afs_delete_async_call(struct work_struct *work) 75108e0e7c8SDavid Howells { 752d001648eSDavid Howells struct afs_call *call = container_of(work, struct afs_call, async_work); 753d001648eSDavid Howells 75408e0e7c8SDavid Howells _enter(""); 75508e0e7c8SDavid Howells 756341f741fSDavid Howells afs_put_call(call); 75708e0e7c8SDavid Howells 75808e0e7c8SDavid Howells _leave(""); 75908e0e7c8SDavid Howells } 76008e0e7c8SDavid Howells 76108e0e7c8SDavid Howells /* 762341f741fSDavid Howells * Perform I/O processing on an asynchronous call. The work item carries a ref 763341f741fSDavid Howells * to the call struct that we either need to release or to pass on. 76408e0e7c8SDavid Howells */ 765d001648eSDavid Howells static void afs_process_async_call(struct work_struct *work) 76608e0e7c8SDavid Howells { 767d001648eSDavid Howells struct afs_call *call = container_of(work, struct afs_call, async_work); 768d001648eSDavid Howells 76908e0e7c8SDavid Howells _enter(""); 77008e0e7c8SDavid Howells 771d001648eSDavid Howells if (call->state < AFS_CALL_COMPLETE && call->need_attention) { 772d001648eSDavid Howells call->need_attention = false; 77308e0e7c8SDavid Howells afs_deliver_to_call(call); 774d001648eSDavid Howells } 77508e0e7c8SDavid Howells 77656ff9c83SDavid Howells if (call->state == AFS_CALL_COMPLETE) { 777341f741fSDavid Howells /* We have two refs to release - one from the alloc and one 778341f741fSDavid Howells * queued with the work item - and we can't just deallocate the 779341f741fSDavid Howells * call because the work item may be queued again. 780341f741fSDavid Howells */ 781d001648eSDavid Howells call->async_work.func = afs_delete_async_call; 782341f741fSDavid Howells if (!queue_work(afs_async_calls, &call->async_work)) 783341f741fSDavid Howells afs_put_call(call); 78408e0e7c8SDavid Howells } 78508e0e7c8SDavid Howells 786341f741fSDavid Howells afs_put_call(call); 78708e0e7c8SDavid Howells _leave(""); 78808e0e7c8SDavid Howells } 78908e0e7c8SDavid Howells 79000e90712SDavid Howells static void afs_rx_attach(struct rxrpc_call *rxcall, unsigned long user_call_ID) 79100e90712SDavid Howells { 79200e90712SDavid Howells struct afs_call *call = (struct afs_call *)user_call_ID; 79300e90712SDavid Howells 79400e90712SDavid Howells call->rxcall = rxcall; 79500e90712SDavid Howells } 79600e90712SDavid Howells 79700e90712SDavid Howells /* 79800e90712SDavid Howells * Charge the incoming call preallocation. 79900e90712SDavid Howells */ 800f044c884SDavid Howells void afs_charge_preallocation(struct work_struct *work) 80100e90712SDavid Howells { 802f044c884SDavid Howells struct afs_net *net = 803f044c884SDavid Howells container_of(work, struct afs_net, charge_preallocation_work); 804f044c884SDavid Howells struct afs_call *call = net->spare_incoming_call; 80500e90712SDavid Howells 80600e90712SDavid Howells for (;;) { 80700e90712SDavid Howells if (!call) { 808f044c884SDavid Howells call = afs_alloc_call(net, &afs_RXCMxxxx, GFP_KERNEL); 80900e90712SDavid Howells if (!call) 81000e90712SDavid Howells break; 81100e90712SDavid Howells 81256ff9c83SDavid Howells call->async = true; 81398bf40cdSDavid Howells call->state = AFS_CALL_SV_AWAIT_OP_ID; 81456ff9c83SDavid Howells init_waitqueue_head(&call->waitq); 81512bdcf33SDavid Howells afs_extract_to_tmp(call); 81600e90712SDavid Howells } 81700e90712SDavid Howells 818f044c884SDavid Howells if (rxrpc_kernel_charge_accept(net->socket, 81900e90712SDavid Howells afs_wake_up_async_call, 82000e90712SDavid Howells afs_rx_attach, 82100e90712SDavid Howells (unsigned long)call, 822a25e21f0SDavid Howells GFP_KERNEL, 823a25e21f0SDavid Howells call->debug_id) < 0) 82400e90712SDavid Howells break; 82500e90712SDavid Howells call = NULL; 82600e90712SDavid Howells } 827f044c884SDavid Howells net->spare_incoming_call = call; 82800e90712SDavid Howells } 82900e90712SDavid Howells 83000e90712SDavid Howells /* 83100e90712SDavid Howells * Discard a preallocated call when a socket is shut down. 83200e90712SDavid Howells */ 83300e90712SDavid Howells static void afs_rx_discard_new_call(struct rxrpc_call *rxcall, 83400e90712SDavid Howells unsigned long user_call_ID) 83500e90712SDavid Howells { 83600e90712SDavid Howells struct afs_call *call = (struct afs_call *)user_call_ID; 83700e90712SDavid Howells 83800e90712SDavid Howells call->rxcall = NULL; 839341f741fSDavid Howells afs_put_call(call); 84000e90712SDavid Howells } 84100e90712SDavid Howells 84208e0e7c8SDavid Howells /* 843d001648eSDavid Howells * Notification of an incoming call. 844d001648eSDavid Howells */ 84500e90712SDavid Howells static void afs_rx_new_call(struct sock *sk, struct rxrpc_call *rxcall, 84600e90712SDavid Howells unsigned long user_call_ID) 847d001648eSDavid Howells { 848f044c884SDavid Howells struct afs_net *net = afs_sock2net(sk); 849f044c884SDavid Howells 850f044c884SDavid Howells queue_work(afs_wq, &net->charge_preallocation_work); 851d001648eSDavid Howells } 852d001648eSDavid Howells 853d001648eSDavid Howells /* 854372ee163SDavid Howells * Grab the operation ID from an incoming cache manager call. The socket 855372ee163SDavid Howells * buffer is discarded on error or if we don't yet have sufficient data. 85608e0e7c8SDavid Howells */ 857d001648eSDavid Howells static int afs_deliver_cm_op_id(struct afs_call *call) 85808e0e7c8SDavid Howells { 859d001648eSDavid Howells int ret; 86008e0e7c8SDavid Howells 861fc276122SDavid Howells _enter("{%zu}", iov_iter_count(call->iter)); 86208e0e7c8SDavid Howells 86308e0e7c8SDavid Howells /* the operation ID forms the first four bytes of the request data */ 86412bdcf33SDavid Howells ret = afs_extract_data(call, true); 865d001648eSDavid Howells if (ret < 0) 866d001648eSDavid Howells return ret; 86708e0e7c8SDavid Howells 86850a2c953SDavid Howells call->operation_ID = ntohl(call->tmp); 86998bf40cdSDavid Howells afs_set_call_state(call, AFS_CALL_SV_AWAIT_OP_ID, AFS_CALL_SV_AWAIT_REQUEST); 87008e0e7c8SDavid Howells 87108e0e7c8SDavid Howells /* ask the cache manager to route the call (it'll change the call type 87208e0e7c8SDavid Howells * if successful) */ 87308e0e7c8SDavid Howells if (!afs_cm_incoming_call(call)) 87408e0e7c8SDavid Howells return -ENOTSUPP; 87508e0e7c8SDavid Howells 8768e8d7f13SDavid Howells trace_afs_cb_call(call); 8778e8d7f13SDavid Howells 87808e0e7c8SDavid Howells /* pass responsibility for the remainer of this message off to the 87908e0e7c8SDavid Howells * cache manager op */ 880d001648eSDavid Howells return call->type->deliver(call); 88108e0e7c8SDavid Howells } 88208e0e7c8SDavid Howells 88308e0e7c8SDavid Howells /* 884e833251aSDavid Howells * Advance the AFS call state when an RxRPC service call ends the transmit 885e833251aSDavid Howells * phase. 886e833251aSDavid Howells */ 887e833251aSDavid Howells static void afs_notify_end_reply_tx(struct sock *sock, 888e833251aSDavid Howells struct rxrpc_call *rxcall, 889e833251aSDavid Howells unsigned long call_user_ID) 890e833251aSDavid Howells { 891e833251aSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 892e833251aSDavid Howells 89398bf40cdSDavid Howells afs_set_call_state(call, AFS_CALL_SV_REPLYING, AFS_CALL_SV_AWAIT_ACK); 894e833251aSDavid Howells } 895e833251aSDavid Howells 896e833251aSDavid Howells /* 89708e0e7c8SDavid Howells * send an empty reply 89808e0e7c8SDavid Howells */ 89908e0e7c8SDavid Howells void afs_send_empty_reply(struct afs_call *call) 90008e0e7c8SDavid Howells { 901f044c884SDavid Howells struct afs_net *net = call->net; 90208e0e7c8SDavid Howells struct msghdr msg; 90308e0e7c8SDavid Howells 90408e0e7c8SDavid Howells _enter(""); 90508e0e7c8SDavid Howells 906f044c884SDavid Howells rxrpc_kernel_set_tx_length(net->socket, call->rxcall, 0); 907e754eba6SDavid Howells 90808e0e7c8SDavid Howells msg.msg_name = NULL; 90908e0e7c8SDavid Howells msg.msg_namelen = 0; 910aa563d7bSDavid Howells iov_iter_kvec(&msg.msg_iter, WRITE, NULL, 0, 0); 91108e0e7c8SDavid Howells msg.msg_control = NULL; 91208e0e7c8SDavid Howells msg.msg_controllen = 0; 91308e0e7c8SDavid Howells msg.msg_flags = 0; 91408e0e7c8SDavid Howells 915f044c884SDavid Howells switch (rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, 0, 916e833251aSDavid Howells afs_notify_end_reply_tx)) { 91708e0e7c8SDavid Howells case 0: 91808e0e7c8SDavid Howells _leave(" [replied]"); 91908e0e7c8SDavid Howells return; 92008e0e7c8SDavid Howells 92108e0e7c8SDavid Howells case -ENOMEM: 92208e0e7c8SDavid Howells _debug("oom"); 923f044c884SDavid Howells rxrpc_kernel_abort_call(net->socket, call->rxcall, 9243a92789aSDavid Howells RX_USER_ABORT, -ENOMEM, "KOO"); 925e690c9e3SGustavo A. R. Silva /* Fall through */ 92608e0e7c8SDavid Howells default: 92708e0e7c8SDavid Howells _leave(" [error]"); 92808e0e7c8SDavid Howells return; 92908e0e7c8SDavid Howells } 93008e0e7c8SDavid Howells } 93108e0e7c8SDavid Howells 93208e0e7c8SDavid Howells /* 933b908fe6bSDavid Howells * send a simple reply 934b908fe6bSDavid Howells */ 935b908fe6bSDavid Howells void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) 936b908fe6bSDavid Howells { 937f044c884SDavid Howells struct afs_net *net = call->net; 938b908fe6bSDavid Howells struct msghdr msg; 9392e90b1c4SAl Viro struct kvec iov[1]; 940bd6dc742SDavid Howells int n; 941b908fe6bSDavid Howells 942b908fe6bSDavid Howells _enter(""); 943b908fe6bSDavid Howells 944f044c884SDavid Howells rxrpc_kernel_set_tx_length(net->socket, call->rxcall, len); 945e754eba6SDavid Howells 946b908fe6bSDavid Howells iov[0].iov_base = (void *) buf; 947b908fe6bSDavid Howells iov[0].iov_len = len; 948b908fe6bSDavid Howells msg.msg_name = NULL; 949b908fe6bSDavid Howells msg.msg_namelen = 0; 950aa563d7bSDavid Howells iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len); 951b908fe6bSDavid Howells msg.msg_control = NULL; 952b908fe6bSDavid Howells msg.msg_controllen = 0; 953b908fe6bSDavid Howells msg.msg_flags = 0; 954b908fe6bSDavid Howells 955f044c884SDavid Howells n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, len, 956e833251aSDavid Howells afs_notify_end_reply_tx); 957bd6dc742SDavid Howells if (n >= 0) { 9586c67c7c3SDavid Howells /* Success */ 959b908fe6bSDavid Howells _leave(" [replied]"); 960b908fe6bSDavid Howells return; 961bd6dc742SDavid Howells } 9626c67c7c3SDavid Howells 963bd6dc742SDavid Howells if (n == -ENOMEM) { 964b908fe6bSDavid Howells _debug("oom"); 965f044c884SDavid Howells rxrpc_kernel_abort_call(net->socket, call->rxcall, 9663a92789aSDavid Howells RX_USER_ABORT, -ENOMEM, "KOO"); 967bd6dc742SDavid Howells } 968b908fe6bSDavid Howells _leave(" [error]"); 969b908fe6bSDavid Howells } 970b908fe6bSDavid Howells 971b908fe6bSDavid Howells /* 972372ee163SDavid Howells * Extract a piece of data from the received data socket buffers. 97308e0e7c8SDavid Howells */ 97412bdcf33SDavid Howells int afs_extract_data(struct afs_call *call, bool want_more) 97508e0e7c8SDavid Howells { 976f044c884SDavid Howells struct afs_net *net = call->net; 977fc276122SDavid Howells struct iov_iter *iter = call->iter; 97898bf40cdSDavid Howells enum afs_call_state state; 9797888da95SDan Carpenter u32 remote_abort = 0; 980d001648eSDavid Howells int ret; 98108e0e7c8SDavid Howells 98212bdcf33SDavid Howells _enter("{%s,%zu},%d", call->type->name, iov_iter_count(iter), want_more); 98308e0e7c8SDavid Howells 98412bdcf33SDavid Howells ret = rxrpc_kernel_recv_data(net->socket, call->rxcall, iter, 98598bf40cdSDavid Howells want_more, &remote_abort, 986a68f4a27SDavid Howells &call->service_id); 987d001648eSDavid Howells if (ret == 0 || ret == -EAGAIN) 988d001648eSDavid Howells return ret; 98908e0e7c8SDavid Howells 99098bf40cdSDavid Howells state = READ_ONCE(call->state); 991d001648eSDavid Howells if (ret == 1) { 99298bf40cdSDavid Howells switch (state) { 99398bf40cdSDavid Howells case AFS_CALL_CL_AWAIT_REPLY: 99498bf40cdSDavid Howells afs_set_call_state(call, state, AFS_CALL_CL_PROC_REPLY); 995d001648eSDavid Howells break; 99698bf40cdSDavid Howells case AFS_CALL_SV_AWAIT_REQUEST: 99798bf40cdSDavid Howells afs_set_call_state(call, state, AFS_CALL_SV_REPLYING); 998d001648eSDavid Howells break; 99998bf40cdSDavid Howells case AFS_CALL_COMPLETE: 100098bf40cdSDavid Howells kdebug("prem complete %d", call->error); 1001f51375cdSDavid Howells return afs_io_error(call, afs_io_error_extract); 1002d001648eSDavid Howells default: 1003d001648eSDavid Howells break; 100408e0e7c8SDavid Howells } 100508e0e7c8SDavid Howells return 0; 100608e0e7c8SDavid Howells } 1007d001648eSDavid Howells 100898bf40cdSDavid Howells afs_set_call_complete(call, ret, remote_abort); 1009d001648eSDavid Howells return ret; 1010d001648eSDavid Howells } 10115f702c8eSDavid Howells 10125f702c8eSDavid Howells /* 10135f702c8eSDavid Howells * Log protocol error production. 10145f702c8eSDavid Howells */ 1015160cb957SDavid Howells noinline int afs_protocol_error(struct afs_call *call, int error, 1016160cb957SDavid Howells enum afs_eproto_cause cause) 10175f702c8eSDavid Howells { 1018160cb957SDavid Howells trace_afs_protocol_error(call, error, cause); 10195f702c8eSDavid Howells return error; 10205f702c8eSDavid Howells } 1021