* [PATCH 2/2] SUNRPC: Drop all entries from cache_detail when cache_purge()
@ 2017-02-06 4:01 Kinglong Mee
2017-02-08 0:04 ` NeilBrown
0 siblings, 1 reply; 3+ messages in thread
From: Kinglong Mee @ 2017-02-06 4:01 UTC (permalink / raw)
To: J. Bruce Fields, linux-nfs; +Cc: NeilBrown, Trond Myklebust, Kinglong Mee
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()."
v2, a stand-alone cache_purge(), not only for sunrpc_destroy_cache_detail
Signed-off-by: Kinglong Mee <kinglongmee@gmail.com>
---
net/sunrpc/cache.c | 39 ++++++++++++++++++++++++---------------
1 file changed, 24 insertions(+), 15 deletions(-)
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 8147e8d..bd6ee79 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -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,30 @@ 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);
+ cache_fresh_unlocked(ch, detail);
+ cache_put(ch, detail);
+ }
+ }
+ write_unlock(&detail->hash_lock);
}
EXPORT_SYMBOL_GPL(cache_purge);
--
2.9.3
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH 2/2] SUNRPC: Drop all entries from cache_detail when cache_purge()
2017-02-06 4:01 [PATCH 2/2] SUNRPC: Drop all entries from cache_detail when cache_purge() Kinglong Mee
@ 2017-02-08 0:04 ` NeilBrown
2017-02-08 1:48 ` Kinglong Mee
0 siblings, 1 reply; 3+ messages in thread
From: NeilBrown @ 2017-02-08 0:04 UTC (permalink / raw)
To: Kinglong Mee, J. Bruce Fields, linux-nfs; +Cc: Trond Myklebust, Kinglong Mee
[-- Attachment #1: Type: text/plain, Size: 3204 bytes --]
On Mon, Feb 06 2017, Kinglong Mee wrote:
> 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()."
>
> v2, a stand-alone cache_purge(), not only for sunrpc_destroy_cache_detail
>
> Signed-off-by: Kinglong Mee <kinglongmee@gmail.com>
> ---
> net/sunrpc/cache.c | 39 ++++++++++++++++++++++++---------------
> 1 file changed, 24 insertions(+), 15 deletions(-)
>
> diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
> index 8147e8d..bd6ee79 100644
> --- a/net/sunrpc/cache.c
> +++ b/net/sunrpc/cache.c
> @@ -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,30 @@ 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);
> + cache_fresh_unlocked(ch, detail);
> + cache_put(ch, detail);
I'm a little bothered by calling cache_fresh_unlocked() while holding
->hash_lock. No other code does that.
You could probably argue that we don't need ->hash_lock at all here
because by the time we call cache_purge(), there cannot safely be any
other users. Should we just drop the write_lock() call?
NeilBrown
> + }
> + }
> + write_unlock(&detail->hash_lock);
> }
> EXPORT_SYMBOL_GPL(cache_purge);
>
> --
> 2.9.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH 2/2] SUNRPC: Drop all entries from cache_detail when cache_purge()
2017-02-08 0:04 ` NeilBrown
@ 2017-02-08 1:48 ` Kinglong Mee
0 siblings, 0 replies; 3+ messages in thread
From: Kinglong Mee @ 2017-02-08 1:48 UTC (permalink / raw)
To: NeilBrown, J. Bruce Fields, linux-nfs; +Cc: Trond Myklebust, Kinglong Mee
On 2/8/2017 08:04, NeilBrown wrote:
> On Mon, Feb 06 2017, Kinglong Mee wrote:
>
>> 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()."
>>
>> v2, a stand-alone cache_purge(), not only for sunrpc_destroy_cache_detail
>>
>> Signed-off-by: Kinglong Mee <kinglongmee@gmail.com>
>> ---
>> net/sunrpc/cache.c | 39 ++++++++++++++++++++++++---------------
>> 1 file changed, 24 insertions(+), 15 deletions(-)
>>
>> diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
>> index 8147e8d..bd6ee79 100644
>> --- a/net/sunrpc/cache.c
>> +++ b/net/sunrpc/cache.c
>> @@ -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,30 @@ 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);
>> + cache_fresh_unlocked(ch, detail);
>> + cache_put(ch, detail);
>
> I'm a little bothered by calling cache_fresh_unlocked() while holding
> ->hash_lock. No other code does that.
> You could probably argue that we don't need ->hash_lock at all here
> because by the time we call cache_purge(), there cannot safely be any
> other users. Should we just drop the write_lock() call?
No, we can't.
We call cache_purge() without remove the cache_detail from cache_list,
so that, if we drop the write_lock(), cache_clean may access the
cache_detail at the same time, a double free may happen.
Just move the cache_fresh_unlocked() out of write_lock().
thanks,
Kinglong Mee
>
> NeilBrown
>
>
>> + }
>> + }
>> + write_unlock(&detail->hash_lock);
>> }
>> EXPORT_SYMBOL_GPL(cache_purge);
>>
>> --
>> 2.9.3
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2017-02-08 1:56 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-06 4:01 [PATCH 2/2] SUNRPC: Drop all entries from cache_detail when cache_purge() Kinglong Mee
2017-02-08 0:04 ` NeilBrown
2017-02-08 1:48 ` Kinglong Mee
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.