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:
Родитель
9123bf6f21
Коммит
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)
|
||||
{
|
||||
free_part_stats(part);
|
||||
free_percpu(part->dkstats);
|
||||
kfree(part->info);
|
||||
percpu_ref_exit(&part->ref);
|
||||
}
|
||||
|
|
|
@ -92,7 +92,6 @@ const char *bdevname(struct block_device *bdev, char *buf)
|
|||
}
|
||||
EXPORT_SYMBOL(bdevname);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static void part_stat_read_all(struct hd_struct *part, struct disk_stats *stat)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
#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,
|
||||
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);
|
||||
if (disk) {
|
||||
if (!init_part_stats(&disk->part0)) {
|
||||
disk->part0.dkstats = alloc_percpu(struct disk_stats);
|
||||
if (!disk->part0.dkstats) {
|
||||
kfree(disk);
|
||||
return NULL;
|
||||
}
|
||||
init_rwsem(&disk->lookup_sem);
|
||||
disk->node_id = node_id;
|
||||
if (disk_expand_part_tbl(disk, 0)) {
|
||||
free_part_stats(&disk->part0);
|
||||
free_percpu(disk->part0.dkstats);
|
||||
kfree(disk);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -387,7 +387,8 @@ static struct hd_struct *add_partition(struct gendisk *disk, int partno,
|
|||
if (!p)
|
||||
return ERR_PTR(-EBUSY);
|
||||
|
||||
if (!init_part_stats(p)) {
|
||||
p->dkstats = alloc_percpu(struct disk_stats);
|
||||
if (!p->dkstats) {
|
||||
err = -ENOMEM;
|
||||
goto out_free;
|
||||
}
|
||||
|
@ -468,7 +469,7 @@ static struct hd_struct *add_partition(struct gendisk *disk, int partno,
|
|||
out_free_info:
|
||||
kfree(p->info);
|
||||
out_free_stats:
|
||||
free_part_stats(p);
|
||||
free_percpu(p->dkstats);
|
||||
out_free:
|
||||
kfree(p);
|
||||
return ERR_PTR(err);
|
||||
|
|
|
@ -39,15 +39,6 @@ extern struct class block_class;
|
|||
#include <linux/fs.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
|
||||
/*
|
||||
* Enough for the string representation of any kind of UUID plus NULL.
|
||||
|
@ -72,11 +63,7 @@ struct hd_struct {
|
|||
seqcount_t nr_sects_seq;
|
||||
#endif
|
||||
unsigned long stamp;
|
||||
#ifdef CONFIG_SMP
|
||||
struct disk_stats __percpu *dkstats;
|
||||
#else
|
||||
struct disk_stats dkstats;
|
||||
#endif
|
||||
struct percpu_ref ref;
|
||||
|
||||
sector_t alignment_offset;
|
||||
|
|
|
@ -4,19 +4,23 @@
|
|||
|
||||
#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:
|
||||
*
|
||||
* {disk|part|all}_stat_{add|sub|inc|dec}() modify the stat counters
|
||||
* and should be called between disk_stat_lock() and
|
||||
* disk_stat_unlock().
|
||||
* {disk|part|all}_stat_{add|sub|inc|dec}() modify the stat counters and should
|
||||
* be called between disk_stat_lock() and disk_stat_unlock().
|
||||
*
|
||||
* 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_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));
|
||||
}
|
||||
|
||||
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) \
|
||||
(part_stat_read(part, field[STAT_READ]) + \
|
||||
part_stat_read(part, field[STAT_WRITE]) + \
|
||||
|
|
Загрузка…
Ссылка в новой задаче