Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 074a7aca authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe
Browse files

block: move stats from disk to part0



Move stats related fields - stamp, in_flight, dkstats - from disk to
part0 and unify stat handling such that...

* part_stat_*() now updates part0 together if the specified partition
  is not part0.  ie. part_stat_*() are now essentially all_stat_*().

* {disk|all}_stat_*() are gone.

* part_round_stats() is updated similary.  It handles part0 stats
  automatically and disk_round_stats() is killed.

* part_{inc|dec}_in_fligh() is implemented which automatically updates
  part0 stats for parts other than part0.

* disk_map_sector_rcu() is updated to return part0 if no part matches.
  Combined with the above changes, this makes NULL special case
  handling in callers unnecessary.

* Separate stats show code paths for disk are collapsed into part
  stats show code paths.

* Rename disk_stat_lock/unlock() to part_stat_lock/unlock()

While at it, reposition stat handling macros a bit and add missing
parentheses around macro parameters.

Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent eddb2e26
Loading
Loading
Loading
Loading
+34 −50
Original line number Original line Diff line number Diff line
@@ -61,21 +61,17 @@ static void drive_stat_acct(struct request *rq, int new_io)
	if (!blk_fs_request(rq) || !rq->rq_disk)
	if (!blk_fs_request(rq) || !rq->rq_disk)
		return;
		return;


	cpu = disk_stat_lock();
	cpu = part_stat_lock();
	part = disk_map_sector_rcu(rq->rq_disk, rq->sector);
	part = disk_map_sector_rcu(rq->rq_disk, rq->sector);


	if (!new_io)
	if (!new_io)
		all_stat_inc(cpu, rq->rq_disk, part, merges[rw], rq->sector);
		part_stat_inc(cpu, part, merges[rw]);
	else {
	else {
		disk_round_stats(cpu, rq->rq_disk);
		rq->rq_disk->in_flight++;
		if (part) {
		part_round_stats(cpu, part);
		part_round_stats(cpu, part);
			part->in_flight++;
		part_inc_in_flight(part);
		}
	}
	}


	disk_stat_unlock();
	part_stat_unlock();
}
}


void blk_queue_congestion_threshold(struct request_queue *q)
void blk_queue_congestion_threshold(struct request_queue *q)
@@ -983,8 +979,22 @@ static inline void add_request(struct request_queue *q, struct request *req)
	__elv_add_request(q, req, ELEVATOR_INSERT_SORT, 0);
	__elv_add_request(q, req, ELEVATOR_INSERT_SORT, 0);
}
}


/*
static void part_round_stats_single(int cpu, struct hd_struct *part,
 * disk_round_stats()	- Round off the performance stats on a struct
				    unsigned long now)
{
	if (now == part->stamp)
		return;

	if (part->in_flight) {
		__part_stat_add(cpu, part, time_in_queue,
				part->in_flight * (now - part->stamp));
		__part_stat_add(cpu, part, io_ticks, (now - part->stamp));
	}
	part->stamp = now;
}

/**
 * part_round_stats()	- Round off the performance stats on a struct
 * disk_stats.
 * disk_stats.
 *
 *
 * The average IO queue length and utilisation statistics are maintained
 * The average IO queue length and utilisation statistics are maintained
@@ -998,36 +1008,15 @@ static inline void add_request(struct request_queue *q, struct request *req)
 * /proc/diskstats.  This accounts immediately for all queue usage up to
 * /proc/diskstats.  This accounts immediately for all queue usage up to
 * the current jiffies and restarts the counters again.
 * the current jiffies and restarts the counters again.
 */
 */
void disk_round_stats(int cpu, struct gendisk *disk)
{
	unsigned long now = jiffies;

	if (now == disk->stamp)
		return;

	if (disk->in_flight) {
		disk_stat_add(cpu, disk, time_in_queue,
			      disk->in_flight * (now - disk->stamp));
		disk_stat_add(cpu, disk, io_ticks, (now - disk->stamp));
	}
	disk->stamp = now;
}
EXPORT_SYMBOL_GPL(disk_round_stats);

void part_round_stats(int cpu, struct hd_struct *part)
void part_round_stats(int cpu, struct hd_struct *part)
{
{
	unsigned long now = jiffies;
	unsigned long now = jiffies;


	if (now == part->stamp)
	if (part->partno)
		return;
		part_round_stats_single(cpu, &part_to_disk(part)->part0, now);

	part_round_stats_single(cpu, part, now);
	if (part->in_flight) {
		part_stat_add(cpu, part, time_in_queue,
			      part->in_flight * (now - part->stamp));
		part_stat_add(cpu, part, io_ticks, (now - part->stamp));
	}
	part->stamp = now;
}
}
EXPORT_SYMBOL_GPL(part_round_stats);


/*
/*
 * queue lock must be held
 * queue lock must be held
@@ -1567,11 +1556,10 @@ static int __end_that_request_first(struct request *req, int error,
		struct hd_struct *part;
		struct hd_struct *part;
		int cpu;
		int cpu;


		cpu = disk_stat_lock();
		cpu = part_stat_lock();
		part = disk_map_sector_rcu(req->rq_disk, req->sector);
		part = disk_map_sector_rcu(req->rq_disk, req->sector);
		all_stat_add(cpu, req->rq_disk, part, sectors[rw],
		part_stat_add(cpu, part, sectors[rw], nr_bytes >> 9);
			     nr_bytes >> 9, req->sector);
		part_stat_unlock();
		disk_stat_unlock();
	}
	}


	total_bytes = bio_nbytes = 0;
	total_bytes = bio_nbytes = 0;
@@ -1758,19 +1746,15 @@ static void end_that_request_last(struct request *req, int error)
		struct hd_struct *part;
		struct hd_struct *part;
		int cpu;
		int cpu;


		cpu = disk_stat_lock();
		cpu = part_stat_lock();
		part = disk_map_sector_rcu(disk, req->sector);
		part = disk_map_sector_rcu(disk, req->sector);


		all_stat_inc(cpu, disk, part, ios[rw], req->sector);
		part_stat_inc(cpu, part, ios[rw]);
		all_stat_add(cpu, disk, part, ticks[rw], duration, req->sector);
		part_stat_add(cpu, part, ticks[rw], duration);
		disk_round_stats(cpu, disk);
		disk->in_flight--;
		if (part) {
		part_round_stats(cpu, part);
		part_round_stats(cpu, part);
			part->in_flight--;
		part_dec_in_flight(part);
		}


		disk_stat_unlock();
		part_stat_unlock();
	}
	}


	if (req->end_io)
	if (req->end_io)
+4 −8
Original line number Original line Diff line number Diff line
@@ -390,17 +390,13 @@ static int attempt_merge(struct request_queue *q, struct request *req,
		struct hd_struct *part;
		struct hd_struct *part;
		int cpu;
		int cpu;


		cpu = disk_stat_lock();
		cpu = part_stat_lock();
		part = disk_map_sector_rcu(req->rq_disk, req->sector);
		part = disk_map_sector_rcu(req->rq_disk, req->sector);


		disk_round_stats(cpu, req->rq_disk);
		req->rq_disk->in_flight--;
		if (part) {
		part_round_stats(cpu, part);
		part_round_stats(cpu, part);
			part->in_flight--;
		part_dec_in_flight(part);
		}


		disk_stat_unlock();
		part_stat_unlock();
	}
	}


	req->ioprio = ioprio_best(req->ioprio, next->ioprio);
	req->ioprio = ioprio_best(req->ioprio, next->ioprio);
+24 −73
Original line number Original line Diff line number Diff line
@@ -176,7 +176,7 @@ EXPORT_SYMBOL_GPL(disk_part_iter_exit);
 * while preemption is disabled.
 * while preemption is disabled.
 *
 *
 * RETURNS:
 * RETURNS:
 * Found partition on success, NULL if there's no matching partition.
 * Found partition on success, part0 is returned if no partition matches
 */
 */
struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector)
struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector)
{
{
@@ -189,7 +189,7 @@ struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector)
		    sector < part->start_sect + part->nr_sects)
		    sector < part->start_sect + part->nr_sects)
			return part;
			return part;
	}
	}
	return NULL;
	return &disk->part0;
}
}
EXPORT_SYMBOL_GPL(disk_map_sector_rcu);
EXPORT_SYMBOL_GPL(disk_map_sector_rcu);


@@ -580,24 +580,24 @@ void __init printk_all_partitions(void)
		 * numbers in hex - the same format as the root=
		 * numbers in hex - the same format as the root=
		 * option takes.
		 * option takes.
		 */
		 */
		printk("%s %10llu %s",
		disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0);
		       bdevt_str(disk_devt(disk), devt_buf),
		while ((part = disk_part_iter_next(&piter))) {
		       (unsigned long long)get_capacity(disk) >> 1,
			bool is_part0 = part == &disk->part0;
		       disk_name(disk, 0, name_buf));

			printk("%s%s %10llu %s", is_part0 ? "" : "  ",
			       bdevt_str(part_devt(part), devt_buf),
			       (unsigned long long)part->nr_sects >> 1,
			       disk_name(disk, part->partno, name_buf));
			if (is_part0) {
				if (disk->driverfs_dev != NULL &&
				if (disk->driverfs_dev != NULL &&
				    disk->driverfs_dev->driver != NULL)
				    disk->driverfs_dev->driver != NULL)
					printk(" driver: %s\n",
					printk(" driver: %s\n",
					      disk->driverfs_dev->driver->name);
					      disk->driverfs_dev->driver->name);
				else
				else
					printk(" (driver?)\n");
					printk(" (driver?)\n");

			} else
		/* now show the partitions */
				printk("\n");
		disk_part_iter_init(&piter, disk, 0);
		}
		while ((part = disk_part_iter_next(&piter)))
			printk("  %s %10llu %s\n",
			       bdevt_str(part_devt(part), devt_buf),
			       (unsigned long long)part->nr_sects >> 1,
			       disk_name(disk, part->partno, name_buf));
		disk_part_iter_exit(&piter);
		disk_part_iter_exit(&piter);
	}
	}
	class_dev_iter_exit(&iter);
	class_dev_iter_exit(&iter);
@@ -674,12 +674,7 @@ static int show_partition(struct seq_file *seqf, void *v)
		return 0;
		return 0;


	/* show the full disk and all non-0 size partitions of it */
	/* show the full disk and all non-0 size partitions of it */
	seq_printf(seqf, "%4d  %7d %10llu %s\n",
	disk_part_iter_init(&piter, sgp, DISK_PITER_INCL_PART0);
		MAJOR(disk_devt(sgp)), MINOR(disk_devt(sgp)),
		(unsigned long long)get_capacity(sgp) >> 1,
		disk_name(sgp, 0, buf));

	disk_part_iter_init(&piter, sgp, 0);
	while ((part = disk_part_iter_next(&piter)))
	while ((part = disk_part_iter_next(&piter)))
		seq_printf(seqf, "%4d  %7d %10llu %s\n",
		seq_printf(seqf, "%4d  %7d %10llu %s\n",
			   MAJOR(part_devt(part)), MINOR(part_devt(part)),
			   MAJOR(part_devt(part)), MINOR(part_devt(part)),
@@ -768,40 +763,13 @@ static ssize_t disk_capability_show(struct device *dev,
	return sprintf(buf, "%x\n", disk->flags);
	return sprintf(buf, "%x\n", disk->flags);
}
}


static ssize_t disk_stat_show(struct device *dev,
			      struct device_attribute *attr, char *buf)
{
	struct gendisk *disk = dev_to_disk(dev);
	int cpu;

	cpu = disk_stat_lock();
	disk_round_stats(cpu, disk);
	disk_stat_unlock();
	return sprintf(buf,
		"%8lu %8lu %8llu %8u "
		"%8lu %8lu %8llu %8u "
		"%8u %8u %8u"
		"\n",
		disk_stat_read(disk, ios[READ]),
		disk_stat_read(disk, merges[READ]),
		(unsigned long long)disk_stat_read(disk, sectors[READ]),
		jiffies_to_msecs(disk_stat_read(disk, ticks[READ])),
		disk_stat_read(disk, ios[WRITE]),
		disk_stat_read(disk, merges[WRITE]),
		(unsigned long long)disk_stat_read(disk, sectors[WRITE]),
		jiffies_to_msecs(disk_stat_read(disk, ticks[WRITE])),
		disk->in_flight,
		jiffies_to_msecs(disk_stat_read(disk, io_ticks)),
		jiffies_to_msecs(disk_stat_read(disk, time_in_queue)));
}

static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL);
static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL);
static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL);
static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL);
static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL);
static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
#ifdef CONFIG_FAIL_MAKE_REQUEST
#ifdef CONFIG_FAIL_MAKE_REQUEST
static struct device_attribute dev_attr_fail =
static struct device_attribute dev_attr_fail =
	__ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
	__ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
@@ -836,7 +804,7 @@ static void disk_release(struct device *dev)


	kfree(disk->random);
	kfree(disk->random);
	kfree(disk->__part);
	kfree(disk->__part);
	free_disk_stats(disk);
	free_part_stats(&disk->part0);
	kfree(disk);
	kfree(disk);
}
}
struct class block_class = {
struct class block_class = {
@@ -873,28 +841,11 @@ static int diskstats_show(struct seq_file *seqf, void *v)
				"\n\n");
				"\n\n");
	*/
	*/
 
 
	cpu = disk_stat_lock();
	disk_part_iter_init(&piter, gp, DISK_PITER_INCL_PART0);
	disk_round_stats(cpu, gp);
	disk_stat_unlock();
	seq_printf(seqf, "%4d %7d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n",
		MAJOR(disk_devt(gp)), MINOR(disk_devt(gp)),
		disk_name(gp, 0, buf),
		disk_stat_read(gp, ios[0]), disk_stat_read(gp, merges[0]),
		(unsigned long long)disk_stat_read(gp, sectors[0]),
		jiffies_to_msecs(disk_stat_read(gp, ticks[0])),
		disk_stat_read(gp, ios[1]), disk_stat_read(gp, merges[1]),
		(unsigned long long)disk_stat_read(gp, sectors[1]),
		jiffies_to_msecs(disk_stat_read(gp, ticks[1])),
		gp->in_flight,
		jiffies_to_msecs(disk_stat_read(gp, io_ticks)),
		jiffies_to_msecs(disk_stat_read(gp, time_in_queue)));

	/* now show all non-0 size partitions of it */
	disk_part_iter_init(&piter, gp, 0);
	while ((hd = disk_part_iter_next(&piter))) {
	while ((hd = disk_part_iter_next(&piter))) {
		cpu = disk_stat_lock();
		cpu = part_stat_lock();
		part_round_stats(cpu, hd);
		part_round_stats(cpu, hd);
		disk_stat_unlock();
		part_stat_unlock();
		seq_printf(seqf, "%4d %7d %s %lu %lu %llu "
		seq_printf(seqf, "%4d %7d %s %lu %lu %llu "
			   "%u %lu %lu %llu %u %u %u %u\n",
			   "%u %lu %lu %llu %u %u %u %u\n",
			   MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
			   MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
@@ -1000,7 +951,7 @@ struct gendisk *alloc_disk_ext_node(int minors, int ext_minors, int node_id)
		int tot_minors = minors + ext_minors;
		int tot_minors = minors + ext_minors;
		int size = tot_minors * sizeof(struct hd_struct *);
		int size = tot_minors * sizeof(struct hd_struct *);


		if (!init_disk_stats(disk)) {
		if (!init_part_stats(&disk->part0)) {
			kfree(disk);
			kfree(disk);
			return NULL;
			return NULL;
		}
		}
@@ -1008,7 +959,7 @@ struct gendisk *alloc_disk_ext_node(int minors, int ext_minors, int node_id)
		disk->__part = kmalloc_node(size, GFP_KERNEL | __GFP_ZERO,
		disk->__part = kmalloc_node(size, GFP_KERNEL | __GFP_ZERO,
					    node_id);
					    node_id);
		if (!disk->__part) {
		if (!disk->__part) {
			free_disk_stats(disk);
				free_part_stats(&disk->part0);
			kfree(disk);
			kfree(disk);
			return NULL;
			return NULL;
		}
		}
+6 −6
Original line number Original line Diff line number Diff line
@@ -758,15 +758,15 @@ diskstats(struct gendisk *disk, struct bio *bio, ulong duration, sector_t sector
	struct hd_struct *part;
	struct hd_struct *part;
	int cpu;
	int cpu;


	cpu = disk_stat_lock();
	cpu = part_stat_lock();
	part = disk_map_sector_rcu(disk, sector);
	part = disk_map_sector_rcu(disk, sector);


	all_stat_inc(cpu, disk, part, ios[rw], sector);
	part_stat_inc(cpu, part, ios[rw]);
	all_stat_add(cpu, disk, part, ticks[rw], duration, sector);
	part_stat_add(cpu, part, ticks[rw], duration);
	all_stat_add(cpu, disk, part, sectors[rw], n_sect, sector);
	part_stat_add(cpu, part, sectors[rw], n_sect);
	all_stat_add(cpu, disk, part, io_ticks, duration, sector);
	part_stat_add(cpu, part, io_ticks, duration);


	disk_stat_unlock();
	part_stat_unlock();
}
}


void
void
+14 −13
Original line number Original line Diff line number Diff line
@@ -381,10 +381,10 @@ static void start_io_acct(struct dm_io *io)


	io->start_time = jiffies;
	io->start_time = jiffies;


	cpu = disk_stat_lock();
	cpu = part_stat_lock();
	disk_round_stats(cpu, dm_disk(md));
	part_round_stats(cpu, &dm_disk(md)->part0);
	disk_stat_unlock();
	part_stat_unlock();
	dm_disk(md)->in_flight = atomic_inc_return(&md->pending);
	dm_disk(md)->part0.in_flight = atomic_inc_return(&md->pending);
}
}


static int end_io_acct(struct dm_io *io)
static int end_io_acct(struct dm_io *io)
@@ -395,12 +395,13 @@ static int end_io_acct(struct dm_io *io)
	int pending, cpu;
	int pending, cpu;
	int rw = bio_data_dir(bio);
	int rw = bio_data_dir(bio);


	cpu = disk_stat_lock();
	cpu = part_stat_lock();
	disk_round_stats(cpu, dm_disk(md));
	part_round_stats(cpu, &dm_disk(md)->part0);
	disk_stat_add(cpu, dm_disk(md), ticks[rw], duration);
	part_stat_add(cpu, &dm_disk(md)->part0, ticks[rw], duration);
	disk_stat_unlock();
	part_stat_unlock();


	dm_disk(md)->in_flight = pending = atomic_dec_return(&md->pending);
	dm_disk(md)->part0.in_flight = pending =
		atomic_dec_return(&md->pending);


	return !pending;
	return !pending;
}
}
@@ -899,10 +900,10 @@ static int dm_request(struct request_queue *q, struct bio *bio)


	down_read(&md->io_lock);
	down_read(&md->io_lock);


	cpu = disk_stat_lock();
	cpu = part_stat_lock();
	disk_stat_inc(cpu, dm_disk(md), ios[rw]);
	part_stat_inc(cpu, &dm_disk(md)->part0, ios[rw]);
	disk_stat_add(cpu, dm_disk(md), sectors[rw], bio_sectors(bio));
	part_stat_add(cpu, &dm_disk(md)->part0, sectors[rw], bio_sectors(bio));
	disk_stat_unlock();
	part_stat_unlock();


	/*
	/*
	 * If we're suspended we have to queue
	 * If we're suspended we have to queue
Loading