Commit d3c10db1 authored by David S. Miller's avatar David S. Miller

Merge tag 'rxrpc-rewrite-20160824-1' of...

Merge tag 'rxrpc-rewrite-20160824-1' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

David Howells says:

====================
rxrpc: More fixes

Here are a couple of fix patches:

 (1) Fix the conn-based retransmission patch posted yesterday.  This breaks
     if it actually has to retransmit.  However, it seems the likelihood of
     this happening is really low, despite the server I'm testing against
     being located >3000 miles away, and sometime of the time it's handled
     in the call background processor before we manage to disconnect the
     call - hence why I didn't spot it.

 (2) /proc/net/rxrpc_calls can cause a crash it accessed whilst a call is
     being torn down.  The window of opportunity is pretty small, however,
     as calls don't stay in this state for long.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d14c800b df5d8bf7
...@@ -407,6 +407,7 @@ enum rxrpc_call_state { ...@@ -407,6 +407,7 @@ enum rxrpc_call_state {
struct rxrpc_call { struct rxrpc_call {
struct rcu_head rcu; struct rcu_head rcu;
struct rxrpc_connection *conn; /* connection carrying call */ struct rxrpc_connection *conn; /* connection carrying call */
struct rxrpc_peer *peer; /* Peer record for remote address */
struct rxrpc_sock *socket; /* socket responsible */ struct rxrpc_sock *socket; /* socket responsible */
struct timer_list lifetimer; /* lifetime remaining on call */ struct timer_list lifetimer; /* lifetime remaining on call */
struct timer_list deadspan; /* reap timer for re-ACK'ing, etc */ struct timer_list deadspan; /* reap timer for re-ACK'ing, etc */
...@@ -717,9 +718,10 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *, ...@@ -717,9 +718,10 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *,
struct sockaddr_rxrpc *, gfp_t); struct sockaddr_rxrpc *, gfp_t);
struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *, gfp_t); struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *, gfp_t);
static inline void rxrpc_get_peer(struct rxrpc_peer *peer) static inline struct rxrpc_peer *rxrpc_get_peer(struct rxrpc_peer *peer)
{ {
atomic_inc(&peer->usage); atomic_inc(&peer->usage);
return peer;
} }
static inline static inline
......
...@@ -315,6 +315,7 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx, ...@@ -315,6 +315,7 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx,
chan = sp->hdr.cid & RXRPC_CHANNELMASK; chan = sp->hdr.cid & RXRPC_CHANNELMASK;
candidate->socket = rx; candidate->socket = rx;
candidate->conn = conn; candidate->conn = conn;
candidate->peer = conn->params.peer;
candidate->cid = sp->hdr.cid; candidate->cid = sp->hdr.cid;
candidate->call_id = sp->hdr.callNumber; candidate->call_id = sp->hdr.callNumber;
candidate->rx_data_post = 0; candidate->rx_data_post = 0;
...@@ -384,6 +385,7 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx, ...@@ -384,6 +385,7 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx,
rcu_assign_pointer(conn->channels[chan].call, call); rcu_assign_pointer(conn->channels[chan].call, call);
sock_hold(&rx->sk); sock_hold(&rx->sk);
rxrpc_get_connection(conn); rxrpc_get_connection(conn);
rxrpc_get_peer(call->peer);
spin_unlock(&conn->channel_lock); spin_unlock(&conn->channel_lock);
spin_lock(&conn->params.peer->lock); spin_lock(&conn->params.peer->lock);
...@@ -610,6 +612,7 @@ static void rxrpc_rcu_destroy_call(struct rcu_head *rcu) ...@@ -610,6 +612,7 @@ static void rxrpc_rcu_destroy_call(struct rcu_head *rcu)
struct rxrpc_call *call = container_of(rcu, struct rxrpc_call, rcu); struct rxrpc_call *call = container_of(rcu, struct rxrpc_call, rcu);
rxrpc_purge_queue(&call->rx_queue); rxrpc_purge_queue(&call->rx_queue);
rxrpc_put_peer(call->peer);
kmem_cache_free(rxrpc_call_jar, call); kmem_cache_free(rxrpc_call_jar, call);
} }
......
...@@ -280,6 +280,7 @@ int rxrpc_connect_call(struct rxrpc_call *call, ...@@ -280,6 +280,7 @@ int rxrpc_connect_call(struct rxrpc_call *call,
found_channel: found_channel:
_debug("found chan"); _debug("found chan");
call->conn = conn; call->conn = conn;
call->peer = rxrpc_get_peer(conn->params.peer);
call->cid = conn->proto.cid | chan; call->cid = conn->proto.cid | chan;
call->call_id = ++conn->channels[chan].call_counter; call->call_id = ++conn->channels[chan].call_counter;
conn->channels[chan].call_id = call->call_id; conn->channels[chan].call_id = call->call_id;
......
...@@ -42,6 +42,7 @@ static void rxrpc_conn_retransmit(struct rxrpc_connection *conn, ...@@ -42,6 +42,7 @@ static void rxrpc_conn_retransmit(struct rxrpc_connection *conn,
} abort; } abort;
struct { struct {
struct rxrpc_ackpacket ack; struct rxrpc_ackpacket ack;
u8 padding[3];
struct rxrpc_ackinfo info; struct rxrpc_ackinfo info;
}; };
}; };
......
...@@ -732,7 +732,7 @@ void rxrpc_data_ready(struct sock *sk) ...@@ -732,7 +732,7 @@ void rxrpc_data_ready(struct sock *sk)
/* For the previous service call, if completed /* For the previous service call, if completed
* successfully, we discard all further packets. * successfully, we discard all further packets.
*/ */
if (rxrpc_conn_is_service(call->conn) && if (rxrpc_conn_is_service(conn) &&
(chan->last_type == RXRPC_PACKET_TYPE_ACK || (chan->last_type == RXRPC_PACKET_TYPE_ACK ||
sp->hdr.type == RXRPC_PACKET_TYPE_ABORT)) sp->hdr.type == RXRPC_PACKET_TYPE_ABORT))
goto discard_unlock; goto discard_unlock;
......
...@@ -46,7 +46,9 @@ static void rxrpc_call_seq_stop(struct seq_file *seq, void *v) ...@@ -46,7 +46,9 @@ static void rxrpc_call_seq_stop(struct seq_file *seq, void *v)
static int rxrpc_call_seq_show(struct seq_file *seq, void *v) static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
{ {
struct rxrpc_connection *conn; struct rxrpc_local *local;
struct rxrpc_sock *rx;
struct rxrpc_peer *peer;
struct rxrpc_call *call; struct rxrpc_call *call;
char lbuff[4 + 4 + 4 + 4 + 5 + 1], rbuff[4 + 4 + 4 + 4 + 5 + 1]; char lbuff[4 + 4 + 4 + 4 + 5 + 1], rbuff[4 + 4 + 4 + 4 + 5 + 1];
...@@ -60,15 +62,24 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v) ...@@ -60,15 +62,24 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
call = list_entry(v, struct rxrpc_call, link); call = list_entry(v, struct rxrpc_call, link);
sprintf(lbuff, "%pI4:%u", rx = READ_ONCE(call->socket);
&call->socket->local->srx.transport.sin.sin_addr, if (rx) {
ntohs(call->socket->local->srx.transport.sin.sin_port)); local = READ_ONCE(rx->local);
if (local)
sprintf(lbuff, "%pI4:%u",
&local->srx.transport.sin.sin_addr,
ntohs(local->srx.transport.sin.sin_port));
else
strcpy(lbuff, "no_local");
} else {
strcpy(lbuff, "no_socket");
}
conn = call->conn; peer = call->peer;
if (conn) if (peer)
sprintf(rbuff, "%pI4:%u", sprintf(rbuff, "%pI4:%u",
&conn->params.peer->srx.transport.sin.sin_addr, &peer->srx.transport.sin.sin_addr,
ntohs(conn->params.peer->srx.transport.sin.sin_port)); ntohs(peer->srx.transport.sin.sin_port));
else else
strcpy(rbuff, "no_connection"); strcpy(rbuff, "no_connection");
......
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