Skip to content

Commit 1189d8e

Browse files
jankaratytso
authored andcommitted
ext2: avoid deleting xattr block that is being reused
Currently when we decide to reuse xattr block we detect the case when the last reference to xattr block is being dropped at the same time and cancel the reuse attempt. Convert ext2 to a new scheme when as soon as matching mbcache entry is found, we wait with dropping the last xattr block reference until mbcache entry reference is dropped (meaning either the xattr block reference is increased or we decided not to reuse the block). Signed-off-by: Jan Kara <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]>
1 parent b67798d commit 1189d8e

File tree

1 file changed

+29
-29
lines changed

1 file changed

+29
-29
lines changed

fs/ext2/xattr.c

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -522,17 +522,18 @@ ext2_xattr_set(struct inode *inode, int name_index, const char *name,
522522
lock_buffer(bh);
523523
if (header->h_refcount == cpu_to_le32(1)) {
524524
__u32 hash = le32_to_cpu(header->h_hash);
525+
struct mb_cache_entry *oe;
525526

526-
ea_bdebug(bh, "modifying in-place");
527+
oe = mb_cache_entry_delete_or_get(EA_BLOCK_CACHE(inode),
528+
hash, bh->b_blocknr);
529+
if (!oe) {
530+
ea_bdebug(bh, "modifying in-place");
531+
goto update_block;
532+
}
527533
/*
528-
* This must happen under buffer lock for
529-
* ext2_xattr_set2() to reliably detect modified block
534+
* Someone is trying to reuse the block, leave it alone
530535
*/
531-
mb_cache_entry_delete(EA_BLOCK_CACHE(inode), hash,
532-
bh->b_blocknr);
533-
534-
/* keep the buffer locked while modifying it. */
535-
goto update_block;
536+
mb_cache_entry_put(EA_BLOCK_CACHE(inode), oe);
536537
}
537538
unlock_buffer(bh);
538539
ea_bdebug(bh, "cloning");
@@ -656,16 +657,29 @@ static void ext2_xattr_release_block(struct inode *inode,
656657
{
657658
struct mb_cache *ea_block_cache = EA_BLOCK_CACHE(inode);
658659

660+
retry_ref:
659661
lock_buffer(bh);
660662
if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
661663
__u32 hash = le32_to_cpu(HDR(bh)->h_hash);
664+
struct mb_cache_entry *oe;
662665

663666
/*
664-
* This must happen under buffer lock for
665-
* ext2_xattr_set2() to reliably detect freed block
667+
* This must happen under buffer lock to properly
668+
* serialize with ext2_xattr_set() reusing the block.
666669
*/
667-
mb_cache_entry_delete(ea_block_cache, hash,
668-
bh->b_blocknr);
670+
oe = mb_cache_entry_delete_or_get(ea_block_cache, hash,
671+
bh->b_blocknr);
672+
if (oe) {
673+
/*
674+
* Someone is trying to reuse the block. Wait
675+
* and retry.
676+
*/
677+
unlock_buffer(bh);
678+
mb_cache_entry_wait_unused(oe);
679+
mb_cache_entry_put(ea_block_cache, oe);
680+
goto retry_ref;
681+
}
682+
669683
/* Free the old block. */
670684
ea_bdebug(bh, "freeing");
671685
ext2_free_blocks(inode, bh->b_blocknr, 1);
@@ -929,7 +943,7 @@ ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header)
929943
if (!header->h_hash)
930944
return NULL; /* never share */
931945
ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
932-
again:
946+
933947
ce = mb_cache_entry_find_first(ea_block_cache, hash);
934948
while (ce) {
935949
struct buffer_head *bh;
@@ -941,22 +955,8 @@ ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header)
941955
inode->i_ino, (unsigned long) ce->e_value);
942956
} else {
943957
lock_buffer(bh);
944-
/*
945-
* We have to be careful about races with freeing or
946-
* rehashing of xattr block. Once we hold buffer lock
947-
* xattr block's state is stable so we can check
948-
* whether the block got freed / rehashed or not.
949-
* Since we unhash mbcache entry under buffer lock when
950-
* freeing / rehashing xattr block, checking whether
951-
* entry is still hashed is reliable.
952-
*/
953-
if (hlist_bl_unhashed(&ce->e_hash_list)) {
954-
mb_cache_entry_put(ea_block_cache, ce);
955-
unlock_buffer(bh);
956-
brelse(bh);
957-
goto again;
958-
} else if (le32_to_cpu(HDR(bh)->h_refcount) >
959-
EXT2_XATTR_REFCOUNT_MAX) {
958+
if (le32_to_cpu(HDR(bh)->h_refcount) >
959+
EXT2_XATTR_REFCOUNT_MAX) {
960960
ea_idebug(inode, "block %ld refcount %d>%d",
961961
(unsigned long) ce->e_value,
962962
le32_to_cpu(HDR(bh)->h_refcount),

0 commit comments

Comments
 (0)