Blame view

fs/mbcache.c 12 KB
09c434b8a   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
f9a61eb4e   Jan Kara   mbcache2: reimple...
2
3
4
5
6
7
  #include <linux/spinlock.h>
  #include <linux/slab.h>
  #include <linux/list.h>
  #include <linux/list_bl.h>
  #include <linux/module.h>
  #include <linux/sched.h>
c2f3140fe   Jan Kara   mbcache2: limit c...
8
  #include <linux/workqueue.h>
7a2508e1b   Jan Kara   mbcache2: rename ...
9
  #include <linux/mbcache.h>
f9a61eb4e   Jan Kara   mbcache2: reimple...
10
11
12
13
  
  /*
   * Mbcache is a simple key-value store. Keys need not be unique, however
   * key-value pairs are expected to be unique (we use this fact in
c07dfcb45   Tahsin Erdogan   mbcache: make mbc...
14
   * mb_cache_entry_delete()).
f9a61eb4e   Jan Kara   mbcache2: reimple...
15
16
   *
   * Ext2 and ext4 use this cache for deduplication of extended attribute blocks.
dec214d00   Tahsin Erdogan   ext4: xattr inode...
17
18
19
20
21
   * Ext4 also uses it for deduplication of xattr values stored in inodes.
   * They use hash of data as a key and provide a value that may represent a
   * block or inode number. That's why keys need not be unique (hash of different
   * data may be the same). However user provided value always uniquely
   * identifies a cache entry.
f9a61eb4e   Jan Kara   mbcache2: reimple...
22
23
24
25
26
   *
   * We provide functions for creation and removal of entries, search by key,
   * and a special "delete entry with given key-value pair" operation. Fixed
   * size hash table is used for fast key lookups.
   */
7a2508e1b   Jan Kara   mbcache2: rename ...
27
  struct mb_cache {
f9a61eb4e   Jan Kara   mbcache2: reimple...
28
29
30
31
  	/* Hash table of entries */
  	struct hlist_bl_head	*c_hash;
  	/* log2 of hash table size */
  	int			c_bucket_bits;
c2f3140fe   Jan Kara   mbcache2: limit c...
32
  	/* Maximum entries in cache to avoid degrading hash too much */
132d4e2d5   Eric Biggers   mbcache: use cons...
33
  	unsigned long		c_max_entries;
f0c8b4623   Jan Kara   mbcache2: Use ref...
34
35
36
  	/* Protects c_list, c_entry_count */
  	spinlock_t		c_list_lock;
  	struct list_head	c_list;
f9a61eb4e   Jan Kara   mbcache2: reimple...
37
38
39
  	/* Number of entries in cache */
  	unsigned long		c_entry_count;
  	struct shrinker		c_shrink;
c2f3140fe   Jan Kara   mbcache2: limit c...
40
41
  	/* Work for shrinking when the cache has too many entries */
  	struct work_struct	c_shrink_work;
f9a61eb4e   Jan Kara   mbcache2: reimple...
42
  };
7a2508e1b   Jan Kara   mbcache2: rename ...
43
  static struct kmem_cache *mb_entry_cache;
f9a61eb4e   Jan Kara   mbcache2: reimple...
44

7a2508e1b   Jan Kara   mbcache2: rename ...
45
  static unsigned long mb_cache_shrink(struct mb_cache *cache,
132d4e2d5   Eric Biggers   mbcache: use cons...
46
  				     unsigned long nr_to_scan);
c2f3140fe   Jan Kara   mbcache2: limit c...
47

dc8d5e565   Andreas Gruenbacher   mbcache: get rid ...
48
49
  static inline struct hlist_bl_head *mb_cache_entry_head(struct mb_cache *cache,
  							u32 key)
f0c8b4623   Jan Kara   mbcache2: Use ref...
50
  {
dc8d5e565   Andreas Gruenbacher   mbcache: get rid ...
51
  	return &cache->c_hash[hash_32(key, cache->c_bucket_bits)];
f0c8b4623   Jan Kara   mbcache2: Use ref...
52
  }
c2f3140fe   Jan Kara   mbcache2: limit c...
53
54
55
56
57
  /*
   * Number of entries to reclaim synchronously when there are too many entries
   * in cache
   */
  #define SYNC_SHRINK_BATCH 64
f9a61eb4e   Jan Kara   mbcache2: reimple...
58
  /*
7a2508e1b   Jan Kara   mbcache2: rename ...
59
   * mb_cache_entry_create - create entry in cache
f9a61eb4e   Jan Kara   mbcache2: reimple...
60
61
62
   * @cache - cache where the entry should be created
   * @mask - gfp mask with which the entry should be allocated
   * @key - key of the entry
c07dfcb45   Tahsin Erdogan   mbcache: make mbc...
63
64
   * @value - value of the entry
   * @reusable - is the entry reusable by others?
f9a61eb4e   Jan Kara   mbcache2: reimple...
65
   *
c07dfcb45   Tahsin Erdogan   mbcache: make mbc...
66
67
68
   * Creates entry in @cache with key @key and value @value. The function returns
   * -EBUSY if entry with the same key and value already exists in cache.
   * Otherwise 0 is returned.
f9a61eb4e   Jan Kara   mbcache2: reimple...
69
   */
7a2508e1b   Jan Kara   mbcache2: rename ...
70
  int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key,
c07dfcb45   Tahsin Erdogan   mbcache: make mbc...
71
  			  u64 value, bool reusable)
f9a61eb4e   Jan Kara   mbcache2: reimple...
72
  {
7a2508e1b   Jan Kara   mbcache2: rename ...
73
  	struct mb_cache_entry *entry, *dup;
f9a61eb4e   Jan Kara   mbcache2: reimple...
74
75
  	struct hlist_bl_node *dup_node;
  	struct hlist_bl_head *head;
c2f3140fe   Jan Kara   mbcache2: limit c...
76
77
78
79
80
  	/* 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)
7a2508e1b   Jan Kara   mbcache2: rename ...
81
  		mb_cache_shrink(cache, SYNC_SHRINK_BATCH);
c2f3140fe   Jan Kara   mbcache2: limit c...
82

7a2508e1b   Jan Kara   mbcache2: rename ...
83
  	entry = kmem_cache_alloc(mb_entry_cache, mask);
f9a61eb4e   Jan Kara   mbcache2: reimple...
84
85
  	if (!entry)
  		return -ENOMEM;
f0c8b4623   Jan Kara   mbcache2: Use ref...
86
  	INIT_LIST_HEAD(&entry->e_list);
f9a61eb4e   Jan Kara   mbcache2: reimple...
87
88
89
  	/* One ref for hash, one ref returned */
  	atomic_set(&entry->e_refcnt, 1);
  	entry->e_key = key;
c07dfcb45   Tahsin Erdogan   mbcache: make mbc...
90
  	entry->e_value = value;
6048c64b2   Andreas Gruenbacher   mbcache: add reus...
91
  	entry->e_reusable = reusable;
3876bbe27   Alexander Potapenko   mbcache: initiali...
92
  	entry->e_referenced = 0;
dc8d5e565   Andreas Gruenbacher   mbcache: get rid ...
93
  	head = mb_cache_entry_head(cache, key);
f9a61eb4e   Jan Kara   mbcache2: reimple...
94
95
  	hlist_bl_lock(head);
  	hlist_bl_for_each_entry(dup, dup_node, head, e_hash_list) {
c07dfcb45   Tahsin Erdogan   mbcache: make mbc...
96
  		if (dup->e_key == key && dup->e_value == value) {
f9a61eb4e   Jan Kara   mbcache2: reimple...
97
  			hlist_bl_unlock(head);
7a2508e1b   Jan Kara   mbcache2: rename ...
98
  			kmem_cache_free(mb_entry_cache, entry);
f9a61eb4e   Jan Kara   mbcache2: reimple...
99
100
101
102
103
  			return -EBUSY;
  		}
  	}
  	hlist_bl_add_head(&entry->e_hash_list, head);
  	hlist_bl_unlock(head);
f0c8b4623   Jan Kara   mbcache2: Use ref...
104
105
  	spin_lock(&cache->c_list_lock);
  	list_add_tail(&entry->e_list, &cache->c_list);
f9a61eb4e   Jan Kara   mbcache2: reimple...
106
107
108
  	/* Grab ref for LRU list */
  	atomic_inc(&entry->e_refcnt);
  	cache->c_entry_count++;
f0c8b4623   Jan Kara   mbcache2: Use ref...
109
  	spin_unlock(&cache->c_list_lock);
f9a61eb4e   Jan Kara   mbcache2: reimple...
110
111
112
  
  	return 0;
  }
7a2508e1b   Jan Kara   mbcache2: rename ...
113
  EXPORT_SYMBOL(mb_cache_entry_create);
f9a61eb4e   Jan Kara   mbcache2: reimple...
114

7a2508e1b   Jan Kara   mbcache2: rename ...
115
  void __mb_cache_entry_free(struct mb_cache_entry *entry)
f9a61eb4e   Jan Kara   mbcache2: reimple...
116
  {
7a2508e1b   Jan Kara   mbcache2: rename ...
117
  	kmem_cache_free(mb_entry_cache, entry);
f9a61eb4e   Jan Kara   mbcache2: reimple...
118
  }
7a2508e1b   Jan Kara   mbcache2: rename ...
119
  EXPORT_SYMBOL(__mb_cache_entry_free);
f9a61eb4e   Jan Kara   mbcache2: reimple...
120

7a2508e1b   Jan Kara   mbcache2: rename ...
121
122
123
  static struct mb_cache_entry *__entry_find(struct mb_cache *cache,
  					   struct mb_cache_entry *entry,
  					   u32 key)
f9a61eb4e   Jan Kara   mbcache2: reimple...
124
  {
7a2508e1b   Jan Kara   mbcache2: rename ...
125
  	struct mb_cache_entry *old_entry = entry;
f9a61eb4e   Jan Kara   mbcache2: reimple...
126
127
  	struct hlist_bl_node *node;
  	struct hlist_bl_head *head;
dc8d5e565   Andreas Gruenbacher   mbcache: get rid ...
128
  	head = mb_cache_entry_head(cache, key);
f9a61eb4e   Jan Kara   mbcache2: reimple...
129
130
131
132
133
134
  	hlist_bl_lock(head);
  	if (entry && !hlist_bl_unhashed(&entry->e_hash_list))
  		node = entry->e_hash_list.next;
  	else
  		node = hlist_bl_first(head);
  	while (node) {
7a2508e1b   Jan Kara   mbcache2: rename ...
135
  		entry = hlist_bl_entry(node, struct mb_cache_entry,
f9a61eb4e   Jan Kara   mbcache2: reimple...
136
  				       e_hash_list);
6048c64b2   Andreas Gruenbacher   mbcache: add reus...
137
  		if (entry->e_key == key && entry->e_reusable) {
f9a61eb4e   Jan Kara   mbcache2: reimple...
138
139
140
141
142
143
144
145
146
  			atomic_inc(&entry->e_refcnt);
  			goto out;
  		}
  		node = node->next;
  	}
  	entry = NULL;
  out:
  	hlist_bl_unlock(head);
  	if (old_entry)
7a2508e1b   Jan Kara   mbcache2: rename ...
147
  		mb_cache_entry_put(cache, old_entry);
f9a61eb4e   Jan Kara   mbcache2: reimple...
148
149
150
151
152
  
  	return entry;
  }
  
  /*
b649668c0   Eric Biggers   mbcache: document...
153
   * mb_cache_entry_find_first - find the first reusable entry with the given key
f9a61eb4e   Jan Kara   mbcache2: reimple...
154
155
156
   * @cache: cache where we should search
   * @key: key to look for
   *
b649668c0   Eric Biggers   mbcache: document...
157
158
   * Search in @cache for a reusable entry with key @key. Grabs reference to the
   * first reusable entry found and returns the entry.
f9a61eb4e   Jan Kara   mbcache2: reimple...
159
   */
7a2508e1b   Jan Kara   mbcache2: rename ...
160
161
  struct mb_cache_entry *mb_cache_entry_find_first(struct mb_cache *cache,
  						 u32 key)
f9a61eb4e   Jan Kara   mbcache2: reimple...
162
163
164
  {
  	return __entry_find(cache, NULL, key);
  }
7a2508e1b   Jan Kara   mbcache2: rename ...
165
  EXPORT_SYMBOL(mb_cache_entry_find_first);
f9a61eb4e   Jan Kara   mbcache2: reimple...
166
167
  
  /*
b649668c0   Eric Biggers   mbcache: document...
168
   * mb_cache_entry_find_next - find next reusable entry with the same key
f9a61eb4e   Jan Kara   mbcache2: reimple...
169
170
171
   * @cache: cache where we should search
   * @entry: entry to start search from
   *
b649668c0   Eric Biggers   mbcache: document...
172
173
174
175
   * Finds next reusable entry in the hash chain which has the same key as @entry.
   * If @entry is unhashed (which can happen when deletion of entry races with the
   * search), finds the first reusable entry in the hash chain. The function drops
   * reference to @entry and returns with a reference to the found entry.
f9a61eb4e   Jan Kara   mbcache2: reimple...
176
   */
7a2508e1b   Jan Kara   mbcache2: rename ...
177
178
  struct mb_cache_entry *mb_cache_entry_find_next(struct mb_cache *cache,
  						struct mb_cache_entry *entry)
f9a61eb4e   Jan Kara   mbcache2: reimple...
179
180
181
  {
  	return __entry_find(cache, entry, entry->e_key);
  }
7a2508e1b   Jan Kara   mbcache2: rename ...
182
  EXPORT_SYMBOL(mb_cache_entry_find_next);
f9a61eb4e   Jan Kara   mbcache2: reimple...
183

6048c64b2   Andreas Gruenbacher   mbcache: add reus...
184
  /*
c07dfcb45   Tahsin Erdogan   mbcache: make mbc...
185
   * mb_cache_entry_get - get a cache entry by value (and key)
6048c64b2   Andreas Gruenbacher   mbcache: add reus...
186
   * @cache - cache we work with
c07dfcb45   Tahsin Erdogan   mbcache: make mbc...
187
188
   * @key - key
   * @value - value
6048c64b2   Andreas Gruenbacher   mbcache: add reus...
189
190
   */
  struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *cache, u32 key,
c07dfcb45   Tahsin Erdogan   mbcache: make mbc...
191
  					  u64 value)
6048c64b2   Andreas Gruenbacher   mbcache: add reus...
192
193
194
195
196
197
198
199
  {
  	struct hlist_bl_node *node;
  	struct hlist_bl_head *head;
  	struct mb_cache_entry *entry;
  
  	head = mb_cache_entry_head(cache, key);
  	hlist_bl_lock(head);
  	hlist_bl_for_each_entry(entry, node, head, e_hash_list) {
c07dfcb45   Tahsin Erdogan   mbcache: make mbc...
200
  		if (entry->e_key == key && entry->e_value == value) {
6048c64b2   Andreas Gruenbacher   mbcache: add reus...
201
202
203
204
205
206
207
208
209
210
  			atomic_inc(&entry->e_refcnt);
  			goto out;
  		}
  	}
  	entry = NULL;
  out:
  	hlist_bl_unlock(head);
  	return entry;
  }
  EXPORT_SYMBOL(mb_cache_entry_get);
c07dfcb45   Tahsin Erdogan   mbcache: make mbc...
211
  /* mb_cache_entry_delete - remove a cache entry
f9a61eb4e   Jan Kara   mbcache2: reimple...
212
   * @cache - cache we work with
c07dfcb45   Tahsin Erdogan   mbcache: make mbc...
213
214
   * @key - key
   * @value - value
f9a61eb4e   Jan Kara   mbcache2: reimple...
215
   *
c07dfcb45   Tahsin Erdogan   mbcache: make mbc...
216
   * Remove entry from cache @cache with key @key and value @value.
f9a61eb4e   Jan Kara   mbcache2: reimple...
217
   */
c07dfcb45   Tahsin Erdogan   mbcache: make mbc...
218
  void mb_cache_entry_delete(struct mb_cache *cache, u32 key, u64 value)
f9a61eb4e   Jan Kara   mbcache2: reimple...
219
220
221
  {
  	struct hlist_bl_node *node;
  	struct hlist_bl_head *head;
7a2508e1b   Jan Kara   mbcache2: rename ...
222
  	struct mb_cache_entry *entry;
f9a61eb4e   Jan Kara   mbcache2: reimple...
223

dc8d5e565   Andreas Gruenbacher   mbcache: get rid ...
224
  	head = mb_cache_entry_head(cache, key);
f9a61eb4e   Jan Kara   mbcache2: reimple...
225
226
  	hlist_bl_lock(head);
  	hlist_bl_for_each_entry(entry, node, head, e_hash_list) {
c07dfcb45   Tahsin Erdogan   mbcache: make mbc...
227
  		if (entry->e_key == key && entry->e_value == value) {
f9a61eb4e   Jan Kara   mbcache2: reimple...
228
229
230
  			/* We keep hash list reference to keep entry alive */
  			hlist_bl_del_init(&entry->e_hash_list);
  			hlist_bl_unlock(head);
f0c8b4623   Jan Kara   mbcache2: Use ref...
231
232
233
  			spin_lock(&cache->c_list_lock);
  			if (!list_empty(&entry->e_list)) {
  				list_del_init(&entry->e_list);
9ee93ba3c   Jiang Biao   mbcache: make sur...
234
235
236
  				if (!WARN_ONCE(cache->c_entry_count == 0,
  		"mbcache: attempt to decrement c_entry_count past zero"))
  					cache->c_entry_count--;
f9a61eb4e   Jan Kara   mbcache2: reimple...
237
238
  				atomic_dec(&entry->e_refcnt);
  			}
f0c8b4623   Jan Kara   mbcache2: Use ref...
239
  			spin_unlock(&cache->c_list_lock);
7a2508e1b   Jan Kara   mbcache2: rename ...
240
  			mb_cache_entry_put(cache, entry);
f9a61eb4e   Jan Kara   mbcache2: reimple...
241
242
243
244
245
  			return;
  		}
  	}
  	hlist_bl_unlock(head);
  }
c07dfcb45   Tahsin Erdogan   mbcache: make mbc...
246
  EXPORT_SYMBOL(mb_cache_entry_delete);
f9a61eb4e   Jan Kara   mbcache2: reimple...
247

7a2508e1b   Jan Kara   mbcache2: rename ...
248
  /* mb_cache_entry_touch - cache entry got used
f9a61eb4e   Jan Kara   mbcache2: reimple...
249
250
251
   * @cache - cache the entry belongs to
   * @entry - entry that got used
   *
f0c8b4623   Jan Kara   mbcache2: Use ref...
252
   * Marks entry as used to give hit higher chances of surviving in cache.
f9a61eb4e   Jan Kara   mbcache2: reimple...
253
   */
7a2508e1b   Jan Kara   mbcache2: rename ...
254
255
  void mb_cache_entry_touch(struct mb_cache *cache,
  			  struct mb_cache_entry *entry)
f9a61eb4e   Jan Kara   mbcache2: reimple...
256
  {
dc8d5e565   Andreas Gruenbacher   mbcache: get rid ...
257
  	entry->e_referenced = 1;
f9a61eb4e   Jan Kara   mbcache2: reimple...
258
  }
7a2508e1b   Jan Kara   mbcache2: rename ...
259
  EXPORT_SYMBOL(mb_cache_entry_touch);
f9a61eb4e   Jan Kara   mbcache2: reimple...
260

7a2508e1b   Jan Kara   mbcache2: rename ...
261
262
  static unsigned long mb_cache_count(struct shrinker *shrink,
  				    struct shrink_control *sc)
f9a61eb4e   Jan Kara   mbcache2: reimple...
263
  {
7a2508e1b   Jan Kara   mbcache2: rename ...
264
265
  	struct mb_cache *cache = container_of(shrink, struct mb_cache,
  					      c_shrink);
f9a61eb4e   Jan Kara   mbcache2: reimple...
266
267
268
269
270
  
  	return cache->c_entry_count;
  }
  
  /* Shrink number of entries in cache */
7a2508e1b   Jan Kara   mbcache2: rename ...
271
  static unsigned long mb_cache_shrink(struct mb_cache *cache,
132d4e2d5   Eric Biggers   mbcache: use cons...
272
  				     unsigned long nr_to_scan)
f9a61eb4e   Jan Kara   mbcache2: reimple...
273
  {
7a2508e1b   Jan Kara   mbcache2: rename ...
274
  	struct mb_cache_entry *entry;
f9a61eb4e   Jan Kara   mbcache2: reimple...
275
  	struct hlist_bl_head *head;
132d4e2d5   Eric Biggers   mbcache: use cons...
276
  	unsigned long shrunk = 0;
f9a61eb4e   Jan Kara   mbcache2: reimple...
277

f0c8b4623   Jan Kara   mbcache2: Use ref...
278
279
280
  	spin_lock(&cache->c_list_lock);
  	while (nr_to_scan-- && !list_empty(&cache->c_list)) {
  		entry = list_first_entry(&cache->c_list,
7a2508e1b   Jan Kara   mbcache2: rename ...
281
  					 struct mb_cache_entry, e_list);
dc8d5e565   Andreas Gruenbacher   mbcache: get rid ...
282
283
  		if (entry->e_referenced) {
  			entry->e_referenced = 0;
918b7306e   Eric Biggers   mbcache: correctl...
284
  			list_move_tail(&entry->e_list, &cache->c_list);
f0c8b4623   Jan Kara   mbcache2: Use ref...
285
286
287
  			continue;
  		}
  		list_del_init(&entry->e_list);
f9a61eb4e   Jan Kara   mbcache2: reimple...
288
289
290
291
292
  		cache->c_entry_count--;
  		/*
  		 * We keep LRU list reference so that entry doesn't go away
  		 * from under us.
  		 */
f0c8b4623   Jan Kara   mbcache2: Use ref...
293
  		spin_unlock(&cache->c_list_lock);
dc8d5e565   Andreas Gruenbacher   mbcache: get rid ...
294
  		head = mb_cache_entry_head(cache, entry->e_key);
f9a61eb4e   Jan Kara   mbcache2: reimple...
295
296
297
298
299
300
  		hlist_bl_lock(head);
  		if (!hlist_bl_unhashed(&entry->e_hash_list)) {
  			hlist_bl_del_init(&entry->e_hash_list);
  			atomic_dec(&entry->e_refcnt);
  		}
  		hlist_bl_unlock(head);
7a2508e1b   Jan Kara   mbcache2: rename ...
301
  		if (mb_cache_entry_put(cache, entry))
f9a61eb4e   Jan Kara   mbcache2: reimple...
302
303
  			shrunk++;
  		cond_resched();
f0c8b4623   Jan Kara   mbcache2: Use ref...
304
  		spin_lock(&cache->c_list_lock);
f9a61eb4e   Jan Kara   mbcache2: reimple...
305
  	}
f0c8b4623   Jan Kara   mbcache2: Use ref...
306
  	spin_unlock(&cache->c_list_lock);
f9a61eb4e   Jan Kara   mbcache2: reimple...
307
308
309
  
  	return shrunk;
  }
7a2508e1b   Jan Kara   mbcache2: rename ...
310
311
  static unsigned long mb_cache_scan(struct shrinker *shrink,
  				   struct shrink_control *sc)
c2f3140fe   Jan Kara   mbcache2: limit c...
312
  {
7a2508e1b   Jan Kara   mbcache2: rename ...
313
  	struct mb_cache *cache = container_of(shrink, struct mb_cache,
c2f3140fe   Jan Kara   mbcache2: limit c...
314
  					      c_shrink);
132d4e2d5   Eric Biggers   mbcache: use cons...
315
  	return mb_cache_shrink(cache, sc->nr_to_scan);
c2f3140fe   Jan Kara   mbcache2: limit c...
316
317
318
319
  }
  
  /* We shrink 1/X of the cache when we have too many entries in it */
  #define SHRINK_DIVISOR 16
7a2508e1b   Jan Kara   mbcache2: rename ...
320
  static void mb_cache_shrink_worker(struct work_struct *work)
c2f3140fe   Jan Kara   mbcache2: limit c...
321
  {
7a2508e1b   Jan Kara   mbcache2: rename ...
322
323
324
  	struct mb_cache *cache = container_of(work, struct mb_cache,
  					      c_shrink_work);
  	mb_cache_shrink(cache, cache->c_max_entries / SHRINK_DIVISOR);
c2f3140fe   Jan Kara   mbcache2: limit c...
325
  }
f9a61eb4e   Jan Kara   mbcache2: reimple...
326
  /*
7a2508e1b   Jan Kara   mbcache2: rename ...
327
   * mb_cache_create - create cache
f9a61eb4e   Jan Kara   mbcache2: reimple...
328
329
330
331
   * @bucket_bits: log2 of the hash table size
   *
   * Create cache for keys with 2^bucket_bits hash entries.
   */
7a2508e1b   Jan Kara   mbcache2: rename ...
332
  struct mb_cache *mb_cache_create(int bucket_bits)
f9a61eb4e   Jan Kara   mbcache2: reimple...
333
  {
7a2508e1b   Jan Kara   mbcache2: rename ...
334
  	struct mb_cache *cache;
132d4e2d5   Eric Biggers   mbcache: use cons...
335
336
  	unsigned long bucket_count = 1UL << bucket_bits;
  	unsigned long i;
f9a61eb4e   Jan Kara   mbcache2: reimple...
337

7a2508e1b   Jan Kara   mbcache2: rename ...
338
  	cache = kzalloc(sizeof(struct mb_cache), GFP_KERNEL);
f9a61eb4e   Jan Kara   mbcache2: reimple...
339
340
341
  	if (!cache)
  		goto err_out;
  	cache->c_bucket_bits = bucket_bits;
c2f3140fe   Jan Kara   mbcache2: limit c...
342
  	cache->c_max_entries = bucket_count << 4;
f0c8b4623   Jan Kara   mbcache2: Use ref...
343
344
  	INIT_LIST_HEAD(&cache->c_list);
  	spin_lock_init(&cache->c_list_lock);
6da2ec560   Kees Cook   treewide: kmalloc...
345
346
347
  	cache->c_hash = kmalloc_array(bucket_count,
  				      sizeof(struct hlist_bl_head),
  				      GFP_KERNEL);
f9a61eb4e   Jan Kara   mbcache2: reimple...
348
349
350
351
352
353
  	if (!cache->c_hash) {
  		kfree(cache);
  		goto err_out;
  	}
  	for (i = 0; i < bucket_count; i++)
  		INIT_HLIST_BL_HEAD(&cache->c_hash[i]);
7a2508e1b   Jan Kara   mbcache2: rename ...
354
355
  	cache->c_shrink.count_objects = mb_cache_count;
  	cache->c_shrink.scan_objects = mb_cache_scan;
f9a61eb4e   Jan Kara   mbcache2: reimple...
356
  	cache->c_shrink.seeks = DEFAULT_SEEKS;
8913f343c   Chao Yu   mbcache: fix to d...
357
358
359
360
361
  	if (register_shrinker(&cache->c_shrink)) {
  		kfree(cache->c_hash);
  		kfree(cache);
  		goto err_out;
  	}
f9a61eb4e   Jan Kara   mbcache2: reimple...
362

7a2508e1b   Jan Kara   mbcache2: rename ...
363
  	INIT_WORK(&cache->c_shrink_work, mb_cache_shrink_worker);
c2f3140fe   Jan Kara   mbcache2: limit c...
364

f9a61eb4e   Jan Kara   mbcache2: reimple...
365
366
367
  	return cache;
  
  err_out:
f9a61eb4e   Jan Kara   mbcache2: reimple...
368
369
  	return NULL;
  }
7a2508e1b   Jan Kara   mbcache2: rename ...
370
  EXPORT_SYMBOL(mb_cache_create);
f9a61eb4e   Jan Kara   mbcache2: reimple...
371
372
  
  /*
7a2508e1b   Jan Kara   mbcache2: rename ...
373
   * mb_cache_destroy - destroy cache
f9a61eb4e   Jan Kara   mbcache2: reimple...
374
375
376
377
378
   * @cache: the cache to destroy
   *
   * Free all entries in cache and cache itself. Caller must make sure nobody
   * (except shrinker) can reach @cache when calling this.
   */
7a2508e1b   Jan Kara   mbcache2: rename ...
379
  void mb_cache_destroy(struct mb_cache *cache)
f9a61eb4e   Jan Kara   mbcache2: reimple...
380
  {
7a2508e1b   Jan Kara   mbcache2: rename ...
381
  	struct mb_cache_entry *entry, *next;
f9a61eb4e   Jan Kara   mbcache2: reimple...
382
383
384
385
386
387
388
  
  	unregister_shrinker(&cache->c_shrink);
  
  	/*
  	 * We don't bother with any locking. Cache must not be used at this
  	 * point.
  	 */
f0c8b4623   Jan Kara   mbcache2: Use ref...
389
  	list_for_each_entry_safe(entry, next, &cache->c_list, e_list) {
f9a61eb4e   Jan Kara   mbcache2: reimple...
390
391
392
393
394
  		if (!hlist_bl_unhashed(&entry->e_hash_list)) {
  			hlist_bl_del_init(&entry->e_hash_list);
  			atomic_dec(&entry->e_refcnt);
  		} else
  			WARN_ON(1);
f0c8b4623   Jan Kara   mbcache2: Use ref...
395
  		list_del(&entry->e_list);
f9a61eb4e   Jan Kara   mbcache2: reimple...
396
  		WARN_ON(atomic_read(&entry->e_refcnt) != 1);
7a2508e1b   Jan Kara   mbcache2: rename ...
397
  		mb_cache_entry_put(cache, entry);
f9a61eb4e   Jan Kara   mbcache2: reimple...
398
399
400
  	}
  	kfree(cache->c_hash);
  	kfree(cache);
f9a61eb4e   Jan Kara   mbcache2: reimple...
401
  }
7a2508e1b   Jan Kara   mbcache2: rename ...
402
  EXPORT_SYMBOL(mb_cache_destroy);
f9a61eb4e   Jan Kara   mbcache2: reimple...
403

7a2508e1b   Jan Kara   mbcache2: rename ...
404
  static int __init mbcache_init(void)
f9a61eb4e   Jan Kara   mbcache2: reimple...
405
  {
7a2508e1b   Jan Kara   mbcache2: rename ...
406
407
  	mb_entry_cache = kmem_cache_create("mbcache",
  				sizeof(struct mb_cache_entry), 0,
f9a61eb4e   Jan Kara   mbcache2: reimple...
408
  				SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
21d0f4fa8   Eric Biggers   mbcache: don't BU...
409
410
  	if (!mb_entry_cache)
  		return -ENOMEM;
f9a61eb4e   Jan Kara   mbcache2: reimple...
411
412
  	return 0;
  }
7a2508e1b   Jan Kara   mbcache2: rename ...
413
  static void __exit mbcache_exit(void)
f9a61eb4e   Jan Kara   mbcache2: reimple...
414
  {
7a2508e1b   Jan Kara   mbcache2: rename ...
415
  	kmem_cache_destroy(mb_entry_cache);
f9a61eb4e   Jan Kara   mbcache2: reimple...
416
  }
7a2508e1b   Jan Kara   mbcache2: rename ...
417
418
  module_init(mbcache_init)
  module_exit(mbcache_exit)
f9a61eb4e   Jan Kara   mbcache2: reimple...
419
420
421
422
  
  MODULE_AUTHOR("Jan Kara <jack@suse.cz>");
  MODULE_DESCRIPTION("Meta block cache (for extended attributes)");
  MODULE_LICENSE("GPL");