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"
1657af281eSDavid Howells #define RXRPC_TRACE_ONLY_DEFINE_ENUMS
1757af281eSDavid Howells #include <trace/events/rxrpc.h>
1808e0e7c8SDavid Howells
19f044c884SDavid Howells struct workqueue_struct *afs_async_calls;
2008e0e7c8SDavid Howells
21d001648eSDavid Howells static void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long);
22d001648eSDavid Howells static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long);
23d001648eSDavid Howells static void afs_process_async_call(struct work_struct *);
2400e90712SDavid Howells static void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long);
2500e90712SDavid Howells static void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long);
26d001648eSDavid Howells static int afs_deliver_cm_op_id(struct afs_call *);
2708e0e7c8SDavid Howells
2808e0e7c8SDavid Howells /* asynchronous incoming call initial processing */
2908e0e7c8SDavid Howells static const struct afs_call_type afs_RXCMxxxx = {
3000d3b7a4SDavid Howells .name = "CB.xxxx",
3108e0e7c8SDavid Howells .deliver = afs_deliver_cm_op_id,
3208e0e7c8SDavid Howells };
3308e0e7c8SDavid Howells
3408e0e7c8SDavid Howells /*
3508e0e7c8SDavid Howells * open an RxRPC socket and bind it to be a server for callback notifications
3608e0e7c8SDavid Howells * - the socket is left in blocking mode and non-blocking ops use MSG_DONTWAIT
3708e0e7c8SDavid Howells */
afs_open_socket(struct afs_net * net)38f044c884SDavid Howells int afs_open_socket(struct afs_net *net)
3908e0e7c8SDavid Howells {
4008e0e7c8SDavid Howells struct sockaddr_rxrpc srx;
4108e0e7c8SDavid Howells struct socket *socket;
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
61298cd88aSChristoph Hellwig ret = rxrpc_sock_set_min_security_level(socket->sk,
62298cd88aSChristoph Hellwig RXRPC_SECURITY_ENCRYPT);
634776cab4SDavid Howells if (ret < 0)
644776cab4SDavid Howells goto error_2;
654776cab4SDavid Howells
6608e0e7c8SDavid Howells ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx));
6783732ec5SMarc Dionne if (ret == -EADDRINUSE) {
6883732ec5SMarc Dionne srx.transport.sin6.sin6_port = 0;
6983732ec5SMarc Dionne ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx));
7083732ec5SMarc Dionne }
710e119b41SDavid Howells if (ret < 0)
720e119b41SDavid Howells goto error_2;
730e119b41SDavid Howells
7435dbfba3SDavid Howells srx.srx_service = YFS_CM_SERVICE;
7535dbfba3SDavid Howells ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx));
7635dbfba3SDavid Howells if (ret < 0)
7735dbfba3SDavid Howells goto error_2;
7835dbfba3SDavid Howells
793bf0fb6fSDavid Howells /* Ideally, we'd turn on service upgrade here, but we can't because
803bf0fb6fSDavid Howells * OpenAFS is buggy and leaks the userStatus field from packet to
813bf0fb6fSDavid Howells * packet and between FS packets and CB packets - so if we try to do an
823bf0fb6fSDavid Howells * upgrade on an FS packet, OpenAFS will leak that into the CB packet
833bf0fb6fSDavid Howells * it sends back to us.
843bf0fb6fSDavid Howells */
8535dbfba3SDavid Howells
8600e90712SDavid Howells rxrpc_kernel_new_call_notification(socket, afs_rx_new_call,
8700e90712SDavid Howells afs_rx_discard_new_call);
88d001648eSDavid Howells
890e119b41SDavid Howells ret = kernel_listen(socket, INT_MAX);
900e119b41SDavid Howells if (ret < 0)
910e119b41SDavid Howells goto error_2;
9208e0e7c8SDavid Howells
93f044c884SDavid Howells net->socket = socket;
94f044c884SDavid Howells afs_charge_preallocation(&net->charge_preallocation_work);
9508e0e7c8SDavid Howells _leave(" = 0");
9608e0e7c8SDavid Howells return 0;
970e119b41SDavid Howells
980e119b41SDavid Howells error_2:
990e119b41SDavid Howells sock_release(socket);
1000e119b41SDavid Howells error_1:
1010e119b41SDavid Howells _leave(" = %d", ret);
1020e119b41SDavid Howells return ret;
10308e0e7c8SDavid Howells }
10408e0e7c8SDavid Howells
10508e0e7c8SDavid Howells /*
10608e0e7c8SDavid Howells * close the RxRPC socket AFS was using
10708e0e7c8SDavid Howells */
afs_close_socket(struct afs_net * net)108f044c884SDavid Howells void afs_close_socket(struct afs_net *net)
10908e0e7c8SDavid Howells {
11008e0e7c8SDavid Howells _enter("");
11108e0e7c8SDavid Howells
112f044c884SDavid Howells kernel_listen(net->socket, 0);
113341f741fSDavid Howells flush_workqueue(afs_async_calls);
114341f741fSDavid Howells
115f044c884SDavid Howells if (net->spare_incoming_call) {
116f044c884SDavid Howells afs_put_call(net->spare_incoming_call);
117f044c884SDavid Howells net->spare_incoming_call = NULL;
11800e90712SDavid Howells }
11900e90712SDavid Howells
120f044c884SDavid Howells _debug("outstanding %u", atomic_read(&net->nr_outstanding_calls));
121ab1fbe32SPeter Zijlstra wait_var_event(&net->nr_outstanding_calls,
122ab1fbe32SPeter Zijlstra !atomic_read(&net->nr_outstanding_calls));
1232f02f7aeSDavid Howells _debug("no outstanding calls");
1242f02f7aeSDavid Howells
125f044c884SDavid Howells kernel_sock_shutdown(net->socket, SHUT_RDWR);
126248f219cSDavid Howells flush_workqueue(afs_async_calls);
127f044c884SDavid Howells sock_release(net->socket);
12808e0e7c8SDavid Howells
12908e0e7c8SDavid Howells _debug("dework");
13008e0e7c8SDavid Howells _leave("");
13108e0e7c8SDavid Howells }
13208e0e7c8SDavid Howells
13308e0e7c8SDavid Howells /*
134341f741fSDavid Howells * Allocate a call.
13500d3b7a4SDavid Howells */
afs_alloc_call(struct afs_net * net,const struct afs_call_type * type,gfp_t gfp)136f044c884SDavid Howells static struct afs_call *afs_alloc_call(struct afs_net *net,
137f044c884SDavid Howells const struct afs_call_type *type,
138341f741fSDavid Howells gfp_t gfp)
13900d3b7a4SDavid Howells {
140341f741fSDavid Howells struct afs_call *call;
141341f741fSDavid Howells int o;
14200d3b7a4SDavid Howells
143341f741fSDavid Howells call = kzalloc(sizeof(*call), gfp);
144341f741fSDavid Howells if (!call)
145341f741fSDavid Howells return NULL;
14600d3b7a4SDavid Howells
147341f741fSDavid Howells call->type = type;
148f044c884SDavid Howells call->net = net;
149a25e21f0SDavid Howells call->debug_id = atomic_inc_return(&rxrpc_debug_id);
150c56f9ec8SDavid Howells refcount_set(&call->ref, 1);
151341f741fSDavid Howells INIT_WORK(&call->async_work, afs_process_async_call);
152341f741fSDavid Howells init_waitqueue_head(&call->waitq);
15398bf40cdSDavid Howells spin_lock_init(&call->state_lock);
154fc276122SDavid Howells call->iter = &call->def_iter;
1552f02f7aeSDavid Howells
156f044c884SDavid Howells o = atomic_inc_return(&net->nr_outstanding_calls);
1572757a4dcSDavid Howells trace_afs_call(call->debug_id, 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 */
afs_put_call(struct afs_call * call)165341f741fSDavid Howells void afs_put_call(struct afs_call *call)
1666c67c7c3SDavid Howells {
167f044c884SDavid Howells struct afs_net *net = call->net;
1682757a4dcSDavid Howells unsigned int debug_id = call->debug_id;
169c56f9ec8SDavid Howells bool zero;
170c56f9ec8SDavid Howells int r, o;
171341f741fSDavid Howells
172c56f9ec8SDavid Howells zero = __refcount_dec_and_test(&call->ref, &r);
173c56f9ec8SDavid Howells o = atomic_read(&net->nr_outstanding_calls);
1742757a4dcSDavid Howells trace_afs_call(debug_id, afs_call_trace_put, r - 1, o,
175341f741fSDavid Howells __builtin_return_address(0));
176341f741fSDavid Howells
177c56f9ec8SDavid Howells if (zero) {
178341f741fSDavid Howells ASSERT(!work_pending(&call->async_work));
179341f741fSDavid Howells ASSERT(call->type->name != NULL);
180341f741fSDavid Howells
1816c67c7c3SDavid Howells if (call->rxcall) {
182e0416e7dSDavid Howells rxrpc_kernel_shutdown_call(net->socket, call->rxcall);
183e0416e7dSDavid Howells rxrpc_kernel_put_call(net->socket, call->rxcall);
1846c67c7c3SDavid Howells call->rxcall = NULL;
1856c67c7c3SDavid Howells }
1866cf12869SNathaniel Wesley Filardo if (call->type->destructor)
1876c67c7c3SDavid Howells call->type->destructor(call);
188341f741fSDavid Howells
189977e5f8eSDavid Howells afs_unuse_server_notime(call->net, call->server, afs_server_trace_put_call);
1903bf0fb6fSDavid Howells afs_put_addrlist(call->alist);
191341f741fSDavid Howells kfree(call->request);
192a25e21f0SDavid Howells
1932757a4dcSDavid Howells trace_afs_call(call->debug_id, afs_call_trace_free, 0, o,
194a25e21f0SDavid Howells __builtin_return_address(0));
195341f741fSDavid Howells kfree(call);
196341f741fSDavid Howells
197f044c884SDavid Howells o = atomic_dec_return(&net->nr_outstanding_calls);
198341f741fSDavid Howells if (o == 0)
199ab1fbe32SPeter Zijlstra wake_up_var(&net->nr_outstanding_calls);
200341f741fSDavid Howells }
2016cf12869SNathaniel Wesley Filardo }
2026cf12869SNathaniel Wesley Filardo
afs_get_call(struct afs_call * call,enum afs_call_trace why)2037a75b007SDavid Howells static struct afs_call *afs_get_call(struct afs_call *call,
2047a75b007SDavid Howells enum afs_call_trace why)
2057a75b007SDavid Howells {
206c56f9ec8SDavid Howells int r;
2077a75b007SDavid Howells
208c56f9ec8SDavid Howells __refcount_inc(&call->ref, &r);
209c56f9ec8SDavid Howells
2102757a4dcSDavid Howells trace_afs_call(call->debug_id, why, r + 1,
2117a75b007SDavid Howells atomic_read(&call->net->nr_outstanding_calls),
2127a75b007SDavid Howells __builtin_return_address(0));
2137a75b007SDavid Howells return call;
2147a75b007SDavid Howells }
2157a75b007SDavid Howells
2166cf12869SNathaniel Wesley Filardo /*
2173bf0fb6fSDavid Howells * Queue the call for actual work.
2186cf12869SNathaniel Wesley Filardo */
afs_queue_call_work(struct afs_call * call)2193bf0fb6fSDavid Howells static void afs_queue_call_work(struct afs_call *call)
2206cf12869SNathaniel Wesley Filardo {
2213bf0fb6fSDavid Howells if (call->type->work) {
222341f741fSDavid Howells INIT_WORK(&call->work, call->type->work);
223341f741fSDavid Howells
2247a75b007SDavid Howells afs_get_call(call, afs_call_trace_work);
225341f741fSDavid Howells if (!queue_work(afs_wq, &call->work))
226341f741fSDavid Howells afs_put_call(call);
2273bf0fb6fSDavid Howells }
2286c67c7c3SDavid Howells }
2296c67c7c3SDavid Howells
2306c67c7c3SDavid Howells /*
23108e0e7c8SDavid Howells * allocate a call with flat request and reply buffers
23208e0e7c8SDavid Howells */
afs_alloc_flat_call(struct afs_net * net,const struct afs_call_type * type,size_t request_size,size_t reply_max)233f044c884SDavid Howells struct afs_call *afs_alloc_flat_call(struct afs_net *net,
234f044c884SDavid Howells const struct afs_call_type *type,
235d001648eSDavid Howells size_t request_size, size_t reply_max)
23608e0e7c8SDavid Howells {
23708e0e7c8SDavid Howells struct afs_call *call;
23808e0e7c8SDavid Howells
239f044c884SDavid Howells call = afs_alloc_call(net, type, GFP_NOFS);
24008e0e7c8SDavid Howells if (!call)
24108e0e7c8SDavid Howells goto nomem_call;
24208e0e7c8SDavid Howells
24300d3b7a4SDavid Howells if (request_size) {
244341f741fSDavid Howells call->request_size = request_size;
24500d3b7a4SDavid Howells call->request = kmalloc(request_size, GFP_NOFS);
24600d3b7a4SDavid Howells if (!call->request)
24700d3b7a4SDavid Howells goto nomem_free;
24800d3b7a4SDavid Howells }
24900d3b7a4SDavid Howells
250d001648eSDavid Howells if (reply_max) {
251341f741fSDavid Howells call->reply_max = reply_max;
252d001648eSDavid Howells call->buffer = kmalloc(reply_max, GFP_NOFS);
25300d3b7a4SDavid Howells if (!call->buffer)
25400d3b7a4SDavid Howells goto nomem_free;
25500d3b7a4SDavid Howells }
25600d3b7a4SDavid Howells
25712bdcf33SDavid Howells afs_extract_to_buf(call, call->reply_max);
258025db80cSDavid Howells call->operation_ID = type->op;
25908e0e7c8SDavid Howells init_waitqueue_head(&call->waitq);
26008e0e7c8SDavid Howells return call;
26108e0e7c8SDavid Howells
26200d3b7a4SDavid Howells nomem_free:
263341f741fSDavid Howells afs_put_call(call);
26408e0e7c8SDavid Howells nomem_call:
26508e0e7c8SDavid Howells return NULL;
26608e0e7c8SDavid Howells }
26708e0e7c8SDavid Howells
26808e0e7c8SDavid Howells /*
26908e0e7c8SDavid Howells * clean up a call with flat buffer
27008e0e7c8SDavid Howells */
afs_flat_call_destructor(struct afs_call * call)27108e0e7c8SDavid Howells void afs_flat_call_destructor(struct afs_call *call)
27208e0e7c8SDavid Howells {
27308e0e7c8SDavid Howells _enter("");
27408e0e7c8SDavid Howells
27508e0e7c8SDavid Howells kfree(call->request);
27608e0e7c8SDavid Howells call->request = NULL;
27708e0e7c8SDavid Howells kfree(call->buffer);
27808e0e7c8SDavid Howells call->buffer = NULL;
27908e0e7c8SDavid Howells }
28008e0e7c8SDavid Howells
28108e0e7c8SDavid Howells /*
282e833251aSDavid Howells * Advance the AFS call state when the RxRPC call ends the transmit phase.
283e833251aSDavid Howells */
afs_notify_end_request_tx(struct sock * sock,struct rxrpc_call * rxcall,unsigned long call_user_ID)284e833251aSDavid Howells static void afs_notify_end_request_tx(struct sock *sock,
285e833251aSDavid Howells struct rxrpc_call *rxcall,
286e833251aSDavid Howells unsigned long call_user_ID)
287e833251aSDavid Howells {
288e833251aSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID;
289e833251aSDavid Howells
29098bf40cdSDavid Howells afs_set_call_state(call, AFS_CALL_CL_REQUESTING, AFS_CALL_CL_AWAIT_REPLY);
291e833251aSDavid Howells }
292e833251aSDavid Howells
293e833251aSDavid Howells /*
2940b9bf381SDavid Howells * Initiate a call and synchronously queue up the parameters for dispatch. Any
2950b9bf381SDavid Howells * error is stored into the call struct, which the caller must check for.
29608e0e7c8SDavid Howells */
afs_make_call(struct afs_addr_cursor * ac,struct afs_call * call,gfp_t gfp)2970b9bf381SDavid Howells void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
29808e0e7c8SDavid Howells {
2992feeaf84SDavid Howells struct sockaddr_rxrpc *srx = &ac->alist->addrs[ac->index];
30008e0e7c8SDavid Howells struct rxrpc_call *rxcall;
30108e0e7c8SDavid Howells struct msghdr msg;
30208e0e7c8SDavid Howells struct kvec iov[1];
303f105da1aSDavid Howells size_t len;
304e754eba6SDavid Howells s64 tx_total_len;
30508e0e7c8SDavid Howells int ret;
30608e0e7c8SDavid Howells
3074d9df986SDavid Howells _enter(",{%pISp},", &srx->transport);
30808e0e7c8SDavid Howells
30900d3b7a4SDavid Howells ASSERT(call->type != NULL);
31000d3b7a4SDavid Howells ASSERT(call->type->name != NULL);
31100d3b7a4SDavid Howells
31231143d5dSDavid Howells _debug("____MAKE %p{%s,%x} [%d]____",
31331143d5dSDavid Howells call, call->type->name, key_serial(call->key),
314f044c884SDavid Howells atomic_read(&call->net->nr_outstanding_calls));
31500d3b7a4SDavid Howells
3163bf0fb6fSDavid Howells call->addr_ix = ac->index;
3173bf0fb6fSDavid Howells call->alist = afs_get_addrlist(ac->alist);
31808e0e7c8SDavid Howells
319e754eba6SDavid Howells /* Work out the length we're going to transmit. This is awkward for
320e754eba6SDavid Howells * calls such as FS.StoreData where there's an extra injection of data
321e754eba6SDavid Howells * after the initial fixed part.
322e754eba6SDavid Howells */
323e754eba6SDavid Howells tx_total_len = call->request_size;
324bd80d8a8SDavid Howells if (call->write_iter)
325bd80d8a8SDavid Howells tx_total_len += iov_iter_count(call->write_iter);
326e754eba6SDavid Howells
32734fa4761SDavid Howells /* If the call is going to be asynchronous, we need an extra ref for
32834fa4761SDavid Howells * the call to hold itself so the caller need not hang on to its ref.
32934fa4761SDavid Howells */
330dde9f095SDavid Howells if (call->async) {
33134fa4761SDavid Howells afs_get_call(call, afs_call_trace_get);
332dde9f095SDavid Howells call->drop_ref = true;
333dde9f095SDavid Howells }
33434fa4761SDavid Howells
33508e0e7c8SDavid Howells /* create a call */
3364d9df986SDavid Howells rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key,
337e754eba6SDavid Howells (unsigned long)call,
338db099c62SDavid Howells tx_total_len,
339db099c62SDavid Howells call->max_lifespan,
340db099c62SDavid Howells gfp,
3410b9bf381SDavid Howells (call->async ?
34256ff9c83SDavid Howells afs_wake_up_async_call :
343a68f4a27SDavid Howells afs_wake_up_call_waiter),
344a25e21f0SDavid Howells call->upgrade,
345e138aa7dSDavid Howells (call->intr ? RXRPC_PREINTERRUPTIBLE :
346e138aa7dSDavid Howells RXRPC_UNINTERRUPTIBLE),
347a25e21f0SDavid Howells call->debug_id);
34808e0e7c8SDavid Howells if (IS_ERR(rxcall)) {
34908e0e7c8SDavid Howells ret = PTR_ERR(rxcall);
3503bf0fb6fSDavid Howells call->error = ret;
35108e0e7c8SDavid Howells goto error_kill_call;
35208e0e7c8SDavid Howells }
35308e0e7c8SDavid Howells
35408e0e7c8SDavid Howells call->rxcall = rxcall;
3557903192cSDavid Howells call->issue_time = ktime_get_real();
35694f699c9SDavid Howells
35708e0e7c8SDavid Howells /* send the request */
35808e0e7c8SDavid Howells iov[0].iov_base = call->request;
35908e0e7c8SDavid Howells iov[0].iov_len = call->request_size;
36008e0e7c8SDavid Howells
36108e0e7c8SDavid Howells msg.msg_name = NULL;
36208e0e7c8SDavid Howells msg.msg_namelen = 0;
363de4eda9dSAl Viro iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, 1, call->request_size);
36408e0e7c8SDavid Howells msg.msg_control = NULL;
36508e0e7c8SDavid Howells msg.msg_controllen = 0;
366bd80d8a8SDavid Howells msg.msg_flags = MSG_WAITALL | (call->write_iter ? MSG_MORE : 0);
36708e0e7c8SDavid Howells
368f044c884SDavid Howells ret = rxrpc_kernel_send_data(call->net->socket, rxcall,
369e833251aSDavid Howells &msg, call->request_size,
370e833251aSDavid Howells afs_notify_end_request_tx);
37108e0e7c8SDavid Howells if (ret < 0)
37208e0e7c8SDavid Howells goto error_do_abort;
37308e0e7c8SDavid Howells
374bd80d8a8SDavid Howells if (call->write_iter) {
375bd80d8a8SDavid Howells msg.msg_iter = *call->write_iter;
376bd80d8a8SDavid Howells msg.msg_flags &= ~MSG_MORE;
377bd80d8a8SDavid Howells trace_afs_send_data(call, &msg);
378bd80d8a8SDavid Howells
379bd80d8a8SDavid Howells ret = rxrpc_kernel_send_data(call->net->socket,
380bd80d8a8SDavid Howells call->rxcall, &msg,
381bd80d8a8SDavid Howells iov_iter_count(&msg.msg_iter),
382bd80d8a8SDavid Howells afs_notify_end_request_tx);
383bd80d8a8SDavid Howells *call->write_iter = msg.msg_iter;
384bd80d8a8SDavid Howells
385bd80d8a8SDavid Howells trace_afs_sent_data(call, &msg, ret);
38631143d5dSDavid Howells if (ret < 0)
38731143d5dSDavid Howells goto error_do_abort;
38831143d5dSDavid Howells }
38931143d5dSDavid Howells
39034fa4761SDavid Howells /* Note that at this point, we may have received the reply or an abort
39134fa4761SDavid Howells * - and an asynchronous call may already have completed.
3920b9bf381SDavid Howells *
3930b9bf381SDavid Howells * afs_wait_for_call_to_complete(call, ac)
3940b9bf381SDavid Howells * must be called to synchronously clean up.
39534fa4761SDavid Howells */
3960b9bf381SDavid Howells return;
39708e0e7c8SDavid Howells
39808e0e7c8SDavid Howells error_do_abort:
39970af0e3bSDavid Howells if (ret != -ECONNABORTED) {
400f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, rxcall,
40157af281eSDavid Howells RX_USER_ABORT, ret,
40257af281eSDavid Howells afs_abort_send_data_error);
40370af0e3bSDavid Howells } else {
404f105da1aSDavid Howells len = 0;
405de4eda9dSAl Viro iov_iter_kvec(&msg.msg_iter, ITER_DEST, NULL, 0, 0);
406eb9950ebSDavid Howells rxrpc_kernel_recv_data(call->net->socket, rxcall,
407f105da1aSDavid Howells &msg.msg_iter, &len, false,
408eb9950ebSDavid Howells &call->abort_code, &call->service_id);
409d2ddc776SDavid Howells ac->abort_code = call->abort_code;
410d2ddc776SDavid Howells ac->responded = true;
41170af0e3bSDavid Howells }
412025db80cSDavid Howells call->error = ret;
413025db80cSDavid Howells trace_afs_call_done(call);
41408e0e7c8SDavid Howells error_kill_call:
4153bf0fb6fSDavid Howells if (call->type->done)
4163bf0fb6fSDavid Howells call->type->done(call);
41734fa4761SDavid Howells
41834fa4761SDavid Howells /* We need to dispose of the extra ref we grabbed for an async call.
41934fa4761SDavid Howells * The call, however, might be queued on afs_async_calls and we need to
42034fa4761SDavid Howells * make sure we don't get any more notifications that might requeue it.
42134fa4761SDavid Howells */
422e0416e7dSDavid Howells if (call->rxcall)
423e0416e7dSDavid Howells rxrpc_kernel_shutdown_call(call->net->socket, call->rxcall);
42434fa4761SDavid Howells if (call->async) {
42534fa4761SDavid Howells if (cancel_work_sync(&call->async_work))
426341f741fSDavid Howells afs_put_call(call);
427*8715fe2fSDavid Howells afs_set_call_complete(call, ret, 0);
42834fa4761SDavid Howells }
42934fa4761SDavid Howells
430d2ddc776SDavid Howells ac->error = ret;
43134fa4761SDavid Howells call->state = AFS_CALL_COMPLETE;
43208e0e7c8SDavid Howells _leave(" = %d", ret);
43308e0e7c8SDavid Howells }
43408e0e7c8SDavid Howells
43508e0e7c8SDavid Howells /*
43605092755SDavid Howells * Log remote abort codes that indicate that we have a protocol disagreement
43705092755SDavid Howells * with the server.
43805092755SDavid Howells */
afs_log_error(struct afs_call * call,s32 remote_abort)43905092755SDavid Howells static void afs_log_error(struct afs_call *call, s32 remote_abort)
44005092755SDavid Howells {
44105092755SDavid Howells static int max = 0;
44205092755SDavid Howells const char *msg;
44305092755SDavid Howells int m;
44405092755SDavid Howells
44505092755SDavid Howells switch (remote_abort) {
44605092755SDavid Howells case RX_EOF: msg = "unexpected EOF"; break;
44705092755SDavid Howells case RXGEN_CC_MARSHAL: msg = "client marshalling"; break;
44805092755SDavid Howells case RXGEN_CC_UNMARSHAL: msg = "client unmarshalling"; break;
44905092755SDavid Howells case RXGEN_SS_MARSHAL: msg = "server marshalling"; break;
45005092755SDavid Howells case RXGEN_SS_UNMARSHAL: msg = "server unmarshalling"; break;
45105092755SDavid Howells case RXGEN_DECODE: msg = "opcode decode"; break;
45205092755SDavid Howells case RXGEN_SS_XDRFREE: msg = "server XDR cleanup"; break;
45305092755SDavid Howells case RXGEN_CC_XDRFREE: msg = "client XDR cleanup"; break;
45405092755SDavid Howells case -32: msg = "insufficient data"; break;
45505092755SDavid Howells default:
45605092755SDavid Howells return;
45705092755SDavid Howells }
45805092755SDavid Howells
45905092755SDavid Howells m = max;
46005092755SDavid Howells if (m < 3) {
46105092755SDavid Howells max = m + 1;
46205092755SDavid Howells pr_notice("kAFS: Peer reported %s failure on %s [%pISp]\n",
46305092755SDavid Howells msg, call->type->name,
46405092755SDavid Howells &call->alist->addrs[call->addr_ix].transport);
46505092755SDavid Howells }
46605092755SDavid Howells }
46705092755SDavid Howells
46805092755SDavid Howells /*
46908e0e7c8SDavid Howells * deliver messages to a call
47008e0e7c8SDavid Howells */
afs_deliver_to_call(struct afs_call * call)47108e0e7c8SDavid Howells static void afs_deliver_to_call(struct afs_call *call)
47208e0e7c8SDavid Howells {
47398bf40cdSDavid Howells enum afs_call_state state;
474f105da1aSDavid Howells size_t len;
47598bf40cdSDavid Howells u32 abort_code, remote_abort = 0;
47608e0e7c8SDavid Howells int ret;
47708e0e7c8SDavid Howells
478d001648eSDavid Howells _enter("%s", call->type->name);
47908e0e7c8SDavid Howells
48098bf40cdSDavid Howells while (state = READ_ONCE(call->state),
48198bf40cdSDavid Howells state == AFS_CALL_CL_AWAIT_REPLY ||
48298bf40cdSDavid Howells state == AFS_CALL_SV_AWAIT_OP_ID ||
48398bf40cdSDavid Howells state == AFS_CALL_SV_AWAIT_REQUEST ||
48498bf40cdSDavid Howells state == AFS_CALL_SV_AWAIT_ACK
485d001648eSDavid Howells ) {
48698bf40cdSDavid Howells if (state == AFS_CALL_SV_AWAIT_ACK) {
487f105da1aSDavid Howells len = 0;
488de4eda9dSAl Viro iov_iter_kvec(&call->def_iter, ITER_DEST, NULL, 0, 0);
489f044c884SDavid Howells ret = rxrpc_kernel_recv_data(call->net->socket,
490fc276122SDavid Howells call->rxcall, &call->def_iter,
491f105da1aSDavid Howells &len, false, &remote_abort,
492a68f4a27SDavid Howells &call->service_id);
493fc276122SDavid Howells trace_afs_receive_data(call, &call->def_iter, false, ret);
4948e8d7f13SDavid Howells
495d001648eSDavid Howells if (ret == -EINPROGRESS || ret == -EAGAIN)
496d001648eSDavid Howells return;
49798bf40cdSDavid Howells if (ret < 0 || ret == 1) {
49898bf40cdSDavid Howells if (ret == 1)
49998bf40cdSDavid Howells ret = 0;
500025db80cSDavid Howells goto call_complete;
50198bf40cdSDavid Howells }
502d001648eSDavid Howells return;
503d001648eSDavid Howells }
504d001648eSDavid Howells
505d001648eSDavid Howells ret = call->type->deliver(call);
50698bf40cdSDavid Howells state = READ_ONCE(call->state);
50738355eecSDavid Howells if (ret == 0 && call->unmarshalling_error)
50838355eecSDavid Howells ret = -EBADMSG;
509d001648eSDavid Howells switch (ret) {
51008e0e7c8SDavid Howells case 0:
5113bf0fb6fSDavid Howells afs_queue_call_work(call);
512f2686b09SDavid Howells if (state == AFS_CALL_CL_PROC_REPLY) {
51320325960SDavid Howells if (call->op)
514f2686b09SDavid Howells set_bit(AFS_SERVER_FL_MAY_HAVE_CB,
51520325960SDavid Howells &call->op->server->flags);
516025db80cSDavid Howells goto call_complete;
517f2686b09SDavid Howells }
51898bf40cdSDavid Howells ASSERTCMP(state, >, AFS_CALL_CL_PROC_REPLY);
519d001648eSDavid Howells goto done;
520d001648eSDavid Howells case -EINPROGRESS:
521d001648eSDavid Howells case -EAGAIN:
522d001648eSDavid Howells goto out;
52370af0e3bSDavid Howells case -ECONNABORTED:
52498bf40cdSDavid Howells ASSERTCMP(state, ==, AFS_CALL_COMPLETE);
52505092755SDavid Howells afs_log_error(call, call->abort_code);
52698bf40cdSDavid Howells goto done;
52708e0e7c8SDavid Howells case -ENOTSUPP:
5281157f153SDavid Howells abort_code = RXGEN_OPCODE;
529f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
53057af281eSDavid Howells abort_code, ret,
53157af281eSDavid Howells afs_abort_op_not_supported);
53298bf40cdSDavid Howells goto local_abort;
5334ac15ea5SDavid Howells case -EIO:
5344ac15ea5SDavid Howells pr_err("kAFS: Call %u in bad state %u\n",
5354ac15ea5SDavid Howells call->debug_id, state);
536df561f66SGustavo A. R. Silva fallthrough;
537d001648eSDavid Howells case -ENODATA:
538d001648eSDavid Howells case -EBADMSG:
539d001648eSDavid Howells case -EMSGSIZE:
540de696c47SDavid Howells case -ENOMEM:
541de696c47SDavid Howells case -EFAULT:
54208e0e7c8SDavid Howells abort_code = RXGEN_CC_UNMARSHAL;
54398bf40cdSDavid Howells if (state != AFS_CALL_CL_AWAIT_REPLY)
54408e0e7c8SDavid Howells abort_code = RXGEN_SS_UNMARSHAL;
545f044c884SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
54657af281eSDavid Howells abort_code, ret,
54757af281eSDavid Howells afs_abort_unmarshal_error);
54898bf40cdSDavid Howells goto local_abort;
5498022c4b9SDavid Howells default:
550de696c47SDavid Howells abort_code = RX_CALL_DEAD;
5518022c4b9SDavid Howells rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
55257af281eSDavid Howells abort_code, ret,
55357af281eSDavid Howells afs_abort_general_error);
5548022c4b9SDavid Howells goto local_abort;
55508e0e7c8SDavid Howells }
55608e0e7c8SDavid Howells }
55708e0e7c8SDavid Howells
558d001648eSDavid Howells done:
5593bf0fb6fSDavid Howells if (call->type->done)
5603bf0fb6fSDavid Howells call->type->done(call);
561d001648eSDavid Howells out:
56208e0e7c8SDavid Howells _leave("");
563d001648eSDavid Howells return;
564d001648eSDavid Howells
56598bf40cdSDavid Howells local_abort:
56698bf40cdSDavid Howells abort_code = 0;
567025db80cSDavid Howells call_complete:
56898bf40cdSDavid Howells afs_set_call_complete(call, ret, remote_abort);
56998bf40cdSDavid Howells state = AFS_CALL_COMPLETE;
570d001648eSDavid Howells goto done;
57108e0e7c8SDavid Howells }
57208e0e7c8SDavid Howells
57308e0e7c8SDavid Howells /*
5740b9bf381SDavid Howells * Wait synchronously for a call to complete and clean up the call struct.
57508e0e7c8SDavid Howells */
afs_wait_for_call_to_complete(struct afs_call * call,struct afs_addr_cursor * ac)5760b9bf381SDavid Howells long afs_wait_for_call_to_complete(struct afs_call *call,
577d2ddc776SDavid Howells struct afs_addr_cursor *ac)
57808e0e7c8SDavid Howells {
57933cd7f2bSDavid Howells long ret;
580f7f1dd31SMarc Dionne bool rxrpc_complete = false;
58108e0e7c8SDavid Howells
58208e0e7c8SDavid Howells DECLARE_WAITQUEUE(myself, current);
58308e0e7c8SDavid Howells
58408e0e7c8SDavid Howells _enter("");
58508e0e7c8SDavid Howells
5860b9bf381SDavid Howells ret = call->error;
5870b9bf381SDavid Howells if (ret < 0)
5880b9bf381SDavid Howells goto out;
5890b9bf381SDavid Howells
59008e0e7c8SDavid Howells add_wait_queue(&call->waitq, &myself);
59108e0e7c8SDavid Howells for (;;) {
592bc5e3a54SDavid Howells set_current_state(TASK_UNINTERRUPTIBLE);
59308e0e7c8SDavid Howells
59408e0e7c8SDavid Howells /* deliver any messages that are in the queue */
59598bf40cdSDavid Howells if (!afs_check_call_state(call, AFS_CALL_COMPLETE) &&
59698bf40cdSDavid Howells call->need_attention) {
597d001648eSDavid Howells call->need_attention = false;
59808e0e7c8SDavid Howells __set_current_state(TASK_RUNNING);
59908e0e7c8SDavid Howells afs_deliver_to_call(call);
60008e0e7c8SDavid Howells continue;
60108e0e7c8SDavid Howells }
60208e0e7c8SDavid Howells
60398bf40cdSDavid Howells if (afs_check_call_state(call, AFS_CALL_COMPLETE))
60408e0e7c8SDavid Howells break;
605bc5e3a54SDavid Howells
6067d7587dbSDavid Howells if (!rxrpc_kernel_check_life(call->net->socket, call->rxcall)) {
607f7f1dd31SMarc Dionne /* rxrpc terminated the call. */
608f7f1dd31SMarc Dionne rxrpc_complete = true;
609f7f1dd31SMarc Dionne break;
610f7f1dd31SMarc Dionne }
611f7f1dd31SMarc Dionne
6127d7587dbSDavid Howells schedule();
61308e0e7c8SDavid Howells }
61408e0e7c8SDavid Howells
61508e0e7c8SDavid Howells remove_wait_queue(&call->waitq, &myself);
61608e0e7c8SDavid Howells __set_current_state(TASK_RUNNING);
61708e0e7c8SDavid Howells
61898bf40cdSDavid Howells if (!afs_check_call_state(call, AFS_CALL_COMPLETE)) {
619f7f1dd31SMarc Dionne if (rxrpc_complete) {
620f7f1dd31SMarc Dionne afs_set_call_complete(call, call->error, call->abort_code);
621f7f1dd31SMarc Dionne } else {
622f7f1dd31SMarc Dionne /* Kill off the call if it's still live. */
623954cd6dcSDavid Howells _debug("call interrupted");
624d2ddc776SDavid Howells if (rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
62557af281eSDavid Howells RX_USER_ABORT, -EINTR,
62657af281eSDavid Howells afs_abort_interrupted))
62798bf40cdSDavid Howells afs_set_call_complete(call, -EINTR, 0);
62808e0e7c8SDavid Howells }
629f7f1dd31SMarc Dionne }
63008e0e7c8SDavid Howells
63198bf40cdSDavid Howells spin_lock_bh(&call->state_lock);
632d2ddc776SDavid Howells ac->abort_code = call->abort_code;
633d2ddc776SDavid Howells ac->error = call->error;
63498bf40cdSDavid Howells spin_unlock_bh(&call->state_lock);
635d2ddc776SDavid Howells
636d2ddc776SDavid Howells ret = ac->error;
637d2ddc776SDavid Howells switch (ret) {
638d2ddc776SDavid Howells case 0:
639ffba718eSDavid Howells ret = call->ret0;
640ffba718eSDavid Howells call->ret0 = 0;
641ffba718eSDavid Howells
642df561f66SGustavo A. R. Silva fallthrough;
643d2ddc776SDavid Howells case -ECONNABORTED:
644d2ddc776SDavid Howells ac->responded = true;
645d2ddc776SDavid Howells break;
646d2ddc776SDavid Howells }
64733cd7f2bSDavid Howells
6480b9bf381SDavid Howells out:
64908e0e7c8SDavid Howells _debug("call complete");
650341f741fSDavid Howells afs_put_call(call);
65133cd7f2bSDavid Howells _leave(" = %p", (void *)ret);
65208e0e7c8SDavid Howells return ret;
65308e0e7c8SDavid Howells }
65408e0e7c8SDavid Howells
65508e0e7c8SDavid Howells /*
65608e0e7c8SDavid Howells * wake up a waiting call
65708e0e7c8SDavid Howells */
afs_wake_up_call_waiter(struct sock * sk,struct rxrpc_call * rxcall,unsigned long call_user_ID)658d001648eSDavid Howells static void afs_wake_up_call_waiter(struct sock *sk, struct rxrpc_call *rxcall,
659d001648eSDavid Howells unsigned long call_user_ID)
66008e0e7c8SDavid Howells {
661d001648eSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID;
662d001648eSDavid Howells
663d001648eSDavid Howells call->need_attention = true;
66408e0e7c8SDavid Howells wake_up(&call->waitq);
66508e0e7c8SDavid Howells }
66608e0e7c8SDavid Howells
66708e0e7c8SDavid Howells /*
66808e0e7c8SDavid Howells * wake up an asynchronous call
66908e0e7c8SDavid Howells */
afs_wake_up_async_call(struct sock * sk,struct rxrpc_call * rxcall,unsigned long call_user_ID)670d001648eSDavid Howells static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall,
671d001648eSDavid Howells unsigned long call_user_ID)
67208e0e7c8SDavid Howells {
673d001648eSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID;
674c56f9ec8SDavid Howells int r;
675d001648eSDavid Howells
6768e8d7f13SDavid Howells trace_afs_notify_call(rxcall, call);
677d001648eSDavid Howells call->need_attention = true;
678341f741fSDavid Howells
679c56f9ec8SDavid Howells if (__refcount_inc_not_zero(&call->ref, &r)) {
6802757a4dcSDavid Howells trace_afs_call(call->debug_id, afs_call_trace_wake, r + 1,
681f044c884SDavid Howells atomic_read(&call->net->nr_outstanding_calls),
682341f741fSDavid Howells __builtin_return_address(0));
683341f741fSDavid Howells
684341f741fSDavid Howells if (!queue_work(afs_async_calls, &call->async_work))
685341f741fSDavid Howells afs_put_call(call);
686341f741fSDavid Howells }
68708e0e7c8SDavid Howells }
68808e0e7c8SDavid Howells
68908e0e7c8SDavid Howells /*
690341f741fSDavid Howells * Perform I/O processing on an asynchronous call. The work item carries a ref
691341f741fSDavid Howells * to the call struct that we either need to release or to pass on.
69208e0e7c8SDavid Howells */
afs_process_async_call(struct work_struct * work)693d001648eSDavid Howells static void afs_process_async_call(struct work_struct *work)
69408e0e7c8SDavid Howells {
695d001648eSDavid Howells struct afs_call *call = container_of(work, struct afs_call, async_work);
696d001648eSDavid Howells
69708e0e7c8SDavid Howells _enter("");
69808e0e7c8SDavid Howells
699d001648eSDavid Howells if (call->state < AFS_CALL_COMPLETE && call->need_attention) {
700d001648eSDavid Howells call->need_attention = false;
70108e0e7c8SDavid Howells afs_deliver_to_call(call);
702d001648eSDavid Howells }
70308e0e7c8SDavid Howells
704341f741fSDavid Howells afs_put_call(call);
70508e0e7c8SDavid Howells _leave("");
70608e0e7c8SDavid Howells }
70708e0e7c8SDavid Howells
afs_rx_attach(struct rxrpc_call * rxcall,unsigned long user_call_ID)70800e90712SDavid Howells static void afs_rx_attach(struct rxrpc_call *rxcall, unsigned long user_call_ID)
70900e90712SDavid Howells {
71000e90712SDavid Howells struct afs_call *call = (struct afs_call *)user_call_ID;
71100e90712SDavid Howells
71200e90712SDavid Howells call->rxcall = rxcall;
71300e90712SDavid Howells }
71400e90712SDavid Howells
71500e90712SDavid Howells /*
71600e90712SDavid Howells * Charge the incoming call preallocation.
71700e90712SDavid Howells */
afs_charge_preallocation(struct work_struct * work)718f044c884SDavid Howells void afs_charge_preallocation(struct work_struct *work)
71900e90712SDavid Howells {
720f044c884SDavid Howells struct afs_net *net =
721f044c884SDavid Howells container_of(work, struct afs_net, charge_preallocation_work);
722f044c884SDavid Howells struct afs_call *call = net->spare_incoming_call;
72300e90712SDavid Howells
72400e90712SDavid Howells for (;;) {
72500e90712SDavid Howells if (!call) {
726f044c884SDavid Howells call = afs_alloc_call(net, &afs_RXCMxxxx, GFP_KERNEL);
72700e90712SDavid Howells if (!call)
72800e90712SDavid Howells break;
72900e90712SDavid Howells
730dde9f095SDavid Howells call->drop_ref = true;
73156ff9c83SDavid Howells call->async = true;
73298bf40cdSDavid Howells call->state = AFS_CALL_SV_AWAIT_OP_ID;
73356ff9c83SDavid Howells init_waitqueue_head(&call->waitq);
73412bdcf33SDavid Howells afs_extract_to_tmp(call);
73500e90712SDavid Howells }
73600e90712SDavid Howells
737f044c884SDavid Howells if (rxrpc_kernel_charge_accept(net->socket,
73800e90712SDavid Howells afs_wake_up_async_call,
73900e90712SDavid Howells afs_rx_attach,
74000e90712SDavid Howells (unsigned long)call,
741a25e21f0SDavid Howells GFP_KERNEL,
742a25e21f0SDavid Howells call->debug_id) < 0)
74300e90712SDavid Howells break;
74400e90712SDavid Howells call = NULL;
74500e90712SDavid Howells }
746f044c884SDavid Howells net->spare_incoming_call = call;
74700e90712SDavid Howells }
74800e90712SDavid Howells
74900e90712SDavid Howells /*
75000e90712SDavid Howells * Discard a preallocated call when a socket is shut down.
75100e90712SDavid Howells */
afs_rx_discard_new_call(struct rxrpc_call * rxcall,unsigned long user_call_ID)75200e90712SDavid Howells static void afs_rx_discard_new_call(struct rxrpc_call *rxcall,
75300e90712SDavid Howells unsigned long user_call_ID)
75400e90712SDavid Howells {
75500e90712SDavid Howells struct afs_call *call = (struct afs_call *)user_call_ID;
75600e90712SDavid Howells
75700e90712SDavid Howells call->rxcall = NULL;
758341f741fSDavid Howells afs_put_call(call);
75900e90712SDavid Howells }
76000e90712SDavid Howells
76108e0e7c8SDavid Howells /*
762d001648eSDavid Howells * Notification of an incoming call.
763d001648eSDavid Howells */
afs_rx_new_call(struct sock * sk,struct rxrpc_call * rxcall,unsigned long user_call_ID)76400e90712SDavid Howells static void afs_rx_new_call(struct sock *sk, struct rxrpc_call *rxcall,
76500e90712SDavid Howells unsigned long user_call_ID)
766d001648eSDavid Howells {
767f044c884SDavid Howells struct afs_net *net = afs_sock2net(sk);
768f044c884SDavid Howells
769f044c884SDavid Howells queue_work(afs_wq, &net->charge_preallocation_work);
770d001648eSDavid Howells }
771d001648eSDavid Howells
772d001648eSDavid Howells /*
773372ee163SDavid Howells * Grab the operation ID from an incoming cache manager call. The socket
774372ee163SDavid Howells * buffer is discarded on error or if we don't yet have sufficient data.
77508e0e7c8SDavid Howells */
afs_deliver_cm_op_id(struct afs_call * call)776d001648eSDavid Howells static int afs_deliver_cm_op_id(struct afs_call *call)
77708e0e7c8SDavid Howells {
778d001648eSDavid Howells int ret;
77908e0e7c8SDavid Howells
780fc276122SDavid Howells _enter("{%zu}", iov_iter_count(call->iter));
78108e0e7c8SDavid Howells
78208e0e7c8SDavid Howells /* the operation ID forms the first four bytes of the request data */
78312bdcf33SDavid Howells ret = afs_extract_data(call, true);
784d001648eSDavid Howells if (ret < 0)
785d001648eSDavid Howells return ret;
78608e0e7c8SDavid Howells
78750a2c953SDavid Howells call->operation_ID = ntohl(call->tmp);
78898bf40cdSDavid Howells afs_set_call_state(call, AFS_CALL_SV_AWAIT_OP_ID, AFS_CALL_SV_AWAIT_REQUEST);
78908e0e7c8SDavid Howells
79008e0e7c8SDavid Howells /* ask the cache manager to route the call (it'll change the call type
79108e0e7c8SDavid Howells * if successful) */
79208e0e7c8SDavid Howells if (!afs_cm_incoming_call(call))
79308e0e7c8SDavid Howells return -ENOTSUPP;
79408e0e7c8SDavid Howells
7958e8d7f13SDavid Howells trace_afs_cb_call(call);
7968e8d7f13SDavid Howells
79708e0e7c8SDavid Howells /* pass responsibility for the remainer of this message off to the
79808e0e7c8SDavid Howells * cache manager op */
799d001648eSDavid Howells return call->type->deliver(call);
80008e0e7c8SDavid Howells }
80108e0e7c8SDavid Howells
80208e0e7c8SDavid Howells /*
803e833251aSDavid Howells * Advance the AFS call state when an RxRPC service call ends the transmit
804e833251aSDavid Howells * phase.
805e833251aSDavid Howells */
afs_notify_end_reply_tx(struct sock * sock,struct rxrpc_call * rxcall,unsigned long call_user_ID)806e833251aSDavid Howells static void afs_notify_end_reply_tx(struct sock *sock,
807e833251aSDavid Howells struct rxrpc_call *rxcall,
808e833251aSDavid Howells unsigned long call_user_ID)
809e833251aSDavid Howells {
810e833251aSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID;
811e833251aSDavid Howells
81298bf40cdSDavid Howells afs_set_call_state(call, AFS_CALL_SV_REPLYING, AFS_CALL_SV_AWAIT_ACK);
813e833251aSDavid Howells }
814e833251aSDavid Howells
815e833251aSDavid Howells /*
81608e0e7c8SDavid Howells * send an empty reply
81708e0e7c8SDavid Howells */
afs_send_empty_reply(struct afs_call * call)81808e0e7c8SDavid Howells void afs_send_empty_reply(struct afs_call *call)
81908e0e7c8SDavid Howells {
820f044c884SDavid Howells struct afs_net *net = call->net;
82108e0e7c8SDavid Howells struct msghdr msg;
82208e0e7c8SDavid Howells
82308e0e7c8SDavid Howells _enter("");
82408e0e7c8SDavid Howells
825f044c884SDavid Howells rxrpc_kernel_set_tx_length(net->socket, call->rxcall, 0);
826e754eba6SDavid Howells
82708e0e7c8SDavid Howells msg.msg_name = NULL;
82808e0e7c8SDavid Howells msg.msg_namelen = 0;
829de4eda9dSAl Viro iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, NULL, 0, 0);
83008e0e7c8SDavid Howells msg.msg_control = NULL;
83108e0e7c8SDavid Howells msg.msg_controllen = 0;
83208e0e7c8SDavid Howells msg.msg_flags = 0;
83308e0e7c8SDavid Howells
834f044c884SDavid Howells switch (rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, 0,
835e833251aSDavid Howells afs_notify_end_reply_tx)) {
83608e0e7c8SDavid Howells case 0:
83708e0e7c8SDavid Howells _leave(" [replied]");
83808e0e7c8SDavid Howells return;
83908e0e7c8SDavid Howells
84008e0e7c8SDavid Howells case -ENOMEM:
84108e0e7c8SDavid Howells _debug("oom");
842f044c884SDavid Howells rxrpc_kernel_abort_call(net->socket, call->rxcall,
84357af281eSDavid Howells RXGEN_SS_MARSHAL, -ENOMEM,
84457af281eSDavid Howells afs_abort_oom);
845df561f66SGustavo A. R. Silva fallthrough;
84608e0e7c8SDavid Howells default:
84708e0e7c8SDavid Howells _leave(" [error]");
84808e0e7c8SDavid Howells return;
84908e0e7c8SDavid Howells }
85008e0e7c8SDavid Howells }
85108e0e7c8SDavid Howells
85208e0e7c8SDavid Howells /*
853b908fe6bSDavid Howells * send a simple reply
854b908fe6bSDavid Howells */
afs_send_simple_reply(struct afs_call * call,const void * buf,size_t len)855b908fe6bSDavid Howells void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
856b908fe6bSDavid Howells {
857f044c884SDavid Howells struct afs_net *net = call->net;
858b908fe6bSDavid Howells struct msghdr msg;
8592e90b1c4SAl Viro struct kvec iov[1];
860bd6dc742SDavid Howells int n;
861b908fe6bSDavid Howells
862b908fe6bSDavid Howells _enter("");
863b908fe6bSDavid Howells
864f044c884SDavid Howells rxrpc_kernel_set_tx_length(net->socket, call->rxcall, len);
865e754eba6SDavid Howells
866b908fe6bSDavid Howells iov[0].iov_base = (void *) buf;
867b908fe6bSDavid Howells iov[0].iov_len = len;
868b908fe6bSDavid Howells msg.msg_name = NULL;
869b908fe6bSDavid Howells msg.msg_namelen = 0;
870de4eda9dSAl Viro iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, 1, len);
871b908fe6bSDavid Howells msg.msg_control = NULL;
872b908fe6bSDavid Howells msg.msg_controllen = 0;
873b908fe6bSDavid Howells msg.msg_flags = 0;
874b908fe6bSDavid Howells
875f044c884SDavid Howells n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, len,
876e833251aSDavid Howells afs_notify_end_reply_tx);
877bd6dc742SDavid Howells if (n >= 0) {
8786c67c7c3SDavid Howells /* Success */
879b908fe6bSDavid Howells _leave(" [replied]");
880b908fe6bSDavid Howells return;
881bd6dc742SDavid Howells }
8826c67c7c3SDavid Howells
883bd6dc742SDavid Howells if (n == -ENOMEM) {
884b908fe6bSDavid Howells _debug("oom");
885f044c884SDavid Howells rxrpc_kernel_abort_call(net->socket, call->rxcall,
88657af281eSDavid Howells RXGEN_SS_MARSHAL, -ENOMEM,
88757af281eSDavid Howells afs_abort_oom);
888bd6dc742SDavid Howells }
889b908fe6bSDavid Howells _leave(" [error]");
890b908fe6bSDavid Howells }
891b908fe6bSDavid Howells
892b908fe6bSDavid Howells /*
893372ee163SDavid Howells * Extract a piece of data from the received data socket buffers.
89408e0e7c8SDavid Howells */
afs_extract_data(struct afs_call * call,bool want_more)89512bdcf33SDavid Howells int afs_extract_data(struct afs_call *call, bool want_more)
89608e0e7c8SDavid Howells {
897f044c884SDavid Howells struct afs_net *net = call->net;
898fc276122SDavid Howells struct iov_iter *iter = call->iter;
89998bf40cdSDavid Howells enum afs_call_state state;
9007888da95SDan Carpenter u32 remote_abort = 0;
901d001648eSDavid Howells int ret;
90208e0e7c8SDavid Howells
903f105da1aSDavid Howells _enter("{%s,%zu,%zu},%d",
904f105da1aSDavid Howells call->type->name, call->iov_len, iov_iter_count(iter), want_more);
90508e0e7c8SDavid Howells
90612bdcf33SDavid Howells ret = rxrpc_kernel_recv_data(net->socket, call->rxcall, iter,
907f105da1aSDavid Howells &call->iov_len, want_more, &remote_abort,
908a68f4a27SDavid Howells &call->service_id);
90993368b6bSDavid Howells trace_afs_receive_data(call, call->iter, want_more, ret);
910d001648eSDavid Howells if (ret == 0 || ret == -EAGAIN)
911d001648eSDavid Howells return ret;
91208e0e7c8SDavid Howells
91398bf40cdSDavid Howells state = READ_ONCE(call->state);
914d001648eSDavid Howells if (ret == 1) {
91598bf40cdSDavid Howells switch (state) {
91698bf40cdSDavid Howells case AFS_CALL_CL_AWAIT_REPLY:
91798bf40cdSDavid Howells afs_set_call_state(call, state, AFS_CALL_CL_PROC_REPLY);
918d001648eSDavid Howells break;
91998bf40cdSDavid Howells case AFS_CALL_SV_AWAIT_REQUEST:
92098bf40cdSDavid Howells afs_set_call_state(call, state, AFS_CALL_SV_REPLYING);
921d001648eSDavid Howells break;
92298bf40cdSDavid Howells case AFS_CALL_COMPLETE:
92398bf40cdSDavid Howells kdebug("prem complete %d", call->error);
924f51375cdSDavid Howells return afs_io_error(call, afs_io_error_extract);
925d001648eSDavid Howells default:
926d001648eSDavid Howells break;
92708e0e7c8SDavid Howells }
92808e0e7c8SDavid Howells return 0;
92908e0e7c8SDavid Howells }
930d001648eSDavid Howells
93198bf40cdSDavid Howells afs_set_call_complete(call, ret, remote_abort);
932d001648eSDavid Howells return ret;
933d001648eSDavid Howells }
9345f702c8eSDavid Howells
9355f702c8eSDavid Howells /*
9365f702c8eSDavid Howells * Log protocol error production.
9375f702c8eSDavid Howells */
afs_protocol_error(struct afs_call * call,enum afs_eproto_cause cause)9387126ead9SDavid Howells noinline int afs_protocol_error(struct afs_call *call,
939160cb957SDavid Howells enum afs_eproto_cause cause)
9405f702c8eSDavid Howells {
9417126ead9SDavid Howells trace_afs_protocol_error(call, cause);
94238355eecSDavid Howells if (call)
94338355eecSDavid Howells call->unmarshalling_error = true;
9447126ead9SDavid Howells return -EBADMSG;
9455f702c8eSDavid Howells }
946