Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

block: always use a percpu variable for disk stats

percpu variables have a perfectly fine working stub implementation
for UP kernels, so use that.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Christoph Hellwig and committed by
Jens Axboe
58d4f14f 9123bf6f

+18 -69
+1 -1
block/blk.h
··· 378 378 379 379 static inline void hd_free_part(struct hd_struct *part) 380 380 { 381 - free_part_stats(part); 381 + free_percpu(part->dkstats); 382 382 kfree(part->info); 383 383 percpu_ref_exit(&part->ref); 384 384 }
+3 -9
block/genhd.c
··· 92 92 } 93 93 EXPORT_SYMBOL(bdevname); 94 94 95 - #ifdef CONFIG_SMP 96 95 static void part_stat_read_all(struct hd_struct *part, struct disk_stats *stat) 97 96 { 98 97 int cpu; ··· 111 112 stat->io_ticks += ptr->io_ticks; 112 113 } 113 114 } 114 - #else /* CONFIG_SMP */ 115 - static void part_stat_read_all(struct hd_struct *part, struct disk_stats *stat) 116 - { 117 - memcpy(stat, &part->dkstats, sizeof(struct disk_stats)); 118 - } 119 - #endif /* CONFIG_SMP */ 120 115 121 116 static unsigned int part_in_flight(struct request_queue *q, 122 117 struct hd_struct *part) ··· 1681 1688 1682 1689 disk = kzalloc_node(sizeof(struct gendisk), GFP_KERNEL, node_id); 1683 1690 if (disk) { 1684 - if (!init_part_stats(&disk->part0)) { 1691 + disk->part0.dkstats = alloc_percpu(struct disk_stats); 1692 + if (!disk->part0.dkstats) { 1685 1693 kfree(disk); 1686 1694 return NULL; 1687 1695 } 1688 1696 init_rwsem(&disk->lookup_sem); 1689 1697 disk->node_id = node_id; 1690 1698 if (disk_expand_part_tbl(disk, 0)) { 1691 - free_part_stats(&disk->part0); 1699 + free_percpu(disk->part0.dkstats); 1692 1700 kfree(disk); 1693 1701 return NULL; 1694 1702 }
+3 -2
block/partitions/core.c
··· 387 387 if (!p) 388 388 return ERR_PTR(-EBUSY); 389 389 390 - if (!init_part_stats(p)) { 390 + p->dkstats = alloc_percpu(struct disk_stats); 391 + if (!p->dkstats) { 391 392 err = -ENOMEM; 392 393 goto out_free; 393 394 } ··· 469 468 out_free_info: 470 469 kfree(p->info); 471 470 out_free_stats: 472 - free_part_stats(p); 471 + free_percpu(p->dkstats); 473 472 out_free: 474 473 kfree(p); 475 474 return ERR_PTR(err);
-13
include/linux/genhd.h
··· 39 39 #include <linux/fs.h> 40 40 #include <linux/workqueue.h> 41 41 42 - struct disk_stats { 43 - u64 nsecs[NR_STAT_GROUPS]; 44 - unsigned long sectors[NR_STAT_GROUPS]; 45 - unsigned long ios[NR_STAT_GROUPS]; 46 - unsigned long merges[NR_STAT_GROUPS]; 47 - unsigned long io_ticks; 48 - local_t in_flight[2]; 49 - }; 50 - 51 42 #define PARTITION_META_INFO_VOLNAMELTH 64 52 43 /* 53 44 * Enough for the string representation of any kind of UUID plus NULL. ··· 63 72 seqcount_t nr_sects_seq; 64 73 #endif 65 74 unsigned long stamp; 66 - #ifdef CONFIG_SMP 67 75 struct disk_stats __percpu *dkstats; 68 - #else 69 - struct disk_stats dkstats; 70 - #endif 71 76 struct percpu_ref ref; 72 77 73 78 sector_t alignment_offset;
+11 -44
include/linux/part_stat.h
··· 4 4 5 5 #include <linux/genhd.h> 6 6 7 + struct disk_stats { 8 + u64 nsecs[NR_STAT_GROUPS]; 9 + unsigned long sectors[NR_STAT_GROUPS]; 10 + unsigned long ios[NR_STAT_GROUPS]; 11 + unsigned long merges[NR_STAT_GROUPS]; 12 + unsigned long io_ticks; 13 + local_t in_flight[2]; 14 + }; 15 + 7 16 /* 8 17 * Macros to operate on percpu disk statistics: 9 18 * 10 - * {disk|part|all}_stat_{add|sub|inc|dec}() modify the stat counters 11 - * and should be called between disk_stat_lock() and 12 - * disk_stat_unlock(). 19 + * {disk|part|all}_stat_{add|sub|inc|dec}() modify the stat counters and should 20 + * be called between disk_stat_lock() and disk_stat_unlock(). 13 21 * 14 22 * part_stat_read() can be called at any time. 15 - * 16 - * part_stat_{add|set_all}() and {init|free}_part_stats are for 17 - * internal use only. 18 23 */ 19 - #ifdef CONFIG_SMP 20 24 #define part_stat_lock() ({ rcu_read_lock(); get_cpu(); }) 21 25 #define part_stat_unlock() do { put_cpu(); rcu_read_unlock(); } while (0) 22 26 ··· 47 43 memset(per_cpu_ptr(part->dkstats, i), value, 48 44 sizeof(struct disk_stats)); 49 45 } 50 - 51 - static inline int init_part_stats(struct hd_struct *part) 52 - { 53 - part->dkstats = alloc_percpu(struct disk_stats); 54 - if (!part->dkstats) 55 - return 0; 56 - return 1; 57 - } 58 - 59 - static inline void free_part_stats(struct hd_struct *part) 60 - { 61 - free_percpu(part->dkstats); 62 - } 63 - 64 - #else /* !CONFIG_SMP */ 65 - #define part_stat_lock() ({ rcu_read_lock(); 0; }) 66 - #define part_stat_unlock() rcu_read_unlock() 67 - 68 - #define part_stat_get(part, field) ((part)->dkstats.field) 69 - #define part_stat_get_cpu(part, field, cpu) part_stat_get(part, field) 70 - #define part_stat_read(part, field) part_stat_get(part, field) 71 - 72 - static inline void part_stat_set_all(struct hd_struct *part, int value) 73 - { 74 - memset(&part->dkstats, value, sizeof(struct disk_stats)); 75 - } 76 - 77 - static inline int init_part_stats(struct hd_struct *part) 78 - { 79 - return 1; 80 - } 81 - 82 - static inline void free_part_stats(struct hd_struct *part) 83 - { 84 - } 85 - 86 - #endif /* CONFIG_SMP */ 87 46 88 47 #define part_stat_read_accum(part, field) \ 89 48 (part_stat_read(part, field[STAT_READ]) + \