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 1208e0e7c8SDavid Howells #include <net/sock.h> 1308e0e7c8SDavid Howells #include <net/af_rxrpc.h> 1408e0e7c8SDavid Howells #include <rxrpc/packet.h> 1508e0e7c8SDavid Howells #include "internal.h" 1608e0e7c8SDavid Howells #include "afs_cm.h" 1708e0e7c8SDavid Howells 1808e0e7c8SDavid Howells static struct socket *afs_socket; /* my RxRPC socket */ 1908e0e7c8SDavid Howells static struct workqueue_struct *afs_async_calls; 2000d3b7a4SDavid Howells static atomic_t afs_outstanding_calls; 2100d3b7a4SDavid Howells static atomic_t afs_outstanding_skbs; 2208e0e7c8SDavid Howells 2308e0e7c8SDavid Howells static void afs_wake_up_call_waiter(struct afs_call *); 2408e0e7c8SDavid Howells static int afs_wait_for_call_to_complete(struct afs_call *); 2508e0e7c8SDavid Howells static void afs_wake_up_async_call(struct afs_call *); 2608e0e7c8SDavid Howells static int afs_dont_wait_for_call_to_complete(struct afs_call *); 2708e0e7c8SDavid Howells static void afs_process_async_call(struct work_struct *); 2808e0e7c8SDavid Howells static void afs_rx_interceptor(struct sock *, unsigned long, struct sk_buff *); 2908e0e7c8SDavid Howells static int afs_deliver_cm_op_id(struct afs_call *, struct sk_buff *, bool); 3008e0e7c8SDavid Howells 3108e0e7c8SDavid Howells /* synchronous call management */ 3208e0e7c8SDavid Howells const struct afs_wait_mode afs_sync_call = { 3308e0e7c8SDavid Howells .rx_wakeup = afs_wake_up_call_waiter, 3408e0e7c8SDavid Howells .wait = afs_wait_for_call_to_complete, 3508e0e7c8SDavid Howells }; 3608e0e7c8SDavid Howells 3708e0e7c8SDavid Howells /* asynchronous call management */ 3808e0e7c8SDavid Howells const struct afs_wait_mode afs_async_call = { 3908e0e7c8SDavid Howells .rx_wakeup = afs_wake_up_async_call, 4008e0e7c8SDavid Howells .wait = afs_dont_wait_for_call_to_complete, 4108e0e7c8SDavid Howells }; 4208e0e7c8SDavid Howells 4308e0e7c8SDavid Howells /* asynchronous incoming call management */ 4408e0e7c8SDavid Howells static const struct afs_wait_mode afs_async_incoming_call = { 4508e0e7c8SDavid Howells .rx_wakeup = afs_wake_up_async_call, 4608e0e7c8SDavid Howells }; 4708e0e7c8SDavid Howells 4808e0e7c8SDavid Howells /* asynchronous incoming call initial processing */ 4908e0e7c8SDavid Howells static const struct afs_call_type afs_RXCMxxxx = { 5000d3b7a4SDavid Howells .name = "CB.xxxx", 5108e0e7c8SDavid Howells .deliver = afs_deliver_cm_op_id, 5208e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 5308e0e7c8SDavid Howells }; 5408e0e7c8SDavid Howells 5508e0e7c8SDavid Howells static void afs_collect_incoming_call(struct work_struct *); 5608e0e7c8SDavid Howells 5708e0e7c8SDavid Howells static struct sk_buff_head afs_incoming_calls; 5808e0e7c8SDavid Howells static DECLARE_WORK(afs_collect_incoming_call_work, afs_collect_incoming_call); 5908e0e7c8SDavid Howells 6008e0e7c8SDavid Howells /* 6108e0e7c8SDavid Howells * open an RxRPC socket and bind it to be a server for callback notifications 6208e0e7c8SDavid Howells * - the socket is left in blocking mode and non-blocking ops use MSG_DONTWAIT 6308e0e7c8SDavid Howells */ 6408e0e7c8SDavid Howells int afs_open_socket(void) 6508e0e7c8SDavid Howells { 6608e0e7c8SDavid Howells struct sockaddr_rxrpc srx; 6708e0e7c8SDavid Howells struct socket *socket; 6808e0e7c8SDavid Howells int ret; 6908e0e7c8SDavid Howells 7008e0e7c8SDavid Howells _enter(""); 7108e0e7c8SDavid Howells 7208e0e7c8SDavid Howells skb_queue_head_init(&afs_incoming_calls); 7308e0e7c8SDavid Howells 7408e0e7c8SDavid Howells afs_async_calls = create_singlethread_workqueue("kafsd"); 7508e0e7c8SDavid Howells if (!afs_async_calls) { 7608e0e7c8SDavid Howells _leave(" = -ENOMEM [wq]"); 7708e0e7c8SDavid Howells return -ENOMEM; 7808e0e7c8SDavid Howells } 7908e0e7c8SDavid Howells 8008e0e7c8SDavid Howells ret = sock_create_kern(AF_RXRPC, SOCK_DGRAM, PF_INET, &socket); 8108e0e7c8SDavid Howells if (ret < 0) { 8208e0e7c8SDavid Howells destroy_workqueue(afs_async_calls); 8308e0e7c8SDavid Howells _leave(" = %d [socket]", ret); 8408e0e7c8SDavid Howells return ret; 8508e0e7c8SDavid Howells } 8608e0e7c8SDavid Howells 8708e0e7c8SDavid Howells socket->sk->sk_allocation = GFP_NOFS; 8808e0e7c8SDavid Howells 8908e0e7c8SDavid Howells /* bind the callback manager's address to make this a server socket */ 9008e0e7c8SDavid Howells srx.srx_family = AF_RXRPC; 9108e0e7c8SDavid Howells srx.srx_service = CM_SERVICE; 9208e0e7c8SDavid Howells srx.transport_type = SOCK_DGRAM; 9308e0e7c8SDavid Howells srx.transport_len = sizeof(srx.transport.sin); 9408e0e7c8SDavid Howells srx.transport.sin.sin_family = AF_INET; 9508e0e7c8SDavid Howells srx.transport.sin.sin_port = htons(AFS_CM_PORT); 9608e0e7c8SDavid Howells memset(&srx.transport.sin.sin_addr, 0, 9708e0e7c8SDavid Howells sizeof(srx.transport.sin.sin_addr)); 9808e0e7c8SDavid Howells 9908e0e7c8SDavid Howells ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); 10008e0e7c8SDavid Howells if (ret < 0) { 10108e0e7c8SDavid Howells sock_release(socket); 10208e0e7c8SDavid Howells _leave(" = %d [bind]", ret); 10308e0e7c8SDavid Howells return ret; 10408e0e7c8SDavid Howells } 10508e0e7c8SDavid Howells 10608e0e7c8SDavid Howells rxrpc_kernel_intercept_rx_messages(socket, afs_rx_interceptor); 10708e0e7c8SDavid Howells 10808e0e7c8SDavid Howells afs_socket = socket; 10908e0e7c8SDavid Howells _leave(" = 0"); 11008e0e7c8SDavid Howells return 0; 11108e0e7c8SDavid Howells } 11208e0e7c8SDavid Howells 11308e0e7c8SDavid Howells /* 11408e0e7c8SDavid Howells * close the RxRPC socket AFS was using 11508e0e7c8SDavid Howells */ 11608e0e7c8SDavid Howells void afs_close_socket(void) 11708e0e7c8SDavid Howells { 11808e0e7c8SDavid Howells _enter(""); 11908e0e7c8SDavid Howells 12008e0e7c8SDavid Howells sock_release(afs_socket); 12108e0e7c8SDavid Howells 12208e0e7c8SDavid Howells _debug("dework"); 12308e0e7c8SDavid Howells destroy_workqueue(afs_async_calls); 12400d3b7a4SDavid Howells 12500d3b7a4SDavid Howells ASSERTCMP(atomic_read(&afs_outstanding_skbs), ==, 0); 12600d3b7a4SDavid Howells ASSERTCMP(atomic_read(&afs_outstanding_calls), ==, 0); 12708e0e7c8SDavid Howells _leave(""); 12808e0e7c8SDavid Howells } 12908e0e7c8SDavid Howells 13008e0e7c8SDavid Howells /* 13100d3b7a4SDavid Howells * note that the data in a socket buffer is now delivered and that the buffer 13200d3b7a4SDavid Howells * should be freed 13300d3b7a4SDavid Howells */ 13400d3b7a4SDavid Howells static void afs_data_delivered(struct sk_buff *skb) 13500d3b7a4SDavid Howells { 13600d3b7a4SDavid Howells if (!skb) { 13700d3b7a4SDavid Howells _debug("DLVR NULL [%d]", atomic_read(&afs_outstanding_skbs)); 13800d3b7a4SDavid Howells dump_stack(); 13900d3b7a4SDavid Howells } else { 14000d3b7a4SDavid Howells _debug("DLVR %p{%u} [%d]", 14100d3b7a4SDavid Howells skb, skb->mark, atomic_read(&afs_outstanding_skbs)); 14200d3b7a4SDavid Howells if (atomic_dec_return(&afs_outstanding_skbs) == -1) 14300d3b7a4SDavid Howells BUG(); 14400d3b7a4SDavid Howells rxrpc_kernel_data_delivered(skb); 14500d3b7a4SDavid Howells } 14600d3b7a4SDavid Howells } 14700d3b7a4SDavid Howells 14800d3b7a4SDavid Howells /* 14900d3b7a4SDavid Howells * free a socket buffer 15000d3b7a4SDavid Howells */ 15100d3b7a4SDavid Howells static void afs_free_skb(struct sk_buff *skb) 15200d3b7a4SDavid Howells { 15300d3b7a4SDavid Howells if (!skb) { 15400d3b7a4SDavid Howells _debug("FREE NULL [%d]", atomic_read(&afs_outstanding_skbs)); 15500d3b7a4SDavid Howells dump_stack(); 15600d3b7a4SDavid Howells } else { 15700d3b7a4SDavid Howells _debug("FREE %p{%u} [%d]", 15800d3b7a4SDavid Howells skb, skb->mark, atomic_read(&afs_outstanding_skbs)); 15900d3b7a4SDavid Howells if (atomic_dec_return(&afs_outstanding_skbs) == -1) 16000d3b7a4SDavid Howells BUG(); 16100d3b7a4SDavid Howells rxrpc_kernel_free_skb(skb); 16200d3b7a4SDavid Howells } 16300d3b7a4SDavid Howells } 16400d3b7a4SDavid Howells 16500d3b7a4SDavid Howells /* 16600d3b7a4SDavid Howells * free a call 16700d3b7a4SDavid Howells */ 16800d3b7a4SDavid Howells static void afs_free_call(struct afs_call *call) 16900d3b7a4SDavid Howells { 17000d3b7a4SDavid Howells _debug("DONE %p{%s} [%d]", 17100d3b7a4SDavid Howells call, call->type->name, atomic_read(&afs_outstanding_calls)); 17200d3b7a4SDavid Howells if (atomic_dec_return(&afs_outstanding_calls) == -1) 17300d3b7a4SDavid Howells BUG(); 17400d3b7a4SDavid Howells 17500d3b7a4SDavid Howells ASSERTCMP(call->rxcall, ==, NULL); 17600d3b7a4SDavid Howells ASSERT(!work_pending(&call->async_work)); 17700d3b7a4SDavid Howells ASSERT(skb_queue_empty(&call->rx_queue)); 17800d3b7a4SDavid Howells ASSERT(call->type->name != NULL); 17900d3b7a4SDavid Howells 18000d3b7a4SDavid Howells kfree(call->request); 18100d3b7a4SDavid Howells kfree(call); 18200d3b7a4SDavid Howells } 18300d3b7a4SDavid Howells 18400d3b7a4SDavid Howells /* 18508e0e7c8SDavid Howells * allocate a call with flat request and reply buffers 18608e0e7c8SDavid Howells */ 18708e0e7c8SDavid Howells struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type, 18808e0e7c8SDavid Howells size_t request_size, size_t reply_size) 18908e0e7c8SDavid Howells { 19008e0e7c8SDavid Howells struct afs_call *call; 19108e0e7c8SDavid Howells 19208e0e7c8SDavid Howells call = kzalloc(sizeof(*call), GFP_NOFS); 19308e0e7c8SDavid Howells if (!call) 19408e0e7c8SDavid Howells goto nomem_call; 19508e0e7c8SDavid Howells 19600d3b7a4SDavid Howells _debug("CALL %p{%s} [%d]", 19700d3b7a4SDavid Howells call, type->name, atomic_read(&afs_outstanding_calls)); 19800d3b7a4SDavid Howells atomic_inc(&afs_outstanding_calls); 19908e0e7c8SDavid Howells 20008e0e7c8SDavid Howells call->type = type; 20108e0e7c8SDavid Howells call->request_size = request_size; 20208e0e7c8SDavid Howells call->reply_max = reply_size; 20308e0e7c8SDavid Howells 20400d3b7a4SDavid Howells if (request_size) { 20500d3b7a4SDavid Howells call->request = kmalloc(request_size, GFP_NOFS); 20600d3b7a4SDavid Howells if (!call->request) 20700d3b7a4SDavid Howells goto nomem_free; 20800d3b7a4SDavid Howells } 20900d3b7a4SDavid Howells 21000d3b7a4SDavid Howells if (reply_size) { 21100d3b7a4SDavid Howells call->buffer = kmalloc(reply_size, GFP_NOFS); 21200d3b7a4SDavid Howells if (!call->buffer) 21300d3b7a4SDavid Howells goto nomem_free; 21400d3b7a4SDavid Howells } 21500d3b7a4SDavid Howells 21608e0e7c8SDavid Howells init_waitqueue_head(&call->waitq); 21708e0e7c8SDavid Howells skb_queue_head_init(&call->rx_queue); 21808e0e7c8SDavid Howells return call; 21908e0e7c8SDavid Howells 22000d3b7a4SDavid Howells nomem_free: 22100d3b7a4SDavid Howells afs_free_call(call); 22208e0e7c8SDavid Howells nomem_call: 22308e0e7c8SDavid Howells return NULL; 22408e0e7c8SDavid Howells } 22508e0e7c8SDavid Howells 22608e0e7c8SDavid Howells /* 22708e0e7c8SDavid Howells * clean up a call with flat buffer 22808e0e7c8SDavid Howells */ 22908e0e7c8SDavid Howells void afs_flat_call_destructor(struct afs_call *call) 23008e0e7c8SDavid Howells { 23108e0e7c8SDavid Howells _enter(""); 23208e0e7c8SDavid Howells 23308e0e7c8SDavid Howells kfree(call->request); 23408e0e7c8SDavid Howells call->request = NULL; 23508e0e7c8SDavid Howells kfree(call->buffer); 23608e0e7c8SDavid Howells call->buffer = NULL; 23708e0e7c8SDavid Howells } 23808e0e7c8SDavid Howells 23908e0e7c8SDavid Howells /* 24031143d5dSDavid Howells * attach the data from a bunch of pages on an inode to a call 24131143d5dSDavid Howells */ 24231143d5dSDavid Howells int afs_send_pages(struct afs_call *call, struct msghdr *msg, struct kvec *iov) 24331143d5dSDavid Howells { 24431143d5dSDavid Howells struct page *pages[8]; 24531143d5dSDavid Howells unsigned count, n, loop, offset, to; 24631143d5dSDavid Howells pgoff_t first = call->first, last = call->last; 24731143d5dSDavid Howells int ret; 24831143d5dSDavid Howells 24931143d5dSDavid Howells _enter(""); 25031143d5dSDavid Howells 25131143d5dSDavid Howells offset = call->first_offset; 25231143d5dSDavid Howells call->first_offset = 0; 25331143d5dSDavid Howells 25431143d5dSDavid Howells do { 25531143d5dSDavid Howells _debug("attach %lx-%lx", first, last); 25631143d5dSDavid Howells 25731143d5dSDavid Howells count = last - first + 1; 25831143d5dSDavid Howells if (count > ARRAY_SIZE(pages)) 25931143d5dSDavid Howells count = ARRAY_SIZE(pages); 26031143d5dSDavid Howells n = find_get_pages_contig(call->mapping, first, count, pages); 26131143d5dSDavid Howells ASSERTCMP(n, ==, count); 26231143d5dSDavid Howells 26331143d5dSDavid Howells loop = 0; 26431143d5dSDavid Howells do { 26531143d5dSDavid Howells msg->msg_flags = 0; 26631143d5dSDavid Howells to = PAGE_SIZE; 26731143d5dSDavid Howells if (first + loop >= last) 26831143d5dSDavid Howells to = call->last_to; 26931143d5dSDavid Howells else 27031143d5dSDavid Howells msg->msg_flags = MSG_MORE; 27131143d5dSDavid Howells iov->iov_base = kmap(pages[loop]) + offset; 27231143d5dSDavid Howells iov->iov_len = to - offset; 27331143d5dSDavid Howells offset = 0; 27431143d5dSDavid Howells 27531143d5dSDavid Howells _debug("- range %u-%u%s", 27631143d5dSDavid Howells offset, to, msg->msg_flags ? " [more]" : ""); 27731143d5dSDavid Howells msg->msg_iov = (struct iovec *) iov; 27831143d5dSDavid Howells msg->msg_iovlen = 1; 27931143d5dSDavid Howells 28031143d5dSDavid Howells /* have to change the state *before* sending the last 28131143d5dSDavid Howells * packet as RxRPC might give us the reply before it 28231143d5dSDavid Howells * returns from sending the request */ 28331143d5dSDavid Howells if (first + loop >= last) 28431143d5dSDavid Howells call->state = AFS_CALL_AWAIT_REPLY; 28531143d5dSDavid Howells ret = rxrpc_kernel_send_data(call->rxcall, msg, 28631143d5dSDavid Howells to - offset); 28731143d5dSDavid Howells kunmap(pages[loop]); 28831143d5dSDavid Howells if (ret < 0) 28931143d5dSDavid Howells break; 29031143d5dSDavid Howells } while (++loop < count); 29131143d5dSDavid Howells first += count; 29231143d5dSDavid Howells 29331143d5dSDavid Howells for (loop = 0; loop < count; loop++) 29431143d5dSDavid Howells put_page(pages[loop]); 29531143d5dSDavid Howells if (ret < 0) 29631143d5dSDavid Howells break; 2975bbf5d39SDavid Howells } while (first <= last); 29831143d5dSDavid Howells 29931143d5dSDavid Howells _leave(" = %d", ret); 30031143d5dSDavid Howells return ret; 30131143d5dSDavid Howells } 30231143d5dSDavid Howells 30331143d5dSDavid Howells /* 30408e0e7c8SDavid Howells * initiate a call 30508e0e7c8SDavid Howells */ 30608e0e7c8SDavid Howells int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, 30708e0e7c8SDavid Howells const struct afs_wait_mode *wait_mode) 30808e0e7c8SDavid Howells { 30908e0e7c8SDavid Howells struct sockaddr_rxrpc srx; 31008e0e7c8SDavid Howells struct rxrpc_call *rxcall; 31108e0e7c8SDavid Howells struct msghdr msg; 31208e0e7c8SDavid Howells struct kvec iov[1]; 31308e0e7c8SDavid Howells int ret; 31408e0e7c8SDavid Howells 31508e0e7c8SDavid Howells _enter("%x,{%d},", addr->s_addr, ntohs(call->port)); 31608e0e7c8SDavid Howells 31700d3b7a4SDavid Howells ASSERT(call->type != NULL); 31800d3b7a4SDavid Howells ASSERT(call->type->name != NULL); 31900d3b7a4SDavid Howells 32031143d5dSDavid Howells _debug("____MAKE %p{%s,%x} [%d]____", 32131143d5dSDavid Howells call, call->type->name, key_serial(call->key), 32231143d5dSDavid Howells atomic_read(&afs_outstanding_calls)); 32300d3b7a4SDavid Howells 32408e0e7c8SDavid Howells call->wait_mode = wait_mode; 32508e0e7c8SDavid Howells INIT_WORK(&call->async_work, afs_process_async_call); 32608e0e7c8SDavid Howells 32708e0e7c8SDavid Howells memset(&srx, 0, sizeof(srx)); 32808e0e7c8SDavid Howells srx.srx_family = AF_RXRPC; 32908e0e7c8SDavid Howells srx.srx_service = call->service_id; 33008e0e7c8SDavid Howells srx.transport_type = SOCK_DGRAM; 33108e0e7c8SDavid Howells srx.transport_len = sizeof(srx.transport.sin); 33208e0e7c8SDavid Howells srx.transport.sin.sin_family = AF_INET; 33308e0e7c8SDavid Howells srx.transport.sin.sin_port = call->port; 33408e0e7c8SDavid Howells memcpy(&srx.transport.sin.sin_addr, addr, 4); 33508e0e7c8SDavid Howells 33608e0e7c8SDavid Howells /* create a call */ 33708e0e7c8SDavid Howells rxcall = rxrpc_kernel_begin_call(afs_socket, &srx, call->key, 33808e0e7c8SDavid Howells (unsigned long) call, gfp); 33900d3b7a4SDavid Howells call->key = NULL; 34008e0e7c8SDavid Howells if (IS_ERR(rxcall)) { 34108e0e7c8SDavid Howells ret = PTR_ERR(rxcall); 34208e0e7c8SDavid Howells goto error_kill_call; 34308e0e7c8SDavid Howells } 34408e0e7c8SDavid Howells 34508e0e7c8SDavid Howells call->rxcall = rxcall; 34608e0e7c8SDavid Howells 34708e0e7c8SDavid Howells /* send the request */ 34808e0e7c8SDavid Howells iov[0].iov_base = call->request; 34908e0e7c8SDavid Howells iov[0].iov_len = call->request_size; 35008e0e7c8SDavid Howells 35108e0e7c8SDavid Howells msg.msg_name = NULL; 35208e0e7c8SDavid Howells msg.msg_namelen = 0; 35308e0e7c8SDavid Howells msg.msg_iov = (struct iovec *) iov; 35408e0e7c8SDavid Howells msg.msg_iovlen = 1; 35508e0e7c8SDavid Howells msg.msg_control = NULL; 35608e0e7c8SDavid Howells msg.msg_controllen = 0; 35731143d5dSDavid Howells msg.msg_flags = (call->send_pages ? MSG_MORE : 0); 35808e0e7c8SDavid Howells 35908e0e7c8SDavid Howells /* have to change the state *before* sending the last packet as RxRPC 36008e0e7c8SDavid Howells * might give us the reply before it returns from sending the 36108e0e7c8SDavid Howells * request */ 36231143d5dSDavid Howells if (!call->send_pages) 36308e0e7c8SDavid Howells call->state = AFS_CALL_AWAIT_REPLY; 36408e0e7c8SDavid Howells ret = rxrpc_kernel_send_data(rxcall, &msg, call->request_size); 36508e0e7c8SDavid Howells if (ret < 0) 36608e0e7c8SDavid Howells goto error_do_abort; 36708e0e7c8SDavid Howells 36831143d5dSDavid Howells if (call->send_pages) { 36931143d5dSDavid Howells ret = afs_send_pages(call, &msg, iov); 37031143d5dSDavid Howells if (ret < 0) 37131143d5dSDavid Howells goto error_do_abort; 37231143d5dSDavid Howells } 37331143d5dSDavid Howells 37408e0e7c8SDavid Howells /* at this point, an async call may no longer exist as it may have 37508e0e7c8SDavid Howells * already completed */ 37608e0e7c8SDavid Howells return wait_mode->wait(call); 37708e0e7c8SDavid Howells 37808e0e7c8SDavid Howells error_do_abort: 37908e0e7c8SDavid Howells rxrpc_kernel_abort_call(rxcall, RX_USER_ABORT); 38008e0e7c8SDavid Howells rxrpc_kernel_end_call(rxcall); 38100d3b7a4SDavid Howells call->rxcall = NULL; 38208e0e7c8SDavid Howells error_kill_call: 38308e0e7c8SDavid Howells call->type->destructor(call); 38400d3b7a4SDavid Howells afs_free_call(call); 38508e0e7c8SDavid Howells _leave(" = %d", ret); 38608e0e7c8SDavid Howells return ret; 38708e0e7c8SDavid Howells } 38808e0e7c8SDavid Howells 38908e0e7c8SDavid Howells /* 39008e0e7c8SDavid Howells * handles intercepted messages that were arriving in the socket's Rx queue 39108e0e7c8SDavid Howells * - called with the socket receive queue lock held to ensure message ordering 39208e0e7c8SDavid Howells * - called with softirqs disabled 39308e0e7c8SDavid Howells */ 39408e0e7c8SDavid Howells static void afs_rx_interceptor(struct sock *sk, unsigned long user_call_ID, 39508e0e7c8SDavid Howells struct sk_buff *skb) 39608e0e7c8SDavid Howells { 39708e0e7c8SDavid Howells struct afs_call *call = (struct afs_call *) user_call_ID; 39808e0e7c8SDavid Howells 39908e0e7c8SDavid Howells _enter("%p,,%u", call, skb->mark); 40008e0e7c8SDavid Howells 40100d3b7a4SDavid Howells _debug("ICPT %p{%u} [%d]", 40200d3b7a4SDavid Howells skb, skb->mark, atomic_read(&afs_outstanding_skbs)); 40300d3b7a4SDavid Howells 40408e0e7c8SDavid Howells ASSERTCMP(sk, ==, afs_socket->sk); 40500d3b7a4SDavid Howells atomic_inc(&afs_outstanding_skbs); 40608e0e7c8SDavid Howells 40708e0e7c8SDavid Howells if (!call) { 40808e0e7c8SDavid Howells /* its an incoming call for our callback service */ 40900d3b7a4SDavid Howells skb_queue_tail(&afs_incoming_calls, skb); 41008e0e7c8SDavid Howells schedule_work(&afs_collect_incoming_call_work); 41108e0e7c8SDavid Howells } else { 41208e0e7c8SDavid Howells /* route the messages directly to the appropriate call */ 41300d3b7a4SDavid Howells skb_queue_tail(&call->rx_queue, skb); 41408e0e7c8SDavid Howells call->wait_mode->rx_wakeup(call); 41508e0e7c8SDavid Howells } 41608e0e7c8SDavid Howells 41708e0e7c8SDavid Howells _leave(""); 41808e0e7c8SDavid Howells } 41908e0e7c8SDavid Howells 42008e0e7c8SDavid Howells /* 42108e0e7c8SDavid Howells * deliver messages to a call 42208e0e7c8SDavid Howells */ 42308e0e7c8SDavid Howells static void afs_deliver_to_call(struct afs_call *call) 42408e0e7c8SDavid Howells { 42508e0e7c8SDavid Howells struct sk_buff *skb; 42608e0e7c8SDavid Howells bool last; 42708e0e7c8SDavid Howells u32 abort_code; 42808e0e7c8SDavid Howells int ret; 42908e0e7c8SDavid Howells 43008e0e7c8SDavid Howells _enter(""); 43108e0e7c8SDavid Howells 43208e0e7c8SDavid Howells while ((call->state == AFS_CALL_AWAIT_REPLY || 43308e0e7c8SDavid Howells call->state == AFS_CALL_AWAIT_OP_ID || 43408e0e7c8SDavid Howells call->state == AFS_CALL_AWAIT_REQUEST || 43508e0e7c8SDavid Howells call->state == AFS_CALL_AWAIT_ACK) && 43608e0e7c8SDavid Howells (skb = skb_dequeue(&call->rx_queue))) { 43708e0e7c8SDavid Howells switch (skb->mark) { 43808e0e7c8SDavid Howells case RXRPC_SKB_MARK_DATA: 43908e0e7c8SDavid Howells _debug("Rcv DATA"); 44008e0e7c8SDavid Howells last = rxrpc_kernel_is_data_last(skb); 44108e0e7c8SDavid Howells ret = call->type->deliver(call, skb, last); 44208e0e7c8SDavid Howells switch (ret) { 44308e0e7c8SDavid Howells case 0: 44408e0e7c8SDavid Howells if (last && 44508e0e7c8SDavid Howells call->state == AFS_CALL_AWAIT_REPLY) 44608e0e7c8SDavid Howells call->state = AFS_CALL_COMPLETE; 44708e0e7c8SDavid Howells break; 44808e0e7c8SDavid Howells case -ENOTCONN: 44908e0e7c8SDavid Howells abort_code = RX_CALL_DEAD; 45008e0e7c8SDavid Howells goto do_abort; 45108e0e7c8SDavid Howells case -ENOTSUPP: 45208e0e7c8SDavid Howells abort_code = RX_INVALID_OPERATION; 45308e0e7c8SDavid Howells goto do_abort; 45408e0e7c8SDavid Howells default: 45508e0e7c8SDavid Howells abort_code = RXGEN_CC_UNMARSHAL; 45608e0e7c8SDavid Howells if (call->state != AFS_CALL_AWAIT_REPLY) 45708e0e7c8SDavid Howells abort_code = RXGEN_SS_UNMARSHAL; 45808e0e7c8SDavid Howells do_abort: 45908e0e7c8SDavid Howells rxrpc_kernel_abort_call(call->rxcall, 46008e0e7c8SDavid Howells abort_code); 46108e0e7c8SDavid Howells call->error = ret; 46208e0e7c8SDavid Howells call->state = AFS_CALL_ERROR; 46308e0e7c8SDavid Howells break; 46408e0e7c8SDavid Howells } 46500d3b7a4SDavid Howells afs_data_delivered(skb); 46608e0e7c8SDavid Howells skb = NULL; 46700d3b7a4SDavid Howells continue; 46808e0e7c8SDavid Howells case RXRPC_SKB_MARK_FINAL_ACK: 46908e0e7c8SDavid Howells _debug("Rcv ACK"); 47008e0e7c8SDavid Howells call->state = AFS_CALL_COMPLETE; 47108e0e7c8SDavid Howells break; 47208e0e7c8SDavid Howells case RXRPC_SKB_MARK_BUSY: 47308e0e7c8SDavid Howells _debug("Rcv BUSY"); 47408e0e7c8SDavid Howells call->error = -EBUSY; 47508e0e7c8SDavid Howells call->state = AFS_CALL_BUSY; 47608e0e7c8SDavid Howells break; 47708e0e7c8SDavid Howells case RXRPC_SKB_MARK_REMOTE_ABORT: 47808e0e7c8SDavid Howells abort_code = rxrpc_kernel_get_abort_code(skb); 47908e0e7c8SDavid Howells call->error = call->type->abort_to_error(abort_code); 48008e0e7c8SDavid Howells call->state = AFS_CALL_ABORTED; 48108e0e7c8SDavid Howells _debug("Rcv ABORT %u -> %d", abort_code, call->error); 48208e0e7c8SDavid Howells break; 48308e0e7c8SDavid Howells case RXRPC_SKB_MARK_NET_ERROR: 48408e0e7c8SDavid Howells call->error = -rxrpc_kernel_get_error_number(skb); 48508e0e7c8SDavid Howells call->state = AFS_CALL_ERROR; 48608e0e7c8SDavid Howells _debug("Rcv NET ERROR %d", call->error); 48708e0e7c8SDavid Howells break; 48808e0e7c8SDavid Howells case RXRPC_SKB_MARK_LOCAL_ERROR: 48908e0e7c8SDavid Howells call->error = -rxrpc_kernel_get_error_number(skb); 49008e0e7c8SDavid Howells call->state = AFS_CALL_ERROR; 49108e0e7c8SDavid Howells _debug("Rcv LOCAL ERROR %d", call->error); 49208e0e7c8SDavid Howells break; 49308e0e7c8SDavid Howells default: 49408e0e7c8SDavid Howells BUG(); 49508e0e7c8SDavid Howells break; 49608e0e7c8SDavid Howells } 49708e0e7c8SDavid Howells 49800d3b7a4SDavid Howells afs_free_skb(skb); 49908e0e7c8SDavid Howells } 50008e0e7c8SDavid Howells 50108e0e7c8SDavid Howells /* make sure the queue is empty if the call is done with (we might have 50208e0e7c8SDavid Howells * aborted the call early because of an unmarshalling error) */ 50308e0e7c8SDavid Howells if (call->state >= AFS_CALL_COMPLETE) { 50408e0e7c8SDavid Howells while ((skb = skb_dequeue(&call->rx_queue))) 50500d3b7a4SDavid Howells afs_free_skb(skb); 50608e0e7c8SDavid Howells if (call->incoming) { 50708e0e7c8SDavid Howells rxrpc_kernel_end_call(call->rxcall); 50800d3b7a4SDavid Howells call->rxcall = NULL; 50908e0e7c8SDavid Howells call->type->destructor(call); 51000d3b7a4SDavid Howells afs_free_call(call); 51108e0e7c8SDavid Howells } 51208e0e7c8SDavid Howells } 51308e0e7c8SDavid Howells 51408e0e7c8SDavid Howells _leave(""); 51508e0e7c8SDavid Howells } 51608e0e7c8SDavid Howells 51708e0e7c8SDavid Howells /* 51808e0e7c8SDavid Howells * wait synchronously for a call to complete 51908e0e7c8SDavid Howells */ 52008e0e7c8SDavid Howells static int afs_wait_for_call_to_complete(struct afs_call *call) 52108e0e7c8SDavid Howells { 52208e0e7c8SDavid Howells struct sk_buff *skb; 52308e0e7c8SDavid Howells int ret; 52408e0e7c8SDavid Howells 52508e0e7c8SDavid Howells DECLARE_WAITQUEUE(myself, current); 52608e0e7c8SDavid Howells 52708e0e7c8SDavid Howells _enter(""); 52808e0e7c8SDavid Howells 52908e0e7c8SDavid Howells add_wait_queue(&call->waitq, &myself); 53008e0e7c8SDavid Howells for (;;) { 53108e0e7c8SDavid Howells set_current_state(TASK_INTERRUPTIBLE); 53208e0e7c8SDavid Howells 53308e0e7c8SDavid Howells /* deliver any messages that are in the queue */ 53408e0e7c8SDavid Howells if (!skb_queue_empty(&call->rx_queue)) { 53508e0e7c8SDavid Howells __set_current_state(TASK_RUNNING); 53608e0e7c8SDavid Howells afs_deliver_to_call(call); 53708e0e7c8SDavid Howells continue; 53808e0e7c8SDavid Howells } 53908e0e7c8SDavid Howells 54008e0e7c8SDavid Howells ret = call->error; 54108e0e7c8SDavid Howells if (call->state >= AFS_CALL_COMPLETE) 54208e0e7c8SDavid Howells break; 54308e0e7c8SDavid Howells ret = -EINTR; 54408e0e7c8SDavid Howells if (signal_pending(current)) 54508e0e7c8SDavid Howells break; 54608e0e7c8SDavid Howells schedule(); 54708e0e7c8SDavid Howells } 54808e0e7c8SDavid Howells 54908e0e7c8SDavid Howells remove_wait_queue(&call->waitq, &myself); 55008e0e7c8SDavid Howells __set_current_state(TASK_RUNNING); 55108e0e7c8SDavid Howells 55208e0e7c8SDavid Howells /* kill the call */ 55308e0e7c8SDavid Howells if (call->state < AFS_CALL_COMPLETE) { 55408e0e7c8SDavid Howells _debug("call incomplete"); 55508e0e7c8SDavid Howells rxrpc_kernel_abort_call(call->rxcall, RX_CALL_DEAD); 55608e0e7c8SDavid Howells while ((skb = skb_dequeue(&call->rx_queue))) 55700d3b7a4SDavid Howells afs_free_skb(skb); 55808e0e7c8SDavid Howells } 55908e0e7c8SDavid Howells 56008e0e7c8SDavid Howells _debug("call complete"); 56108e0e7c8SDavid Howells rxrpc_kernel_end_call(call->rxcall); 56200d3b7a4SDavid Howells call->rxcall = NULL; 56308e0e7c8SDavid Howells call->type->destructor(call); 56400d3b7a4SDavid Howells afs_free_call(call); 56508e0e7c8SDavid Howells _leave(" = %d", ret); 56608e0e7c8SDavid Howells return ret; 56708e0e7c8SDavid Howells } 56808e0e7c8SDavid Howells 56908e0e7c8SDavid Howells /* 57008e0e7c8SDavid Howells * wake up a waiting call 57108e0e7c8SDavid Howells */ 57208e0e7c8SDavid Howells static void afs_wake_up_call_waiter(struct afs_call *call) 57308e0e7c8SDavid Howells { 57408e0e7c8SDavid Howells wake_up(&call->waitq); 57508e0e7c8SDavid Howells } 57608e0e7c8SDavid Howells 57708e0e7c8SDavid Howells /* 57808e0e7c8SDavid Howells * wake up an asynchronous call 57908e0e7c8SDavid Howells */ 58008e0e7c8SDavid Howells static void afs_wake_up_async_call(struct afs_call *call) 58108e0e7c8SDavid Howells { 58208e0e7c8SDavid Howells _enter(""); 58308e0e7c8SDavid Howells queue_work(afs_async_calls, &call->async_work); 58408e0e7c8SDavid Howells } 58508e0e7c8SDavid Howells 58608e0e7c8SDavid Howells /* 58708e0e7c8SDavid Howells * put a call into asynchronous mode 58808e0e7c8SDavid Howells * - mustn't touch the call descriptor as the call my have completed by the 58908e0e7c8SDavid Howells * time we get here 59008e0e7c8SDavid Howells */ 59108e0e7c8SDavid Howells static int afs_dont_wait_for_call_to_complete(struct afs_call *call) 59208e0e7c8SDavid Howells { 59308e0e7c8SDavid Howells _enter(""); 59408e0e7c8SDavid Howells return -EINPROGRESS; 59508e0e7c8SDavid Howells } 59608e0e7c8SDavid Howells 59708e0e7c8SDavid Howells /* 59808e0e7c8SDavid Howells * delete an asynchronous call 59908e0e7c8SDavid Howells */ 60008e0e7c8SDavid Howells static void afs_delete_async_call(struct work_struct *work) 60108e0e7c8SDavid Howells { 60208e0e7c8SDavid Howells struct afs_call *call = 60308e0e7c8SDavid Howells container_of(work, struct afs_call, async_work); 60408e0e7c8SDavid Howells 60508e0e7c8SDavid Howells _enter(""); 60608e0e7c8SDavid Howells 60700d3b7a4SDavid Howells afs_free_call(call); 60808e0e7c8SDavid Howells 60908e0e7c8SDavid Howells _leave(""); 61008e0e7c8SDavid Howells } 61108e0e7c8SDavid Howells 61208e0e7c8SDavid Howells /* 61308e0e7c8SDavid Howells * perform processing on an asynchronous call 61408e0e7c8SDavid Howells * - on a multiple-thread workqueue this work item may try to run on several 61508e0e7c8SDavid Howells * CPUs at the same time 61608e0e7c8SDavid Howells */ 61708e0e7c8SDavid Howells static void afs_process_async_call(struct work_struct *work) 61808e0e7c8SDavid Howells { 61908e0e7c8SDavid Howells struct afs_call *call = 62008e0e7c8SDavid Howells container_of(work, struct afs_call, async_work); 62108e0e7c8SDavid Howells 62208e0e7c8SDavid Howells _enter(""); 62308e0e7c8SDavid Howells 62408e0e7c8SDavid Howells if (!skb_queue_empty(&call->rx_queue)) 62508e0e7c8SDavid Howells afs_deliver_to_call(call); 62608e0e7c8SDavid Howells 62708e0e7c8SDavid Howells if (call->state >= AFS_CALL_COMPLETE && call->wait_mode) { 62808e0e7c8SDavid Howells if (call->wait_mode->async_complete) 62908e0e7c8SDavid Howells call->wait_mode->async_complete(call->reply, 63008e0e7c8SDavid Howells call->error); 63108e0e7c8SDavid Howells call->reply = NULL; 63208e0e7c8SDavid Howells 63308e0e7c8SDavid Howells /* kill the call */ 63408e0e7c8SDavid Howells rxrpc_kernel_end_call(call->rxcall); 63500d3b7a4SDavid Howells call->rxcall = NULL; 63608e0e7c8SDavid Howells if (call->type->destructor) 63708e0e7c8SDavid Howells call->type->destructor(call); 63808e0e7c8SDavid Howells 63908e0e7c8SDavid Howells /* we can't just delete the call because the work item may be 64008e0e7c8SDavid Howells * queued */ 64108e0e7c8SDavid Howells PREPARE_WORK(&call->async_work, afs_delete_async_call); 64208e0e7c8SDavid Howells queue_work(afs_async_calls, &call->async_work); 64308e0e7c8SDavid Howells } 64408e0e7c8SDavid Howells 64508e0e7c8SDavid Howells _leave(""); 64608e0e7c8SDavid Howells } 64708e0e7c8SDavid Howells 64808e0e7c8SDavid Howells /* 64908e0e7c8SDavid Howells * empty a socket buffer into a flat reply buffer 65008e0e7c8SDavid Howells */ 65108e0e7c8SDavid Howells void afs_transfer_reply(struct afs_call *call, struct sk_buff *skb) 65208e0e7c8SDavid Howells { 65308e0e7c8SDavid Howells size_t len = skb->len; 65408e0e7c8SDavid Howells 65508e0e7c8SDavid Howells if (skb_copy_bits(skb, 0, call->buffer + call->reply_size, len) < 0) 65608e0e7c8SDavid Howells BUG(); 65708e0e7c8SDavid Howells call->reply_size += len; 65808e0e7c8SDavid Howells } 65908e0e7c8SDavid Howells 66008e0e7c8SDavid Howells /* 66108e0e7c8SDavid Howells * accept the backlog of incoming calls 66208e0e7c8SDavid Howells */ 66308e0e7c8SDavid Howells static void afs_collect_incoming_call(struct work_struct *work) 66408e0e7c8SDavid Howells { 66508e0e7c8SDavid Howells struct rxrpc_call *rxcall; 66608e0e7c8SDavid Howells struct afs_call *call = NULL; 66708e0e7c8SDavid Howells struct sk_buff *skb; 66808e0e7c8SDavid Howells 66908e0e7c8SDavid Howells while ((skb = skb_dequeue(&afs_incoming_calls))) { 67008e0e7c8SDavid Howells _debug("new call"); 67108e0e7c8SDavid Howells 67208e0e7c8SDavid Howells /* don't need the notification */ 67300d3b7a4SDavid Howells afs_free_skb(skb); 67408e0e7c8SDavid Howells 67508e0e7c8SDavid Howells if (!call) { 67608e0e7c8SDavid Howells call = kzalloc(sizeof(struct afs_call), GFP_KERNEL); 67708e0e7c8SDavid Howells if (!call) { 67808e0e7c8SDavid Howells rxrpc_kernel_reject_call(afs_socket); 67908e0e7c8SDavid Howells return; 68008e0e7c8SDavid Howells } 68108e0e7c8SDavid Howells 68208e0e7c8SDavid Howells INIT_WORK(&call->async_work, afs_process_async_call); 68308e0e7c8SDavid Howells call->wait_mode = &afs_async_incoming_call; 68408e0e7c8SDavid Howells call->type = &afs_RXCMxxxx; 68508e0e7c8SDavid Howells init_waitqueue_head(&call->waitq); 68608e0e7c8SDavid Howells skb_queue_head_init(&call->rx_queue); 68708e0e7c8SDavid Howells call->state = AFS_CALL_AWAIT_OP_ID; 68800d3b7a4SDavid Howells 68900d3b7a4SDavid Howells _debug("CALL %p{%s} [%d]", 69000d3b7a4SDavid Howells call, call->type->name, 69100d3b7a4SDavid Howells atomic_read(&afs_outstanding_calls)); 69200d3b7a4SDavid Howells atomic_inc(&afs_outstanding_calls); 69308e0e7c8SDavid Howells } 69408e0e7c8SDavid Howells 69508e0e7c8SDavid Howells rxcall = rxrpc_kernel_accept_call(afs_socket, 69608e0e7c8SDavid Howells (unsigned long) call); 69708e0e7c8SDavid Howells if (!IS_ERR(rxcall)) { 69808e0e7c8SDavid Howells call->rxcall = rxcall; 69908e0e7c8SDavid Howells call = NULL; 70008e0e7c8SDavid Howells } 70108e0e7c8SDavid Howells } 70208e0e7c8SDavid Howells 70300d3b7a4SDavid Howells if (call) 70400d3b7a4SDavid Howells afs_free_call(call); 70508e0e7c8SDavid Howells } 70608e0e7c8SDavid Howells 70708e0e7c8SDavid Howells /* 70808e0e7c8SDavid Howells * grab the operation ID from an incoming cache manager call 70908e0e7c8SDavid Howells */ 71008e0e7c8SDavid Howells static int afs_deliver_cm_op_id(struct afs_call *call, struct sk_buff *skb, 71108e0e7c8SDavid Howells bool last) 71208e0e7c8SDavid Howells { 71308e0e7c8SDavid Howells size_t len = skb->len; 71408e0e7c8SDavid Howells void *oibuf = (void *) &call->operation_ID; 71508e0e7c8SDavid Howells 71608e0e7c8SDavid Howells _enter("{%u},{%zu},%d", call->offset, len, last); 71708e0e7c8SDavid Howells 71808e0e7c8SDavid Howells ASSERTCMP(call->offset, <, 4); 71908e0e7c8SDavid Howells 72008e0e7c8SDavid Howells /* the operation ID forms the first four bytes of the request data */ 72108e0e7c8SDavid Howells len = min_t(size_t, len, 4 - call->offset); 72208e0e7c8SDavid Howells if (skb_copy_bits(skb, 0, oibuf + call->offset, len) < 0) 72308e0e7c8SDavid Howells BUG(); 72408e0e7c8SDavid Howells if (!pskb_pull(skb, len)) 72508e0e7c8SDavid Howells BUG(); 72608e0e7c8SDavid Howells call->offset += len; 72708e0e7c8SDavid Howells 72808e0e7c8SDavid Howells if (call->offset < 4) { 72908e0e7c8SDavid Howells if (last) { 73008e0e7c8SDavid Howells _leave(" = -EBADMSG [op ID short]"); 73108e0e7c8SDavid Howells return -EBADMSG; 73208e0e7c8SDavid Howells } 73308e0e7c8SDavid Howells _leave(" = 0 [incomplete]"); 73408e0e7c8SDavid Howells return 0; 73508e0e7c8SDavid Howells } 73608e0e7c8SDavid Howells 73708e0e7c8SDavid Howells call->state = AFS_CALL_AWAIT_REQUEST; 73808e0e7c8SDavid Howells 73908e0e7c8SDavid Howells /* ask the cache manager to route the call (it'll change the call type 74008e0e7c8SDavid Howells * if successful) */ 74108e0e7c8SDavid Howells if (!afs_cm_incoming_call(call)) 74208e0e7c8SDavid Howells return -ENOTSUPP; 74308e0e7c8SDavid Howells 74408e0e7c8SDavid Howells /* pass responsibility for the remainer of this message off to the 74508e0e7c8SDavid Howells * cache manager op */ 74608e0e7c8SDavid Howells return call->type->deliver(call, skb, last); 74708e0e7c8SDavid Howells } 74808e0e7c8SDavid Howells 74908e0e7c8SDavid Howells /* 75008e0e7c8SDavid Howells * send an empty reply 75108e0e7c8SDavid Howells */ 75208e0e7c8SDavid Howells void afs_send_empty_reply(struct afs_call *call) 75308e0e7c8SDavid Howells { 75408e0e7c8SDavid Howells struct msghdr msg; 75508e0e7c8SDavid Howells struct iovec iov[1]; 75608e0e7c8SDavid Howells 75708e0e7c8SDavid Howells _enter(""); 75808e0e7c8SDavid Howells 75908e0e7c8SDavid Howells iov[0].iov_base = NULL; 76008e0e7c8SDavid Howells iov[0].iov_len = 0; 76108e0e7c8SDavid Howells msg.msg_name = NULL; 76208e0e7c8SDavid Howells msg.msg_namelen = 0; 76308e0e7c8SDavid Howells msg.msg_iov = iov; 76408e0e7c8SDavid Howells msg.msg_iovlen = 0; 76508e0e7c8SDavid Howells msg.msg_control = NULL; 76608e0e7c8SDavid Howells msg.msg_controllen = 0; 76708e0e7c8SDavid Howells msg.msg_flags = 0; 76808e0e7c8SDavid Howells 76908e0e7c8SDavid Howells call->state = AFS_CALL_AWAIT_ACK; 77008e0e7c8SDavid Howells switch (rxrpc_kernel_send_data(call->rxcall, &msg, 0)) { 77108e0e7c8SDavid Howells case 0: 77208e0e7c8SDavid Howells _leave(" [replied]"); 77308e0e7c8SDavid Howells return; 77408e0e7c8SDavid Howells 77508e0e7c8SDavid Howells case -ENOMEM: 77608e0e7c8SDavid Howells _debug("oom"); 77708e0e7c8SDavid Howells rxrpc_kernel_abort_call(call->rxcall, RX_USER_ABORT); 77808e0e7c8SDavid Howells default: 77908e0e7c8SDavid Howells rxrpc_kernel_end_call(call->rxcall); 78008e0e7c8SDavid Howells call->rxcall = NULL; 78108e0e7c8SDavid Howells call->type->destructor(call); 78200d3b7a4SDavid Howells afs_free_call(call); 78308e0e7c8SDavid Howells _leave(" [error]"); 78408e0e7c8SDavid Howells return; 78508e0e7c8SDavid Howells } 78608e0e7c8SDavid Howells } 78708e0e7c8SDavid Howells 78808e0e7c8SDavid Howells /* 789b908fe6bSDavid Howells * send a simple reply 790b908fe6bSDavid Howells */ 791b908fe6bSDavid Howells void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) 792b908fe6bSDavid Howells { 793b908fe6bSDavid Howells struct msghdr msg; 794b908fe6bSDavid Howells struct iovec iov[1]; 795b908fe6bSDavid Howells 796b908fe6bSDavid Howells _enter(""); 797b908fe6bSDavid Howells 798b908fe6bSDavid Howells iov[0].iov_base = (void *) buf; 799b908fe6bSDavid Howells iov[0].iov_len = len; 800b908fe6bSDavid Howells msg.msg_name = NULL; 801b908fe6bSDavid Howells msg.msg_namelen = 0; 802b908fe6bSDavid Howells msg.msg_iov = iov; 803b908fe6bSDavid Howells msg.msg_iovlen = 1; 804b908fe6bSDavid Howells msg.msg_control = NULL; 805b908fe6bSDavid Howells msg.msg_controllen = 0; 806b908fe6bSDavid Howells msg.msg_flags = 0; 807b908fe6bSDavid Howells 808b908fe6bSDavid Howells call->state = AFS_CALL_AWAIT_ACK; 809b908fe6bSDavid Howells switch (rxrpc_kernel_send_data(call->rxcall, &msg, len)) { 810b908fe6bSDavid Howells case 0: 811b908fe6bSDavid Howells _leave(" [replied]"); 812b908fe6bSDavid Howells return; 813b908fe6bSDavid Howells 814b908fe6bSDavid Howells case -ENOMEM: 815b908fe6bSDavid Howells _debug("oom"); 816b908fe6bSDavid Howells rxrpc_kernel_abort_call(call->rxcall, RX_USER_ABORT); 817b908fe6bSDavid Howells default: 818b908fe6bSDavid Howells rxrpc_kernel_end_call(call->rxcall); 819b908fe6bSDavid Howells call->rxcall = NULL; 820b908fe6bSDavid Howells call->type->destructor(call); 821b908fe6bSDavid Howells afs_free_call(call); 822b908fe6bSDavid Howells _leave(" [error]"); 823b908fe6bSDavid Howells return; 824b908fe6bSDavid Howells } 825b908fe6bSDavid Howells } 826b908fe6bSDavid Howells 827b908fe6bSDavid Howells /* 82808e0e7c8SDavid Howells * extract a piece of data from the received data socket buffers 82908e0e7c8SDavid Howells */ 83008e0e7c8SDavid Howells int afs_extract_data(struct afs_call *call, struct sk_buff *skb, 83108e0e7c8SDavid Howells bool last, void *buf, size_t count) 83208e0e7c8SDavid Howells { 83308e0e7c8SDavid Howells size_t len = skb->len; 83408e0e7c8SDavid Howells 83508e0e7c8SDavid Howells _enter("{%u},{%zu},%d,,%zu", call->offset, len, last, count); 83608e0e7c8SDavid Howells 83708e0e7c8SDavid Howells ASSERTCMP(call->offset, <, count); 83808e0e7c8SDavid Howells 83908e0e7c8SDavid Howells len = min_t(size_t, len, count - call->offset); 84008e0e7c8SDavid Howells if (skb_copy_bits(skb, 0, buf + call->offset, len) < 0 || 84108e0e7c8SDavid Howells !pskb_pull(skb, len)) 84208e0e7c8SDavid Howells BUG(); 84308e0e7c8SDavid Howells call->offset += len; 84408e0e7c8SDavid Howells 84508e0e7c8SDavid Howells if (call->offset < count) { 84608e0e7c8SDavid Howells if (last) { 847b1bdb691SDavid Howells _leave(" = -EBADMSG [%d < %zu]", call->offset, count); 84808e0e7c8SDavid Howells return -EBADMSG; 84908e0e7c8SDavid Howells } 85008e0e7c8SDavid Howells _leave(" = -EAGAIN"); 85108e0e7c8SDavid Howells return -EAGAIN; 85208e0e7c8SDavid Howells } 85308e0e7c8SDavid Howells return 0; 85408e0e7c8SDavid Howells } 855