From: Qu Wenruo Date: Tue, 7 Apr 2026 09:34:00 +0000 (+0930) Subject: btrfs: always update/create the dev stats item when adding a new device X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=923546d3c3e367fcf1344bd47291029b02b17c5f;p=thirdparty%2Flinux.git btrfs: always update/create the dev stats item when adding a new device [MINOR PROBLEM] When adding a new btrfs device, the corresponding DEV_STATS item creation can only triggered by a mount cycle if there is no other error triggered: # mkfs.btrfs -f $dev1 $mnt # mount $dev1 $mnt # btrfs dev add $dev2 $mnt # sync # btrfs ins dump-tree -t dev $dev1 device tree key (DEV_TREE ROOT_ITEM 0) leaf 30588928 items 6 free space 15853 generation 9 owner DEV_TREE 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 (1 DEV_EXTENT 13631488) itemoff 16195 itemsize 48 Only after a mount cycle and a new transaction, the DEV_STATS for devid 2 can show up: # umount $mnt # mount $dev1 $mnt # touch $mnt # sync # btrfs ins dump-tree -t dev $dev1 device tree key (DEV_TREE ROOT_ITEM 0) leaf 30605312 items 7 free space 15788 generation 10 owner DEV_TREE 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 [CAUSE] Btrfs only updates the DEV_STATS item when the device->dev_stats_ccnt counter is not 0. This is to reduce COW for the device tree. However that dev_stats_ccnt is only increased at the following call sites: - btrfs_dev_stat_inc() This happens when some IO error happened. - btrfs_dev_stat_read_and_reset() This happens for GET_DEV_STATS ioctl with BTRFS_DEV_STATS_RESET flag. - btrfs_dev_stat_set() This happens inside btrfs_device_init_dev_stats(). So when a new device is added, its dev_stats_ccnt is just initialized to 0, and btrfs won't create nor update the corresponding DEV_STATS item at all. [ENHANCEMENT] When a new device is added, also increase the dev_stats_ccnt by one. This includes both device add ioctl and dev-replace. This will force btrfs to create a new DEV_STATS item or update the existing one with the correct values. This not only makes the DEV_STATS creation early, but also prevents old DEV_STATS left from older kernels to cause false alerts for the newly added device. Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index f34b812f7aab0..318ddb7904292 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -307,6 +307,8 @@ static int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, device->bdev_file = bdev_file; set_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state); set_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state); + /* Check the comment in btrfs_init_new_device() for the reason. */ + atomic_inc(&device->dev_stats_ccnt); device->dev_stats_valid = 1; set_blocksize(bdev_file, BTRFS_BDEV_BLOCKSIZE); device->fs_devices = fs_devices; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 5733b964ab7e5..42615e6e79925 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2927,6 +2927,12 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path device->commit_total_bytes = device->total_bytes; set_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state); clear_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state); + + /* + * Increase dev_stats_ccnt so that corresponding DEV_STATS item can be + * created at the next transaction commit. + */ + atomic_inc(&device->dev_stats_ccnt); device->dev_stats_valid = 1; set_blocksize(device->bdev_file, BTRFS_BDEV_BLOCKSIZE);