From: Su Yue <l@damenly.org>
To: Qu Wenruo <wqu@suse.com>
Cc: linux-btrfs@vger.kernel.org, Su Yue <glass.su@suse.com>,
stable@vger.kernel.org
Subject: Re: [PATCH] btrfs: do not trim a device which is not writeable
Date: Tue, 02 Jun 2026 13:38:48 +0800 [thread overview]
Message-ID: <cxy9qz6f.fsf@damenly.org> (raw)
In-Reply-To: <0d25653c3bc93726e259dbb9d01559c4cfdf47ac.1780373081.git.wqu@suse.com> (Qu Wenruo's message of "Tue, 2 Jun 2026 13:34:46 +0930")
On Tue 02 Jun 2026 at 13:34, Qu Wenruo <wqu@suse.com> wrote:
> [BUG]
> There is a bug report that btrfs/242 can randomly fail with the
> following NULL pointer dereference:
>
> run fstests btrfs/242 at 2026-06-01 10:25:08
> BTRFS: device fsid d4d7f234-487c-4787-88e4-47a8b68c9874 devid 1
> transid 9 /dev/sdc (8:32) scanned by mount (122609)
> BTRFS info (device sdc): first mount of filesystem
> d4d7f234-487c-4787-88e4-47a8b68c9874
> BTRFS info (device sdc): using crc32c checksum algorithm
> BTRFS warning (device sdc): devid 2 uuid
> fbe72d72-3272-482d-80fb-ab88ed398192 is missing
> BTRFS warning (device sdc): devid 2 uuid
> fbe72d72-3272-482d-80fb-ab88ed398192 is missing
> BTRFS info (device sdc): allowing degraded mounts
> BTRFS info (device sdc): turning on async discard
> BTRFS info (device sdc): enabling free space tree
> Unable to handle kernel NULL pointer dereference at virtual
> address 0000000000000018
> user pgtable: 4k pages, 48-bit VAs, pgdp=000000013fd6b000
> CPU: 4 UID: 0 PID: 122625 Comm: fstrim Not tainted
> 7.0.10-2-default #1 PREEMPT(full) openSUSE Tumbleweed
> e9a5f6b24978fba3bf015a992f865837fdfff3dd
> Hardware name: QEMU KVM Virtual Machine, BIOS
> edk2-20250812-19.fc42 08/12/2025
> pstate: 01400005 (nzcv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--)
> pc : btrfs_trim_fs+0x34c/0xa00 [btrfs]
> lr : btrfs_trim_fs+0x1f0/0xa00 [btrfs]
> Call trace:
> btrfs_trim_fs+0x34c/0xa00 [btrfs
> f02c1d570ceea621c69d302ba75dd61868083840] (P)
> btrfs_ioctl_fitrim+0xe8/0x178 [btrfs
> f02c1d570ceea621c69d302ba75dd61868083840]
> btrfs_ioctl+0xdd4/0x2bd8 [btrfs
> f02c1d570ceea621c69d302ba75dd61868083840]
> __arm64_sys_ioctl+0xac/0x108
> invoke_syscall.constprop.0+0x5c/0xd0
> el0_svc_common.constprop.0+0x40/0xf0
> do_el0_svc+0x24/0x40
> el0_svc+0x40/0x1d0
> el0t_64_sync_handler+0xa0/0xe8
> el0t_64_sync+0x1b0/0x1b8
> Code: 17ffff83 f94017e0 f9002be0 f9402ea0 (f9400c00)
> ---[ end trace 0000000000000000 ]---
>
> Also the reporter is very kind to test the following ASSERT()
> added to
> btrfs_trim_free_extents_throttle():
>
> ASSERT(device->bdev,
> "devid=%llu path=%s dev_state=0x%lx\n",
> device->devid, btrfs_dev_name(device),
> device->dev_state);
>
> And it shows the following output:
>
> assertion failed: device->bdev, in extent-tree.c:6630 (devid=2
> path=/dev/sdd dev_state=0x82)
>
> Which means the device->bdev is NULL, and the dev_state is
> BTRFS_DEV_STATE_IN_FS_METADATA | BTRFS_DEV_STATE_ITEM_FOUND,
> without
> BTRFS_DEV_STATE_WRITEABLE flag set.
>
> [CAUSE]
> The pc points to the following call chain:
>
> btrfs_trim_fs()
> |- btrfs_trim_free_extents()
> |- btrfs_trim_free_extents_throttle()
> |- bdev_max_discard_sectors(device->bdev)
>
> So the NULL pointer dereference is caused by device->bdev being
> NULL.
>
> This looks impossible by a quick glance, as just before calling
> btrfs_trim_free_extents_throttle(), we have skipped any device
> that has
> BTRFS_DEV_STATE_MISSING flag set.
>
> However in this particular case, there is a window where the
> missing
> device is later re-scanned, causing btrfs to remove the
> BTRFS_DEV_STATE_MISSING flag:
>
> btrfs_control_ioctl()
> |- btrfs_scan_one_device()
> |- device_list_add()
> |- rcu_assign_pointer(device->name, name);
> | This updates the missing device's path to the new good
> path.
> |
> |- clear_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state)
> This removes the BTRFS_DEV_STATE_MISSING flag.
>
> This allows the missing device to re-appear and clear the
> BTRFS_DEV_STATE_MISSING flag.
> However the device still does not have the
> BTRFS_DEV_STATE_WRITEABLE
> flag set, nor is its bdev pointer updated.
>
> The bdev pointer remains NULL, triggering the crash later.
>
> [FIX]
> This is a big de-synchronization between BTRFS_DEV_STATE_MISSING
> and
> device->bdev pointer, and shows a gap in btrfs's
> re-appearing-device
> handling.
>
> The proper handling of re-appearing device will need quite some
> extra
> work, which is out of the context of this small fix.
>
> Thankfully the regular bbio submission path has already handled
> it well
> by checking if the device->bdev is NULL before submitting.
>
> So here we just fix the crash by checking if the device is
> writeable and
> has a bdev pointer before calling bdev_max_discard_sectors().
>
> Reported-by: Su Yue <glass.su@suse.com>
> Link:
> https://lore.kernel.org/linux-btrfs/wlwir19t.fsf@damenly.org/
> Cc: stable@vger.kernel.org # 5.10+
> Signed-off-by: Qu Wenruo <wqu@suse.com>
>
Thanks. No crash happens on my side after applying this patch.
--
Su
> ---
> fs/btrfs/extent-tree.c | 13 +++++++++----
> 1 file changed, 9 insertions(+), 4 deletions(-)
>
> diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
> index 6030cdbdb742..f3c3eb508f86 100644
> --- a/fs/btrfs/extent-tree.c
> +++ b/fs/btrfs/extent-tree.c
> @@ -6624,12 +6624,17 @@ static int
> btrfs_trim_free_extents_throttle(struct btrfs_device *device,
>
> *trimmed = 0;
>
> - /* Discard not supported = nothing to do. */
> - if (!bdev_max_discard_sectors(device->bdev))
> + /*
> + * The caller only filters out MISSING devices, but a device
> that was
> + * missing at mount and later rescanned has MISSING cleared
> while
> + * bdev is still NULL and WRITEABLE is still unset. Skip those
> here.
> + */
> + if (!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)
> ||
> + !device->bdev)
> return 0;
>
> - /* Not writable = nothing to do. */
> - if (!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state))
> + /* Discard not supported = nothing to do. */
> + if (!bdev_max_discard_sectors(device->bdev))
> return 0;
>
> /* No free space = nothing to do. */
next prev parent reply other threads:[~2026-06-02 5:44 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-02 4:04 [PATCH] btrfs: do not trim a device which is not writeable Qu Wenruo
2026-06-02 5:38 ` Su Yue [this message]
2026-06-02 10:11 ` Filipe Manana
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=cxy9qz6f.fsf@damenly.org \
--to=l@damenly.org \
--cc=glass.su@suse.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=stable@vger.kernel.org \
--cc=wqu@suse.com \
/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