Commit 76487f02 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jens Axboe
Browse files

z2ram: use separate gendisk for the different modes



Use separate gendisks (which share a tag_set) for the different operating
modes instead of redirecting the gendisk lookup using a probe callback.
This avoids potential problems with aliased block_device instances and
will eventually allow for removing the blk_register_region framework.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 6c3a05e1
Loading
Loading
Loading
Loading
+58 −42
Original line number Diff line number Diff line
@@ -63,7 +63,7 @@ static int current_device = -1;

static DEFINE_SPINLOCK(z2ram_lock);

static struct gendisk *z2ram_gendisk;
static struct gendisk *z2ram_gendisk[Z2MINOR_COUNT];

static blk_status_t z2_queue_rq(struct blk_mq_hw_ctx *hctx,
				const struct blk_mq_queue_data *bd)
@@ -283,7 +283,7 @@ static int z2_open(struct block_device *bdev, fmode_t mode)

		current_device = device;
		z2ram_size <<= Z2RAM_CHUNKSHIFT;
		set_capacity(z2ram_gendisk, z2ram_size >> 9);
		set_capacity(z2ram_gendisk[device], z2ram_size >> 9);
	}

	mutex_unlock(&z2ram_mutex);
@@ -315,71 +315,87 @@ static const struct block_device_operations z2_fops = {
	.release = z2_release,
};

static struct kobject *z2_find(dev_t dev, int *part, void *data)
{
	*part = 0;
	return get_disk_and_module(z2ram_gendisk);
}

static struct request_queue *z2_queue;
static struct blk_mq_tag_set tag_set;

static const struct blk_mq_ops z2_mq_ops = {
	.queue_rq = z2_queue_rq,
};

static int z2ram_register_disk(int minor)
{
	struct request_queue *q;
	struct gendisk *disk;

	disk = alloc_disk(1);
	if (!disk)
		return -ENOMEM;

	q = blk_mq_init_queue(&tag_set);
	if (IS_ERR(q)) {
		put_disk(disk);
		return PTR_ERR(q);
	}

	disk->major = Z2RAM_MAJOR;
	disk->first_minor = minor;
	disk->fops = &z2_fops;
	if (minor)
		sprintf(disk->disk_name, "z2ram%d", minor);
	else
		sprintf(disk->disk_name, "z2ram");
	disk->queue = q;

	z2ram_gendisk[minor] = disk;
	add_disk(disk);
	return 0;
}

static int __init z2_init(void)
{
	int ret;
	int ret, i;

	if (!MACH_IS_AMIGA)
		return -ENODEV;

	ret = -EBUSY;
	if (register_blkdev(Z2RAM_MAJOR, DEVICE_NAME))
		goto err;
		return -EBUSY;

	ret = -ENOMEM;
	z2ram_gendisk = alloc_disk(1);
	if (!z2ram_gendisk)
		goto out_disk;
	tag_set.ops = &z2_mq_ops;
	tag_set.nr_hw_queues = 1;
	tag_set.nr_maps = 1;
	tag_set.queue_depth = 16;
	tag_set.numa_node = NUMA_NO_NODE;
	tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
	ret = blk_mq_alloc_tag_set(&tag_set);
	if (ret)
		goto out_unregister_blkdev;

	z2_queue = blk_mq_init_sq_queue(&tag_set, &z2_mq_ops, 16,
					BLK_MQ_F_SHOULD_MERGE);
	if (IS_ERR(z2_queue)) {
		ret = PTR_ERR(z2_queue);
		z2_queue = NULL;
		goto out_queue;
	for (i = 0; i < Z2MINOR_COUNT; i++) {
		ret = z2ram_register_disk(i);
		if (ret && i == 0)
			goto out_free_tagset;
	}

	z2ram_gendisk->major = Z2RAM_MAJOR;
	z2ram_gendisk->first_minor = 0;
	z2ram_gendisk->fops = &z2_fops;
	sprintf(z2ram_gendisk->disk_name, "z2ram");

	z2ram_gendisk->queue = z2_queue;
	add_disk(z2ram_gendisk);
	blk_register_region(MKDEV(Z2RAM_MAJOR, 0), Z2MINOR_COUNT, THIS_MODULE,
			    z2_find, NULL, NULL);

	return 0;

out_queue:
	put_disk(z2ram_gendisk);
out_disk:
out_free_tagset:
	blk_mq_free_tag_set(&tag_set);
out_unregister_blkdev:
	unregister_blkdev(Z2RAM_MAJOR, DEVICE_NAME);
err:
	return ret;
}

static void __exit z2_exit(void)
{
	int i, j;
	blk_unregister_region(MKDEV(Z2RAM_MAJOR, 0), Z2MINOR_COUNT);

	unregister_blkdev(Z2RAM_MAJOR, DEVICE_NAME);
	del_gendisk(z2ram_gendisk);
	put_disk(z2ram_gendisk);
	blk_cleanup_queue(z2_queue);

	for (i = 0; i < Z2MINOR_COUNT; i++) {
		del_gendisk(z2ram_gendisk[i]);
		blk_cleanup_queue(z2ram_gendisk[i]->queue);
		put_disk(z2ram_gendisk[i]);
	}
	blk_mq_free_tag_set(&tag_set);

	if (current_device != -1) {