Linux kernel -stable discussions
 help / color / mirror / Atom feed
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. */

  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