diff options
author | Tejun Heo <tj@kernel.org> | 2008-08-25 06:56:17 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2008-10-09 02:56:08 -0400 |
commit | 3e1a7ff8a0a7b948f2684930166954f9e8e776fe (patch) | |
tree | 0a8642f5cdbc6ddfdd66dc7241c915e57b3cb7ff | |
parent | 689d6fac40b41c7bf154f362deaf442548e4dc81 (diff) |
block: allow disk to have extended device number
Now that disk and partition handlings are mostly unified, it's easy to
allow disk to have extended device number. This patch makes
add_disk() use extended device number if disk->minors is zero. Both
sd and ide-disk are updated to use this.
* sd_format_disk_name() is implemented which can generically determine
the drive name. This removes disk number restriction stemming from
limited device names.
* If sd index goes over SD_MAX_DISKS (which can be increased now BTW),
sd simply doesn't initialize minors letting block layer choose
extended device number.
* If CONFIG_DEBUG_EXT_DEVT is set, both sd and ide-disk always set
minors to 0 and use extended device numbers.
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r-- | block/genhd.c | 25 | ||||
-rw-r--r-- | drivers/ide/ide-disk.c | 2 | ||||
-rw-r--r-- | drivers/scsi/sd.c | 74 | ||||
-rw-r--r-- | fs/partitions/check.c | 1 | ||||
-rw-r--r-- | include/linux/genhd.h | 3 |
5 files changed, 82 insertions, 23 deletions
diff --git a/block/genhd.c b/block/genhd.c index eedab5b4685b..d9de3e482d1e 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
@@ -478,14 +478,37 @@ static int exact_lock(dev_t devt, void *data) | |||
478 | * | 478 | * |
479 | * This function registers the partitioning information in @disk | 479 | * This function registers the partitioning information in @disk |
480 | * with the kernel. | 480 | * with the kernel. |
481 | * | ||
482 | * FIXME: error handling | ||
481 | */ | 483 | */ |
482 | void add_disk(struct gendisk *disk) | 484 | void add_disk(struct gendisk *disk) |
483 | { | 485 | { |
484 | struct backing_dev_info *bdi; | 486 | struct backing_dev_info *bdi; |
487 | dev_t devt; | ||
485 | int retval; | 488 | int retval; |
486 | 489 | ||
490 | /* minors == 0 indicates to use ext devt from part0 and should | ||
491 | * be accompanied with EXT_DEVT flag. Make sure all | ||
492 | * parameters make sense. | ||
493 | */ | ||
494 | WARN_ON(disk->minors && !(disk->major || disk->first_minor)); | ||
495 | WARN_ON(!disk->minors && !(disk->flags & GENHD_FL_EXT_DEVT)); | ||
496 | |||
487 | disk->flags |= GENHD_FL_UP; | 497 | disk->flags |= GENHD_FL_UP; |
488 | disk_to_dev(disk)->devt = MKDEV(disk->major, disk->first_minor); | 498 | |
499 | retval = blk_alloc_devt(&disk->part0, &devt); | ||
500 | if (retval) { | ||
501 | WARN_ON(1); | ||
502 | return; | ||
503 | } | ||
504 | disk_to_dev(disk)->devt = devt; | ||
505 | |||
506 | /* ->major and ->first_minor aren't supposed to be | ||
507 | * dereferenced from here on, but set them just in case. | ||
508 | */ | ||
509 | disk->major = MAJOR(devt); | ||
510 | disk->first_minor = MINOR(devt); | ||
511 | |||
489 | blk_register_region(disk_devt(disk), disk->minors, NULL, | 512 | blk_register_region(disk_devt(disk), disk->minors, NULL, |
490 | exact_match, exact_lock, disk); | 513 | exact_match, exact_lock, disk); |
491 | register_disk(disk); | 514 | register_disk(disk); |
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 29c8ae752683..33ea8c048717 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c | |||
@@ -44,7 +44,7 @@ | |||
44 | #if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT) | 44 | #if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT) |
45 | #define IDE_DISK_MINORS (1 << PARTN_BITS) | 45 | #define IDE_DISK_MINORS (1 << PARTN_BITS) |
46 | #else | 46 | #else |
47 | #define IDE_DISK_MINORS 1 | 47 | #define IDE_DISK_MINORS 0 |
48 | #endif | 48 | #endif |
49 | 49 | ||
50 | struct ide_disk_obj { | 50 | struct ide_disk_obj { |
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 6598024531dd..bcb04b2a7676 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
@@ -89,7 +89,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC); | |||
89 | #if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT) | 89 | #if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT) |
90 | #define SD_MINORS 16 | 90 | #define SD_MINORS 16 |
91 | #else | 91 | #else |
92 | #define SD_MINORS 1 | 92 | #define SD_MINORS 0 |
93 | #endif | 93 | #endif |
94 | 94 | ||
95 | static int sd_revalidate_disk(struct gendisk *); | 95 | static int sd_revalidate_disk(struct gendisk *); |
@@ -1770,6 +1770,52 @@ static int sd_revalidate_disk(struct gendisk *disk) | |||
1770 | } | 1770 | } |
1771 | 1771 | ||
1772 | /** | 1772 | /** |
1773 | * sd_format_disk_name - format disk name | ||
1774 | * @prefix: name prefix - ie. "sd" for SCSI disks | ||
1775 | * @index: index of the disk to format name for | ||
1776 | * @buf: output buffer | ||
1777 | * @buflen: length of the output buffer | ||
1778 | * | ||
1779 | * SCSI disk names starts at sda. The 26th device is sdz and the | ||
1780 | * 27th is sdaa. The last one for two lettered suffix is sdzz | ||
1781 | * which is followed by sdaaa. | ||
1782 | * | ||
1783 | * This is basically 26 base counting with one extra 'nil' entry | ||
1784 | * at the beggining from the second digit on and can be | ||
1785 | * determined using similar method as 26 base conversion with the | ||
1786 | * index shifted -1 after each digit is computed. | ||
1787 | * | ||
1788 | * CONTEXT: | ||
1789 | * Don't care. | ||
1790 | * | ||
1791 | * RETURNS: | ||
1792 | * 0 on success, -errno on failure. | ||
1793 | */ | ||
1794 | static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen) | ||
1795 | { | ||
1796 | const int base = 'z' - 'a' + 1; | ||
1797 | char *begin = buf + strlen(prefix); | ||
1798 | char *end = buf + buflen; | ||
1799 | char *p; | ||
1800 | int unit; | ||
1801 | |||
1802 | p = end - 1; | ||
1803 | *p = '\0'; | ||
1804 | unit = base; | ||
1805 | do { | ||
1806 | if (p == begin) | ||
1807 | return -EINVAL; | ||
1808 | *--p = 'a' + (index % unit); | ||
1809 | index = (index / unit) - 1; | ||
1810 | } while (index >= 0); | ||
1811 | |||
1812 | memmove(begin, p, end - p); | ||
1813 | memcpy(buf, prefix, strlen(prefix)); | ||
1814 | |||
1815 | return 0; | ||
1816 | } | ||
1817 | |||
1818 | /** | ||
1773 | * sd_probe - called during driver initialization and whenever a | 1819 | * sd_probe - called during driver initialization and whenever a |
1774 | * new scsi device is attached to the system. It is called once | 1820 | * new scsi device is attached to the system. It is called once |
1775 | * for each scsi device (not just disks) present. | 1821 | * for each scsi device (not just disks) present. |
@@ -1821,8 +1867,8 @@ static int sd_probe(struct device *dev) | |||
1821 | if (error) | 1867 | if (error) |
1822 | goto out_put; | 1868 | goto out_put; |
1823 | 1869 | ||
1824 | error = -EBUSY; | 1870 | error = sd_format_disk_name("sd", index, gd->disk_name, DISK_NAME_LEN); |
1825 | if (index >= SD_MAX_DISKS) | 1871 | if (error) |
1826 | goto out_free_index; | 1872 | goto out_free_index; |
1827 | 1873 | ||
1828 | sdkp->device = sdp; | 1874 | sdkp->device = sdp; |
@@ -1849,24 +1895,12 @@ static int sd_probe(struct device *dev) | |||
1849 | 1895 | ||
1850 | get_device(&sdp->sdev_gendev); | 1896 | get_device(&sdp->sdev_gendev); |
1851 | 1897 | ||
1852 | gd->major = sd_major((index & 0xf0) >> 4); | 1898 | if (index < SD_MAX_DISKS) { |
1853 | gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); | 1899 | gd->major = sd_major((index & 0xf0) >> 4); |
1854 | gd->minors = SD_MINORS; | 1900 | gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); |
1855 | gd->fops = &sd_fops; | 1901 | gd->minors = SD_MINORS; |
1856 | |||
1857 | if (index < 26) { | ||
1858 | sprintf(gd->disk_name, "sd%c", 'a' + index % 26); | ||
1859 | } else if (index < (26 + 1) * 26) { | ||
1860 | sprintf(gd->disk_name, "sd%c%c", | ||
1861 | 'a' + index / 26 - 1,'a' + index % 26); | ||
1862 | } else { | ||
1863 | const unsigned int m1 = (index / 26 - 1) / 26 - 1; | ||
1864 | const unsigned int m2 = (index / 26 - 1) % 26; | ||
1865 | const unsigned int m3 = index % 26; | ||
1866 | sprintf(gd->disk_name, "sd%c%c%c", | ||
1867 | 'a' + m1, 'a' + m2, 'a' + m3); | ||
1868 | } | 1902 | } |
1869 | 1903 | gd->fops = &sd_fops; | |
1870 | gd->private_data = &sdkp->driver; | 1904 | gd->private_data = &sdkp->driver; |
1871 | gd->queue = sdkp->device->request_queue; | 1905 | gd->queue = sdkp->device->request_queue; |
1872 | 1906 | ||
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 772b2ed8d239..0e411603fdf5 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
@@ -593,6 +593,7 @@ void del_gendisk(struct gendisk *disk) | |||
593 | disk_part_iter_exit(&piter); | 593 | disk_part_iter_exit(&piter); |
594 | 594 | ||
595 | invalidate_partition(disk, 0); | 595 | invalidate_partition(disk, 0); |
596 | blk_free_devt(disk_to_dev(disk)->devt); | ||
596 | set_capacity(disk, 0); | 597 | set_capacity(disk, 0); |
597 | disk->flags &= ~GENHD_FL_UP; | 598 | disk->flags &= ~GENHD_FL_UP; |
598 | unlink_gendisk(disk); | 599 | unlink_gendisk(disk); |
diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 04524c213de1..206cdf96c3a7 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h | |||
@@ -59,6 +59,7 @@ enum { | |||
59 | }; | 59 | }; |
60 | 60 | ||
61 | #define DISK_MAX_PARTS 256 | 61 | #define DISK_MAX_PARTS 256 |
62 | #define DISK_NAME_LEN 32 | ||
62 | 63 | ||
63 | #include <linux/major.h> | 64 | #include <linux/major.h> |
64 | #include <linux/device.h> | 65 | #include <linux/device.h> |
@@ -140,7 +141,7 @@ struct gendisk { | |||
140 | int minors; /* maximum number of minors, =1 for | 141 | int minors; /* maximum number of minors, =1 for |
141 | * disks that can't be partitioned. */ | 142 | * disks that can't be partitioned. */ |
142 | 143 | ||
143 | char disk_name[32]; /* name of major driver */ | 144 | char disk_name[DISK_NAME_LEN]; /* name of major driver */ |
144 | 145 | ||
145 | /* Array of pointers to partitions indexed by partno. | 146 | /* Array of pointers to partitions indexed by partno. |
146 | * Protected with matching bdev lock but stat and other | 147 | * Protected with matching bdev lock but stat and other |