rxrpc: Don't expose skbs to in-kernel users [ver #2]
Don't expose skbs to in-kernel users, such as the AFS filesystem, but instead provide a notification hook the indicates that a call needs attention and another that indicates that there's a new call to be collected. This makes the following possibilities more achievable: (1) Call refcounting can be made simpler if skbs don't hold refs to calls. (2) skbs referring to non-data events will be able to be freed much sooner rather than being queued for AFS to pick up as rxrpc_kernel_recv_data will be able to consult the call state. (3) We can shortcut the receive phase when a call is remotely aborted because we don't have to go through all the packets to get to the one cancelling the operation. (4) It makes it easier to do encryption/decryption directly between AFS's buffers and sk_buffs. (5) Encryption/decryption can more easily be done in the AFS's thread contexts - usually that of the userspace process that issued a syscall - rather than in one of rxrpc's background threads on a workqueue. (6) AFS will be able to wait synchronously on a call inside AF_RXRPC. To make this work, the following interface function has been added: int rxrpc_kernel_recv_data( struct socket *sock, struct rxrpc_call *call, void *buffer, size_t bufsize, size_t *_offset, bool want_more, u32 *_abort_code); This is the recvmsg equivalent. It allows the caller to find out about the state of a specific call and to transfer received data into a buffer piecemeal. afs_extract_data() and rxrpc_kernel_recv_data() now do all the extraction logic between them. They don't wait synchronously yet because the socket lock needs to be dealt with. Five interface functions have been removed: rxrpc_kernel_is_data_last() rxrpc_kernel_get_abort_code() rxrpc_kernel_get_error_number() rxrpc_kernel_free_skb() rxrpc_kernel_data_consumed() As a temporary hack, sk_buffs going to an in-kernel call are queued on the rxrpc_call struct (->knlrecv_queue) rather than being handed over to the in-kernel user. To process the queue internally, a temporary function, temp_deliver_data() has been added. This will be replaced with common code between the rxrpc_recvmsg() path and the kernel_rxrpc_recv_data() path in a future patch. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
95ac399451
commit
d001648ec7
@@ -231,6 +231,8 @@ static int rxrpc_listen(struct socket *sock, int backlog)
|
||||
* @srx: The address of the peer to contact
|
||||
* @key: The security context to use (defaults to socket setting)
|
||||
* @user_call_ID: The ID to use
|
||||
* @gfp: The allocation constraints
|
||||
* @notify_rx: Where to send notifications instead of socket queue
|
||||
*
|
||||
* Allow a kernel service to begin a call on the nominated socket. This just
|
||||
* sets up all the internal tracking structures and allocates connection and
|
||||
@@ -243,7 +245,8 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
|
||||
struct sockaddr_rxrpc *srx,
|
||||
struct key *key,
|
||||
unsigned long user_call_ID,
|
||||
gfp_t gfp)
|
||||
gfp_t gfp,
|
||||
rxrpc_notify_rx_t notify_rx)
|
||||
{
|
||||
struct rxrpc_conn_parameters cp;
|
||||
struct rxrpc_call *call;
|
||||
@@ -270,6 +273,8 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
|
||||
cp.exclusive = false;
|
||||
cp.service_id = srx->srx_service;
|
||||
call = rxrpc_new_client_call(rx, &cp, srx, user_call_ID, gfp);
|
||||
if (!IS_ERR(call))
|
||||
call->notify_rx = notify_rx;
|
||||
|
||||
release_sock(&rx->sk);
|
||||
_leave(" = %p", call);
|
||||
@@ -289,31 +294,27 @@ void rxrpc_kernel_end_call(struct socket *sock, struct rxrpc_call *call)
|
||||
{
|
||||
_enter("%d{%d}", call->debug_id, atomic_read(&call->usage));
|
||||
rxrpc_remove_user_ID(rxrpc_sk(sock->sk), call);
|
||||
rxrpc_purge_queue(&call->knlrecv_queue);
|
||||
rxrpc_put_call(call);
|
||||
}
|
||||
EXPORT_SYMBOL(rxrpc_kernel_end_call);
|
||||
|
||||
/**
|
||||
* rxrpc_kernel_intercept_rx_messages - Intercept received RxRPC messages
|
||||
* rxrpc_kernel_new_call_notification - Get notifications of new calls
|
||||
* @sock: The socket to intercept received messages on
|
||||
* @interceptor: The function to pass the messages to
|
||||
* @notify_new_call: Function to be called when new calls appear
|
||||
*
|
||||
* Allow a kernel service to intercept messages heading for the Rx queue on an
|
||||
* RxRPC socket. They get passed to the specified function instead.
|
||||
* @interceptor should free the socket buffers it is given. @interceptor is
|
||||
* called with the socket receive queue spinlock held and softirqs disabled -
|
||||
* this ensures that the messages will be delivered in the right order.
|
||||
* Allow a kernel service to be given notifications about new calls.
|
||||
*/
|
||||
void rxrpc_kernel_intercept_rx_messages(struct socket *sock,
|
||||
rxrpc_interceptor_t interceptor)
|
||||
void rxrpc_kernel_new_call_notification(
|
||||
struct socket *sock,
|
||||
rxrpc_notify_new_call_t notify_new_call)
|
||||
{
|
||||
struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
|
||||
|
||||
_enter("");
|
||||
rx->interceptor = interceptor;
|
||||
rx->notify_new_call = notify_new_call;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(rxrpc_kernel_intercept_rx_messages);
|
||||
EXPORT_SYMBOL(rxrpc_kernel_new_call_notification);
|
||||
|
||||
/*
|
||||
* connect an RxRPC socket
|
||||
|
Reference in New Issue
Block a user