diff options
Diffstat (limited to 'lib/rhashtable.c')
-rw-r--r-- | lib/rhashtable.c | 506 |
1 files changed, 174 insertions, 332 deletions
diff --git a/lib/rhashtable.c b/lib/rhashtable.c index ba15dceee27f..b1c19c5fb326 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c | |||
@@ -66,9 +66,9 @@ static u32 rht_bucket_index(const struct bucket_table *tbl, u32 hash) | |||
66 | return hash & (tbl->size - 1); | 66 | return hash & (tbl->size - 1); |
67 | } | 67 | } |
68 | 68 | ||
69 | static u32 obj_raw_hashfn(struct rhashtable *ht, const void *ptr) | 69 | static u32 obj_raw_hashfn(struct rhashtable *ht, |
70 | const struct bucket_table *tbl, const void *ptr) | ||
70 | { | 71 | { |
71 | struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht); | ||
72 | u32 hash; | 72 | u32 hash; |
73 | 73 | ||
74 | if (unlikely(!ht->p.key_len)) | 74 | if (unlikely(!ht->p.key_len)) |
@@ -80,10 +80,9 @@ static u32 obj_raw_hashfn(struct rhashtable *ht, const void *ptr) | |||
80 | return hash >> HASH_RESERVED_SPACE; | 80 | return hash >> HASH_RESERVED_SPACE; |
81 | } | 81 | } |
82 | 82 | ||
83 | static u32 key_hashfn(struct rhashtable *ht, const void *key, u32 len) | 83 | static u32 key_hashfn(struct rhashtable *ht, const struct bucket_table *tbl, |
84 | const void *key, u32 len) | ||
84 | { | 85 | { |
85 | struct bucket_table *tbl = rht_dereference_rcu(ht->tbl, ht); | ||
86 | |||
87 | return ht->p.hashfn(key, len, tbl->hash_rnd) >> HASH_RESERVED_SPACE; | 86 | return ht->p.hashfn(key, len, tbl->hash_rnd) >> HASH_RESERVED_SPACE; |
88 | } | 87 | } |
89 | 88 | ||
@@ -91,60 +90,11 @@ static u32 head_hashfn(struct rhashtable *ht, | |||
91 | const struct bucket_table *tbl, | 90 | const struct bucket_table *tbl, |
92 | const struct rhash_head *he) | 91 | const struct rhash_head *he) |
93 | { | 92 | { |
94 | return rht_bucket_index(tbl, obj_raw_hashfn(ht, rht_obj(ht, he))); | 93 | return rht_bucket_index(tbl, obj_raw_hashfn(ht, tbl, rht_obj(ht, he))); |
95 | } | 94 | } |
96 | 95 | ||
97 | #ifdef CONFIG_PROVE_LOCKING | 96 | #ifdef CONFIG_PROVE_LOCKING |
98 | static void debug_dump_buckets(struct rhashtable *ht, | ||
99 | const struct bucket_table *tbl) | ||
100 | { | ||
101 | struct rhash_head *he; | ||
102 | unsigned int i, hash; | ||
103 | |||
104 | for (i = 0; i < tbl->size; i++) { | ||
105 | pr_warn(" [Bucket %d] ", i); | ||
106 | rht_for_each_rcu(he, tbl, i) { | ||
107 | hash = head_hashfn(ht, tbl, he); | ||
108 | pr_cont("[hash = %#x, lock = %p] ", | ||
109 | hash, bucket_lock(tbl, hash)); | ||
110 | } | ||
111 | pr_cont("\n"); | ||
112 | } | ||
113 | |||
114 | } | ||
115 | |||
116 | static void debug_dump_table(struct rhashtable *ht, | ||
117 | const struct bucket_table *tbl, | ||
118 | unsigned int hash) | ||
119 | { | ||
120 | struct bucket_table *old_tbl, *future_tbl; | ||
121 | |||
122 | pr_emerg("BUG: lock for hash %#x in table %p not held\n", | ||
123 | hash, tbl); | ||
124 | |||
125 | rcu_read_lock(); | ||
126 | future_tbl = rht_dereference_rcu(ht->future_tbl, ht); | ||
127 | old_tbl = rht_dereference_rcu(ht->tbl, ht); | ||
128 | if (future_tbl != old_tbl) { | ||
129 | pr_warn("Future table %p (size: %zd)\n", | ||
130 | future_tbl, future_tbl->size); | ||
131 | debug_dump_buckets(ht, future_tbl); | ||
132 | } | ||
133 | |||
134 | pr_warn("Table %p (size: %zd)\n", old_tbl, old_tbl->size); | ||
135 | debug_dump_buckets(ht, old_tbl); | ||
136 | |||
137 | rcu_read_unlock(); | ||
138 | } | ||
139 | |||
140 | #define ASSERT_RHT_MUTEX(HT) BUG_ON(!lockdep_rht_mutex_is_held(HT)) | 97 | #define ASSERT_RHT_MUTEX(HT) BUG_ON(!lockdep_rht_mutex_is_held(HT)) |
141 | #define ASSERT_BUCKET_LOCK(HT, TBL, HASH) \ | ||
142 | do { \ | ||
143 | if (unlikely(!lockdep_rht_bucket_is_held(TBL, HASH))) { \ | ||
144 | debug_dump_table(HT, TBL, HASH); \ | ||
145 | BUG(); \ | ||
146 | } \ | ||
147 | } while (0) | ||
148 | 98 | ||
149 | int lockdep_rht_mutex_is_held(struct rhashtable *ht) | 99 | int lockdep_rht_mutex_is_held(struct rhashtable *ht) |
150 | { | 100 | { |
@@ -161,22 +111,9 @@ int lockdep_rht_bucket_is_held(const struct bucket_table *tbl, u32 hash) | |||
161 | EXPORT_SYMBOL_GPL(lockdep_rht_bucket_is_held); | 111 | EXPORT_SYMBOL_GPL(lockdep_rht_bucket_is_held); |
162 | #else | 112 | #else |
163 | #define ASSERT_RHT_MUTEX(HT) | 113 | #define ASSERT_RHT_MUTEX(HT) |
164 | #define ASSERT_BUCKET_LOCK(HT, TBL, HASH) | ||
165 | #endif | 114 | #endif |
166 | 115 | ||
167 | 116 | ||
168 | static struct rhash_head __rcu **bucket_tail(struct bucket_table *tbl, u32 n) | ||
169 | { | ||
170 | struct rhash_head __rcu **pprev; | ||
171 | |||
172 | for (pprev = &tbl->buckets[n]; | ||
173 | !rht_is_a_nulls(rht_dereference_bucket(*pprev, tbl, n)); | ||
174 | pprev = &rht_dereference_bucket(*pprev, tbl, n)->next) | ||
175 | ; | ||
176 | |||
177 | return pprev; | ||
178 | } | ||
179 | |||
180 | static int alloc_bucket_locks(struct rhashtable *ht, struct bucket_table *tbl) | 117 | static int alloc_bucket_locks(struct rhashtable *ht, struct bucket_table *tbl) |
181 | { | 118 | { |
182 | unsigned int i, size; | 119 | unsigned int i, size; |
@@ -270,101 +207,99 @@ static bool rht_shrink_below_30(const struct rhashtable *ht, size_t new_size) | |||
270 | (atomic_read(&ht->shift) > ht->p.min_shift); | 207 | (atomic_read(&ht->shift) > ht->p.min_shift); |
271 | } | 208 | } |
272 | 209 | ||
273 | static void lock_buckets(struct bucket_table *new_tbl, | 210 | static int rhashtable_rehash_one(struct rhashtable *ht, unsigned old_hash) |
274 | struct bucket_table *old_tbl, unsigned int hash) | ||
275 | __acquires(old_bucket_lock) | ||
276 | { | 211 | { |
277 | spin_lock_bh(bucket_lock(old_tbl, hash)); | 212 | struct bucket_table *new_tbl = rht_dereference(ht->future_tbl, ht); |
278 | if (new_tbl != old_tbl) | 213 | struct bucket_table *old_tbl = rht_dereference(ht->tbl, ht); |
279 | spin_lock_bh_nested(bucket_lock(new_tbl, hash), | 214 | struct rhash_head __rcu **pprev = &old_tbl->buckets[old_hash]; |
280 | RHT_LOCK_NESTED); | 215 | int err = -ENOENT; |
281 | } | 216 | struct rhash_head *head, *next, *entry; |
217 | spinlock_t *new_bucket_lock; | ||
218 | unsigned new_hash; | ||
282 | 219 | ||
283 | static void unlock_buckets(struct bucket_table *new_tbl, | 220 | rht_for_each(entry, old_tbl, old_hash) { |
284 | struct bucket_table *old_tbl, unsigned int hash) | 221 | err = 0; |
285 | __releases(old_bucket_lock) | 222 | next = rht_dereference_bucket(entry->next, old_tbl, old_hash); |
286 | { | ||
287 | if (new_tbl != old_tbl) | ||
288 | spin_unlock_bh(bucket_lock(new_tbl, hash)); | ||
289 | spin_unlock_bh(bucket_lock(old_tbl, hash)); | ||
290 | } | ||
291 | 223 | ||
292 | /** | 224 | if (rht_is_a_nulls(next)) |
293 | * Unlink entries on bucket which hash to different bucket. | 225 | break; |
294 | * | ||
295 | * Returns true if no more work needs to be performed on the bucket. | ||
296 | */ | ||
297 | static bool hashtable_chain_unzip(struct rhashtable *ht, | ||
298 | const struct bucket_table *new_tbl, | ||
299 | struct bucket_table *old_tbl, | ||
300 | size_t old_hash) | ||
301 | { | ||
302 | struct rhash_head *he, *p, *next; | ||
303 | unsigned int new_hash, new_hash2; | ||
304 | 226 | ||
305 | ASSERT_BUCKET_LOCK(ht, old_tbl, old_hash); | 227 | pprev = &entry->next; |
228 | } | ||
306 | 229 | ||
307 | /* Old bucket empty, no work needed. */ | 230 | if (err) |
308 | p = rht_dereference_bucket(old_tbl->buckets[old_hash], old_tbl, | 231 | goto out; |
309 | old_hash); | ||
310 | if (rht_is_a_nulls(p)) | ||
311 | return false; | ||
312 | 232 | ||
313 | new_hash = head_hashfn(ht, new_tbl, p); | 233 | new_hash = head_hashfn(ht, new_tbl, entry); |
314 | ASSERT_BUCKET_LOCK(ht, new_tbl, new_hash); | ||
315 | 234 | ||
316 | /* Advance the old bucket pointer one or more times until it | 235 | new_bucket_lock = bucket_lock(new_tbl, new_hash); |
317 | * reaches a node that doesn't hash to the same bucket as the | ||
318 | * previous node p. Call the previous node p; | ||
319 | */ | ||
320 | rht_for_each_continue(he, p->next, old_tbl, old_hash) { | ||
321 | new_hash2 = head_hashfn(ht, new_tbl, he); | ||
322 | ASSERT_BUCKET_LOCK(ht, new_tbl, new_hash2); | ||
323 | 236 | ||
324 | if (new_hash != new_hash2) | 237 | spin_lock(new_bucket_lock); |
325 | break; | 238 | head = rht_dereference_bucket(new_tbl->buckets[new_hash], |
326 | p = he; | 239 | new_tbl, new_hash); |
327 | } | ||
328 | rcu_assign_pointer(old_tbl->buckets[old_hash], p->next); | ||
329 | 240 | ||
330 | /* Find the subsequent node which does hash to the same | 241 | if (rht_is_a_nulls(head)) |
331 | * bucket as node P, or NULL if no such node exists. | 242 | INIT_RHT_NULLS_HEAD(entry->next, ht, new_hash); |
332 | */ | 243 | else |
333 | INIT_RHT_NULLS_HEAD(next, ht, old_hash); | 244 | RCU_INIT_POINTER(entry->next, head); |
334 | if (!rht_is_a_nulls(he)) { | ||
335 | rht_for_each_continue(he, he->next, old_tbl, old_hash) { | ||
336 | if (head_hashfn(ht, new_tbl, he) == new_hash) { | ||
337 | next = he; | ||
338 | break; | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | 245 | ||
343 | /* Set p's next pointer to that subsequent node pointer, | 246 | rcu_assign_pointer(new_tbl->buckets[new_hash], entry); |
344 | * bypassing the nodes which do not hash to p's bucket | 247 | spin_unlock(new_bucket_lock); |
345 | */ | ||
346 | rcu_assign_pointer(p->next, next); | ||
347 | 248 | ||
348 | p = rht_dereference_bucket(old_tbl->buckets[old_hash], old_tbl, | 249 | rcu_assign_pointer(*pprev, next); |
349 | old_hash); | ||
350 | 250 | ||
351 | return !rht_is_a_nulls(p); | 251 | out: |
252 | return err; | ||
352 | } | 253 | } |
353 | 254 | ||
354 | static void link_old_to_new(struct rhashtable *ht, struct bucket_table *new_tbl, | 255 | static void rhashtable_rehash_chain(struct rhashtable *ht, unsigned old_hash) |
355 | unsigned int new_hash, struct rhash_head *entry) | ||
356 | { | 256 | { |
357 | ASSERT_BUCKET_LOCK(ht, new_tbl, new_hash); | 257 | struct bucket_table *old_tbl = rht_dereference(ht->tbl, ht); |
258 | spinlock_t *old_bucket_lock; | ||
259 | |||
260 | old_bucket_lock = bucket_lock(old_tbl, old_hash); | ||
358 | 261 | ||
359 | rcu_assign_pointer(*bucket_tail(new_tbl, new_hash), entry); | 262 | spin_lock_bh(old_bucket_lock); |
263 | while (!rhashtable_rehash_one(ht, old_hash)) | ||
264 | ; | ||
265 | spin_unlock_bh(old_bucket_lock); | ||
266 | } | ||
267 | |||
268 | static void rhashtable_rehash(struct rhashtable *ht, | ||
269 | struct bucket_table *new_tbl) | ||
270 | { | ||
271 | struct bucket_table *old_tbl = rht_dereference(ht->tbl, ht); | ||
272 | unsigned old_hash; | ||
273 | |||
274 | get_random_bytes(&new_tbl->hash_rnd, sizeof(new_tbl->hash_rnd)); | ||
275 | |||
276 | /* Make insertions go into the new, empty table right away. Deletions | ||
277 | * and lookups will be attempted in both tables until we synchronize. | ||
278 | * The synchronize_rcu() guarantees for the new table to be picked up | ||
279 | * so no new additions go into the old table while we relink. | ||
280 | */ | ||
281 | rcu_assign_pointer(ht->future_tbl, new_tbl); | ||
282 | |||
283 | for (old_hash = 0; old_hash < old_tbl->size; old_hash++) | ||
284 | rhashtable_rehash_chain(ht, old_hash); | ||
285 | |||
286 | /* Publish the new table pointer. */ | ||
287 | rcu_assign_pointer(ht->tbl, new_tbl); | ||
288 | |||
289 | /* Wait for readers. All new readers will see the new | ||
290 | * table, and thus no references to the old table will | ||
291 | * remain. | ||
292 | */ | ||
293 | synchronize_rcu(); | ||
294 | |||
295 | bucket_table_free(old_tbl); | ||
360 | } | 296 | } |
361 | 297 | ||
362 | /** | 298 | /** |
363 | * rhashtable_expand - Expand hash table while allowing concurrent lookups | 299 | * rhashtable_expand - Expand hash table while allowing concurrent lookups |
364 | * @ht: the hash table to expand | 300 | * @ht: the hash table to expand |
365 | * | 301 | * |
366 | * A secondary bucket array is allocated and the hash entries are migrated | 302 | * A secondary bucket array is allocated and the hash entries are migrated. |
367 | * while keeping them on both lists until the end of the RCU grace period. | ||
368 | * | 303 | * |
369 | * This function may only be called in a context where it is safe to call | 304 | * This function may only be called in a context where it is safe to call |
370 | * synchronize_rcu(), e.g. not within a rcu_read_lock() section. | 305 | * synchronize_rcu(), e.g. not within a rcu_read_lock() section. |
@@ -378,9 +313,6 @@ static void link_old_to_new(struct rhashtable *ht, struct bucket_table *new_tbl, | |||
378 | int rhashtable_expand(struct rhashtable *ht) | 313 | int rhashtable_expand(struct rhashtable *ht) |
379 | { | 314 | { |
380 | struct bucket_table *new_tbl, *old_tbl = rht_dereference(ht->tbl, ht); | 315 | struct bucket_table *new_tbl, *old_tbl = rht_dereference(ht->tbl, ht); |
381 | struct rhash_head *he; | ||
382 | unsigned int new_hash, old_hash; | ||
383 | bool complete = false; | ||
384 | 316 | ||
385 | ASSERT_RHT_MUTEX(ht); | 317 | ASSERT_RHT_MUTEX(ht); |
386 | 318 | ||
@@ -392,64 +324,8 @@ int rhashtable_expand(struct rhashtable *ht) | |||
392 | 324 | ||
393 | atomic_inc(&ht->shift); | 325 | atomic_inc(&ht->shift); |
394 | 326 | ||
395 | /* Make insertions go into the new, empty table right away. Deletions | 327 | rhashtable_rehash(ht, new_tbl); |
396 | * and lookups will be attempted in both tables until we synchronize. | ||
397 | * The synchronize_rcu() guarantees for the new table to be picked up | ||
398 | * so no new additions go into the old table while we relink. | ||
399 | */ | ||
400 | rcu_assign_pointer(ht->future_tbl, new_tbl); | ||
401 | synchronize_rcu(); | ||
402 | 328 | ||
403 | /* For each new bucket, search the corresponding old bucket for the | ||
404 | * first entry that hashes to the new bucket, and link the end of | ||
405 | * newly formed bucket chain (containing entries added to future | ||
406 | * table) to that entry. Since all the entries which will end up in | ||
407 | * the new bucket appear in the same old bucket, this constructs an | ||
408 | * entirely valid new hash table, but with multiple buckets | ||
409 | * "zipped" together into a single imprecise chain. | ||
410 | */ | ||
411 | for (new_hash = 0; new_hash < new_tbl->size; new_hash++) { | ||
412 | old_hash = rht_bucket_index(old_tbl, new_hash); | ||
413 | lock_buckets(new_tbl, old_tbl, new_hash); | ||
414 | rht_for_each(he, old_tbl, old_hash) { | ||
415 | if (head_hashfn(ht, new_tbl, he) == new_hash) { | ||
416 | link_old_to_new(ht, new_tbl, new_hash, he); | ||
417 | break; | ||
418 | } | ||
419 | } | ||
420 | unlock_buckets(new_tbl, old_tbl, new_hash); | ||
421 | cond_resched(); | ||
422 | } | ||
423 | |||
424 | /* Unzip interleaved hash chains */ | ||
425 | while (!complete && !ht->being_destroyed) { | ||
426 | /* Wait for readers. All new readers will see the new | ||
427 | * table, and thus no references to the old table will | ||
428 | * remain. | ||
429 | */ | ||
430 | synchronize_rcu(); | ||
431 | |||
432 | /* For each bucket in the old table (each of which | ||
433 | * contains items from multiple buckets of the new | ||
434 | * table): ... | ||
435 | */ | ||
436 | complete = true; | ||
437 | for (old_hash = 0; old_hash < old_tbl->size; old_hash++) { | ||
438 | lock_buckets(new_tbl, old_tbl, old_hash); | ||
439 | |||
440 | if (hashtable_chain_unzip(ht, new_tbl, old_tbl, | ||
441 | old_hash)) | ||
442 | complete = false; | ||
443 | |||
444 | unlock_buckets(new_tbl, old_tbl, old_hash); | ||
445 | cond_resched(); | ||
446 | } | ||
447 | } | ||
448 | |||
449 | rcu_assign_pointer(ht->tbl, new_tbl); | ||
450 | synchronize_rcu(); | ||
451 | |||
452 | bucket_table_free(old_tbl); | ||
453 | return 0; | 329 | return 0; |
454 | } | 330 | } |
455 | EXPORT_SYMBOL_GPL(rhashtable_expand); | 331 | EXPORT_SYMBOL_GPL(rhashtable_expand); |
@@ -473,7 +349,6 @@ EXPORT_SYMBOL_GPL(rhashtable_expand); | |||
473 | int rhashtable_shrink(struct rhashtable *ht) | 349 | int rhashtable_shrink(struct rhashtable *ht) |
474 | { | 350 | { |
475 | struct bucket_table *new_tbl, *tbl = rht_dereference(ht->tbl, ht); | 351 | struct bucket_table *new_tbl, *tbl = rht_dereference(ht->tbl, ht); |
476 | unsigned int new_hash; | ||
477 | 352 | ||
478 | ASSERT_RHT_MUTEX(ht); | 353 | ASSERT_RHT_MUTEX(ht); |
479 | 354 | ||
@@ -483,39 +358,9 @@ int rhashtable_shrink(struct rhashtable *ht) | |||
483 | 358 | ||
484 | new_tbl->hash_rnd = tbl->hash_rnd; | 359 | new_tbl->hash_rnd = tbl->hash_rnd; |
485 | 360 | ||
486 | rcu_assign_pointer(ht->future_tbl, new_tbl); | ||
487 | synchronize_rcu(); | ||
488 | |||
489 | /* Link the first entry in the old bucket to the end of the | ||
490 | * bucket in the new table. As entries are concurrently being | ||
491 | * added to the new table, lock down the new bucket. As we | ||
492 | * always divide the size in half when shrinking, each bucket | ||
493 | * in the new table maps to exactly two buckets in the old | ||
494 | * table. | ||
495 | */ | ||
496 | for (new_hash = 0; new_hash < new_tbl->size; new_hash++) { | ||
497 | lock_buckets(new_tbl, tbl, new_hash); | ||
498 | |||
499 | rcu_assign_pointer(*bucket_tail(new_tbl, new_hash), | ||
500 | tbl->buckets[new_hash]); | ||
501 | ASSERT_BUCKET_LOCK(ht, tbl, new_hash + new_tbl->size); | ||
502 | rcu_assign_pointer(*bucket_tail(new_tbl, new_hash), | ||
503 | tbl->buckets[new_hash + new_tbl->size]); | ||
504 | |||
505 | unlock_buckets(new_tbl, tbl, new_hash); | ||
506 | cond_resched(); | ||
507 | } | ||
508 | |||
509 | /* Publish the new, valid hash table */ | ||
510 | rcu_assign_pointer(ht->tbl, new_tbl); | ||
511 | atomic_dec(&ht->shift); | 361 | atomic_dec(&ht->shift); |
512 | 362 | ||
513 | /* Wait for readers. No new readers will have references to the | 363 | rhashtable_rehash(ht, new_tbl); |
514 | * old hash table. | ||
515 | */ | ||
516 | synchronize_rcu(); | ||
517 | |||
518 | bucket_table_free(tbl); | ||
519 | 364 | ||
520 | return 0; | 365 | return 0; |
521 | } | 366 | } |
@@ -545,18 +390,46 @@ unlock: | |||
545 | mutex_unlock(&ht->mutex); | 390 | mutex_unlock(&ht->mutex); |
546 | } | 391 | } |
547 | 392 | ||
548 | static void __rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj, | 393 | static bool __rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj, |
549 | struct bucket_table *tbl, | 394 | bool (*compare)(void *, void *), void *arg) |
550 | const struct bucket_table *old_tbl, u32 hash) | ||
551 | { | 395 | { |
552 | bool no_resize_running = tbl == old_tbl; | 396 | struct bucket_table *tbl, *old_tbl; |
553 | struct rhash_head *head; | 397 | struct rhash_head *head; |
398 | bool no_resize_running; | ||
399 | unsigned hash; | ||
400 | bool success = true; | ||
401 | |||
402 | rcu_read_lock(); | ||
403 | |||
404 | old_tbl = rht_dereference_rcu(ht->tbl, ht); | ||
405 | hash = obj_raw_hashfn(ht, old_tbl, rht_obj(ht, obj)); | ||
406 | |||
407 | spin_lock_bh(bucket_lock(old_tbl, hash)); | ||
408 | |||
409 | /* Because we have already taken the bucket lock in old_tbl, | ||
410 | * if we find that future_tbl is not yet visible then that | ||
411 | * guarantees all other insertions of the same entry will | ||
412 | * also grab the bucket lock in old_tbl because until the | ||
413 | * rehash completes ht->tbl won't be changed. | ||
414 | */ | ||
415 | tbl = rht_dereference_rcu(ht->future_tbl, ht); | ||
416 | if (tbl != old_tbl) { | ||
417 | hash = obj_raw_hashfn(ht, tbl, rht_obj(ht, obj)); | ||
418 | spin_lock(bucket_lock(tbl, hash)); | ||
419 | } | ||
420 | |||
421 | if (compare && | ||
422 | rhashtable_lookup_compare(ht, rht_obj(ht, obj) + ht->p.key_offset, | ||
423 | compare, arg)) { | ||
424 | success = false; | ||
425 | goto exit; | ||
426 | } | ||
427 | |||
428 | no_resize_running = tbl == old_tbl; | ||
554 | 429 | ||
555 | hash = rht_bucket_index(tbl, hash); | 430 | hash = rht_bucket_index(tbl, hash); |
556 | head = rht_dereference_bucket(tbl->buckets[hash], tbl, hash); | 431 | head = rht_dereference_bucket(tbl->buckets[hash], tbl, hash); |
557 | 432 | ||
558 | ASSERT_BUCKET_LOCK(ht, tbl, hash); | ||
559 | |||
560 | if (rht_is_a_nulls(head)) | 433 | if (rht_is_a_nulls(head)) |
561 | INIT_RHT_NULLS_HEAD(obj->next, ht, hash); | 434 | INIT_RHT_NULLS_HEAD(obj->next, ht, hash); |
562 | else | 435 | else |
@@ -567,6 +440,19 @@ static void __rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj, | |||
567 | atomic_inc(&ht->nelems); | 440 | atomic_inc(&ht->nelems); |
568 | if (no_resize_running && rht_grow_above_75(ht, tbl->size)) | 441 | if (no_resize_running && rht_grow_above_75(ht, tbl->size)) |
569 | schedule_work(&ht->run_work); | 442 | schedule_work(&ht->run_work); |
443 | |||
444 | exit: | ||
445 | if (tbl != old_tbl) { | ||
446 | hash = obj_raw_hashfn(ht, tbl, rht_obj(ht, obj)); | ||
447 | spin_unlock(bucket_lock(tbl, hash)); | ||
448 | } | ||
449 | |||
450 | hash = obj_raw_hashfn(ht, old_tbl, rht_obj(ht, obj)); | ||
451 | spin_unlock_bh(bucket_lock(old_tbl, hash)); | ||
452 | |||
453 | rcu_read_unlock(); | ||
454 | |||
455 | return success; | ||
570 | } | 456 | } |
571 | 457 | ||
572 | /** | 458 | /** |
@@ -586,22 +472,42 @@ static void __rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj, | |||
586 | */ | 472 | */ |
587 | void rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj) | 473 | void rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj) |
588 | { | 474 | { |
589 | struct bucket_table *tbl, *old_tbl; | 475 | __rhashtable_insert(ht, obj, NULL, NULL); |
476 | } | ||
477 | EXPORT_SYMBOL_GPL(rhashtable_insert); | ||
478 | |||
479 | static bool __rhashtable_remove(struct rhashtable *ht, | ||
480 | struct bucket_table *tbl, | ||
481 | struct rhash_head *obj) | ||
482 | { | ||
483 | struct rhash_head __rcu **pprev; | ||
484 | struct rhash_head *he; | ||
485 | spinlock_t * lock; | ||
590 | unsigned hash; | 486 | unsigned hash; |
487 | bool ret = false; | ||
591 | 488 | ||
592 | rcu_read_lock(); | 489 | hash = obj_raw_hashfn(ht, tbl, rht_obj(ht, obj)); |
490 | lock = bucket_lock(tbl, hash); | ||
491 | hash = rht_bucket_index(tbl, hash); | ||
593 | 492 | ||
594 | tbl = rht_dereference_rcu(ht->future_tbl, ht); | 493 | spin_lock_bh(lock); |
595 | old_tbl = rht_dereference_rcu(ht->tbl, ht); | ||
596 | hash = obj_raw_hashfn(ht, rht_obj(ht, obj)); | ||
597 | 494 | ||
598 | lock_buckets(tbl, old_tbl, hash); | 495 | pprev = &tbl->buckets[hash]; |
599 | __rhashtable_insert(ht, obj, tbl, old_tbl, hash); | 496 | rht_for_each(he, tbl, hash) { |
600 | unlock_buckets(tbl, old_tbl, hash); | 497 | if (he != obj) { |
498 | pprev = &he->next; | ||
499 | continue; | ||
500 | } | ||
601 | 501 | ||
602 | rcu_read_unlock(); | 502 | rcu_assign_pointer(*pprev, obj->next); |
503 | ret = true; | ||
504 | break; | ||
505 | } | ||
506 | |||
507 | spin_unlock_bh(lock); | ||
508 | |||
509 | return ret; | ||
603 | } | 510 | } |
604 | EXPORT_SYMBOL_GPL(rhashtable_insert); | ||
605 | 511 | ||
606 | /** | 512 | /** |
607 | * rhashtable_remove - remove object from hash table | 513 | * rhashtable_remove - remove object from hash table |
@@ -620,68 +526,28 @@ EXPORT_SYMBOL_GPL(rhashtable_insert); | |||
620 | */ | 526 | */ |
621 | bool rhashtable_remove(struct rhashtable *ht, struct rhash_head *obj) | 527 | bool rhashtable_remove(struct rhashtable *ht, struct rhash_head *obj) |
622 | { | 528 | { |
623 | struct bucket_table *tbl, *new_tbl, *old_tbl; | 529 | struct bucket_table *tbl, *old_tbl; |
624 | struct rhash_head __rcu **pprev; | 530 | bool ret; |
625 | struct rhash_head *he, *he2; | ||
626 | unsigned int hash, new_hash; | ||
627 | bool ret = false; | ||
628 | 531 | ||
629 | rcu_read_lock(); | 532 | rcu_read_lock(); |
630 | old_tbl = rht_dereference_rcu(ht->tbl, ht); | ||
631 | tbl = new_tbl = rht_dereference_rcu(ht->future_tbl, ht); | ||
632 | new_hash = obj_raw_hashfn(ht, rht_obj(ht, obj)); | ||
633 | |||
634 | lock_buckets(new_tbl, old_tbl, new_hash); | ||
635 | restart: | ||
636 | hash = rht_bucket_index(tbl, new_hash); | ||
637 | pprev = &tbl->buckets[hash]; | ||
638 | rht_for_each(he, tbl, hash) { | ||
639 | if (he != obj) { | ||
640 | pprev = &he->next; | ||
641 | continue; | ||
642 | } | ||
643 | 533 | ||
644 | ASSERT_BUCKET_LOCK(ht, tbl, hash); | 534 | old_tbl = rht_dereference_rcu(ht->tbl, ht); |
645 | 535 | ret = __rhashtable_remove(ht, old_tbl, obj); | |
646 | if (old_tbl->size > new_tbl->size && tbl == old_tbl && | ||
647 | !rht_is_a_nulls(obj->next) && | ||
648 | head_hashfn(ht, tbl, obj->next) != hash) { | ||
649 | rcu_assign_pointer(*pprev, (struct rhash_head *) rht_marker(ht, hash)); | ||
650 | } else if (unlikely(old_tbl->size < new_tbl->size && tbl == new_tbl)) { | ||
651 | rht_for_each_continue(he2, obj->next, tbl, hash) { | ||
652 | if (head_hashfn(ht, tbl, he2) == hash) { | ||
653 | rcu_assign_pointer(*pprev, he2); | ||
654 | goto found; | ||
655 | } | ||
656 | } | ||
657 | |||
658 | rcu_assign_pointer(*pprev, (struct rhash_head *) rht_marker(ht, hash)); | ||
659 | } else { | ||
660 | rcu_assign_pointer(*pprev, obj->next); | ||
661 | } | ||
662 | |||
663 | found: | ||
664 | ret = true; | ||
665 | break; | ||
666 | } | ||
667 | 536 | ||
668 | /* The entry may be linked in either 'tbl', 'future_tbl', or both. | 537 | /* Because we have already taken (and released) the bucket |
669 | * 'future_tbl' only exists for a short period of time during | 538 | * lock in old_tbl, if we find that future_tbl is not yet |
670 | * resizing. Thus traversing both is fine and the added cost is | 539 | * visible then that guarantees the entry to still be in |
671 | * very rare. | 540 | * old_tbl if it exists. |
672 | */ | 541 | */ |
673 | if (tbl != old_tbl) { | 542 | tbl = rht_dereference_rcu(ht->future_tbl, ht); |
674 | tbl = old_tbl; | 543 | if (!ret && old_tbl != tbl) |
675 | goto restart; | 544 | ret = __rhashtable_remove(ht, tbl, obj); |
676 | } | ||
677 | |||
678 | unlock_buckets(new_tbl, old_tbl, new_hash); | ||
679 | 545 | ||
680 | if (ret) { | 546 | if (ret) { |
681 | bool no_resize_running = new_tbl == old_tbl; | 547 | bool no_resize_running = tbl == old_tbl; |
682 | 548 | ||
683 | atomic_dec(&ht->nelems); | 549 | atomic_dec(&ht->nelems); |
684 | if (no_resize_running && rht_shrink_below_30(ht, new_tbl->size)) | 550 | if (no_resize_running && rht_shrink_below_30(ht, tbl->size)) |
685 | schedule_work(&ht->run_work); | 551 | schedule_work(&ht->run_work); |
686 | } | 552 | } |
687 | 553 | ||
@@ -753,9 +619,8 @@ void *rhashtable_lookup_compare(struct rhashtable *ht, const void *key, | |||
753 | 619 | ||
754 | rcu_read_lock(); | 620 | rcu_read_lock(); |
755 | 621 | ||
756 | old_tbl = rht_dereference_rcu(ht->tbl, ht); | 622 | tbl = rht_dereference_rcu(ht->tbl, ht); |
757 | tbl = rht_dereference_rcu(ht->future_tbl, ht); | 623 | hash = key_hashfn(ht, tbl, key, ht->p.key_len); |
758 | hash = key_hashfn(ht, key, ht->p.key_len); | ||
759 | restart: | 624 | restart: |
760 | rht_for_each_rcu(he, tbl, rht_bucket_index(tbl, hash)) { | 625 | rht_for_each_rcu(he, tbl, rht_bucket_index(tbl, hash)) { |
761 | if (!compare(rht_obj(ht, he), arg)) | 626 | if (!compare(rht_obj(ht, he), arg)) |
@@ -764,10 +629,10 @@ restart: | |||
764 | return rht_obj(ht, he); | 629 | return rht_obj(ht, he); |
765 | } | 630 | } |
766 | 631 | ||
767 | if (unlikely(tbl != old_tbl)) { | 632 | old_tbl = tbl; |
768 | tbl = old_tbl; | 633 | tbl = rht_dereference_rcu(ht->future_tbl, ht); |
634 | if (unlikely(tbl != old_tbl)) | ||
769 | goto restart; | 635 | goto restart; |
770 | } | ||
771 | rcu_read_unlock(); | 636 | rcu_read_unlock(); |
772 | 637 | ||
773 | return NULL; | 638 | return NULL; |
@@ -833,32 +698,9 @@ bool rhashtable_lookup_compare_insert(struct rhashtable *ht, | |||
833 | bool (*compare)(void *, void *), | 698 | bool (*compare)(void *, void *), |
834 | void *arg) | 699 | void *arg) |
835 | { | 700 | { |
836 | struct bucket_table *new_tbl, *old_tbl; | ||
837 | u32 new_hash; | ||
838 | bool success = true; | ||
839 | |||
840 | BUG_ON(!ht->p.key_len); | 701 | BUG_ON(!ht->p.key_len); |
841 | 702 | ||
842 | rcu_read_lock(); | 703 | return __rhashtable_insert(ht, obj, compare, arg); |
843 | old_tbl = rht_dereference_rcu(ht->tbl, ht); | ||
844 | new_tbl = rht_dereference_rcu(ht->future_tbl, ht); | ||
845 | new_hash = obj_raw_hashfn(ht, rht_obj(ht, obj)); | ||
846 | |||
847 | lock_buckets(new_tbl, old_tbl, new_hash); | ||
848 | |||
849 | if (rhashtable_lookup_compare(ht, rht_obj(ht, obj) + ht->p.key_offset, | ||
850 | compare, arg)) { | ||
851 | success = false; | ||
852 | goto exit; | ||
853 | } | ||
854 | |||
855 | __rhashtable_insert(ht, obj, new_tbl, old_tbl, new_hash); | ||
856 | |||
857 | exit: | ||
858 | unlock_buckets(new_tbl, old_tbl, new_hash); | ||
859 | rcu_read_unlock(); | ||
860 | |||
861 | return success; | ||
862 | } | 704 | } |
863 | EXPORT_SYMBOL_GPL(rhashtable_lookup_compare_insert); | 705 | EXPORT_SYMBOL_GPL(rhashtable_lookup_compare_insert); |
864 | 706 | ||