From patchwork Fri Jan 2 00:50:44 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1178 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1767315136; bh=VEkrcGz3tFAEm1Y+zLG9A4cvsoweE2xrjv6Ea0bLkrY=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=bLRPVVENkncUTa+ZBPW2OpdbYPRAyXhQFtXAUGMdWZB93TFfiqZdxjkDGiFS0buwV IwAcVjo1PUf3o4Zy/RYf3PluSuQKiTsixrpoE0ctcd2wqtNXeWg4u9qySUzUXwk3Ce RzsvEe9wfdYsqCUsCDeg/VuG8iAltH5gEOqNboCxTQZC5+oJXy6tRHGcesYi1SVPmI e5KXJFlAEjjcsq+OKHumh3mjHWaaGJx+9ElU8sg3tuiv1CVskBf5lqKGAmZTpDv+5P SuR8DHn6pRkL8ZOPgyEceog1tYe+T/4NjwStn/VfpPrAC+igvVZ5iitoce2+HuJ29Y x5fFBFeOLdJ6Q== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id E683E69010 for ; Thu, 1 Jan 2026 17:52:16 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id OEjqLUl1mt0z for ; Thu, 1 Jan 2026 17:52:16 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1767315136; bh=VEkrcGz3tFAEm1Y+zLG9A4cvsoweE2xrjv6Ea0bLkrY=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=bLRPVVENkncUTa+ZBPW2OpdbYPRAyXhQFtXAUGMdWZB93TFfiqZdxjkDGiFS0buwV IwAcVjo1PUf3o4Zy/RYf3PluSuQKiTsixrpoE0ctcd2wqtNXeWg4u9qySUzUXwk3Ce RzsvEe9wfdYsqCUsCDeg/VuG8iAltH5gEOqNboCxTQZC5+oJXy6tRHGcesYi1SVPmI e5KXJFlAEjjcsq+OKHumh3mjHWaaGJx+9ElU8sg3tuiv1CVskBf5lqKGAmZTpDv+5P SuR8DHn6pRkL8ZOPgyEceog1tYe+T/4NjwStn/VfpPrAC+igvVZ5iitoce2+HuJ29Y x5fFBFeOLdJ6Q== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id D55A769007 for ; Thu, 1 Jan 2026 17:52:16 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1767315134; bh=1jHgxVGPUE+J5Rb/fD+bFmsYxGEL++WDvB2BjqUvMuM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gX4/4ZIz8JYPhHDXkfndQ+WIOlYwtAcFmfOy4uKocdTvcF4xX7R8qfHHm1rOmQm7q wdBTyYiTMZzr1sCXp2gi0ujEvevgBwCceGGSf83rfhC7zTUbzgZ+aFKvcnwGRVSODJ uEK+QsSziE7I4rpYa4pUwM9/+Egt/C1kIJfmkWwCcP+EJVIQ92Zb6dEH2pddCAun6e Y2dZhjGtmS5Gfvqw0/DDH+NYQ4kfE2LF3m2r3eOK9lz7QgVmYY0ahCM0vNaBlx+MXM xubAnGe+pWg+P+xORC5iCN//II0Gk4UaFmy4BpoR1efDrjLKOBt9pCZq7uBU4uFZJh yMau830zmlzbw== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 978206901F; Thu, 1 Jan 2026 17:52:14 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id QMGp86RYOYw7; Thu, 1 Jan 2026 17:52:14 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1767315126; bh=326KITdzvMFyq+QDv1q+q+QTPMQ6JejK9C8ZhDQ1yIY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VyNZw1QIa4WnzpFkwaGJonZobXW1ylBjCvIhuCSbfgZizxit2+Tc9O75xosHe9vfb axZmoGMr6gk/+Q1mAyMZD+XGm8t5PdJ4CdiYsTkxRUhxaLq7kmlW/r2EDF//f8avwQ VZq58SwQpHxrbKq2O1Cm2UeP6sSNvCBew+D/Kq8UKi7xjMYZMWefZ2vP5MRnCEhny3 1MFMoWetWMA6+P2znXRHbRzyHpdR4/nty7uT4Q3crjTJSviAbQCnYtAMB0lKCTOi33 EAfympDuR7vjEuutnVHxZXRI3M8PVin0lfOi7qtIZQhdu7p4pEIhJilVy92BB7LgHB 4jEX2h1k0ROcQ== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 4A7F568FFD; Thu, 1 Jan 2026 17:52:06 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Thu, 1 Jan 2026 17:50:44 -0700 Message-ID: <20260102005112.552256-15-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260102005112.552256-1-sjg@u-boot.org> References: <20260102005112.552256-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: 4D3EMC3X7DFAVLGKJVYM6FZDBCET2RMS X-Message-ID-Hash: 4D3EMC3X7DFAVLGKJVYM6FZDBCET2RMS X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Heinrich Schuchardt , Simon Glass , Claude X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH v2 14/30] ext4l: Fix a few problems with handling bh_cache List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Several buffer cache issues cause problems when remounting: 1. bh_cache_insert() only checks block number, but the same block can be read with different sizes (e.g. superblock at 1K vs 4K). Check both block number and size when determining if already cached. 2. bh_cache_clear() leaves stale buffer references, causing memory leaks. Force the reference count to 1 before releasing since ext4 code won't access these buffers after unmount. 3. brelse() frees buffer heads when the reference count reaches zero, but cached buffer heads should only be freed by bh_cache_clear() during unmount. This causes a double-free. Add a BH_Cached flag to distinguish cached buffers from temporary ones: set BH_Cached in bh_cache_insert() when adding to cache, and in brelse() only free non-cached buffers when count reaches zero. Also fix a bit conflict: BH_OwnsData was using BH_JBDPrivateStart which conflicts with BH_BITMAP_UPTODATE in ext4.h. Move U-Boot private bits to start at BH_JBDPrivateStart + 1. Co-developed-by: Claude Signed-off-by: Simon Glass --- (no changes since v1) fs/ext4l/ext4_uboot.h | 15 ++++++++++++--- fs/ext4l/support.c | 28 ++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/fs/ext4l/ext4_uboot.h b/fs/ext4l/ext4_uboot.h index 78d44faa0db..588670a8b62 100644 --- a/fs/ext4l/ext4_uboot.h +++ b/fs/ext4l/ext4_uboot.h @@ -521,12 +521,21 @@ struct sb_writers { #include /* - * U-Boot: marks buffer owns b_data and should free it. - * Use BH_JBDPrivateStart to avoid conflicts with JBD2 state bits. + * U-Boot buffer head private bits. + * + * Start at BH_JBDPrivateStart + 1 because ext4.h uses BH_JBDPrivateStart + * for BH_BITMAP_UPTODATE. */ -#define BH_OwnsData BH_JBDPrivateStart +#define BH_OwnsData (BH_JBDPrivateStart + 1) BUFFER_FNS(OwnsData, ownsdata) +/* + * U-Boot: marks buffer is in the buffer cache. + * Cached buffers are freed by bh_cache_clear(), not brelse(). + */ +#define BH_Cached (BH_JBDPrivateStart + 2) +BUFFER_FNS(Cached, cached) + /* Forward declare for get_block_t */ struct inode; struct buffer_head; diff --git a/fs/ext4l/support.c b/fs/ext4l/support.c index 7f2bea4ca06..0f68746d99a 100644 --- a/fs/ext4l/support.c +++ b/fs/ext4l/support.c @@ -258,9 +258,10 @@ static void bh_cache_insert(struct buffer_head *bh) unsigned int hash = bh_cache_hash(bh->b_blocknr); struct bh_cache_entry *entry; - /* Check if already in cache */ + /* Check if already in cache - must match block AND size */ for (entry = bh_cache[hash]; entry; entry = entry->next) { - if (entry->bh && entry->bh->b_blocknr == bh->b_blocknr) + if (entry->bh && entry->bh->b_blocknr == bh->b_blocknr && + entry->bh->b_size == bh->b_size) return; /* Already cached */ } @@ -272,6 +273,9 @@ static void bh_cache_insert(struct buffer_head *bh) entry->next = bh_cache[hash]; bh_cache[hash] = entry; + /* Mark as cached so brelse() knows not to free it */ + set_buffer_cached(bh); + /* Add a reference to keep the buffer alive in cache */ atomic_inc(&bh->b_count); } @@ -316,7 +320,12 @@ void bh_cache_clear(void) struct buffer_head *bh = entry->bh; bh_clear_stale_jbd(bh); - /* Release the cache's reference */ + /* + * Force count to 1 so the buffer will be freed. + * On unmount, ext4 code won't access these + * buffers again, so extra references are stale. + */ + atomic_set(&bh->b_count, 1); if (atomic_dec_and_test(&bh->b_count)) free_buffer_head(bh); } @@ -629,13 +638,24 @@ struct buffer_head *sb_bread(struct super_block *sb, sector_t block) /** * brelse() - Release a buffer_head * @bh: Buffer head to release + * + * Decrements the reference count on the buffer. Cached buffer heads are + * freed by bh_cache_clear() on unmount, so this just decrements the count. + * Non-cached buffers are freed when the count reaches zero. */ void brelse(struct buffer_head *bh) { if (!bh) return; - if (atomic_dec_and_test(&bh->b_count)) + /* + * If buffer has JBD attached, don't let ref count go to zero. + * The journal owns a reference and will clean up properly. + */ + if (buffer_jbd(bh) && atomic_read(&bh->b_count) <= 1) + return; + + if (atomic_dec_and_test(&bh->b_count) && !buffer_cached(bh)) free_buffer_head(bh); }