aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/socket.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/socket.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/socket.c')
-rw-r--r--net/sctp/socket.c98
1 files changed, 28 insertions, 70 deletions
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;