aboutsummaryrefslogtreecommitdiffstats
path: root/net/llc/llc_proc.c
diff options
context:
space:
mode:
authorOctavian Purdila <opurdila@ixiacom.com>2009-12-26 06:51:05 -0500
committerDavid S. Miller <davem@davemloft.net>2009-12-26 23:45:32 -0500
commit52d58aef5ee460fedd7f250f05e79081019f2c79 (patch)
tree9c8d2bf8374570038820a47325a2305bcb83111d /net/llc/llc_proc.c
parent6d2e3ea284463d5ab34e9cf2a41d0b8627b95d02 (diff)
llc: replace the socket list with a local address based hash
For the cases where a lot of interfaces are used in conjunction with a lot of LLC sockets bound to the same SAP, the iteration of the socket list becomes prohibitively expensive. Replacing the list with a a local address based hash significantly improves the bind and listener lookup operations as well as the datagram delivery. Connected sockets delivery is also improved, but this patch does not address the case where we have lots of sockets with the same local address connected to different remote addresses. In order to keep the socket sanity checks alive and fast a socket counter was added to the SAP structure. Signed-off-by: Octavian Purdila <opurdila@ixiacom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/llc/llc_proc.c')
-rw-r--r--net/llc/llc_proc.c44
1 files changed, 30 insertions, 14 deletions
diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c
index 6b3d033b3236..09dec6307206 100644
--- a/net/llc/llc_proc.c
+++ b/net/llc/llc_proc.c
@@ -34,17 +34,22 @@ static struct sock *llc_get_sk_idx(loff_t pos)
34{ 34{
35 struct list_head *sap_entry; 35 struct list_head *sap_entry;
36 struct llc_sap *sap; 36 struct llc_sap *sap;
37 struct hlist_nulls_node *node;
38 struct sock *sk = NULL; 37 struct sock *sk = NULL;
38 int i;
39 39
40 list_for_each(sap_entry, &llc_sap_list) { 40 list_for_each(sap_entry, &llc_sap_list) {
41 sap = list_entry(sap_entry, struct llc_sap, node); 41 sap = list_entry(sap_entry, struct llc_sap, node);
42 42
43 spin_lock_bh(&sap->sk_lock); 43 spin_lock_bh(&sap->sk_lock);
44 sk_nulls_for_each(sk, node, &sap->sk_list) { 44 for (i = 0; i < LLC_SK_LADDR_HASH_ENTRIES; i++) {
45 if (!pos) 45 struct hlist_nulls_head *head = &sap->sk_laddr_hash[i];
46 goto found; 46 struct hlist_nulls_node *node;
47 --pos; 47
48 sk_nulls_for_each(sk, node, head) {
49 if (!pos)
50 goto found; /* keep the lock */
51 --pos;
52 }
48 } 53 }
49 spin_unlock_bh(&sap->sk_lock); 54 spin_unlock_bh(&sap->sk_lock);
50 } 55 }
@@ -61,6 +66,19 @@ static void *llc_seq_start(struct seq_file *seq, loff_t *pos)
61 return l ? llc_get_sk_idx(--l) : SEQ_START_TOKEN; 66 return l ? llc_get_sk_idx(--l) : SEQ_START_TOKEN;
62} 67}
63 68
69static struct sock *laddr_hash_next(struct llc_sap *sap, int bucket)
70{
71 struct hlist_nulls_node *node;
72 struct sock *sk = NULL;
73
74 while (++bucket < LLC_SK_LADDR_HASH_ENTRIES)
75 sk_nulls_for_each(sk, node, &sap->sk_laddr_hash[bucket])
76 goto out;
77
78out:
79 return sk;
80}
81
64static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos) 82static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
65{ 83{
66 struct sock* sk, *next; 84 struct sock* sk, *next;
@@ -80,17 +98,15 @@ static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
80 } 98 }
81 llc = llc_sk(sk); 99 llc = llc_sk(sk);
82 sap = llc->sap; 100 sap = llc->sap;
101 sk = laddr_hash_next(sap, llc_sk_laddr_hashfn(sap, &llc->laddr));
102 if (sk)
103 goto out;
83 spin_unlock_bh(&sap->sk_lock); 104 spin_unlock_bh(&sap->sk_lock);
84 sk = NULL; 105 list_for_each_entry_continue(sap, &llc_sap_list, node) {
85 for (;;) {
86 if (sap->node.next == &llc_sap_list)
87 break;
88 sap = list_entry(sap->node.next, struct llc_sap, node);
89 spin_lock_bh(&sap->sk_lock); 106 spin_lock_bh(&sap->sk_lock);
90 if (!hlist_nulls_empty(&sap->sk_list)) { 107 sk = laddr_hash_next(sap, -1);
91 sk = sk_nulls_head(&sap->sk_list); 108 if (sk)
92 break; 109 break; /* keep the lock */
93 }
94 spin_unlock_bh(&sap->sk_lock); 110 spin_unlock_bh(&sap->sk_lock);
95 } 111 }
96out: 112out: