aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/protocol.c
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/sctp/protocol.c
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/sctp/protocol.c')
-rw-r--r--net/sctp/protocol.c25
1 files changed, 10 insertions, 15 deletions
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",