diff --git a/drivers/md/dm.c b/drivers/md/dm.c index e04b34c144607707e8fe9b046a00b559305bb04c..62838c8f24f82437843e8757fc45a61c21e166a4 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1564,6 +1564,9 @@ static void init_clone_info(struct clone_info *ci, struct mapped_device *md, ci->sector = bio->bi_iter.bi_sector; } +#define __dm_part_stat_sub(part, field, subnd) \ + (part_stat_get(part, field) -= (subnd)) + /* * Entry point to split a bio into clones and submit them to the targets. */ @@ -1612,6 +1615,19 @@ static blk_qc_t __split_and_process_bio(struct mapped_device *md, struct bio *b = bio_split(bio, bio_sectors(bio) - ci.sector_count, GFP_NOIO, &md->queue->bio_split); ci.io->orig_bio = b; + + /* + * Adjust IO stats for each split, otherwise upon queue + * reentry there will be redundant IO accounting. + * NOTE: this is a stop-gap fix, a proper fix involves + * significant refactoring of DM core's bio splitting + * (by eliminating DM's splitting and just using bio_split) + */ + part_stat_lock(); + __dm_part_stat_sub(&dm_disk(md)->part0, + sectors[op_stat_group(bio_op(bio))], ci.sector_count); + part_stat_unlock(); + bio_chain(b, bio); ret = generic_make_request(bio); break; diff --git a/include/linux/genhd.h b/include/linux/genhd.h index f13272d8433200b5c846365b808a29180d21b12f..7ce9f2977c26721a7c9872c46dd07f5fb7211758 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -298,6 +298,9 @@ extern struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, #define __part_stat_add(cpu, part, field, addnd) \ (per_cpu_ptr((part)->dkstats, (cpu))->field += (addnd)) +#define part_stat_get(part, field) \ + (per_cpu_ptr((part)->dkstats, smp_processor_id())->field) + #define part_stat_read(part, field) \ ({ \ typeof((part)->dkstats->field) res = 0; \ @@ -336,6 +339,7 @@ static inline void free_part_stats(struct hd_struct *part) #define __part_stat_add(cpu, part, field, addnd) \ ((part)->dkstats.field += addnd) +#define part_stat_get(part, field) ((part)->dkstats.field) #define part_stat_read(part, field) ((part)->dkstats.field) static inline void part_stat_set_all(struct hd_struct *part, int value)