Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 183326
b: refs/heads/master
c: b76f5a8
h: refs/heads/master
v: v3
  • Loading branch information
Octavian Purdila authored and David S. Miller committed Dec 27, 2009
1 parent 42dfc07 commit d847fe1
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 72 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: abf9d537fea225af60762640361af7fb233b3103
refs/heads/master: b76f5a8427ac2928c07fa4ff2144bb8db072c240
7 changes: 3 additions & 4 deletions trunk/include/net/llc.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/if_ether.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/rculist_nulls.h>

#include <asm/atomic.h>

Expand Down Expand Up @@ -53,10 +54,8 @@ struct llc_sap {
struct net_device *orig_dev);
struct llc_addr laddr;
struct list_head node;
struct {
rwlock_t lock;
struct hlist_head list;
} sk_list;
spinlock_t sk_lock;
struct hlist_nulls_head sk_list;
};

#define LLC_DEST_INVALID 0 /* Invalid LLC PDU type */
Expand Down
1 change: 1 addition & 0 deletions trunk/net/llc/af_llc.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ static struct proto llc_proto = {
.name = "LLC",
.owner = THIS_MODULE,
.obj_size = sizeof(struct llc_sock),
.slab_flags = SLAB_DESTROY_BY_RCU,
};

/**
Expand Down
93 changes: 62 additions & 31 deletions trunk/net/llc/llc_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,19 @@ static int llc_exec_conn_trans_actions(struct sock *sk,
return rc;
}

static inline bool llc_estab_match(const struct llc_sap *sap,
const struct llc_addr *daddr,
const struct llc_addr *laddr,
const struct sock *sk)
{
struct llc_sock *llc = llc_sk(sk);

return llc->laddr.lsap == laddr->lsap &&
llc->daddr.lsap == daddr->lsap &&
llc_mac_match(llc->laddr.mac, laddr->mac) &&
llc_mac_match(llc->daddr.mac, daddr->mac);
}

/**
* __llc_lookup_established - Finds connection for the remote/local sap/mac
* @sap: SAP
Expand All @@ -484,23 +497,26 @@ static struct sock *__llc_lookup_established(struct llc_sap *sap,
struct llc_addr *laddr)
{
struct sock *rc;
struct hlist_node *node;

read_lock(&sap->sk_list.lock);
sk_for_each(rc, node, &sap->sk_list.list) {
struct llc_sock *llc = llc_sk(rc);

if (llc->laddr.lsap == laddr->lsap &&
llc->daddr.lsap == daddr->lsap &&
llc_mac_match(llc->laddr.mac, laddr->mac) &&
llc_mac_match(llc->daddr.mac, daddr->mac)) {
sock_hold(rc);
struct hlist_nulls_node *node;

rcu_read_lock();
again:
sk_nulls_for_each_rcu(rc, node, &sap->sk_list) {
if (llc_estab_match(sap, daddr, laddr, rc)) {
/* Extra checks required by SLAB_DESTROY_BY_RCU */
if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
goto again;
if (unlikely(llc_sk(rc)->sap != sap ||
!llc_estab_match(sap, daddr, laddr, rc))) {
sock_put(rc);
continue;
}
goto found;
}
}
rc = NULL;
found:
read_unlock(&sap->sk_list.lock);
rcu_read_unlock();
return rc;
}

Expand All @@ -516,6 +532,18 @@ struct sock *llc_lookup_established(struct llc_sap *sap,
return sk;
}

static inline bool llc_listener_match(const struct llc_sap *sap,
const struct llc_addr *laddr,
const struct sock *sk)
{
struct llc_sock *llc = llc_sk(sk);

return sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN &&
llc->laddr.lsap == laddr->lsap &&
(llc_mac_match(llc->laddr.mac, laddr->mac) ||
llc_mac_null(llc->laddr.mac));
}

/**
* llc_lookup_listener - Finds listener for local MAC + SAP
* @sap: SAP
Expand All @@ -530,23 +558,26 @@ static struct sock *llc_lookup_listener(struct llc_sap *sap,
struct llc_addr *laddr)
{
struct sock *rc;
struct hlist_node *node;

read_lock(&sap->sk_list.lock);
sk_for_each(rc, node, &sap->sk_list.list) {
struct llc_sock *llc = llc_sk(rc);

if (rc->sk_type == SOCK_STREAM && rc->sk_state == TCP_LISTEN &&
llc->laddr.lsap == laddr->lsap &&
(llc_mac_match(llc->laddr.mac, laddr->mac) ||
llc_mac_null(llc->laddr.mac))) {
sock_hold(rc);
struct hlist_nulls_node *node;

rcu_read_lock();
again:
sk_nulls_for_each_rcu(rc, node, &sap->sk_list) {
if (llc_listener_match(sap, laddr, rc)) {
/* Extra checks required by SLAB_DESTROY_BY_RCU */
if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
goto again;
if (unlikely(llc_sk(rc)->sap != sap ||
!llc_listener_match(sap, laddr, rc))) {
sock_put(rc);
continue;
}
goto found;
}
}
rc = NULL;
found:
read_unlock(&sap->sk_list.lock);
rcu_read_unlock();
return rc;
}

Expand Down Expand Up @@ -652,25 +683,25 @@ static int llc_find_offset(int state, int ev_type)
void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk)
{
llc_sap_hold(sap);
write_lock_bh(&sap->sk_list.lock);
spin_lock_bh(&sap->sk_lock);
llc_sk(sk)->sap = sap;
sk_add_node(sk, &sap->sk_list.list);
write_unlock_bh(&sap->sk_list.lock);
sk_nulls_add_node_rcu(sk, &sap->sk_list);
spin_unlock_bh(&sap->sk_lock);
}

/**
* llc_sap_remove_socket - removes a socket from SAP
* @sap: SAP
* @sk: socket
*
* This function removes a connection from sk_list.list of a SAP if
* This function removes a connection from sk_list of a SAP if
* the connection was in this list.
*/
void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk)
{
write_lock_bh(&sap->sk_list.lock);
sk_del_node_init(sk);
write_unlock_bh(&sap->sk_list.lock);
spin_lock_bh(&sap->sk_lock);
sk_nulls_del_node_init_rcu(sk);
spin_unlock_bh(&sap->sk_lock);
llc_sap_put(sap);
}

Expand Down
5 changes: 3 additions & 2 deletions trunk/net/llc/llc_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ static struct llc_sap *llc_sap_alloc(void)
if (sap) {
/* sap->laddr.mac - leave as a null, it's filled by bind */
sap->state = LLC_SAP_STATE_ACTIVE;
rwlock_init(&sap->sk_list.lock);
spin_lock_init(&sap->sk_lock);
INIT_HLIST_NULLS_HEAD(&sap->sk_list, 0);
atomic_set(&sap->refcnt, 1);
}
return sap;
Expand Down Expand Up @@ -142,7 +143,7 @@ struct llc_sap *llc_sap_open(unsigned char lsap,
*/
void llc_sap_close(struct llc_sap *sap)
{
WARN_ON(!hlist_empty(&sap->sk_list.list));
WARN_ON(!hlist_nulls_empty(&sap->sk_list));
llc_del_sap(sap);
kfree(sap);
}
Expand Down
22 changes: 11 additions & 11 deletions trunk/net/llc/llc_proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,19 @@ static struct sock *llc_get_sk_idx(loff_t pos)
{
struct list_head *sap_entry;
struct llc_sap *sap;
struct hlist_node *node;
struct hlist_nulls_node *node;
struct sock *sk = NULL;

list_for_each(sap_entry, &llc_sap_list) {
sap = list_entry(sap_entry, struct llc_sap, node);

read_lock_bh(&sap->sk_list.lock);
sk_for_each(sk, node, &sap->sk_list.list) {
spin_lock_bh(&sap->sk_lock);
sk_nulls_for_each(sk, node, &sap->sk_list) {
if (!pos)
goto found;
--pos;
}
read_unlock_bh(&sap->sk_list.lock);
spin_unlock_bh(&sap->sk_lock);
}
sk = NULL;
found:
Expand All @@ -73,25 +73,25 @@ static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
goto out;
}
sk = v;
next = sk_next(sk);
next = sk_nulls_next(sk);
if (next) {
sk = next;
goto out;
}
llc = llc_sk(sk);
sap = llc->sap;
read_unlock_bh(&sap->sk_list.lock);
spin_unlock_bh(&sap->sk_lock);
sk = NULL;
for (;;) {
if (sap->node.next == &llc_sap_list)
break;
sap = list_entry(sap->node.next, struct llc_sap, node);
read_lock_bh(&sap->sk_list.lock);
if (!hlist_empty(&sap->sk_list.list)) {
sk = sk_head(&sap->sk_list.list);
spin_lock_bh(&sap->sk_lock);
if (!hlist_nulls_empty(&sap->sk_list)) {
sk = sk_nulls_head(&sap->sk_list);
break;
}
read_unlock_bh(&sap->sk_list.lock);
spin_unlock_bh(&sap->sk_lock);
}
out:
return sk;
Expand All @@ -104,7 +104,7 @@ static void llc_seq_stop(struct seq_file *seq, void *v)
struct llc_sock *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap;

read_unlock_bh(&sap->sk_list.lock);
spin_unlock_bh(&sap->sk_lock);
}
read_unlock_bh(&llc_sap_list_lock);
}
Expand Down
66 changes: 43 additions & 23 deletions trunk/net/llc/llc_sap.c
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,17 @@ static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb,
llc_sap_state_process(sap, skb);
}

static inline bool llc_dgram_match(const struct llc_sap *sap,
const struct llc_addr *laddr,
const struct sock *sk)
{
struct llc_sock *llc = llc_sk(sk);

return sk->sk_type == SOCK_DGRAM &&
llc->laddr.lsap == laddr->lsap &&
llc_mac_match(llc->laddr.mac, laddr->mac);
}

/**
* llc_lookup_dgram - Finds dgram socket for the local sap/mac
* @sap: SAP
Expand All @@ -309,25 +320,41 @@ static struct sock *llc_lookup_dgram(struct llc_sap *sap,
const struct llc_addr *laddr)
{
struct sock *rc;
struct hlist_node *node;

read_lock_bh(&sap->sk_list.lock);
sk_for_each(rc, node, &sap->sk_list.list) {
struct llc_sock *llc = llc_sk(rc);

if (rc->sk_type == SOCK_DGRAM &&
llc->laddr.lsap == laddr->lsap &&
llc_mac_match(llc->laddr.mac, laddr->mac)) {
sock_hold(rc);
struct hlist_nulls_node *node;

rcu_read_lock_bh();
again:
sk_nulls_for_each_rcu(rc, node, &sap->sk_list) {
if (llc_dgram_match(sap, laddr, rc)) {
/* Extra checks required by SLAB_DESTROY_BY_RCU */
if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
goto again;
if (unlikely(llc_sk(rc)->sap != sap ||
!llc_dgram_match(sap, laddr, rc))) {
sock_put(rc);
continue;
}
goto found;
}
}
rc = NULL;
found:
read_unlock_bh(&sap->sk_list.lock);
rcu_read_unlock_bh();
return rc;
}

static inline bool llc_mcast_match(const struct llc_sap *sap,
const struct llc_addr *laddr,
const struct sk_buff *skb,
const struct sock *sk)
{
struct llc_sock *llc = llc_sk(sk);

return sk->sk_type == SOCK_DGRAM &&
llc->laddr.lsap == laddr->lsap &&
llc->dev == skb->dev;
}

/**
* llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets.
* @sap: SAP
Expand All @@ -341,20 +368,13 @@ static void llc_sap_mcast(struct llc_sap *sap,
struct sk_buff *skb)
{
struct sock *sk;
struct hlist_node *node;
struct hlist_nulls_node *node;

read_lock_bh(&sap->sk_list.lock);
sk_for_each(sk, node, &sap->sk_list.list) {
struct llc_sock *llc = llc_sk(sk);
spin_lock_bh(&sap->sk_lock);
sk_nulls_for_each_rcu(sk, node, &sap->sk_list) {
struct sk_buff *skb1;

if (sk->sk_type != SOCK_DGRAM)
continue;

if (llc->laddr.lsap != laddr->lsap)
continue;

if (llc->dev != skb->dev)
if (!llc_mcast_match(sap, laddr, skb, sk))
continue;

skb1 = skb_clone(skb, GFP_ATOMIC);
Expand All @@ -365,7 +385,7 @@ static void llc_sap_mcast(struct llc_sap *sap,
llc_sap_rcv(sap, skb1, sk);
sock_put(sk);
}
read_unlock_bh(&sap->sk_list.lock);
spin_unlock_bh(&sap->sk_lock);
}


Expand Down

0 comments on commit d847fe1

Please sign in to comment.