Commit 0d02129e authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jens Axboe
Browse files

block: merge struct block_device and struct hd_struct



Instead of having two structures that represent each block device with
different life time rules, merge them into a single one.  This also
greatly simplifies the reference counting rules, as we can use the inode
reference count as the main reference count for the new struct
block_device, with the device model reference front ending it for device
model interaction.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarJan Kara <jack@suse.cz>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 9499ffc7
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -820,9 +820,9 @@ static void blkcg_fill_root_iostats(void)

	class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
	while ((dev = class_dev_iter_next(&iter))) {
		struct gendisk *disk = dev_to_disk(dev);
		struct hd_struct *part = disk_get_part(disk, 0);
		struct blkcg_gq *blkg = blk_queue_root_blkg(disk->queue);
		struct block_device *bdev = dev_to_bdev(dev);
		struct blkcg_gq *blkg =
			blk_queue_root_blkg(bdev->bd_disk->queue);
		struct blkg_iostat tmp;
		int cpu;

@@ -830,7 +830,7 @@ static void blkcg_fill_root_iostats(void)
		for_each_possible_cpu(cpu) {
			struct disk_stats *cpu_dkstats;

			cpu_dkstats = per_cpu_ptr(part->bdev->bd_stats, cpu);
			cpu_dkstats = per_cpu_ptr(bdev->bd_stats, cpu);
			tmp.ios[BLKG_IOSTAT_READ] +=
				cpu_dkstats->ios[STAT_READ];
			tmp.ios[BLKG_IOSTAT_WRITE] +=
+1 −1
Original line number Diff line number Diff line
@@ -356,7 +356,7 @@ char *disk_name(struct gendisk *hd, int partno, char *buf);
#define ADDPART_FLAG_NONE	0
#define ADDPART_FLAG_RAID	1
#define ADDPART_FLAG_WHOLEDISK	2
void delete_partition(struct hd_struct *part);
void delete_partition(struct block_device *part);
int bdev_add_partition(struct block_device *bdev, int partno,
		sector_t start, sector_t length);
int bdev_del_partition(struct block_device *bdev, int partno);
+26 −64
Original line number Diff line number Diff line
@@ -106,13 +106,14 @@ const char *bdevname(struct block_device *bdev, char *buf)
}
EXPORT_SYMBOL(bdevname);

static void part_stat_read_all(struct hd_struct *part, struct disk_stats *stat)
static void part_stat_read_all(struct block_device *part,
		struct disk_stats *stat)
{
	int cpu;

	memset(stat, 0, sizeof(struct disk_stats));
	for_each_possible_cpu(cpu) {
		struct disk_stats *ptr = per_cpu_ptr(part->bdev->bd_stats, cpu);
		struct disk_stats *ptr = per_cpu_ptr(part->bd_stats, cpu);
		int group;

		for (group = 0; group < NR_STAT_GROUPS; group++) {
@@ -167,39 +168,6 @@ struct block_device *__disk_get_part(struct gendisk *disk, int partno)
	return rcu_dereference(ptbl->part[partno]);
}

/**
 * disk_get_part - get partition
 * @disk: disk to look partition from
 * @partno: partition number
 *
 * Look for partition @partno from @disk.  If found, increment
 * reference count and return it.
 *
 * CONTEXT:
 * Don't care.
 *
 * RETURNS:
 * Pointer to the found partition on success, NULL if not found.
 */
struct hd_struct *disk_get_part(struct gendisk *disk, int partno)
{
	struct block_device *bdev;
	struct hd_struct *part;

	rcu_read_lock();
	bdev = __disk_get_part(disk, partno);
	if (!bdev)
		goto fail;
	part = bdev->bd_part;
	if (!kobject_get_unless_zero(&part_to_dev(part)->kobj))
		goto fail;
	rcu_read_unlock();
	return part;
fail:
	rcu_read_unlock();
	return NULL;
}

/**
 * disk_part_iter_init - initialize partition iterator
 * @piter: iterator to initialize
@@ -859,7 +827,7 @@ void del_gendisk(struct gendisk *disk)
			     DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE);
	while ((part = disk_part_iter_next(&piter))) {
		invalidate_partition(part);
		delete_partition(part->bd_part);
		delete_partition(part);
	}
	disk_part_iter_exit(&piter);

@@ -952,13 +920,13 @@ void blk_request_module(dev_t devt)
 */
struct block_device *bdget_disk(struct gendisk *disk, int partno)
{
	struct hd_struct *part;
	struct block_device *bdev = NULL;

	part = disk_get_part(disk, partno);
	if (part)
		bdev = bdget_part(part);
	disk_put_part(part);
	rcu_read_lock();
	bdev = __disk_get_part(disk, partno);
	if (bdev && !bdgrab(bdev))
		bdev = NULL;
	rcu_read_unlock();

	return bdev;
}
@@ -1175,24 +1143,22 @@ static ssize_t disk_ro_show(struct device *dev,
ssize_t part_size_show(struct device *dev,
		       struct device_attribute *attr, char *buf)
{
	struct hd_struct *p = dev_to_part(dev);

	return sprintf(buf, "%llu\n", bdev_nr_sectors(p->bdev));
	return sprintf(buf, "%llu\n", bdev_nr_sectors(dev_to_bdev(dev)));
}

ssize_t part_stat_show(struct device *dev,
		       struct device_attribute *attr, char *buf)
{
	struct hd_struct *p = dev_to_part(dev);
	struct request_queue *q = part_to_disk(p)->queue;
	struct block_device *bdev = dev_to_bdev(dev);
	struct request_queue *q = bdev->bd_disk->queue;
	struct disk_stats stat;
	unsigned int inflight;

	part_stat_read_all(p, &stat);
	part_stat_read_all(bdev, &stat);
	if (queue_is_mq(q))
		inflight = blk_mq_in_flight(q, p->bdev);
		inflight = blk_mq_in_flight(q, bdev);
	else
		inflight = part_in_flight(p->bdev);
		inflight = part_in_flight(bdev);

	return sprintf(buf,
		"%8lu %8lu %8llu %8u "
@@ -1227,14 +1193,14 @@ ssize_t part_stat_show(struct device *dev,
ssize_t part_inflight_show(struct device *dev, struct device_attribute *attr,
			   char *buf)
{
	struct hd_struct *p = dev_to_part(dev);
	struct request_queue *q = part_to_disk(p)->queue;
	struct block_device *bdev = dev_to_bdev(dev);
	struct request_queue *q = bdev->bd_disk->queue;
	unsigned int inflight[2];

	if (queue_is_mq(q))
		blk_mq_in_flight_rw(q, p->bdev, inflight);
		blk_mq_in_flight_rw(q, bdev, inflight);
	else
		part_in_flight_rw(p->bdev, inflight);
		part_in_flight_rw(bdev, inflight);

	return sprintf(buf, "%8u %8u\n", inflight[0], inflight[1]);
}
@@ -1282,20 +1248,17 @@ static DEVICE_ATTR(badblocks, 0644, disk_badblocks_show, disk_badblocks_store);
ssize_t part_fail_show(struct device *dev,
		       struct device_attribute *attr, char *buf)
{
	struct hd_struct *p = dev_to_part(dev);

	return sprintf(buf, "%d\n", p->bdev->bd_make_it_fail);
	return sprintf(buf, "%d\n", dev_to_bdev(dev)->bd_make_it_fail);
}

ssize_t part_fail_store(struct device *dev,
			struct device_attribute *attr,
			const char *buf, size_t count)
{
	struct hd_struct *p = dev_to_part(dev);
	int i;

	if (count > 0 && sscanf(buf, "%d", &i) > 0)
		p->bdev->bd_make_it_fail = i;
		dev_to_bdev(dev)->bd_make_it_fail = i;

	return count;
}
@@ -1505,7 +1468,7 @@ static int diskstats_show(struct seq_file *seqf, void *v)

	disk_part_iter_init(&piter, gp, DISK_PITER_INCL_EMPTY_PART0);
	while ((hd = disk_part_iter_next(&piter))) {
		part_stat_read_all(hd->bd_part, &stat);
		part_stat_read_all(hd, &stat);
		if (queue_is_mq(gp->queue))
			inflight = blk_mq_in_flight(gp->queue, hd);
		else
@@ -1577,7 +1540,7 @@ dev_t blk_lookup_devt(const char *name, int partno)
	class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
	while ((dev = class_dev_iter_next(&iter))) {
		struct gendisk *disk = dev_to_disk(dev);
		struct hd_struct *part;
		struct block_device *part;

		if (strcmp(dev_name(dev), name))
			continue;
@@ -1590,13 +1553,12 @@ dev_t blk_lookup_devt(const char *name, int partno)
				     MINOR(dev->devt) + partno);
			break;
		}
		part = disk_get_part(disk, partno);
		part = bdget_disk(disk, partno);
		if (part) {
			devt = part_devt(part);
			disk_put_part(part);
			devt = part->bd_dev;
			bdput(part);
			break;
		}
		disk_put_part(part);
	}
	class_dev_iter_exit(&iter);
	return devt;
+44 −72
Original line number Diff line number Diff line
@@ -182,44 +182,39 @@ static struct parsed_partitions *check_partition(struct gendisk *hd,
static ssize_t part_partition_show(struct device *dev,
				   struct device_attribute *attr, char *buf)
{
	struct hd_struct *p = dev_to_part(dev);

	return sprintf(buf, "%d\n", p->bdev->bd_partno);
	return sprintf(buf, "%d\n", dev_to_bdev(dev)->bd_partno);
}

static ssize_t part_start_show(struct device *dev,
			       struct device_attribute *attr, char *buf)
{
	struct hd_struct *p = dev_to_part(dev);

	return sprintf(buf, "%llu\n", p->bdev->bd_start_sect);
	return sprintf(buf, "%llu\n", dev_to_bdev(dev)->bd_start_sect);
}

static ssize_t part_ro_show(struct device *dev,
			    struct device_attribute *attr, char *buf)
{
	struct hd_struct *p = dev_to_part(dev);
	return sprintf(buf, "%d\n", p->bdev->bd_read_only);
	return sprintf(buf, "%d\n", dev_to_bdev(dev)->bd_read_only);
}

static ssize_t part_alignment_offset_show(struct device *dev,
					  struct device_attribute *attr, char *buf)
{
	struct hd_struct *p = dev_to_part(dev);
	struct block_device *bdev = dev_to_bdev(dev);

	return sprintf(buf, "%u\n",
		queue_limit_alignment_offset(&part_to_disk(p)->queue->limits,
				p->bdev->bd_start_sect));
		queue_limit_alignment_offset(&bdev->bd_disk->queue->limits,
				bdev->bd_start_sect));
}

static ssize_t part_discard_alignment_show(struct device *dev,
					   struct device_attribute *attr, char *buf)
{
	struct hd_struct *p = dev_to_part(dev);
	struct block_device *bdev = dev_to_bdev(dev);

	return sprintf(buf, "%u\n",
		queue_limit_discard_alignment(&part_to_disk(p)->queue->limits,
				p->bdev->bd_start_sect));
		queue_limit_discard_alignment(&bdev->bd_disk->queue->limits,
				bdev->bd_start_sect));
}

static DEVICE_ATTR(partition, 0444, part_partition_show, NULL);
@@ -264,20 +259,17 @@ static const struct attribute_group *part_attr_groups[] = {

static void part_release(struct device *dev)
{
	struct hd_struct *p = dev_to_part(dev);

	blk_free_devt(dev->devt);
	bdput(p->bdev);
	bdput(dev_to_bdev(dev));
}

static int part_uevent(struct device *dev, struct kobj_uevent_env *env)
{
	struct hd_struct *part = dev_to_part(dev);
	struct block_device *part = dev_to_bdev(dev);

	add_uevent_var(env, "PARTN=%u", part->bdev->bd_partno);
	if (part->bdev->bd_meta_info && part->bdev->bd_meta_info->volname[0])
		add_uevent_var(env, "PARTNAME=%s",
			       part->bdev->bd_meta_info->volname);
	add_uevent_var(env, "PARTN=%u", part->bd_partno);
	if (part->bd_meta_info && part->bd_meta_info->volname[0])
		add_uevent_var(env, "PARTNAME=%s", part->bd_meta_info->volname);
	return 0;
}

@@ -292,25 +284,25 @@ struct device_type part_type = {
 * Must be called either with bd_mutex held, before a disk can be opened or
 * after all disk users are gone.
 */
void delete_partition(struct hd_struct *part)
void delete_partition(struct block_device *part)
{
	struct gendisk *disk = part_to_disk(part);
	struct gendisk *disk = part->bd_disk;
	struct disk_part_tbl *ptbl =
		rcu_dereference_protected(disk->part_tbl, 1);

	rcu_assign_pointer(ptbl->part[part->bdev->bd_partno], NULL);
	rcu_assign_pointer(ptbl->part[part->bd_partno], NULL);
	rcu_assign_pointer(ptbl->last_lookup, NULL);

	kobject_put(part->bdev->bd_holder_dir);
	device_del(part_to_dev(part));
	kobject_put(part->bd_holder_dir);
	device_del(&part->bd_device);

	/*
	 * Remove the block device from the inode hash, so that it cannot be
	 * looked up any more even when openers still hold references.
	 */
	remove_inode_hash(part->bdev->bd_inode);
	remove_inode_hash(part->bd_inode);

	put_device(part_to_dev(part));
	put_device(&part->bd_device);
}

static ssize_t whole_disk_show(struct device *dev,
@@ -324,11 +316,10 @@ static DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL);
 * Must be called either with bd_mutex held, before a disk can be opened or
 * after all disk users are gone.
 */
static struct hd_struct *add_partition(struct gendisk *disk, int partno,
static struct block_device *add_partition(struct gendisk *disk, int partno,
				sector_t start, sector_t len, int flags,
				struct partition_meta_info *info)
{
	struct hd_struct *p;
	dev_t devt = MKDEV(0, 0);
	struct device *ddev = disk_to_dev(disk);
	struct device *pdev;
@@ -367,9 +358,6 @@ static struct hd_struct *add_partition(struct gendisk *disk, int partno,
	if (!bdev)
		return ERR_PTR(-ENOMEM);

	p = bdev->bd_part;
	pdev = part_to_dev(p);

	bdev->bd_start_sect = start;
	bdev_set_nr_sectors(bdev, len);
	bdev->bd_read_only = get_disk_ro(disk);
@@ -381,6 +369,7 @@ static struct hd_struct *add_partition(struct gendisk *disk, int partno,
			goto out_bdput;
	}

	pdev = &bdev->bd_device;
	dname = dev_name(ddev);
	if (isdigit(dname[strlen(dname) - 1]))
		dev_set_name(pdev, "%sp%d", dname, partno);
@@ -422,7 +411,7 @@ static struct hd_struct *add_partition(struct gendisk *disk, int partno,
	/* suppress uevent if the disk suppresses it */
	if (!dev_get_uevent_suppress(ddev))
		kobject_uevent(&pdev->kobj, KOBJ_ADD);
	return p;
	return bdev;

out_bdput:
	bdput(bdev);
@@ -459,7 +448,7 @@ static bool partition_overlaps(struct gendisk *disk, sector_t start,
int bdev_add_partition(struct block_device *bdev, int partno,
		sector_t start, sector_t length)
{
	struct hd_struct *part;
	struct block_device *part;

	mutex_lock(&bdev->bd_mutex);
	if (partition_overlaps(bdev->bd_disk, start, length, -1)) {
@@ -475,76 +464,59 @@ int bdev_add_partition(struct block_device *bdev, int partno,

int bdev_del_partition(struct block_device *bdev, int partno)
{
	struct block_device *bdevp;
	struct hd_struct *part = NULL;
	struct block_device *part;
	int ret;

	bdevp = bdget_disk(bdev->bd_disk, partno);
	if (!bdevp)
	part = bdget_disk(bdev->bd_disk, partno);
	if (!part)
		return -ENXIO;

	mutex_lock(&bdevp->bd_mutex);
	mutex_lock(&part->bd_mutex);
	mutex_lock_nested(&bdev->bd_mutex, 1);

	ret = -ENXIO;
	part = disk_get_part(bdev->bd_disk, partno);
	if (!part)
		goto out_unlock;

	ret = -EBUSY;
	if (bdevp->bd_openers)
	if (part->bd_openers)
		goto out_unlock;

	sync_blockdev(bdevp);
	invalidate_bdev(bdevp);
	sync_blockdev(part);
	invalidate_bdev(part);

	delete_partition(part);
	ret = 0;
out_unlock:
	mutex_unlock(&bdev->bd_mutex);
	mutex_unlock(&bdevp->bd_mutex);
	bdput(bdevp);
	if (part)
		disk_put_part(part);
	mutex_unlock(&part->bd_mutex);
	bdput(part);
	return ret;
}

int bdev_resize_partition(struct block_device *bdev, int partno,
		sector_t start, sector_t length)
{
	struct block_device *bdevp;
	struct hd_struct *part;
	struct block_device *part;
	int ret = 0;

	part = disk_get_part(bdev->bd_disk, partno);
	part = bdget_disk(bdev->bd_disk, partno);
	if (!part)
		return -ENXIO;

	ret = -ENOMEM;
	bdevp = bdget_part(part);
	if (!bdevp)
		goto out_put_part;

	mutex_lock(&bdevp->bd_mutex);
	mutex_lock(&part->bd_mutex);
	mutex_lock_nested(&bdev->bd_mutex, 1);

	ret = -EINVAL;
	if (start != part->bdev->bd_start_sect)
	if (start != part->bd_start_sect)
		goto out_unlock;

	ret = -EBUSY;
	if (partition_overlaps(bdev->bd_disk, start, length, partno))
		goto out_unlock;

	bdev_set_nr_sectors(bdevp, length);
	bdev_set_nr_sectors(part, length);

	ret = 0;
out_unlock:
	mutex_unlock(&bdevp->bd_mutex);
	mutex_unlock(&part->bd_mutex);
	mutex_unlock(&bdev->bd_mutex);
	bdput(bdevp);
out_put_part:
	disk_put_part(part);
	bdput(part);
	return ret;
}

@@ -577,7 +549,7 @@ int blk_drop_partitions(struct block_device *bdev)

	disk_part_iter_init(&piter, bdev->bd_disk, DISK_PITER_INCL_EMPTY);
	while ((part = disk_part_iter_next(&piter)))
		delete_partition(part->bd_part);
		delete_partition(part);
	disk_part_iter_exit(&piter);

	return 0;
@@ -592,7 +564,7 @@ static bool blk_add_partition(struct gendisk *disk, struct block_device *bdev,
{
	sector_t size = state->parts[p].size;
	sector_t from = state->parts[p].from;
	struct hd_struct *part;
	struct block_device *part;

	if (!size)
		return true;
@@ -632,7 +604,7 @@ static bool blk_add_partition(struct gendisk *disk, struct block_device *bdev,

	if (IS_BUILTIN(CONFIG_BLK_DEV_MD) &&
	    (state->parts[p].flags & ADDPART_FLAG_RAID))
		md_autodetect_dev(part_to_dev(part)->devt);
		md_autodetect_dev(part->bd_dev);

	return true;
}
+0 −9
Original line number Diff line number Diff line
@@ -39,7 +39,6 @@

struct bdev_inode {
	struct block_device bdev;
	struct hd_struct hd;
	struct inode vfs_inode;
};

@@ -887,9 +886,6 @@ struct block_device *bdev_alloc(struct gendisk *disk, u8 partno)
		iput(inode);
		return NULL;
	}
	bdev->bd_part = &BDEV_I(inode)->hd;
	memset(bdev->bd_part, 0, sizeof(*bdev->bd_part));
	bdev->bd_part->bdev = bdev;
	return bdev;
}

@@ -926,11 +922,6 @@ struct block_device *bdgrab(struct block_device *bdev)
}
EXPORT_SYMBOL(bdgrab);

struct block_device *bdget_part(struct hd_struct *part)
{
	return bdget(part_devt(part));
}

long nr_blockdev_pages(void)
{
	struct inode *inode;
Loading