Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f008781 authored by Xin Long's avatar Xin Long Committed by David S. Miller
Browse files

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: default avatarXin Long <lucien.xin@gmail.com>
Signed-off-by: default avatarMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d6c0256a
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -383,6 +383,7 @@ void sctp_association_free(struct sctp_association *asoc)
	list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
		transport = list_entry(pos, struct sctp_transport, transports);
		list_del_rcu(pos);
		sctp_unhash_transport(transport);
		sctp_transport_free(transport);
	}

@@ -500,6 +501,8 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,

	/* Remove this peer from the list. */
	list_del_rcu(&peer->transports);
	/* Remove this peer from the transport hashtable */
	sctp_unhash_transport(peer);

	/* Get the first transport of asoc. */
	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.  */
	list_add_tail_rcu(&peer->transports, &asoc->peer.transport_addr_list);
	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 (!asoc->peer.primary_path) {
+8 −27
Original line number Diff line number Diff line
@@ -314,8 +314,8 @@ struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
}

/* Find the association that goes with this chunk.
 * We do a linear search of the associations for this endpoint.
 * We return the matching transport address too.
 * We lookup the transport from hashtable at first, then get association
 * through t->assoc.
 */
static struct sctp_association *__sctp_endpoint_lookup_assoc(
	const struct sctp_endpoint *ep,
@@ -323,12 +323,7 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc(
	struct sctp_transport **transport)
{
	struct sctp_association *asoc = NULL;
	struct sctp_association *tmp;
	struct sctp_transport *t = NULL;
	struct sctp_hashbucket *head;
	struct sctp_ep_common *epb;
	int hash;
	int rport;
	struct sctp_transport *t;

	*transport = NULL;

@@ -337,26 +332,12 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc(
	 */
	if (!ep->base.bind_addr.port)
		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;
			break;
		}
	}
	read_unlock(&head->lock);
	asoc = t->asoc;
out:
	return asoc;
}
+10 −29
Original line number Diff line number Diff line
@@ -981,38 +981,19 @@ static struct sctp_association *__sctp_lookup_association(
					const union sctp_addr *peer,
					struct sctp_transport **pt)
{
	struct sctp_hashbucket *head;
	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);
	struct sctp_transport *t;

	t = sctp_addrs_lookup_transport(net, local, peer);
	if (!t || t->dead || t->asoc->temp)
		return NULL;

hit:
	*pt = transport;
	sctp_association_hold(asoc);
	read_unlock(&head->lock);
	return asoc;
	sctp_association_hold(t->asoc);
	*pt = t;

	return t->asoc;
}

/* Look up an association. BH-safe. */
/* Look up an association. protected by RCU read lock */
static
struct sctp_association *sctp_lookup_association(struct net *net,
						 const union sctp_addr *laddr,
@@ -1021,9 +1002,9 @@ struct sctp_association *sctp_lookup_association(struct net *net,
{
	struct sctp_association *asoc;

	local_bh_disable();
	rcu_read_lock();
	asoc = __sctp_lookup_association(net, laddr, paddr, transportp);
	local_bh_enable();
	rcu_read_unlock();

	return asoc;
}
+6 −0
Original line number Diff line number Diff line
@@ -1467,6 +1467,9 @@ static __init int sctp_init(void)
		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",
		sctp_assoc_hashsize, sctp_port_hashsize);

@@ -1521,6 +1524,8 @@ static __init int sctp_init(void)
		   get_order(sctp_port_hashsize *
			     sizeof(struct sctp_bind_hashbucket)));
err_bhash_alloc:
	sctp_transport_hashtable_destroy();
err_thash_alloc:
	kfree(sctp_ep_hashtable);
err_ehash_alloc:
	free_pages((unsigned long)sctp_assoc_hashtable,
@@ -1567,6 +1572,7 @@ static __exit void sctp_exit(void)
	free_pages((unsigned long)sctp_port_hashtable,
		   get_order(sctp_port_hashsize *
			     sizeof(struct sctp_bind_hashbucket)));
	sctp_transport_hashtable_destroy();

	percpu_counter_destroy(&sctp_sockets_allocated);