From nobody Mon Sep 28 15:34:28 2026 Received: from zg8tmtyylji0my4xnjqumte4.icoremail.net (zg8tmtyylji0my4xnjqumte4.icoremail.net [162.243.164.118]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 7EB9C440A38; Thu, 20 Aug 2026 12:27:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=162.243.164.118 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787228857; cv=none; b=RTZCOnhkjsafFV5nx2uWKl2QwLgVFgGZSJro0oy8a6mjhkBpSRQVnlOuoU0VsLqJ5bBqdKce9hVpLR0NaxsPUb4GG+K/udfpUB6X53vVNeOIHrEKsw2vwxCBVabKSyB4yme47kNfykcifi6bqeTqIvcH5VaBncLPEHbzaPezlt8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787228857; c=relaxed/simple; bh=Ooy7rgIfZVZAAua0ycOet7ai6bc4H9+SI56LFkaaqHI=; h=Date:From:To:Cc:Subject:Content-Type:MIME-Version:Message-ID; b=WeHR0tXkPosf0R8tQ4qNxCs5TgrF14L/RPHaWRJhGXKIgped6QHryjoxgxg2xLN+s4J3yGMnkSmRHGOsAxWh5WL3J3NXcHNWYVK8oLgXHXU2fnJIrT/Bmi9vo7Pox7HI2rmDr3Fd+KLRfKzxajLYdUdwLuW22bueknE9NGEhv4c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=zju.edu.cn; spf=pass smtp.mailfrom=zju.edu.cn; arc=none smtp.client-ip=162.243.164.118 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=zju.edu.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=zju.edu.cn Received: from zju.edu.cn (unknown [10.190.161.59]) by mtasvr (Coremail) with SMTP id _____wDHsH6r8oZqn8StAA--.5474S3; Thu, 20 Aug 2026 20:27:24 +0800 (CST) Received: from stitch$zju.edu.cn ( [10.190.161.59] ) by ajax-webmail-mail-app4 (Coremail) ; Thu, 20 Aug 2026 20:27:23 +0800 (GMT+08:00) Date: Thu, 20 Aug 2026 20:27:23 +0800 (GMT+08:00) X-CM-HeaderCharset: UTF-8 From: "Jiacheng Xu" To: "Chris Mason" Cc: "David Sterba" , linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] btrfs: drain sysfs callbacks before stopping transaction kthread X-Priority: 3 X-Mailer: Coremail Webmail Server Version 2025.3-cmXT6 build 20260617(6f868824) Copyright (c) 2002-2026 www.mailtech.cn zju.edu.cn Content-Transfer-Encoding: quoted-printable Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <20b09e24.16b27.1a01f23ee08.Coremail.stitch@zju.edu.cn> X-Coremail-Locale: zh_CN X-CM-TRANSID: zi_KCgDnyzSr8oZqtM1UAw--.43845W X-CM-SenderInfo: qtrxiiaqttimo62m3hxhgxhubq/1tbiAwcJC2qGXxcHhQACsi X-CM-DELIVERINFO: =?B?fVjDPQXKKxbFmtjJiESix3B1w3tMoM3snk/k5SVzZVydjEqe1eefKHnLf95EnB4iem egW6OtOZBcKG2svvn9tKcPsEqSZfH/rhUZ82UzTuhwLO74Dz+v9QxEDui1mfkxx9Nefk9s KyqtwbrnuvvWpKKloq3IMfiAvDwR5BpmDsnllcaupvLmhX4F+HZI5p9ebtxsrw== X-Coremail-Antispam: 1Uk129KBj93XoWxtr4kCFy5XFWrtryrAFyUtwc_yoWxJr45pr 4rJr1YgrWDJrsrGw4xCa18Kw4Sqr4vkw4DGrZavayftw4qy34aqryvka48Ar1YyrWkCF4j vr18Aw15JFsrCFcCm3ZEXasCq-sJn29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7KY7ZEXa sCq-sGcSsGvfJ3Ic02F40EFcxC0VAKzVAqx4xG6I80ebIjqfuFe4nvWSU5nxnvy29KBjDU 0xBIdaVrnRJUUUPCb4IE77IF4wAFF20E14v26r1j6r4UM7CY07I20VC2zVCF04k26cxKx2 IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48v e4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_tr0E3s1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI 0_Gr1j6F4UJwA2z4x0Y4vEx4A2jsIE14v26rxl6s0DM28EF7xvwVC2z280aVCY1x0267AK xVW0oVCq3wAS0I0E0xvYzxvE52x082IY62kv0487Mc804VCY07AIYIkI8VC2zVCFFI0UMc 02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7IYx2IY67AKxVWUJVWUGwAv7VC2z280aVAF wI0_Jr0_Gr1lOx8S6xCaFVCjc4AY6r1j6r4UM4x0Y48IcxkI7VAKI48JM4x0Y48IcxkI7V AKI48G6xCjnVAKz4kxM4xvF2IEb7IF0Fy264kE64k0F24lFcxC0VAYjxAxZF0Ex2IqxwCF 04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14v26r1j6r 18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_JF0_Jw1lIxkGc2Ij64vI r41lIxAIcVC0I7IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Jr0_Gr 1lIxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r1j6r4UMIIF0xvE x4A2jsIEc7CjxVAFwI0_Gr0_Gr1UMVCEFcxC0VAYjxAxZFUvcSsGvfC2KfnxnUUI43ZEXa 7IU86OJ7UUUUU== Content-Type: text/plain; charset="utf-8" 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. Apply the same ordering to the open_ctree() failure path when the transaction kthread has already been created. Tested-by: Jiacheng Xu Signed-off-by: Jiacheng Xu --- 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 =3D 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 =3D 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 bt= rfs_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 acti= ve + * callbacks during removal, so this must be done before stopping any kthr= ead + * which can be woken up by those callbacks. + */ +void btrfs_sysfs_remove_mounted_attrs(struct btrfs_fs_info *fs_info) { struct kobject *fsid_kobj =3D &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);