diff options
author | Sridhar Samudrala <sri@us.ibm.com> | 2006-12-13 19:26:26 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-13 19:48:27 -0500 |
commit | 29c7cf96186ac14ce7380633f690fc39732ff03a (patch) | |
tree | ccc95adc0e1185469e77a1adcae1d300d0b534d1 /net/sctp/socket.c | |
parent | 6931ba7cef3991fbb970997d33e24139ccdc3c2c (diff) |
[SCTP]: Handle address add/delete events in a more efficient way.
Currently in SCTP, we maintain a local address list by rebuilding the whole
list from the device list whenever we get a address add/delete event.
This patch fixes it by only adding/deleting the address for which we
receive the event.
Also removed the sctp_local_addr_lock() which is no longer needed as we
now use list_for_each_safe() to traverse this list. This fixes the bugs
in sctp_copy_laddrs_xxx() routines where we do copy_to_user() while
holding this lock.
Signed-off-by: Sridhar Samudrala <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.c | 34 |
1 files changed, 10 insertions, 24 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 1e8132b8c4d9..fa29eae83e91 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -3821,10 +3821,9 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len, | |||
3821 | sctp_assoc_t id; | 3821 | sctp_assoc_t id; |
3822 | struct sctp_bind_addr *bp; | 3822 | struct sctp_bind_addr *bp; |
3823 | struct sctp_association *asoc; | 3823 | struct sctp_association *asoc; |
3824 | struct list_head *pos; | 3824 | struct list_head *pos, *temp; |
3825 | struct sctp_sockaddr_entry *addr; | 3825 | struct sctp_sockaddr_entry *addr; |
3826 | rwlock_t *addr_lock; | 3826 | rwlock_t *addr_lock; |
3827 | unsigned long flags; | ||
3828 | int cnt = 0; | 3827 | int cnt = 0; |
3829 | 3828 | ||
3830 | if (len != sizeof(sctp_assoc_t)) | 3829 | if (len != sizeof(sctp_assoc_t)) |
@@ -3859,8 +3858,7 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len, | |||
3859 | addr = list_entry(bp->address_list.next, | 3858 | addr = list_entry(bp->address_list.next, |
3860 | struct sctp_sockaddr_entry, list); | 3859 | struct sctp_sockaddr_entry, list); |
3861 | if (sctp_is_any(&addr->a)) { | 3860 | if (sctp_is_any(&addr->a)) { |
3862 | sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); | 3861 | list_for_each_safe(pos, temp, &sctp_local_addr_list) { |
3863 | list_for_each(pos, &sctp_local_addr_list) { | ||
3864 | addr = list_entry(pos, | 3862 | addr = list_entry(pos, |
3865 | struct sctp_sockaddr_entry, | 3863 | struct sctp_sockaddr_entry, |
3866 | list); | 3864 | list); |
@@ -3869,8 +3867,6 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len, | |||
3869 | continue; | 3867 | continue; |
3870 | cnt++; | 3868 | cnt++; |
3871 | } | 3869 | } |
3872 | sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, | ||
3873 | flags); | ||
3874 | } else { | 3870 | } else { |
3875 | cnt = 1; | 3871 | cnt = 1; |
3876 | } | 3872 | } |
@@ -3892,15 +3888,13 @@ done: | |||
3892 | static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs, | 3888 | static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs, |
3893 | void __user *to) | 3889 | void __user *to) |
3894 | { | 3890 | { |
3895 | struct list_head *pos; | 3891 | struct list_head *pos, *next; |
3896 | struct sctp_sockaddr_entry *addr; | 3892 | struct sctp_sockaddr_entry *addr; |
3897 | unsigned long flags; | ||
3898 | union sctp_addr temp; | 3893 | union sctp_addr temp; |
3899 | int cnt = 0; | 3894 | int cnt = 0; |
3900 | int addrlen; | 3895 | int addrlen; |
3901 | 3896 | ||
3902 | sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); | 3897 | list_for_each_safe(pos, next, &sctp_local_addr_list) { |
3903 | list_for_each(pos, &sctp_local_addr_list) { | ||
3904 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); | 3898 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); |
3905 | if ((PF_INET == sk->sk_family) && | 3899 | if ((PF_INET == sk->sk_family) && |
3906 | (AF_INET6 == addr->a.sa.sa_family)) | 3900 | (AF_INET6 == addr->a.sa.sa_family)) |
@@ -3909,16 +3903,13 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add | |||
3909 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), | 3903 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), |
3910 | &temp); | 3904 | &temp); |
3911 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | 3905 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; |
3912 | if (copy_to_user(to, &temp, addrlen)) { | 3906 | if (copy_to_user(to, &temp, addrlen)) |
3913 | sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, | ||
3914 | flags); | ||
3915 | return -EFAULT; | 3907 | return -EFAULT; |
3916 | } | 3908 | |
3917 | to += addrlen; | 3909 | to += addrlen; |
3918 | cnt ++; | 3910 | cnt ++; |
3919 | if (cnt >= max_addrs) break; | 3911 | if (cnt >= max_addrs) break; |
3920 | } | 3912 | } |
3921 | sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags); | ||
3922 | 3913 | ||
3923 | return cnt; | 3914 | return cnt; |
3924 | } | 3915 | } |
@@ -3926,15 +3917,13 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add | |||
3926 | static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, | 3917 | static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, |
3927 | void __user **to, size_t space_left) | 3918 | void __user **to, size_t space_left) |
3928 | { | 3919 | { |
3929 | struct list_head *pos; | 3920 | struct list_head *pos, *next; |
3930 | struct sctp_sockaddr_entry *addr; | 3921 | struct sctp_sockaddr_entry *addr; |
3931 | unsigned long flags; | ||
3932 | union sctp_addr temp; | 3922 | union sctp_addr temp; |
3933 | int cnt = 0; | 3923 | int cnt = 0; |
3934 | int addrlen; | 3924 | int addrlen; |
3935 | 3925 | ||
3936 | sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); | 3926 | list_for_each_safe(pos, next, &sctp_local_addr_list) { |
3937 | list_for_each(pos, &sctp_local_addr_list) { | ||
3938 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); | 3927 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); |
3939 | if ((PF_INET == sk->sk_family) && | 3928 | if ((PF_INET == sk->sk_family) && |
3940 | (AF_INET6 == addr->a.sa.sa_family)) | 3929 | (AF_INET6 == addr->a.sa.sa_family)) |
@@ -3945,16 +3934,13 @@ static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, | |||
3945 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | 3934 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; |
3946 | if(space_left<addrlen) | 3935 | if(space_left<addrlen) |
3947 | return -ENOMEM; | 3936 | return -ENOMEM; |
3948 | if (copy_to_user(*to, &temp, addrlen)) { | 3937 | if (copy_to_user(*to, &temp, addrlen)) |
3949 | sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, | ||
3950 | flags); | ||
3951 | return -EFAULT; | 3938 | return -EFAULT; |
3952 | } | 3939 | |
3953 | *to += addrlen; | 3940 | *to += addrlen; |
3954 | cnt ++; | 3941 | cnt ++; |
3955 | space_left -= addrlen; | 3942 | space_left -= addrlen; |
3956 | } | 3943 | } |
3957 | sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags); | ||
3958 | 3944 | ||
3959 | return cnt; | 3945 | return cnt; |
3960 | } | 3946 | } |