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>
This commit is contained in:

committed by
Jens Axboe

parent
9123bf6f21
commit
58d4f14fc3
@@ -378,7 +378,7 @@ static inline void hd_struct_put(struct hd_struct *part)
|
|||||||
|
|
||||||
static inline void hd_free_part(struct hd_struct *part)
|
static inline void hd_free_part(struct hd_struct *part)
|
||||||
{
|
{
|
||||||
free_part_stats(part);
|
free_percpu(part->dkstats);
|
||||||
kfree(part->info);
|
kfree(part->info);
|
||||||
percpu_ref_exit(&part->ref);
|
percpu_ref_exit(&part->ref);
|
||||||
}
|
}
|
||||||
|
@@ -92,7 +92,6 @@ const char *bdevname(struct block_device *bdev, char *buf)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(bdevname);
|
EXPORT_SYMBOL(bdevname);
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
static void part_stat_read_all(struct hd_struct *part, struct disk_stats *stat)
|
static void part_stat_read_all(struct hd_struct *part, struct disk_stats *stat)
|
||||||
{
|
{
|
||||||
int cpu;
|
int cpu;
|
||||||
@@ -112,12 +111,6 @@ static void part_stat_read_all(struct hd_struct *part, struct disk_stats *stat)
|
|||||||
stat->io_ticks += ptr->io_ticks;
|
stat->io_ticks += ptr->io_ticks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else /* CONFIG_SMP */
|
|
||||||
static void part_stat_read_all(struct hd_struct *part, struct disk_stats *stat)
|
|
||||||
{
|
|
||||||
memcpy(stat, &part->dkstats, sizeof(struct disk_stats));
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_SMP */
|
|
||||||
|
|
||||||
static unsigned int part_in_flight(struct request_queue *q,
|
static unsigned int part_in_flight(struct request_queue *q,
|
||||||
struct hd_struct *part)
|
struct hd_struct *part)
|
||||||
@@ -1688,14 +1681,15 @@ struct gendisk *__alloc_disk_node(int minors, int node_id)
|
|||||||
|
|
||||||
disk = kzalloc_node(sizeof(struct gendisk), GFP_KERNEL, node_id);
|
disk = kzalloc_node(sizeof(struct gendisk), GFP_KERNEL, node_id);
|
||||||
if (disk) {
|
if (disk) {
|
||||||
if (!init_part_stats(&disk->part0)) {
|
disk->part0.dkstats = alloc_percpu(struct disk_stats);
|
||||||
|
if (!disk->part0.dkstats) {
|
||||||
kfree(disk);
|
kfree(disk);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
init_rwsem(&disk->lookup_sem);
|
init_rwsem(&disk->lookup_sem);
|
||||||
disk->node_id = node_id;
|
disk->node_id = node_id;
|
||||||
if (disk_expand_part_tbl(disk, 0)) {
|
if (disk_expand_part_tbl(disk, 0)) {
|
||||||
free_part_stats(&disk->part0);
|
free_percpu(disk->part0.dkstats);
|
||||||
kfree(disk);
|
kfree(disk);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@@ -387,7 +387,8 @@ static struct hd_struct *add_partition(struct gendisk *disk, int partno,
|
|||||||
if (!p)
|
if (!p)
|
||||||
return ERR_PTR(-EBUSY);
|
return ERR_PTR(-EBUSY);
|
||||||
|
|
||||||
if (!init_part_stats(p)) {
|
p->dkstats = alloc_percpu(struct disk_stats);
|
||||||
|
if (!p->dkstats) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
@@ -468,7 +469,7 @@ static struct hd_struct *add_partition(struct gendisk *disk, int partno,
|
|||||||
out_free_info:
|
out_free_info:
|
||||||
kfree(p->info);
|
kfree(p->info);
|
||||||
out_free_stats:
|
out_free_stats:
|
||||||
free_part_stats(p);
|
free_percpu(p->dkstats);
|
||||||
out_free:
|
out_free:
|
||||||
kfree(p);
|
kfree(p);
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
|
@@ -39,15 +39,6 @@ extern struct class block_class;
|
|||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
struct disk_stats {
|
|
||||||
u64 nsecs[NR_STAT_GROUPS];
|
|
||||||
unsigned long sectors[NR_STAT_GROUPS];
|
|
||||||
unsigned long ios[NR_STAT_GROUPS];
|
|
||||||
unsigned long merges[NR_STAT_GROUPS];
|
|
||||||
unsigned long io_ticks;
|
|
||||||
local_t in_flight[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PARTITION_META_INFO_VOLNAMELTH 64
|
#define PARTITION_META_INFO_VOLNAMELTH 64
|
||||||
/*
|
/*
|
||||||
* Enough for the string representation of any kind of UUID plus NULL.
|
* Enough for the string representation of any kind of UUID plus NULL.
|
||||||
@@ -72,11 +63,7 @@ struct hd_struct {
|
|||||||
seqcount_t nr_sects_seq;
|
seqcount_t nr_sects_seq;
|
||||||
#endif
|
#endif
|
||||||
unsigned long stamp;
|
unsigned long stamp;
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
struct disk_stats __percpu *dkstats;
|
struct disk_stats __percpu *dkstats;
|
||||||
#else
|
|
||||||
struct disk_stats dkstats;
|
|
||||||
#endif
|
|
||||||
struct percpu_ref ref;
|
struct percpu_ref ref;
|
||||||
|
|
||||||
sector_t alignment_offset;
|
sector_t alignment_offset;
|
||||||
|
@@ -4,19 +4,23 @@
|
|||||||
|
|
||||||
#include <linux/genhd.h>
|
#include <linux/genhd.h>
|
||||||
|
|
||||||
|
struct disk_stats {
|
||||||
|
u64 nsecs[NR_STAT_GROUPS];
|
||||||
|
unsigned long sectors[NR_STAT_GROUPS];
|
||||||
|
unsigned long ios[NR_STAT_GROUPS];
|
||||||
|
unsigned long merges[NR_STAT_GROUPS];
|
||||||
|
unsigned long io_ticks;
|
||||||
|
local_t in_flight[2];
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Macros to operate on percpu disk statistics:
|
* Macros to operate on percpu disk statistics:
|
||||||
*
|
*
|
||||||
* {disk|part|all}_stat_{add|sub|inc|dec}() modify the stat counters
|
* {disk|part|all}_stat_{add|sub|inc|dec}() modify the stat counters and should
|
||||||
* and should be called between disk_stat_lock() and
|
* be called between disk_stat_lock() and disk_stat_unlock().
|
||||||
* disk_stat_unlock().
|
|
||||||
*
|
*
|
||||||
* part_stat_read() can be called at any time.
|
* part_stat_read() can be called at any time.
|
||||||
*
|
|
||||||
* part_stat_{add|set_all}() and {init|free}_part_stats are for
|
|
||||||
* internal use only.
|
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
#define part_stat_lock() ({ rcu_read_lock(); get_cpu(); })
|
#define part_stat_lock() ({ rcu_read_lock(); get_cpu(); })
|
||||||
#define part_stat_unlock() do { put_cpu(); rcu_read_unlock(); } while (0)
|
#define part_stat_unlock() do { put_cpu(); rcu_read_unlock(); } while (0)
|
||||||
|
|
||||||
@@ -44,43 +48,6 @@ static inline void part_stat_set_all(struct hd_struct *part, int value)
|
|||||||
sizeof(struct disk_stats));
|
sizeof(struct disk_stats));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int init_part_stats(struct hd_struct *part)
|
|
||||||
{
|
|
||||||
part->dkstats = alloc_percpu(struct disk_stats);
|
|
||||||
if (!part->dkstats)
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void free_part_stats(struct hd_struct *part)
|
|
||||||
{
|
|
||||||
free_percpu(part->dkstats);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* !CONFIG_SMP */
|
|
||||||
#define part_stat_lock() ({ rcu_read_lock(); 0; })
|
|
||||||
#define part_stat_unlock() rcu_read_unlock()
|
|
||||||
|
|
||||||
#define part_stat_get(part, field) ((part)->dkstats.field)
|
|
||||||
#define part_stat_get_cpu(part, field, cpu) part_stat_get(part, field)
|
|
||||||
#define part_stat_read(part, field) part_stat_get(part, field)
|
|
||||||
|
|
||||||
static inline void part_stat_set_all(struct hd_struct *part, int value)
|
|
||||||
{
|
|
||||||
memset(&part->dkstats, value, sizeof(struct disk_stats));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int init_part_stats(struct hd_struct *part)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void free_part_stats(struct hd_struct *part)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* CONFIG_SMP */
|
|
||||||
|
|
||||||
#define part_stat_read_accum(part, field) \
|
#define part_stat_read_accum(part, field) \
|
||||||
(part_stat_read(part, field[STAT_READ]) + \
|
(part_stat_read(part, field[STAT_READ]) + \
|
||||||
part_stat_read(part, field[STAT_WRITE]) + \
|
part_stat_read(part, field[STAT_WRITE]) + \
|
||||||
|
Reference in New Issue
Block a user