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:
@@ -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);
|
||||
|
Reference in New Issue
Block a user