diff options
Diffstat (limited to 'net/llc/llc_proc.c')
-rw-r--r-- | net/llc/llc_proc.c | 44 |
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 | ||
69 | static 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 | |||
78 | out: | ||
79 | return sk; | ||
80 | } | ||
81 | |||
64 | static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 82 | static 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 | } |
96 | out: | 112 | out: |