diff options
-rw-r--r-- | fs/mbcache2.c | 50 |
1 files changed, 45 insertions, 5 deletions
diff --git a/fs/mbcache2.c b/fs/mbcache2.c index 5c3e1a8c38f6..3e3198d6b9d6 100644 --- a/fs/mbcache2.c +++ b/fs/mbcache2.c @@ -4,6 +4,7 @@ #include <linux/list_bl.h> #include <linux/module.h> #include <linux/sched.h> +#include <linux/workqueue.h> #include <linux/mbcache2.h> /* @@ -27,16 +28,29 @@ struct mb2_cache { struct hlist_bl_head *c_hash; /* log2 of hash table size */ int c_bucket_bits; + /* Maximum entries in cache to avoid degrading hash too much */ + int c_max_entries; /* Protects c_lru_list, c_entry_count */ spinlock_t c_lru_list_lock; struct list_head c_lru_list; /* Number of entries in cache */ unsigned long c_entry_count; struct shrinker c_shrink; + /* Work for shrinking when the cache has too many entries */ + struct work_struct c_shrink_work; }; static struct kmem_cache *mb2_entry_cache; +static unsigned long mb2_cache_shrink(struct mb2_cache *cache, + unsigned int nr_to_scan); + +/* + * Number of entries to reclaim synchronously when there are too many entries + * in cache + */ +#define SYNC_SHRINK_BATCH 64 + /* * mb2_cache_entry_create - create entry in cache * @cache - cache where the entry should be created @@ -55,6 +69,13 @@ int mb2_cache_entry_create(struct mb2_cache *cache, gfp_t mask, u32 key, struct hlist_bl_node *dup_node; struct hlist_bl_head *head; + /* Schedule background reclaim if there are too many entries */ + if (cache->c_entry_count >= cache->c_max_entries) + schedule_work(&cache->c_shrink_work); + /* Do some sync reclaim if background reclaim cannot keep up */ + if (cache->c_entry_count >= 2*cache->c_max_entries) + mb2_cache_shrink(cache, SYNC_SHRINK_BATCH); + entry = kmem_cache_alloc(mb2_entry_cache, mask); if (!entry) return -ENOMEM; @@ -223,12 +244,9 @@ static unsigned long mb2_cache_count(struct shrinker *shrink, } /* Shrink number of entries in cache */ -static unsigned long mb2_cache_scan(struct shrinker *shrink, - struct shrink_control *sc) +static unsigned long mb2_cache_shrink(struct mb2_cache *cache, + unsigned int nr_to_scan) { - int nr_to_scan = sc->nr_to_scan; - struct mb2_cache *cache = container_of(shrink, struct mb2_cache, - c_shrink); struct mb2_cache_entry *entry; struct hlist_bl_head *head; unsigned int shrunk = 0; @@ -261,6 +279,25 @@ static unsigned long mb2_cache_scan(struct shrinker *shrink, return shrunk; } +static unsigned long mb2_cache_scan(struct shrinker *shrink, + struct shrink_control *sc) +{ + int nr_to_scan = sc->nr_to_scan; + struct mb2_cache *cache = container_of(shrink, struct mb2_cache, + c_shrink); + return mb2_cache_shrink(cache, nr_to_scan); +} + +/* We shrink 1/X of the cache when we have too many entries in it */ +#define SHRINK_DIVISOR 16 + +static void mb2_cache_shrink_worker(struct work_struct *work) +{ + struct mb2_cache *cache = container_of(work, struct mb2_cache, + c_shrink_work); + mb2_cache_shrink(cache, cache->c_max_entries / SHRINK_DIVISOR); +} + /* * mb2_cache_create - create cache * @bucket_bits: log2 of the hash table size @@ -280,6 +317,7 @@ struct mb2_cache *mb2_cache_create(int bucket_bits) if (!cache) goto err_out; cache->c_bucket_bits = bucket_bits; + cache->c_max_entries = bucket_count << 4; INIT_LIST_HEAD(&cache->c_lru_list); spin_lock_init(&cache->c_lru_list_lock); cache->c_hash = kmalloc(bucket_count * sizeof(struct hlist_bl_head), @@ -296,6 +334,8 @@ struct mb2_cache *mb2_cache_create(int bucket_bits) cache->c_shrink.seeks = DEFAULT_SEEKS; register_shrinker(&cache->c_shrink); + INIT_WORK(&cache->c_shrink_work, mb2_cache_shrink_worker); + return cache; err_out: |