162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#include <linux/spinlock.h> 362306a36Sopenharmony_ci#include <linux/slab.h> 462306a36Sopenharmony_ci#include <linux/list.h> 562306a36Sopenharmony_ci#include <linux/list_bl.h> 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <linux/sched.h> 862306a36Sopenharmony_ci#include <linux/workqueue.h> 962306a36Sopenharmony_ci#include <linux/mbcache.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* 1262306a36Sopenharmony_ci * Mbcache is a simple key-value store. Keys need not be unique, however 1362306a36Sopenharmony_ci * key-value pairs are expected to be unique (we use this fact in 1462306a36Sopenharmony_ci * mb_cache_entry_delete_or_get()). 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Ext2 and ext4 use this cache for deduplication of extended attribute blocks. 1762306a36Sopenharmony_ci * Ext4 also uses it for deduplication of xattr values stored in inodes. 1862306a36Sopenharmony_ci * They use hash of data as a key and provide a value that may represent a 1962306a36Sopenharmony_ci * block or inode number. That's why keys need not be unique (hash of different 2062306a36Sopenharmony_ci * data may be the same). However user provided value always uniquely 2162306a36Sopenharmony_ci * identifies a cache entry. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * We provide functions for creation and removal of entries, search by key, 2462306a36Sopenharmony_ci * and a special "delete entry with given key-value pair" operation. Fixed 2562306a36Sopenharmony_ci * size hash table is used for fast key lookups. 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct mb_cache { 2962306a36Sopenharmony_ci /* Hash table of entries */ 3062306a36Sopenharmony_ci struct hlist_bl_head *c_hash; 3162306a36Sopenharmony_ci /* log2 of hash table size */ 3262306a36Sopenharmony_ci int c_bucket_bits; 3362306a36Sopenharmony_ci /* Maximum entries in cache to avoid degrading hash too much */ 3462306a36Sopenharmony_ci unsigned long c_max_entries; 3562306a36Sopenharmony_ci /* Protects c_list, c_entry_count */ 3662306a36Sopenharmony_ci spinlock_t c_list_lock; 3762306a36Sopenharmony_ci struct list_head c_list; 3862306a36Sopenharmony_ci /* Number of entries in cache */ 3962306a36Sopenharmony_ci unsigned long c_entry_count; 4062306a36Sopenharmony_ci struct shrinker c_shrink; 4162306a36Sopenharmony_ci /* Work for shrinking when the cache has too many entries */ 4262306a36Sopenharmony_ci struct work_struct c_shrink_work; 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic struct kmem_cache *mb_entry_cache; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic unsigned long mb_cache_shrink(struct mb_cache *cache, 4862306a36Sopenharmony_ci unsigned long nr_to_scan); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic inline struct hlist_bl_head *mb_cache_entry_head(struct mb_cache *cache, 5162306a36Sopenharmony_ci u32 key) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci return &cache->c_hash[hash_32(key, cache->c_bucket_bits)]; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * Number of entries to reclaim synchronously when there are too many entries 5862306a36Sopenharmony_ci * in cache 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci#define SYNC_SHRINK_BATCH 64 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* 6362306a36Sopenharmony_ci * mb_cache_entry_create - create entry in cache 6462306a36Sopenharmony_ci * @cache - cache where the entry should be created 6562306a36Sopenharmony_ci * @mask - gfp mask with which the entry should be allocated 6662306a36Sopenharmony_ci * @key - key of the entry 6762306a36Sopenharmony_ci * @value - value of the entry 6862306a36Sopenharmony_ci * @reusable - is the entry reusable by others? 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * Creates entry in @cache with key @key and value @value. The function returns 7162306a36Sopenharmony_ci * -EBUSY if entry with the same key and value already exists in cache. 7262306a36Sopenharmony_ci * Otherwise 0 is returned. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ciint mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key, 7562306a36Sopenharmony_ci u64 value, bool reusable) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct mb_cache_entry *entry, *dup; 7862306a36Sopenharmony_ci struct hlist_bl_node *dup_node; 7962306a36Sopenharmony_ci struct hlist_bl_head *head; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* Schedule background reclaim if there are too many entries */ 8262306a36Sopenharmony_ci if (cache->c_entry_count >= cache->c_max_entries) 8362306a36Sopenharmony_ci schedule_work(&cache->c_shrink_work); 8462306a36Sopenharmony_ci /* Do some sync reclaim if background reclaim cannot keep up */ 8562306a36Sopenharmony_ci if (cache->c_entry_count >= 2*cache->c_max_entries) 8662306a36Sopenharmony_ci mb_cache_shrink(cache, SYNC_SHRINK_BATCH); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci entry = kmem_cache_alloc(mb_entry_cache, mask); 8962306a36Sopenharmony_ci if (!entry) 9062306a36Sopenharmony_ci return -ENOMEM; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci INIT_LIST_HEAD(&entry->e_list); 9362306a36Sopenharmony_ci /* 9462306a36Sopenharmony_ci * We create entry with two references. One reference is kept by the 9562306a36Sopenharmony_ci * hash table, the other reference is used to protect us from 9662306a36Sopenharmony_ci * mb_cache_entry_delete_or_get() until the entry is fully setup. This 9762306a36Sopenharmony_ci * avoids nesting of cache->c_list_lock into hash table bit locks which 9862306a36Sopenharmony_ci * is problematic for RT. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci atomic_set(&entry->e_refcnt, 2); 10162306a36Sopenharmony_ci entry->e_key = key; 10262306a36Sopenharmony_ci entry->e_value = value; 10362306a36Sopenharmony_ci entry->e_flags = 0; 10462306a36Sopenharmony_ci if (reusable) 10562306a36Sopenharmony_ci set_bit(MBE_REUSABLE_B, &entry->e_flags); 10662306a36Sopenharmony_ci head = mb_cache_entry_head(cache, key); 10762306a36Sopenharmony_ci hlist_bl_lock(head); 10862306a36Sopenharmony_ci hlist_bl_for_each_entry(dup, dup_node, head, e_hash_list) { 10962306a36Sopenharmony_ci if (dup->e_key == key && dup->e_value == value) { 11062306a36Sopenharmony_ci hlist_bl_unlock(head); 11162306a36Sopenharmony_ci kmem_cache_free(mb_entry_cache, entry); 11262306a36Sopenharmony_ci return -EBUSY; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci hlist_bl_add_head(&entry->e_hash_list, head); 11662306a36Sopenharmony_ci hlist_bl_unlock(head); 11762306a36Sopenharmony_ci spin_lock(&cache->c_list_lock); 11862306a36Sopenharmony_ci list_add_tail(&entry->e_list, &cache->c_list); 11962306a36Sopenharmony_ci cache->c_entry_count++; 12062306a36Sopenharmony_ci spin_unlock(&cache->c_list_lock); 12162306a36Sopenharmony_ci mb_cache_entry_put(cache, entry); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return 0; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ciEXPORT_SYMBOL(mb_cache_entry_create); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_civoid __mb_cache_entry_free(struct mb_cache *cache, struct mb_cache_entry *entry) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct hlist_bl_head *head; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci head = mb_cache_entry_head(cache, entry->e_key); 13262306a36Sopenharmony_ci hlist_bl_lock(head); 13362306a36Sopenharmony_ci hlist_bl_del(&entry->e_hash_list); 13462306a36Sopenharmony_ci hlist_bl_unlock(head); 13562306a36Sopenharmony_ci kmem_cache_free(mb_entry_cache, entry); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ciEXPORT_SYMBOL(__mb_cache_entry_free); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* 14062306a36Sopenharmony_ci * mb_cache_entry_wait_unused - wait to be the last user of the entry 14162306a36Sopenharmony_ci * 14262306a36Sopenharmony_ci * @entry - entry to work on 14362306a36Sopenharmony_ci * 14462306a36Sopenharmony_ci * Wait to be the last user of the entry. 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_civoid mb_cache_entry_wait_unused(struct mb_cache_entry *entry) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci wait_var_event(&entry->e_refcnt, atomic_read(&entry->e_refcnt) <= 2); 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ciEXPORT_SYMBOL(mb_cache_entry_wait_unused); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic struct mb_cache_entry *__entry_find(struct mb_cache *cache, 15362306a36Sopenharmony_ci struct mb_cache_entry *entry, 15462306a36Sopenharmony_ci u32 key) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct mb_cache_entry *old_entry = entry; 15762306a36Sopenharmony_ci struct hlist_bl_node *node; 15862306a36Sopenharmony_ci struct hlist_bl_head *head; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci head = mb_cache_entry_head(cache, key); 16162306a36Sopenharmony_ci hlist_bl_lock(head); 16262306a36Sopenharmony_ci if (entry && !hlist_bl_unhashed(&entry->e_hash_list)) 16362306a36Sopenharmony_ci node = entry->e_hash_list.next; 16462306a36Sopenharmony_ci else 16562306a36Sopenharmony_ci node = hlist_bl_first(head); 16662306a36Sopenharmony_ci while (node) { 16762306a36Sopenharmony_ci entry = hlist_bl_entry(node, struct mb_cache_entry, 16862306a36Sopenharmony_ci e_hash_list); 16962306a36Sopenharmony_ci if (entry->e_key == key && 17062306a36Sopenharmony_ci test_bit(MBE_REUSABLE_B, &entry->e_flags) && 17162306a36Sopenharmony_ci atomic_inc_not_zero(&entry->e_refcnt)) 17262306a36Sopenharmony_ci goto out; 17362306a36Sopenharmony_ci node = node->next; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci entry = NULL; 17662306a36Sopenharmony_ciout: 17762306a36Sopenharmony_ci hlist_bl_unlock(head); 17862306a36Sopenharmony_ci if (old_entry) 17962306a36Sopenharmony_ci mb_cache_entry_put(cache, old_entry); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return entry; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/* 18562306a36Sopenharmony_ci * mb_cache_entry_find_first - find the first reusable entry with the given key 18662306a36Sopenharmony_ci * @cache: cache where we should search 18762306a36Sopenharmony_ci * @key: key to look for 18862306a36Sopenharmony_ci * 18962306a36Sopenharmony_ci * Search in @cache for a reusable entry with key @key. Grabs reference to the 19062306a36Sopenharmony_ci * first reusable entry found and returns the entry. 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_cistruct mb_cache_entry *mb_cache_entry_find_first(struct mb_cache *cache, 19362306a36Sopenharmony_ci u32 key) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci return __entry_find(cache, NULL, key); 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ciEXPORT_SYMBOL(mb_cache_entry_find_first); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/* 20062306a36Sopenharmony_ci * mb_cache_entry_find_next - find next reusable entry with the same key 20162306a36Sopenharmony_ci * @cache: cache where we should search 20262306a36Sopenharmony_ci * @entry: entry to start search from 20362306a36Sopenharmony_ci * 20462306a36Sopenharmony_ci * Finds next reusable entry in the hash chain which has the same key as @entry. 20562306a36Sopenharmony_ci * If @entry is unhashed (which can happen when deletion of entry races with the 20662306a36Sopenharmony_ci * search), finds the first reusable entry in the hash chain. The function drops 20762306a36Sopenharmony_ci * reference to @entry and returns with a reference to the found entry. 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_cistruct mb_cache_entry *mb_cache_entry_find_next(struct mb_cache *cache, 21062306a36Sopenharmony_ci struct mb_cache_entry *entry) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci return __entry_find(cache, entry, entry->e_key); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ciEXPORT_SYMBOL(mb_cache_entry_find_next); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/* 21762306a36Sopenharmony_ci * mb_cache_entry_get - get a cache entry by value (and key) 21862306a36Sopenharmony_ci * @cache - cache we work with 21962306a36Sopenharmony_ci * @key - key 22062306a36Sopenharmony_ci * @value - value 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_cistruct mb_cache_entry *mb_cache_entry_get(struct mb_cache *cache, u32 key, 22362306a36Sopenharmony_ci u64 value) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct hlist_bl_node *node; 22662306a36Sopenharmony_ci struct hlist_bl_head *head; 22762306a36Sopenharmony_ci struct mb_cache_entry *entry; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci head = mb_cache_entry_head(cache, key); 23062306a36Sopenharmony_ci hlist_bl_lock(head); 23162306a36Sopenharmony_ci hlist_bl_for_each_entry(entry, node, head, e_hash_list) { 23262306a36Sopenharmony_ci if (entry->e_key == key && entry->e_value == value && 23362306a36Sopenharmony_ci atomic_inc_not_zero(&entry->e_refcnt)) 23462306a36Sopenharmony_ci goto out; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci entry = NULL; 23762306a36Sopenharmony_ciout: 23862306a36Sopenharmony_ci hlist_bl_unlock(head); 23962306a36Sopenharmony_ci return entry; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ciEXPORT_SYMBOL(mb_cache_entry_get); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/* mb_cache_entry_delete_or_get - remove a cache entry if it has no users 24462306a36Sopenharmony_ci * @cache - cache we work with 24562306a36Sopenharmony_ci * @key - key 24662306a36Sopenharmony_ci * @value - value 24762306a36Sopenharmony_ci * 24862306a36Sopenharmony_ci * Remove entry from cache @cache with key @key and value @value. The removal 24962306a36Sopenharmony_ci * happens only if the entry is unused. The function returns NULL in case the 25062306a36Sopenharmony_ci * entry was successfully removed or there's no entry in cache. Otherwise the 25162306a36Sopenharmony_ci * function grabs reference of the entry that we failed to delete because it 25262306a36Sopenharmony_ci * still has users and return it. 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_cistruct mb_cache_entry *mb_cache_entry_delete_or_get(struct mb_cache *cache, 25562306a36Sopenharmony_ci u32 key, u64 value) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct mb_cache_entry *entry; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci entry = mb_cache_entry_get(cache, key, value); 26062306a36Sopenharmony_ci if (!entry) 26162306a36Sopenharmony_ci return NULL; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* 26462306a36Sopenharmony_ci * Drop the ref we got from mb_cache_entry_get() and the initial hash 26562306a36Sopenharmony_ci * ref if we are the last user 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_ci if (atomic_cmpxchg(&entry->e_refcnt, 2, 0) != 2) 26862306a36Sopenharmony_ci return entry; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci spin_lock(&cache->c_list_lock); 27162306a36Sopenharmony_ci if (!list_empty(&entry->e_list)) 27262306a36Sopenharmony_ci list_del_init(&entry->e_list); 27362306a36Sopenharmony_ci cache->c_entry_count--; 27462306a36Sopenharmony_ci spin_unlock(&cache->c_list_lock); 27562306a36Sopenharmony_ci __mb_cache_entry_free(cache, entry); 27662306a36Sopenharmony_ci return NULL; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ciEXPORT_SYMBOL(mb_cache_entry_delete_or_get); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci/* mb_cache_entry_touch - cache entry got used 28162306a36Sopenharmony_ci * @cache - cache the entry belongs to 28262306a36Sopenharmony_ci * @entry - entry that got used 28362306a36Sopenharmony_ci * 28462306a36Sopenharmony_ci * Marks entry as used to give hit higher chances of surviving in cache. 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_civoid mb_cache_entry_touch(struct mb_cache *cache, 28762306a36Sopenharmony_ci struct mb_cache_entry *entry) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci set_bit(MBE_REFERENCED_B, &entry->e_flags); 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ciEXPORT_SYMBOL(mb_cache_entry_touch); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic unsigned long mb_cache_count(struct shrinker *shrink, 29462306a36Sopenharmony_ci struct shrink_control *sc) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci struct mb_cache *cache = container_of(shrink, struct mb_cache, 29762306a36Sopenharmony_ci c_shrink); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci return cache->c_entry_count; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci/* Shrink number of entries in cache */ 30362306a36Sopenharmony_cistatic unsigned long mb_cache_shrink(struct mb_cache *cache, 30462306a36Sopenharmony_ci unsigned long nr_to_scan) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci struct mb_cache_entry *entry; 30762306a36Sopenharmony_ci unsigned long shrunk = 0; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci spin_lock(&cache->c_list_lock); 31062306a36Sopenharmony_ci while (nr_to_scan-- && !list_empty(&cache->c_list)) { 31162306a36Sopenharmony_ci entry = list_first_entry(&cache->c_list, 31262306a36Sopenharmony_ci struct mb_cache_entry, e_list); 31362306a36Sopenharmony_ci /* Drop initial hash reference if there is no user */ 31462306a36Sopenharmony_ci if (test_bit(MBE_REFERENCED_B, &entry->e_flags) || 31562306a36Sopenharmony_ci atomic_cmpxchg(&entry->e_refcnt, 1, 0) != 1) { 31662306a36Sopenharmony_ci clear_bit(MBE_REFERENCED_B, &entry->e_flags); 31762306a36Sopenharmony_ci list_move_tail(&entry->e_list, &cache->c_list); 31862306a36Sopenharmony_ci continue; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci list_del_init(&entry->e_list); 32162306a36Sopenharmony_ci cache->c_entry_count--; 32262306a36Sopenharmony_ci spin_unlock(&cache->c_list_lock); 32362306a36Sopenharmony_ci __mb_cache_entry_free(cache, entry); 32462306a36Sopenharmony_ci shrunk++; 32562306a36Sopenharmony_ci cond_resched(); 32662306a36Sopenharmony_ci spin_lock(&cache->c_list_lock); 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci spin_unlock(&cache->c_list_lock); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci return shrunk; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic unsigned long mb_cache_scan(struct shrinker *shrink, 33462306a36Sopenharmony_ci struct shrink_control *sc) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci struct mb_cache *cache = container_of(shrink, struct mb_cache, 33762306a36Sopenharmony_ci c_shrink); 33862306a36Sopenharmony_ci return mb_cache_shrink(cache, sc->nr_to_scan); 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/* We shrink 1/X of the cache when we have too many entries in it */ 34262306a36Sopenharmony_ci#define SHRINK_DIVISOR 16 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic void mb_cache_shrink_worker(struct work_struct *work) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct mb_cache *cache = container_of(work, struct mb_cache, 34762306a36Sopenharmony_ci c_shrink_work); 34862306a36Sopenharmony_ci mb_cache_shrink(cache, cache->c_max_entries / SHRINK_DIVISOR); 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci/* 35262306a36Sopenharmony_ci * mb_cache_create - create cache 35362306a36Sopenharmony_ci * @bucket_bits: log2 of the hash table size 35462306a36Sopenharmony_ci * 35562306a36Sopenharmony_ci * Create cache for keys with 2^bucket_bits hash entries. 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_cistruct mb_cache *mb_cache_create(int bucket_bits) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct mb_cache *cache; 36062306a36Sopenharmony_ci unsigned long bucket_count = 1UL << bucket_bits; 36162306a36Sopenharmony_ci unsigned long i; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci cache = kzalloc(sizeof(struct mb_cache), GFP_KERNEL); 36462306a36Sopenharmony_ci if (!cache) 36562306a36Sopenharmony_ci goto err_out; 36662306a36Sopenharmony_ci cache->c_bucket_bits = bucket_bits; 36762306a36Sopenharmony_ci cache->c_max_entries = bucket_count << 4; 36862306a36Sopenharmony_ci INIT_LIST_HEAD(&cache->c_list); 36962306a36Sopenharmony_ci spin_lock_init(&cache->c_list_lock); 37062306a36Sopenharmony_ci cache->c_hash = kmalloc_array(bucket_count, 37162306a36Sopenharmony_ci sizeof(struct hlist_bl_head), 37262306a36Sopenharmony_ci GFP_KERNEL); 37362306a36Sopenharmony_ci if (!cache->c_hash) { 37462306a36Sopenharmony_ci kfree(cache); 37562306a36Sopenharmony_ci goto err_out; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci for (i = 0; i < bucket_count; i++) 37862306a36Sopenharmony_ci INIT_HLIST_BL_HEAD(&cache->c_hash[i]); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci cache->c_shrink.count_objects = mb_cache_count; 38162306a36Sopenharmony_ci cache->c_shrink.scan_objects = mb_cache_scan; 38262306a36Sopenharmony_ci cache->c_shrink.seeks = DEFAULT_SEEKS; 38362306a36Sopenharmony_ci if (register_shrinker(&cache->c_shrink, "mbcache-shrinker")) { 38462306a36Sopenharmony_ci kfree(cache->c_hash); 38562306a36Sopenharmony_ci kfree(cache); 38662306a36Sopenharmony_ci goto err_out; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci INIT_WORK(&cache->c_shrink_work, mb_cache_shrink_worker); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return cache; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cierr_out: 39462306a36Sopenharmony_ci return NULL; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ciEXPORT_SYMBOL(mb_cache_create); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci/* 39962306a36Sopenharmony_ci * mb_cache_destroy - destroy cache 40062306a36Sopenharmony_ci * @cache: the cache to destroy 40162306a36Sopenharmony_ci * 40262306a36Sopenharmony_ci * Free all entries in cache and cache itself. Caller must make sure nobody 40362306a36Sopenharmony_ci * (except shrinker) can reach @cache when calling this. 40462306a36Sopenharmony_ci */ 40562306a36Sopenharmony_civoid mb_cache_destroy(struct mb_cache *cache) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct mb_cache_entry *entry, *next; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci unregister_shrinker(&cache->c_shrink); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci /* 41262306a36Sopenharmony_ci * We don't bother with any locking. Cache must not be used at this 41362306a36Sopenharmony_ci * point. 41462306a36Sopenharmony_ci */ 41562306a36Sopenharmony_ci list_for_each_entry_safe(entry, next, &cache->c_list, e_list) { 41662306a36Sopenharmony_ci list_del(&entry->e_list); 41762306a36Sopenharmony_ci WARN_ON(atomic_read(&entry->e_refcnt) != 1); 41862306a36Sopenharmony_ci mb_cache_entry_put(cache, entry); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci kfree(cache->c_hash); 42162306a36Sopenharmony_ci kfree(cache); 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ciEXPORT_SYMBOL(mb_cache_destroy); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic int __init mbcache_init(void) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci mb_entry_cache = kmem_cache_create("mbcache", 42862306a36Sopenharmony_ci sizeof(struct mb_cache_entry), 0, 42962306a36Sopenharmony_ci SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL); 43062306a36Sopenharmony_ci if (!mb_entry_cache) 43162306a36Sopenharmony_ci return -ENOMEM; 43262306a36Sopenharmony_ci return 0; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic void __exit mbcache_exit(void) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci kmem_cache_destroy(mb_entry_cache); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cimodule_init(mbcache_init) 44162306a36Sopenharmony_cimodule_exit(mbcache_exit) 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ciMODULE_AUTHOR("Jan Kara <jack@suse.cz>"); 44462306a36Sopenharmony_ciMODULE_DESCRIPTION("Meta block cache (for extended attributes)"); 44562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 446