1 ext2: convert to mbcache2
3 From: Jan Kara <jack@suse.cz>
5 The conversion is generally straightforward. We convert filesystem from
6 a global cache to per-fs one. Similarly to ext4 the tricky part is that
7 xattr block corresponding to found mbcache entry can get freed before we
8 get buffer lock for that block. So we have to check whether the entry is
9 still valid after getting the buffer lock.
11 Signed-off-by: Jan Kara <jack@suse.cz>
12 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
15 fs/ext2/super.c | 25 ++++++----
16 fs/ext2/xattr.c | 143 ++++++++++++++++++++++++++------------------------------
17 fs/ext2/xattr.h | 21 ++-------
18 4 files changed, 92 insertions(+), 100 deletions(-)
20 diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
21 index 4c69c94cafd8..f98ce7e60a0f 100644
24 @@ -61,6 +61,8 @@ struct ext2_block_alloc_info {
25 #define rsv_start rsv_window._rsv_start
26 #define rsv_end rsv_window._rsv_end
31 * second extended-fs super-block data in memory
33 @@ -111,6 +113,7 @@ struct ext2_sb_info {
34 * of the mount options.
37 + struct mb2_cache *s_mb_cache;
40 static inline spinlock_t *
41 diff --git a/fs/ext2/super.c b/fs/ext2/super.c
42 index 2a188413a2b0..b78caf25f746 100644
45 @@ -131,7 +131,10 @@ static void ext2_put_super (struct super_block * sb)
47 dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
49 - ext2_xattr_put_super(sb);
50 + if (sbi->s_mb_cache) {
51 + ext2_xattr_destroy_cache(sbi->s_mb_cache);
52 + sbi->s_mb_cache = NULL;
54 if (!(sb->s_flags & MS_RDONLY)) {
55 struct ext2_super_block *es = sbi->s_es;
57 @@ -1104,6 +1107,14 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
58 ext2_msg(sb, KERN_ERR, "error: insufficient memory");
62 +#ifdef CONFIG_EXT2_FS_XATTR
63 + sbi->s_mb_cache = ext2_xattr_create_cache();
64 + if (!sbi->s_mb_cache) {
65 + ext2_msg(sb, KERN_ERR, "Failed to create an mb_cache");
70 * set up enough so that it can read an inode
72 @@ -1149,6 +1160,8 @@ cantfind_ext2:
76 + if (sbi->s_mb_cache)
77 + ext2_xattr_destroy_cache(sbi->s_mb_cache);
78 percpu_counter_destroy(&sbi->s_freeblocks_counter);
79 percpu_counter_destroy(&sbi->s_freeinodes_counter);
80 percpu_counter_destroy(&sbi->s_dirs_counter);
81 @@ -1555,20 +1568,17 @@ MODULE_ALIAS_FS("ext2");
83 static int __init init_ext2_fs(void)
85 - int err = init_ext2_xattr();
90 err = init_inodecache();
94 err = register_filesystem(&ext2_fs_type);
105 @@ -1576,7 +1586,6 @@ static void __exit exit_ext2_fs(void)
107 unregister_filesystem(&ext2_fs_type);
108 destroy_inodecache();
112 MODULE_AUTHOR("Remy Card and others");
113 diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c
114 index f57a7aba32eb..7162b4869bc3 100644
115 --- a/fs/ext2/xattr.c
116 +++ b/fs/ext2/xattr.c
118 #include <linux/buffer_head.h>
119 #include <linux/init.h>
120 #include <linux/slab.h>
121 -#include <linux/mbcache.h>
122 +#include <linux/mbcache2.h>
123 #include <linux/quotaops.h>
124 #include <linux/rwsem.h>
125 #include <linux/security.h>
127 static int ext2_xattr_set2(struct inode *, struct buffer_head *,
128 struct ext2_xattr_header *);
130 -static int ext2_xattr_cache_insert(struct buffer_head *);
131 +static int ext2_xattr_cache_insert(struct mb2_cache *, struct buffer_head *);
132 static struct buffer_head *ext2_xattr_cache_find(struct inode *,
133 struct ext2_xattr_header *);
134 static void ext2_xattr_rehash(struct ext2_xattr_header *,
135 struct ext2_xattr_entry *);
137 -static struct mb_cache *ext2_xattr_cache;
139 static const struct xattr_handler *ext2_xattr_handler_map[] = {
140 [EXT2_XATTR_INDEX_USER] = &ext2_xattr_user_handler,
141 #ifdef CONFIG_EXT2_FS_POSIX_ACL
142 @@ -152,6 +150,7 @@ ext2_xattr_get(struct inode *inode, int name_index, const char *name,
143 size_t name_len, size;
146 + struct mb2_cache *ext2_mb_cache = EXT2_SB(inode->i_sb)->s_mb_cache;
148 ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
149 name_index, name, buffer, (long)buffer_size);
150 @@ -196,7 +195,7 @@ bad_block: ext2_error(inode->i_sb, "ext2_xattr_get",
154 - if (ext2_xattr_cache_insert(bh))
155 + if (ext2_xattr_cache_insert(ext2_mb_cache, bh))
156 ea_idebug(inode, "cache insert failed");
159 @@ -209,7 +208,7 @@ found:
160 le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize)
163 - if (ext2_xattr_cache_insert(bh))
164 + if (ext2_xattr_cache_insert(ext2_mb_cache, bh))
165 ea_idebug(inode, "cache insert failed");
168 @@ -247,6 +246,7 @@ ext2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
170 size_t rest = buffer_size;
172 + struct mb2_cache *ext2_mb_cache = EXT2_SB(inode->i_sb)->s_mb_cache;
174 ea_idebug(inode, "buffer=%p, buffer_size=%ld",
175 buffer, (long)buffer_size);
176 @@ -281,7 +281,7 @@ bad_block: ext2_error(inode->i_sb, "ext2_xattr_list",
180 - if (ext2_xattr_cache_insert(bh))
181 + if (ext2_xattr_cache_insert(ext2_mb_cache, bh))
182 ea_idebug(inode, "cache insert failed");
184 /* list the attribute names */
185 @@ -483,22 +483,23 @@ bad_block: ext2_error(sb, "ext2_xattr_set",
186 /* Here we know that we can set the new attribute. */
189 - struct mb_cache_entry *ce;
191 /* assert(header == HDR(bh)); */
192 - ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev,
195 if (header->h_refcount == cpu_to_le32(1)) {
196 + __u32 hash = le32_to_cpu(header->h_hash);
198 ea_bdebug(bh, "modifying in-place");
200 - mb_cache_entry_free(ce);
202 + * This must happen under buffer lock for
203 + * ext2_xattr_set2() to reliably detect modified block
205 + mb2_cache_entry_delete_block(EXT2_SB(sb)->s_mb_cache,
206 + hash, bh->b_blocknr);
208 /* keep the buffer locked while modifying it. */
213 - mb_cache_entry_release(ce);
215 ea_bdebug(bh, "cloning");
216 header = kmalloc(bh->b_size, GFP_KERNEL);
217 @@ -626,6 +627,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
218 struct super_block *sb = inode->i_sb;
219 struct buffer_head *new_bh = NULL;
221 + struct mb2_cache *ext2_mb_cache = EXT2_SB(sb)->s_mb_cache;
224 new_bh = ext2_xattr_cache_find(inode, header);
225 @@ -653,7 +655,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
226 don't need to change the reference count. */
229 - ext2_xattr_cache_insert(new_bh);
230 + ext2_xattr_cache_insert(ext2_mb_cache, new_bh);
232 /* We need to allocate a new block */
233 ext2_fsblk_t goal = ext2_group_first_block_no(sb,
234 @@ -674,7 +676,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
235 memcpy(new_bh->b_data, header, new_bh->b_size);
236 set_buffer_uptodate(new_bh);
237 unlock_buffer(new_bh);
238 - ext2_xattr_cache_insert(new_bh);
239 + ext2_xattr_cache_insert(ext2_mb_cache, new_bh);
241 ext2_xattr_update_super_block(sb);
243 @@ -707,19 +709,21 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
246 if (old_bh && old_bh != new_bh) {
247 - struct mb_cache_entry *ce;
250 * If there was an old block and we are no longer using it,
251 * release the old block.
253 - ce = mb_cache_entry_get(ext2_xattr_cache, old_bh->b_bdev,
254 - old_bh->b_blocknr);
256 if (HDR(old_bh)->h_refcount == cpu_to_le32(1)) {
257 + __u32 hash = le32_to_cpu(HDR(old_bh)->h_hash);
260 + * This must happen under buffer lock for
261 + * ext2_xattr_set2() to reliably detect freed block
263 + mb2_cache_entry_delete_block(ext2_mb_cache,
264 + hash, old_bh->b_blocknr);
265 /* Free the old block. */
267 - mb_cache_entry_free(ce);
268 ea_bdebug(old_bh, "freeing");
269 ext2_free_blocks(inode, old_bh->b_blocknr, 1);
270 mark_inode_dirty(inode);
271 @@ -730,8 +734,6 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
273 /* Decrement the refcount only. */
274 le32_add_cpu(&HDR(old_bh)->h_refcount, -1);
276 - mb_cache_entry_release(ce);
277 dquot_free_block_nodirty(inode, 1);
278 mark_inode_dirty(inode);
279 mark_buffer_dirty(old_bh);
280 @@ -757,7 +759,6 @@ void
281 ext2_xattr_delete_inode(struct inode *inode)
283 struct buffer_head *bh = NULL;
284 - struct mb_cache_entry *ce;
286 down_write(&EXT2_I(inode)->xattr_sem);
287 if (!EXT2_I(inode)->i_file_acl)
288 @@ -777,19 +778,22 @@ ext2_xattr_delete_inode(struct inode *inode)
289 EXT2_I(inode)->i_file_acl);
292 - ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev, bh->b_blocknr);
294 if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
296 - mb_cache_entry_free(ce);
297 + __u32 hash = le32_to_cpu(HDR(bh)->h_hash);
300 + * This must happen under buffer lock for ext2_xattr_set2() to
301 + * reliably detect freed block
303 + mb2_cache_entry_delete_block(EXT2_SB(inode->i_sb)->s_mb_cache,
304 + hash, bh->b_blocknr);
305 ext2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1);
310 le32_add_cpu(&HDR(bh)->h_refcount, -1);
312 - mb_cache_entry_release(ce);
313 ea_bdebug(bh, "refcount now=%d",
314 le32_to_cpu(HDR(bh)->h_refcount));
316 @@ -806,18 +810,6 @@ cleanup:
320 - * ext2_xattr_put_super()
322 - * This is called when a file system is unmounted.
325 -ext2_xattr_put_super(struct super_block *sb)
327 - mb_cache_shrink(sb->s_bdev);
332 * ext2_xattr_cache_insert()
334 * Create a new entry in the extended attribute cache, and insert
335 @@ -826,28 +818,20 @@ ext2_xattr_put_super(struct super_block *sb)
336 * Returns 0, or a negative error number on failure.
339 -ext2_xattr_cache_insert(struct buffer_head *bh)
340 +ext2_xattr_cache_insert(struct mb2_cache *cache, struct buffer_head *bh)
342 __u32 hash = le32_to_cpu(HDR(bh)->h_hash);
343 - struct mb_cache_entry *ce;
346 - ce = mb_cache_entry_alloc(ext2_xattr_cache, GFP_NOFS);
349 - error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash);
350 + error = mb2_cache_entry_create(cache, GFP_NOFS, hash, bh->b_blocknr);
352 - mb_cache_entry_free(ce);
353 if (error == -EBUSY) {
354 ea_bdebug(bh, "already in cache (%d cache entries)",
355 atomic_read(&ext2_xattr_cache->c_entry_count));
359 - ea_bdebug(bh, "inserting [%x] (%d cache entries)", (int)hash,
360 - atomic_read(&ext2_xattr_cache->c_entry_count));
361 - mb_cache_entry_release(ce);
364 + ea_bdebug(bh, "inserting [%x]", (int)hash);
368 @@ -903,23 +887,17 @@ static struct buffer_head *
369 ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header)
371 __u32 hash = le32_to_cpu(header->h_hash);
372 - struct mb_cache_entry *ce;
373 + struct mb2_cache_entry *ce;
374 + struct mb2_cache *ext2_mb_cache = EXT2_SB(inode->i_sb)->s_mb_cache;
377 return NULL; /* never share */
378 ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
380 - ce = mb_cache_entry_find_first(ext2_xattr_cache, inode->i_sb->s_bdev,
382 + ce = mb2_cache_entry_find_first(ext2_mb_cache, hash);
384 struct buffer_head *bh;
387 - if (PTR_ERR(ce) == -EAGAIN)
392 bh = sb_bread(inode->i_sb, ce->e_block);
394 ext2_error(inode->i_sb, "ext2_xattr_cache_find",
395 @@ -927,7 +905,21 @@ again:
396 inode->i_ino, (unsigned long) ce->e_block);
399 - if (le32_to_cpu(HDR(bh)->h_refcount) >
401 + * We have to be careful about races with freeing or
402 + * rehashing of xattr block. Once we hold buffer lock
403 + * xattr block's state is stable so we can check
404 + * whether the block got freed / rehashed or not.
405 + * Since we unhash mbcache entry under buffer lock when
406 + * freeing / rehashing xattr block, checking whether
407 + * entry is still hashed is reliable.
409 + if (hlist_bl_unhashed(&ce->e_hash_list)) {
410 + mb2_cache_entry_put(ext2_mb_cache, ce);
414 + } else if (le32_to_cpu(HDR(bh)->h_refcount) >
415 EXT2_XATTR_REFCOUNT_MAX) {
416 ea_idebug(inode, "block %ld refcount %d>%d",
417 (unsigned long) ce->e_block,
418 @@ -936,13 +928,14 @@ again:
419 } else if (!ext2_xattr_cmp(header, HDR(bh))) {
420 ea_bdebug(bh, "b_count=%d",
421 atomic_read(&(bh->b_count)));
422 - mb_cache_entry_release(ce);
423 + mb2_cache_entry_touch(ext2_mb_cache, ce);
424 + mb2_cache_entry_put(ext2_mb_cache, ce);
430 - ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash);
431 + ce = mb2_cache_entry_find_next(ext2_mb_cache, ce);
435 @@ -1015,17 +1008,15 @@ static void ext2_xattr_rehash(struct ext2_xattr_header *header,
437 #undef BLOCK_HASH_SHIFT
440 -init_ext2_xattr(void)
441 +#define HASH_BUCKET_BITS 10
443 +struct mb2_cache *ext2_xattr_create_cache(void)
445 - ext2_xattr_cache = mb_cache_create("ext2_xattr", 6);
446 - if (!ext2_xattr_cache)
449 + return mb2_cache_create(HASH_BUCKET_BITS);
453 -exit_ext2_xattr(void)
454 +void ext2_xattr_destroy_cache(struct mb2_cache *cache)
456 - mb_cache_destroy(ext2_xattr_cache);
458 + mb2_cache_destroy(cache);
460 diff --git a/fs/ext2/xattr.h b/fs/ext2/xattr.h
461 index 60edf298644e..6ea38aa9563a 100644
462 --- a/fs/ext2/xattr.h
463 +++ b/fs/ext2/xattr.h
464 @@ -53,6 +53,8 @@ struct ext2_xattr_entry {
465 #define EXT2_XATTR_SIZE(size) \
466 (((size) + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND)
470 # ifdef CONFIG_EXT2_FS_XATTR
472 extern const struct xattr_handler ext2_xattr_user_handler;
473 @@ -65,10 +67,9 @@ extern int ext2_xattr_get(struct inode *, int, const char *, void *, size_t);
474 extern int ext2_xattr_set(struct inode *, int, const char *, const void *, size_t, int);
476 extern void ext2_xattr_delete_inode(struct inode *);
477 -extern void ext2_xattr_put_super(struct super_block *);
479 -extern int init_ext2_xattr(void);
480 -extern void exit_ext2_xattr(void);
481 +extern struct mb2_cache *ext2_xattr_create_cache(void);
482 +extern void ext2_xattr_destroy_cache(struct mb2_cache *cache);
484 extern const struct xattr_handler *ext2_xattr_handlers[];
486 @@ -93,19 +94,7 @@ ext2_xattr_delete_inode(struct inode *inode)
491 -ext2_xattr_put_super(struct super_block *sb)
496 -init_ext2_xattr(void)
502 -exit_ext2_xattr(void)
503 +static inline void ext2_xattr_destroy_cache(struct mb2_cache *cache)