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>
This commit is contained in:
parent
81fa3275f9
commit
471a930ad7
|
@ -362,11 +362,6 @@ void sunrpc_destroy_cache_detail(struct cache_detail *cd)
|
|||
cache_purge(cd);
|
||||
spin_lock(&cache_list_lock);
|
||||
write_lock(&cd->hash_lock);
|
||||
if (cd->entries) {
|
||||
write_unlock(&cd->hash_lock);
|
||||
spin_unlock(&cache_list_lock);
|
||||
goto out;
|
||||
}
|
||||
if (current_detail == cd)
|
||||
current_detail = NULL;
|
||||
list_del_init(&cd->others);
|
||||
|
@ -376,9 +371,6 @@ void sunrpc_destroy_cache_detail(struct cache_detail *cd)
|
|||
/* module must be being unloaded so its safe to kill the worker */
|
||||
cancel_delayed_work_sync(&cache_cleaner);
|
||||
}
|
||||
return;
|
||||
out:
|
||||
printk(KERN_ERR "RPC: failed to unregister %s cache\n", cd->name);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sunrpc_destroy_cache_detail);
|
||||
|
||||
|
@ -497,13 +489,32 @@ EXPORT_SYMBOL_GPL(cache_flush);
|
|||
|
||||
void cache_purge(struct cache_detail *detail)
|
||||
{
|
||||
time_t now = seconds_since_boot();
|
||||
if (detail->flush_time >= now)
|
||||
now = detail->flush_time + 1;
|
||||
/* 'now' is the maximum value any 'last_refresh' can have */
|
||||
detail->flush_time = now;
|
||||
detail->nextcheck = seconds_since_boot();
|
||||
cache_flush();
|
||||
struct cache_head *ch = NULL;
|
||||
struct hlist_head *head = NULL;
|
||||
struct hlist_node *tmp = NULL;
|
||||
int i = 0;
|
||||
|
||||
write_lock(&detail->hash_lock);
|
||||
if (!detail->entries) {
|
||||
write_unlock(&detail->hash_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
dprintk("RPC: %d entries in %s cache\n", detail->entries, detail->name);
|
||||
for (i = 0; i < detail->hash_size; i++) {
|
||||
head = &detail->hash_table[i];
|
||||
hlist_for_each_entry_safe(ch, tmp, head, cache_list) {
|
||||
hlist_del_init(&ch->cache_list);
|
||||
detail->entries--;
|
||||
|
||||
set_bit(CACHE_CLEANED, &ch->flags);
|
||||
write_unlock(&detail->hash_lock);
|
||||
cache_fresh_unlocked(ch, detail);
|
||||
cache_put(ch, detail);
|
||||
write_lock(&detail->hash_lock);
|
||||
}
|
||||
}
|
||||
write_unlock(&detail->hash_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cache_purge);
|
||||
|
||||
|
|
Loading…
Reference in New Issue