From: Qu Wenruo Date: Tue, 7 Apr 2026 09:33:59 +0000 (+0930) Subject: btrfs: remove the dev stats item when removing a device X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=052273b63d8e8f63b55ae865f64167a156c5c5af;p=thirdparty%2Fkernel%2Flinux.git btrfs: remove the dev stats item when removing a device [MINOR BUG] The following script will cause DEV_STATS item to be left after the corresponding device is removed: # mkfs.btrfs -f $dev1 # mount $dev1 $mnt # btrfs dev add $dev2 $mnt # umount $mnt ## Without real errors, only at mount time btrfs will update ## dev->dev_stats_ccnt, thus we need a mount cycle to create the ## DEV_STATS item for the new device. # mount $dev1 $mnt # touch $mnt/foobar # sync # btrfs dev remove $dev2 $mnt # umount $mnt This will result the DEV_STATS item for devid 2 still left in device tree: device tree key (DEV_TREE ROOT_ITEM 0) leaf 31064064 items 7 free space 15788 generation 18 owner DEV_TREE leaf 31064064 flags 0x1(WRITTEN) backref revision 1 fs uuid 4bd853ed-f6ef-45fd-bbf1-1c3a2d9987cb chunk uuid b496eab1-ec23-46b5-81c1-2f1b3503ca07 item 0 key (DEV_STATS PERSISTENT_ITEM 1) itemoff 16243 itemsize 40 persistent item objectid DEV_STATS offset 1 device stats write_errs 0 read_errs 0 flush_errs 0 corruption_errs 0 generation 0 item 1 key (DEV_STATS PERSISTENT_ITEM 2) itemoff 16203 itemsize 40 persistent item objectid DEV_STATS offset 2 device stats write_errs 0 read_errs 0 flush_errs 0 corruption_errs 0 generation 0 This is not a huge problem, but if the existing DEV_STATS contains errors, and a new device is added into the fs taking the old devid, then after a mount cycle, the new device will suddenly inherit old errors which can give false alerts. [CAUSE] Btrfs never has the ability to delete DEV_STATS items. It either create a new one through update_dev_stat_item(), or read an existing one through btrfs_device_init_dev_stats(). However update_dev_stat_item() is only called lazily, if a new device is created and no new update to dev stats, then it will skip the update of the on-disk item. So if the old DEV_STATS item exists and a new device is added, and no errors during the remaining operations, the old DEV_STATS will not be updated. Then at the next mount cycle, btrfs_device_init_dev_stats() is called at mount time, which will read out the old records, causing false alerts to the newly added device. [FIX] Manually remove the DEV_STATS item during btrfs_rm_device(). Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index bfbb63cf14f55..5733b964ab7e5 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2397,6 +2397,12 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, return ret; } + ret = btrfs_remove_dev_stat_item(trans, device->devid); + if (unlikely(ret)) { + btrfs_abort_transaction(trans, ret); + btrfs_end_transaction(trans); + return ret; + } clear_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state); btrfs_scrub_cancel_dev(device);