mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 04:31:50 +00:00
rxrpc fixes
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEqG5UsNXhtOCrfGQP+7dXa6fLC2sFAl7aPH8ACgkQ+7dXa6fL C2sOGQ//etn1sPirX0GpYYwZ8yLCbSnyeLigexd5yvqwsiYhyQleaJO5xF5/NzWH CeuJmQ3qR1JkslGJXhA0hhwvFjG0t8+ib8QbLDOoIhzzxbQj5vOC9upP7v8VpbVF PgsAKkoSdHKNTEC5Lsyvo9c3AFcZcefqRM1D9JHozELPuClTFNHPZ2FXEZtnkbz0 aSNqOYjvvpDpBLE88tWA4M2ae5iwILLbEsjsI6wcwo1prwG/1czEVkSQuD46bpEW 5H/hufvWih2srjzwuh0gGd/a1cGiFW7ugBNZ3e/DNBCqfEFUjbGRlGzqI5lO4pN8 NVpKyXkUFg0PaBc4GSPrU5uDKclSilkZvL/CeItcpSLq74wuh8R8XmoJxdaDKEvf WEFPBRISxXw97ELBdmcxacOsGJbpuiLd4n5k7hxSGfENGRgNOqN826S4/p+aC4CA N9Py4N7h9LkArGRd95TnOelgiFdFywkf7Sbcy8MSHRqzLanimlpSG4N4lMCvBktD z3Q97wJptkugX31FjpIbFC0QQyfjBY+9LDWiPyNFyQ7E8TDV5UG3UxLQXLmJnoaU J6ECNMYrT1/64KvYQeMsd/iEy1hSRs+CsrChVmLBDpb1t7gcbv1YGtV9UcFsdDzN 1iV/XyR4AiTwYnwlIgQKH1U9laV2Ttk3QS7u2s4ZRHZjCoiDg70= =PnAQ -----END PGP SIGNATURE----- Merge tag 'rxrpc-fixes-20200605' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs David Howells says: ==================== rxrpc: Fix hang due to missing notification Here's a fix for AF_RXRPC. Occasionally calls hang because there are circumstances in which rxrpc generate a notification when a call is completed - primarily because initial packet transmission failed and the call was killed off and an error returned. But the AFS filesystem driver doesn't check this under all circumstances, expecting failure to be delivered by asynchronous notification. There are two patches: the first moves the problematic bits out-of-line and the second contains the fix. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
07a86b01c0
@ -809,100 +809,6 @@ static inline bool rxrpc_is_client_call(const struct rxrpc_call *call)
|
||||
return !rxrpc_is_service_call(call);
|
||||
}
|
||||
|
||||
/*
|
||||
* Transition a call to the complete state.
|
||||
*/
|
||||
static inline bool __rxrpc_set_call_completion(struct rxrpc_call *call,
|
||||
enum rxrpc_call_completion compl,
|
||||
u32 abort_code,
|
||||
int error)
|
||||
{
|
||||
if (call->state < RXRPC_CALL_COMPLETE) {
|
||||
call->abort_code = abort_code;
|
||||
call->error = error;
|
||||
call->completion = compl,
|
||||
call->state = RXRPC_CALL_COMPLETE;
|
||||
trace_rxrpc_call_complete(call);
|
||||
wake_up(&call->waitq);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool rxrpc_set_call_completion(struct rxrpc_call *call,
|
||||
enum rxrpc_call_completion compl,
|
||||
u32 abort_code,
|
||||
int error)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
write_lock_bh(&call->state_lock);
|
||||
ret = __rxrpc_set_call_completion(call, compl, abort_code, error);
|
||||
write_unlock_bh(&call->state_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Record that a call successfully completed.
|
||||
*/
|
||||
static inline bool __rxrpc_call_completed(struct rxrpc_call *call)
|
||||
{
|
||||
return __rxrpc_set_call_completion(call, RXRPC_CALL_SUCCEEDED, 0, 0);
|
||||
}
|
||||
|
||||
static inline bool rxrpc_call_completed(struct rxrpc_call *call)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
write_lock_bh(&call->state_lock);
|
||||
ret = __rxrpc_call_completed(call);
|
||||
write_unlock_bh(&call->state_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Record that a call is locally aborted.
|
||||
*/
|
||||
static inline bool __rxrpc_abort_call(const char *why, struct rxrpc_call *call,
|
||||
rxrpc_seq_t seq,
|
||||
u32 abort_code, int error)
|
||||
{
|
||||
trace_rxrpc_abort(call->debug_id, why, call->cid, call->call_id, seq,
|
||||
abort_code, error);
|
||||
return __rxrpc_set_call_completion(call, RXRPC_CALL_LOCALLY_ABORTED,
|
||||
abort_code, error);
|
||||
}
|
||||
|
||||
static inline bool rxrpc_abort_call(const char *why, struct rxrpc_call *call,
|
||||
rxrpc_seq_t seq, u32 abort_code, int error)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
write_lock_bh(&call->state_lock);
|
||||
ret = __rxrpc_abort_call(why, call, seq, abort_code, error);
|
||||
write_unlock_bh(&call->state_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Abort a call due to a protocol error.
|
||||
*/
|
||||
static inline bool __rxrpc_abort_eproto(struct rxrpc_call *call,
|
||||
struct sk_buff *skb,
|
||||
const char *eproto_why,
|
||||
const char *why,
|
||||
u32 abort_code)
|
||||
{
|
||||
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
||||
|
||||
trace_rxrpc_rx_eproto(call, sp->hdr.serial, eproto_why);
|
||||
return rxrpc_abort_call(why, call, sp->hdr.seq, abort_code, -EPROTO);
|
||||
}
|
||||
|
||||
#define rxrpc_abort_eproto(call, skb, eproto_why, abort_why, abort_code) \
|
||||
__rxrpc_abort_eproto((call), (skb), tracepoint_string(eproto_why), \
|
||||
(abort_why), (abort_code))
|
||||
|
||||
/*
|
||||
* conn_client.c
|
||||
*/
|
||||
@ -1101,8 +1007,33 @@ extern const struct seq_operations rxrpc_peer_seq_ops;
|
||||
* recvmsg.c
|
||||
*/
|
||||
void rxrpc_notify_socket(struct rxrpc_call *);
|
||||
bool __rxrpc_set_call_completion(struct rxrpc_call *, enum rxrpc_call_completion, u32, int);
|
||||
bool rxrpc_set_call_completion(struct rxrpc_call *, enum rxrpc_call_completion, u32, int);
|
||||
bool __rxrpc_call_completed(struct rxrpc_call *);
|
||||
bool rxrpc_call_completed(struct rxrpc_call *);
|
||||
bool __rxrpc_abort_call(const char *, struct rxrpc_call *, rxrpc_seq_t, u32, int);
|
||||
bool rxrpc_abort_call(const char *, struct rxrpc_call *, rxrpc_seq_t, u32, int);
|
||||
int rxrpc_recvmsg(struct socket *, struct msghdr *, size_t, int);
|
||||
|
||||
/*
|
||||
* Abort a call due to a protocol error.
|
||||
*/
|
||||
static inline bool __rxrpc_abort_eproto(struct rxrpc_call *call,
|
||||
struct sk_buff *skb,
|
||||
const char *eproto_why,
|
||||
const char *why,
|
||||
u32 abort_code)
|
||||
{
|
||||
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
||||
|
||||
trace_rxrpc_rx_eproto(call, sp->hdr.serial, eproto_why);
|
||||
return rxrpc_abort_call(why, call, sp->hdr.seq, abort_code, -EPROTO);
|
||||
}
|
||||
|
||||
#define rxrpc_abort_eproto(call, skb, eproto_why, abort_why, abort_code) \
|
||||
__rxrpc_abort_eproto((call), (skb), tracepoint_string(eproto_why), \
|
||||
(abort_why), (abort_code))
|
||||
|
||||
/*
|
||||
* rtt.c
|
||||
*/
|
||||
|
@ -320,7 +320,6 @@ recheck_state:
|
||||
|
||||
if (call->state == RXRPC_CALL_COMPLETE) {
|
||||
del_timer_sync(&call->timer);
|
||||
rxrpc_notify_socket(call);
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
|
@ -173,10 +173,9 @@ static void rxrpc_abort_calls(struct rxrpc_connection *conn,
|
||||
else
|
||||
trace_rxrpc_rx_abort(call, serial,
|
||||
conn->abort_code);
|
||||
if (rxrpc_set_call_completion(call, compl,
|
||||
conn->abort_code,
|
||||
conn->error))
|
||||
rxrpc_notify_socket(call);
|
||||
rxrpc_set_call_completion(call, compl,
|
||||
conn->abort_code,
|
||||
conn->error);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,7 +275,6 @@ static bool rxrpc_end_tx_phase(struct rxrpc_call *call, bool reply_begun,
|
||||
|
||||
case RXRPC_CALL_SERVER_AWAIT_ACK:
|
||||
__rxrpc_call_completed(call);
|
||||
rxrpc_notify_socket(call);
|
||||
state = call->state;
|
||||
break;
|
||||
|
||||
@ -1013,9 +1012,8 @@ static void rxrpc_input_abort(struct rxrpc_call *call, struct sk_buff *skb)
|
||||
|
||||
_proto("Rx ABORT %%%u { %x }", sp->hdr.serial, abort_code);
|
||||
|
||||
if (rxrpc_set_call_completion(call, RXRPC_CALL_REMOTELY_ABORTED,
|
||||
abort_code, -ECONNABORTED))
|
||||
rxrpc_notify_socket(call);
|
||||
rxrpc_set_call_completion(call, RXRPC_CALL_REMOTELY_ABORTED,
|
||||
abort_code, -ECONNABORTED);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1102,7 +1100,6 @@ static void rxrpc_input_implicit_end_call(struct rxrpc_sock *rx,
|
||||
spin_lock(&rx->incoming_lock);
|
||||
__rxrpc_disconnect_call(conn, call);
|
||||
spin_unlock(&rx->incoming_lock);
|
||||
rxrpc_notify_socket(call);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -292,9 +292,7 @@ static void rxrpc_distribute_error(struct rxrpc_peer *peer, int error,
|
||||
|
||||
hlist_for_each_entry_rcu(call, &peer->error_targets, error_link) {
|
||||
rxrpc_see_call(call);
|
||||
if (call->state < RXRPC_CALL_COMPLETE &&
|
||||
rxrpc_set_call_completion(call, compl, 0, -error))
|
||||
rxrpc_notify_socket(call);
|
||||
rxrpc_set_call_completion(call, compl, 0, -error);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,85 @@ void rxrpc_notify_socket(struct rxrpc_call *call)
|
||||
_leave("");
|
||||
}
|
||||
|
||||
/*
|
||||
* Transition a call to the complete state.
|
||||
*/
|
||||
bool __rxrpc_set_call_completion(struct rxrpc_call *call,
|
||||
enum rxrpc_call_completion compl,
|
||||
u32 abort_code,
|
||||
int error)
|
||||
{
|
||||
if (call->state < RXRPC_CALL_COMPLETE) {
|
||||
call->abort_code = abort_code;
|
||||
call->error = error;
|
||||
call->completion = compl,
|
||||
call->state = RXRPC_CALL_COMPLETE;
|
||||
trace_rxrpc_call_complete(call);
|
||||
wake_up(&call->waitq);
|
||||
rxrpc_notify_socket(call);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool rxrpc_set_call_completion(struct rxrpc_call *call,
|
||||
enum rxrpc_call_completion compl,
|
||||
u32 abort_code,
|
||||
int error)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (call->state < RXRPC_CALL_COMPLETE) {
|
||||
write_lock_bh(&call->state_lock);
|
||||
ret = __rxrpc_set_call_completion(call, compl, abort_code, error);
|
||||
write_unlock_bh(&call->state_lock);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Record that a call successfully completed.
|
||||
*/
|
||||
bool __rxrpc_call_completed(struct rxrpc_call *call)
|
||||
{
|
||||
return __rxrpc_set_call_completion(call, RXRPC_CALL_SUCCEEDED, 0, 0);
|
||||
}
|
||||
|
||||
bool rxrpc_call_completed(struct rxrpc_call *call)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (call->state < RXRPC_CALL_COMPLETE) {
|
||||
write_lock_bh(&call->state_lock);
|
||||
ret = __rxrpc_call_completed(call);
|
||||
write_unlock_bh(&call->state_lock);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Record that a call is locally aborted.
|
||||
*/
|
||||
bool __rxrpc_abort_call(const char *why, struct rxrpc_call *call,
|
||||
rxrpc_seq_t seq, u32 abort_code, int error)
|
||||
{
|
||||
trace_rxrpc_abort(call->debug_id, why, call->cid, call->call_id, seq,
|
||||
abort_code, error);
|
||||
return __rxrpc_set_call_completion(call, RXRPC_CALL_LOCALLY_ABORTED,
|
||||
abort_code, error);
|
||||
}
|
||||
|
||||
bool rxrpc_abort_call(const char *why, struct rxrpc_call *call,
|
||||
rxrpc_seq_t seq, u32 abort_code, int error)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
write_lock_bh(&call->state_lock);
|
||||
ret = __rxrpc_abort_call(why, call, seq, abort_code, error);
|
||||
write_unlock_bh(&call->state_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass a call terminating message to userspace.
|
||||
*/
|
||||
|
@ -261,10 +261,8 @@ static int rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call,
|
||||
case -ENETUNREACH:
|
||||
case -EHOSTUNREACH:
|
||||
case -ECONNREFUSED:
|
||||
rxrpc_set_call_completion(call,
|
||||
RXRPC_CALL_LOCAL_ERROR,
|
||||
rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR,
|
||||
0, ret);
|
||||
rxrpc_notify_socket(call);
|
||||
goto out;
|
||||
}
|
||||
_debug("need instant resend %d", ret);
|
||||
|
Loading…
Reference in New Issue
Block a user