162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* Maintain an RxRPC server socket to do AFS communications through 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include <linux/sched/signal.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <net/sock.h> 1262306a36Sopenharmony_ci#include <net/af_rxrpc.h> 1362306a36Sopenharmony_ci#include "internal.h" 1462306a36Sopenharmony_ci#include "afs_cm.h" 1562306a36Sopenharmony_ci#include "protocol_yfs.h" 1662306a36Sopenharmony_ci#define RXRPC_TRACE_ONLY_DEFINE_ENUMS 1762306a36Sopenharmony_ci#include <trace/events/rxrpc.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistruct workqueue_struct *afs_async_calls; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long); 2262306a36Sopenharmony_cistatic void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long); 2362306a36Sopenharmony_cistatic void afs_process_async_call(struct work_struct *); 2462306a36Sopenharmony_cistatic void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long); 2562306a36Sopenharmony_cistatic void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long); 2662306a36Sopenharmony_cistatic int afs_deliver_cm_op_id(struct afs_call *); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* asynchronous incoming call initial processing */ 2962306a36Sopenharmony_cistatic const struct afs_call_type afs_RXCMxxxx = { 3062306a36Sopenharmony_ci .name = "CB.xxxx", 3162306a36Sopenharmony_ci .deliver = afs_deliver_cm_op_id, 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci * open an RxRPC socket and bind it to be a server for callback notifications 3662306a36Sopenharmony_ci * - the socket is left in blocking mode and non-blocking ops use MSG_DONTWAIT 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ciint afs_open_socket(struct afs_net *net) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct sockaddr_rxrpc srx; 4162306a36Sopenharmony_ci struct socket *socket; 4262306a36Sopenharmony_ci int ret; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci _enter(""); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci ret = sock_create_kern(net->net, AF_RXRPC, SOCK_DGRAM, PF_INET6, &socket); 4762306a36Sopenharmony_ci if (ret < 0) 4862306a36Sopenharmony_ci goto error_1; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci socket->sk->sk_allocation = GFP_NOFS; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci /* bind the callback manager's address to make this a server socket */ 5362306a36Sopenharmony_ci memset(&srx, 0, sizeof(srx)); 5462306a36Sopenharmony_ci srx.srx_family = AF_RXRPC; 5562306a36Sopenharmony_ci srx.srx_service = CM_SERVICE; 5662306a36Sopenharmony_ci srx.transport_type = SOCK_DGRAM; 5762306a36Sopenharmony_ci srx.transport_len = sizeof(srx.transport.sin6); 5862306a36Sopenharmony_ci srx.transport.sin6.sin6_family = AF_INET6; 5962306a36Sopenharmony_ci srx.transport.sin6.sin6_port = htons(AFS_CM_PORT); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci ret = rxrpc_sock_set_min_security_level(socket->sk, 6262306a36Sopenharmony_ci RXRPC_SECURITY_ENCRYPT); 6362306a36Sopenharmony_ci if (ret < 0) 6462306a36Sopenharmony_ci goto error_2; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); 6762306a36Sopenharmony_ci if (ret == -EADDRINUSE) { 6862306a36Sopenharmony_ci srx.transport.sin6.sin6_port = 0; 6962306a36Sopenharmony_ci ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci if (ret < 0) 7262306a36Sopenharmony_ci goto error_2; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci srx.srx_service = YFS_CM_SERVICE; 7562306a36Sopenharmony_ci ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); 7662306a36Sopenharmony_ci if (ret < 0) 7762306a36Sopenharmony_ci goto error_2; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* Ideally, we'd turn on service upgrade here, but we can't because 8062306a36Sopenharmony_ci * OpenAFS is buggy and leaks the userStatus field from packet to 8162306a36Sopenharmony_ci * packet and between FS packets and CB packets - so if we try to do an 8262306a36Sopenharmony_ci * upgrade on an FS packet, OpenAFS will leak that into the CB packet 8362306a36Sopenharmony_ci * it sends back to us. 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci rxrpc_kernel_new_call_notification(socket, afs_rx_new_call, 8762306a36Sopenharmony_ci afs_rx_discard_new_call); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci ret = kernel_listen(socket, INT_MAX); 9062306a36Sopenharmony_ci if (ret < 0) 9162306a36Sopenharmony_ci goto error_2; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci net->socket = socket; 9462306a36Sopenharmony_ci afs_charge_preallocation(&net->charge_preallocation_work); 9562306a36Sopenharmony_ci _leave(" = 0"); 9662306a36Sopenharmony_ci return 0; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cierror_2: 9962306a36Sopenharmony_ci sock_release(socket); 10062306a36Sopenharmony_cierror_1: 10162306a36Sopenharmony_ci _leave(" = %d", ret); 10262306a36Sopenharmony_ci return ret; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* 10662306a36Sopenharmony_ci * close the RxRPC socket AFS was using 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_civoid afs_close_socket(struct afs_net *net) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci _enter(""); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci kernel_listen(net->socket, 0); 11362306a36Sopenharmony_ci flush_workqueue(afs_async_calls); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (net->spare_incoming_call) { 11662306a36Sopenharmony_ci afs_put_call(net->spare_incoming_call); 11762306a36Sopenharmony_ci net->spare_incoming_call = NULL; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci _debug("outstanding %u", atomic_read(&net->nr_outstanding_calls)); 12162306a36Sopenharmony_ci wait_var_event(&net->nr_outstanding_calls, 12262306a36Sopenharmony_ci !atomic_read(&net->nr_outstanding_calls)); 12362306a36Sopenharmony_ci _debug("no outstanding calls"); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci kernel_sock_shutdown(net->socket, SHUT_RDWR); 12662306a36Sopenharmony_ci flush_workqueue(afs_async_calls); 12762306a36Sopenharmony_ci sock_release(net->socket); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci _debug("dework"); 13062306a36Sopenharmony_ci _leave(""); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* 13462306a36Sopenharmony_ci * Allocate a call. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_cistatic struct afs_call *afs_alloc_call(struct afs_net *net, 13762306a36Sopenharmony_ci const struct afs_call_type *type, 13862306a36Sopenharmony_ci gfp_t gfp) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct afs_call *call; 14162306a36Sopenharmony_ci int o; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci call = kzalloc(sizeof(*call), gfp); 14462306a36Sopenharmony_ci if (!call) 14562306a36Sopenharmony_ci return NULL; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci call->type = type; 14862306a36Sopenharmony_ci call->net = net; 14962306a36Sopenharmony_ci call->debug_id = atomic_inc_return(&rxrpc_debug_id); 15062306a36Sopenharmony_ci refcount_set(&call->ref, 1); 15162306a36Sopenharmony_ci INIT_WORK(&call->async_work, afs_process_async_call); 15262306a36Sopenharmony_ci init_waitqueue_head(&call->waitq); 15362306a36Sopenharmony_ci spin_lock_init(&call->state_lock); 15462306a36Sopenharmony_ci call->iter = &call->def_iter; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci o = atomic_inc_return(&net->nr_outstanding_calls); 15762306a36Sopenharmony_ci trace_afs_call(call->debug_id, afs_call_trace_alloc, 1, o, 15862306a36Sopenharmony_ci __builtin_return_address(0)); 15962306a36Sopenharmony_ci return call; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/* 16362306a36Sopenharmony_ci * Dispose of a reference on a call. 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_civoid afs_put_call(struct afs_call *call) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct afs_net *net = call->net; 16862306a36Sopenharmony_ci unsigned int debug_id = call->debug_id; 16962306a36Sopenharmony_ci bool zero; 17062306a36Sopenharmony_ci int r, o; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci zero = __refcount_dec_and_test(&call->ref, &r); 17362306a36Sopenharmony_ci o = atomic_read(&net->nr_outstanding_calls); 17462306a36Sopenharmony_ci trace_afs_call(debug_id, afs_call_trace_put, r - 1, o, 17562306a36Sopenharmony_ci __builtin_return_address(0)); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (zero) { 17862306a36Sopenharmony_ci ASSERT(!work_pending(&call->async_work)); 17962306a36Sopenharmony_ci ASSERT(call->type->name != NULL); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (call->rxcall) { 18262306a36Sopenharmony_ci rxrpc_kernel_shutdown_call(net->socket, call->rxcall); 18362306a36Sopenharmony_ci rxrpc_kernel_put_call(net->socket, call->rxcall); 18462306a36Sopenharmony_ci call->rxcall = NULL; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci if (call->type->destructor) 18762306a36Sopenharmony_ci call->type->destructor(call); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci afs_unuse_server_notime(call->net, call->server, afs_server_trace_put_call); 19062306a36Sopenharmony_ci afs_put_addrlist(call->alist); 19162306a36Sopenharmony_ci kfree(call->request); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci trace_afs_call(call->debug_id, afs_call_trace_free, 0, o, 19462306a36Sopenharmony_ci __builtin_return_address(0)); 19562306a36Sopenharmony_ci kfree(call); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci o = atomic_dec_return(&net->nr_outstanding_calls); 19862306a36Sopenharmony_ci if (o == 0) 19962306a36Sopenharmony_ci wake_up_var(&net->nr_outstanding_calls); 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic struct afs_call *afs_get_call(struct afs_call *call, 20462306a36Sopenharmony_ci enum afs_call_trace why) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci int r; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci __refcount_inc(&call->ref, &r); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci trace_afs_call(call->debug_id, why, r + 1, 21162306a36Sopenharmony_ci atomic_read(&call->net->nr_outstanding_calls), 21262306a36Sopenharmony_ci __builtin_return_address(0)); 21362306a36Sopenharmony_ci return call; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/* 21762306a36Sopenharmony_ci * Queue the call for actual work. 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_cistatic void afs_queue_call_work(struct afs_call *call) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci if (call->type->work) { 22262306a36Sopenharmony_ci INIT_WORK(&call->work, call->type->work); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci afs_get_call(call, afs_call_trace_work); 22562306a36Sopenharmony_ci if (!queue_work(afs_wq, &call->work)) 22662306a36Sopenharmony_ci afs_put_call(call); 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci/* 23162306a36Sopenharmony_ci * allocate a call with flat request and reply buffers 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_cistruct afs_call *afs_alloc_flat_call(struct afs_net *net, 23462306a36Sopenharmony_ci const struct afs_call_type *type, 23562306a36Sopenharmony_ci size_t request_size, size_t reply_max) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct afs_call *call; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci call = afs_alloc_call(net, type, GFP_NOFS); 24062306a36Sopenharmony_ci if (!call) 24162306a36Sopenharmony_ci goto nomem_call; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (request_size) { 24462306a36Sopenharmony_ci call->request_size = request_size; 24562306a36Sopenharmony_ci call->request = kmalloc(request_size, GFP_NOFS); 24662306a36Sopenharmony_ci if (!call->request) 24762306a36Sopenharmony_ci goto nomem_free; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (reply_max) { 25162306a36Sopenharmony_ci call->reply_max = reply_max; 25262306a36Sopenharmony_ci call->buffer = kmalloc(reply_max, GFP_NOFS); 25362306a36Sopenharmony_ci if (!call->buffer) 25462306a36Sopenharmony_ci goto nomem_free; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci afs_extract_to_buf(call, call->reply_max); 25862306a36Sopenharmony_ci call->operation_ID = type->op; 25962306a36Sopenharmony_ci init_waitqueue_head(&call->waitq); 26062306a36Sopenharmony_ci return call; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cinomem_free: 26362306a36Sopenharmony_ci afs_put_call(call); 26462306a36Sopenharmony_cinomem_call: 26562306a36Sopenharmony_ci return NULL; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci/* 26962306a36Sopenharmony_ci * clean up a call with flat buffer 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_civoid afs_flat_call_destructor(struct afs_call *call) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci _enter(""); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci kfree(call->request); 27662306a36Sopenharmony_ci call->request = NULL; 27762306a36Sopenharmony_ci kfree(call->buffer); 27862306a36Sopenharmony_ci call->buffer = NULL; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci/* 28262306a36Sopenharmony_ci * Advance the AFS call state when the RxRPC call ends the transmit phase. 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_cistatic void afs_notify_end_request_tx(struct sock *sock, 28562306a36Sopenharmony_ci struct rxrpc_call *rxcall, 28662306a36Sopenharmony_ci unsigned long call_user_ID) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct afs_call *call = (struct afs_call *)call_user_ID; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci afs_set_call_state(call, AFS_CALL_CL_REQUESTING, AFS_CALL_CL_AWAIT_REPLY); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci/* 29462306a36Sopenharmony_ci * Initiate a call and synchronously queue up the parameters for dispatch. Any 29562306a36Sopenharmony_ci * error is stored into the call struct, which the caller must check for. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_civoid afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct sockaddr_rxrpc *srx = &ac->alist->addrs[ac->index]; 30062306a36Sopenharmony_ci struct rxrpc_call *rxcall; 30162306a36Sopenharmony_ci struct msghdr msg; 30262306a36Sopenharmony_ci struct kvec iov[1]; 30362306a36Sopenharmony_ci size_t len; 30462306a36Sopenharmony_ci s64 tx_total_len; 30562306a36Sopenharmony_ci int ret; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci _enter(",{%pISp},", &srx->transport); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci ASSERT(call->type != NULL); 31062306a36Sopenharmony_ci ASSERT(call->type->name != NULL); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci _debug("____MAKE %p{%s,%x} [%d]____", 31362306a36Sopenharmony_ci call, call->type->name, key_serial(call->key), 31462306a36Sopenharmony_ci atomic_read(&call->net->nr_outstanding_calls)); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci call->addr_ix = ac->index; 31762306a36Sopenharmony_ci call->alist = afs_get_addrlist(ac->alist); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* Work out the length we're going to transmit. This is awkward for 32062306a36Sopenharmony_ci * calls such as FS.StoreData where there's an extra injection of data 32162306a36Sopenharmony_ci * after the initial fixed part. 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ci tx_total_len = call->request_size; 32462306a36Sopenharmony_ci if (call->write_iter) 32562306a36Sopenharmony_ci tx_total_len += iov_iter_count(call->write_iter); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci /* If the call is going to be asynchronous, we need an extra ref for 32862306a36Sopenharmony_ci * the call to hold itself so the caller need not hang on to its ref. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_ci if (call->async) { 33162306a36Sopenharmony_ci afs_get_call(call, afs_call_trace_get); 33262306a36Sopenharmony_ci call->drop_ref = true; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* create a call */ 33662306a36Sopenharmony_ci rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key, 33762306a36Sopenharmony_ci (unsigned long)call, 33862306a36Sopenharmony_ci tx_total_len, 33962306a36Sopenharmony_ci call->max_lifespan, 34062306a36Sopenharmony_ci gfp, 34162306a36Sopenharmony_ci (call->async ? 34262306a36Sopenharmony_ci afs_wake_up_async_call : 34362306a36Sopenharmony_ci afs_wake_up_call_waiter), 34462306a36Sopenharmony_ci call->upgrade, 34562306a36Sopenharmony_ci (call->intr ? RXRPC_PREINTERRUPTIBLE : 34662306a36Sopenharmony_ci RXRPC_UNINTERRUPTIBLE), 34762306a36Sopenharmony_ci call->debug_id); 34862306a36Sopenharmony_ci if (IS_ERR(rxcall)) { 34962306a36Sopenharmony_ci ret = PTR_ERR(rxcall); 35062306a36Sopenharmony_ci call->error = ret; 35162306a36Sopenharmony_ci goto error_kill_call; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci call->rxcall = rxcall; 35562306a36Sopenharmony_ci call->issue_time = ktime_get_real(); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* send the request */ 35862306a36Sopenharmony_ci iov[0].iov_base = call->request; 35962306a36Sopenharmony_ci iov[0].iov_len = call->request_size; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci msg.msg_name = NULL; 36262306a36Sopenharmony_ci msg.msg_namelen = 0; 36362306a36Sopenharmony_ci iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, 1, call->request_size); 36462306a36Sopenharmony_ci msg.msg_control = NULL; 36562306a36Sopenharmony_ci msg.msg_controllen = 0; 36662306a36Sopenharmony_ci msg.msg_flags = MSG_WAITALL | (call->write_iter ? MSG_MORE : 0); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci ret = rxrpc_kernel_send_data(call->net->socket, rxcall, 36962306a36Sopenharmony_ci &msg, call->request_size, 37062306a36Sopenharmony_ci afs_notify_end_request_tx); 37162306a36Sopenharmony_ci if (ret < 0) 37262306a36Sopenharmony_ci goto error_do_abort; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci if (call->write_iter) { 37562306a36Sopenharmony_ci msg.msg_iter = *call->write_iter; 37662306a36Sopenharmony_ci msg.msg_flags &= ~MSG_MORE; 37762306a36Sopenharmony_ci trace_afs_send_data(call, &msg); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci ret = rxrpc_kernel_send_data(call->net->socket, 38062306a36Sopenharmony_ci call->rxcall, &msg, 38162306a36Sopenharmony_ci iov_iter_count(&msg.msg_iter), 38262306a36Sopenharmony_ci afs_notify_end_request_tx); 38362306a36Sopenharmony_ci *call->write_iter = msg.msg_iter; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci trace_afs_sent_data(call, &msg, ret); 38662306a36Sopenharmony_ci if (ret < 0) 38762306a36Sopenharmony_ci goto error_do_abort; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* Note that at this point, we may have received the reply or an abort 39162306a36Sopenharmony_ci * - and an asynchronous call may already have completed. 39262306a36Sopenharmony_ci * 39362306a36Sopenharmony_ci * afs_wait_for_call_to_complete(call, ac) 39462306a36Sopenharmony_ci * must be called to synchronously clean up. 39562306a36Sopenharmony_ci */ 39662306a36Sopenharmony_ci return; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cierror_do_abort: 39962306a36Sopenharmony_ci if (ret != -ECONNABORTED) { 40062306a36Sopenharmony_ci rxrpc_kernel_abort_call(call->net->socket, rxcall, 40162306a36Sopenharmony_ci RX_USER_ABORT, ret, 40262306a36Sopenharmony_ci afs_abort_send_data_error); 40362306a36Sopenharmony_ci } else { 40462306a36Sopenharmony_ci len = 0; 40562306a36Sopenharmony_ci iov_iter_kvec(&msg.msg_iter, ITER_DEST, NULL, 0, 0); 40662306a36Sopenharmony_ci rxrpc_kernel_recv_data(call->net->socket, rxcall, 40762306a36Sopenharmony_ci &msg.msg_iter, &len, false, 40862306a36Sopenharmony_ci &call->abort_code, &call->service_id); 40962306a36Sopenharmony_ci ac->abort_code = call->abort_code; 41062306a36Sopenharmony_ci ac->responded = true; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci call->error = ret; 41362306a36Sopenharmony_ci trace_afs_call_done(call); 41462306a36Sopenharmony_cierror_kill_call: 41562306a36Sopenharmony_ci if (call->type->done) 41662306a36Sopenharmony_ci call->type->done(call); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci /* We need to dispose of the extra ref we grabbed for an async call. 41962306a36Sopenharmony_ci * The call, however, might be queued on afs_async_calls and we need to 42062306a36Sopenharmony_ci * make sure we don't get any more notifications that might requeue it. 42162306a36Sopenharmony_ci */ 42262306a36Sopenharmony_ci if (call->rxcall) 42362306a36Sopenharmony_ci rxrpc_kernel_shutdown_call(call->net->socket, call->rxcall); 42462306a36Sopenharmony_ci if (call->async) { 42562306a36Sopenharmony_ci if (cancel_work_sync(&call->async_work)) 42662306a36Sopenharmony_ci afs_put_call(call); 42762306a36Sopenharmony_ci afs_set_call_complete(call, ret, 0); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci ac->error = ret; 43162306a36Sopenharmony_ci call->state = AFS_CALL_COMPLETE; 43262306a36Sopenharmony_ci _leave(" = %d", ret); 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci/* 43662306a36Sopenharmony_ci * Log remote abort codes that indicate that we have a protocol disagreement 43762306a36Sopenharmony_ci * with the server. 43862306a36Sopenharmony_ci */ 43962306a36Sopenharmony_cistatic void afs_log_error(struct afs_call *call, s32 remote_abort) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci static int max = 0; 44262306a36Sopenharmony_ci const char *msg; 44362306a36Sopenharmony_ci int m; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci switch (remote_abort) { 44662306a36Sopenharmony_ci case RX_EOF: msg = "unexpected EOF"; break; 44762306a36Sopenharmony_ci case RXGEN_CC_MARSHAL: msg = "client marshalling"; break; 44862306a36Sopenharmony_ci case RXGEN_CC_UNMARSHAL: msg = "client unmarshalling"; break; 44962306a36Sopenharmony_ci case RXGEN_SS_MARSHAL: msg = "server marshalling"; break; 45062306a36Sopenharmony_ci case RXGEN_SS_UNMARSHAL: msg = "server unmarshalling"; break; 45162306a36Sopenharmony_ci case RXGEN_DECODE: msg = "opcode decode"; break; 45262306a36Sopenharmony_ci case RXGEN_SS_XDRFREE: msg = "server XDR cleanup"; break; 45362306a36Sopenharmony_ci case RXGEN_CC_XDRFREE: msg = "client XDR cleanup"; break; 45462306a36Sopenharmony_ci case -32: msg = "insufficient data"; break; 45562306a36Sopenharmony_ci default: 45662306a36Sopenharmony_ci return; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci m = max; 46062306a36Sopenharmony_ci if (m < 3) { 46162306a36Sopenharmony_ci max = m + 1; 46262306a36Sopenharmony_ci pr_notice("kAFS: Peer reported %s failure on %s [%pISp]\n", 46362306a36Sopenharmony_ci msg, call->type->name, 46462306a36Sopenharmony_ci &call->alist->addrs[call->addr_ix].transport); 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci/* 46962306a36Sopenharmony_ci * deliver messages to a call 47062306a36Sopenharmony_ci */ 47162306a36Sopenharmony_cistatic void afs_deliver_to_call(struct afs_call *call) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci enum afs_call_state state; 47462306a36Sopenharmony_ci size_t len; 47562306a36Sopenharmony_ci u32 abort_code, remote_abort = 0; 47662306a36Sopenharmony_ci int ret; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci _enter("%s", call->type->name); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci while (state = READ_ONCE(call->state), 48162306a36Sopenharmony_ci state == AFS_CALL_CL_AWAIT_REPLY || 48262306a36Sopenharmony_ci state == AFS_CALL_SV_AWAIT_OP_ID || 48362306a36Sopenharmony_ci state == AFS_CALL_SV_AWAIT_REQUEST || 48462306a36Sopenharmony_ci state == AFS_CALL_SV_AWAIT_ACK 48562306a36Sopenharmony_ci ) { 48662306a36Sopenharmony_ci if (state == AFS_CALL_SV_AWAIT_ACK) { 48762306a36Sopenharmony_ci len = 0; 48862306a36Sopenharmony_ci iov_iter_kvec(&call->def_iter, ITER_DEST, NULL, 0, 0); 48962306a36Sopenharmony_ci ret = rxrpc_kernel_recv_data(call->net->socket, 49062306a36Sopenharmony_ci call->rxcall, &call->def_iter, 49162306a36Sopenharmony_ci &len, false, &remote_abort, 49262306a36Sopenharmony_ci &call->service_id); 49362306a36Sopenharmony_ci trace_afs_receive_data(call, &call->def_iter, false, ret); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (ret == -EINPROGRESS || ret == -EAGAIN) 49662306a36Sopenharmony_ci return; 49762306a36Sopenharmony_ci if (ret < 0 || ret == 1) { 49862306a36Sopenharmony_ci if (ret == 1) 49962306a36Sopenharmony_ci ret = 0; 50062306a36Sopenharmony_ci goto call_complete; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci return; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci ret = call->type->deliver(call); 50662306a36Sopenharmony_ci state = READ_ONCE(call->state); 50762306a36Sopenharmony_ci if (ret == 0 && call->unmarshalling_error) 50862306a36Sopenharmony_ci ret = -EBADMSG; 50962306a36Sopenharmony_ci switch (ret) { 51062306a36Sopenharmony_ci case 0: 51162306a36Sopenharmony_ci afs_queue_call_work(call); 51262306a36Sopenharmony_ci if (state == AFS_CALL_CL_PROC_REPLY) { 51362306a36Sopenharmony_ci if (call->op) 51462306a36Sopenharmony_ci set_bit(AFS_SERVER_FL_MAY_HAVE_CB, 51562306a36Sopenharmony_ci &call->op->server->flags); 51662306a36Sopenharmony_ci goto call_complete; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci ASSERTCMP(state, >, AFS_CALL_CL_PROC_REPLY); 51962306a36Sopenharmony_ci goto done; 52062306a36Sopenharmony_ci case -EINPROGRESS: 52162306a36Sopenharmony_ci case -EAGAIN: 52262306a36Sopenharmony_ci goto out; 52362306a36Sopenharmony_ci case -ECONNABORTED: 52462306a36Sopenharmony_ci ASSERTCMP(state, ==, AFS_CALL_COMPLETE); 52562306a36Sopenharmony_ci afs_log_error(call, call->abort_code); 52662306a36Sopenharmony_ci goto done; 52762306a36Sopenharmony_ci case -ENOTSUPP: 52862306a36Sopenharmony_ci abort_code = RXGEN_OPCODE; 52962306a36Sopenharmony_ci rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 53062306a36Sopenharmony_ci abort_code, ret, 53162306a36Sopenharmony_ci afs_abort_op_not_supported); 53262306a36Sopenharmony_ci goto local_abort; 53362306a36Sopenharmony_ci case -EIO: 53462306a36Sopenharmony_ci pr_err("kAFS: Call %u in bad state %u\n", 53562306a36Sopenharmony_ci call->debug_id, state); 53662306a36Sopenharmony_ci fallthrough; 53762306a36Sopenharmony_ci case -ENODATA: 53862306a36Sopenharmony_ci case -EBADMSG: 53962306a36Sopenharmony_ci case -EMSGSIZE: 54062306a36Sopenharmony_ci case -ENOMEM: 54162306a36Sopenharmony_ci case -EFAULT: 54262306a36Sopenharmony_ci abort_code = RXGEN_CC_UNMARSHAL; 54362306a36Sopenharmony_ci if (state != AFS_CALL_CL_AWAIT_REPLY) 54462306a36Sopenharmony_ci abort_code = RXGEN_SS_UNMARSHAL; 54562306a36Sopenharmony_ci rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 54662306a36Sopenharmony_ci abort_code, ret, 54762306a36Sopenharmony_ci afs_abort_unmarshal_error); 54862306a36Sopenharmony_ci goto local_abort; 54962306a36Sopenharmony_ci default: 55062306a36Sopenharmony_ci abort_code = RX_CALL_DEAD; 55162306a36Sopenharmony_ci rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 55262306a36Sopenharmony_ci abort_code, ret, 55362306a36Sopenharmony_ci afs_abort_general_error); 55462306a36Sopenharmony_ci goto local_abort; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cidone: 55962306a36Sopenharmony_ci if (call->type->done) 56062306a36Sopenharmony_ci call->type->done(call); 56162306a36Sopenharmony_ciout: 56262306a36Sopenharmony_ci _leave(""); 56362306a36Sopenharmony_ci return; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cilocal_abort: 56662306a36Sopenharmony_ci abort_code = 0; 56762306a36Sopenharmony_cicall_complete: 56862306a36Sopenharmony_ci afs_set_call_complete(call, ret, remote_abort); 56962306a36Sopenharmony_ci state = AFS_CALL_COMPLETE; 57062306a36Sopenharmony_ci goto done; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci/* 57462306a36Sopenharmony_ci * Wait synchronously for a call to complete and clean up the call struct. 57562306a36Sopenharmony_ci */ 57662306a36Sopenharmony_cilong afs_wait_for_call_to_complete(struct afs_call *call, 57762306a36Sopenharmony_ci struct afs_addr_cursor *ac) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci long ret; 58062306a36Sopenharmony_ci bool rxrpc_complete = false; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci DECLARE_WAITQUEUE(myself, current); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci _enter(""); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci ret = call->error; 58762306a36Sopenharmony_ci if (ret < 0) 58862306a36Sopenharmony_ci goto out; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci add_wait_queue(&call->waitq, &myself); 59162306a36Sopenharmony_ci for (;;) { 59262306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* deliver any messages that are in the queue */ 59562306a36Sopenharmony_ci if (!afs_check_call_state(call, AFS_CALL_COMPLETE) && 59662306a36Sopenharmony_ci call->need_attention) { 59762306a36Sopenharmony_ci call->need_attention = false; 59862306a36Sopenharmony_ci __set_current_state(TASK_RUNNING); 59962306a36Sopenharmony_ci afs_deliver_to_call(call); 60062306a36Sopenharmony_ci continue; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (afs_check_call_state(call, AFS_CALL_COMPLETE)) 60462306a36Sopenharmony_ci break; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (!rxrpc_kernel_check_life(call->net->socket, call->rxcall)) { 60762306a36Sopenharmony_ci /* rxrpc terminated the call. */ 60862306a36Sopenharmony_ci rxrpc_complete = true; 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci schedule(); 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci remove_wait_queue(&call->waitq, &myself); 61662306a36Sopenharmony_ci __set_current_state(TASK_RUNNING); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci if (!afs_check_call_state(call, AFS_CALL_COMPLETE)) { 61962306a36Sopenharmony_ci if (rxrpc_complete) { 62062306a36Sopenharmony_ci afs_set_call_complete(call, call->error, call->abort_code); 62162306a36Sopenharmony_ci } else { 62262306a36Sopenharmony_ci /* Kill off the call if it's still live. */ 62362306a36Sopenharmony_ci _debug("call interrupted"); 62462306a36Sopenharmony_ci if (rxrpc_kernel_abort_call(call->net->socket, call->rxcall, 62562306a36Sopenharmony_ci RX_USER_ABORT, -EINTR, 62662306a36Sopenharmony_ci afs_abort_interrupted)) 62762306a36Sopenharmony_ci afs_set_call_complete(call, -EINTR, 0); 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci spin_lock_bh(&call->state_lock); 63262306a36Sopenharmony_ci ac->abort_code = call->abort_code; 63362306a36Sopenharmony_ci ac->error = call->error; 63462306a36Sopenharmony_ci spin_unlock_bh(&call->state_lock); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci ret = ac->error; 63762306a36Sopenharmony_ci switch (ret) { 63862306a36Sopenharmony_ci case 0: 63962306a36Sopenharmony_ci ret = call->ret0; 64062306a36Sopenharmony_ci call->ret0 = 0; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci fallthrough; 64362306a36Sopenharmony_ci case -ECONNABORTED: 64462306a36Sopenharmony_ci ac->responded = true; 64562306a36Sopenharmony_ci break; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ciout: 64962306a36Sopenharmony_ci _debug("call complete"); 65062306a36Sopenharmony_ci afs_put_call(call); 65162306a36Sopenharmony_ci _leave(" = %p", (void *)ret); 65262306a36Sopenharmony_ci return ret; 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci/* 65662306a36Sopenharmony_ci * wake up a waiting call 65762306a36Sopenharmony_ci */ 65862306a36Sopenharmony_cistatic void afs_wake_up_call_waiter(struct sock *sk, struct rxrpc_call *rxcall, 65962306a36Sopenharmony_ci unsigned long call_user_ID) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci struct afs_call *call = (struct afs_call *)call_user_ID; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci call->need_attention = true; 66462306a36Sopenharmony_ci wake_up(&call->waitq); 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci/* 66862306a36Sopenharmony_ci * wake up an asynchronous call 66962306a36Sopenharmony_ci */ 67062306a36Sopenharmony_cistatic void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall, 67162306a36Sopenharmony_ci unsigned long call_user_ID) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci struct afs_call *call = (struct afs_call *)call_user_ID; 67462306a36Sopenharmony_ci int r; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci trace_afs_notify_call(rxcall, call); 67762306a36Sopenharmony_ci call->need_attention = true; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (__refcount_inc_not_zero(&call->ref, &r)) { 68062306a36Sopenharmony_ci trace_afs_call(call->debug_id, afs_call_trace_wake, r + 1, 68162306a36Sopenharmony_ci atomic_read(&call->net->nr_outstanding_calls), 68262306a36Sopenharmony_ci __builtin_return_address(0)); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (!queue_work(afs_async_calls, &call->async_work)) 68562306a36Sopenharmony_ci afs_put_call(call); 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci/* 69062306a36Sopenharmony_ci * Perform I/O processing on an asynchronous call. The work item carries a ref 69162306a36Sopenharmony_ci * to the call struct that we either need to release or to pass on. 69262306a36Sopenharmony_ci */ 69362306a36Sopenharmony_cistatic void afs_process_async_call(struct work_struct *work) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci struct afs_call *call = container_of(work, struct afs_call, async_work); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci _enter(""); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci if (call->state < AFS_CALL_COMPLETE && call->need_attention) { 70062306a36Sopenharmony_ci call->need_attention = false; 70162306a36Sopenharmony_ci afs_deliver_to_call(call); 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci afs_put_call(call); 70562306a36Sopenharmony_ci _leave(""); 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic void afs_rx_attach(struct rxrpc_call *rxcall, unsigned long user_call_ID) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci struct afs_call *call = (struct afs_call *)user_call_ID; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci call->rxcall = rxcall; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci/* 71662306a36Sopenharmony_ci * Charge the incoming call preallocation. 71762306a36Sopenharmony_ci */ 71862306a36Sopenharmony_civoid afs_charge_preallocation(struct work_struct *work) 71962306a36Sopenharmony_ci{ 72062306a36Sopenharmony_ci struct afs_net *net = 72162306a36Sopenharmony_ci container_of(work, struct afs_net, charge_preallocation_work); 72262306a36Sopenharmony_ci struct afs_call *call = net->spare_incoming_call; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci for (;;) { 72562306a36Sopenharmony_ci if (!call) { 72662306a36Sopenharmony_ci call = afs_alloc_call(net, &afs_RXCMxxxx, GFP_KERNEL); 72762306a36Sopenharmony_ci if (!call) 72862306a36Sopenharmony_ci break; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci call->drop_ref = true; 73162306a36Sopenharmony_ci call->async = true; 73262306a36Sopenharmony_ci call->state = AFS_CALL_SV_AWAIT_OP_ID; 73362306a36Sopenharmony_ci init_waitqueue_head(&call->waitq); 73462306a36Sopenharmony_ci afs_extract_to_tmp(call); 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (rxrpc_kernel_charge_accept(net->socket, 73862306a36Sopenharmony_ci afs_wake_up_async_call, 73962306a36Sopenharmony_ci afs_rx_attach, 74062306a36Sopenharmony_ci (unsigned long)call, 74162306a36Sopenharmony_ci GFP_KERNEL, 74262306a36Sopenharmony_ci call->debug_id) < 0) 74362306a36Sopenharmony_ci break; 74462306a36Sopenharmony_ci call = NULL; 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci net->spare_incoming_call = call; 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci/* 75062306a36Sopenharmony_ci * Discard a preallocated call when a socket is shut down. 75162306a36Sopenharmony_ci */ 75262306a36Sopenharmony_cistatic void afs_rx_discard_new_call(struct rxrpc_call *rxcall, 75362306a36Sopenharmony_ci unsigned long user_call_ID) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci struct afs_call *call = (struct afs_call *)user_call_ID; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci call->rxcall = NULL; 75862306a36Sopenharmony_ci afs_put_call(call); 75962306a36Sopenharmony_ci} 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci/* 76262306a36Sopenharmony_ci * Notification of an incoming call. 76362306a36Sopenharmony_ci */ 76462306a36Sopenharmony_cistatic void afs_rx_new_call(struct sock *sk, struct rxrpc_call *rxcall, 76562306a36Sopenharmony_ci unsigned long user_call_ID) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci struct afs_net *net = afs_sock2net(sk); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci queue_work(afs_wq, &net->charge_preallocation_work); 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci/* 77362306a36Sopenharmony_ci * Grab the operation ID from an incoming cache manager call. The socket 77462306a36Sopenharmony_ci * buffer is discarded on error or if we don't yet have sufficient data. 77562306a36Sopenharmony_ci */ 77662306a36Sopenharmony_cistatic int afs_deliver_cm_op_id(struct afs_call *call) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci int ret; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci _enter("{%zu}", iov_iter_count(call->iter)); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci /* the operation ID forms the first four bytes of the request data */ 78362306a36Sopenharmony_ci ret = afs_extract_data(call, true); 78462306a36Sopenharmony_ci if (ret < 0) 78562306a36Sopenharmony_ci return ret; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci call->operation_ID = ntohl(call->tmp); 78862306a36Sopenharmony_ci afs_set_call_state(call, AFS_CALL_SV_AWAIT_OP_ID, AFS_CALL_SV_AWAIT_REQUEST); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci /* ask the cache manager to route the call (it'll change the call type 79162306a36Sopenharmony_ci * if successful) */ 79262306a36Sopenharmony_ci if (!afs_cm_incoming_call(call)) 79362306a36Sopenharmony_ci return -ENOTSUPP; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci trace_afs_cb_call(call); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci /* pass responsibility for the remainer of this message off to the 79862306a36Sopenharmony_ci * cache manager op */ 79962306a36Sopenharmony_ci return call->type->deliver(call); 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci/* 80362306a36Sopenharmony_ci * Advance the AFS call state when an RxRPC service call ends the transmit 80462306a36Sopenharmony_ci * phase. 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_cistatic void afs_notify_end_reply_tx(struct sock *sock, 80762306a36Sopenharmony_ci struct rxrpc_call *rxcall, 80862306a36Sopenharmony_ci unsigned long call_user_ID) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci struct afs_call *call = (struct afs_call *)call_user_ID; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci afs_set_call_state(call, AFS_CALL_SV_REPLYING, AFS_CALL_SV_AWAIT_ACK); 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci/* 81662306a36Sopenharmony_ci * send an empty reply 81762306a36Sopenharmony_ci */ 81862306a36Sopenharmony_civoid afs_send_empty_reply(struct afs_call *call) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci struct afs_net *net = call->net; 82162306a36Sopenharmony_ci struct msghdr msg; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci _enter(""); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci rxrpc_kernel_set_tx_length(net->socket, call->rxcall, 0); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci msg.msg_name = NULL; 82862306a36Sopenharmony_ci msg.msg_namelen = 0; 82962306a36Sopenharmony_ci iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, NULL, 0, 0); 83062306a36Sopenharmony_ci msg.msg_control = NULL; 83162306a36Sopenharmony_ci msg.msg_controllen = 0; 83262306a36Sopenharmony_ci msg.msg_flags = 0; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci switch (rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, 0, 83562306a36Sopenharmony_ci afs_notify_end_reply_tx)) { 83662306a36Sopenharmony_ci case 0: 83762306a36Sopenharmony_ci _leave(" [replied]"); 83862306a36Sopenharmony_ci return; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci case -ENOMEM: 84162306a36Sopenharmony_ci _debug("oom"); 84262306a36Sopenharmony_ci rxrpc_kernel_abort_call(net->socket, call->rxcall, 84362306a36Sopenharmony_ci RXGEN_SS_MARSHAL, -ENOMEM, 84462306a36Sopenharmony_ci afs_abort_oom); 84562306a36Sopenharmony_ci fallthrough; 84662306a36Sopenharmony_ci default: 84762306a36Sopenharmony_ci _leave(" [error]"); 84862306a36Sopenharmony_ci return; 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci} 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci/* 85362306a36Sopenharmony_ci * send a simple reply 85462306a36Sopenharmony_ci */ 85562306a36Sopenharmony_civoid afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci struct afs_net *net = call->net; 85862306a36Sopenharmony_ci struct msghdr msg; 85962306a36Sopenharmony_ci struct kvec iov[1]; 86062306a36Sopenharmony_ci int n; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci _enter(""); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci rxrpc_kernel_set_tx_length(net->socket, call->rxcall, len); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci iov[0].iov_base = (void *) buf; 86762306a36Sopenharmony_ci iov[0].iov_len = len; 86862306a36Sopenharmony_ci msg.msg_name = NULL; 86962306a36Sopenharmony_ci msg.msg_namelen = 0; 87062306a36Sopenharmony_ci iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, iov, 1, len); 87162306a36Sopenharmony_ci msg.msg_control = NULL; 87262306a36Sopenharmony_ci msg.msg_controllen = 0; 87362306a36Sopenharmony_ci msg.msg_flags = 0; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci n = rxrpc_kernel_send_data(net->socket, call->rxcall, &msg, len, 87662306a36Sopenharmony_ci afs_notify_end_reply_tx); 87762306a36Sopenharmony_ci if (n >= 0) { 87862306a36Sopenharmony_ci /* Success */ 87962306a36Sopenharmony_ci _leave(" [replied]"); 88062306a36Sopenharmony_ci return; 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci if (n == -ENOMEM) { 88462306a36Sopenharmony_ci _debug("oom"); 88562306a36Sopenharmony_ci rxrpc_kernel_abort_call(net->socket, call->rxcall, 88662306a36Sopenharmony_ci RXGEN_SS_MARSHAL, -ENOMEM, 88762306a36Sopenharmony_ci afs_abort_oom); 88862306a36Sopenharmony_ci } 88962306a36Sopenharmony_ci _leave(" [error]"); 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci/* 89362306a36Sopenharmony_ci * Extract a piece of data from the received data socket buffers. 89462306a36Sopenharmony_ci */ 89562306a36Sopenharmony_ciint afs_extract_data(struct afs_call *call, bool want_more) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci struct afs_net *net = call->net; 89862306a36Sopenharmony_ci struct iov_iter *iter = call->iter; 89962306a36Sopenharmony_ci enum afs_call_state state; 90062306a36Sopenharmony_ci u32 remote_abort = 0; 90162306a36Sopenharmony_ci int ret; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci _enter("{%s,%zu,%zu},%d", 90462306a36Sopenharmony_ci call->type->name, call->iov_len, iov_iter_count(iter), want_more); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci ret = rxrpc_kernel_recv_data(net->socket, call->rxcall, iter, 90762306a36Sopenharmony_ci &call->iov_len, want_more, &remote_abort, 90862306a36Sopenharmony_ci &call->service_id); 90962306a36Sopenharmony_ci trace_afs_receive_data(call, call->iter, want_more, ret); 91062306a36Sopenharmony_ci if (ret == 0 || ret == -EAGAIN) 91162306a36Sopenharmony_ci return ret; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci state = READ_ONCE(call->state); 91462306a36Sopenharmony_ci if (ret == 1) { 91562306a36Sopenharmony_ci switch (state) { 91662306a36Sopenharmony_ci case AFS_CALL_CL_AWAIT_REPLY: 91762306a36Sopenharmony_ci afs_set_call_state(call, state, AFS_CALL_CL_PROC_REPLY); 91862306a36Sopenharmony_ci break; 91962306a36Sopenharmony_ci case AFS_CALL_SV_AWAIT_REQUEST: 92062306a36Sopenharmony_ci afs_set_call_state(call, state, AFS_CALL_SV_REPLYING); 92162306a36Sopenharmony_ci break; 92262306a36Sopenharmony_ci case AFS_CALL_COMPLETE: 92362306a36Sopenharmony_ci kdebug("prem complete %d", call->error); 92462306a36Sopenharmony_ci return afs_io_error(call, afs_io_error_extract); 92562306a36Sopenharmony_ci default: 92662306a36Sopenharmony_ci break; 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci return 0; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci afs_set_call_complete(call, ret, remote_abort); 93262306a36Sopenharmony_ci return ret; 93362306a36Sopenharmony_ci} 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci/* 93662306a36Sopenharmony_ci * Log protocol error production. 93762306a36Sopenharmony_ci */ 93862306a36Sopenharmony_cinoinline int afs_protocol_error(struct afs_call *call, 93962306a36Sopenharmony_ci enum afs_eproto_cause cause) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci trace_afs_protocol_error(call, cause); 94262306a36Sopenharmony_ci if (call) 94362306a36Sopenharmony_ci call->unmarshalling_error = true; 94462306a36Sopenharmony_ci return -EBADMSG; 94562306a36Sopenharmony_ci} 946