Commit 166c8818 authored by David S. Miller's avatar David S. Miller

Merge tag 'rxrpc-next-20171111' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

David Howells says:

====================
rxrpc: Fixes

Here are some patches that fix some things in AF_RXRPC:

 (1) Prevent notifications from being passed to a kernel service for a call
     that it has ended.

 (2) Fix a null pointer deference that occurs under some circumstances when an
     ACK is generated.

 (3) Fix a number of things to do with call expiration.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 442866ff dcbefc30
...@@ -322,6 +322,14 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, ...@@ -322,6 +322,14 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
} }
EXPORT_SYMBOL(rxrpc_kernel_begin_call); EXPORT_SYMBOL(rxrpc_kernel_begin_call);
/*
* Dummy function used to stop the notifier talking to recvmsg().
*/
static void rxrpc_dummy_notify_rx(struct sock *sk, struct rxrpc_call *rxcall,
unsigned long call_user_ID)
{
}
/** /**
* rxrpc_kernel_end_call - Allow a kernel service to end a call it was using * rxrpc_kernel_end_call - Allow a kernel service to end a call it was using
* @sock: The socket the call is on * @sock: The socket the call is on
...@@ -336,6 +344,14 @@ void rxrpc_kernel_end_call(struct socket *sock, struct rxrpc_call *call) ...@@ -336,6 +344,14 @@ void rxrpc_kernel_end_call(struct socket *sock, struct rxrpc_call *call)
mutex_lock(&call->user_mutex); mutex_lock(&call->user_mutex);
rxrpc_release_call(rxrpc_sk(sock->sk), call); rxrpc_release_call(rxrpc_sk(sock->sk), call);
/* Make sure we're not going to call back into a kernel service */
if (call->notify_rx) {
spin_lock_bh(&call->notify_lock);
call->notify_rx = rxrpc_dummy_notify_rx;
spin_unlock_bh(&call->notify_lock);
}
mutex_unlock(&call->user_mutex); mutex_unlock(&call->user_mutex);
rxrpc_put_call(call, rxrpc_call_put_kernel); rxrpc_put_call(call, rxrpc_call_put_kernel);
} }
......
...@@ -525,6 +525,7 @@ struct rxrpc_call { ...@@ -525,6 +525,7 @@ struct rxrpc_call {
unsigned long flags; unsigned long flags;
unsigned long events; unsigned long events;
spinlock_t lock; spinlock_t lock;
spinlock_t notify_lock; /* Kernel notification lock */
rwlock_t state_lock; /* lock for state transition */ rwlock_t state_lock; /* lock for state transition */
u32 abort_code; /* Local/remote abort code */ u32 abort_code; /* Local/remote abort code */
int error; /* Local error incurred */ int error; /* Local error incurred */
......
...@@ -386,7 +386,7 @@ void rxrpc_process_call(struct work_struct *work) ...@@ -386,7 +386,7 @@ void rxrpc_process_call(struct work_struct *work)
now = ktime_get_real(); now = ktime_get_real();
if (ktime_before(call->expire_at, now)) { if (ktime_before(call->expire_at, now)) {
rxrpc_abort_call("EXP", call, 0, RX_CALL_TIMEOUT, -ETIME); rxrpc_abort_call("EXP", call, 0, RX_USER_ABORT, -ETIME);
set_bit(RXRPC_CALL_EV_ABORT, &call->events); set_bit(RXRPC_CALL_EV_ABORT, &call->events);
goto recheck_state; goto recheck_state;
} }
......
...@@ -124,6 +124,7 @@ struct rxrpc_call *rxrpc_alloc_call(gfp_t gfp) ...@@ -124,6 +124,7 @@ struct rxrpc_call *rxrpc_alloc_call(gfp_t gfp)
INIT_LIST_HEAD(&call->sock_link); INIT_LIST_HEAD(&call->sock_link);
init_waitqueue_head(&call->waitq); init_waitqueue_head(&call->waitq);
spin_lock_init(&call->lock); spin_lock_init(&call->lock);
spin_lock_init(&call->notify_lock);
rwlock_init(&call->state_lock); rwlock_init(&call->state_lock);
atomic_set(&call->usage, 1); atomic_set(&call->usage, 1);
call->debug_id = atomic_inc_return(&rxrpc_debug_id); call->debug_id = atomic_inc_return(&rxrpc_debug_id);
......
...@@ -298,8 +298,6 @@ static bool rxrpc_end_tx_phase(struct rxrpc_call *call, bool reply_begun, ...@@ -298,8 +298,6 @@ static bool rxrpc_end_tx_phase(struct rxrpc_call *call, bool reply_begun,
write_unlock(&call->state_lock); write_unlock(&call->state_lock);
if (call->state == RXRPC_CALL_CLIENT_AWAIT_REPLY) { if (call->state == RXRPC_CALL_CLIENT_AWAIT_REPLY) {
rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, 0, 0, false, true,
rxrpc_propose_ack_client_tx_end);
trace_rxrpc_transmit(call, rxrpc_transmit_await_reply); trace_rxrpc_transmit(call, rxrpc_transmit_await_reply);
} else { } else {
trace_rxrpc_transmit(call, rxrpc_transmit_end); trace_rxrpc_transmit(call, rxrpc_transmit_end);
......
...@@ -35,7 +35,8 @@ struct rxrpc_abort_buffer { ...@@ -35,7 +35,8 @@ struct rxrpc_abort_buffer {
/* /*
* Fill out an ACK packet. * Fill out an ACK packet.
*/ */
static size_t rxrpc_fill_out_ack(struct rxrpc_call *call, static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn,
struct rxrpc_call *call,
struct rxrpc_ack_buffer *pkt, struct rxrpc_ack_buffer *pkt,
rxrpc_seq_t *_hard_ack, rxrpc_seq_t *_hard_ack,
rxrpc_seq_t *_top, rxrpc_seq_t *_top,
...@@ -77,8 +78,8 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_call *call, ...@@ -77,8 +78,8 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_call *call,
} while (before_eq(seq, top)); } while (before_eq(seq, top));
} }
mtu = call->conn->params.peer->if_mtu; mtu = conn->params.peer->if_mtu;
mtu -= call->conn->params.peer->hdrsize; mtu -= conn->params.peer->hdrsize;
jmax = (call->nr_jumbo_bad > 3) ? 1 : rxrpc_rx_jumbo_max; jmax = (call->nr_jumbo_bad > 3) ? 1 : rxrpc_rx_jumbo_max;
pkt->ackinfo.rxMTU = htonl(rxrpc_rx_mtu); pkt->ackinfo.rxMTU = htonl(rxrpc_rx_mtu);
pkt->ackinfo.maxMTU = htonl(mtu); pkt->ackinfo.maxMTU = htonl(mtu);
...@@ -148,7 +149,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping) ...@@ -148,7 +149,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping)
} }
call->ackr_reason = 0; call->ackr_reason = 0;
} }
n = rxrpc_fill_out_ack(call, pkt, &hard_ack, &top, reason); n = rxrpc_fill_out_ack(conn, call, pkt, &hard_ack, &top, reason);
spin_unlock_bh(&call->lock); spin_unlock_bh(&call->lock);
...@@ -221,6 +222,16 @@ int rxrpc_send_abort_packet(struct rxrpc_call *call) ...@@ -221,6 +222,16 @@ int rxrpc_send_abort_packet(struct rxrpc_call *call)
rxrpc_serial_t serial; rxrpc_serial_t serial;
int ret; int ret;
/* Don't bother sending aborts for a client call once the server has
* hard-ACK'd all of its request data. After that point, we're not
* going to stop the operation proceeding, and whilst we might limit
* the reply, it's not worth it if we can send a new call on the same
* channel instead, thereby closing off this call.
*/
if (rxrpc_is_client_call(call) &&
test_bit(RXRPC_CALL_TX_LAST, &call->flags))
return 0;
spin_lock_bh(&call->lock); spin_lock_bh(&call->lock);
if (call->conn) if (call->conn)
conn = rxrpc_get_connection_maybe(call->conn); conn = rxrpc_get_connection_maybe(call->conn);
......
...@@ -40,7 +40,9 @@ void rxrpc_notify_socket(struct rxrpc_call *call) ...@@ -40,7 +40,9 @@ void rxrpc_notify_socket(struct rxrpc_call *call)
sk = &rx->sk; sk = &rx->sk;
if (rx && sk->sk_state < RXRPC_CLOSE) { if (rx && sk->sk_state < RXRPC_CLOSE) {
if (call->notify_rx) { if (call->notify_rx) {
spin_lock_bh(&call->notify_lock);
call->notify_rx(sk, call, call->user_call_ID); call->notify_rx(sk, call, call->user_call_ID);
spin_unlock_bh(&call->notify_lock);
} else { } else {
write_lock_bh(&rx->recvmsg_lock); write_lock_bh(&rx->recvmsg_lock);
if (list_empty(&call->recvmsg_link)) { if (list_empty(&call->recvmsg_link)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment