aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKinglong Mee <kinglongmee@gmail.com>2017-02-07 20:54:33 -0500
committerJ. Bruce Fields <bfields@redhat.com>2017-02-08 16:49:32 -0500
commit471a930ad7d1b868456e835a67169a661ec73f65 (patch)
tree0b4cc18a4de82c303aceaa5ab72511acf21ebace
parent81fa3275f95ac357188fe3ca81b8e7c75360c88d (diff)
SUNRPC: Drop all entries from cache_detail when cache_purge()
User always free the cache_detail after sunrpc_destroy_cache_detail(), so, it must cleanup up entries that left in the cache_detail, otherwise, NULL reference may be caused when using the left entries. Also, NeriBrown suggests "write a stand-alone cache_purge()." v3, move the cache_fresh_unlocked() out of write lock, v2, a stand-alone cache_purge(), not only for sunrpc_destroy_cache_detail Signed-off-by: Kinglong Mee <kinglongmee@gmail.com> Reviewed-by: NeilBrown <neilb@suse.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--net/sunrpc/cache.c41
1 files changed, 26 insertions, 15 deletions
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 502b9fe9817b..f5d6c60aae26 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -362,11 +362,6 @@ void sunrpc_destroy_cache_detail(struct cache_detail *cd)
362 cache_purge(cd); 362 cache_purge(cd);
363 spin_lock(&cache_list_lock); 363 spin_lock(&cache_list_lock);
364 write_lock(&cd->hash_lock); 364 write_lock(&cd->hash_lock);
365 if (cd->entries) {
366 write_unlock(&cd->hash_lock);
367 spin_unlock(&cache_list_lock);
368 goto out;
369 }
370 if (current_detail == cd) 365 if (current_detail == cd)
371 current_detail = NULL; 366 current_detail = NULL;
372 list_del_init(&cd->others); 367 list_del_init(&cd->others);
@@ -376,9 +371,6 @@ void sunrpc_destroy_cache_detail(struct cache_detail *cd)
376 /* module must be being unloaded so its safe to kill the worker */ 371 /* module must be being unloaded so its safe to kill the worker */
377 cancel_delayed_work_sync(&cache_cleaner); 372 cancel_delayed_work_sync(&cache_cleaner);
378 } 373 }
379 return;
380out:
381 printk(KERN_ERR "RPC: failed to unregister %s cache\n", cd->name);
382} 374}
383EXPORT_SYMBOL_GPL(sunrpc_destroy_cache_detail); 375EXPORT_SYMBOL_GPL(sunrpc_destroy_cache_detail);
384 376
@@ -497,13 +489,32 @@ EXPORT_SYMBOL_GPL(cache_flush);
497 489
498void cache_purge(struct cache_detail *detail) 490void cache_purge(struct cache_detail *detail)
499{ 491{
500 time_t now = seconds_since_boot(); 492 struct cache_head *ch = NULL;
501 if (detail->flush_time >= now) 493 struct hlist_head *head = NULL;
502 now = detail->flush_time + 1; 494 struct hlist_node *tmp = NULL;
503 /* 'now' is the maximum value any 'last_refresh' can have */ 495 int i = 0;
504 detail->flush_time = now; 496
505 detail->nextcheck = seconds_since_boot(); 497 write_lock(&detail->hash_lock);
506 cache_flush(); 498 if (!detail->entries) {
499 write_unlock(&detail->hash_lock);
500 return;
501 }
502
503 dprintk("RPC: %d entries in %s cache\n", detail->entries, detail->name);
504 for (i = 0; i < detail->hash_size; i++) {
505 head = &detail->hash_table[i];
506 hlist_for_each_entry_safe(ch, tmp, head, cache_list) {
507 hlist_del_init(&ch->cache_list);
508 detail->entries--;
509
510 set_bit(CACHE_CLEANED, &ch->flags);
511 write_unlock(&detail->hash_lock);
512 cache_fresh_unlocked(ch, detail);
513 cache_put(ch, detail);
514 write_lock(&detail->hash_lock);
515 }
516 }
517 write_unlock(&detail->hash_lock);
507} 518}
508EXPORT_SYMBOL_GPL(cache_purge); 519EXPORT_SYMBOL_GPL(cache_purge);
509 520