amiflop: use separate gendisks for Amiga vs MS-DOS mode

Use separate gendisks (which share a tag_set) for the native Amgiga vs
the MS-DOS mode 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: Christoph Hellwig <hch@lst.de>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Christoph Hellwig 2020-10-29 15:58:37 +01:00 committed by Jens Axboe
parent 302cfee150
commit 0033a9b41f
1 changed files with 56 additions and 44 deletions

View File

@ -201,7 +201,7 @@ struct amiga_floppy_struct {
int busy; /* true when drive is active */
int dirty; /* true when trackbuf is not on disk */
int status; /* current error code for unit */
struct gendisk *gendisk;
struct gendisk *gendisk[2];
struct blk_mq_tag_set tag_set;
};
@ -1669,6 +1669,11 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
return -EBUSY;
}
if (unit[drive].type->code == FD_NODRIVE) {
mutex_unlock(&amiflop_mutex);
return -ENXIO;
}
if (mode & (FMODE_READ|FMODE_WRITE)) {
bdev_check_media_change(bdev);
if (mode & FMODE_WRITE) {
@ -1695,7 +1700,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
unit[drive].dtype=&data_types[system];
unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks*
data_types[system].sects*unit[drive].type->sect_mult;
set_capacity(unit[drive].gendisk, unit[drive].blocks);
set_capacity(unit[drive].gendisk[system], unit[drive].blocks);
printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive,
unit[drive].type->name, data_types[system].name);
@ -1772,36 +1777,68 @@ static const struct blk_mq_ops amiflop_mq_ops = {
.queue_rq = amiflop_queue_rq,
};
static struct gendisk *fd_alloc_disk(int drive)
static int fd_alloc_disk(int drive, int system)
{
struct gendisk *disk;
disk = alloc_disk(1);
if (!disk)
goto out;
disk->queue = blk_mq_init_sq_queue(&unit[drive].tag_set, &amiflop_mq_ops,
2, BLK_MQ_F_SHOULD_MERGE);
if (IS_ERR(disk->queue)) {
disk->queue = NULL;
disk->queue = blk_mq_init_queue(&unit[drive].tag_set);
if (IS_ERR(disk->queue))
goto out_put_disk;
}
unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL);
if (!unit[drive].trackbuf)
goto out_cleanup_queue;
disk->major = FLOPPY_MAJOR;
disk->first_minor = drive + system;
disk->fops = &floppy_fops;
disk->events = DISK_EVENT_MEDIA_CHANGE;
if (system)
sprintf(disk->disk_name, "fd%d_msdos", drive);
else
sprintf(disk->disk_name, "fd%d", drive);
disk->private_data = &unit[drive];
set_capacity(disk, 880 * 2);
return disk;
unit[drive].gendisk[system] = disk;
add_disk(disk);
return 0;
out_cleanup_queue:
blk_cleanup_queue(disk->queue);
disk->queue = NULL;
blk_mq_free_tag_set(&unit[drive].tag_set);
out_put_disk:
disk->queue = NULL;
put_disk(disk);
out:
return -ENOMEM;
}
static int fd_alloc_drive(int drive)
{
unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL);
if (!unit[drive].trackbuf)
goto out;
memset(&unit[drive].tag_set, 0, sizeof(unit[drive].tag_set));
unit[drive].tag_set.ops = &amiflop_mq_ops;
unit[drive].tag_set.nr_hw_queues = 1;
unit[drive].tag_set.nr_maps = 1;
unit[drive].tag_set.queue_depth = 2;
unit[drive].tag_set.numa_node = NUMA_NO_NODE;
unit[drive].tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
if (blk_mq_alloc_tag_set(&unit[drive].tag_set))
goto out_cleanup_trackbuf;
pr_cont(" fd%d", drive);
if (fd_alloc_disk(drive, 0) || fd_alloc_disk(drive, 1))
goto out_cleanup_tagset;
return 0;
out_cleanup_tagset:
blk_mq_free_tag_set(&unit[drive].tag_set);
out_cleanup_trackbuf:
kfree(unit[drive].trackbuf);
out:
unit[drive].type->code = FD_NODRIVE;
return NULL;
return -ENOMEM;
}
static int __init fd_probe_drives(void)
@ -1812,29 +1849,16 @@ static int __init fd_probe_drives(void)
drives=0;
nomem=0;
for(drive=0;drive<FD_MAX_UNITS;drive++) {
struct gendisk *disk;
fd_probe(drive);
if (unit[drive].type->code == FD_NODRIVE)
continue;
disk = fd_alloc_disk(drive);
if (!disk) {
if (fd_alloc_drive(drive) < 0) {
pr_cont(" no mem for fd%d", drive);
nomem = 1;
continue;
}
unit[drive].gendisk = disk;
drives++;
pr_cont(" fd%d",drive);
disk->major = FLOPPY_MAJOR;
disk->first_minor = drive;
disk->fops = &floppy_fops;
disk->events = DISK_EVENT_MEDIA_CHANGE;
sprintf(disk->disk_name, "fd%d", drive);
disk->private_data = &unit[drive];
set_capacity(disk, 880*2);
add_disk(disk);
}
if ((drives > 0) || (nomem == 0)) {
if (drives == 0)
@ -1846,15 +1870,6 @@ static int __init fd_probe_drives(void)
return -ENOMEM;
}
static struct kobject *floppy_find(dev_t dev, int *part, void *data)
{
int drive = *part & 3;
if (unit[drive].type->code == FD_NODRIVE)
return NULL;
*part = 0;
return get_disk_and_module(unit[drive].gendisk);
}
static int __init amiga_floppy_probe(struct platform_device *pdev)
{
int i, ret;
@ -1884,9 +1899,6 @@ static int __init amiga_floppy_probe(struct platform_device *pdev)
if (fd_probe_drives() < 1) /* No usable drives */
goto out_probe;
blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
floppy_find, NULL, NULL);
/* initialize variables */
timer_setup(&motor_on_timer, motor_on_callback, 0);
motor_on_timer.expires = 0;