Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ataflop: use a separate gendisk for each media format

The Atari floppy driver usually autodetects the media when used with the
ormal /dev/fd? devices, which also are the only nodes created by udev.
But it also supports various aliases that force a given media format.
That is currently supported using the blk_register_region framework
which finds the floppy gendisk even for a 'mismatched' dev_t. The
problem with this (besides the code complexity) is that it creates
multiple struct block_device instances for the whole device of a
single gendisk, which can lead to interesting issues in code not
aware of that fact.

To fix this just create a separate gendisk for each of the aliases
if they are accessed.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Christoph Hellwig and committed by
Jens Axboe
bf9c0538 0033a9b4

+86 -49
+86 -49
drivers/block/ataflop.c
··· 297 297 unsigned int wpstat; /* current state of WP signal (for 298 298 disk change detection) */ 299 299 int flags; /* flags */ 300 - struct gendisk *disk; 300 + struct gendisk *disk[NUM_DISK_MINORS]; 301 301 int ref; 302 302 int type; 303 303 struct blk_mq_tag_set tag_set; ··· 723 723 724 724 static int do_format(int drive, int type, struct atari_format_descr *desc) 725 725 { 726 - struct request_queue *q = unit[drive].disk->queue; 726 + struct request_queue *q; 727 727 unsigned char *p; 728 728 int sect, nsect; 729 729 unsigned long flags; 730 730 int ret; 731 731 732 + if (type) 733 + type--; 734 + 735 + q = unit[drive].disk[type]->queue; 732 736 blk_mq_freeze_queue(q); 733 737 blk_mq_quiesce_queue(q); 734 738 ··· 742 738 local_irq_restore(flags); 743 739 744 740 if (type) { 745 - if (--type >= NUM_DISK_MINORS || 741 + if (type >= NUM_DISK_MINORS || 746 742 minor2disktype[type].drive_types > DriveType) { 747 743 ret = -EINVAL; 748 744 goto out; ··· 1158 1154 if (SUDT[-1].blocks > ReqBlock) { 1159 1155 /* try another disk type */ 1160 1156 SUDT--; 1161 - set_capacity(unit[SelectedDrive].disk, 1157 + set_capacity(unit[SelectedDrive].disk[0], 1162 1158 SUDT->blocks); 1163 1159 } else 1164 1160 Probing = 0; ··· 1173 1169 /* record not found, but not probing. Maybe stretch wrong ? Restart probing */ 1174 1170 if (SUD.autoprobe) { 1175 1171 SUDT = atari_disk_type + StartDiskType[DriveType]; 1176 - set_capacity(unit[SelectedDrive].disk, 1172 + set_capacity(unit[SelectedDrive].disk[0], 1177 1173 SUDT->blocks); 1178 1174 Probing = 1; 1179 1175 } ··· 1519 1515 if (!UDT) { 1520 1516 Probing = 1; 1521 1517 UDT = atari_disk_type + StartDiskType[DriveType]; 1522 - set_capacity(floppy->disk, UDT->blocks); 1518 + set_capacity(bd->rq->rq_disk, UDT->blocks); 1523 1519 UD.autoprobe = 1; 1524 1520 } 1525 1521 } ··· 1537 1533 } 1538 1534 type = minor2disktype[type].index; 1539 1535 UDT = &atari_disk_type[type]; 1540 - set_capacity(floppy->disk, UDT->blocks); 1536 + set_capacity(bd->rq->rq_disk, UDT->blocks); 1541 1537 UD.autoprobe = 0; 1542 1538 } 1543 1539 ··· 1662 1658 printk (KERN_INFO "floppy%d: setting %s %p!\n", 1663 1659 drive, dtp->name, dtp); 1664 1660 UDT = dtp; 1665 - set_capacity(floppy->disk, UDT->blocks); 1661 + set_capacity(disk, UDT->blocks); 1666 1662 1667 1663 if (cmd == FDDEFPRM) { 1668 1664 /* save settings as permanent default type */ ··· 1706 1702 return -EINVAL; 1707 1703 1708 1704 UDT = dtp; 1709 - set_capacity(floppy->disk, UDT->blocks); 1705 + set_capacity(disk, UDT->blocks); 1710 1706 1711 1707 return 0; 1712 1708 case FDMSGON: ··· 1729 1725 UDT = NULL; 1730 1726 /* MSch: invalidate default_params */ 1731 1727 default_params[drive].blocks = 0; 1732 - set_capacity(floppy->disk, MAX_DISK_SIZE * 2); 1728 + set_capacity(disk, MAX_DISK_SIZE * 2); 1733 1729 fallthrough; 1734 1730 case FDFMTEND: 1735 1731 case FDFLUSH: ··· 1966 1962 .commit_rqs = ataflop_commit_rqs, 1967 1963 }; 1968 1964 1969 - static struct kobject *floppy_find(dev_t dev, int *part, void *data) 1965 + static int ataflop_alloc_disk(unsigned int drive, unsigned int type) 1970 1966 { 1971 - int drive = *part & 3; 1972 - int type = *part >> 2; 1967 + struct gendisk *disk; 1968 + int ret; 1969 + 1970 + disk = alloc_disk(1); 1971 + if (!disk) 1972 + return -ENOMEM; 1973 + 1974 + disk->queue = blk_mq_init_queue(&unit[drive].tag_set); 1975 + if (IS_ERR(disk->queue)) { 1976 + ret = PTR_ERR(disk->queue); 1977 + disk->queue = NULL; 1978 + put_disk(disk); 1979 + return ret; 1980 + } 1981 + 1982 + disk->major = FLOPPY_MAJOR; 1983 + disk->first_minor = drive + (type << 2); 1984 + sprintf(disk->disk_name, "fd%d", drive); 1985 + disk->fops = &floppy_fops; 1986 + disk->events = DISK_EVENT_MEDIA_CHANGE; 1987 + disk->private_data = &unit[drive]; 1988 + set_capacity(disk, MAX_DISK_SIZE * 2); 1989 + 1990 + unit[drive].disk[type] = disk; 1991 + return 0; 1992 + } 1993 + 1994 + static DEFINE_MUTEX(ataflop_probe_lock); 1995 + 1996 + static void ataflop_probe(dev_t dev) 1997 + { 1998 + int drive = MINOR(dev) & 3; 1999 + int type = MINOR(dev) >> 2; 2000 + 1973 2001 if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS) 1974 - return NULL; 1975 - *part = 0; 1976 - return get_disk_and_module(unit[drive].disk); 2002 + return; 2003 + mutex_lock(&ataflop_probe_lock); 2004 + if (!unit[drive].disk[type]) { 2005 + if (ataflop_alloc_disk(drive, type) == 0) 2006 + add_disk(unit[drive].disk[type]); 2007 + } 2008 + mutex_unlock(&ataflop_probe_lock); 1977 2009 } 1978 2010 1979 2011 static int __init atari_floppy_init (void) ··· 2021 1981 /* Amiga, Mac, ... don't have Atari-compatible floppy :-) */ 2022 1982 return -ENODEV; 2023 1983 2024 - if (register_blkdev(FLOPPY_MAJOR,"fd")) 2025 - return -EBUSY; 1984 + mutex_lock(&ataflop_probe_lock); 1985 + ret = __register_blkdev(FLOPPY_MAJOR, "fd", ataflop_probe); 1986 + if (ret) 1987 + goto out_unlock; 2026 1988 2027 1989 for (i = 0; i < FD_MAX_UNITS; i++) { 2028 - unit[i].disk = alloc_disk(1); 2029 - if (!unit[i].disk) { 2030 - ret = -ENOMEM; 1990 + memset(&unit[i].tag_set, 0, sizeof(unit[i].tag_set)); 1991 + unit[i].tag_set.ops = &ataflop_mq_ops; 1992 + unit[i].tag_set.nr_hw_queues = 1; 1993 + unit[i].tag_set.nr_maps = 1; 1994 + unit[i].tag_set.queue_depth = 2; 1995 + unit[i].tag_set.numa_node = NUMA_NO_NODE; 1996 + unit[i].tag_set.flags = BLK_MQ_F_SHOULD_MERGE; 1997 + ret = blk_mq_alloc_tag_set(&unit[i].tag_set); 1998 + if (ret) 2031 1999 goto err; 2032 - } 2033 2000 2034 - unit[i].disk->queue = blk_mq_init_sq_queue(&unit[i].tag_set, 2035 - &ataflop_mq_ops, 2, 2036 - BLK_MQ_F_SHOULD_MERGE); 2037 - if (IS_ERR(unit[i].disk->queue)) { 2038 - put_disk(unit[i].disk); 2039 - ret = PTR_ERR(unit[i].disk->queue); 2040 - unit[i].disk->queue = NULL; 2001 + ret = ataflop_alloc_disk(i, 0); 2002 + if (ret) { 2003 + blk_mq_free_tag_set(&unit[i].tag_set); 2041 2004 goto err; 2042 2005 } 2043 2006 } ··· 2070 2027 for (i = 0; i < FD_MAX_UNITS; i++) { 2071 2028 unit[i].track = -1; 2072 2029 unit[i].flags = 0; 2073 - unit[i].disk->major = FLOPPY_MAJOR; 2074 - unit[i].disk->first_minor = i; 2075 - sprintf(unit[i].disk->disk_name, "fd%d", i); 2076 - unit[i].disk->fops = &floppy_fops; 2077 - unit[i].disk->events = DISK_EVENT_MEDIA_CHANGE; 2078 - unit[i].disk->private_data = &unit[i]; 2079 - set_capacity(unit[i].disk, MAX_DISK_SIZE * 2); 2080 - add_disk(unit[i].disk); 2030 + add_disk(unit[i].disk[0]); 2081 2031 } 2082 - 2083 - blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE, 2084 - floppy_find, NULL, NULL); 2085 2032 2086 2033 printk(KERN_INFO "Atari floppy driver: max. %cD, %strack buffering\n", 2087 2034 DriveType == 0 ? 'D' : DriveType == 1 ? 'H' : 'E', ··· 2082 2049 2083 2050 err: 2084 2051 while (--i >= 0) { 2085 - struct gendisk *disk = unit[i].disk; 2086 - 2087 - blk_cleanup_queue(disk->queue); 2052 + blk_cleanup_queue(unit[i].disk[0]->queue); 2053 + put_disk(unit[i].disk[0]); 2088 2054 blk_mq_free_tag_set(&unit[i].tag_set); 2089 - put_disk(unit[i].disk); 2090 2055 } 2091 2056 2092 2057 unregister_blkdev(FLOPPY_MAJOR, "fd"); 2058 + out_unlock: 2059 + mutex_unlock(&ataflop_probe_lock); 2093 2060 return ret; 2094 2061 } 2095 2062 ··· 2134 2101 2135 2102 static void __exit atari_floppy_exit(void) 2136 2103 { 2137 - int i; 2138 - blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); 2104 + int i, type; 2105 + 2139 2106 for (i = 0; i < FD_MAX_UNITS; i++) { 2140 - del_gendisk(unit[i].disk); 2141 - blk_cleanup_queue(unit[i].disk->queue); 2107 + for (type = 0; type < NUM_DISK_MINORS; type++) { 2108 + if (!unit[i].disk[type]) 2109 + continue; 2110 + del_gendisk(unit[i].disk[type]); 2111 + blk_cleanup_queue(unit[i].disk[type]->queue); 2112 + put_disk(unit[i].disk[type]); 2113 + } 2142 2114 blk_mq_free_tag_set(&unit[i].tag_set); 2143 - put_disk(unit[i].disk); 2144 2115 } 2145 2116 unregister_blkdev(FLOPPY_MAJOR, "fd"); 2146 2117