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

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

block: don't depend on consecutive minor space



* Implement disk_devt() and part_devt() and use them to directly
  access devt instead of computing it from ->major and ->first_minor.

  Note that all references to ->major and ->first_minor outside of
  block layer is used to determine devt of the disk (the part0) and as
  ->major and ->first_minor will continue to represent devt for the
  disk, converting these users aren't strictly necessary.  However,
  convert them for consistency.

* Implement disk_max_parts() to avoid directly deferencing
  genhd->minors.

* Update bdget_disk() such that it doesn't assume consecutive minor
  space.

* Move devt computation from register_disk() to add_disk() and make it
  the only one (all other usages use the initially determined value).

These changes clean up the code and will help disk->part dereference
fix and extended block device numbers.

Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent cf771cb5
Loading
Loading
Loading
Loading
+76 −31
Original line number Original line Diff line number Diff line
@@ -186,13 +186,14 @@ void add_disk(struct gendisk *disk)
	int retval;
	int retval;


	disk->flags |= GENHD_FL_UP;
	disk->flags |= GENHD_FL_UP;
	blk_register_region(MKDEV(disk->major, disk->first_minor),
	disk->dev.devt = MKDEV(disk->major, disk->first_minor);
			    disk->minors, NULL, exact_match, exact_lock, disk);
	blk_register_region(disk_devt(disk), disk->minors, NULL,
			    exact_match, exact_lock, disk);
	register_disk(disk);
	register_disk(disk);
	blk_register_queue(disk);
	blk_register_queue(disk);


	bdi = &disk->queue->backing_dev_info;
	bdi = &disk->queue->backing_dev_info;
	bdi_register_dev(bdi, MKDEV(disk->major, disk->first_minor));
	bdi_register_dev(bdi, disk_devt(disk));
	retval = sysfs_create_link(&disk->dev.kobj, &bdi->dev->kobj, "bdi");
	retval = sysfs_create_link(&disk->dev.kobj, &bdi->dev->kobj, "bdi");
	WARN_ON(retval);
	WARN_ON(retval);
}
}
@@ -205,8 +206,7 @@ void unlink_gendisk(struct gendisk *disk)
	sysfs_remove_link(&disk->dev.kobj, "bdi");
	sysfs_remove_link(&disk->dev.kobj, "bdi");
	bdi_unregister(&disk->queue->backing_dev_info);
	bdi_unregister(&disk->queue->backing_dev_info);
	blk_unregister_queue(disk);
	blk_unregister_queue(disk);
	blk_unregister_region(MKDEV(disk->major, disk->first_minor),
	blk_unregister_region(disk_devt(disk), disk->minors);
			      disk->minors);
}
}


/**
/**
@@ -225,6 +225,38 @@ struct gendisk *get_gendisk(dev_t devt, int *partno)
	return  kobj ? dev_to_disk(dev) : NULL;
	return  kobj ? dev_to_disk(dev) : NULL;
}
}


/**
 * bdget_disk - do bdget() by gendisk and partition number
 * @disk: gendisk of interest
 * @partno: partition number
 *
 * Find partition @partno from @disk, do bdget() on it.
 *
 * CONTEXT:
 * Don't care.
 *
 * RETURNS:
 * Resulting block_device on success, NULL on failure.
 */
extern struct block_device *bdget_disk(struct gendisk *disk, int partno)
{
	dev_t devt = MKDEV(0, 0);

	if (partno == 0)
		devt = disk_devt(disk);
	else {
		struct hd_struct *part = disk->part[partno - 1];

		if (part && part->nr_sects)
			devt = part_devt(part);
	}

	if (likely(devt != MKDEV(0, 0)))
		return bdget(devt);
	return NULL;
}
EXPORT_SYMBOL(bdget_disk);

/*
/*
 * print a full list of all partitions - intended for places where the root
 * print a full list of all partitions - intended for places where the root
 * filesystem can't be mounted and thus to give the victim some idea of what
 * filesystem can't be mounted and thus to give the victim some idea of what
@@ -255,7 +287,7 @@ void __init printk_all_partitions(void)
		 * option takes.
		 * option takes.
		 */
		 */
		printk("%02x%02x %10llu %s",
		printk("%02x%02x %10llu %s",
		       disk->major, disk->first_minor,
		       MAJOR(disk_devt(disk)), MINOR(disk_devt(disk)),
		       (unsigned long long)get_capacity(disk) >> 1,
		       (unsigned long long)get_capacity(disk) >> 1,
		       disk_name(disk, 0, buf));
		       disk_name(disk, 0, buf));
		if (disk->driverfs_dev != NULL &&
		if (disk->driverfs_dev != NULL &&
@@ -266,15 +298,15 @@ void __init printk_all_partitions(void)
			printk(" (driver?)\n");
			printk(" (driver?)\n");


		/* now show the partitions */
		/* now show the partitions */
		for (n = 0; n < disk->minors - 1; ++n) {
		for (n = 0; n < disk_max_parts(disk); ++n) {
			if (disk->part[n] == NULL)
			struct hd_struct *part = disk->part[n];
				continue;

			if (disk->part[n]->nr_sects == 0)
			if (!part || !part->nr_sects)
				continue;
				continue;
			printk("  %02x%02x %10llu %s\n",
			printk("  %02x%02x %10llu %s\n",
			       disk->major, n + 1 + disk->first_minor,
			       MAJOR(part_devt(part)), MINOR(part_devt(part)),
			       (unsigned long long)disk->part[n]->nr_sects >> 1,
			       (unsigned long long)part->nr_sects >> 1,
			       disk_name(disk, n + 1, buf));
			       disk_name(disk, part->partno, buf));
		}
		}
	}
	}
	class_dev_iter_exit(&iter);
	class_dev_iter_exit(&iter);
@@ -343,26 +375,27 @@ static int show_partition(struct seq_file *seqf, void *v)
	char buf[BDEVNAME_SIZE];
	char buf[BDEVNAME_SIZE];


	/* Don't show non-partitionable removeable devices or empty devices */
	/* Don't show non-partitionable removeable devices or empty devices */
	if (!get_capacity(sgp) ||
	if (!get_capacity(sgp) || (!disk_max_parts(sgp) &&
			(sgp->minors == 1 && (sgp->flags & GENHD_FL_REMOVABLE)))
				   (sgp->flags & GENHD_FL_REMOVABLE)))
		return 0;
		return 0;
	if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)
	if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)
		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  %4d %10llu %s\n",
	seq_printf(seqf, "%4d  %4d %10llu %s\n",
		sgp->major, sgp->first_minor,
		MAJOR(disk_devt(sgp)), MINOR(disk_devt(sgp)),
		(unsigned long long)get_capacity(sgp) >> 1,
		(unsigned long long)get_capacity(sgp) >> 1,
		disk_name(sgp, 0, buf));
		disk_name(sgp, 0, buf));
	for (n = 0; n < sgp->minors - 1; n++) {
	for (n = 0; n < disk_max_parts(sgp); n++) {
		if (!sgp->part[n])
		struct hd_struct *part = sgp->part[n];
		if (!part)
			continue;
			continue;
		if (sgp->part[n]->nr_sects == 0)
		if (part->nr_sects == 0)
			continue;
			continue;
		seq_printf(seqf, "%4d  %4d %10llu %s\n",
		seq_printf(seqf, "%4d  %4d %10llu %s\n",
			sgp->major, n + 1 + sgp->first_minor,
			   MAJOR(part_devt(part)), MINOR(part_devt(part)),
			(unsigned long long)sgp->part[n]->nr_sects >> 1 ,
			   (unsigned long long)part->nr_sects >> 1,
			disk_name(sgp, n + 1, buf));
			   disk_name(sgp, part->partno, buf));
	}
	}


	return 0;
	return 0;
@@ -578,7 +611,8 @@ static int diskstats_show(struct seq_file *seqf, void *v)
	disk_round_stats(gp);
	disk_round_stats(gp);
	preempt_enable();
	preempt_enable();
	seq_printf(seqf, "%4d %4d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n",
	seq_printf(seqf, "%4d %4d %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u\n",
		gp->major, gp->first_minor, disk_name(gp, 0, buf),
		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]),
		disk_stat_read(gp, ios[0]), disk_stat_read(gp, merges[0]),
		(unsigned long long)disk_stat_read(gp, sectors[0]),
		(unsigned long long)disk_stat_read(gp, sectors[0]),
		jiffies_to_msecs(disk_stat_read(gp, ticks[0])),
		jiffies_to_msecs(disk_stat_read(gp, ticks[0])),
@@ -590,7 +624,7 @@ static int diskstats_show(struct seq_file *seqf, void *v)
		jiffies_to_msecs(disk_stat_read(gp, time_in_queue)));
		jiffies_to_msecs(disk_stat_read(gp, time_in_queue)));


	/* now show all non-0 size partitions of it */
	/* now show all non-0 size partitions of it */
	for (n = 0; n < gp->minors - 1; n++) {
	for (n = 0; n < disk_max_parts(gp); n++) {
		struct hd_struct *hd = gp->part[n];
		struct hd_struct *hd = gp->part[n];


		if (!hd || !hd->nr_sects)
		if (!hd || !hd->nr_sects)
@@ -601,8 +635,8 @@ static int diskstats_show(struct seq_file *seqf, void *v)
		preempt_enable();
		preempt_enable();
		seq_printf(seqf, "%4d %4d %s %lu %lu %llu "
		seq_printf(seqf, "%4d %4d %s %lu %lu %llu "
			   "%u %lu %lu %llu %u %u %u %u\n",
			   "%u %lu %lu %llu %u %u %u %u\n",
			   gp->major, n + gp->first_minor + 1,
			   MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
			   disk_name(gp, n + 1, buf),
			   disk_name(gp, hd->partno, buf),
			   part_stat_read(hd, ios[0]),
			   part_stat_read(hd, ios[0]),
			   part_stat_read(hd, merges[0]),
			   part_stat_read(hd, merges[0]),
			   (unsigned long long)part_stat_read(hd, sectors[0]),
			   (unsigned long long)part_stat_read(hd, sectors[0]),
@@ -661,11 +695,22 @@ dev_t blk_lookup_devt(const char *name, int partno)
	while ((dev = class_dev_iter_next(&iter))) {
	while ((dev = class_dev_iter_next(&iter))) {
		struct gendisk *disk = dev_to_disk(dev);
		struct gendisk *disk = dev_to_disk(dev);


		if (!strcmp(dev->bus_id, name) && partno < disk->minors) {
		if (strcmp(dev->bus_id, name))
			devt = MKDEV(MAJOR(dev->devt),
			continue;
				     MINOR(dev->devt) + partno);
		if (partno < 0 || partno > disk_max_parts(disk))
			break;
			continue;

		if (partno == 0)
			devt = disk_devt(disk);
		else {
			struct hd_struct *part = disk->part[partno - 1];

			if (!part || !part->nr_sects)
				continue;

			devt = part_devt(part);
		}
		}
		break;
	}
	}
	class_dev_iter_exit(&iter);
	class_dev_iter_exit(&iter);
	return devt;
	return devt;
@@ -755,7 +800,7 @@ void set_disk_ro(struct gendisk *disk, int flag)
{
{
	int i;
	int i;
	disk->policy = flag;
	disk->policy = flag;
	for (i = 0; i < disk->minors - 1; i++)
	for (i = 0; i < disk_max_parts(disk); i++)
		if (disk->part[i]) disk->part[i]->policy = flag;
		if (disk->part[i]) disk->part[i]->policy = flag;
}
}


+3 −3
Original line number Original line Diff line number Diff line
@@ -29,7 +29,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
	if (bdev != bdev->bd_contains)
	if (bdev != bdev->bd_contains)
		return -EINVAL;
		return -EINVAL;
	partno = p.pno;
	partno = p.pno;
	if (partno <= 0 || partno >= disk->minors)
	if (partno <= 0 || partno > disk_max_parts(disk))
		return -EINVAL;
		return -EINVAL;
	switch (a.op) {
	switch (a.op) {
		case BLKPG_ADD_PARTITION:
		case BLKPG_ADD_PARTITION:
@@ -47,7 +47,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
			mutex_lock(&bdev->bd_mutex);
			mutex_lock(&bdev->bd_mutex);


			/* overlap? */
			/* overlap? */
			for (i = 0; i < disk->minors - 1; i++) {
			for (i = 0; i < disk_max_parts(disk); i++) {
				struct hd_struct *s = disk->part[i];
				struct hd_struct *s = disk->part[i];


				if (!s)
				if (!s)
@@ -96,7 +96,7 @@ static int blkdev_reread_part(struct block_device *bdev)
	struct gendisk *disk = bdev->bd_disk;
	struct gendisk *disk = bdev->bd_disk;
	int res;
	int res;


	if (disk->minors == 1 || bdev != bdev->bd_contains)
	if (!disk_max_parts(disk) || bdev != bdev->bd_contains)
		return -EINVAL;
		return -EINVAL;
	if (!capable(CAP_SYS_ADMIN))
	if (!capable(CAP_SYS_ADMIN))
		return -EACCES;
		return -EACCES;
+1 −1
Original line number Original line Diff line number Diff line
@@ -2911,7 +2911,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
	if (!disk->queue)
	if (!disk->queue)
		goto out_mem2;
		goto out_mem2;


	pd->pkt_dev = MKDEV(disk->major, disk->first_minor);
	pd->pkt_dev = MKDEV(pktdev_major, idx);
	ret = pkt_new_dev(pd, dev);
	ret = pkt_new_dev(pd, dev);
	if (ret)
	if (ret)
		goto out_new_dev;
		goto out_new_dev;
+1 −1
Original line number Original line Diff line number Diff line
@@ -541,7 +541,7 @@ static int ps3disk_remove(struct ps3_system_bus_device *_dev)
	struct ps3disk_private *priv = dev->sbd.core.driver_data;
	struct ps3disk_private *priv = dev->sbd.core.driver_data;


	mutex_lock(&ps3disk_mask_mutex);
	mutex_lock(&ps3disk_mask_mutex);
	__clear_bit(priv->gendisk->first_minor / PS3DISK_MINORS,
	__clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS,
		    &ps3disk_mask);
		    &ps3disk_mask);
	mutex_unlock(&ps3disk_mask_mutex);
	mutex_unlock(&ps3disk_mask_mutex);
	del_gendisk(priv->gendisk);
	del_gendisk(priv->gendisk);
+3 −3
Original line number Original line Diff line number Diff line
@@ -661,10 +661,10 @@ void add_disk_randomness(struct gendisk *disk)
	if (!disk || !disk->random)
	if (!disk || !disk->random)
		return;
		return;
	/* first major is 1, so we get >= 0x200 here */
	/* first major is 1, so we get >= 0x200 here */
	DEBUG_ENT("disk event %d:%d\n", disk->major, disk->first_minor);
	DEBUG_ENT("disk event %d:%d\n",
		  MAJOR(disk_devt(disk)), MINOR(disk_devt(disk)));


	add_timer_randomness(disk->random,
	add_timer_randomness(disk->random, 0x100 + disk_devt(disk));
			     0x100 + MKDEV(disk->major, disk->first_minor));
}
}
#endif
#endif


Loading