@@ -450,6 +450,14 @@ static void btrfs_submit_dev_bio(struct btrfs_device *dev, struct bio *bio)
(unsigned long)dev->bdev->bd_dev, btrfs_dev_name(dev),
dev->devid, bio->bi_iter.bi_size);
+ /*
+ * Track reads if tracking is enabled; ignore I/O operations before
+ * fully initialized.
+ */
+ if (dev->fs_devices->fs_stats && bio_op(bio) == REQ_OP_READ && dev->fs_info)
+ percpu_counter_add(&dev->fs_devices->read_cnt_blocks,
+ bio->bi_iter.bi_size >> dev->fs_info->sectorsize_bits);
+
if (bio->bi_opf & REQ_BTRFS_CGROUP_PUNT)
blkcg_punt_bio_submit(bio);
else
@@ -3481,6 +3481,9 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
goto fail_sysfs;
}
+ /* Disable filesystem stats tracking unless required by a feature. */
+ fs_devices->fs_stats = false;
+
ret = btrfs_read_block_groups(fs_info);
if (ret) {
btrfs_err(fs_info, "failed to read block groups: %d", ret);
@@ -1254,6 +1254,7 @@ static void close_fs_devices(struct btrfs_fs_devices *fs_devices)
list_for_each_entry_safe(device, tmp, &fs_devices->devices, dev_list)
btrfs_close_one_device(device);
+ percpu_counter_destroy(&fs_devices->read_cnt_blocks);
WARN_ON(fs_devices->open_devices);
WARN_ON(fs_devices->rw_devices);
fs_devices->opened = 0;
@@ -1300,6 +1301,11 @@ static int open_fs_devices(struct btrfs_fs_devices *fs_devices,
struct btrfs_device *tmp_device;
int ret = 0;
+ /* Initialize the in-memory record of filesystem read count */
+ ret = percpu_counter_init(&fs_devices->read_cnt_blocks, 0, GFP_KERNEL);
+ if (ret)
+ return ret;
+
list_for_each_entry_safe(device, tmp_device, &fs_devices->devices,
dev_list) {
int ret2;
@@ -7669,7 +7675,7 @@ int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info)
list_for_each_entry(device, &fs_devices->devices, dev_list) {
ret = btrfs_device_init_dev_stats(device, path);
if (ret)
- goto out;
+ return ret;
}
list_for_each_entry(seed_devs, &fs_devices->seed_list, seed_list) {
list_for_each_entry(device, &seed_devs->devices, dev_list) {
@@ -185,7 +185,7 @@ struct btrfs_device {
* enum btrfs_dev_stat_values in ioctl.h */
int dev_stats_valid;
- /* Counter to record the change of device stats */
+ /* Counter to record of the change of device stats */
atomic_t dev_stats_ccnt;
atomic_t dev_stat_values[BTRFS_DEV_STAT_VALUES_MAX];
@@ -417,6 +417,8 @@ struct btrfs_fs_devices {
bool seeding;
/* The mount needs to use a randomly generated fsid. */
bool temp_fsid;
+ /* Enable/disable the filesystem stats tracking */
+ bool fs_stats;
struct btrfs_fs_info *fs_info;
/* sysfs kobjects */
@@ -427,6 +429,9 @@ struct btrfs_fs_devices {
enum btrfs_chunk_allocation_policy chunk_alloc_policy;
+ /* Tracks the number of blocks (sectors) read from the filesystem. */
+ struct percpu_counter read_cnt_blocks;
+
/* Policy used to read the mirrored stripes. */
enum btrfs_read_policy read_policy;
Add fs_devices::read_cnt_blocks to track read blocks, initialize it in open_fs_devices() and clean it up in close_fs_devices(). btrfs_submit_dev_bio() increments it for reads when stats tracking is enabled. Stats tracking is disabled by default and is enabled through fs_devices::fs_stats when required. The code is not under the EXPERIMENTAL define, as stats can be expanded to include write counts and other performance counters, with the user interface independent of its internal use. This is an in-memory-only feature, different to the dev error stats. Signed-off-by: Anand Jain <anand.jain@oracle.com> --- fs/btrfs/bio.c | 8 ++++++++ fs/btrfs/disk-io.c | 3 +++ fs/btrfs/volumes.c | 8 +++++++- fs/btrfs/volumes.h | 7 ++++++- 4 files changed, 24 insertions(+), 2 deletions(-)