diff options
Diffstat (limited to 'net/llc/llc_sap.c')
-rw-r--r-- | net/llc/llc_sap.c | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c index 94cb706f6cc4..ad6e6e1cf22f 100644 --- a/net/llc/llc_sap.c +++ b/net/llc/llc_sap.c | |||
@@ -321,10 +321,12 @@ static struct sock *llc_lookup_dgram(struct llc_sap *sap, | |||
321 | { | 321 | { |
322 | struct sock *rc; | 322 | struct sock *rc; |
323 | struct hlist_nulls_node *node; | 323 | struct hlist_nulls_node *node; |
324 | int slot = llc_sk_laddr_hashfn(sap, laddr); | ||
325 | struct hlist_nulls_head *laddr_hb = &sap->sk_laddr_hash[slot]; | ||
324 | 326 | ||
325 | rcu_read_lock_bh(); | 327 | rcu_read_lock_bh(); |
326 | again: | 328 | again: |
327 | sk_nulls_for_each_rcu(rc, node, &sap->sk_list) { | 329 | sk_nulls_for_each_rcu(rc, node, laddr_hb) { |
328 | if (llc_dgram_match(sap, laddr, rc)) { | 330 | if (llc_dgram_match(sap, laddr, rc)) { |
329 | /* Extra checks required by SLAB_DESTROY_BY_RCU */ | 331 | /* Extra checks required by SLAB_DESTROY_BY_RCU */ |
330 | if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) | 332 | if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) |
@@ -338,6 +340,13 @@ again: | |||
338 | } | 340 | } |
339 | } | 341 | } |
340 | rc = NULL; | 342 | rc = NULL; |
343 | /* | ||
344 | * if the nulls value we got at the end of this lookup is | ||
345 | * not the expected one, we must restart lookup. | ||
346 | * We probably met an item that was moved to another chain. | ||
347 | */ | ||
348 | if (unlikely(get_nulls_value(node) != slot)) | ||
349 | goto again; | ||
341 | found: | 350 | found: |
342 | rcu_read_unlock_bh(); | 351 | rcu_read_unlock_bh(); |
343 | return rc; | 352 | return rc; |