From: Jan Kara <jack@suse.cz>
To: Ted Tso <tytso@mit.edu>
Cc: <linux-ext4@vger.kernel.org>,
Ritesh Harjani <ritesh.list@gmail.com>, Jan Kara <jack@suse.cz>
Subject: [PATCH 08/10] ext2: Avoid deleting xattr block that is being reused
Date: Tue, 12 Jul 2022 12:54:27 +0200 [thread overview]
Message-ID: <20220712105436.32204-8-jack@suse.cz> (raw)
In-Reply-To: <20220712104519.29887-1-jack@suse.cz>
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 <jack@suse.cz>
---
fs/ext2/xattr.c | 58 ++++++++++++++++++++++++-------------------------
1 file changed, 29 insertions(+), 29 deletions(-)
diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c
index 37ce495eb279..641abfa4b718 100644
--- a/fs/ext2/xattr.c
+++ b/fs/ext2/xattr.c
@@ -522,17 +522,18 @@ ext2_xattr_set(struct inode *inode, int name_index, const char *name,
lock_buffer(bh);
if (header->h_refcount == cpu_to_le32(1)) {
__u32 hash = le32_to_cpu(header->h_hash);
+ struct mb_cache_entry *oe;
- ea_bdebug(bh, "modifying in-place");
+ oe = mb_cache_entry_delete_or_get(EA_BLOCK_CACHE(inode),
+ hash, bh->b_blocknr);
+ if (!oe) {
+ ea_bdebug(bh, "modifying in-place");
+ goto update_block;
+ }
/*
- * This must happen under buffer lock for
- * ext2_xattr_set2() to reliably detect modified block
+ * Someone is trying to reuse the block, leave it alone
*/
- mb_cache_entry_delete(EA_BLOCK_CACHE(inode), hash,
- bh->b_blocknr);
-
- /* keep the buffer locked while modifying it. */
- goto update_block;
+ mb_cache_entry_put(EA_BLOCK_CACHE(inode), oe);
}
unlock_buffer(bh);
ea_bdebug(bh, "cloning");
@@ -656,16 +657,29 @@ static void ext2_xattr_release_block(struct inode *inode,
{
struct mb_cache *ea_block_cache = EA_BLOCK_CACHE(inode);
+retry_ref:
lock_buffer(bh);
if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
__u32 hash = le32_to_cpu(HDR(bh)->h_hash);
+ struct mb_cache_entry *oe;
/*
- * This must happen under buffer lock for
- * ext2_xattr_set2() to reliably detect freed block
+ * This must happen under buffer lock to properly
+ * serialize with ext2_xattr_set() reusing the block.
*/
- mb_cache_entry_delete(ea_block_cache, hash,
- bh->b_blocknr);
+ oe = mb_cache_entry_delete_or_get(ea_block_cache, hash,
+ bh->b_blocknr);
+ if (oe) {
+ /*
+ * Someone is trying to reuse the block. Wait
+ * and retry.
+ */
+ unlock_buffer(bh);
+ mb_cache_entry_wait_unused(oe);
+ mb_cache_entry_put(ea_block_cache, oe);
+ goto retry_ref;
+ }
+
/* Free the old block. */
ea_bdebug(bh, "freeing");
ext2_free_blocks(inode, bh->b_blocknr, 1);
@@ -929,7 +943,7 @@ ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header)
if (!header->h_hash)
return NULL; /* never share */
ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
-again:
+
ce = mb_cache_entry_find_first(ea_block_cache, hash);
while (ce) {
struct buffer_head *bh;
@@ -941,22 +955,8 @@ ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header)
inode->i_ino, (unsigned long) ce->e_value);
} else {
lock_buffer(bh);
- /*
- * We have to be careful about races with freeing or
- * rehashing of xattr block. Once we hold buffer lock
- * xattr block's state is stable so we can check
- * whether the block got freed / rehashed or not.
- * Since we unhash mbcache entry under buffer lock when
- * freeing / rehashing xattr block, checking whether
- * entry is still hashed is reliable.
- */
- if (hlist_bl_unhashed(&ce->e_hash_list)) {
- mb_cache_entry_put(ea_block_cache, ce);
- unlock_buffer(bh);
- brelse(bh);
- goto again;
- } else if (le32_to_cpu(HDR(bh)->h_refcount) >
- EXT2_XATTR_REFCOUNT_MAX) {
+ if (le32_to_cpu(HDR(bh)->h_refcount) >
+ EXT2_XATTR_REFCOUNT_MAX) {
ea_idebug(inode, "block %ld refcount %d>%d",
(unsigned long) ce->e_value,
le32_to_cpu(HDR(bh)->h_refcount),
--
2.35.3
next prev parent reply other threads:[~2022-07-12 10:54 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-07-12 10:54 [PATCH 0/10 v3] ext4: Fix possible fs corruption due to xattr races Jan Kara
2022-07-12 10:54 ` [PATCH 01/10] mbcache: Don't reclaim used entries Jan Kara
2022-07-14 11:47 ` Ritesh Harjani
2022-07-14 14:36 ` Jan Kara
2022-07-14 14:49 ` Ritesh Harjani
2022-07-22 13:58 ` Theodore Ts'o
2022-07-12 10:54 ` [PATCH 02/10] mbcache: Add functions to delete entry if unused Jan Kara
2022-07-14 12:15 ` Ritesh Harjani
2022-07-14 14:49 ` Jan Kara
2022-07-14 15:00 ` Ritesh Harjani
2022-07-12 10:54 ` [PATCH 03/10] ext4: Remove EA inode entry from mbcache on inode eviction Jan Kara
2022-07-12 10:54 ` [PATCH 04/10] ext4: Unindent codeblock in ext4_xattr_block_set() Jan Kara
2022-07-14 12:19 ` Ritesh Harjani
2022-07-12 10:54 ` [PATCH 05/10] ext4: Fix race when reusing xattr blocks Jan Kara
2022-07-14 12:26 ` Ritesh Harjani
2022-07-16 3:00 ` Zhihao Cheng
2022-07-25 15:23 ` Jan Kara
2022-07-26 1:14 ` Zhihao Cheng
2022-07-12 10:54 ` [PATCH 06/10] ext2: Factor our freeing of xattr block reference Jan Kara
2022-07-14 12:37 ` Ritesh Harjani
2022-07-14 14:55 ` Jan Kara
2022-07-14 16:17 ` Ritesh Harjani
2022-07-12 10:54 ` [PATCH 07/10] ext2: Unindent codeblock in ext2_xattr_set() Jan Kara
2022-07-14 12:38 ` Ritesh Harjani
2022-07-12 10:54 ` Jan Kara [this message]
2022-07-12 10:54 ` [PATCH 09/10] mbcache: Remove mb_cache_entry_delete() Jan Kara
2022-07-12 10:54 ` [PATCH 10/10] mbcache: Automatically delete entries from cache on freeing Jan Kara
2022-07-14 13:09 ` Ritesh Harjani
2022-07-14 15:05 ` Jan Kara
2022-07-12 12:47 ` [PATCH 0/10 v3] ext4: Fix possible fs corruption due to xattr races Ritesh Harjani
-- strict thread matches above, loose matches on Subject: below --
2022-06-14 16:05 [PATCH 0/10 v2] " Jan Kara
2022-06-14 16:05 ` [PATCH 08/10] ext2: Avoid deleting xattr block that is being reused Jan Kara
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220712105436.32204-8-jack@suse.cz \
--to=jack@suse.cz \
--cc=linux-ext4@vger.kernel.org \
--cc=ritesh.list@gmail.com \
--cc=tytso@mit.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox