Received: by 2002:a05:6358:d09b:b0:dc:cd0c:909e with SMTP id jc27csp7860127rwb; Wed, 23 Nov 2022 11:45:29 -0800 (PST) X-Google-Smtp-Source: AA0mqf6zS3v0oZX/DOFv5uKTh4Gx8jOXopQ9N+377VRqfVK7ME+egHbvOdGmgP9UADELrUeGzw+t X-Received: by 2002:aa7:c50b:0:b0:469:d36e:3213 with SMTP id o11-20020aa7c50b000000b00469d36e3213mr10654520edq.206.1669232728720; Wed, 23 Nov 2022 11:45:28 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1669232728; cv=none; d=google.com; s=arc-20160816; b=HB5gpmf93Km9fmjGahU5ZqLoH9HSPVAQ3KsUzwHridXtb3wRLu/U8aYB7v9YBoGELE jvQYjDaDJDREjGV9eopj7pKGcOxLs1lLeXcUAIHW1W3djQf3TlZcznq7v3Q05P78X9kf ntMfY4DocLMbkeFS6QUJdqNSyBmfV1bALe/v5K4eX0kTUXg54o4DblXBf4nQqKc/WxyL ym6V2Fb/Hr7nJhzc2dUYWSAm2pTgwvVDVzwe0lNnOGC311droFvo3jI0cy8ATJBZnWZI X01iMXsWKmokKJTOzeWOppj8KQnR4lKrDGNn7i5Hj7l+vXd/IK4WwjAslH0mbfchfuj/ 7AOg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature:dkim-signature; bh=ytycr3bFhFf1cRbLiEf0ox+A4fPM8/896n/b+QrLrng=; b=BqwHWxddeV+wSxWJNeDQ1yLDiA8eK7+ld8biOCOvqRYQnDvetOM/ZtoYOirSGquFNR CglvksVq+uPLziaB2OLgmvZg9ecH0ZqcOoEKJHp49s7SZ0yHBxe/flbuNc0RQMLASshR q7WScG7VPYrz8HkIxpE0xMIQf+KH6Qe7m9w6ntujq7qkzWP65UciSwe6ed0iJxw7SoNq IdypHlo3mQGrIcs5r9eKy/THHedRKUy0yMKbw+PMbMQRuBqMnXVS1XdRA36wseOWssXG pl79OhN0KTVlplaZgfOUeWDhPy3Ortmudd0aUbQqLAIIne/++ihHu7whQTdGJtsHZBUm H/7A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@suse.cz header.s=susede2_rsa header.b=DM++R2+p; dkim=neutral (no key) header.i=@suse.cz header.s=susede2_ed25519 header.b="vz1/Aebk"; spf=pass (google.com: domain of linux-ext4-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-ext4-owner@vger.kernel.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id l18-20020a170906795200b007ae9f42f86esi15569354ejo.383.2022.11.23.11.44.56; Wed, 23 Nov 2022 11:45:28 -0800 (PST) Received-SPF: pass (google.com: domain of linux-ext4-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@suse.cz header.s=susede2_rsa header.b=DM++R2+p; dkim=neutral (no key) header.i=@suse.cz header.s=susede2_ed25519 header.b="vz1/Aebk"; spf=pass (google.com: domain of linux-ext4-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-ext4-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238160AbiKWTkB (ORCPT + 99 others); Wed, 23 Nov 2022 14:40:01 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35128 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237463AbiKWTj6 (ORCPT ); Wed, 23 Nov 2022 14:39:58 -0500 Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 30D1E91513; Wed, 23 Nov 2022 11:39:57 -0800 (PST) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id D902A1F8B2; Wed, 23 Nov 2022 19:39:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.cz; s=susede2_rsa; t=1669232395; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=ytycr3bFhFf1cRbLiEf0ox+A4fPM8/896n/b+QrLrng=; b=DM++R2+pLusfDy6C3Su2gxHMEP6ZENr/iarbdWwq9IvpTRv6R3EbVKBd1s2/2dhc/UWK5A ruWSbe1GW82ERd3HT2QbXNZYkG+sdWn2BaqhOIfAaqviGS+qhD01zRV4702EWXMJ6MnTnJ HhTQaWszwEDZiMcpZdtKb482RdRmVGY= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.cz; s=susede2_ed25519; t=1669232395; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=ytycr3bFhFf1cRbLiEf0ox+A4fPM8/896n/b+QrLrng=; b=vz1/AebkKzaBrFLQY4qQTIM8RQUsJ7THAt0+P0ECBa54PnZTF65C2CILTAFVHvesS13eLc TBGi3EejZX8+VPBg== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id BC15F13AE7; Wed, 23 Nov 2022 19:39:55 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id /0RdLQt3fmO0NQAAMHmgww (envelope-from ); Wed, 23 Nov 2022 19:39:55 +0000 Received: by quack3.suse.cz (Postfix, from userid 1000) id 3844BA0709; Wed, 23 Nov 2022 20:39:55 +0100 (CET) From: Jan Kara To: Ted Tso Cc: Andreas Gruenbacher , , Jan Kara , stable@vger.kernel.org, Jeremi Piotrowski , Thilo Fromm Subject: [PATCH] ext4: Fix deadlock due to mbcache entry corruption Date: Wed, 23 Nov 2022 20:39:50 +0100 Message-Id: <20221123193950.16758-1-jack@suse.cz> X-Mailer: git-send-email 2.35.3 MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=4691; i=jack@suse.cz; h=from:subject; bh=lgqcR+tlXwQh9p07uNn3TLJ8bLqtsHv8DfmUFPhjuwQ=; b=owEBbQGS/pANAwAIAZydqgc/ZEDZAcsmYgBjfncA6ph/VLAGCRJioNHRQaLvJVljt3nJujkuO8i0 SKb14nKJATMEAAEIAB0WIQSrWdEr1p4yirVVKBycnaoHP2RA2QUCY353AAAKCRCcnaoHP2RA2RCrB/ 4xA9Q7hRSFF52O4iIVngWyhWuIFfiIM20wTv+JF0EZJzsSr+8Qsc6j6e3Y1DR+Wacp8GI2I5RYI6V6 YgIYGnf2VuKHupW1XEaFUU7AHDps0UoNHBeiJbcu0h3vdLoa5XfUr9mz7JIeXsbR1fDV49WHZRKpgE GJ+wrKtQe/v8K0twgg3a85YM9wFahzD50bMeNYFjdP9aKeyChN1MEj+hZM6WrmqicQWQu4Z50ZYuZg 7f9vvXV9leRAv8DvAPRaJ0TmwTXY5Ii8goxqrqHRNOvHR2vBISaVFSOWGqfsHS0GIBcXx8ETrdlJY3 I+1WLXtydrW8dzF+SCvGHsZYgBq+6z X-Developer-Key: i=jack@suse.cz; a=openpgp; fpr=93C6099A142276A28BBE35D815BC833443038D8C Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-3.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_MED,SPF_HELO_NONE, SPF_SOFTFAIL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org When manipulating xattr blocks, we can deadlock infinitely looping inside ext4_xattr_block_set() where we constantly keep finding xattr block for reuse in mbcache but we are unable to reuse it because its reference count is too big. This happens because cache entry for the xattr block is marked as reusable (e_reusable set) although its reference count is too big. When this inconsistency happens, this inconsistent state is kept indefinitely and so ext4_xattr_block_set() keeps retrying indefinitely. The inconsistent state is caused by non-atomic update of e_reusable bit. e_reusable is part of a bitfield and e_reusable update can race with update of e_referenced bit in the same bitfield resulting in loss of one of the updates. Fix the problem by using atomic bitops instead. CC: stable@vger.kernel.org Fixes: 6048c64b2609 ("mbcache: add reusable flag to cache entries") Reported-and-tested-by: Jeremi Piotrowski Reported-by: Thilo Fromm Link: https://lore.kernel.org/r/c77bf00f-4618-7149-56f1-b8d1664b9d07@linux.microsoft.com/ Signed-off-by: Jan Kara --- fs/ext4/xattr.c | 4 ++-- fs/mbcache.c | 14 ++++++++------ include/linux/mbcache.h | 9 +++++++-- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 800ce5cdb9d2..08043aa72cf1 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -1281,7 +1281,7 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, ce = mb_cache_entry_get(ea_block_cache, hash, bh->b_blocknr); if (ce) { - ce->e_reusable = 1; + set_bit(MBE_REUSABLE_B, &ce->e_flags); mb_cache_entry_put(ea_block_cache, ce); } } @@ -2042,7 +2042,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, } BHDR(new_bh)->h_refcount = cpu_to_le32(ref); if (ref == EXT4_XATTR_REFCOUNT_MAX) - ce->e_reusable = 0; + clear_bit(MBE_REUSABLE_B, &ce->e_flags); ea_bdebug(new_bh, "reusing; refcount now=%d", ref); ext4_xattr_block_csum_set(inode, new_bh); diff --git a/fs/mbcache.c b/fs/mbcache.c index e272ad738faf..2a4b8b549e93 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -100,8 +100,9 @@ int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key, atomic_set(&entry->e_refcnt, 2); entry->e_key = key; entry->e_value = value; - entry->e_reusable = reusable; - entry->e_referenced = 0; + entry->e_flags = 0; + if (reusable) + set_bit(MBE_REUSABLE_B, &entry->e_flags); head = mb_cache_entry_head(cache, key); hlist_bl_lock(head); hlist_bl_for_each_entry(dup, dup_node, head, e_hash_list) { @@ -165,7 +166,8 @@ static struct mb_cache_entry *__entry_find(struct mb_cache *cache, while (node) { entry = hlist_bl_entry(node, struct mb_cache_entry, e_hash_list); - if (entry->e_key == key && entry->e_reusable && + if (entry->e_key == key && + test_bit(MBE_REUSABLE_B, &entry->e_flags) && atomic_inc_not_zero(&entry->e_refcnt)) goto out; node = node->next; @@ -284,7 +286,7 @@ EXPORT_SYMBOL(mb_cache_entry_delete_or_get); void mb_cache_entry_touch(struct mb_cache *cache, struct mb_cache_entry *entry) { - entry->e_referenced = 1; + set_bit(MBE_REFERENCED_B, &entry->e_flags); } EXPORT_SYMBOL(mb_cache_entry_touch); @@ -309,9 +311,9 @@ static unsigned long mb_cache_shrink(struct mb_cache *cache, entry = list_first_entry(&cache->c_list, struct mb_cache_entry, e_list); /* Drop initial hash reference if there is no user */ - if (entry->e_referenced || + if (test_bit(MBE_REFERENCED_B, &entry->e_flags) || atomic_cmpxchg(&entry->e_refcnt, 1, 0) != 1) { - entry->e_referenced = 0; + clear_bit(MBE_REFERENCED_B, &entry->e_flags); list_move_tail(&entry->e_list, &cache->c_list); continue; } diff --git a/include/linux/mbcache.h b/include/linux/mbcache.h index 2da63fd7b98f..97e64184767d 100644 --- a/include/linux/mbcache.h +++ b/include/linux/mbcache.h @@ -10,6 +10,12 @@ struct mb_cache; +/* Cache entry flags */ +enum { + MBE_REFERENCED_B = 0, + MBE_REUSABLE_B +}; + struct mb_cache_entry { /* List of entries in cache - protected by cache->c_list_lock */ struct list_head e_list; @@ -26,8 +32,7 @@ struct mb_cache_entry { atomic_t e_refcnt; /* Key in hash - stable during lifetime of the entry */ u32 e_key; - u32 e_referenced:1; - u32 e_reusable:1; + unsigned long e_flags; /* User provided value - stable during lifetime of the entry */ u64 e_value; }; -- 2.35.3