108e0e7c8SDavid Howells /* Maintain an RxRPC server socket to do AFS communications through 208e0e7c8SDavid Howells * 308e0e7c8SDavid Howells * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 408e0e7c8SDavid Howells * Written by David Howells (dhowells@redhat.com) 508e0e7c8SDavid Howells * 608e0e7c8SDavid Howells * This program is free software; you can redistribute it and/or 708e0e7c8SDavid Howells * modify it under the terms of the GNU General Public License 808e0e7c8SDavid Howells * as published by the Free Software Foundation; either version 908e0e7c8SDavid Howells * 2 of the License, or (at your option) any later version. 1008e0e7c8SDavid Howells */ 1108e0e7c8SDavid Howells 125a0e3ad6STejun Heo #include <linux/slab.h> 1308e0e7c8SDavid Howells #include <net/sock.h> 1408e0e7c8SDavid Howells #include <net/af_rxrpc.h> 1508e0e7c8SDavid Howells #include <rxrpc/packet.h> 1608e0e7c8SDavid Howells #include "internal.h" 1708e0e7c8SDavid Howells #include "afs_cm.h" 1808e0e7c8SDavid Howells 198324f0bcSDavid Howells struct socket *afs_socket; /* my RxRPC socket */ 2008e0e7c8SDavid Howells static struct workqueue_struct *afs_async_calls; 2100e90712SDavid Howells static struct afs_call *afs_spare_incoming_call; 2200d3b7a4SDavid Howells static atomic_t afs_outstanding_calls; 2308e0e7c8SDavid Howells 24d001648eSDavid Howells static void afs_free_call(struct afs_call *); 25d001648eSDavid Howells static void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long); 2608e0e7c8SDavid Howells static int afs_wait_for_call_to_complete(struct afs_call *); 27d001648eSDavid Howells static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long); 2808e0e7c8SDavid Howells static int afs_dont_wait_for_call_to_complete(struct afs_call *); 29d001648eSDavid Howells static void afs_process_async_call(struct work_struct *); 3000e90712SDavid Howells static void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long); 3100e90712SDavid Howells static void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long); 32d001648eSDavid Howells static int afs_deliver_cm_op_id(struct afs_call *); 3308e0e7c8SDavid Howells 3408e0e7c8SDavid Howells /* synchronous call management */ 3508e0e7c8SDavid Howells const struct afs_wait_mode afs_sync_call = { 36d001648eSDavid Howells .notify_rx = afs_wake_up_call_waiter, 3708e0e7c8SDavid Howells .wait = afs_wait_for_call_to_complete, 3808e0e7c8SDavid Howells }; 3908e0e7c8SDavid Howells 4008e0e7c8SDavid Howells /* asynchronous call management */ 4108e0e7c8SDavid Howells const struct afs_wait_mode afs_async_call = { 42d001648eSDavid Howells .notify_rx = afs_wake_up_async_call, 4308e0e7c8SDavid Howells .wait = afs_dont_wait_for_call_to_complete, 4408e0e7c8SDavid Howells }; 4508e0e7c8SDavid Howells 4608e0e7c8SDavid Howells /* asynchronous incoming call management */ 4708e0e7c8SDavid Howells static const struct afs_wait_mode afs_async_incoming_call = { 48d001648eSDavid Howells .notify_rx = afs_wake_up_async_call, 4908e0e7c8SDavid Howells }; 5008e0e7c8SDavid Howells 5108e0e7c8SDavid Howells /* asynchronous incoming call initial processing */ 5208e0e7c8SDavid Howells static const struct afs_call_type afs_RXCMxxxx = { 5300d3b7a4SDavid Howells .name = "CB.xxxx", 5408e0e7c8SDavid Howells .deliver = afs_deliver_cm_op_id, 5508e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 5608e0e7c8SDavid Howells }; 5708e0e7c8SDavid Howells 5800e90712SDavid Howells static void afs_charge_preallocation(struct work_struct *); 5908e0e7c8SDavid Howells 6000e90712SDavid Howells static DECLARE_WORK(afs_charge_preallocation_work, afs_charge_preallocation); 6108e0e7c8SDavid Howells 622f02f7aeSDavid Howells static int afs_wait_atomic_t(atomic_t *p) 632f02f7aeSDavid Howells { 642f02f7aeSDavid Howells schedule(); 652f02f7aeSDavid Howells return 0; 662f02f7aeSDavid Howells } 672f02f7aeSDavid Howells 6808e0e7c8SDavid Howells /* 6908e0e7c8SDavid Howells * open an RxRPC socket and bind it to be a server for callback notifications 7008e0e7c8SDavid Howells * - the socket is left in blocking mode and non-blocking ops use MSG_DONTWAIT 7108e0e7c8SDavid Howells */ 7208e0e7c8SDavid Howells int afs_open_socket(void) 7308e0e7c8SDavid Howells { 7408e0e7c8SDavid Howells struct sockaddr_rxrpc srx; 7508e0e7c8SDavid Howells struct socket *socket; 7608e0e7c8SDavid Howells int ret; 7708e0e7c8SDavid Howells 7808e0e7c8SDavid Howells _enter(""); 7908e0e7c8SDavid Howells 800e119b41SDavid Howells ret = -ENOMEM; 8169ad052aSBhaktipriya Shridhar afs_async_calls = alloc_workqueue("kafsd", WQ_MEM_RECLAIM, 0); 820e119b41SDavid Howells if (!afs_async_calls) 830e119b41SDavid Howells goto error_0; 8408e0e7c8SDavid Howells 85eeb1bd5cSEric W. Biederman ret = sock_create_kern(&init_net, AF_RXRPC, SOCK_DGRAM, PF_INET, &socket); 860e119b41SDavid Howells if (ret < 0) 870e119b41SDavid Howells goto error_1; 8808e0e7c8SDavid Howells 8908e0e7c8SDavid Howells socket->sk->sk_allocation = GFP_NOFS; 9008e0e7c8SDavid Howells 9108e0e7c8SDavid Howells /* bind the callback manager's address to make this a server socket */ 9208e0e7c8SDavid Howells srx.srx_family = AF_RXRPC; 9308e0e7c8SDavid Howells srx.srx_service = CM_SERVICE; 9408e0e7c8SDavid Howells srx.transport_type = SOCK_DGRAM; 9508e0e7c8SDavid Howells srx.transport_len = sizeof(srx.transport.sin); 9608e0e7c8SDavid Howells srx.transport.sin.sin_family = AF_INET; 9708e0e7c8SDavid Howells srx.transport.sin.sin_port = htons(AFS_CM_PORT); 9808e0e7c8SDavid Howells memset(&srx.transport.sin.sin_addr, 0, 9908e0e7c8SDavid Howells sizeof(srx.transport.sin.sin_addr)); 10008e0e7c8SDavid Howells 10108e0e7c8SDavid Howells ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); 1020e119b41SDavid Howells if (ret < 0) 1030e119b41SDavid Howells goto error_2; 1040e119b41SDavid Howells 10500e90712SDavid Howells rxrpc_kernel_new_call_notification(socket, afs_rx_new_call, 10600e90712SDavid Howells afs_rx_discard_new_call); 107d001648eSDavid Howells 1080e119b41SDavid Howells ret = kernel_listen(socket, INT_MAX); 1090e119b41SDavid Howells if (ret < 0) 1100e119b41SDavid Howells goto error_2; 11108e0e7c8SDavid Howells 11208e0e7c8SDavid Howells afs_socket = socket; 11300e90712SDavid Howells afs_charge_preallocation(NULL); 11408e0e7c8SDavid Howells _leave(" = 0"); 11508e0e7c8SDavid Howells return 0; 1160e119b41SDavid Howells 1170e119b41SDavid Howells error_2: 1180e119b41SDavid Howells sock_release(socket); 1190e119b41SDavid Howells error_1: 1200e119b41SDavid Howells destroy_workqueue(afs_async_calls); 1210e119b41SDavid Howells error_0: 1220e119b41SDavid Howells _leave(" = %d", ret); 1230e119b41SDavid Howells return ret; 12408e0e7c8SDavid Howells } 12508e0e7c8SDavid Howells 12608e0e7c8SDavid Howells /* 12708e0e7c8SDavid Howells * close the RxRPC socket AFS was using 12808e0e7c8SDavid Howells */ 12908e0e7c8SDavid Howells void afs_close_socket(void) 13008e0e7c8SDavid Howells { 13108e0e7c8SDavid Howells _enter(""); 13208e0e7c8SDavid Howells 13300e90712SDavid Howells if (afs_spare_incoming_call) { 13400e90712SDavid Howells atomic_inc(&afs_outstanding_calls); 13500e90712SDavid Howells afs_free_call(afs_spare_incoming_call); 13600e90712SDavid Howells afs_spare_incoming_call = NULL; 13700e90712SDavid Howells } 13800e90712SDavid Howells 139d001648eSDavid Howells _debug("outstanding %u", atomic_read(&afs_outstanding_calls)); 1402f02f7aeSDavid Howells wait_on_atomic_t(&afs_outstanding_calls, afs_wait_atomic_t, 1412f02f7aeSDavid Howells TASK_UNINTERRUPTIBLE); 1422f02f7aeSDavid Howells _debug("no outstanding calls"); 1432f02f7aeSDavid Howells 144d001648eSDavid Howells flush_workqueue(afs_async_calls); 145248f219cSDavid Howells kernel_sock_shutdown(afs_socket, SHUT_RDWR); 146248f219cSDavid Howells flush_workqueue(afs_async_calls); 14708e0e7c8SDavid Howells sock_release(afs_socket); 14808e0e7c8SDavid Howells 14908e0e7c8SDavid Howells _debug("dework"); 15008e0e7c8SDavid Howells destroy_workqueue(afs_async_calls); 15108e0e7c8SDavid Howells _leave(""); 15208e0e7c8SDavid Howells } 15308e0e7c8SDavid Howells 15408e0e7c8SDavid Howells /* 15500d3b7a4SDavid Howells * free a call 15600d3b7a4SDavid Howells */ 15700d3b7a4SDavid Howells static void afs_free_call(struct afs_call *call) 15800d3b7a4SDavid Howells { 15900d3b7a4SDavid Howells _debug("DONE %p{%s} [%d]", 16000d3b7a4SDavid Howells call, call->type->name, atomic_read(&afs_outstanding_calls)); 16100d3b7a4SDavid Howells 16200d3b7a4SDavid Howells ASSERTCMP(call->rxcall, ==, NULL); 16300d3b7a4SDavid Howells ASSERT(!work_pending(&call->async_work)); 16400d3b7a4SDavid Howells ASSERT(call->type->name != NULL); 16500d3b7a4SDavid Howells 16600d3b7a4SDavid Howells kfree(call->request); 16700d3b7a4SDavid Howells kfree(call); 1682f02f7aeSDavid Howells 1692f02f7aeSDavid Howells if (atomic_dec_and_test(&afs_outstanding_calls)) 1702f02f7aeSDavid Howells wake_up_atomic_t(&afs_outstanding_calls); 17100d3b7a4SDavid Howells } 17200d3b7a4SDavid Howells 17300d3b7a4SDavid Howells /* 1746cf12869SNathaniel Wesley Filardo * End a call but do not free it 1756c67c7c3SDavid Howells */ 1766cf12869SNathaniel Wesley Filardo static void afs_end_call_nofree(struct afs_call *call) 1776c67c7c3SDavid Howells { 1786c67c7c3SDavid Howells if (call->rxcall) { 1794de48af6SDavid Howells rxrpc_kernel_end_call(afs_socket, call->rxcall); 1806c67c7c3SDavid Howells call->rxcall = NULL; 1816c67c7c3SDavid Howells } 1826cf12869SNathaniel Wesley Filardo if (call->type->destructor) 1836c67c7c3SDavid Howells call->type->destructor(call); 1846cf12869SNathaniel Wesley Filardo } 1856cf12869SNathaniel Wesley Filardo 1866cf12869SNathaniel Wesley Filardo /* 1876cf12869SNathaniel Wesley Filardo * End a call and free it 1886cf12869SNathaniel Wesley Filardo */ 1896cf12869SNathaniel Wesley Filardo static void afs_end_call(struct afs_call *call) 1906cf12869SNathaniel Wesley Filardo { 1916cf12869SNathaniel Wesley Filardo afs_end_call_nofree(call); 1926c67c7c3SDavid Howells afs_free_call(call); 1936c67c7c3SDavid Howells } 1946c67c7c3SDavid Howells 1956c67c7c3SDavid Howells /* 19608e0e7c8SDavid Howells * allocate a call with flat request and reply buffers 19708e0e7c8SDavid Howells */ 19808e0e7c8SDavid Howells struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type, 199d001648eSDavid Howells size_t request_size, size_t reply_max) 20008e0e7c8SDavid Howells { 20108e0e7c8SDavid Howells struct afs_call *call; 20208e0e7c8SDavid Howells 20308e0e7c8SDavid Howells call = kzalloc(sizeof(*call), GFP_NOFS); 20408e0e7c8SDavid Howells if (!call) 20508e0e7c8SDavid Howells goto nomem_call; 20608e0e7c8SDavid Howells 20700d3b7a4SDavid Howells _debug("CALL %p{%s} [%d]", 20800d3b7a4SDavid Howells call, type->name, atomic_read(&afs_outstanding_calls)); 20900d3b7a4SDavid Howells atomic_inc(&afs_outstanding_calls); 21008e0e7c8SDavid Howells 21108e0e7c8SDavid Howells call->type = type; 21208e0e7c8SDavid Howells call->request_size = request_size; 213d001648eSDavid Howells call->reply_max = reply_max; 21408e0e7c8SDavid Howells 21500d3b7a4SDavid Howells if (request_size) { 21600d3b7a4SDavid Howells call->request = kmalloc(request_size, GFP_NOFS); 21700d3b7a4SDavid Howells if (!call->request) 21800d3b7a4SDavid Howells goto nomem_free; 21900d3b7a4SDavid Howells } 22000d3b7a4SDavid Howells 221d001648eSDavid Howells if (reply_max) { 222d001648eSDavid Howells call->buffer = kmalloc(reply_max, GFP_NOFS); 22300d3b7a4SDavid Howells if (!call->buffer) 22400d3b7a4SDavid Howells goto nomem_free; 22500d3b7a4SDavid Howells } 22600d3b7a4SDavid Howells 22708e0e7c8SDavid Howells init_waitqueue_head(&call->waitq); 22808e0e7c8SDavid Howells return call; 22908e0e7c8SDavid Howells 23000d3b7a4SDavid Howells nomem_free: 23100d3b7a4SDavid Howells afs_free_call(call); 23208e0e7c8SDavid Howells nomem_call: 23308e0e7c8SDavid Howells return NULL; 23408e0e7c8SDavid Howells } 23508e0e7c8SDavid Howells 23608e0e7c8SDavid Howells /* 23708e0e7c8SDavid Howells * clean up a call with flat buffer 23808e0e7c8SDavid Howells */ 23908e0e7c8SDavid Howells void afs_flat_call_destructor(struct afs_call *call) 24008e0e7c8SDavid Howells { 24108e0e7c8SDavid Howells _enter(""); 24208e0e7c8SDavid Howells 24308e0e7c8SDavid Howells kfree(call->request); 24408e0e7c8SDavid Howells call->request = NULL; 24508e0e7c8SDavid Howells kfree(call->buffer); 24608e0e7c8SDavid Howells call->buffer = NULL; 24708e0e7c8SDavid Howells } 24808e0e7c8SDavid Howells 24908e0e7c8SDavid Howells /* 25031143d5dSDavid Howells * attach the data from a bunch of pages on an inode to a call 25131143d5dSDavid Howells */ 25239c6aceaSAl Viro static int afs_send_pages(struct afs_call *call, struct msghdr *msg) 25331143d5dSDavid Howells { 25431143d5dSDavid Howells struct page *pages[8]; 25531143d5dSDavid Howells unsigned count, n, loop, offset, to; 25631143d5dSDavid Howells pgoff_t first = call->first, last = call->last; 25731143d5dSDavid Howells int ret; 25831143d5dSDavid Howells 25931143d5dSDavid Howells _enter(""); 26031143d5dSDavid Howells 26131143d5dSDavid Howells offset = call->first_offset; 26231143d5dSDavid Howells call->first_offset = 0; 26331143d5dSDavid Howells 26431143d5dSDavid Howells do { 26531143d5dSDavid Howells _debug("attach %lx-%lx", first, last); 26631143d5dSDavid Howells 26731143d5dSDavid Howells count = last - first + 1; 26831143d5dSDavid Howells if (count > ARRAY_SIZE(pages)) 26931143d5dSDavid Howells count = ARRAY_SIZE(pages); 27031143d5dSDavid Howells n = find_get_pages_contig(call->mapping, first, count, pages); 27131143d5dSDavid Howells ASSERTCMP(n, ==, count); 27231143d5dSDavid Howells 27331143d5dSDavid Howells loop = 0; 27431143d5dSDavid Howells do { 27539c6aceaSAl Viro struct bio_vec bvec = {.bv_page = pages[loop], 27639c6aceaSAl Viro .bv_offset = offset}; 27731143d5dSDavid Howells msg->msg_flags = 0; 27831143d5dSDavid Howells to = PAGE_SIZE; 27931143d5dSDavid Howells if (first + loop >= last) 28031143d5dSDavid Howells to = call->last_to; 28131143d5dSDavid Howells else 28231143d5dSDavid Howells msg->msg_flags = MSG_MORE; 28339c6aceaSAl Viro bvec.bv_len = to - offset; 28431143d5dSDavid Howells offset = 0; 28531143d5dSDavid Howells 28631143d5dSDavid Howells _debug("- range %u-%u%s", 28731143d5dSDavid Howells offset, to, msg->msg_flags ? " [more]" : ""); 28839c6aceaSAl Viro iov_iter_bvec(&msg->msg_iter, WRITE | ITER_BVEC, 28939c6aceaSAl Viro &bvec, 1, to - offset); 29031143d5dSDavid Howells 29131143d5dSDavid Howells /* have to change the state *before* sending the last 29231143d5dSDavid Howells * packet as RxRPC might give us the reply before it 29331143d5dSDavid Howells * returns from sending the request */ 29431143d5dSDavid Howells if (first + loop >= last) 29531143d5dSDavid Howells call->state = AFS_CALL_AWAIT_REPLY; 2964de48af6SDavid Howells ret = rxrpc_kernel_send_data(afs_socket, call->rxcall, 2974de48af6SDavid Howells msg, to - offset); 29831143d5dSDavid Howells if (ret < 0) 29931143d5dSDavid Howells break; 30031143d5dSDavid Howells } while (++loop < count); 30131143d5dSDavid Howells first += count; 30231143d5dSDavid Howells 30331143d5dSDavid Howells for (loop = 0; loop < count; loop++) 30431143d5dSDavid Howells put_page(pages[loop]); 30531143d5dSDavid Howells if (ret < 0) 30631143d5dSDavid Howells break; 3075bbf5d39SDavid Howells } while (first <= last); 30831143d5dSDavid Howells 30931143d5dSDavid Howells _leave(" = %d", ret); 31031143d5dSDavid Howells return ret; 31131143d5dSDavid Howells } 31231143d5dSDavid Howells 31331143d5dSDavid Howells /* 31408e0e7c8SDavid Howells * initiate a call 31508e0e7c8SDavid Howells */ 31608e0e7c8SDavid Howells int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, 31708e0e7c8SDavid Howells const struct afs_wait_mode *wait_mode) 31808e0e7c8SDavid Howells { 31908e0e7c8SDavid Howells struct sockaddr_rxrpc srx; 32008e0e7c8SDavid Howells struct rxrpc_call *rxcall; 32108e0e7c8SDavid Howells struct msghdr msg; 32208e0e7c8SDavid Howells struct kvec iov[1]; 32308e0e7c8SDavid Howells int ret; 32408e0e7c8SDavid Howells 32508e0e7c8SDavid Howells _enter("%x,{%d},", addr->s_addr, ntohs(call->port)); 32608e0e7c8SDavid Howells 32700d3b7a4SDavid Howells ASSERT(call->type != NULL); 32800d3b7a4SDavid Howells ASSERT(call->type->name != NULL); 32900d3b7a4SDavid Howells 33031143d5dSDavid Howells _debug("____MAKE %p{%s,%x} [%d]____", 33131143d5dSDavid Howells call, call->type->name, key_serial(call->key), 33231143d5dSDavid Howells atomic_read(&afs_outstanding_calls)); 33300d3b7a4SDavid Howells 33408e0e7c8SDavid Howells call->wait_mode = wait_mode; 335d001648eSDavid Howells INIT_WORK(&call->async_work, afs_process_async_call); 33608e0e7c8SDavid Howells 33708e0e7c8SDavid Howells memset(&srx, 0, sizeof(srx)); 33808e0e7c8SDavid Howells srx.srx_family = AF_RXRPC; 33908e0e7c8SDavid Howells srx.srx_service = call->service_id; 34008e0e7c8SDavid Howells srx.transport_type = SOCK_DGRAM; 34108e0e7c8SDavid Howells srx.transport_len = sizeof(srx.transport.sin); 34208e0e7c8SDavid Howells srx.transport.sin.sin_family = AF_INET; 34308e0e7c8SDavid Howells srx.transport.sin.sin_port = call->port; 34408e0e7c8SDavid Howells memcpy(&srx.transport.sin.sin_addr, addr, 4); 34508e0e7c8SDavid Howells 34608e0e7c8SDavid Howells /* create a call */ 34708e0e7c8SDavid Howells rxcall = rxrpc_kernel_begin_call(afs_socket, &srx, call->key, 348d001648eSDavid Howells (unsigned long) call, gfp, 349d001648eSDavid Howells wait_mode->notify_rx); 35000d3b7a4SDavid Howells call->key = NULL; 35108e0e7c8SDavid Howells if (IS_ERR(rxcall)) { 35208e0e7c8SDavid Howells ret = PTR_ERR(rxcall); 35308e0e7c8SDavid Howells goto error_kill_call; 35408e0e7c8SDavid Howells } 35508e0e7c8SDavid Howells 35608e0e7c8SDavid Howells call->rxcall = rxcall; 35708e0e7c8SDavid Howells 35808e0e7c8SDavid Howells /* send the request */ 35908e0e7c8SDavid Howells iov[0].iov_base = call->request; 36008e0e7c8SDavid Howells iov[0].iov_len = call->request_size; 36108e0e7c8SDavid Howells 36208e0e7c8SDavid Howells msg.msg_name = NULL; 36308e0e7c8SDavid Howells msg.msg_namelen = 0; 3642e90b1c4SAl Viro iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iov, 1, 365c0371da6SAl Viro call->request_size); 36608e0e7c8SDavid Howells msg.msg_control = NULL; 36708e0e7c8SDavid Howells msg.msg_controllen = 0; 36831143d5dSDavid Howells msg.msg_flags = (call->send_pages ? MSG_MORE : 0); 36908e0e7c8SDavid Howells 37008e0e7c8SDavid Howells /* have to change the state *before* sending the last packet as RxRPC 37108e0e7c8SDavid Howells * might give us the reply before it returns from sending the 37208e0e7c8SDavid Howells * request */ 37331143d5dSDavid Howells if (!call->send_pages) 37408e0e7c8SDavid Howells call->state = AFS_CALL_AWAIT_REPLY; 3754de48af6SDavid Howells ret = rxrpc_kernel_send_data(afs_socket, rxcall, 3764de48af6SDavid Howells &msg, call->request_size); 37708e0e7c8SDavid Howells if (ret < 0) 37808e0e7c8SDavid Howells goto error_do_abort; 37908e0e7c8SDavid Howells 38031143d5dSDavid Howells if (call->send_pages) { 38139c6aceaSAl Viro ret = afs_send_pages(call, &msg); 38231143d5dSDavid Howells if (ret < 0) 38331143d5dSDavid Howells goto error_do_abort; 38431143d5dSDavid Howells } 38531143d5dSDavid Howells 38608e0e7c8SDavid Howells /* at this point, an async call may no longer exist as it may have 38708e0e7c8SDavid Howells * already completed */ 38808e0e7c8SDavid Howells return wait_mode->wait(call); 38908e0e7c8SDavid Howells 39008e0e7c8SDavid Howells error_do_abort: 3915a42976dSDavid Howells rxrpc_kernel_abort_call(afs_socket, rxcall, RX_USER_ABORT, -ret, "KSD"); 39208e0e7c8SDavid Howells error_kill_call: 3936c67c7c3SDavid Howells afs_end_call(call); 39408e0e7c8SDavid Howells _leave(" = %d", ret); 39508e0e7c8SDavid Howells return ret; 39608e0e7c8SDavid Howells } 39708e0e7c8SDavid Howells 39808e0e7c8SDavid Howells /* 39908e0e7c8SDavid Howells * deliver messages to a call 40008e0e7c8SDavid Howells */ 40108e0e7c8SDavid Howells static void afs_deliver_to_call(struct afs_call *call) 40208e0e7c8SDavid Howells { 40308e0e7c8SDavid Howells u32 abort_code; 40408e0e7c8SDavid Howells int ret; 40508e0e7c8SDavid Howells 406d001648eSDavid Howells _enter("%s", call->type->name); 40708e0e7c8SDavid Howells 408d001648eSDavid Howells while (call->state == AFS_CALL_AWAIT_REPLY || 40908e0e7c8SDavid Howells call->state == AFS_CALL_AWAIT_OP_ID || 41008e0e7c8SDavid Howells call->state == AFS_CALL_AWAIT_REQUEST || 411d001648eSDavid Howells call->state == AFS_CALL_AWAIT_ACK 412d001648eSDavid Howells ) { 413d001648eSDavid Howells if (call->state == AFS_CALL_AWAIT_ACK) { 414d001648eSDavid Howells size_t offset = 0; 415d001648eSDavid Howells ret = rxrpc_kernel_recv_data(afs_socket, call->rxcall, 416d001648eSDavid Howells NULL, 0, &offset, false, 417d001648eSDavid Howells &call->abort_code); 418d001648eSDavid Howells if (ret == -EINPROGRESS || ret == -EAGAIN) 419d001648eSDavid Howells return; 4209008f998SDavid Howells if (ret == 1 || ret < 0) { 421d001648eSDavid Howells call->state = AFS_CALL_COMPLETE; 422d001648eSDavid Howells goto done; 423372ee163SDavid Howells } 424d001648eSDavid Howells return; 425d001648eSDavid Howells } 426d001648eSDavid Howells 427d001648eSDavid Howells ret = call->type->deliver(call); 428d001648eSDavid Howells switch (ret) { 42908e0e7c8SDavid Howells case 0: 430372ee163SDavid Howells if (call->state == AFS_CALL_AWAIT_REPLY) 43108e0e7c8SDavid Howells call->state = AFS_CALL_COMPLETE; 432d001648eSDavid Howells goto done; 433d001648eSDavid Howells case -EINPROGRESS: 434d001648eSDavid Howells case -EAGAIN: 435d001648eSDavid Howells goto out; 43608e0e7c8SDavid Howells case -ENOTCONN: 43708e0e7c8SDavid Howells abort_code = RX_CALL_DEAD; 438d001648eSDavid Howells rxrpc_kernel_abort_call(afs_socket, call->rxcall, 4395a42976dSDavid Howells abort_code, -ret, "KNC"); 44008e0e7c8SDavid Howells goto do_abort; 44108e0e7c8SDavid Howells case -ENOTSUPP: 44208e0e7c8SDavid Howells abort_code = RX_INVALID_OPERATION; 443d001648eSDavid Howells rxrpc_kernel_abort_call(afs_socket, call->rxcall, 4445a42976dSDavid Howells abort_code, -ret, "KIV"); 44508e0e7c8SDavid Howells goto do_abort; 446d001648eSDavid Howells case -ENODATA: 447d001648eSDavid Howells case -EBADMSG: 448d001648eSDavid Howells case -EMSGSIZE: 44908e0e7c8SDavid Howells default: 45008e0e7c8SDavid Howells abort_code = RXGEN_CC_UNMARSHAL; 45108e0e7c8SDavid Howells if (call->state != AFS_CALL_AWAIT_REPLY) 45208e0e7c8SDavid Howells abort_code = RXGEN_SS_UNMARSHAL; 453d001648eSDavid Howells rxrpc_kernel_abort_call(afs_socket, call->rxcall, 4545a42976dSDavid Howells abort_code, EBADMSG, "KUM"); 455d001648eSDavid Howells goto do_abort; 45608e0e7c8SDavid Howells } 45708e0e7c8SDavid Howells } 45808e0e7c8SDavid Howells 459d001648eSDavid Howells done: 460d001648eSDavid Howells if (call->state == AFS_CALL_COMPLETE && call->incoming) 4616c67c7c3SDavid Howells afs_end_call(call); 462d001648eSDavid Howells out: 46308e0e7c8SDavid Howells _leave(""); 464d001648eSDavid Howells return; 465d001648eSDavid Howells 466d001648eSDavid Howells do_abort: 467d001648eSDavid Howells call->error = ret; 468d001648eSDavid Howells call->state = AFS_CALL_COMPLETE; 469d001648eSDavid Howells goto done; 47008e0e7c8SDavid Howells } 47108e0e7c8SDavid Howells 47208e0e7c8SDavid Howells /* 47308e0e7c8SDavid Howells * wait synchronously for a call to complete 47408e0e7c8SDavid Howells */ 47508e0e7c8SDavid Howells static int afs_wait_for_call_to_complete(struct afs_call *call) 47608e0e7c8SDavid Howells { 4775a42976dSDavid Howells const char *abort_why; 47808e0e7c8SDavid Howells int ret; 47908e0e7c8SDavid Howells 48008e0e7c8SDavid Howells DECLARE_WAITQUEUE(myself, current); 48108e0e7c8SDavid Howells 48208e0e7c8SDavid Howells _enter(""); 48308e0e7c8SDavid Howells 48408e0e7c8SDavid Howells add_wait_queue(&call->waitq, &myself); 48508e0e7c8SDavid Howells for (;;) { 48608e0e7c8SDavid Howells set_current_state(TASK_INTERRUPTIBLE); 48708e0e7c8SDavid Howells 48808e0e7c8SDavid Howells /* deliver any messages that are in the queue */ 489d001648eSDavid Howells if (call->state < AFS_CALL_COMPLETE && call->need_attention) { 490d001648eSDavid Howells call->need_attention = false; 49108e0e7c8SDavid Howells __set_current_state(TASK_RUNNING); 49208e0e7c8SDavid Howells afs_deliver_to_call(call); 49308e0e7c8SDavid Howells continue; 49408e0e7c8SDavid Howells } 49508e0e7c8SDavid Howells 4965a42976dSDavid Howells abort_why = "KWC"; 49708e0e7c8SDavid Howells ret = call->error; 498d001648eSDavid Howells if (call->state == AFS_CALL_COMPLETE) 49908e0e7c8SDavid Howells break; 5005a42976dSDavid Howells abort_why = "KWI"; 50108e0e7c8SDavid Howells ret = -EINTR; 50208e0e7c8SDavid Howells if (signal_pending(current)) 50308e0e7c8SDavid Howells break; 50408e0e7c8SDavid Howells schedule(); 50508e0e7c8SDavid Howells } 50608e0e7c8SDavid Howells 50708e0e7c8SDavid Howells remove_wait_queue(&call->waitq, &myself); 50808e0e7c8SDavid Howells __set_current_state(TASK_RUNNING); 50908e0e7c8SDavid Howells 51008e0e7c8SDavid Howells /* kill the call */ 51108e0e7c8SDavid Howells if (call->state < AFS_CALL_COMPLETE) { 51208e0e7c8SDavid Howells _debug("call incomplete"); 513d001648eSDavid Howells rxrpc_kernel_abort_call(afs_socket, call->rxcall, 5145a42976dSDavid Howells RX_CALL_DEAD, -ret, abort_why); 51508e0e7c8SDavid Howells } 51608e0e7c8SDavid Howells 51708e0e7c8SDavid Howells _debug("call complete"); 5186c67c7c3SDavid Howells afs_end_call(call); 51908e0e7c8SDavid Howells _leave(" = %d", ret); 52008e0e7c8SDavid Howells return ret; 52108e0e7c8SDavid Howells } 52208e0e7c8SDavid Howells 52308e0e7c8SDavid Howells /* 52408e0e7c8SDavid Howells * wake up a waiting call 52508e0e7c8SDavid Howells */ 526d001648eSDavid Howells static void afs_wake_up_call_waiter(struct sock *sk, struct rxrpc_call *rxcall, 527d001648eSDavid Howells unsigned long call_user_ID) 52808e0e7c8SDavid Howells { 529d001648eSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 530d001648eSDavid Howells 531d001648eSDavid Howells call->need_attention = true; 53208e0e7c8SDavid Howells wake_up(&call->waitq); 53308e0e7c8SDavid Howells } 53408e0e7c8SDavid Howells 53508e0e7c8SDavid Howells /* 53608e0e7c8SDavid Howells * wake up an asynchronous call 53708e0e7c8SDavid Howells */ 538d001648eSDavid Howells static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall, 539d001648eSDavid Howells unsigned long call_user_ID) 54008e0e7c8SDavid Howells { 541d001648eSDavid Howells struct afs_call *call = (struct afs_call *)call_user_ID; 542d001648eSDavid Howells 543d001648eSDavid Howells call->need_attention = true; 54408e0e7c8SDavid Howells queue_work(afs_async_calls, &call->async_work); 54508e0e7c8SDavid Howells } 54608e0e7c8SDavid Howells 54708e0e7c8SDavid Howells /* 54808e0e7c8SDavid Howells * put a call into asynchronous mode 54908e0e7c8SDavid Howells * - mustn't touch the call descriptor as the call my have completed by the 55008e0e7c8SDavid Howells * time we get here 55108e0e7c8SDavid Howells */ 55208e0e7c8SDavid Howells static int afs_dont_wait_for_call_to_complete(struct afs_call *call) 55308e0e7c8SDavid Howells { 55408e0e7c8SDavid Howells _enter(""); 55508e0e7c8SDavid Howells return -EINPROGRESS; 55608e0e7c8SDavid Howells } 55708e0e7c8SDavid Howells 55808e0e7c8SDavid Howells /* 55908e0e7c8SDavid Howells * delete an asynchronous call 56008e0e7c8SDavid Howells */ 561d001648eSDavid Howells static void afs_delete_async_call(struct work_struct *work) 56208e0e7c8SDavid Howells { 563d001648eSDavid Howells struct afs_call *call = container_of(work, struct afs_call, async_work); 564d001648eSDavid Howells 56508e0e7c8SDavid Howells _enter(""); 56608e0e7c8SDavid Howells 56700d3b7a4SDavid Howells afs_free_call(call); 56808e0e7c8SDavid Howells 56908e0e7c8SDavid Howells _leave(""); 57008e0e7c8SDavid Howells } 57108e0e7c8SDavid Howells 57208e0e7c8SDavid Howells /* 57308e0e7c8SDavid Howells * perform processing on an asynchronous call 57408e0e7c8SDavid Howells */ 575d001648eSDavid Howells static void afs_process_async_call(struct work_struct *work) 57608e0e7c8SDavid Howells { 577d001648eSDavid Howells struct afs_call *call = container_of(work, struct afs_call, async_work); 578d001648eSDavid Howells 57908e0e7c8SDavid Howells _enter(""); 58008e0e7c8SDavid Howells 581d001648eSDavid Howells if (call->state < AFS_CALL_COMPLETE && call->need_attention) { 582d001648eSDavid Howells call->need_attention = false; 58308e0e7c8SDavid Howells afs_deliver_to_call(call); 584d001648eSDavid Howells } 58508e0e7c8SDavid Howells 586d001648eSDavid Howells if (call->state == AFS_CALL_COMPLETE && call->wait_mode) { 58708e0e7c8SDavid Howells if (call->wait_mode->async_complete) 58808e0e7c8SDavid Howells call->wait_mode->async_complete(call->reply, 58908e0e7c8SDavid Howells call->error); 59008e0e7c8SDavid Howells call->reply = NULL; 59108e0e7c8SDavid Howells 59208e0e7c8SDavid Howells /* kill the call */ 5936cf12869SNathaniel Wesley Filardo afs_end_call_nofree(call); 59408e0e7c8SDavid Howells 59508e0e7c8SDavid Howells /* we can't just delete the call because the work item may be 59608e0e7c8SDavid Howells * queued */ 597d001648eSDavid Howells call->async_work.func = afs_delete_async_call; 59808e0e7c8SDavid Howells queue_work(afs_async_calls, &call->async_work); 59908e0e7c8SDavid Howells } 60008e0e7c8SDavid Howells 60108e0e7c8SDavid Howells _leave(""); 60208e0e7c8SDavid Howells } 60308e0e7c8SDavid Howells 60400e90712SDavid Howells static void afs_rx_attach(struct rxrpc_call *rxcall, unsigned long user_call_ID) 60500e90712SDavid Howells { 60600e90712SDavid Howells struct afs_call *call = (struct afs_call *)user_call_ID; 60700e90712SDavid Howells 60800e90712SDavid Howells call->rxcall = rxcall; 60900e90712SDavid Howells } 61000e90712SDavid Howells 61100e90712SDavid Howells /* 61200e90712SDavid Howells * Charge the incoming call preallocation. 61300e90712SDavid Howells */ 61400e90712SDavid Howells static void afs_charge_preallocation(struct work_struct *work) 61500e90712SDavid Howells { 61600e90712SDavid Howells struct afs_call *call = afs_spare_incoming_call; 61700e90712SDavid Howells 61800e90712SDavid Howells for (;;) { 61900e90712SDavid Howells if (!call) { 62000e90712SDavid Howells call = kzalloc(sizeof(struct afs_call), GFP_KERNEL); 62100e90712SDavid Howells if (!call) 62200e90712SDavid Howells break; 62300e90712SDavid Howells 62400e90712SDavid Howells INIT_WORK(&call->async_work, afs_process_async_call); 62500e90712SDavid Howells call->wait_mode = &afs_async_incoming_call; 62600e90712SDavid Howells call->type = &afs_RXCMxxxx; 62700e90712SDavid Howells init_waitqueue_head(&call->waitq); 62800e90712SDavid Howells call->state = AFS_CALL_AWAIT_OP_ID; 62900e90712SDavid Howells } 63000e90712SDavid Howells 63100e90712SDavid Howells if (rxrpc_kernel_charge_accept(afs_socket, 63200e90712SDavid Howells afs_wake_up_async_call, 63300e90712SDavid Howells afs_rx_attach, 63400e90712SDavid Howells (unsigned long)call, 63500e90712SDavid Howells GFP_KERNEL) < 0) 63600e90712SDavid Howells break; 63700e90712SDavid Howells call = NULL; 63800e90712SDavid Howells } 63900e90712SDavid Howells afs_spare_incoming_call = call; 64000e90712SDavid Howells } 64100e90712SDavid Howells 64200e90712SDavid Howells /* 64300e90712SDavid Howells * Discard a preallocated call when a socket is shut down. 64400e90712SDavid Howells */ 64500e90712SDavid Howells static void afs_rx_discard_new_call(struct rxrpc_call *rxcall, 64600e90712SDavid Howells unsigned long user_call_ID) 64700e90712SDavid Howells { 64800e90712SDavid Howells struct afs_call *call = (struct afs_call *)user_call_ID; 64900e90712SDavid Howells 65000e90712SDavid Howells atomic_inc(&afs_outstanding_calls); 65100e90712SDavid Howells call->rxcall = NULL; 65200e90712SDavid Howells afs_free_call(call); 65300e90712SDavid Howells } 65400e90712SDavid Howells 65508e0e7c8SDavid Howells /* 656d001648eSDavid Howells * Notification of an incoming call. 657d001648eSDavid Howells */ 65800e90712SDavid Howells static void afs_rx_new_call(struct sock *sk, struct rxrpc_call *rxcall, 65900e90712SDavid Howells unsigned long user_call_ID) 660d001648eSDavid Howells { 661248f219cSDavid Howells atomic_inc(&afs_outstanding_calls); 66200e90712SDavid Howells queue_work(afs_wq, &afs_charge_preallocation_work); 663d001648eSDavid Howells } 664d001648eSDavid Howells 665d001648eSDavid Howells /* 666372ee163SDavid Howells * Grab the operation ID from an incoming cache manager call. The socket 667372ee163SDavid Howells * buffer is discarded on error or if we don't yet have sufficient data. 66808e0e7c8SDavid Howells */ 669d001648eSDavid Howells static int afs_deliver_cm_op_id(struct afs_call *call) 67008e0e7c8SDavid Howells { 671d001648eSDavid Howells int ret; 67208e0e7c8SDavid Howells 673d001648eSDavid Howells _enter("{%zu}", call->offset); 67408e0e7c8SDavid Howells 67508e0e7c8SDavid Howells ASSERTCMP(call->offset, <, 4); 67608e0e7c8SDavid Howells 67708e0e7c8SDavid Howells /* the operation ID forms the first four bytes of the request data */ 67850a2c953SDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 679d001648eSDavid Howells if (ret < 0) 680d001648eSDavid Howells return ret; 68108e0e7c8SDavid Howells 68250a2c953SDavid Howells call->operation_ID = ntohl(call->tmp); 68308e0e7c8SDavid Howells call->state = AFS_CALL_AWAIT_REQUEST; 684d001648eSDavid Howells call->offset = 0; 68508e0e7c8SDavid Howells 68608e0e7c8SDavid Howells /* ask the cache manager to route the call (it'll change the call type 68708e0e7c8SDavid Howells * if successful) */ 68808e0e7c8SDavid Howells if (!afs_cm_incoming_call(call)) 68908e0e7c8SDavid Howells return -ENOTSUPP; 69008e0e7c8SDavid Howells 69108e0e7c8SDavid Howells /* pass responsibility for the remainer of this message off to the 69208e0e7c8SDavid Howells * cache manager op */ 693d001648eSDavid Howells return call->type->deliver(call); 69408e0e7c8SDavid Howells } 69508e0e7c8SDavid Howells 69608e0e7c8SDavid Howells /* 69708e0e7c8SDavid Howells * send an empty reply 69808e0e7c8SDavid Howells */ 69908e0e7c8SDavid Howells void afs_send_empty_reply(struct afs_call *call) 70008e0e7c8SDavid Howells { 70108e0e7c8SDavid Howells struct msghdr msg; 70208e0e7c8SDavid Howells 70308e0e7c8SDavid Howells _enter(""); 70408e0e7c8SDavid Howells 70508e0e7c8SDavid Howells msg.msg_name = NULL; 70608e0e7c8SDavid Howells msg.msg_namelen = 0; 707bfd4e956SDavid Howells iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, NULL, 0, 0); 70808e0e7c8SDavid Howells msg.msg_control = NULL; 70908e0e7c8SDavid Howells msg.msg_controllen = 0; 71008e0e7c8SDavid Howells msg.msg_flags = 0; 71108e0e7c8SDavid Howells 71208e0e7c8SDavid Howells call->state = AFS_CALL_AWAIT_ACK; 7134de48af6SDavid Howells switch (rxrpc_kernel_send_data(afs_socket, call->rxcall, &msg, 0)) { 71408e0e7c8SDavid Howells case 0: 71508e0e7c8SDavid Howells _leave(" [replied]"); 71608e0e7c8SDavid Howells return; 71708e0e7c8SDavid Howells 71808e0e7c8SDavid Howells case -ENOMEM: 71908e0e7c8SDavid Howells _debug("oom"); 7204de48af6SDavid Howells rxrpc_kernel_abort_call(afs_socket, call->rxcall, 7215a42976dSDavid Howells RX_USER_ABORT, ENOMEM, "KOO"); 72208e0e7c8SDavid Howells default: 7236c67c7c3SDavid Howells afs_end_call(call); 72408e0e7c8SDavid Howells _leave(" [error]"); 72508e0e7c8SDavid Howells return; 72608e0e7c8SDavid Howells } 72708e0e7c8SDavid Howells } 72808e0e7c8SDavid Howells 72908e0e7c8SDavid Howells /* 730b908fe6bSDavid Howells * send a simple reply 731b908fe6bSDavid Howells */ 732b908fe6bSDavid Howells void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) 733b908fe6bSDavid Howells { 734b908fe6bSDavid Howells struct msghdr msg; 7352e90b1c4SAl Viro struct kvec iov[1]; 736bd6dc742SDavid Howells int n; 737b908fe6bSDavid Howells 738b908fe6bSDavid Howells _enter(""); 739b908fe6bSDavid Howells 740b908fe6bSDavid Howells iov[0].iov_base = (void *) buf; 741b908fe6bSDavid Howells iov[0].iov_len = len; 742b908fe6bSDavid Howells msg.msg_name = NULL; 743b908fe6bSDavid Howells msg.msg_namelen = 0; 7442e90b1c4SAl Viro iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iov, 1, len); 745b908fe6bSDavid Howells msg.msg_control = NULL; 746b908fe6bSDavid Howells msg.msg_controllen = 0; 747b908fe6bSDavid Howells msg.msg_flags = 0; 748b908fe6bSDavid Howells 749b908fe6bSDavid Howells call->state = AFS_CALL_AWAIT_ACK; 7504de48af6SDavid Howells n = rxrpc_kernel_send_data(afs_socket, call->rxcall, &msg, len); 751bd6dc742SDavid Howells if (n >= 0) { 7526c67c7c3SDavid Howells /* Success */ 753b908fe6bSDavid Howells _leave(" [replied]"); 754b908fe6bSDavid Howells return; 755bd6dc742SDavid Howells } 7566c67c7c3SDavid Howells 757bd6dc742SDavid Howells if (n == -ENOMEM) { 758b908fe6bSDavid Howells _debug("oom"); 7594de48af6SDavid Howells rxrpc_kernel_abort_call(afs_socket, call->rxcall, 7605a42976dSDavid Howells RX_USER_ABORT, ENOMEM, "KOO"); 761bd6dc742SDavid Howells } 7626c67c7c3SDavid Howells afs_end_call(call); 763b908fe6bSDavid Howells _leave(" [error]"); 764b908fe6bSDavid Howells } 765b908fe6bSDavid Howells 766b908fe6bSDavid Howells /* 767372ee163SDavid Howells * Extract a piece of data from the received data socket buffers. 76808e0e7c8SDavid Howells */ 769d001648eSDavid Howells int afs_extract_data(struct afs_call *call, void *buf, size_t count, 770d001648eSDavid Howells bool want_more) 77108e0e7c8SDavid Howells { 772d001648eSDavid Howells int ret; 77308e0e7c8SDavid Howells 774d001648eSDavid Howells _enter("{%s,%zu},,%zu,%d", 775d001648eSDavid Howells call->type->name, call->offset, count, want_more); 77608e0e7c8SDavid Howells 777d001648eSDavid Howells ASSERTCMP(call->offset, <=, count); 77808e0e7c8SDavid Howells 779d001648eSDavid Howells ret = rxrpc_kernel_recv_data(afs_socket, call->rxcall, 780d001648eSDavid Howells buf, count, &call->offset, 781d001648eSDavid Howells want_more, &call->abort_code); 782d001648eSDavid Howells if (ret == 0 || ret == -EAGAIN) 783d001648eSDavid Howells return ret; 78408e0e7c8SDavid Howells 785d001648eSDavid Howells if (ret == 1) { 786d001648eSDavid Howells switch (call->state) { 787d001648eSDavid Howells case AFS_CALL_AWAIT_REPLY: 788d001648eSDavid Howells call->state = AFS_CALL_COMPLETE; 789d001648eSDavid Howells break; 790d001648eSDavid Howells case AFS_CALL_AWAIT_REQUEST: 791d001648eSDavid Howells call->state = AFS_CALL_REPLYING; 792d001648eSDavid Howells break; 793d001648eSDavid Howells default: 794d001648eSDavid Howells break; 79508e0e7c8SDavid Howells } 79608e0e7c8SDavid Howells return 0; 79708e0e7c8SDavid Howells } 798d001648eSDavid Howells 799d001648eSDavid Howells if (ret == -ECONNABORTED) 800d001648eSDavid Howells call->error = call->type->abort_to_error(call->abort_code); 801d001648eSDavid Howells else 802d001648eSDavid Howells call->error = ret; 803d001648eSDavid Howells call->state = AFS_CALL_COMPLETE; 804d001648eSDavid Howells return ret; 805d001648eSDavid Howells } 806