diff options
-rw-r--r-- | include/net/sctp/structs.h | 2 | ||||
-rw-r--r-- | net/sctp/associola.c | 6 | ||||
-rw-r--r-- | net/sctp/proc.c | 14 | ||||
-rw-r--r-- | net/sctp/transport.c | 18 |
4 files changed, 30 insertions, 10 deletions
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index c2521016d646..fdeb85a970fc 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h | |||
@@ -949,6 +949,8 @@ struct sctp_transport { | |||
949 | 949 | ||
950 | /* 64-bit random number sent with heartbeat. */ | 950 | /* 64-bit random number sent with heartbeat. */ |
951 | __u64 hb_nonce; | 951 | __u64 hb_nonce; |
952 | |||
953 | struct rcu_head rcu; | ||
952 | }; | 954 | }; |
953 | 955 | ||
954 | struct sctp_transport *sctp_transport_new(struct net *, const union sctp_addr *, | 956 | struct sctp_transport *sctp_transport_new(struct net *, const union sctp_addr *, |
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index ba3f9cc4c047..b45ed1f96921 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -448,7 +448,7 @@ void sctp_association_free(struct sctp_association *asoc) | |||
448 | /* Release the transport structures. */ | 448 | /* Release the transport structures. */ |
449 | list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { | 449 | list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { |
450 | transport = list_entry(pos, struct sctp_transport, transports); | 450 | transport = list_entry(pos, struct sctp_transport, transports); |
451 | list_del(pos); | 451 | list_del_rcu(pos); |
452 | sctp_transport_free(transport); | 452 | sctp_transport_free(transport); |
453 | } | 453 | } |
454 | 454 | ||
@@ -568,7 +568,7 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc, | |||
568 | sctp_assoc_update_retran_path(asoc); | 568 | sctp_assoc_update_retran_path(asoc); |
569 | 569 | ||
570 | /* Remove this peer from the list. */ | 570 | /* Remove this peer from the list. */ |
571 | list_del(&peer->transports); | 571 | list_del_rcu(&peer->transports); |
572 | 572 | ||
573 | /* Get the first transport of asoc. */ | 573 | /* Get the first transport of asoc. */ |
574 | pos = asoc->peer.transport_addr_list.next; | 574 | pos = asoc->peer.transport_addr_list.next; |
@@ -769,7 +769,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, | |||
769 | peer->state = peer_state; | 769 | peer->state = peer_state; |
770 | 770 | ||
771 | /* Attach the remote transport to our asoc. */ | 771 | /* Attach the remote transport to our asoc. */ |
772 | list_add_tail(&peer->transports, &asoc->peer.transport_addr_list); | 772 | list_add_tail_rcu(&peer->transports, &asoc->peer.transport_addr_list); |
773 | asoc->peer.transport_count++; | 773 | asoc->peer.transport_count++; |
774 | 774 | ||
775 | /* If we do not yet have a primary path, set one. */ | 775 | /* If we do not yet have a primary path, set one. */ |
diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 06b05ee17d8d..8c19e97262ca 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c | |||
@@ -162,15 +162,20 @@ static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_associa | |||
162 | struct sctp_af *af; | 162 | struct sctp_af *af; |
163 | 163 | ||
164 | primary = &assoc->peer.primary_addr; | 164 | primary = &assoc->peer.primary_addr; |
165 | list_for_each_entry(transport, &assoc->peer.transport_addr_list, | 165 | rcu_read_lock(); |
166 | list_for_each_entry_rcu(transport, &assoc->peer.transport_addr_list, | ||
166 | transports) { | 167 | transports) { |
167 | addr = &transport->ipaddr; | 168 | addr = &transport->ipaddr; |
169 | if (transport->dead) | ||
170 | continue; | ||
171 | |||
168 | af = sctp_get_af_specific(addr->sa.sa_family); | 172 | af = sctp_get_af_specific(addr->sa.sa_family); |
169 | if (af->cmp_addr(addr, primary)) { | 173 | if (af->cmp_addr(addr, primary)) { |
170 | seq_printf(seq, "*"); | 174 | seq_printf(seq, "*"); |
171 | } | 175 | } |
172 | af->seq_dump_addr(seq, addr); | 176 | af->seq_dump_addr(seq, addr); |
173 | } | 177 | } |
178 | rcu_read_unlock(); | ||
174 | } | 179 | } |
175 | 180 | ||
176 | static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos) | 181 | static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos) |
@@ -441,12 +446,16 @@ static int sctp_remaddr_seq_show(struct seq_file *seq, void *v) | |||
441 | head = &sctp_assoc_hashtable[hash]; | 446 | head = &sctp_assoc_hashtable[hash]; |
442 | sctp_local_bh_disable(); | 447 | sctp_local_bh_disable(); |
443 | read_lock(&head->lock); | 448 | read_lock(&head->lock); |
449 | rcu_read_lock(); | ||
444 | sctp_for_each_hentry(epb, node, &head->chain) { | 450 | sctp_for_each_hentry(epb, node, &head->chain) { |
445 | if (!net_eq(sock_net(epb->sk), seq_file_net(seq))) | 451 | if (!net_eq(sock_net(epb->sk), seq_file_net(seq))) |
446 | continue; | 452 | continue; |
447 | assoc = sctp_assoc(epb); | 453 | assoc = sctp_assoc(epb); |
448 | list_for_each_entry(tsp, &assoc->peer.transport_addr_list, | 454 | list_for_each_entry_rcu(tsp, &assoc->peer.transport_addr_list, |
449 | transports) { | 455 | transports) { |
456 | if (tsp->dead) | ||
457 | continue; | ||
458 | |||
450 | /* | 459 | /* |
451 | * The remote address (ADDR) | 460 | * The remote address (ADDR) |
452 | */ | 461 | */ |
@@ -492,6 +501,7 @@ static int sctp_remaddr_seq_show(struct seq_file *seq, void *v) | |||
492 | } | 501 | } |
493 | } | 502 | } |
494 | 503 | ||
504 | rcu_read_unlock(); | ||
495 | read_unlock(&head->lock); | 505 | read_unlock(&head->lock); |
496 | sctp_local_bh_enable(); | 506 | sctp_local_bh_enable(); |
497 | 507 | ||
diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 310f11eb2206..4e45bb68aef0 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c | |||
@@ -163,13 +163,11 @@ void sctp_transport_free(struct sctp_transport *transport) | |||
163 | sctp_transport_put(transport); | 163 | sctp_transport_put(transport); |
164 | } | 164 | } |
165 | 165 | ||
166 | /* Destroy the transport data structure. | 166 | static void sctp_transport_destroy_rcu(struct rcu_head *head) |
167 | * Assumes there are no more users of this structure. | ||
168 | */ | ||
169 | static void sctp_transport_destroy(struct sctp_transport *transport) | ||
170 | { | 167 | { |
171 | SCTP_ASSERT(transport->dead, "Transport is not dead", return); | 168 | struct sctp_transport *transport; |
172 | 169 | ||
170 | transport = container_of(head, struct sctp_transport, rcu); | ||
173 | if (transport->asoc) | 171 | if (transport->asoc) |
174 | sctp_association_put(transport->asoc); | 172 | sctp_association_put(transport->asoc); |
175 | 173 | ||
@@ -180,6 +178,16 @@ static void sctp_transport_destroy(struct sctp_transport *transport) | |||
180 | SCTP_DBG_OBJCNT_DEC(transport); | 178 | SCTP_DBG_OBJCNT_DEC(transport); |
181 | } | 179 | } |
182 | 180 | ||
181 | /* Destroy the transport data structure. | ||
182 | * Assumes there are no more users of this structure. | ||
183 | */ | ||
184 | static void sctp_transport_destroy(struct sctp_transport *transport) | ||
185 | { | ||
186 | SCTP_ASSERT(transport->dead, "Transport is not dead", return); | ||
187 | |||
188 | call_rcu(&transport->rcu, sctp_transport_destroy_rcu); | ||
189 | } | ||
190 | |||
183 | /* Start T3_rtx timer if it is not already running and update the heartbeat | 191 | /* Start T3_rtx timer if it is not already running and update the heartbeat |
184 | * timer. This routine is called every time a DATA chunk is sent. | 192 | * timer. This routine is called every time a DATA chunk is sent. |
185 | */ | 193 | */ |