mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 12:42:02 +00:00
sctp: apply rhashtable api to send/recv path
apply lookup apis to two functions, for __sctp_endpoint_lookup_assoc and __sctp_lookup_association, it's invoked in the protection of sock lock, it will be safe, but sctp_lookup_association need to call rcu_read_lock() and to detect the t->dead to protect it. Signed-off-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
d6c0256a60
commit
4f00878126
@ -383,6 +383,7 @@ void sctp_association_free(struct sctp_association *asoc)
|
|||||||
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
|
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
|
||||||
transport = list_entry(pos, struct sctp_transport, transports);
|
transport = list_entry(pos, struct sctp_transport, transports);
|
||||||
list_del_rcu(pos);
|
list_del_rcu(pos);
|
||||||
|
sctp_unhash_transport(transport);
|
||||||
sctp_transport_free(transport);
|
sctp_transport_free(transport);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -500,6 +501,8 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
|
|||||||
|
|
||||||
/* Remove this peer from the list. */
|
/* Remove this peer from the list. */
|
||||||
list_del_rcu(&peer->transports);
|
list_del_rcu(&peer->transports);
|
||||||
|
/* Remove this peer from the transport hashtable */
|
||||||
|
sctp_unhash_transport(peer);
|
||||||
|
|
||||||
/* Get the first transport of asoc. */
|
/* Get the first transport of asoc. */
|
||||||
pos = asoc->peer.transport_addr_list.next;
|
pos = asoc->peer.transport_addr_list.next;
|
||||||
@ -699,6 +702,8 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
|
|||||||
/* Attach the remote transport to our asoc. */
|
/* Attach the remote transport to our asoc. */
|
||||||
list_add_tail_rcu(&peer->transports, &asoc->peer.transport_addr_list);
|
list_add_tail_rcu(&peer->transports, &asoc->peer.transport_addr_list);
|
||||||
asoc->peer.transport_count++;
|
asoc->peer.transport_count++;
|
||||||
|
/* Add this peer into the transport hashtable */
|
||||||
|
sctp_hash_transport(peer);
|
||||||
|
|
||||||
/* If we do not yet have a primary path, set one. */
|
/* If we do not yet have a primary path, set one. */
|
||||||
if (!asoc->peer.primary_path) {
|
if (!asoc->peer.primary_path) {
|
||||||
|
@ -314,8 +314,8 @@ struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Find the association that goes with this chunk.
|
/* Find the association that goes with this chunk.
|
||||||
* We do a linear search of the associations for this endpoint.
|
* We lookup the transport from hashtable at first, then get association
|
||||||
* We return the matching transport address too.
|
* through t->assoc.
|
||||||
*/
|
*/
|
||||||
static struct sctp_association *__sctp_endpoint_lookup_assoc(
|
static struct sctp_association *__sctp_endpoint_lookup_assoc(
|
||||||
const struct sctp_endpoint *ep,
|
const struct sctp_endpoint *ep,
|
||||||
@ -323,12 +323,7 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc(
|
|||||||
struct sctp_transport **transport)
|
struct sctp_transport **transport)
|
||||||
{
|
{
|
||||||
struct sctp_association *asoc = NULL;
|
struct sctp_association *asoc = NULL;
|
||||||
struct sctp_association *tmp;
|
struct sctp_transport *t;
|
||||||
struct sctp_transport *t = NULL;
|
|
||||||
struct sctp_hashbucket *head;
|
|
||||||
struct sctp_ep_common *epb;
|
|
||||||
int hash;
|
|
||||||
int rport;
|
|
||||||
|
|
||||||
*transport = NULL;
|
*transport = NULL;
|
||||||
|
|
||||||
@ -337,26 +332,12 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc(
|
|||||||
*/
|
*/
|
||||||
if (!ep->base.bind_addr.port)
|
if (!ep->base.bind_addr.port)
|
||||||
goto out;
|
goto out;
|
||||||
|
t = sctp_epaddr_lookup_transport(ep, paddr);
|
||||||
|
if (!t || t->asoc->temp)
|
||||||
|
goto out;
|
||||||
|
|
||||||
rport = ntohs(paddr->v4.sin_port);
|
|
||||||
|
|
||||||
hash = sctp_assoc_hashfn(sock_net(ep->base.sk), ep->base.bind_addr.port,
|
|
||||||
rport);
|
|
||||||
head = &sctp_assoc_hashtable[hash];
|
|
||||||
read_lock(&head->lock);
|
|
||||||
sctp_for_each_hentry(epb, &head->chain) {
|
|
||||||
tmp = sctp_assoc(epb);
|
|
||||||
if (tmp->ep != ep || rport != tmp->peer.port)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
t = sctp_assoc_lookup_paddr(tmp, paddr);
|
|
||||||
if (t) {
|
|
||||||
asoc = tmp;
|
|
||||||
*transport = t;
|
*transport = t;
|
||||||
break;
|
asoc = t->asoc;
|
||||||
}
|
|
||||||
}
|
|
||||||
read_unlock(&head->lock);
|
|
||||||
out:
|
out:
|
||||||
return asoc;
|
return asoc;
|
||||||
}
|
}
|
||||||
|
@ -981,38 +981,19 @@ static struct sctp_association *__sctp_lookup_association(
|
|||||||
const union sctp_addr *peer,
|
const union sctp_addr *peer,
|
||||||
struct sctp_transport **pt)
|
struct sctp_transport **pt)
|
||||||
{
|
{
|
||||||
struct sctp_hashbucket *head;
|
struct sctp_transport *t;
|
||||||
struct sctp_ep_common *epb;
|
|
||||||
struct sctp_association *asoc;
|
|
||||||
struct sctp_transport *transport;
|
|
||||||
int hash;
|
|
||||||
|
|
||||||
/* Optimize here for direct hit, only listening connections can
|
|
||||||
* have wildcards anyways.
|
|
||||||
*/
|
|
||||||
hash = sctp_assoc_hashfn(net, ntohs(local->v4.sin_port),
|
|
||||||
ntohs(peer->v4.sin_port));
|
|
||||||
head = &sctp_assoc_hashtable[hash];
|
|
||||||
read_lock(&head->lock);
|
|
||||||
sctp_for_each_hentry(epb, &head->chain) {
|
|
||||||
asoc = sctp_assoc(epb);
|
|
||||||
transport = sctp_assoc_is_match(asoc, net, local, peer);
|
|
||||||
if (transport)
|
|
||||||
goto hit;
|
|
||||||
}
|
|
||||||
|
|
||||||
read_unlock(&head->lock);
|
|
||||||
|
|
||||||
|
t = sctp_addrs_lookup_transport(net, local, peer);
|
||||||
|
if (!t || t->dead || t->asoc->temp)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
hit:
|
sctp_association_hold(t->asoc);
|
||||||
*pt = transport;
|
*pt = t;
|
||||||
sctp_association_hold(asoc);
|
|
||||||
read_unlock(&head->lock);
|
return t->asoc;
|
||||||
return asoc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look up an association. BH-safe. */
|
/* Look up an association. protected by RCU read lock */
|
||||||
static
|
static
|
||||||
struct sctp_association *sctp_lookup_association(struct net *net,
|
struct sctp_association *sctp_lookup_association(struct net *net,
|
||||||
const union sctp_addr *laddr,
|
const union sctp_addr *laddr,
|
||||||
@ -1021,9 +1002,9 @@ struct sctp_association *sctp_lookup_association(struct net *net,
|
|||||||
{
|
{
|
||||||
struct sctp_association *asoc;
|
struct sctp_association *asoc;
|
||||||
|
|
||||||
local_bh_disable();
|
rcu_read_lock();
|
||||||
asoc = __sctp_lookup_association(net, laddr, paddr, transportp);
|
asoc = __sctp_lookup_association(net, laddr, paddr, transportp);
|
||||||
local_bh_enable();
|
rcu_read_unlock();
|
||||||
|
|
||||||
return asoc;
|
return asoc;
|
||||||
}
|
}
|
||||||
|
@ -1467,6 +1467,9 @@ static __init int sctp_init(void)
|
|||||||
INIT_HLIST_HEAD(&sctp_port_hashtable[i].chain);
|
INIT_HLIST_HEAD(&sctp_port_hashtable[i].chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sctp_transport_hashtable_init())
|
||||||
|
goto err_thash_alloc;
|
||||||
|
|
||||||
pr_info("Hash tables configured (established %d bind %d)\n",
|
pr_info("Hash tables configured (established %d bind %d)\n",
|
||||||
sctp_assoc_hashsize, sctp_port_hashsize);
|
sctp_assoc_hashsize, sctp_port_hashsize);
|
||||||
|
|
||||||
@ -1521,6 +1524,8 @@ err_register_defaults:
|
|||||||
get_order(sctp_port_hashsize *
|
get_order(sctp_port_hashsize *
|
||||||
sizeof(struct sctp_bind_hashbucket)));
|
sizeof(struct sctp_bind_hashbucket)));
|
||||||
err_bhash_alloc:
|
err_bhash_alloc:
|
||||||
|
sctp_transport_hashtable_destroy();
|
||||||
|
err_thash_alloc:
|
||||||
kfree(sctp_ep_hashtable);
|
kfree(sctp_ep_hashtable);
|
||||||
err_ehash_alloc:
|
err_ehash_alloc:
|
||||||
free_pages((unsigned long)sctp_assoc_hashtable,
|
free_pages((unsigned long)sctp_assoc_hashtable,
|
||||||
@ -1567,6 +1572,7 @@ static __exit void sctp_exit(void)
|
|||||||
free_pages((unsigned long)sctp_port_hashtable,
|
free_pages((unsigned long)sctp_port_hashtable,
|
||||||
get_order(sctp_port_hashsize *
|
get_order(sctp_port_hashsize *
|
||||||
sizeof(struct sctp_bind_hashbucket)));
|
sizeof(struct sctp_bind_hashbucket)));
|
||||||
|
sctp_transport_hashtable_destroy();
|
||||||
|
|
||||||
percpu_counter_destroy(&sctp_sockets_allocated);
|
percpu_counter_destroy(&sctp_sockets_allocated);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user