From nobody Mon Sep 28 11:40:13 2026 Received: from azure-sdnproxy.icoremail.net (azure-sdnproxy.icoremail.net [52.187.6.220]) by smtp.subspace.kernel.org (Postfix) with ESMTP id C7E8B5695; Sat, 22 Aug 2026 03:42:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=52.187.6.220 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787370164; cv=none; b=RFiUAK4fXjjRKLG9v0RMmv/dyFaArT2XidN7/BKRfopPvCbPifNqKdmh3f79mK4D3vP70LpbZcKiEk13MvpOwIFAIrUAkE2iuhT5z4BJf8JBqpUYVnPQElAetj1+emBOyBeL9DnkEHAOeinmtLbYLVpYGqrMZ3JTw0uWSGy7aK8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787370164; c=relaxed/simple; bh=yNWUvRhVM74P/BBYCEInGvKw0BQ9u85O7uSPlxg6Xhg=; h=Date:From:To:Cc:Subject:In-Reply-To:References:Content-Type: MIME-Version:Message-ID; b=lOAf88diDBBtsbEmEEnVo6zwsOVI1LIqCrhMDF5SPQrimVaw+NOJbcXuLpj+QAqracbuUDGu1Ev7sFQCrgPjiEVuwN9Y8AExPphXNCZEe+OLm89ZbD6RZrXV/85VYoOTKcd2xJn6D+BDLB8uJOHfRC2556RkCfpIZgKMjuiKWE0= 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=52.187.6.220 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 _____wBHAzatGolqTke0AA--.18298S3; Sat, 22 Aug 2026 11:42:37 +0800 (CST) Received: from stitch$zju.edu.cn ( [10.190.161.59] ) by ajax-webmail-mail-app3 (Coremail) ; Sat, 22 Aug 2026 11:42:37 +0800 (GMT+08:00) Date: Sat, 22 Aug 2026 11:42:37 +0800 (GMT+08:00) X-CM-HeaderCharset: UTF-8 From: "Jiacheng Xu" To: wqu@suse.com Cc: linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 1/2] btrfs: sysfs: factor out mounted fsid attribute 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 In-Reply-To: <698e5039.16b92.1a0278ef67b.Coremail.stitch@zju.edu.cn> References: <20b09e24.16b27.1a01f23ee08.Coremail.stitch@zju.edu.cn> <698e5039.16b92.1a0278ef67b.Coremail.stitch@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: <2f9846bb.16b97.1a027903498.Coremail.stitch@zju.edu.cn> X-Coremail-Locale: zh_CN X-CM-TRANSID: zS_KCgBngHKtGolqHpaUBA--.20553W X-CM-SenderInfo: qtrxiiaqttimo62m3hxhgxhubq/1tbiAwULC2qJAhcBLQACse X-CM-DELIVERINFO: =?B?6IJg7gXKKxbFmtjJiESix3B1w3tMoM3snk/k5SVzZVydjEqe1eefKHnLf95EnB4iem egW1kKDTffj9RZcKrT0I+755sYiG5vbrfqfRE8il7acou5fqUuWUK9C2iaWOoJ8C0g3YNR +LQK/ezviA7VgEN1gl4ahRlqZpdBHnO8CIQaoSFlf2n5ZXGwAZH77hngzzpiIg== X-Coremail-Antispam: 1Uk129KBj9fXoW3KFWrCry5CFW3XF1kuFyfAFc_yoW8Jw1UAo W0gr17X3yrtr10yr4kCFs7Gw4Du348Ka1ktr4F93s3u3Wkt3Z8Zry5KFsrGF1UX3WrKF4x Ga4UGr1qqr4IyFWxl-sFpf9Il3svdjkaLaAFLSUrUUUUUb8apTn2vfkv8UJUUUU8wcxFpf 9Il3svdxBIdaVrn0xqx4xG64xvF2IEw4CE5I8CrVC2j2Jv73VFW2AGmfu7bjvjm3AaLaJ3 UjIYCTnIWjp_UUUOO7kC6x804xWl14x267AKxVWUJVW8JwAFc2x0x2IEx4CE42xK8VAvwI 8IcIk0rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xG Y2AK021l84ACjcxK6xIIjxv20xvE14v26w1j6s0DM28EF7xvwVC0I7IYx2IY6xkF7I0E14 v26rxl6s0DM28EF7xvwVC2z280aVAFwI0_GcCE3s1l84ACjcxK6I8E87Iv6xkF7I0E14v2 6rxl6s0DM2AIxVAIcxkEcVAq07x20xvEncxIr21l57IF6xkI12xvs2x26I8E6xACxx1l5I 8CrVACY4xI64kE6c02F40Ex7xfMcIj6xIIjxv20xvE14v26r106r15McIj6I8E87Iv67AK xVWUJVW8JwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41lF7xvr2IYc2Ij64 vIr40E4x8a64kEw24lFcxC0VAYjxAxZF0Ew4CEw7xC0wACY4xI67k04243AVC20s07MxAI w28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4UMI8I3I0E5I8CrVAFwI0_Jr0_Jr 4lx2IqxVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWUXVWUAwCIc40Y0x0EwIxG rwCI42IY6xIIjxv20xvE14v26r1j6r1xMIIF0xvE2Ix0cI8IcVCY1x0267AKxVWUJVW8Jw CI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2 z280aVCY1x0267AKxVWUJVW8JwCE64xvF2IEb7IF0Fy7YxBIdaVFxhVjvjDU0xZFpf9x07 jbMa5UUUUU= Content-Type: text/plain; charset="utf-8" The attributes attached directly to the mounted filesystem fsid kobject are currently created and removed as part of the broader mounted sysfs setup. Factor the main filesystem attributes, the feature group and dynamically generated unknown feature attributes into dedicated helpers. Keep the helpers called from the existing mounted sysfs setup and teardown paths for now. This prepares for adjusting their lifetime separately from the required subdirectories. Signed-off-by: Jiacheng Xu --- fs/btrfs/sysfs.c | 47 +++++++++++++++++++++++++++++++++++------------ fs/btrfs/sysfs.h | 2 ++ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 0d14570..a89e5ae 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -1707,6 +1707,15 @@ static void btrfs_sysfs_remove_fs_devices(struct btr= fs_fs_devices *fs_devices) } } =20 +void btrfs_sysfs_remove_mounted_attrs(struct btrfs_fs_info *fs_info) +{ + struct kobject *fsid_kobj =3D &fs_info->fs_devices->fsid_kobj; + + 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(struct btrfs_fs_info *fs_info) { struct kobject *fsid_kobj =3D &fs_info->fs_devices->fsid_kobj; @@ -1730,9 +1739,7 @@ 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); + btrfs_sysfs_remove_mounted_attrs(fs_info); btrfs_sysfs_remove_fs_devices(fs_info->fs_devices); } =20 @@ -2284,6 +2291,30 @@ int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs= _devs) return 0; } =20 +int btrfs_sysfs_add_mounted_attrs(struct btrfs_fs_info *fs_info) +{ + struct kobject *fsid_kobj =3D &fs_info->fs_devices->fsid_kobj; + int ret; + + ret =3D sysfs_create_files(fsid_kobj, btrfs_attrs); + if (ret) + return ret; + + ret =3D sysfs_create_group(fsid_kobj, &btrfs_feature_attr_group); + if (ret) + goto failure; + + ret =3D addrm_unknown_feature_attrs(fs_info, true); + if (ret) + goto failure; + + return 0; + +failure: + btrfs_sysfs_remove_mounted_attrs(fs_info); + return ret; +} + int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info) { int ret; @@ -2294,16 +2325,12 @@ int btrfs_sysfs_add_mounted(struct btrfs_fs_info *f= s_info) if (ret) return ret; =20 - ret =3D sysfs_create_files(fsid_kobj, btrfs_attrs); + ret =3D btrfs_sysfs_add_mounted_attrs(fs_info); if (ret) { btrfs_sysfs_remove_fs_devices(fs_devs); return ret; } =20 - ret =3D sysfs_create_group(fsid_kobj, &btrfs_feature_attr_group); - if (ret) - goto failure; - #ifdef CONFIG_BTRFS_DEBUG fs_info->debug_kobj =3D kobject_create_and_add("debug", fsid_kobj); if (!fs_info->debug_kobj) { @@ -2327,10 +2354,6 @@ int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs= _info) if (ret) goto failure; =20 - ret =3D addrm_unknown_feature_attrs(fs_info, true); - if (ret) - goto failure; - ret =3D sysfs_create_link(fsid_kobj, &fs_info->sb->s_bdi->dev->kobj= , "bdi"); if (ret) goto failure; diff --git a/fs/btrfs/sysfs.h b/fs/btrfs/sysfs.h index 05498e5..d71438f 100644 --- a/fs/btrfs/sysfs.h +++ b/fs/btrfs/sysfs.h @@ -35,6 +35,8 @@ 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); +int btrfs_sysfs_add_mounted_attrs(struct btrfs_fs_info *fs_info); +void btrfs_sysfs_remove_mounted_attrs(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); --=20 2.25.1 > -----=E5=8E=9F=E5=A7=8B=E9=82=AE=E4=BB=B6----- > =E5=8F=91=E4=BB=B6=E4=BA=BA: "Jiacheng Xu" > =E5=8F=91=E9=80=81=E6=97=B6=E9=97=B4:2026-08-22 11:41:15 (=E6=98=9F=E6=9C= =9F=E5=85=AD) > =E6=94=B6=E4=BB=B6=E4=BA=BA: wqu@suse.com > =E6=8A=84=E9=80=81: linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel= .org > =E4=B8=BB=E9=A2=98: [PATCH v2 0/2] btrfs: delay mounted sysfs attributes = until mount is ready >=20 > Here is a potential fix following Wenruo's idea. >=20 > btrfs_sysfs_add_mounted() currently publishes the writable label and > feature attributes before the transaction kthread is created. A concurrent > sysfs write can therefore dereference a NULL transaction_kthread in > wake_up_process(). >=20 > This series follows the suggested lifecycle: create only the required > subdirectories during early mount, publish the fsid attributes after mount > initialization, and remove them before the kthreads are stopped. The > feature attributes are included because their store callback has the same > transaction_kthread dependency as the label callback. >=20 > Patch 1 factors the fsid attribute handling into dedicated helpers. Patch= 2 > moves their publication and removal to the safe mount and unmount stages. > On unmount the cleaner is parked before attribute removal so it cannot > recreate the feature group through sysfs_update_group(). Both patches are > required for stable backports. >=20 > The resulting fs/btrfs/sysfs.o and fs/btrfs/disk-io.o were build-tested. >=20 > Changes in v2: > - Delay creation of both the root and feature attributes until mount setup > is complete. > - Remove those attributes while their kthread dependencies are still > valid. > - Split helper extraction from the lifecycle fix for stable backports. >=20 > Jiacheng Xu (2): > btrfs: sysfs: factor out mounted fsid attribute helpers > btrfs: delay mounted fsid attributes until the fs is ready >=20 > fs/btrfs/disk-io.c | 18 ++++++++++++++++- > fs/btrfs/sysfs.c | 50 ++++++++++++++++++++++++++++++---------------- > fs/btrfs/sysfs.h | 2 ++ > 3 files changed, 52 insertions(+), 18 deletions(-) >=20 > base-commit: 0f23d56f17fdfc7db69d51f64c8b91bbab947aa9 > --=20 > 2.25.1 >=20 >=20 > > -----=E5=8E=9F=E5=A7=8B=E9=82=AE=E4=BB=B6----- > > =E5=8F=91=E4=BB=B6=E4=BA=BA: "Jiacheng Xu" > > =E5=8F=91=E9=80=81=E6=97=B6=E9=97=B4:2026-08-20 20:27:23 (=E6=98=9F=E6= =9C=9F=E5=9B=9B) > > =E6=94=B6=E4=BB=B6=E4=BA=BA: "Chris Mason" > > =E6=8A=84=E9=80=81: "David Sterba" , linux-btrfs@vger= .kernel.org, linux-kernel@vger.kernel.org > > =E4=B8=BB=E9=A2=98: [PATCH] btrfs: drain sysfs callbacks before stoppin= g transaction kthread > >=20 > > btrfs_label_store() and btrfs_feature_attr_store() wake up the > > transaction kthread through fs_info->transaction_kthread. > >=20 > > 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(). > >=20 > > 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. > >=20 > > 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. > >=20 > > Apply the same ordering to the open_ctree() failure path when the > > transaction kthread has already been created. > >=20 > > 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(-) > >=20 > > 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, str= uct 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; > >=20 > > @@ -3780,6 +3781,9 @@ int __cold open_ctree(struct super_block *sb, str= uct 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, str= uct btrfs_fs_devices *fs_device > > filemap_write_and_wait(fs_info->btree_inode->i_mapping); > >=20 > > 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); > >=20 > > 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) > >=20 > > set_bit(BTRFS_FS_CLOSING_START, &fs_info->flags); > >=20 > > + /* 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)); > >=20 > > - btrfs_sysfs_remove_mounted(fs_info); > > + btrfs_sysfs_remove_mounted_kobjects(fs_info); > > btrfs_sysfs_remove_fsid(fs_info->fs_devices); > >=20 > > btrfs_put_block_group_cache(fs_info); > >=20 > > 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(struc= t btrfs_fs_devices *fs_devices) > > } > > } > >=20 > > -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 =3D &fs_info->fs_devices->fsid_kobj; > >=20 > > - 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_i= nfo) > > +{ > > + sysfs_remove_link(&fs_info->fs_devices->fsid_kobj, "bdi"); > >=20 > > if (fs_info->space_info_kobj) { > > sysfs_remove_files(fs_info->space_info_kobj, allocation_att= rs); > > @@ -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); > > } > >=20 > > 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= ); From nobody Mon Sep 28 11:40:13 2026 Received: from azure-sdnproxy.icoremail.net (azure-sdnproxy.icoremail.net [52.187.6.220]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8ED342D0292; Sat, 22 Aug 2026 03:46:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=52.187.6.220 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787370419; cv=none; b=GkINzS6k4uLr5UrAlSI+U6NZyPGd5HXQEMeQRRSoB777CoAre1ROYQQVOVKAkCV0SdoeZwPZ9NLQUoZs0shab3HAVeQuMvzp75SZdVpDeTJjGcC826DZGhobw67pXfStct1jmjCFbkcW2CoFNwpob7CQtRXc2ntN2ghVr+iFbNI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787370419; c=relaxed/simple; bh=lJHFHDkepejKA6K5zaUeLbhkYcWC8SMTO9mdn8vo8YI=; h=Date:From:To:Cc:Subject:In-Reply-To:References:Content-Type: MIME-Version:Message-ID; b=WVYv4gpC98my7N+nsyzQJ94udKU2T7JoK5Bg1KSlqtIJwdeIgZ5i4W+2V1isNzefLePcxgarat+TVx86hgEAwuXb9bNt144UgGrI4Uig1miXcn0sBpYe1HLL/8kZepSA7CY4I+WJgqkxv6koY12nED2IBfHs+p/nGK9QGVf3xkM= 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=52.187.6.220 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 _____wBHMS+oG4lqj0m0AA--.18471S3; Sat, 22 Aug 2026 11:46:48 +0800 (CST) Received: from stitch$zju.edu.cn ( [10.190.161.59] ) by ajax-webmail-mail-app3 (Coremail) ; Sat, 22 Aug 2026 11:46:48 +0800 (GMT+08:00) Date: Sat, 22 Aug 2026 11:46:48 +0800 (GMT+08:00) X-CM-HeaderCharset: UTF-8 From: "Jiacheng Xu" To: wqu@suse.com Cc: linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 2/2] btrfs: delay mounted sysfs attributes until mount is ready 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 In-Reply-To: <698e5039.16b92.1a0278ef67b.Coremail.stitch@zju.edu.cn> References: <20b09e24.16b27.1a01f23ee08.Coremail.stitch@zju.edu.cn> <698e5039.16b92.1a0278ef67b.Coremail.stitch@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: <761f4c3.16b9c.1a027940a42.Coremail.stitch@zju.edu.cn> X-Coremail-Locale: zh_CN X-CM-TRANSID: zS_KCgD3wXWoG4lqPZmUBA--.25461W X-CM-SenderInfo: qtrxiiaqttimo62m3hxhgxhubq/1tbiAwULC2qJAhcBLQAEsY X-CM-DELIVERINFO: =?B?VPGDZgXKKxbFmtjJiESix3B1w3tMoM3snk/k5SVzZVydjEqe1eefKHnLf95EnB4iem egW1kKDTffj9RZcKrT0I+755umOLsOkZSVGaDXiZpJDePD44JK6CHyT1ELix8hV4NJdhal y6BOTbPoMgog6XCMoYbkn/03HVfrA5/7VUR1Gl9nmMk5UdxdaOCY79taTvFqPA== X-Coremail-Antispam: 1Uk129KBj9fXoW3Kr4fWF4xKF4fCw1xJw48Zrc_yoW8Jr1rJo WFgr17X3yrtr1jyF4kCrZ7Gwsru348Kan7tr4F93s3u3WDt3Z8Zry5KanxGa4UX3WrKF4x Ja4UGrn0qr4IyFWfl-sFpf9Il3svdjkaLaAFLSUrUUUUUb8apTn2vfkv8UJUUUU8wcxFpf 9Il3svdxBIdaVrn0xqx4xG64xvF2IEw4CE5I8CrVC2j2Jv73VFW2AGmfu7bjvjm3AaLaJ3 UjIYCTnIWjp_UUUOo7kC6x804xWl14x267AKxVWUJVW8JwAFc2x0x2IEx4CE42xK8VAvwI 8IcIk0rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xG Y2AK021l84ACjcxK6xIIjxv20xvE14v26w1j6s0DM28EF7xvwVC0I7IYx2IY6xkF7I0E14 v26rxl6s0DM28EF7xvwVC2z280aVAFwI0_GcCE3s1l84ACjcxK6I8E87Iv6xkF7I0E14v2 6rxl6s0DM2AIxVAIcxkEcVAq07x20xvEncxIr21l57IF6xkI12xvs2x26I8E6xACxx1l5I 8CrVACY4xI64kE6c02F40Ex7xfMcIj6xIIjxv20xvE14v26r1Y6r17McIj6I8E87Iv67AK xVWUJVW8JwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41lF7xvr2IYc2Ij64 vIr40E4x8a64kEw24lFcxC0VAYjxAxZF0Ew4CEw7xC0wACY4xI67k04243AVC20s07MxAI w28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4UMI8I3I0E5I8CrVAFwI0_Jr0_Jr 4lx2IqxVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWUXVWUAwCIc40Y0x0EwIxG rwCI42IY6xIIjxv20xvE14v26r1j6r1xMIIF0xvE2Ix0cI8IcVCY1x0267AKxVWUJVW8Jw CI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2 z280aVCY1x0267AKxVW8JVW8Jr1l6VACY4xI67k04243AbIYCTnIWIevJa73UjIFyTuYvj xU29YwDUUUU Content-Type: text/plain; charset="utf-8" btrfs_sysfs_add_mounted() publishes the writable label and feature attributes before the transaction kthread is created. A concurrent sysfs write can therefore reach wake_up_process() while fs_info->transaction_kthread is still NULL and cause a null-ptr-dereference=20 in try_to_wake_up(). A flag check in the store callbacks would not synchronize with teardown after a callback has already passed the check. Instead, publish the fsid attributes only after the transaction kthread and the rest of the mount state are initialized. Do this before setting BTRFS_FS_OPEN so the cleaner cannot update a feature group that has not been created yet. On unmount, park the cleaner first so it cannot recreate the feature group. Then remove the fsid attributes. The sysfs removal drains active callbacks while both kthreads are still valid. Fixes: a6f69dc8018d ("btrfs: move commit out of sysfs when changing label") Fixes: 0eae2747ec1d ("btrfs: move commit out of sysfs when changing feature= s") Signed-off-by: Jiacheng Xu --- fs/btrfs/disk-io.c | 18 +++++++++++++++++- fs/btrfs/sysfs.c | 7 ------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 2f1666d..93d62a7 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3747,8 +3747,12 @@ int __cold open_ctree(struct super_block *sb, struct= btrfs_fs_devices *fs_device goto fail_qgroup; } =20 - if (sb_rdonly(sb)) + if (sb_rdonly(sb)) { + ret =3D btrfs_sysfs_add_mounted_attrs(fs_info); + if (ret) + goto fail_qgroup; return 0; + } =20 ret =3D btrfs_start_pre_rw_mount(fs_info); if (ret) { @@ -3769,6 +3773,12 @@ int __cold open_ctree(struct super_block *sb, struct= btrfs_fs_devices *fs_device } } =20 + ret =3D btrfs_sysfs_add_mounted_attrs(fs_info); + if (ret) { + close_ctree(fs_info); + return ret; + } + set_bit(BTRFS_FS_OPEN, &fs_info->flags); =20 /* Kick the cleaner thread so it'll start deleting snapshots. */ @@ -4347,6 +4357,12 @@ void __cold close_ctree(struct btrfs_fs_info *fs_inf= o) */ kthread_park(fs_info->cleaner_kthread); =20 + /* + * The cleaner can no longer recreate feature attributes. Remove the + * fsid attributes and drain callbacks before stopping the kthreads. + */ + btrfs_sysfs_remove_mounted_attrs(fs_info); + /* wait for the qgroup rescan worker to stop */ btrfs_qgroup_wait_for_completion(fs_info, false); =20 diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index a89e5ae..5ecebb2 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -1739,7 +1739,6 @@ void btrfs_sysfs_remove_mounted(struct btrfs_fs_info = *fs_info) kobject_put(fs_info->debug_kobj); } #endif - btrfs_sysfs_remove_mounted_attrs(fs_info); btrfs_sysfs_remove_fs_devices(fs_info->fs_devices); } =20 @@ -2325,12 +2324,6 @@ int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs= _info) if (ret) return ret; =20 - ret =3D btrfs_sysfs_add_mounted_attrs(fs_info); - if (ret) { - btrfs_sysfs_remove_fs_devices(fs_devs); - return ret; - } - #ifdef CONFIG_BTRFS_DEBUG fs_info->debug_kobj =3D kobject_create_and_add("debug", fsid_kobj); if (!fs_info->debug_kobj) { --=20 2.25.1 > -----=E5=8E=9F=E5=A7=8B=E9=82=AE=E4=BB=B6----- > =E5=8F=91=E4=BB=B6=E4=BA=BA: "Jiacheng Xu" > =E5=8F=91=E9=80=81=E6=97=B6=E9=97=B4:2026-08-22 11:41:15 (=E6=98=9F=E6=9C= =9F=E5=85=AD) > =E6=94=B6=E4=BB=B6=E4=BA=BA: wqu@suse.com > =E6=8A=84=E9=80=81: linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel= .org > =E4=B8=BB=E9=A2=98: [PATCH v2 0/2] btrfs: delay mounted sysfs attributes = until mount is ready >=20 > Here is a potential fix following Wenruo's idea. >=20 > btrfs_sysfs_add_mounted() currently publishes the writable label and > feature attributes before the transaction kthread is created. A concurrent > sysfs write can therefore dereference a NULL transaction_kthread in > wake_up_process(). >=20 > This series follows the suggested lifecycle: create only the required > subdirectories during early mount, publish the fsid attributes after mount > initialization, and remove them before the kthreads are stopped. The > feature attributes are included because their store callback has the same > transaction_kthread dependency as the label callback. >=20 > Patch 1 factors the fsid attribute handling into dedicated helpers. Patch= 2 > moves their publication and removal to the safe mount and unmount stages. > On unmount the cleaner is parked before attribute removal so it cannot > recreate the feature group through sysfs_update_group(). Both patches are > required for stable backports. >=20 > The resulting fs/btrfs/sysfs.o and fs/btrfs/disk-io.o were build-tested. >=20 > Changes in v2: > - Delay creation of both the root and feature attributes until mount setup > is complete. > - Remove those attributes while their kthread dependencies are still > valid. > - Split helper extraction from the lifecycle fix for stable backports. >=20 > Jiacheng Xu (2): > btrfs: sysfs: factor out mounted fsid attribute helpers > btrfs: delay mounted fsid attributes until the fs is ready >=20 > fs/btrfs/disk-io.c | 18 ++++++++++++++++- > fs/btrfs/sysfs.c | 50 ++++++++++++++++++++++++++++++---------------- > fs/btrfs/sysfs.h | 2 ++ > 3 files changed, 52 insertions(+), 18 deletions(-) >=20 > base-commit: 0f23d56f17fdfc7db69d51f64c8b91bbab947aa9 > --=20 > 2.25.1 >=20 >=20 > > -----=E5=8E=9F=E5=A7=8B=E9=82=AE=E4=BB=B6----- > > =E5=8F=91=E4=BB=B6=E4=BA=BA: "Jiacheng Xu" > > =E5=8F=91=E9=80=81=E6=97=B6=E9=97=B4:2026-08-20 20:27:23 (=E6=98=9F=E6= =9C=9F=E5=9B=9B) > > =E6=94=B6=E4=BB=B6=E4=BA=BA: "Chris Mason" > > =E6=8A=84=E9=80=81: "David Sterba" , linux-btrfs@vger= .kernel.org, linux-kernel@vger.kernel.org > > =E4=B8=BB=E9=A2=98: [PATCH] btrfs: drain sysfs callbacks before stoppin= g transaction kthread > >=20 > > btrfs_label_store() and btrfs_feature_attr_store() wake up the > > transaction kthread through fs_info->transaction_kthread. > >=20 > > 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(). > >=20 > > 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. > >=20 > > 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. > >=20 > > Apply the same ordering to the open_ctree() failure path when the > > transaction kthread has already been created. > >=20 > > 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(-) > >=20 > > 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, str= uct 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; > >=20 > > @@ -3780,6 +3781,9 @@ int __cold open_ctree(struct super_block *sb, str= uct 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, str= uct btrfs_fs_devices *fs_device > > filemap_write_and_wait(fs_info->btree_inode->i_mapping); > >=20 > > 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); > >=20 > > 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) > >=20 > > set_bit(BTRFS_FS_CLOSING_START, &fs_info->flags); > >=20 > > + /* 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)); > >=20 > > - btrfs_sysfs_remove_mounted(fs_info); > > + btrfs_sysfs_remove_mounted_kobjects(fs_info); > > btrfs_sysfs_remove_fsid(fs_info->fs_devices); > >=20 > > btrfs_put_block_group_cache(fs_info); > >=20 > > 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(struc= t btrfs_fs_devices *fs_devices) > > } > > } > >=20 > > -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 =3D &fs_info->fs_devices->fsid_kobj; > >=20 > > - 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_i= nfo) > > +{ > > + sysfs_remove_link(&fs_info->fs_devices->fsid_kobj, "bdi"); > >=20 > > if (fs_info->space_info_kobj) { > > sysfs_remove_files(fs_info->space_info_kobj, allocation_att= rs); > > @@ -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); > > } > >=20 > > 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= );