Skip to content

Commit

Permalink
amiflop: use separate gendisks for Amiga vs MS-DOS mode
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Christoph Hellwig authored and Jens Axboe committed Nov 16, 2020
1 parent 302cfee commit 0033a9b
Showing 1 changed file with 55 additions and 43 deletions.
98 changes: 55 additions & 43 deletions drivers/block/amiflop.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}

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);

unit[drive].gendisk[system] = disk;
add_disk(disk);
return 0;

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_cleanup_queue;
goto out;

return disk;
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;

out_cleanup_queue:
blk_cleanup_queue(disk->queue);
disk->queue = NULL;
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_put_disk:
put_disk(disk);
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)
Expand All @@ -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)
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 0033a9b

Please sign in to comment.