diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c index 1d38e279e2ef..9ea162cb521f 100644 --- a/net/rxrpc/sendmsg.c +++ b/net/rxrpc/sendmsg.c @@ -33,11 +33,16 @@ static bool rxrpc_check_tx_space(struct rxrpc_call *call, rxrpc_seq_t *_tx_win) } /* + * @holding_mutex: An indication whether caller can still holds + * the call->user_mutex when returned to caller. + * This argument can be NULL, which will effect nothing. + * * Wait for space to appear in the Tx queue or a signal to occur. */ static int rxrpc_wait_for_tx_window_intr(struct rxrpc_sock *rx, struct rxrpc_call *call, - long *timeo) + long *timeo, + bool *holding_mutex) { for (;;) { set_current_state(TASK_INTERRUPTIBLE); @@ -53,8 +58,11 @@ static int rxrpc_wait_for_tx_window_intr(struct rxrpc_sock *rx, trace_rxrpc_transmit(call, rxrpc_transmit_wait); mutex_unlock(&call->user_mutex); *timeo = schedule_timeout(*timeo); - if (mutex_lock_interruptible(&call->user_mutex) < 0) + if (mutex_lock_interruptible(&call->user_mutex) < 0) { + if (holding_mutex) + *holding_mutex = false; return sock_intr_errno(*timeo); + } } } @@ -121,13 +129,18 @@ static int rxrpc_wait_for_tx_window_nonintr(struct rxrpc_sock *rx, } /* + * @holding_mutex: An indication whether caller can still holds + * the call->user_mutex when returned to caller. + * This argument can be NULL, which will effect nothing. + * * wait for space to appear in the transmit/ACK window * - caller holds the socket locked */ static int rxrpc_wait_for_tx_window(struct rxrpc_sock *rx, struct rxrpc_call *call, long *timeo, - bool waitall) + bool waitall, + bool *holding_mutex) { DECLARE_WAITQUEUE(myself, current); int ret; @@ -142,7 +155,7 @@ static int rxrpc_wait_for_tx_window(struct rxrpc_sock *rx, if (waitall) ret = rxrpc_wait_for_tx_window_waitall(rx, call); else - ret = rxrpc_wait_for_tx_window_intr(rx, call, timeo); + ret = rxrpc_wait_for_tx_window_intr(rx, call, timeo, holding_mutex); break; case RXRPC_PREINTERRUPTIBLE: case RXRPC_UNINTERRUPTIBLE: @@ -284,13 +297,19 @@ static int rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call, /* * send data through a socket + * + * @holding_mutex: An indication whether caller can still holds + * the call->user_mutex when returned to caller. + * This argument can be NULL, which will effect nothing. + * * - must be called in process context * - The caller holds the call user access mutex, but not the socket lock. */ static int rxrpc_send_data(struct rxrpc_sock *rx, struct rxrpc_call *call, struct msghdr *msg, size_t len, - rxrpc_notify_end_tx_t notify_end_tx) + rxrpc_notify_end_tx_t notify_end_tx, + bool *holding_mutex) { struct rxrpc_skb_priv *sp; struct sk_buff *skb; @@ -299,6 +318,13 @@ static int rxrpc_send_data(struct rxrpc_sock *rx, bool more; int ret, copied; + /* + * The caller holds the call->user_mutex when calls + * rxrpc_send_data(), so initial it with True + */ + if (holding_mutex) + *holding_mutex = true; + timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); /* this should be in poll */ @@ -337,7 +363,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx, goto maybe_error; ret = rxrpc_wait_for_tx_window(rx, call, &timeo, - msg->msg_flags & MSG_WAITALL); + msg->msg_flags & MSG_WAITALL, + holding_mutex); if (ret < 0) goto maybe_error; } @@ -631,6 +658,12 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len) unsigned long now, j; int ret; + /* + * An indication whether rxrpc_do_sendmsg can hold the + * call->user_mutex, after calling the rxrpc_do_sendmsg() + */ + bool holding_mutex; + struct rxrpc_send_params p = { .call.tx_total_len = -1, .call.user_call_ID = 0, @@ -747,7 +780,11 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len) /* Reply phase not begun or not complete for service call. */ ret = -EPROTO; } else { - ret = rxrpc_send_data(rx, call, msg, len, NULL); + ret = rxrpc_send_data(rx, call, msg, len, NULL, &holding_mutex); + + /* ignore mutex_unlock if did not hold call->user_mutex */ + if (!holding_mutex) + goto error_put; } out_put_unlock: @@ -796,7 +833,7 @@ int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call, case RXRPC_CALL_SERVER_ACK_REQUEST: case RXRPC_CALL_SERVER_SEND_REPLY: ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg, len, - notify_end_tx); + notify_end_tx, NULL); break; case RXRPC_CALL_COMPLETE: read_lock_bh(&call->state_lock);