aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2007-09-16 19:03:28 -0400
committerDavid S. Miller <davem@davemloft.net>2007-09-16 19:03:28 -0400
commit559cf710b07c5e2cfa3fb8d8f4a1320fd84c53f9 (patch)
treedeb74aea811a7d7c7e203f3743fd15372f8a6589 /net
parent293035479942400a7fe8e4f72465d4e4e466b91a (diff)
[SCTP]: Convert bind_addr_list locking to RCU
Since the sctp_sockaddr_entry is now RCU enabled as part of the patch to synchronize sctp_localaddr_list, it makes sense to change all handling of these entries to RCU. This includes the sctp_bind_addrs structure and it's list of bound addresses. This list is currently protected by an external rw_lock and that looks like an overkill. There are only 2 writers to the list: bind()/bindx() calls, and BH processing of ASCONF-ACK chunks. These are already seriealized via the socket lock, so they will not step on each other. These are also relatively rare, so we should be good with RCU. The readers are varied and they are easily converted to RCU. Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com> Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Acked-by: Sridhar Samdurala <sri@us.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/sctp/associola.c14
-rw-r--r--net/sctp/bind_addr.c68
-rw-r--r--net/sctp/endpointola.c27
-rw-r--r--net/sctp/ipv6.c12
-rw-r--r--net/sctp/protocol.c25
-rw-r--r--net/sctp/sm_make_chunk.c18
-rw-r--r--net/sctp/socket.c98
7 files changed, 103 insertions, 159 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 2ad1caf1ea42..9bad8ba0feda 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -99,7 +99,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
99 99
100 /* Initialize the bind addr area. */ 100 /* Initialize the bind addr area. */
101 sctp_bind_addr_init(&asoc->base.bind_addr, ep->base.bind_addr.port); 101 sctp_bind_addr_init(&asoc->base.bind_addr, ep->base.bind_addr.port);
102 rwlock_init(&asoc->base.addr_lock);
103 102
104 asoc->state = SCTP_STATE_CLOSED; 103 asoc->state = SCTP_STATE_CLOSED;
105 104
@@ -937,8 +936,6 @@ struct sctp_transport *sctp_assoc_is_match(struct sctp_association *asoc,
937{ 936{
938 struct sctp_transport *transport; 937 struct sctp_transport *transport;
939 938
940 sctp_read_lock(&asoc->base.addr_lock);
941
942 if ((htons(asoc->base.bind_addr.port) == laddr->v4.sin_port) && 939 if ((htons(asoc->base.bind_addr.port) == laddr->v4.sin_port) &&
943 (htons(asoc->peer.port) == paddr->v4.sin_port)) { 940 (htons(asoc->peer.port) == paddr->v4.sin_port)) {
944 transport = sctp_assoc_lookup_paddr(asoc, paddr); 941 transport = sctp_assoc_lookup_paddr(asoc, paddr);
@@ -952,7 +949,6 @@ struct sctp_transport *sctp_assoc_is_match(struct sctp_association *asoc,
952 transport = NULL; 949 transport = NULL;
953 950
954out: 951out:
955 sctp_read_unlock(&asoc->base.addr_lock);
956 return transport; 952 return transport;
957} 953}
958 954
@@ -1376,19 +1372,13 @@ int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *asoc,
1376int sctp_assoc_lookup_laddr(struct sctp_association *asoc, 1372int sctp_assoc_lookup_laddr(struct sctp_association *asoc,
1377 const union sctp_addr *laddr) 1373 const union sctp_addr *laddr)
1378{ 1374{
1379 int found; 1375 int found = 0;
1380 1376
1381 sctp_read_lock(&asoc->base.addr_lock);
1382 if ((asoc->base.bind_addr.port == ntohs(laddr->v4.sin_port)) && 1377 if ((asoc->base.bind_addr.port == ntohs(laddr->v4.sin_port)) &&
1383 sctp_bind_addr_match(&asoc->base.bind_addr, laddr, 1378 sctp_bind_addr_match(&asoc->base.bind_addr, laddr,
1384 sctp_sk(asoc->base.sk))) { 1379 sctp_sk(asoc->base.sk)))
1385 found = 1; 1380 found = 1;
1386 goto out;
1387 }
1388 1381
1389 found = 0;
1390out:
1391 sctp_read_unlock(&asoc->base.addr_lock);
1392 return found; 1382 return found;
1393} 1383}
1394 1384
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index 7fc369f9035d..d35cbf5aae33 100644
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@ -167,7 +167,11 @@ int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,
167 167
168 INIT_LIST_HEAD(&addr->list); 168 INIT_LIST_HEAD(&addr->list);
169 INIT_RCU_HEAD(&addr->rcu); 169 INIT_RCU_HEAD(&addr->rcu);
170 list_add_tail(&addr->list, &bp->address_list); 170
171 /* We always hold a socket lock when calling this function,
172 * and that acts as a writer synchronizing lock.
173 */
174 list_add_tail_rcu(&addr->list, &bp->address_list);
171 SCTP_DBG_OBJCNT_INC(addr); 175 SCTP_DBG_OBJCNT_INC(addr);
172 176
173 return 0; 177 return 0;
@@ -176,23 +180,35 @@ int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,
176/* Delete an address from the bind address list in the SCTP_bind_addr 180/* Delete an address from the bind address list in the SCTP_bind_addr
177 * structure. 181 * structure.
178 */ 182 */
179int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr) 183int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr,
184 void (*rcu_call)(struct rcu_head *head,
185 void (*func)(struct rcu_head *head)))
180{ 186{
181 struct list_head *pos, *temp; 187 struct sctp_sockaddr_entry *addr, *temp;
182 struct sctp_sockaddr_entry *addr;
183 188
184 list_for_each_safe(pos, temp, &bp->address_list) { 189 /* We hold the socket lock when calling this function,
185 addr = list_entry(pos, struct sctp_sockaddr_entry, list); 190 * and that acts as a writer synchronizing lock.
191 */
192 list_for_each_entry_safe(addr, temp, &bp->address_list, list) {
186 if (sctp_cmp_addr_exact(&addr->a, del_addr)) { 193 if (sctp_cmp_addr_exact(&addr->a, del_addr)) {
187 /* Found the exact match. */ 194 /* Found the exact match. */
188 list_del(pos); 195 addr->valid = 0;
189 kfree(addr); 196 list_del_rcu(&addr->list);
190 SCTP_DBG_OBJCNT_DEC(addr); 197 break;
191
192 return 0;
193 } 198 }
194 } 199 }
195 200
201 /* Call the rcu callback provided in the args. This function is
202 * called by both BH packet processing and user side socket option
203 * processing, but it works on different lists in those 2 contexts.
204 * Each context provides it's own callback, whether call_rcu_bh()
205 * or call_rcu(), to make sure that we wait for an appropriate time.
206 */
207 if (addr && !addr->valid) {
208 rcu_call(&addr->rcu, sctp_local_addr_free);
209 SCTP_DBG_OBJCNT_DEC(addr);
210 }
211
196 return -EINVAL; 212 return -EINVAL;
197} 213}
198 214
@@ -302,15 +318,20 @@ int sctp_bind_addr_match(struct sctp_bind_addr *bp,
302 struct sctp_sock *opt) 318 struct sctp_sock *opt)
303{ 319{
304 struct sctp_sockaddr_entry *laddr; 320 struct sctp_sockaddr_entry *laddr;
305 struct list_head *pos; 321 int match = 0;
306 322
307 list_for_each(pos, &bp->address_list) { 323 rcu_read_lock();
308 laddr = list_entry(pos, struct sctp_sockaddr_entry, list); 324 list_for_each_entry_rcu(laddr, &bp->address_list, list) {
309 if (opt->pf->cmp_addr(&laddr->a, addr, opt)) 325 if (!laddr->valid)
310 return 1; 326 continue;
327 if (opt->pf->cmp_addr(&laddr->a, addr, opt)) {
328 match = 1;
329 break;
330 }
311 } 331 }
332 rcu_read_unlock();
312 333
313 return 0; 334 return match;
314} 335}
315 336
316/* Find the first address in the bind address list that is not present in 337/* Find the first address in the bind address list that is not present in
@@ -325,18 +346,19 @@ union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp,
325 union sctp_addr *addr; 346 union sctp_addr *addr;
326 void *addr_buf; 347 void *addr_buf;
327 struct sctp_af *af; 348 struct sctp_af *af;
328 struct list_head *pos;
329 int i; 349 int i;
330 350
331 list_for_each(pos, &bp->address_list) { 351 /* This is only called sctp_send_asconf_del_ip() and we hold
332 laddr = list_entry(pos, struct sctp_sockaddr_entry, list); 352 * the socket lock in that code patch, so that address list
333 353 * can't change.
354 */
355 list_for_each_entry(laddr, &bp->address_list, list) {
334 addr_buf = (union sctp_addr *)addrs; 356 addr_buf = (union sctp_addr *)addrs;
335 for (i = 0; i < addrcnt; i++) { 357 for (i = 0; i < addrcnt; i++) {
336 addr = (union sctp_addr *)addr_buf; 358 addr = (union sctp_addr *)addr_buf;
337 af = sctp_get_af_specific(addr->v4.sin_family); 359 af = sctp_get_af_specific(addr->v4.sin_family);
338 if (!af) 360 if (!af)
339 return NULL; 361 break;
340 362
341 if (opt->pf->cmp_addr(&laddr->a, addr, opt)) 363 if (opt->pf->cmp_addr(&laddr->a, addr, opt))
342 break; 364 break;
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
index 1404a9e2e78f..8f485a0d14bd 100644
--- a/net/sctp/endpointola.c
+++ b/net/sctp/endpointola.c
@@ -92,7 +92,6 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
92 92
93 /* Initialize the bind addr area */ 93 /* Initialize the bind addr area */
94 sctp_bind_addr_init(&ep->base.bind_addr, 0); 94 sctp_bind_addr_init(&ep->base.bind_addr, 0);
95 rwlock_init(&ep->base.addr_lock);
96 95
97 /* Remember who we are attached to. */ 96 /* Remember who we are attached to. */
98 ep->base.sk = sk; 97 ep->base.sk = sk;
@@ -225,21 +224,14 @@ void sctp_endpoint_put(struct sctp_endpoint *ep)
225struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep, 224struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
226 const union sctp_addr *laddr) 225 const union sctp_addr *laddr)
227{ 226{
228 struct sctp_endpoint *retval; 227 struct sctp_endpoint *retval = NULL;
229 228
230 sctp_read_lock(&ep->base.addr_lock);
231 if (htons(ep->base.bind_addr.port) == laddr->v4.sin_port) { 229 if (htons(ep->base.bind_addr.port) == laddr->v4.sin_port) {
232 if (sctp_bind_addr_match(&ep->base.bind_addr, laddr, 230 if (sctp_bind_addr_match(&ep->base.bind_addr, laddr,
233 sctp_sk(ep->base.sk))) { 231 sctp_sk(ep->base.sk)))
234 retval = ep; 232 retval = ep;
235 goto out;
236 }
237 } 233 }
238 234
239 retval = NULL;
240
241out:
242 sctp_read_unlock(&ep->base.addr_lock);
243 return retval; 235 return retval;
244} 236}
245 237
@@ -261,9 +253,7 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc(
261 list_for_each(pos, &ep->asocs) { 253 list_for_each(pos, &ep->asocs) {
262 asoc = list_entry(pos, struct sctp_association, asocs); 254 asoc = list_entry(pos, struct sctp_association, asocs);
263 if (rport == asoc->peer.port) { 255 if (rport == asoc->peer.port) {
264 sctp_read_lock(&asoc->base.addr_lock);
265 *transport = sctp_assoc_lookup_paddr(asoc, paddr); 256 *transport = sctp_assoc_lookup_paddr(asoc, paddr);
266 sctp_read_unlock(&asoc->base.addr_lock);
267 257
268 if (*transport) 258 if (*transport)
269 return asoc; 259 return asoc;
@@ -295,20 +285,17 @@ struct sctp_association *sctp_endpoint_lookup_assoc(
295int sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep, 285int sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep,
296 const union sctp_addr *paddr) 286 const union sctp_addr *paddr)
297{ 287{
298 struct list_head *pos;
299 struct sctp_sockaddr_entry *addr; 288 struct sctp_sockaddr_entry *addr;
300 struct sctp_bind_addr *bp; 289 struct sctp_bind_addr *bp;
301 290
302 sctp_read_lock(&ep->base.addr_lock);
303 bp = &ep->base.bind_addr; 291 bp = &ep->base.bind_addr;
304 list_for_each(pos, &bp->address_list) { 292 /* This function is called with the socket lock held,
305 addr = list_entry(pos, struct sctp_sockaddr_entry, list); 293 * so the address_list can not change.
306 if (sctp_has_association(&addr->a, paddr)) { 294 */
307 sctp_read_unlock(&ep->base.addr_lock); 295 list_for_each_entry(addr, &bp->address_list, list) {
296 if (sctp_has_association(&addr->a, paddr))
308 return 1; 297 return 1;
309 }
310 } 298 }
311 sctp_read_unlock(&ep->base.addr_lock);
312 299
313 return 0; 300 return 0;
314} 301}
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index e12fa0a91da4..670fd2740b89 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -302,9 +302,7 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
302 union sctp_addr *saddr) 302 union sctp_addr *saddr)
303{ 303{
304 struct sctp_bind_addr *bp; 304 struct sctp_bind_addr *bp;
305 rwlock_t *addr_lock;
306 struct sctp_sockaddr_entry *laddr; 305 struct sctp_sockaddr_entry *laddr;
307 struct list_head *pos;
308 sctp_scope_t scope; 306 sctp_scope_t scope;
309 union sctp_addr *baddr = NULL; 307 union sctp_addr *baddr = NULL;
310 __u8 matchlen = 0; 308 __u8 matchlen = 0;
@@ -324,14 +322,14 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
324 scope = sctp_scope(daddr); 322 scope = sctp_scope(daddr);
325 323
326 bp = &asoc->base.bind_addr; 324 bp = &asoc->base.bind_addr;
327 addr_lock = &asoc->base.addr_lock;
328 325
329 /* Go through the bind address list and find the best source address 326 /* Go through the bind address list and find the best source address
330 * that matches the scope of the destination address. 327 * that matches the scope of the destination address.
331 */ 328 */
332 sctp_read_lock(addr_lock); 329 rcu_read_lock();
333 list_for_each(pos, &bp->address_list) { 330 list_for_each_entry_rcu(laddr, &bp->address_list, list) {
334 laddr = list_entry(pos, struct sctp_sockaddr_entry, list); 331 if (!laddr->valid)
332 continue;
335 if ((laddr->use_as_src) && 333 if ((laddr->use_as_src) &&
336 (laddr->a.sa.sa_family == AF_INET6) && 334 (laddr->a.sa.sa_family == AF_INET6) &&
337 (scope <= sctp_scope(&laddr->a))) { 335 (scope <= sctp_scope(&laddr->a))) {
@@ -353,7 +351,7 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
353 __FUNCTION__, asoc, NIP6(daddr->v6.sin6_addr)); 351 __FUNCTION__, asoc, NIP6(daddr->v6.sin6_addr));
354 } 352 }
355 353
356 sctp_read_unlock(addr_lock); 354 rcu_read_unlock();
357} 355}
358 356
359/* Make a copy of all potential local addresses. */ 357/* Make a copy of all potential local addresses. */
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 7ee120e85913..3d036cdfae41 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -224,7 +224,7 @@ int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
224 (copy_flags & SCTP_ADDR6_ALLOWED) && 224 (copy_flags & SCTP_ADDR6_ALLOWED) &&
225 (copy_flags & SCTP_ADDR6_PEERSUPP)))) { 225 (copy_flags & SCTP_ADDR6_PEERSUPP)))) {
226 error = sctp_add_bind_addr(bp, &addr->a, 1, 226 error = sctp_add_bind_addr(bp, &addr->a, 1,
227 GFP_ATOMIC); 227 GFP_ATOMIC);
228 if (error) 228 if (error)
229 goto end_copy; 229 goto end_copy;
230 } 230 }
@@ -428,9 +428,7 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
428 struct rtable *rt; 428 struct rtable *rt;
429 struct flowi fl; 429 struct flowi fl;
430 struct sctp_bind_addr *bp; 430 struct sctp_bind_addr *bp;
431 rwlock_t *addr_lock;
432 struct sctp_sockaddr_entry *laddr; 431 struct sctp_sockaddr_entry *laddr;
433 struct list_head *pos;
434 struct dst_entry *dst = NULL; 432 struct dst_entry *dst = NULL;
435 union sctp_addr dst_saddr; 433 union sctp_addr dst_saddr;
436 434
@@ -459,23 +457,20 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
459 goto out; 457 goto out;
460 458
461 bp = &asoc->base.bind_addr; 459 bp = &asoc->base.bind_addr;
462 addr_lock = &asoc->base.addr_lock;
463 460
464 if (dst) { 461 if (dst) {
465 /* Walk through the bind address list and look for a bind 462 /* Walk through the bind address list and look for a bind
466 * address that matches the source address of the returned dst. 463 * address that matches the source address of the returned dst.
467 */ 464 */
468 sctp_read_lock(addr_lock); 465 rcu_read_lock();
469 list_for_each(pos, &bp->address_list) { 466 list_for_each_entry_rcu(laddr, &bp->address_list, list) {
470 laddr = list_entry(pos, struct sctp_sockaddr_entry, 467 if (!laddr->valid || !laddr->use_as_src)
471 list);
472 if (!laddr->use_as_src)
473 continue; 468 continue;
474 sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port)); 469 sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port));
475 if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a)) 470 if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
476 goto out_unlock; 471 goto out_unlock;
477 } 472 }
478 sctp_read_unlock(addr_lock); 473 rcu_read_unlock();
479 474
480 /* None of the bound addresses match the source address of the 475 /* None of the bound addresses match the source address of the
481 * dst. So release it. 476 * dst. So release it.
@@ -487,10 +482,10 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
487 /* Walk through the bind address list and try to get a dst that 482 /* Walk through the bind address list and try to get a dst that
488 * matches a bind address as the source address. 483 * matches a bind address as the source address.
489 */ 484 */
490 sctp_read_lock(addr_lock); 485 rcu_read_lock();
491 list_for_each(pos, &bp->address_list) { 486 list_for_each_entry_rcu(laddr, &bp->address_list, list) {
492 laddr = list_entry(pos, struct sctp_sockaddr_entry, list); 487 if (!laddr->valid)
493 488 continue;
494 if ((laddr->use_as_src) && 489 if ((laddr->use_as_src) &&
495 (AF_INET == laddr->a.sa.sa_family)) { 490 (AF_INET == laddr->a.sa.sa_family)) {
496 fl.fl4_src = laddr->a.v4.sin_addr.s_addr; 491 fl.fl4_src = laddr->a.v4.sin_addr.s_addr;
@@ -502,7 +497,7 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
502 } 497 }
503 498
504out_unlock: 499out_unlock:
505 sctp_read_unlock(addr_lock); 500 rcu_read_unlock();
506out: 501out:
507 if (dst) 502 if (dst)
508 SCTP_DEBUG_PRINTK("rt_dst:%u.%u.%u.%u, rt_src:%u.%u.%u.%u\n", 503 SCTP_DEBUG_PRINTK("rt_dst:%u.%u.%u.%u, rt_src:%u.%u.%u.%u\n",
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 79856c924525..2e34220d94cd 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1531,7 +1531,7 @@ no_hmac:
1531 /* Also, add the destination address. */ 1531 /* Also, add the destination address. */
1532 if (list_empty(&retval->base.bind_addr.address_list)) { 1532 if (list_empty(&retval->base.bind_addr.address_list)) {
1533 sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest, 1, 1533 sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest, 1,
1534 GFP_ATOMIC); 1534 GFP_ATOMIC);
1535 } 1535 }
1536 1536
1537 retval->next_tsn = retval->c.initial_tsn; 1537 retval->next_tsn = retval->c.initial_tsn;
@@ -2613,22 +2613,16 @@ static int sctp_asconf_param_success(struct sctp_association *asoc,
2613 2613
2614 switch (asconf_param->param_hdr.type) { 2614 switch (asconf_param->param_hdr.type) {
2615 case SCTP_PARAM_ADD_IP: 2615 case SCTP_PARAM_ADD_IP:
2616 sctp_local_bh_disable(); 2616 /* This is always done in BH context with a socket lock
2617 sctp_write_lock(&asoc->base.addr_lock); 2617 * held, so the list can not change.
2618 list_for_each(pos, &bp->address_list) { 2618 */
2619 saddr = list_entry(pos, struct sctp_sockaddr_entry, list); 2619 list_for_each_entry(saddr, &bp->address_list, list) {
2620 if (sctp_cmp_addr_exact(&saddr->a, &addr)) 2620 if (sctp_cmp_addr_exact(&saddr->a, &addr))
2621 saddr->use_as_src = 1; 2621 saddr->use_as_src = 1;
2622 } 2622 }
2623 sctp_write_unlock(&asoc->base.addr_lock);
2624 sctp_local_bh_enable();
2625 break; 2623 break;
2626 case SCTP_PARAM_DEL_IP: 2624 case SCTP_PARAM_DEL_IP:
2627 sctp_local_bh_disable(); 2625 retval = sctp_del_bind_addr(bp, &addr, call_rcu_bh);
2628 sctp_write_lock(&asoc->base.addr_lock);
2629 retval = sctp_del_bind_addr(bp, &addr);
2630 sctp_write_unlock(&asoc->base.addr_lock);
2631 sctp_local_bh_enable();
2632 list_for_each(pos, &asoc->peer.transport_addr_list) { 2626 list_for_each(pos, &asoc->peer.transport_addr_list) {
2633 transport = list_entry(pos, struct sctp_transport, 2627 transport = list_entry(pos, struct sctp_transport,
2634 transports); 2628 transports);
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index a3acf78d06ba..772fbfb4bfda 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -367,14 +367,10 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
367 if (!bp->port) 367 if (!bp->port)
368 bp->port = inet_sk(sk)->num; 368 bp->port = inet_sk(sk)->num;
369 369
370 /* Add the address to the bind address list. */ 370 /* Add the address to the bind address list.
371 sctp_local_bh_disable(); 371 * Use GFP_ATOMIC since BHs will be disabled.
372 sctp_write_lock(&ep->base.addr_lock); 372 */
373
374 /* Use GFP_ATOMIC since BHs are disabled. */
375 ret = sctp_add_bind_addr(bp, addr, 1, GFP_ATOMIC); 373 ret = sctp_add_bind_addr(bp, addr, 1, GFP_ATOMIC);
376 sctp_write_unlock(&ep->base.addr_lock);
377 sctp_local_bh_enable();
378 374
379 /* Copy back into socket for getsockname() use. */ 375 /* Copy back into socket for getsockname() use. */
380 if (!ret) { 376 if (!ret) {
@@ -544,15 +540,12 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
544 if (i < addrcnt) 540 if (i < addrcnt)
545 continue; 541 continue;
546 542
547 /* Use the first address in bind addr list of association as 543 /* Use the first valid address in bind addr list of
548 * Address Parameter of ASCONF CHUNK. 544 * association as Address Parameter of ASCONF CHUNK.
549 */ 545 */
550 sctp_read_lock(&asoc->base.addr_lock);
551 bp = &asoc->base.bind_addr; 546 bp = &asoc->base.bind_addr;
552 p = bp->address_list.next; 547 p = bp->address_list.next;
553 laddr = list_entry(p, struct sctp_sockaddr_entry, list); 548 laddr = list_entry(p, struct sctp_sockaddr_entry, list);
554 sctp_read_unlock(&asoc->base.addr_lock);
555
556 chunk = sctp_make_asconf_update_ip(asoc, &laddr->a, addrs, 549 chunk = sctp_make_asconf_update_ip(asoc, &laddr->a, addrs,
557 addrcnt, SCTP_PARAM_ADD_IP); 550 addrcnt, SCTP_PARAM_ADD_IP);
558 if (!chunk) { 551 if (!chunk) {
@@ -567,8 +560,6 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
567 /* Add the new addresses to the bind address list with 560 /* Add the new addresses to the bind address list with
568 * use_as_src set to 0. 561 * use_as_src set to 0.
569 */ 562 */
570 sctp_local_bh_disable();
571 sctp_write_lock(&asoc->base.addr_lock);
572 addr_buf = addrs; 563 addr_buf = addrs;
573 for (i = 0; i < addrcnt; i++) { 564 for (i = 0; i < addrcnt; i++) {
574 addr = (union sctp_addr *)addr_buf; 565 addr = (union sctp_addr *)addr_buf;
@@ -578,8 +569,6 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
578 GFP_ATOMIC); 569 GFP_ATOMIC);
579 addr_buf += af->sockaddr_len; 570 addr_buf += af->sockaddr_len;
580 } 571 }
581 sctp_write_unlock(&asoc->base.addr_lock);
582 sctp_local_bh_enable();
583 } 572 }
584 573
585out: 574out:
@@ -651,13 +640,7 @@ static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt)
651 * socket routing and failover schemes. Refer to comments in 640 * socket routing and failover schemes. Refer to comments in
652 * sctp_do_bind(). -daisy 641 * sctp_do_bind(). -daisy
653 */ 642 */
654 sctp_local_bh_disable(); 643 retval = sctp_del_bind_addr(bp, sa_addr, call_rcu);
655 sctp_write_lock(&ep->base.addr_lock);
656
657 retval = sctp_del_bind_addr(bp, sa_addr);
658
659 sctp_write_unlock(&ep->base.addr_lock);
660 sctp_local_bh_enable();
661 644
662 addr_buf += af->sockaddr_len; 645 addr_buf += af->sockaddr_len;
663err_bindx_rem: 646err_bindx_rem:
@@ -748,14 +731,16 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
748 * make sure that we do not delete all the addresses in the 731 * make sure that we do not delete all the addresses in the
749 * association. 732 * association.
750 */ 733 */
751 sctp_read_lock(&asoc->base.addr_lock);
752 bp = &asoc->base.bind_addr; 734 bp = &asoc->base.bind_addr;
753 laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs, 735 laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs,
754 addrcnt, sp); 736 addrcnt, sp);
755 sctp_read_unlock(&asoc->base.addr_lock);
756 if (!laddr) 737 if (!laddr)
757 continue; 738 continue;
758 739
740 /* We do not need RCU protection throughout this loop
741 * because this is done under a socket lock from the
742 * setsockopt call.
743 */
759 chunk = sctp_make_asconf_update_ip(asoc, laddr, addrs, addrcnt, 744 chunk = sctp_make_asconf_update_ip(asoc, laddr, addrs, addrcnt,
760 SCTP_PARAM_DEL_IP); 745 SCTP_PARAM_DEL_IP);
761 if (!chunk) { 746 if (!chunk) {
@@ -766,23 +751,16 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
766 /* Reset use_as_src flag for the addresses in the bind address 751 /* Reset use_as_src flag for the addresses in the bind address
767 * list that are to be deleted. 752 * list that are to be deleted.
768 */ 753 */
769 sctp_local_bh_disable();
770 sctp_write_lock(&asoc->base.addr_lock);
771 addr_buf = addrs; 754 addr_buf = addrs;
772 for (i = 0; i < addrcnt; i++) { 755 for (i = 0; i < addrcnt; i++) {
773 laddr = (union sctp_addr *)addr_buf; 756 laddr = (union sctp_addr *)addr_buf;
774 af = sctp_get_af_specific(laddr->v4.sin_family); 757 af = sctp_get_af_specific(laddr->v4.sin_family);
775 list_for_each(pos1, &bp->address_list) { 758 list_for_each_entry(saddr, &bp->address_list, list) {
776 saddr = list_entry(pos1,
777 struct sctp_sockaddr_entry,
778 list);
779 if (sctp_cmp_addr_exact(&saddr->a, laddr)) 759 if (sctp_cmp_addr_exact(&saddr->a, laddr))
780 saddr->use_as_src = 0; 760 saddr->use_as_src = 0;
781 } 761 }
782 addr_buf += af->sockaddr_len; 762 addr_buf += af->sockaddr_len;
783 } 763 }
784 sctp_write_unlock(&asoc->base.addr_lock);
785 sctp_local_bh_enable();
786 764
787 /* Update the route and saddr entries for all the transports 765 /* Update the route and saddr entries for all the transports
788 * as some of the addresses in the bind address list are 766 * as some of the addresses in the bind address list are
@@ -4057,11 +4035,9 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
4057 int __user *optlen) 4035 int __user *optlen)
4058{ 4036{
4059 sctp_assoc_t id; 4037 sctp_assoc_t id;
4060 struct list_head *pos;
4061 struct sctp_bind_addr *bp; 4038 struct sctp_bind_addr *bp;
4062 struct sctp_association *asoc; 4039 struct sctp_association *asoc;
4063 struct sctp_sockaddr_entry *addr; 4040 struct sctp_sockaddr_entry *addr;
4064 rwlock_t *addr_lock;
4065 int cnt = 0; 4041 int cnt = 0;
4066 4042
4067 if (len < sizeof(sctp_assoc_t)) 4043 if (len < sizeof(sctp_assoc_t))
@@ -4078,17 +4054,13 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
4078 */ 4054 */
4079 if (0 == id) { 4055 if (0 == id) {
4080 bp = &sctp_sk(sk)->ep->base.bind_addr; 4056 bp = &sctp_sk(sk)->ep->base.bind_addr;
4081 addr_lock = &sctp_sk(sk)->ep->base.addr_lock;
4082 } else { 4057 } else {
4083 asoc = sctp_id2assoc(sk, id); 4058 asoc = sctp_id2assoc(sk, id);
4084 if (!asoc) 4059 if (!asoc)
4085 return -EINVAL; 4060 return -EINVAL;
4086 bp = &asoc->base.bind_addr; 4061 bp = &asoc->base.bind_addr;
4087 addr_lock = &asoc->base.addr_lock;
4088 } 4062 }
4089 4063
4090 sctp_read_lock(addr_lock);
4091
4092 /* If the endpoint is bound to 0.0.0.0 or ::0, count the valid 4064 /* If the endpoint is bound to 0.0.0.0 or ::0, count the valid
4093 * addresses from the global local address list. 4065 * addresses from the global local address list.
4094 */ 4066 */
@@ -4115,12 +4087,14 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
4115 goto done; 4087 goto done;
4116 } 4088 }
4117 4089
4118 list_for_each(pos, &bp->address_list) { 4090 /* Protection on the bound address list is not needed,
4091 * since in the socket option context we hold the socket lock,
4092 * so there is no way that the bound address list can change.
4093 */
4094 list_for_each_entry(addr, &bp->address_list, list) {
4119 cnt ++; 4095 cnt ++;
4120 } 4096 }
4121
4122done: 4097done:
4123 sctp_read_unlock(addr_lock);
4124 return cnt; 4098 return cnt;
4125} 4099}
4126 4100
@@ -4204,7 +4178,6 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
4204{ 4178{
4205 struct sctp_bind_addr *bp; 4179 struct sctp_bind_addr *bp;
4206 struct sctp_association *asoc; 4180 struct sctp_association *asoc;
4207 struct list_head *pos;
4208 int cnt = 0; 4181 int cnt = 0;
4209 struct sctp_getaddrs_old getaddrs; 4182 struct sctp_getaddrs_old getaddrs;
4210 struct sctp_sockaddr_entry *addr; 4183 struct sctp_sockaddr_entry *addr;
@@ -4212,7 +4185,6 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
4212 union sctp_addr temp; 4185 union sctp_addr temp;
4213 struct sctp_sock *sp = sctp_sk(sk); 4186 struct sctp_sock *sp = sctp_sk(sk);
4214 int addrlen; 4187 int addrlen;
4215 rwlock_t *addr_lock;
4216 int err = 0; 4188 int err = 0;
4217 void *addrs; 4189 void *addrs;
4218 void *buf; 4190 void *buf;
@@ -4234,13 +4206,11 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
4234 */ 4206 */
4235 if (0 == getaddrs.assoc_id) { 4207 if (0 == getaddrs.assoc_id) {
4236 bp = &sctp_sk(sk)->ep->base.bind_addr; 4208 bp = &sctp_sk(sk)->ep->base.bind_addr;
4237 addr_lock = &sctp_sk(sk)->ep->base.addr_lock;
4238 } else { 4209 } else {
4239 asoc = sctp_id2assoc(sk, getaddrs.assoc_id); 4210 asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
4240 if (!asoc) 4211 if (!asoc)
4241 return -EINVAL; 4212 return -EINVAL;
4242 bp = &asoc->base.bind_addr; 4213 bp = &asoc->base.bind_addr;
4243 addr_lock = &asoc->base.addr_lock;
4244 } 4214 }
4245 4215
4246 to = getaddrs.addrs; 4216 to = getaddrs.addrs;
@@ -4254,8 +4224,6 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
4254 if (!addrs) 4224 if (!addrs)
4255 return -ENOMEM; 4225 return -ENOMEM;
4256 4226
4257 sctp_read_lock(addr_lock);
4258
4259 /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid 4227 /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
4260 * addresses from the global local address list. 4228 * addresses from the global local address list.
4261 */ 4229 */
@@ -4271,8 +4239,11 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
4271 } 4239 }
4272 4240
4273 buf = addrs; 4241 buf = addrs;
4274 list_for_each(pos, &bp->address_list) { 4242 /* Protection on the bound address list is not needed since
4275 addr = list_entry(pos, struct sctp_sockaddr_entry, list); 4243 * in the socket option context we hold a socket lock and
4244 * thus the bound address list can't change.
4245 */
4246 list_for_each_entry(addr, &bp->address_list, list) {
4276 memcpy(&temp, &addr->a, sizeof(temp)); 4247 memcpy(&temp, &addr->a, sizeof(temp));
4277 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); 4248 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
4278 addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; 4249 addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
@@ -4284,8 +4255,6 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
4284 } 4255 }
4285 4256
4286copy_getaddrs: 4257copy_getaddrs:
4287 sctp_read_unlock(addr_lock);
4288
4289 /* copy the entire address list into the user provided space */ 4258 /* copy the entire address list into the user provided space */
4290 if (copy_to_user(to, addrs, bytes_copied)) { 4259 if (copy_to_user(to, addrs, bytes_copied)) {
4291 err = -EFAULT; 4260 err = -EFAULT;
@@ -4307,7 +4276,6 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
4307{ 4276{
4308 struct sctp_bind_addr *bp; 4277 struct sctp_bind_addr *bp;
4309 struct sctp_association *asoc; 4278 struct sctp_association *asoc;
4310 struct list_head *pos;
4311 int cnt = 0; 4279 int cnt = 0;
4312 struct sctp_getaddrs getaddrs; 4280 struct sctp_getaddrs getaddrs;
4313 struct sctp_sockaddr_entry *addr; 4281 struct sctp_sockaddr_entry *addr;
@@ -4315,7 +4283,6 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
4315 union sctp_addr temp; 4283 union sctp_addr temp;
4316 struct sctp_sock *sp = sctp_sk(sk); 4284 struct sctp_sock *sp = sctp_sk(sk);
4317 int addrlen; 4285 int addrlen;
4318 rwlock_t *addr_lock;
4319 int err = 0; 4286 int err = 0;
4320 size_t space_left; 4287 size_t space_left;
4321 int bytes_copied = 0; 4288 int bytes_copied = 0;
@@ -4336,13 +4303,11 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
4336 */ 4303 */
4337 if (0 == getaddrs.assoc_id) { 4304 if (0 == getaddrs.assoc_id) {
4338 bp = &sctp_sk(sk)->ep->base.bind_addr; 4305 bp = &sctp_sk(sk)->ep->base.bind_addr;
4339 addr_lock = &sctp_sk(sk)->ep->base.addr_lock;
4340 } else { 4306 } else {
4341 asoc = sctp_id2assoc(sk, getaddrs.assoc_id); 4307 asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
4342 if (!asoc) 4308 if (!asoc)
4343 return -EINVAL; 4309 return -EINVAL;
4344 bp = &asoc->base.bind_addr; 4310 bp = &asoc->base.bind_addr;
4345 addr_lock = &asoc->base.addr_lock;
4346 } 4311 }
4347 4312
4348 to = optval + offsetof(struct sctp_getaddrs,addrs); 4313 to = optval + offsetof(struct sctp_getaddrs,addrs);
@@ -4352,8 +4317,6 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
4352 if (!addrs) 4317 if (!addrs)
4353 return -ENOMEM; 4318 return -ENOMEM;
4354 4319
4355 sctp_read_lock(addr_lock);
4356
4357 /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid 4320 /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
4358 * addresses from the global local address list. 4321 * addresses from the global local address list.
4359 */ 4322 */
@@ -4365,21 +4328,24 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
4365 space_left, &bytes_copied); 4328 space_left, &bytes_copied);
4366 if (cnt < 0) { 4329 if (cnt < 0) {
4367 err = cnt; 4330 err = cnt;
4368 goto error_lock; 4331 goto out;
4369 } 4332 }
4370 goto copy_getaddrs; 4333 goto copy_getaddrs;
4371 } 4334 }
4372 } 4335 }
4373 4336
4374 buf = addrs; 4337 buf = addrs;
4375 list_for_each(pos, &bp->address_list) { 4338 /* Protection on the bound address list is not needed since
4376 addr = list_entry(pos, struct sctp_sockaddr_entry, list); 4339 * in the socket option context we hold a socket lock and
4340 * thus the bound address list can't change.
4341 */
4342 list_for_each_entry(addr, &bp->address_list, list) {
4377 memcpy(&temp, &addr->a, sizeof(temp)); 4343 memcpy(&temp, &addr->a, sizeof(temp));
4378 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); 4344 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
4379 addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; 4345 addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
4380 if (space_left < addrlen) { 4346 if (space_left < addrlen) {
4381 err = -ENOMEM; /*fixme: right error?*/ 4347 err = -ENOMEM; /*fixme: right error?*/
4382 goto error_lock; 4348 goto out;
4383 } 4349 }
4384 memcpy(buf, &temp, addrlen); 4350 memcpy(buf, &temp, addrlen);
4385 buf += addrlen; 4351 buf += addrlen;
@@ -4389,8 +4355,6 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
4389 } 4355 }
4390 4356
4391copy_getaddrs: 4357copy_getaddrs:
4392 sctp_read_unlock(addr_lock);
4393
4394 if (copy_to_user(to, addrs, bytes_copied)) { 4358 if (copy_to_user(to, addrs, bytes_copied)) {
4395 err = -EFAULT; 4359 err = -EFAULT;
4396 goto out; 4360 goto out;
@@ -4401,12 +4365,6 @@ copy_getaddrs:
4401 } 4365 }
4402 if (put_user(bytes_copied, optlen)) 4366 if (put_user(bytes_copied, optlen))
4403 err = -EFAULT; 4367 err = -EFAULT;
4404
4405 goto out;
4406
4407error_lock:
4408 sctp_read_unlock(addr_lock);
4409
4410out: 4368out:
4411 kfree(addrs); 4369 kfree(addrs);
4412 return err; 4370 return err;