aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2016-07-01 02:51:50 -0400
committerDavid Howells <dhowells@redhat.com>2016-07-06 05:51:14 -0400
commit8496af50eb385c1cadff9ad396fd5359e96b6c27 (patch)
treeea5adee605917e9b7b1d3b809dc2458cbd07c271
parent995f1405610bd8446c5be37d2ffc031a7729e406 (diff)
rxrpc: Use RCU to access a peer's service connection tree
Move to using RCU access to a peer's service connection tree when routing an incoming packet. This is done using a seqlock to trigger retrying of the tree walk if a change happened. Further, we no longer get a ref on the connection looked up in the data_ready handler unless we queue the connection's work item - and then only if the refcount > 0. Note that I'm avoiding the use of a hash table for service connections because each service connection is addressed by a 62-bit number (constructed from epoch and connection ID >> 2) that would allow the client to engage in bucket stuffing, given knowledge of the hash algorithm. Peers, however, are hashed as the network address is less controllable by the client. The total number of peers will also be limited in a future commit. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--net/rxrpc/ar-internal.h21
-rw-r--r--net/rxrpc/conn_client.c2
-rw-r--r--net/rxrpc/conn_object.c65
-rw-r--r--net/rxrpc/conn_service.c270
-rw-r--r--net/rxrpc/input.c44
-rw-r--r--net/rxrpc/peer_object.c2
6 files changed, 224 insertions, 180 deletions
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 0fe63baf1286..e292276c8539 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -10,6 +10,7 @@
10 */ 10 */
11 11
12#include <linux/atomic.h> 12#include <linux/atomic.h>
13#include <linux/seqlock.h>
13#include <net/sock.h> 14#include <net/sock.h>
14#include <net/af_rxrpc.h> 15#include <net/af_rxrpc.h>
15#include <rxrpc/packet.h> 16#include <rxrpc/packet.h>
@@ -206,7 +207,7 @@ struct rxrpc_peer {
206 struct hlist_head error_targets; /* targets for net error distribution */ 207 struct hlist_head error_targets; /* targets for net error distribution */
207 struct work_struct error_distributor; 208 struct work_struct error_distributor;
208 struct rb_root service_conns; /* Service connections */ 209 struct rb_root service_conns; /* Service connections */
209 rwlock_t conn_lock; 210 seqlock_t service_conn_lock;
210 spinlock_t lock; /* access lock */ 211 spinlock_t lock; /* access lock */
211 unsigned int if_mtu; /* interface MTU for this peer */ 212 unsigned int if_mtu; /* interface MTU for this peer */
212 unsigned int mtu; /* network MTU for this peer */ 213 unsigned int mtu; /* network MTU for this peer */
@@ -559,12 +560,10 @@ extern unsigned int rxrpc_connection_expiry;
559extern struct list_head rxrpc_connections; 560extern struct list_head rxrpc_connections;
560extern rwlock_t rxrpc_connection_lock; 561extern rwlock_t rxrpc_connection_lock;
561 562
562void rxrpc_conn_hash_proto_key(struct rxrpc_conn_proto *); 563int rxrpc_extract_addr_from_skb(struct sockaddr_rxrpc *, struct sk_buff *);
563void rxrpc_extract_conn_params(struct rxrpc_conn_proto *,
564 struct rxrpc_local *, struct sk_buff *);
565struct rxrpc_connection *rxrpc_alloc_connection(gfp_t); 564struct rxrpc_connection *rxrpc_alloc_connection(gfp_t);
566struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_local *, 565struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *,
567 struct sk_buff *); 566 struct sk_buff *);
568void __rxrpc_disconnect_call(struct rxrpc_call *); 567void __rxrpc_disconnect_call(struct rxrpc_call *);
569void rxrpc_disconnect_call(struct rxrpc_call *); 568void rxrpc_disconnect_call(struct rxrpc_call *);
570void rxrpc_put_connection(struct rxrpc_connection *); 569void rxrpc_put_connection(struct rxrpc_connection *);
@@ -591,16 +590,20 @@ struct rxrpc_connection *rxrpc_get_connection_maybe(struct rxrpc_connection *con
591 return atomic_inc_not_zero(&conn->usage) ? conn : NULL; 590 return atomic_inc_not_zero(&conn->usage) ? conn : NULL;
592} 591}
593 592
594static inline void rxrpc_queue_conn(struct rxrpc_connection *conn) 593static inline bool rxrpc_queue_conn(struct rxrpc_connection *conn)
595{ 594{
596 if (rxrpc_get_connection_maybe(conn) && 595 if (!rxrpc_get_connection_maybe(conn))
597 !rxrpc_queue_work(&conn->processor)) 596 return false;
597 if (!rxrpc_queue_work(&conn->processor))
598 rxrpc_put_connection(conn); 598 rxrpc_put_connection(conn);
599 return true;
599} 600}
600 601
601/* 602/*
602 * conn_service.c 603 * conn_service.c
603 */ 604 */
605struct rxrpc_connection *rxrpc_find_service_conn_rcu(struct rxrpc_peer *,
606 struct sk_buff *);
604struct rxrpc_connection *rxrpc_incoming_connection(struct rxrpc_local *, 607struct rxrpc_connection *rxrpc_incoming_connection(struct rxrpc_local *,
605 struct sockaddr_rxrpc *, 608 struct sockaddr_rxrpc *,
606 struct sk_buff *); 609 struct sk_buff *);
diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c
index 917db48d7f59..9e91f27b0d0f 100644
--- a/net/rxrpc/conn_client.c
+++ b/net/rxrpc/conn_client.c
@@ -132,8 +132,6 @@ rxrpc_alloc_client_connection(struct rxrpc_conn_parameters *cp, gfp_t gfp)
132 } 132 }
133 133
134 conn->params = *cp; 134 conn->params = *cp;
135 conn->proto.epoch = rxrpc_epoch;
136 conn->proto.cid = 0;
137 conn->out_clientflag = RXRPC_CLIENT_INITIATED; 135 conn->out_clientflag = RXRPC_CLIENT_INITIATED;
138 conn->state = RXRPC_CONN_CLIENT; 136 conn->state = RXRPC_CONN_CLIENT;
139 137
diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c
index 130713869a16..896d84493a05 100644
--- a/net/rxrpc/conn_object.c
+++ b/net/rxrpc/conn_object.c
@@ -15,7 +15,6 @@
15#include <linux/slab.h> 15#include <linux/slab.h>
16#include <linux/net.h> 16#include <linux/net.h>
17#include <linux/skbuff.h> 17#include <linux/skbuff.h>
18#include <linux/crypto.h>
19#include <net/sock.h> 18#include <net/sock.h>
20#include <net/af_rxrpc.h> 19#include <net/af_rxrpc.h>
21#include "ar-internal.h" 20#include "ar-internal.h"
@@ -64,24 +63,30 @@ struct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp)
64} 63}
65 64
66/* 65/*
67 * find a connection based on transport and RxRPC connection ID for an incoming 66 * Look up a connection in the cache by protocol parameters.
68 * packet 67 *
68 * If successful, a pointer to the connection is returned, but no ref is taken.
69 * NULL is returned if there is no match.
70 *
71 * The caller must be holding the RCU read lock.
69 */ 72 */
70struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_local *local, 73struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *local,
71 struct sk_buff *skb) 74 struct sk_buff *skb)
72{ 75{
73 struct rxrpc_connection *conn; 76 struct rxrpc_connection *conn;
74 struct rxrpc_conn_proto k; 77 struct rxrpc_conn_proto k;
75 struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 78 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
76 struct sockaddr_rxrpc srx; 79 struct sockaddr_rxrpc srx;
77 struct rxrpc_peer *peer; 80 struct rxrpc_peer *peer;
78 struct rb_node *p;
79 81
80 _enter(",{%x,%x}", sp->hdr.cid, sp->hdr.flags); 82 _enter(",%x", sp->hdr.cid & RXRPC_CIDMASK);
81 83
82 if (rxrpc_extract_addr_from_skb(&srx, skb) < 0) 84 if (rxrpc_extract_addr_from_skb(&srx, skb) < 0)
83 goto not_found; 85 goto not_found;
84 86
87 k.epoch = sp->hdr.epoch;
88 k.cid = sp->hdr.cid & RXRPC_CIDMASK;
89
85 /* We may have to handle mixing IPv4 and IPv6 */ 90 /* We may have to handle mixing IPv4 and IPv6 */
86 if (srx.transport.family != local->srx.transport.family) { 91 if (srx.transport.family != local->srx.transport.family) {
87 pr_warn_ratelimited("AF_RXRPC: Protocol mismatch %u not %u\n", 92 pr_warn_ratelimited("AF_RXRPC: Protocol mismatch %u not %u\n",
@@ -101,32 +106,23 @@ struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_local *local,
101 peer = rxrpc_lookup_peer_rcu(local, &srx); 106 peer = rxrpc_lookup_peer_rcu(local, &srx);
102 if (!peer) 107 if (!peer)
103 goto not_found; 108 goto not_found;
104 109 conn = rxrpc_find_service_conn_rcu(peer, skb);
105 read_lock_bh(&peer->conn_lock); 110 if (!conn || atomic_read(&conn->usage) == 0)
106 111 goto not_found;
107 p = peer->service_conns.rb_node; 112 _leave(" = %p", conn);
108 while (p) { 113 return conn;
109 conn = rb_entry(p, struct rxrpc_connection, service_node);
110
111 _debug("maybe %x", conn->proto.cid);
112
113 if (k.epoch < conn->proto.epoch)
114 p = p->rb_left;
115 else if (k.epoch > conn->proto.epoch)
116 p = p->rb_right;
117 else if (k.cid < conn->proto.cid)
118 p = p->rb_left;
119 else if (k.cid > conn->proto.cid)
120 p = p->rb_right;
121 else
122 goto found_service_conn;
123 }
124 read_unlock_bh(&peer->conn_lock);
125 } else { 114 } else {
115 /* Look up client connections by connection ID alone as their
116 * IDs are unique for this machine.
117 */
126 conn = idr_find(&rxrpc_client_conn_ids, 118 conn = idr_find(&rxrpc_client_conn_ids,
127 k.cid >> RXRPC_CIDSHIFT); 119 sp->hdr.cid >> RXRPC_CIDSHIFT);
128 if (!conn || 120 if (!conn || atomic_read(&conn->usage) == 0) {
129 conn->proto.epoch != k.epoch || 121 _debug("no conn");
122 goto not_found;
123 }
124
125 if (conn->proto.epoch != k.epoch ||
130 conn->params.local != local) 126 conn->params.local != local)
131 goto not_found; 127 goto not_found;
132 128
@@ -143,7 +139,6 @@ struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_local *local,
143 BUG(); 139 BUG();
144 } 140 }
145 141
146 conn = rxrpc_get_connection_maybe(conn);
147 _leave(" = %p", conn); 142 _leave(" = %p", conn);
148 return conn; 143 return conn;
149 } 144 }
@@ -151,12 +146,6 @@ struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_local *local,
151not_found: 146not_found:
152 _leave(" = NULL"); 147 _leave(" = NULL");
153 return NULL; 148 return NULL;
154
155found_service_conn:
156 conn = rxrpc_get_connection_maybe(conn);
157 read_unlock_bh(&peer->conn_lock);
158 _leave(" = %p", conn);
159 return conn;
160} 149}
161 150
162/* 151/*
diff --git a/net/rxrpc/conn_service.c b/net/rxrpc/conn_service.c
index c6db2e8400a2..7cbd612be0d7 100644
--- a/net/rxrpc/conn_service.c
+++ b/net/rxrpc/conn_service.c
@@ -13,18 +13,122 @@
13#include "ar-internal.h" 13#include "ar-internal.h"
14 14
15/* 15/*
16 * Find a service connection under RCU conditions.
17 *
18 * We could use a hash table, but that is subject to bucket stuffing by an
19 * attacker as the client gets to pick the epoch and cid values and would know
20 * the hash function. So, instead, we use a hash table for the peer and from
21 * that an rbtree to find the service connection. Under ordinary circumstances
22 * it might be slower than a large hash table, but it is at least limited in
23 * depth.
24 */
25struct rxrpc_connection *rxrpc_find_service_conn_rcu(struct rxrpc_peer *peer,
26 struct sk_buff *skb)
27{
28 struct rxrpc_connection *conn = NULL;
29 struct rxrpc_conn_proto k;
30 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
31 struct rb_node *p;
32 unsigned int seq = 0;
33
34 k.epoch = sp->hdr.epoch;
35 k.cid = sp->hdr.cid & RXRPC_CIDMASK;
36
37 do {
38 /* Unfortunately, rbtree walking doesn't give reliable results
39 * under just the RCU read lock, so we have to check for
40 * changes.
41 */
42 read_seqbegin_or_lock(&peer->service_conn_lock, &seq);
43
44 p = rcu_dereference_raw(peer->service_conns.rb_node);
45 while (p) {
46 conn = rb_entry(p, struct rxrpc_connection, service_node);
47
48 if (conn->proto.index_key < k.index_key)
49 p = rcu_dereference_raw(p->rb_left);
50 else if (conn->proto.index_key > k.index_key)
51 p = rcu_dereference_raw(p->rb_right);
52 else
53 goto done;
54 conn = NULL;
55 }
56 } while (need_seqretry(&peer->service_conn_lock, seq));
57
58done:
59 done_seqretry(&peer->service_conn_lock, seq);
60 _leave(" = %d", conn ? conn->debug_id : -1);
61 return conn;
62}
63
64/*
65 * Insert a service connection into a peer's tree, thereby making it a target
66 * for incoming packets.
67 */
68static struct rxrpc_connection *
69rxrpc_publish_service_conn(struct rxrpc_peer *peer,
70 struct rxrpc_connection *conn)
71{
72 struct rxrpc_connection *cursor = NULL;
73 struct rxrpc_conn_proto k = conn->proto;
74 struct rb_node **pp, *parent;
75
76 write_seqlock_bh(&peer->service_conn_lock);
77
78 pp = &peer->service_conns.rb_node;
79 parent = NULL;
80 while (*pp) {
81 parent = *pp;
82 cursor = rb_entry(parent,
83 struct rxrpc_connection, service_node);
84
85 if (cursor->proto.index_key < k.index_key)
86 pp = &(*pp)->rb_left;
87 else if (cursor->proto.index_key > k.index_key)
88 pp = &(*pp)->rb_right;
89 else
90 goto found_extant_conn;
91 }
92
93 rb_link_node_rcu(&conn->service_node, parent, pp);
94 rb_insert_color(&conn->service_node, &peer->service_conns);
95conn_published:
96 set_bit(RXRPC_CONN_IN_SERVICE_CONNS, &conn->flags);
97 write_sequnlock_bh(&peer->service_conn_lock);
98 _leave(" = %d [new]", conn->debug_id);
99 return conn;
100
101found_extant_conn:
102 if (atomic_read(&cursor->usage) == 0)
103 goto replace_old_connection;
104 write_sequnlock_bh(&peer->service_conn_lock);
105 /* We should not be able to get here. rxrpc_incoming_connection() is
106 * called in a non-reentrant context, so there can't be a race to
107 * insert a new connection.
108 */
109 BUG();
110
111replace_old_connection:
112 /* The old connection is from an outdated epoch. */
113 _debug("replace conn");
114 rb_replace_node_rcu(&cursor->service_node,
115 &conn->service_node,
116 &peer->service_conns);
117 clear_bit(RXRPC_CONN_IN_SERVICE_CONNS, &cursor->flags);
118 goto conn_published;
119}
120
121/*
16 * get a record of an incoming connection 122 * get a record of an incoming connection
17 */ 123 */
18struct rxrpc_connection *rxrpc_incoming_connection(struct rxrpc_local *local, 124struct rxrpc_connection *rxrpc_incoming_connection(struct rxrpc_local *local,
19 struct sockaddr_rxrpc *srx, 125 struct sockaddr_rxrpc *srx,
20 struct sk_buff *skb) 126 struct sk_buff *skb)
21{ 127{
22 struct rxrpc_connection *conn, *candidate = NULL; 128 struct rxrpc_connection *conn;
23 struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 129 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
24 struct rxrpc_peer *peer; 130 struct rxrpc_peer *peer;
25 struct rb_node *p, **pp;
26 const char *new = "old"; 131 const char *new = "old";
27 u32 epoch, cid;
28 132
29 _enter(""); 133 _enter("");
30 134
@@ -36,131 +140,79 @@ struct rxrpc_connection *rxrpc_incoming_connection(struct rxrpc_local *local,
36 140
37 ASSERT(sp->hdr.flags & RXRPC_CLIENT_INITIATED); 141 ASSERT(sp->hdr.flags & RXRPC_CLIENT_INITIATED);
38 142
39 epoch = sp->hdr.epoch; 143 rcu_read_lock();
40 cid = sp->hdr.cid & RXRPC_CIDMASK; 144 peer = rxrpc_lookup_peer_rcu(local, srx);
41 145 if (peer) {
42 /* search the connection list first */ 146 conn = rxrpc_find_service_conn_rcu(peer, skb);
43 read_lock_bh(&peer->conn_lock); 147 if (conn) {
44 148 if (sp->hdr.securityIndex != conn->security_ix)
45 p = peer->service_conns.rb_node; 149 goto security_mismatch_rcu;
46 while (p) { 150 if (rxrpc_get_connection_maybe(conn))
47 conn = rb_entry(p, struct rxrpc_connection, service_node); 151 goto found_extant_connection_rcu;
48 152
49 _debug("maybe %x", conn->proto.cid); 153 /* The conn has expired but we can't remove it without
50 154 * the appropriate lock, so we attempt to replace it
51 if (epoch < conn->proto.epoch) 155 * when we have a new candidate.
52 p = p->rb_left; 156 */
53 else if (epoch > conn->proto.epoch) 157 }
54 p = p->rb_right; 158
55 else if (cid < conn->proto.cid) 159 if (!rxrpc_get_peer_maybe(peer))
56 p = p->rb_left; 160 peer = NULL;
57 else if (cid > conn->proto.cid)
58 p = p->rb_right;
59 else
60 goto found_extant_connection;
61 } 161 }
62 read_unlock_bh(&peer->conn_lock); 162 rcu_read_unlock();
63
64 /* not yet present - create a candidate for a new record and then
65 * redo the search */
66 candidate = rxrpc_alloc_connection(GFP_NOIO);
67 if (!candidate) {
68 rxrpc_put_peer(peer);
69 _leave(" = -ENOMEM");
70 return ERR_PTR(-ENOMEM);
71 }
72
73 candidate->proto.epoch = sp->hdr.epoch;
74 candidate->proto.cid = sp->hdr.cid & RXRPC_CIDMASK;
75 candidate->params.local = local;
76 candidate->params.peer = peer;
77 candidate->params.service_id = sp->hdr.serviceId;
78 candidate->security_ix = sp->hdr.securityIndex;
79 candidate->out_clientflag = 0;
80 candidate->state = RXRPC_CONN_SERVICE;
81 if (candidate->params.service_id)
82 candidate->state = RXRPC_CONN_SERVICE_UNSECURED;
83
84 write_lock_bh(&peer->conn_lock);
85
86 pp = &peer->service_conns.rb_node;
87 p = NULL;
88 while (*pp) {
89 p = *pp;
90 conn = rb_entry(p, struct rxrpc_connection, service_node);
91 163
92 if (epoch < conn->proto.epoch) 164 if (!peer) {
93 pp = &(*pp)->rb_left; 165 peer = rxrpc_lookup_peer(local, srx, GFP_NOIO);
94 else if (epoch > conn->proto.epoch) 166 if (IS_ERR(peer))
95 pp = &(*pp)->rb_right; 167 goto enomem;
96 else if (cid < conn->proto.cid)
97 pp = &(*pp)->rb_left;
98 else if (cid > conn->proto.cid)
99 pp = &(*pp)->rb_right;
100 else
101 goto found_extant_second;
102 } 168 }
103 169
104 /* we can now add the new candidate to the list */ 170 /* We don't have a matching record yet. */
105 set_bit(RXRPC_CONN_IN_SERVICE_CONNS, &candidate->flags); 171 conn = rxrpc_alloc_connection(GFP_NOIO);
106 rb_link_node(&candidate->service_node, p, pp); 172 if (!conn)
107 rb_insert_color(&candidate->service_node, &peer->service_conns); 173 goto enomem_peer;
108attached: 174
109 conn = candidate; 175 conn->proto.epoch = sp->hdr.epoch;
110 candidate = NULL; 176 conn->proto.cid = sp->hdr.cid & RXRPC_CIDMASK;
111 rxrpc_get_peer(peer); 177 conn->params.local = local;
112 rxrpc_get_local(local); 178 conn->params.peer = peer;
179 conn->params.service_id = sp->hdr.serviceId;
180 conn->security_ix = sp->hdr.securityIndex;
181 conn->out_clientflag = 0;
182 conn->state = RXRPC_CONN_SERVICE;
183 if (conn->params.service_id)
184 conn->state = RXRPC_CONN_SERVICE_UNSECURED;
113 185
114 write_unlock_bh(&peer->conn_lock); 186 rxrpc_get_local(local);
115 187
116 write_lock(&rxrpc_connection_lock); 188 write_lock(&rxrpc_connection_lock);
117 list_add_tail(&conn->link, &rxrpc_connections); 189 list_add_tail(&conn->link, &rxrpc_connections);
118 write_unlock(&rxrpc_connection_lock); 190 write_unlock(&rxrpc_connection_lock);
119 191
192 /* Make the connection a target for incoming packets. */
193 rxrpc_publish_service_conn(peer, conn);
194
120 new = "new"; 195 new = "new";
121 196
122success: 197success:
123 _net("CONNECTION %s %d {%x}", new, conn->debug_id, conn->proto.cid); 198 _net("CONNECTION %s %d {%x}", new, conn->debug_id, conn->proto.cid);
124
125 rxrpc_put_peer(peer);
126 _leave(" = %p {u=%d}", conn, atomic_read(&conn->usage)); 199 _leave(" = %p {u=%d}", conn, atomic_read(&conn->usage));
127 return conn; 200 return conn;
128 201
129 /* we found the connection in the list immediately */ 202found_extant_connection_rcu:
130found_extant_connection: 203 rcu_read_unlock();
131 if (!rxrpc_get_connection_maybe(conn)) {
132 set_bit(RXRPC_CONN_IN_SERVICE_CONNS, &candidate->flags);
133 rb_replace_node(&conn->service_node,
134 &candidate->service_node,
135 &peer->service_conns);
136 clear_bit(RXRPC_CONN_IN_SERVICE_CONNS, &conn->flags);
137 goto attached;
138 }
139
140 if (sp->hdr.securityIndex != conn->security_ix) {
141 read_unlock_bh(&peer->conn_lock);
142 goto security_mismatch_put;
143 }
144 read_unlock_bh(&peer->conn_lock);
145 goto success;
146
147 /* we found the connection on the second time through the list */
148found_extant_second:
149 if (sp->hdr.securityIndex != conn->security_ix) {
150 write_unlock_bh(&peer->conn_lock);
151 goto security_mismatch;
152 }
153 rxrpc_get_connection(conn);
154 write_unlock_bh(&peer->conn_lock);
155 kfree(candidate);
156 goto success; 204 goto success;
157 205
158security_mismatch_put: 206security_mismatch_rcu:
159 rxrpc_put_connection(conn); 207 rcu_read_unlock();
160security_mismatch:
161 kfree(candidate);
162 _leave(" = -EKEYREJECTED"); 208 _leave(" = -EKEYREJECTED");
163 return ERR_PTR(-EKEYREJECTED); 209 return ERR_PTR(-EKEYREJECTED);
210
211enomem_peer:
212 rxrpc_put_peer(peer);
213enomem:
214 _leave(" = -ENOMEM");
215 return ERR_PTR(-ENOMEM);
164} 216}
165 217
166/* 218/*
@@ -171,8 +223,8 @@ void rxrpc_unpublish_service_conn(struct rxrpc_connection *conn)
171{ 223{
172 struct rxrpc_peer *peer = conn->params.peer; 224 struct rxrpc_peer *peer = conn->params.peer;
173 225
174 write_lock_bh(&peer->conn_lock); 226 write_seqlock_bh(&peer->service_conn_lock);
175 if (test_and_clear_bit(RXRPC_CONN_IN_SERVICE_CONNS, &conn->flags)) 227 if (test_and_clear_bit(RXRPC_CONN_IN_SERVICE_CONNS, &conn->flags))
176 rb_erase(&conn->service_node, &peer->service_conns); 228 rb_erase(&conn->service_node, &peer->service_conns);
177 write_unlock_bh(&peer->conn_lock); 229 write_sequnlock_bh(&peer->service_conn_lock);
178} 230}
diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c
index c2436476f793..991a20d25093 100644
--- a/net/rxrpc/input.c
+++ b/net/rxrpc/input.c
@@ -575,13 +575,13 @@ done:
575 * post connection-level events to the connection 575 * post connection-level events to the connection
576 * - this includes challenges, responses and some aborts 576 * - this includes challenges, responses and some aborts
577 */ 577 */
578static void rxrpc_post_packet_to_conn(struct rxrpc_connection *conn, 578static bool rxrpc_post_packet_to_conn(struct rxrpc_connection *conn,
579 struct sk_buff *skb) 579 struct sk_buff *skb)
580{ 580{
581 _enter("%p,%p", conn, skb); 581 _enter("%p,%p", conn, skb);
582 582
583 skb_queue_tail(&conn->rx_queue, skb); 583 skb_queue_tail(&conn->rx_queue, skb);
584 rxrpc_queue_conn(conn); 584 return rxrpc_queue_conn(conn);
585} 585}
586 586
587/* 587/*
@@ -636,6 +636,7 @@ int rxrpc_extract_header(struct rxrpc_skb_priv *sp, struct sk_buff *skb)
636 */ 636 */
637void rxrpc_data_ready(struct sock *sk) 637void rxrpc_data_ready(struct sock *sk)
638{ 638{
639 struct rxrpc_connection *conn;
639 struct rxrpc_skb_priv *sp; 640 struct rxrpc_skb_priv *sp;
640 struct rxrpc_local *local = sk->sk_user_data; 641 struct rxrpc_local *local = sk->sk_user_data;
641 struct sk_buff *skb; 642 struct sk_buff *skb;
@@ -699,36 +700,37 @@ void rxrpc_data_ready(struct sock *sk)
699 (sp->hdr.callNumber == 0 || sp->hdr.seq == 0)) 700 (sp->hdr.callNumber == 0 || sp->hdr.seq == 0))
700 goto bad_message; 701 goto bad_message;
701 702
702 if (sp->hdr.callNumber == 0) { 703 rcu_read_lock();
703 /* This is a connection-level packet. These should be 704
704 * fairly rare, so the extra overhead of looking them up the 705retry_find_conn:
705 * old-fashioned way doesn't really hurt */ 706 conn = rxrpc_find_connection_rcu(local, skb);
706 struct rxrpc_connection *conn; 707 if (!conn)
707 708 goto cant_route_call;
708 rcu_read_lock();
709 conn = rxrpc_find_connection(local, skb);
710 rcu_read_unlock();
711 if (!conn)
712 goto cant_route_call;
713 709
710 if (sp->hdr.callNumber == 0) {
711 /* Connection-level packet */
714 _debug("CONN %p {%d}", conn, conn->debug_id); 712 _debug("CONN %p {%d}", conn, conn->debug_id);
715 rxrpc_post_packet_to_conn(conn, skb); 713 if (!rxrpc_post_packet_to_conn(conn, skb))
716 rxrpc_put_connection(conn); 714 goto retry_find_conn;
717 } else { 715 } else {
718 struct rxrpc_call *call; 716 /* Call-bound packets are routed by connection channel. */
717 unsigned int channel = sp->hdr.cid & RXRPC_CHANNELMASK;
718 struct rxrpc_channel *chan = &conn->channels[channel];
719 struct rxrpc_call *call = rcu_dereference(chan->call);
719 720
720 call = rxrpc_find_call_hash(&sp->hdr, local, 721 if (!call || atomic_read(&call->usage) == 0)
721 AF_INET, &ip_hdr(skb)->saddr);
722 if (call)
723 rxrpc_post_packet_to_call(call, skb);
724 else
725 goto cant_route_call; 722 goto cant_route_call;
723
724 rxrpc_post_packet_to_call(call, skb);
726 } 725 }
727 726
727 rcu_read_unlock();
728out: 728out:
729 return; 729 return;
730 730
731cant_route_call: 731cant_route_call:
732 rcu_read_unlock();
733
732 _debug("can't route call"); 734 _debug("can't route call");
733 if (sp->hdr.flags & RXRPC_CLIENT_INITIATED && 735 if (sp->hdr.flags & RXRPC_CLIENT_INITIATED &&
734 sp->hdr.type == RXRPC_PACKET_TYPE_DATA) { 736 sp->hdr.type == RXRPC_PACKET_TYPE_DATA) {
diff --git a/net/rxrpc/peer_object.c b/net/rxrpc/peer_object.c
index 01d4930a11f7..538e9831c699 100644
--- a/net/rxrpc/peer_object.c
+++ b/net/rxrpc/peer_object.c
@@ -189,7 +189,7 @@ struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *local, gfp_t gfp)
189 INIT_WORK(&peer->error_distributor, 189 INIT_WORK(&peer->error_distributor,
190 &rxrpc_peer_error_distributor); 190 &rxrpc_peer_error_distributor);
191 peer->service_conns = RB_ROOT; 191 peer->service_conns = RB_ROOT;
192 rwlock_init(&peer->conn_lock); 192 seqlock_init(&peer->service_conn_lock);
193 spin_lock_init(&peer->lock); 193 spin_lock_init(&peer->lock);
194 peer->debug_id = atomic_inc_return(&rxrpc_debug_id); 194 peer->debug_id = atomic_inc_return(&rxrpc_debug_id);
195 } 195 }