Skip to content

Commit 82939d7

Browse files
jankaratytso
authored andcommitted
ext4: convert to mbcache2
The conversion is generally straightforward. The only tricky part is that xattr block corresponding to found mbcache entry can get freed before we get buffer lock for that block. So we have to check whether the entry is still valid after getting buffer lock. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent f9a61eb commit 82939d7

File tree

4 files changed

+75
-75
lines changed

4 files changed

+75
-75
lines changed

fs/ext4/ext4.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1468,7 +1468,7 @@ struct ext4_sb_info {
14681468
struct list_head s_es_list; /* List of inodes with reclaimable extents */
14691469
long s_es_nr_inode;
14701470
struct ext4_es_stats s_es_stats;
1471-
struct mb_cache *s_mb_cache;
1471+
struct mb2_cache *s_mb_cache;
14721472
spinlock_t s_es_lock ____cacheline_aligned_in_smp;
14731473

14741474
/* Ratelimit ext4 messages. */

fs/ext4/super.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -844,7 +844,6 @@ static void ext4_put_super(struct super_block *sb)
844844
ext4_release_system_zone(sb);
845845
ext4_mb_release(sb);
846846
ext4_ext_release(sb);
847-
ext4_xattr_put_super(sb);
848847

849848
if (!(sb->s_flags & MS_RDONLY)) {
850849
ext4_clear_feature_journal_needs_recovery(sb);
@@ -3797,7 +3796,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
37973796

37983797
no_journal:
37993798
if (ext4_mballoc_ready) {
3800-
sbi->s_mb_cache = ext4_xattr_create_cache(sb->s_id);
3799+
sbi->s_mb_cache = ext4_xattr_create_cache();
38013800
if (!sbi->s_mb_cache) {
38023801
ext4_msg(sb, KERN_ERR, "Failed to create an mb_cache");
38033802
goto failed_mount_wq;
@@ -4027,6 +4026,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
40274026
if (EXT4_SB(sb)->rsv_conversion_wq)
40284027
destroy_workqueue(EXT4_SB(sb)->rsv_conversion_wq);
40294028
failed_mount_wq:
4029+
if (sbi->s_mb_cache) {
4030+
ext4_xattr_destroy_cache(sbi->s_mb_cache);
4031+
sbi->s_mb_cache = NULL;
4032+
}
40304033
if (sbi->s_journal) {
40314034
jbd2_journal_destroy(sbi->s_journal);
40324035
sbi->s_journal = NULL;

fs/ext4/xattr.c

Lines changed: 67 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
#include <linux/init.h>
5454
#include <linux/fs.h>
5555
#include <linux/slab.h>
56-
#include <linux/mbcache.h>
56+
#include <linux/mbcache2.h>
5757
#include <linux/quotaops.h>
5858
#include "ext4_jbd2.h"
5959
#include "ext4.h"
@@ -78,10 +78,10 @@
7878
# define ea_bdebug(bh, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
7979
#endif
8080

81-
static void ext4_xattr_cache_insert(struct mb_cache *, struct buffer_head *);
81+
static void ext4_xattr_cache_insert(struct mb2_cache *, struct buffer_head *);
8282
static struct buffer_head *ext4_xattr_cache_find(struct inode *,
8383
struct ext4_xattr_header *,
84-
struct mb_cache_entry **);
84+
struct mb2_cache_entry **);
8585
static void ext4_xattr_rehash(struct ext4_xattr_header *,
8686
struct ext4_xattr_entry *);
8787
static int ext4_xattr_list(struct dentry *dentry, char *buffer,
@@ -276,7 +276,7 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
276276
struct ext4_xattr_entry *entry;
277277
size_t size;
278278
int error;
279-
struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
279+
struct mb2_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
280280

281281
ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
282282
name_index, name, buffer, (long)buffer_size);
@@ -428,7 +428,7 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size)
428428
struct inode *inode = d_inode(dentry);
429429
struct buffer_head *bh = NULL;
430430
int error;
431-
struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
431+
struct mb2_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
432432

433433
ea_idebug(inode, "buffer=%p, buffer_size=%ld",
434434
buffer, (long)buffer_size);
@@ -545,30 +545,31 @@ static void
545545
ext4_xattr_release_block(handle_t *handle, struct inode *inode,
546546
struct buffer_head *bh)
547547
{
548-
struct mb_cache_entry *ce = NULL;
549548
int error = 0;
550-
struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
551549

552-
ce = mb_cache_entry_get(ext4_mb_cache, bh->b_bdev, bh->b_blocknr);
553550
BUFFER_TRACE(bh, "get_write_access");
554551
error = ext4_journal_get_write_access(handle, bh);
555552
if (error)
556553
goto out;
557554

558555
lock_buffer(bh);
559556
if (BHDR(bh)->h_refcount == cpu_to_le32(1)) {
557+
__u32 hash = le32_to_cpu(BHDR(bh)->h_hash);
558+
560559
ea_bdebug(bh, "refcount now=0; freeing");
561-
if (ce)
562-
mb_cache_entry_free(ce);
560+
/*
561+
* This must happen under buffer lock for
562+
* ext4_xattr_block_set() to reliably detect freed block
563+
*/
564+
mb2_cache_entry_delete_block(EXT4_GET_MB_CACHE(inode), hash,
565+
bh->b_blocknr);
563566
get_bh(bh);
564567
unlock_buffer(bh);
565568
ext4_free_blocks(handle, inode, bh, 0, 1,
566569
EXT4_FREE_BLOCKS_METADATA |
567570
EXT4_FREE_BLOCKS_FORGET);
568571
} else {
569572
le32_add_cpu(&BHDR(bh)->h_refcount, -1);
570-
if (ce)
571-
mb_cache_entry_release(ce);
572573
/*
573574
* Beware of this ugliness: Releasing of xattr block references
574575
* from different inodes can race and so we have to protect
@@ -781,28 +782,31 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
781782
struct super_block *sb = inode->i_sb;
782783
struct buffer_head *new_bh = NULL;
783784
struct ext4_xattr_search *s = &bs->s;
784-
struct mb_cache_entry *ce = NULL;
785+
struct mb2_cache_entry *ce = NULL;
785786
int error = 0;
786-
struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
787+
struct mb2_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
787788

788789
#define header(x) ((struct ext4_xattr_header *)(x))
789790

790791
if (i->value && i->value_len > sb->s_blocksize)
791792
return -ENOSPC;
792793
if (s->base) {
793-
ce = mb_cache_entry_get(ext4_mb_cache, bs->bh->b_bdev,
794-
bs->bh->b_blocknr);
795794
BUFFER_TRACE(bs->bh, "get_write_access");
796795
error = ext4_journal_get_write_access(handle, bs->bh);
797796
if (error)
798797
goto cleanup;
799798
lock_buffer(bs->bh);
800799

801800
if (header(s->base)->h_refcount == cpu_to_le32(1)) {
802-
if (ce) {
803-
mb_cache_entry_free(ce);
804-
ce = NULL;
805-
}
801+
__u32 hash = le32_to_cpu(BHDR(bs->bh)->h_hash);
802+
803+
/*
804+
* This must happen under buffer lock for
805+
* ext4_xattr_block_set() to reliably detect modified
806+
* block
807+
*/
808+
mb2_cache_entry_delete_block(ext4_mb_cache, hash,
809+
bs->bh->b_blocknr);
806810
ea_bdebug(bs->bh, "modifying in-place");
807811
error = ext4_xattr_set_entry(i, s);
808812
if (!error) {
@@ -826,10 +830,6 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
826830
int offset = (char *)s->here - bs->bh->b_data;
827831

828832
unlock_buffer(bs->bh);
829-
if (ce) {
830-
mb_cache_entry_release(ce);
831-
ce = NULL;
832-
}
833833
ea_bdebug(bs->bh, "cloning");
834834
s->base = kmalloc(bs->bh->b_size, GFP_NOFS);
835835
error = -ENOMEM;
@@ -884,6 +884,31 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
884884
if (error)
885885
goto cleanup_dquot;
886886
lock_buffer(new_bh);
887+
/*
888+
* We have to be careful about races with
889+
* freeing or rehashing of xattr block. Once we
890+
* hold buffer lock xattr block's state is
891+
* stable so we can check whether the block got
892+
* freed / rehashed or not. Since we unhash
893+
* mbcache entry under buffer lock when freeing
894+
* / rehashing xattr block, checking whether
895+
* entry is still hashed is reliable.
896+
*/
897+
if (hlist_bl_unhashed(&ce->e_hash_list)) {
898+
/*
899+
* Undo everything and check mbcache
900+
* again.
901+
*/
902+
unlock_buffer(new_bh);
903+
dquot_free_block(inode,
904+
EXT4_C2B(EXT4_SB(sb),
905+
1));
906+
brelse(new_bh);
907+
mb2_cache_entry_put(ext4_mb_cache, ce);
908+
ce = NULL;
909+
new_bh = NULL;
910+
goto inserted;
911+
}
887912
le32_add_cpu(&BHDR(new_bh)->h_refcount, 1);
888913
ea_bdebug(new_bh, "reusing; refcount now=%d",
889914
le32_to_cpu(BHDR(new_bh)->h_refcount));
@@ -894,7 +919,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
894919
if (error)
895920
goto cleanup_dquot;
896921
}
897-
mb_cache_entry_release(ce);
922+
mb2_cache_entry_touch(ext4_mb_cache, ce);
923+
mb2_cache_entry_put(ext4_mb_cache, ce);
898924
ce = NULL;
899925
} else if (bs->bh && s->base == bs->bh->b_data) {
900926
/* We were modifying this block in-place. */
@@ -959,7 +985,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
959985

960986
cleanup:
961987
if (ce)
962-
mb_cache_entry_release(ce);
988+
mb2_cache_entry_put(ext4_mb_cache, ce);
963989
brelse(new_bh);
964990
if (!(bs->bh && s->base == bs->bh->b_data))
965991
kfree(s->base);
@@ -1511,17 +1537,6 @@ ext4_xattr_delete_inode(handle_t *handle, struct inode *inode)
15111537
brelse(bh);
15121538
}
15131539

1514-
/*
1515-
* ext4_xattr_put_super()
1516-
*
1517-
* This is called when a file system is unmounted.
1518-
*/
1519-
void
1520-
ext4_xattr_put_super(struct super_block *sb)
1521-
{
1522-
mb_cache_shrink(sb->s_bdev);
1523-
}
1524-
15251540
/*
15261541
* ext4_xattr_cache_insert()
15271542
*
@@ -1531,28 +1546,18 @@ ext4_xattr_put_super(struct super_block *sb)
15311546
* Returns 0, or a negative error number on failure.
15321547
*/
15331548
static void
1534-
ext4_xattr_cache_insert(struct mb_cache *ext4_mb_cache, struct buffer_head *bh)
1549+
ext4_xattr_cache_insert(struct mb2_cache *ext4_mb_cache, struct buffer_head *bh)
15351550
{
15361551
__u32 hash = le32_to_cpu(BHDR(bh)->h_hash);
1537-
struct mb_cache_entry *ce;
15381552
int error;
15391553

1540-
ce = mb_cache_entry_alloc(ext4_mb_cache, GFP_NOFS);
1541-
if (!ce) {
1542-
ea_bdebug(bh, "out of memory");
1543-
return;
1544-
}
1545-
error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash);
1554+
error = mb2_cache_entry_create(ext4_mb_cache, GFP_NOFS, hash,
1555+
bh->b_blocknr);
15461556
if (error) {
1547-
mb_cache_entry_free(ce);
1548-
if (error == -EBUSY) {
1557+
if (error == -EBUSY)
15491558
ea_bdebug(bh, "already in cache");
1550-
error = 0;
1551-
}
1552-
} else {
1559+
} else
15531560
ea_bdebug(bh, "inserting [%x]", (int)hash);
1554-
mb_cache_entry_release(ce);
1555-
}
15561561
}
15571562

15581563
/*
@@ -1605,26 +1610,19 @@ ext4_xattr_cmp(struct ext4_xattr_header *header1,
16051610
*/
16061611
static struct buffer_head *
16071612
ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header,
1608-
struct mb_cache_entry **pce)
1613+
struct mb2_cache_entry **pce)
16091614
{
16101615
__u32 hash = le32_to_cpu(header->h_hash);
1611-
struct mb_cache_entry *ce;
1612-
struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
1616+
struct mb2_cache_entry *ce;
1617+
struct mb2_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
16131618

16141619
if (!header->h_hash)
16151620
return NULL; /* never share */
16161621
ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
1617-
again:
1618-
ce = mb_cache_entry_find_first(ext4_mb_cache, inode->i_sb->s_bdev,
1619-
hash);
1622+
ce = mb2_cache_entry_find_first(ext4_mb_cache, hash);
16201623
while (ce) {
16211624
struct buffer_head *bh;
16221625

1623-
if (IS_ERR(ce)) {
1624-
if (PTR_ERR(ce) == -EAGAIN)
1625-
goto again;
1626-
break;
1627-
}
16281626
bh = sb_bread(inode->i_sb, ce->e_block);
16291627
if (!bh) {
16301628
EXT4_ERROR_INODE(inode, "block %lu read error",
@@ -1640,7 +1638,7 @@ ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header,
16401638
return bh;
16411639
}
16421640
brelse(bh);
1643-
ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash);
1641+
ce = mb2_cache_entry_find_next(ext4_mb_cache, ce);
16441642
}
16451643
return NULL;
16461644
}
@@ -1715,15 +1713,15 @@ static void ext4_xattr_rehash(struct ext4_xattr_header *header,
17151713

17161714
#define HASH_BUCKET_BITS 10
17171715

1718-
struct mb_cache *
1719-
ext4_xattr_create_cache(char *name)
1716+
struct mb2_cache *
1717+
ext4_xattr_create_cache(void)
17201718
{
1721-
return mb_cache_create(name, HASH_BUCKET_BITS);
1719+
return mb2_cache_create(HASH_BUCKET_BITS);
17221720
}
17231721

1724-
void ext4_xattr_destroy_cache(struct mb_cache *cache)
1722+
void ext4_xattr_destroy_cache(struct mb2_cache *cache)
17251723
{
17261724
if (cache)
1727-
mb_cache_destroy(cache);
1725+
mb2_cache_destroy(cache);
17281726
}
17291727

fs/ext4/xattr.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_
108108
extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int);
109109

110110
extern void ext4_xattr_delete_inode(handle_t *, struct inode *);
111-
extern void ext4_xattr_put_super(struct super_block *);
112111

113112
extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
114113
struct ext4_inode *raw_inode, handle_t *handle);
@@ -124,8 +123,8 @@ extern int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode,
124123
struct ext4_xattr_info *i,
125124
struct ext4_xattr_ibody_find *is);
126125

127-
extern struct mb_cache *ext4_xattr_create_cache(char *name);
128-
extern void ext4_xattr_destroy_cache(struct mb_cache *);
126+
extern struct mb2_cache *ext4_xattr_create_cache(void);
127+
extern void ext4_xattr_destroy_cache(struct mb2_cache *);
129128

130129
#ifdef CONFIG_EXT4_FS_SECURITY
131130
extern int ext4_init_security(handle_t *handle, struct inode *inode,

0 commit comments

Comments
 (0)