1 ext4: each filesystem creates and uses its own mb_cache
3 From: T Makphaibulchoke <tmac@hp.com>
5 This patch adds new interfaces to create and destory cache,
6 ext4_xattr_create_cache() and ext4_xattr_destroy_cache(), and remove
7 the cache creation and destory calls from ex4_init_xattr() and
8 ext4_exitxattr() in fs/ext4/xattr.c. fs/ext4/super.c has been changed
9 so that when a filesystem is mounted a cache is allocated and attched
10 to its ext4_sb_info structure.
12 Signed-off-by: T. Makphaibulchoke <tmac@hp.com>
13 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
16 fs/ext4/super.c | 37 ++++++++++++++++++++++++++++---------
17 fs/ext4/xattr.c | 54 +++++++++++++++++++++++++++++++-----------------------
18 fs/ext4/xattr.h | 8 +++++---
19 fs/mbcache.c | 50 +++++++++++++++++++++++++++++++++++++-------------
20 include/linux/mbcache.h | 3 +++
21 6 files changed, 105 insertions(+), 48 deletions(-)
23 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
24 index 65485ab..c3d1993 100644
27 @@ -1314,6 +1314,7 @@ struct ext4_sb_info {
28 struct list_head s_es_lru;
29 unsigned long s_es_last_sorted;
30 struct percpu_counter s_extent_cache_cnt;
31 + struct mb_cache *s_mb_cache;
32 spinlock_t s_es_lru_lock ____cacheline_aligned_in_smp;
34 /* Ratelimit ext4 messages. */
35 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
36 index d3a857b..d529807 100644
40 #include <linux/vfs.h>
41 #include <linux/random.h>
42 #include <linux/mount.h>
43 +#include <linux/mbcache.h>
44 #include <linux/namei.h>
45 #include <linux/quotaops.h>
46 #include <linux/seq_file.h>
47 @@ -59,6 +60,7 @@ static struct kset *ext4_kset;
48 static struct ext4_lazy_init *ext4_li_info;
49 static struct mutex ext4_li_mtx;
50 static struct ext4_features *ext4_feat;
51 +static int ext4_mballoc_ready;
53 static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
54 unsigned long journal_devnum);
55 @@ -845,6 +847,10 @@ static void ext4_put_super(struct super_block *sb)
56 invalidate_bdev(sbi->journal_bdev);
57 ext4_blkdev_remove(sbi);
59 + if (sbi->s_mb_cache) {
60 + ext4_xattr_destroy_cache(sbi->s_mb_cache);
61 + sbi->s_mb_cache = NULL;
64 kthread_stop(sbi->s_mmp_tsk);
66 @@ -3984,6 +3990,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
67 set_task_ioprio(sbi->s_journal->j_task, journal_ioprio);
69 sbi->s_journal->j_commit_callback = ext4_journal_commit_callback;
70 + if (ext4_mballoc_ready) {
71 + sbi->s_mb_cache = ext4_xattr_create_cache(sb->s_id);
72 + if (!sbi->s_mb_cache) {
73 + ext4_msg(sb, KERN_ERR, "Failed to create an mb_cache");
74 + goto failed_mount_wq;
79 * The journal may have updated the bg summary counts, so we
80 @@ -5480,9 +5493,16 @@ static int __init ext4_init_fs(void)
81 init_waitqueue_head(&ext4__ioend_wq[i]);
84 + ext4_xattr_kmem_cache = kmem_cache_create("ext4_xattr",
85 + sizeof(struct mb_cache_entry), 0,
86 + SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
87 + if (ext4_xattr_kmem_cache == NULL)
96 err = ext4_init_pageio();
98 @@ -5504,11 +5524,9 @@ static int __init ext4_init_fs(void)
100 err = ext4_init_mballoc();
104 - err = ext4_init_xattr();
108 + ext4_mballoc_ready = 1;
109 err = init_inodecache();
112 @@ -5524,10 +5542,9 @@ out:
113 unregister_as_ext3();
114 destroy_inodecache();
118 + ext4_mballoc_ready = 0;
122 ext4_exit_feat_adverts();
125 @@ -5539,18 +5556,20 @@ out6:
130 + kmem_cache_destroy(ext4_xattr_kmem_cache);
135 static void __exit ext4_exit_fs(void)
137 + kmem_cache_destroy(ext4_xattr_kmem_cache);
138 ext4_destroy_lazyinit_thread();
139 unregister_as_ext2();
140 unregister_as_ext3();
141 unregister_filesystem(&ext4_fs_type);
142 destroy_inodecache();
145 ext4_exit_feat_adverts();
146 remove_proc_entry("fs/ext4", NULL);
147 diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
148 index 03e9beb..3d2bd5a 100644
149 --- a/fs/ext4/xattr.c
150 +++ b/fs/ext4/xattr.c
152 # define ea_bdebug(bh, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
155 -static void ext4_xattr_cache_insert(struct buffer_head *);
156 +struct kmem_cache *ext4_xattr_kmem_cache;
158 +static void ext4_xattr_cache_insert(struct mb_cache *, struct buffer_head *);
159 static struct buffer_head *ext4_xattr_cache_find(struct inode *,
160 struct ext4_xattr_header *,
161 struct mb_cache_entry **);
162 @@ -90,8 +92,6 @@ static void ext4_xattr_rehash(struct ext4_xattr_header *,
163 static int ext4_xattr_list(struct dentry *dentry, char *buffer,
166 -static struct mb_cache *ext4_xattr_cache;
168 static const struct xattr_handler *ext4_xattr_handler_map[] = {
169 [EXT4_XATTR_INDEX_USER] = &ext4_xattr_user_handler,
170 #ifdef CONFIG_EXT4_FS_POSIX_ACL
171 @@ -117,6 +117,9 @@ const struct xattr_handler *ext4_xattr_handlers[] = {
175 +#define EXT4_GET_MB_CACHE(inode) (((struct ext4_sb_info *) \
176 + inode->i_sb->s_fs_info)->s_mb_cache)
178 static __le32 ext4_xattr_block_csum(struct inode *inode,
180 struct ext4_xattr_header *hdr)
181 @@ -265,6 +268,7 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
182 struct ext4_xattr_entry *entry;
185 + struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
187 ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
188 name_index, name, buffer, (long)buffer_size);
189 @@ -286,7 +290,7 @@ bad_block:
193 - ext4_xattr_cache_insert(bh);
194 + ext4_xattr_cache_insert(ext4_mb_cache, bh);
196 error = ext4_xattr_find_entry(&entry, name_index, name, bh->b_size, 1);
198 @@ -409,6 +413,7 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
199 struct inode *inode = dentry->d_inode;
200 struct buffer_head *bh = NULL;
202 + struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
204 ea_idebug(inode, "buffer=%p, buffer_size=%ld",
205 buffer, (long)buffer_size);
206 @@ -430,7 +435,7 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
210 - ext4_xattr_cache_insert(bh);
211 + ext4_xattr_cache_insert(ext4_mb_cache, bh);
212 error = ext4_xattr_list_entries(dentry, BFIRST(bh), buffer, buffer_size);
215 @@ -526,8 +531,9 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
217 struct mb_cache_entry *ce = NULL;
219 + struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
221 - ce = mb_cache_entry_get(ext4_xattr_cache, bh->b_bdev, bh->b_blocknr);
222 + ce = mb_cache_entry_get(ext4_mb_cache, bh->b_bdev, bh->b_blocknr);
223 error = ext4_journal_get_write_access(handle, bh);
226 @@ -745,13 +751,14 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
227 struct ext4_xattr_search *s = &bs->s;
228 struct mb_cache_entry *ce = NULL;
230 + struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
232 #define header(x) ((struct ext4_xattr_header *)(x))
234 if (i->value && i->value_len > sb->s_blocksize)
237 - ce = mb_cache_entry_get(ext4_xattr_cache, bs->bh->b_bdev,
238 + ce = mb_cache_entry_get(ext4_mb_cache, bs->bh->b_bdev,
240 error = ext4_journal_get_write_access(handle, bs->bh);
242 @@ -769,7 +776,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
243 if (!IS_LAST_ENTRY(s->first))
244 ext4_xattr_rehash(header(s->base),
246 - ext4_xattr_cache_insert(bs->bh);
247 + ext4_xattr_cache_insert(ext4_mb_cache,
250 unlock_buffer(bs->bh);
252 @@ -905,7 +913,7 @@ getblk_failed:
253 memcpy(new_bh->b_data, s->base, new_bh->b_size);
254 set_buffer_uptodate(new_bh);
255 unlock_buffer(new_bh);
256 - ext4_xattr_cache_insert(new_bh);
257 + ext4_xattr_cache_insert(ext4_mb_cache, new_bh);
258 error = ext4_handle_dirty_xattr_block(handle,
261 @@ -1494,13 +1502,13 @@ ext4_xattr_put_super(struct super_block *sb)
262 * Returns 0, or a negative error number on failure.
265 -ext4_xattr_cache_insert(struct buffer_head *bh)
266 +ext4_xattr_cache_insert(struct mb_cache *ext4_mb_cache, struct buffer_head *bh)
268 __u32 hash = le32_to_cpu(BHDR(bh)->h_hash);
269 struct mb_cache_entry *ce;
272 - ce = mb_cache_entry_alloc(ext4_xattr_cache, GFP_NOFS);
273 + ce = mb_cache_entry_alloc(ext4_mb_cache, GFP_NOFS);
275 ea_bdebug(bh, "out of memory");
277 @@ -1572,12 +1580,13 @@ ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header,
279 __u32 hash = le32_to_cpu(header->h_hash);
280 struct mb_cache_entry *ce;
281 + struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
284 return NULL; /* never share */
285 ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
287 - ce = mb_cache_entry_find_first(ext4_xattr_cache, inode->i_sb->s_bdev,
288 + ce = mb_cache_entry_find_first(ext4_mb_cache, inode->i_sb->s_bdev,
291 struct buffer_head *bh;
292 @@ -1675,19 +1684,18 @@ static void ext4_xattr_rehash(struct ext4_xattr_header *header,
294 #undef BLOCK_HASH_SHIFT
297 -ext4_init_xattr(void)
298 +#define HASH_BUCKET_BITS 6
301 +ext4_xattr_create_cache(char *name)
303 - ext4_xattr_cache = mb_cache_create("ext4_xattr", 6);
304 - if (!ext4_xattr_cache)
307 + return mb_cache_create_instance(name, HASH_BUCKET_BITS,
308 + ext4_xattr_kmem_cache);
312 -ext4_exit_xattr(void)
313 +void ext4_xattr_destroy_cache(struct mb_cache *cache)
315 - if (ext4_xattr_cache)
316 - mb_cache_destroy(ext4_xattr_cache);
317 - ext4_xattr_cache = NULL;
319 + mb_cache_destroy(cache);
322 diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
323 index c767dbd..15616eb 100644
324 --- a/fs/ext4/xattr.h
325 +++ b/fs/ext4/xattr.h
326 @@ -94,6 +94,8 @@ struct ext4_xattr_ibody_find {
327 struct ext4_iloc iloc;
330 +extern struct kmem_cache *ext4_xattr_kmem_cache;
332 extern const struct xattr_handler ext4_xattr_user_handler;
333 extern const struct xattr_handler ext4_xattr_trusted_handler;
334 extern const struct xattr_handler ext4_xattr_acl_access_handler;
335 @@ -112,9 +114,6 @@ extern void ext4_xattr_put_super(struct super_block *);
336 extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
337 struct ext4_inode *raw_inode, handle_t *handle);
339 -extern int __init ext4_init_xattr(void);
340 -extern void ext4_exit_xattr(void);
342 extern const struct xattr_handler *ext4_xattr_handlers[];
344 extern int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i,
345 @@ -126,6 +125,9 @@ extern int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode,
346 struct ext4_xattr_info *i,
347 struct ext4_xattr_ibody_find *is);
349 +extern struct mb_cache *ext4_xattr_create_cache(char *name);
350 +extern void ext4_xattr_destroy_cache(struct mb_cache *);
352 #ifdef CONFIG_EXT4_FS_SECURITY
353 extern int ext4_init_security(handle_t *handle, struct inode *inode,
354 struct inode *dir, const struct qstr *qstr);
355 diff --git a/fs/mbcache.c b/fs/mbcache.c
356 index 44e7153..8e373c6 100644
359 @@ -96,6 +96,7 @@ MODULE_DESCRIPTION("Meta block cache (for extended attributes)");
360 MODULE_LICENSE("GPL");
362 EXPORT_SYMBOL(mb_cache_create);
363 +EXPORT_SYMBOL(mb_cache_create_instance);
364 EXPORT_SYMBOL(mb_cache_shrink);
365 EXPORT_SYMBOL(mb_cache_destroy);
366 EXPORT_SYMBOL(mb_cache_entry_alloc);
367 @@ -260,18 +261,20 @@ static struct shrinker mb_cache_shrinker = {
371 - * mb_cache_create() create a new cache
372 + * mb_cache_create_instance() create a new cache for a device
374 * All entries in one cache are equal size. Cache entries may be from
375 - * multiple devices. If this is the first mbcache created, registers
376 - * the cache with kernel memory management. Returns NULL if no more
377 + * multiple devices. The caller must create a kmem_cache appropriate
378 + * for allocating struct mb_cache_entry. Returns NULL if no more
379 * memory was available.
381 * @name: name of the cache (informal)
382 * @bucket_bits: log2(number of hash buckets)
383 + * @mb_kmem_cache: slab cache for mb_cache_entry structures
386 -mb_cache_create(const char *name, int bucket_bits)
387 +mb_cache_create_instance(const char *name, int bucket_bits,
388 + struct kmem_cache *mb_kmem_cache)
390 int n, bucket_count = 1 << bucket_bits;
391 struct mb_cache *cache = NULL;
392 @@ -294,11 +297,8 @@ mb_cache_create(const char *name, int bucket_bits)
394 for (n=0; n<bucket_count; n++)
395 INIT_HLIST_BL_HEAD(&cache->c_index_hash[n]);
396 - cache->c_entry_cache = kmem_cache_create(name,
397 - sizeof(struct mb_cache_entry), 0,
398 - SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
399 - if (!cache->c_entry_cache)
401 + BUG_ON(mb_kmem_cache == NULL);
402 + cache->c_entry_cache = mb_kmem_cache;
405 * Set an upper limit on the number of cache entries so that the hash
406 @@ -311,15 +311,38 @@ mb_cache_create(const char *name, int bucket_bits)
407 spin_unlock(&mb_cache_spinlock);
411 - kfree(cache->c_index_hash);
414 kfree(cache->c_block_hash);
420 + * mb_cache_create() create a new cache
422 + * All entries in one cache are equal size. Cache entries may be from
423 + * multiple devices. Returns NULL if no more memory was available.
425 + * @name: name of the cache (informal)
426 + * @bucket_bits: log2(number of hash buckets)
429 +mb_cache_create(const char *name, int bucket_bits)
431 + struct kmem_cache *mb_kmem_cache;
432 + struct mb_cache *cache;
434 + mb_kmem_cache = kmem_cache_create(name,
435 + sizeof(struct mb_cache_entry), 0,
436 + SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
437 + if (mb_kmem_cache == NULL)
439 + cache = mb_cache_create_instance(name, bucket_bits, mb_kmem_cache);
441 + kmem_cache_destroy(mb_kmem_cache);
442 + cache->c_entry_cache_autofree = 1;
448 @@ -406,7 +429,8 @@ mb_cache_destroy(struct mb_cache *cache)
449 atomic_read(&cache->c_entry_count));
452 - kmem_cache_destroy(cache->c_entry_cache);
453 + if (cache->c_entry_cache_autofree)
454 + kmem_cache_destroy(cache->c_entry_cache);
456 kfree(cache->c_index_hash);
457 kfree(cache->c_block_hash);
458 diff --git a/include/linux/mbcache.h b/include/linux/mbcache.h
459 index 89826c0..b326ce7 100644
460 --- a/include/linux/mbcache.h
461 +++ b/include/linux/mbcache.h
462 @@ -29,11 +29,14 @@ struct mb_cache {
463 struct kmem_cache *c_entry_cache;
464 struct hlist_bl_head *c_block_hash;
465 struct hlist_bl_head *c_index_hash;
466 + unsigned int c_entry_cache_autofree:1;
469 /* Functions on caches */
471 struct mb_cache *mb_cache_create(const char *, int);
472 +struct mb_cache *mb_cache_create_instance(const char *,
473 + int, struct kmem_cache *);
474 void mb_cache_shrink(struct block_device *);
475 void mb_cache_destroy(struct mb_cache *);