aboutsummaryrefslogtreecommitdiffstats
path: root/lib/rhashtable.c
diff options
context:
space:
mode:
authorYing Xue <ying.xue@windriver.com>2015-01-15 22:13:09 -0500
committerDavid S. Miller <davem@davemloft.net>2015-01-16 01:18:51 -0500
commit57699a40b4f2694d3ee63fd5e6465ec8f600b620 (patch)
treeb3523af9d1685de66d9cba887007803bd2a1f467 /lib/rhashtable.c
parentcbbd36676b152719bc8f01a2b91f998820554961 (diff)
rhashtable: Fix race in rhashtable_destroy() and use regular work_struct
When we put our declared work task in the global workqueue with schedule_delayed_work(), its delay parameter is always zero. Therefore, we should define a regular work in rhashtable structure instead of a delayed work. By the way, we add a condition to check whether resizing functions are NULL before cancelling the work, avoiding to cancel an uninitialized work. Lastly, while we wait for all work items we submitted before to run to completion with cancel_delayed_work(), ht->mutex has been taken in rhashtable_destroy(). Moreover, cancel_delayed_work() doesn't return until all work items are accomplished, and when work items are scheduled, the work's function - rht_deferred_worker() will be called. However, as rht_deferred_worker() also needs to acquire the lock, deadlock might happen at the moment as the lock is already held before. So if the cancel work function is moved out of the lock covered scope, this will avoid the deadlock. Fixes: 97defe1 ("rhashtable: Per bucket locks & deferred expansion/shrinking") Signed-off-by: Ying Xue <ying.xue@windriver.com> Cc: Thomas Graf <tgraf@suug.ch> Acked-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'lib/rhashtable.c')
-rw-r--r--lib/rhashtable.c12
1 files changed, 6 insertions, 6 deletions
diff --git a/lib/rhashtable.c b/lib/rhashtable.c
index aca699813ba9..84a78e396a56 100644
--- a/lib/rhashtable.c
+++ b/lib/rhashtable.c
@@ -485,7 +485,7 @@ static void rht_deferred_worker(struct work_struct *work)
485 struct rhashtable *ht; 485 struct rhashtable *ht;
486 struct bucket_table *tbl; 486 struct bucket_table *tbl;
487 487
488 ht = container_of(work, struct rhashtable, run_work.work); 488 ht = container_of(work, struct rhashtable, run_work);
489 mutex_lock(&ht->mutex); 489 mutex_lock(&ht->mutex);
490 tbl = rht_dereference(ht->tbl, ht); 490 tbl = rht_dereference(ht->tbl, ht);
491 491
@@ -507,7 +507,7 @@ static void rhashtable_wakeup_worker(struct rhashtable *ht)
507 if (tbl == new_tbl && 507 if (tbl == new_tbl &&
508 ((ht->p.grow_decision && ht->p.grow_decision(ht, size)) || 508 ((ht->p.grow_decision && ht->p.grow_decision(ht, size)) ||
509 (ht->p.shrink_decision && ht->p.shrink_decision(ht, size)))) 509 (ht->p.shrink_decision && ht->p.shrink_decision(ht, size))))
510 schedule_delayed_work(&ht->run_work, 0); 510 schedule_work(&ht->run_work);
511} 511}
512 512
513static void __rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj, 513static void __rhashtable_insert(struct rhashtable *ht, struct rhash_head *obj,
@@ -903,7 +903,7 @@ int rhashtable_init(struct rhashtable *ht, struct rhashtable_params *params)
903 get_random_bytes(&ht->p.hash_rnd, sizeof(ht->p.hash_rnd)); 903 get_random_bytes(&ht->p.hash_rnd, sizeof(ht->p.hash_rnd));
904 904
905 if (ht->p.grow_decision || ht->p.shrink_decision) 905 if (ht->p.grow_decision || ht->p.shrink_decision)
906 INIT_DEFERRABLE_WORK(&ht->run_work, rht_deferred_worker); 906 INIT_WORK(&ht->run_work, rht_deferred_worker);
907 907
908 return 0; 908 return 0;
909} 909}
@@ -921,11 +921,11 @@ void rhashtable_destroy(struct rhashtable *ht)
921{ 921{
922 ht->being_destroyed = true; 922 ht->being_destroyed = true;
923 923
924 mutex_lock(&ht->mutex); 924 if (ht->p.grow_decision || ht->p.shrink_decision)
925 cancel_work_sync(&ht->run_work);
925 926
926 cancel_delayed_work(&ht->run_work); 927 mutex_lock(&ht->mutex);
927 bucket_table_free(rht_dereference(ht->tbl, ht)); 928 bucket_table_free(rht_dereference(ht->tbl, ht));
928
929 mutex_unlock(&ht->mutex); 929 mutex_unlock(&ht->mutex);
930} 930}
931EXPORT_SYMBOL_GPL(rhashtable_destroy); 931EXPORT_SYMBOL_GPL(rhashtable_destroy);