Skip to content

Commit

Permalink
Merge tag 'rxrpc-fixes-20200605' of git://git.kernel.org/pub/scm/linu…
Browse files Browse the repository at this point in the history
…x/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 <[email protected]>
  • Loading branch information
davem330 committed Jun 9, 2020
2 parents 8e60eed + 5ac0d62 commit 07a86b0
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 110 deletions.
119 changes: 25 additions & 94 deletions net/rxrpc/ar-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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
*/
Expand Down
1 change: 0 additions & 1 deletion net/rxrpc/call_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,6 @@ void rxrpc_process_call(struct work_struct *work)

if (call->state == RXRPC_CALL_COMPLETE) {
del_timer_sync(&call->timer);
rxrpc_notify_socket(call);
goto out_put;
}

Expand Down
7 changes: 3 additions & 4 deletions net/rxrpc/conn_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
7 changes: 2 additions & 5 deletions net/rxrpc/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}

/*
Expand Down Expand Up @@ -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);
}

/*
Expand Down
4 changes: 1 addition & 3 deletions net/rxrpc/peer_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
79 changes: 79 additions & 0 deletions net/rxrpc/recvmsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
4 changes: 1 addition & 3 deletions net/rxrpc/sendmsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 07a86b0

Please sign in to comment.