From patchwork Sun Mar 30 06:47:31 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luis Chamberlain X-Patchwork-Id: 14032836 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id C3F89C36013 for ; Sun, 30 Mar 2025 06:47:58 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 5780028018A; Sun, 30 Mar 2025 02:47:52 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 3B157280188; Sun, 30 Mar 2025 02:47:52 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 0A45F28018D; Sun, 30 Mar 2025 02:47:51 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0017.hostedemail.com [216.40.44.17]) by kanga.kvack.org (Postfix) with ESMTP id 83F99280185 for ; Sun, 30 Mar 2025 02:47:51 -0400 (EDT) Received: from smtpin15.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay06.hostedemail.com (Postfix) with ESMTP id AD1ADB813C for ; Sun, 30 Mar 2025 06:47:52 +0000 (UTC) X-FDA: 83277287184.15.4DD0341 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) by imf25.hostedemail.com (Postfix) with ESMTP id 68B7EA0003 for ; Sun, 30 Mar 2025 06:47:50 +0000 (UTC) Authentication-Results: imf25.hostedemail.com; dkim=pass header.d=infradead.org header.s=bombadil.20210309 header.b=lBxP2tPR; dmarc=fail reason="No valid SPF, DKIM not aligned (relaxed)" header.from=kernel.org (policy=quarantine); spf=none (imf25.hostedemail.com: domain of mcgrof@infradead.org has no SPF policy when checking 198.137.202.133) smtp.mailfrom=mcgrof@infradead.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1743317271; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=WvkQNL4UoSpr5M5OPz09tyQKaqGswnC535CSvTx1frY=; b=uQp/xa2ISTdTQukZhM3hRaEyGHj9I33SuPc9SUTjA4no6XoplKBqCSbMO+5crVUtUgSHUl 4k3lfNU5CdHiVCsyLyCCXZW4ymouO0XsDzivQwUwbQkbfDmCs6PSxS+RbVwI6MGApHjxFC 92EFRIavpeS2Z05v1D736M02aPta0mI= ARC-Authentication-Results: i=1; imf25.hostedemail.com; dkim=pass header.d=infradead.org header.s=bombadil.20210309 header.b=lBxP2tPR; dmarc=fail reason="No valid SPF, DKIM not aligned (relaxed)" header.from=kernel.org (policy=quarantine); spf=none (imf25.hostedemail.com: domain of mcgrof@infradead.org has no SPF policy when checking 198.137.202.133) smtp.mailfrom=mcgrof@infradead.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1743317271; a=rsa-sha256; cv=none; b=Xom+uQoh6tfH9V3uUDTNfKy3+5hUm8Iev48GNLDATUBncUiqu+u5amDxxWYfk3rT0E/Pmw sEMm4mlORsoMnB68GA1Sb1wa30wcSQ2kZ3vNdHl9Lh9rO37t7plPky8eVEf0lRzSUpVNsp f/7wZTOwXxZKclUtPs+bp4HVEvEeJYM= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20210309; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=WvkQNL4UoSpr5M5OPz09tyQKaqGswnC535CSvTx1frY=; b=lBxP2tPRv807B6pteDVfoVeW5l t4xF5y51y4CUe/vc1YBpuGNECtVgw+G170yWqRio9Mv/QAem9zmMb4zZvbOBXaxM1MG+ViVD4JKwD ycA7sYi9LNkc3nzxgkPZyrgdzBa/BiTBP/R2rLjcNDAVfLBh95kcWnxkNdd4ErC3PkJQJQf67q1JL 9vZfG2UEQIPeOYARpuJm9XjpKWeyv8K0wfXS7ER2bATXEymH3woDQXvYRFhT9NVto9IAW1T5y/r2E /X/t2mnrOzTvAxzj5vBvz3ZvsnNAcUmLWNilcgb33fYF8dnFYD8C3Ljl4FbaoPmIJqSQN94PK5PJF h90GRUWg==; Received: from mcgrof by bombadil.infradead.org with local (Exim 4.98.1 #2 (Red Hat Linux)) id 1tymSJ-0000000FreC-2FwG; Sun, 30 Mar 2025 06:47:39 +0000 From: Luis Chamberlain To: brauner@kernel.org, jack@suse.cz, tytso@mit.edu, adilger.kernel@dilger.ca, linux-ext4@vger.kernel.org, riel@surriel.com Cc: willy@infradead.org, hannes@cmpxchg.org, oliver.sang@intel.com, dave@stgolabs.net, david@redhat.com, axboe@kernel.dk, hare@suse.de, david@fromorbit.com, djwong@kernel.org, ritesh.list@gmail.com, linux-fsdevel@vger.kernel.org, linux-block@vger.kernel.org, linux-mm@kvack.org, gost.dev@samsung.com, p.raghav@samsung.com, da.gomez@samsung.com, mcgrof@kernel.org Subject: [PATCH 2/3] fs/buffer: avoid races with folio migrations on __find_get_block_slow() Date: Sat, 29 Mar 2025 23:47:31 -0700 Message-ID: <20250330064732.3781046-3-mcgrof@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250330064732.3781046-1-mcgrof@kernel.org> References: <20250330064732.3781046-1-mcgrof@kernel.org> MIME-Version: 1.0 X-Rspamd-Server: rspam11 X-Rspamd-Queue-Id: 68B7EA0003 X-Stat-Signature: wa6ycqhuzzzadj4wrze86pgybnestqk8 X-Rspamd-Pre-Result: action=add header; module=dmarc; Action set by DMARC X-Rspam-User: X-Rspam: Yes X-HE-Tag: 1743317270-759693 X-HE-Meta: U2FsdGVkX18oRhI35W6Th4ZgVoE6CdvnDwnGYnk2dW/8ZtspuZQR9oNTLKVsoSPhpEjwH6MxS09Kgo87lEzX8pP5micg8ik6UQHmmxWWdb9LDrImIHMpm1PLBA0hqBbQC1FDtk5sP4pfCCECY2HHuL6NoSHmXrekF5fKNJ6LP1mMhTD112rnZVH+DvyKKzHR/eV/rgAZVapMB0FkyAx2GN5NJzYWz/ZdZiE68Bma94vbWzaGw14M8jMfS5T/eX2W7QM7RltoTQVXmuerQfaTjznuOKRJgizk7+I1Kbo4qetsFTxEwXQTBA7Vyj+TPsJ07L8NH88EPAKH1itmT6vQ77QvqhtQVHBxiYbNB8jtY2IraqVHGAxdMRlU/c5krH1NujgHLZshxS7YWsFkm5BYMylYp37g/mJRbf6fx4ms+2vJvf27RTZl2mkmYPg9unxmmGXlnvOlJx5t3UcFY9G84RywEPmoiwHZomVkKQSKreyOyhuhgNIIh/lf2djoT7eSa/xO0Zv2pxtHu9Gjh8B7bD/cXVK93s2I+5RloMNBrIE/KvdjB+db3RVUQW4PBZ6UmkOB0npDTzOkgRsge4om0tmyC5G+B978nNFDnvRbk26HAgu+SU2w5vD9nZvAwFwYcQfkjz5ACbcG5FD3vJjO1Th71j3jxBJBUML04FxPdhB4LaR5SQfduQaH7vVuJbcL8fNv6guDcQ2MeeH/d/CE5HA7WOv6LIn2h9tQZrrGsFJHsz6bIEoQIfzCx0mXza0iRsiM7wak/9Fmy91FCYZrm/FBkWJB5oe/ylf0I/OBn1A7VVG/zjoTxFegJU0r8hqUrI/guIDZ+RNgoUDdtSu/KdFiMpYZzlO28pOB0XpcNEhYV0gw9e8WiwX5aMRkouA0xT/BmNuPO6qRQDS2YUzzQsKcnTaI3eNF3Q/3JsbuHQL1N2C0z9o2zVkBg3OmfW+Fk2vPFucf3VB9vMTOn4b 0YYGBpaa 1/cbDeeioC/2+zRe9fqwCVGoUF+Xq2dtMNDTYXdCYqqhLMM2QQsf6DNNQObSmJldCkROpy+Y3N/lY6SWxg01B+eaeMIn65MKnI6KOQ7NyojDlqOIf1HAH1vBx3am0vnGDm31NgDo+WtmVm3sz+UkK2F5Z609fyrtodiDImAcMQ/We8D679k6Cl6mPofjmV0y+p69WpM0UPL6Y3lim8KfEGNo3XprgsgdIHIsbV1vAMPY8UkTZMw1GYHBB5jTC6WPlP/SyiqYaotI0S+HwMi24oAhnwaUXIX57gNy7kmNCMWpAnyOF7dIUkztn0sJYxNqvac+1VFHxAG44WRLhLzXzBB681mPHc4sISwQnPPt6U3B3NF8LoI3RaMJgr+5SkspB+2mMMT1+74VifujFwc7Ab4hxMxXF+YGD8SEOU4UWDC0J6TXC7a8y4V1SXCxmi0DGaINtuUJ9dfTjcPqK5xELVirbzfuzYCmbQ06gGE0I4Ev3CjM0vsfo88OTPcsExkGKUYNdbRZ4dC2J5G0xKb7x2dTcLjkHafEMIC65qTbtNZq2ri4Kcklf+Clkxm0ZU4XgkuieWKaW7IO40vXaFUDKG2suGQcFtmqhMm8bk085NXVhy+qllJVoU+uqHxBDOZpPx4rA+cyocyu+KKrU0JidSPmF4ZsPC6s8IARbgcsSUOOZVpd0trehq1Rr+w== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Filesystems which use buffer-heads where it cannot guarantees that the there are no other references to the folio, for example with a folio lock, must use buffer_migrate_folio_norefs() for the address space mapping migrate_folio() callback. There are only 3 filesystems which use this callback: 1) the block device cache 2) ext4 for its ext4_journalled_aops 3) nilfs2 The commit ebdf4de5642fb6 ("mm: migrate: fix reference check race between __find_get_block() and migration") added a spin lock to prevent races with page migration which ext4 users were reporting through the SUSE bugzilla (bnc#1137609 [0]). Although implicit, the spinlock is only held for users of buffer_migrate_folio_norefs() which was added by commit 89cb0888ca148 ("mm: migrate: provide buffer_migrate_page_norefs()") to support page migration on block device folios. Later commit dae999602eeb ("ext4: stop providing .writepage hook") made ext4_journalled_aops use the same callback. It is worth elaborating on why ext4 journalled aops uses this: so that buffers cannot be modified under jdb2's hands as that can cause data corruption. For example when commit code does writeout of transaction buffers in jbd2_journal_write_metadata_buffer(), we don't hold page lock or have page writeback bit set or have the buffer locked. So page migration code would go and happily migrate the page elsewhere while the copy is running thus corrupting data. Although we don't have exact traces of the filesystem corruption we can can reproduce fs corruption one ext4 by just removing the spinlock and stress testing the filesystem with generic/750, we eventually end up after 3 hours of testing with kdevops using libvirt on the ext4 profile ext4-4k. Things like the below as reported recently [1]: Mar 28 03:36:37 extra-ext4-4k unknown: run fstests generic/750 at 2025-03-28 03:36:37 <-- etc --> Mar 28 05:57:09 extra-ext4-4k kernel: EXT4-fs error (device loop5): ext4_get_first_dir_block:3538: inode #5174: comm fsstress: directory missing '.' Mar 28 06:04:43 extra-ext4-4k kernel: EXT4-fs warning (device loop5): ext4_empty_dir:3088: inode #5176: comm fsstress: directory missing '.' Mar 28 06:42:05 extra-ext4-4k kernel: EXT4-fs error (device loop5): __ext4_find_entry:1626: inode #5173: comm fsstress: checksumming directory block 0 Mar 28 08:16:43 extra-ext4-4k kernel: EXT4-fs error (device loop5): ext4_find_extent:938: inode #1104560: comm fsstress: pblk 4932229 bad header/extent: invalid magic - magic 8383, entries 33667, max 33667(0), depth 33667(0) The block device cache is a user of buffer_migrate_folio_norefs() and it supports large folios, in that case we can sleep on folio_mc_copy() on page migration on a cond_resched(). So we want to avoid requiring a spin lock even on the buffer_migrate_folio_norefs() case so to enable large folios on buffer-head folio migration. To address this we must avoid races with folio migration in a different way. This provides an alternative by avoiding giving away a folio in __find_get_block_slow() on folio migration candidates so to enable us to let us later rip out the spin_lock() held on the folio migration buffer_migrate_folio_norefs() path. We limit the scope of this sanity check only for filesystems which cannot provide any guarantees that there are no references to the folio, so only users of the folio migration callback buffer_migrate_folio_norefs(). Although we have no direct clear semantics to check if a folio is being evaluated for folio migration we know that folio migration happens LRU folios [2]. Since folio migration must not be called with folio_test_writeback() folios we can skip these folios as well. The other corner case we can be concerned is for a drive implement mops, but the docs indicate VM seems to use lru for that too. A real concern to have here is if the check is starving readers or writers who want to read a block into the page cache and it is part of the LRU. The path __getblk_slow() will first try __find_get_block() which uses __filemap_get_folio() without FGP_CREAT, and if it fails it will call grow_buffers() which calls again __filemap_get_folio() but with with FGP_CREAT now, but __filemap_get_folio() won't create a folio for us if it already exists. So if the folio was in LRU __getblk_slow() will essentially end up checking again for the folio until its gone from the page cache or migration ended, effectively preventing a race with folio migration which is what we want. This commit and the subsequent one prove to be an alternative to fix the filesystem corruption noted above. Link: https://bugzilla.suse.com/show_bug.cgi?id=1137609 # [0] Link: https://lkml.kernel.org/r/Z-ZwToVfJbdTVRtG@bombadil.infradead.org # [1] Link: https://docs.kernel.org/mm/page_migration.html # [2] Signed-off-by: Luis Chamberlain --- fs/buffer.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/buffer.c b/fs/buffer.c index c7abb4a029dc..a4e4455a6ce2 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -208,6 +208,15 @@ __find_get_block_slow(struct block_device *bdev, sector_t block) head = folio_buffers(folio); if (!head) goto out_unlock; + + if (folio->mapping->a_ops->migrate_folio && + folio->mapping->a_ops->migrate_folio == buffer_migrate_folio_norefs) { + if (folio_test_lru(folio) && + folio_test_locked(folio) && + !folio_test_writeback(folio)) + goto out_unlock; + } + bh = head; do { if (!buffer_mapped(bh))