From: Qu Wenruo <wqu@suse.com>
To: Jiacheng Xu <stitch@zju.edu.cn>, Chris Mason <clm@fb.com>
Cc: David Sterba <dsterba@suse.com>,
linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] btrfs: drain sysfs callbacks before stopping transaction kthread
Date: Fri, 21 Aug 2026 08:02:14 +0930 [thread overview]
Message-ID: <2252e770-a254-4971-9acc-c3768f3bb119@suse.com> (raw)
In-Reply-To: <20b09e24.16b27.1a01f23ee08.Coremail.stitch@zju.edu.cn>
在 2026/8/20 21:57, Jiacheng Xu 写道:
> btrfs_label_store() and btrfs_feature_attr_store() wake up the
> transaction kthread through fs_info->transaction_kthread.
>
> During filesystem teardown, close_ctree() stops the transaction kthread
> before removing the mounted filesystem's sysfs attributes. A concurrent
> sysfs write can therefore enter one of these callbacks after the kthread
> has been stopped and pass an invalid task pointer to wake_up_process().
>
> This results in a concurrent null-pointer dereference in
> try_to_wake_up(). The scheduler is not the root cause; the invalid
> transaction kthread pointer is used by a Btrfs sysfs callback during
> teardown.
>
> Split mounted sysfs cleanup into two stages. Remove attributes which may
> have store callbacks before stopping the transaction kthread. The
> remaining sysfs kobjects are removed at the original teardown point,
> after the kthread has been stopped.
Why not just simpliy reject sysfs write operations when the fs has
CLOSING_START or without FS_OPEN flags?
>
> Apply the same ordering to the open_ctree() failure path when the
> transaction kthread has already been created.
>
> Tested-by: Jiacheng Xu <stitch@zju.edu.cn>
> Signed-off-by: Jiacheng Xu <stitch@zju.edu.cn>
> ---
> fs/btrfs/disk-io.c | 16 ++++++++++++++--
> fs/btrfs/sysfs.c | 26 +++++++++++++++++++++-----
> fs/btrfs/sysfs.h | 3 +++
> 3 files changed, 38 insertions(+), 7 deletions(-)
>
> diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
> index 2f1666d9544e..4f5bcc576dc6 100644
> --- a/fs/btrfs/disk-io.c
> +++ b/fs/btrfs/disk-io.c
> @@ -3363,6 +3363,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
> struct btrfs_root *tree_root;
> struct btrfs_root *chunk_root;
> struct btrfs_root *remap_root;
> + bool sysfs_attrs_removed = false;
> int ret;
> int level;
>
> @@ -3780,6 +3781,9 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
> fail_qgroup:
> btrfs_free_qgroup_config(fs_info);
> fail_trans_kthread:
> + btrfs_sysfs_remove_mounted_attrs(fs_info);
> + sysfs_attrs_removed = true;
> +
> kthread_stop(fs_info->transaction_kthread);
> btrfs_cleanup_transaction(fs_info);
> btrfs_free_fs_roots(fs_info);
> @@ -3793,7 +3797,9 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
> filemap_write_and_wait(fs_info->btree_inode->i_mapping);
>
> fail_sysfs:
> - btrfs_sysfs_remove_mounted(fs_info);
> + if (!sysfs_attrs_removed)
> + btrfs_sysfs_remove_mounted_attrs(fs_info);
> + btrfs_sysfs_remove_mounted_kobjects(fs_info);
>
> fail_fsdev_sysfs:
> btrfs_sysfs_remove_fsid(fs_info->fs_devices);
> @@ -4318,6 +4324,9 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
>
> set_bit(BTRFS_FS_CLOSING_START, &fs_info->flags);
>
> + /* Drain sysfs callbacks before stopping the transaction kthread. */
> + btrfs_sysfs_remove_mounted_attrs(fs_info);
> +
> /*
> * If we had UNFINISHED_DROPS we could still be processing them, so
> * clear that bit and wake up relocation so it can stop.
> @@ -4538,7 +4547,7 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
> percpu_counter_sum(&fs_info->ordered_bytes));
>
> - btrfs_sysfs_remove_mounted(fs_info);
> + btrfs_sysfs_remove_mounted_kobjects(fs_info);
> btrfs_sysfs_remove_fsid(fs_info->fs_devices);
>
> btrfs_put_block_group_cache(fs_info);
>
> diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
> index 0d14570c8bc2..d90d76a152e9 100644
> --- a/fs/btrfs/sysfs.c
> +++ b/fs/btrfs/sysfs.c
> @@ -1707,11 +1707,23 @@ static void btrfs_sysfs_remove_fs_devices(struct btrfs_fs_devices *fs_devices)
> }
> }
>
> -void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info)
> +/*
> + * Remove attributes which may have store callbacks. kernfs waits for active
> + * callbacks during removal, so this must be done before stopping any kthread
> + * which can be woken up by those callbacks.
> + */
> +void btrfs_sysfs_remove_mounted_attrs(struct btrfs_fs_info *fs_info)
> {
> struct kobject *fsid_kobj = &fs_info->fs_devices->fsid_kobj;
>
> - sysfs_remove_link(fsid_kobj, "bdi");
> + addrm_unknown_feature_attrs(fs_info, false);
> + sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group);
> + sysfs_remove_files(fsid_kobj, btrfs_attrs);
> +}
> +
> +static void btrfs_sysfs_remove_mounted_dirs(struct btrfs_fs_info *fs_info)
> +{
> + sysfs_remove_link(&fs_info->fs_devices->fsid_kobj, "bdi");
>
> if (fs_info->space_info_kobj) {
> sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs);
> @@ -1730,9 +1742,18 @@ void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info)
> kobject_put(fs_info->debug_kobj);
> }
> #endif
> - addrm_unknown_feature_attrs(fs_info, false);
> - sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group);
> - sysfs_remove_files(fsid_kobj, btrfs_attrs);
> +}
> +
> +void btrfs_sysfs_remove_mounted_kobjects(struct btrfs_fs_info *fs_info)
> +{
> + btrfs_sysfs_remove_mounted_dirs(fs_info);
> + btrfs_sysfs_remove_fs_devices(fs_info->fs_devices);
> +}
> +
> +void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info)
> +{
> + btrfs_sysfs_remove_mounted_dirs(fs_info);
> + btrfs_sysfs_remove_mounted_attrs(fs_info);
> btrfs_sysfs_remove_fs_devices(fs_info->fs_devices);
> }
>
> diff --git a/fs/btrfs/sysfs.h b/fs/btrfs/sysfs.h
> index 05498e5346c3..0d008fc8f1b8 100644
> --- a/fs/btrfs/sysfs.h
> +++ b/fs/btrfs/sysfs.h
> @@ -35,6 +35,9 @@ void btrfs_kobject_uevent(struct block_device *bdev, enum kobject_action action)
> int __init btrfs_init_sysfs(void);
> void __cold btrfs_exit_sysfs(void);
> int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info);
> +void btrfs_sysfs_remove_mounted_attrs(struct btrfs_fs_info *fs_info);
> +void btrfs_sysfs_remove_mounted_kobjects(struct btrfs_fs_info *fs_info);
> void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info);
> void btrfs_sysfs_add_block_group_type(struct btrfs_block_group *cache);
> int btrfs_sysfs_add_space_info_type(struct btrfs_space_info *space_info);
next prev parent reply other threads:[~2026-08-20 22:32 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-20 12:27 [PATCH] btrfs: drain sysfs callbacks before stopping transaction kthread Jiacheng Xu
2026-08-20 22:32 ` Qu Wenruo [this message]
2026-08-21 4:30 ` Jiacheng Xu
2026-08-21 5:21 ` Qu Wenruo
2026-08-21 6:49 ` Jiacheng Xu
2026-08-21 7:08 ` Qu Wenruo
2026-08-21 9:05 ` Qu Wenruo
2026-08-22 3:41 ` [PATCH v2 0/2] btrfs: delay mounted sysfs attributes until mount is ready Jiacheng Xu
2026-08-22 3:42 ` [PATCH v2 1/2] btrfs: sysfs: factor out mounted fsid attribute Jiacheng Xu
2026-08-22 3:46 ` [PATCH v2 2/2] btrfs: delay mounted sysfs attributes until mount is ready Jiacheng Xu
2026-08-22 4:57 ` [PATCH v2 0/2] " Qu Wenruo
2026-08-22 5:39 ` Jiacheng Xu
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=2252e770-a254-4971-9acc-c3768f3bb119@suse.com \
--to=wqu@suse.com \
--cc=clm@fb.com \
--cc=dsterba@suse.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=stitch@zju.edu.cn \
/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