Messages in this thread Patch in this message | | | Date | Wed, 14 Jun 2006 23:54:04 -0700 | From | Pete Zaitcev <> | Subject | Sparse minor space in ub |
| |
I wrote a patch which allows to expand the number of partitions in ub without breaking compatibility with the existing non-udev based distributions.
I do not know if I want this in the kernel or not. Looks pretty fishy, and its reason to exist is my lack of foresight. So far I heard from one user only who hit the limit, so obviously it's not something vitally important.
But I thought I'd just throw this out in case anyone wants something similar in the future for any reason.
Here how it looks in shell:
[zaitcev@lembas ~]$ cat /proc/partitions major minor #blocks name
3 0 39070080 hda 3 1 5935986 hda1 3 2 5936017 hda2 3 3 554242 hda3 3 4 1 hda4 3 5 26643771 hda5 180 0 253440 uba 180 1 253424 uba1 180 8 128000 ubb 180 9 752 ubb1 180 10 1 ubb2 180 13 752 ubb5 180 14 752 ubb6 180 15 752 ubb7 180 264 752 ubb8 180 265 1008 ubb9 [zaitcev@lembas ~]$ ls -l /dev/ub* brw-r----- 1 root disk 180, 0 Jun 14 23:18 /dev/uba brw-r----- 1 root disk 180, 1 Jun 14 23:18 /dev/uba1 brw-r----- 1 root disk 180, 8 Jun 14 23:18 /dev/ubb brw-r----- 1 root disk 180, 9 Jun 14 23:18 /dev/ubb1 brw-r----- 1 root disk 180, 10 Jun 14 23:18 /dev/ubb2 brw-r----- 1 root disk 180, 13 Jun 14 23:18 /dev/ubb5 brw-r----- 1 root disk 180, 14 Jun 14 23:18 /dev/ubb6 brw-r----- 1 root disk 180, 15 Jun 14 23:18 /dev/ubb7 brw-r----- 1 root disk 180, 264 Jun 14 23:18 /dev/ubb8 brw-r----- 1 root disk 180, 265 Jun 14 23:18 /dev/ubb9 [zaitcev@lembas ~]$
By the way, when I looked at the way things work in kobj_lookup(), a thought occured to me. If floppy ever returns NULL from its match function floppy_find(), the whole thing is going to loop endlessly. This happens because we restart the search, which, I suspect, was done to accomodate md. The md_probe() always returns NULL, and inserts new arrays into the list of regions. Thus, it needs a rescan. Someone needs to think about this mechanism, it seems a little underdeveloped. I have no idea if my patch below implements the lock/match API correctly, especially in regards to locking.
-- Pete
diff -urp -X dontdiff linux-2.6.17-rc5/block/genhd.c linux-2.6.17-rc5-lem/block/genhd.c --- linux-2.6.17-rc5/block/genhd.c 2006-05-25 14:03:19.000000000 -0700 +++ linux-2.6.17-rc5-lem/block/genhd.c 2006-06-14 22:57:28.000000000 -0700 @@ -183,7 +183,8 @@ static int exact_lock(dev_t dev, void *d void add_disk(struct gendisk *disk) { disk->flags |= GENHD_FL_UP; - blk_register_region(MKDEV(disk->major, disk->first_minor), + if (!(disk->flags & GENHD_FL_SPARSE_MINORS)) + blk_register_region(MKDEV(disk->major, disk->first_minor), disk->minors, NULL, exact_match, exact_lock, disk); register_disk(disk); blk_register_queue(disk); @@ -195,8 +196,9 @@ EXPORT_SYMBOL(del_gendisk); /* in partit void unlink_gendisk(struct gendisk *disk) { blk_unregister_queue(disk); - blk_unregister_region(MKDEV(disk->major, disk->first_minor), - disk->minors); + if (!(disk->flags & GENHD_FL_SPARSE_MINORS)) + blk_unregister_region(MKDEV(disk->major, disk->first_minor), + disk->minors); } #define to_disk(obj) container_of(obj,struct gendisk,kobj) @@ -268,7 +270,7 @@ static int show_partition(struct seq_fil if (sgp->part[n]->nr_sects == 0) continue; seq_printf(part, "%4d %4d %10llu %s\n", - sgp->major, n + 1 + sgp->first_minor, + sgp->major, sgp->part[n]->partmin, (unsigned long long)sgp->part[n]->nr_sects >> 1 , disk_name(sgp, n + 1, buf)); } @@ -466,8 +468,7 @@ static int block_uevent(struct kset *kse disk = container_of(kobj->parent, struct gendisk, kobj); part = container_of(kobj, struct hd_struct, kobj); add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "MINOR=%u", - disk->first_minor + part->partno); + &length, "MINOR=%u", part->partmin); } else return 0; @@ -586,7 +587,7 @@ static int diskstats_show(struct seq_fil if (hd && hd->nr_sects) seq_printf(s, "%4d %4d %s %u %u %u %u\n", - gp->major, n + gp->first_minor + 1, + gp->major, hd->partmin, disk_name(gp, n + 1, buf), hd->ios[0], hd->sectors[0], hd->ios[1], hd->sectors[1]); diff -urp -X dontdiff linux-2.6.17-rc5/Documentation/devices.txt linux-2.6.17-rc5-lem/Documentation/devices.txt --- linux-2.6.17-rc5/Documentation/devices.txt 2006-05-25 14:02:59.000000000 -0700 +++ linux-2.6.17-rc5-lem/Documentation/devices.txt 2006-05-25 15:45:34.000000000 -0700 @@ -2552,10 +2552,10 @@ Your cooperation is appreciated. 66 = /dev/usb/cpad0 Synaptics cPad (mouse/LCD) 180 block USB block devices - 0 = /dev/uba First USB block device - 8 = /dev/ubb Second USB block device - 16 = /dev/ubc Thrid USB block device - ... + 0 = /dev/uba First USB block device + 16 = /dev/ubb Second USB block device + 32 = /dev/ubc Third USB block device + ... 181 char Conrad Electronic parallel port radio clocks 0 = /dev/pcfclock0 First Conrad radio clock diff -urp -X dontdiff linux-2.6.17-rc5/drivers/block/ub.c linux-2.6.17-rc5-lem/drivers/block/ub.c --- linux-2.6.17-rc5/drivers/block/ub.c 2006-05-25 14:03:20.000000000 -0700 +++ linux-2.6.17-rc5-lem/drivers/block/ub.c 2006-06-14 23:16:10.000000000 -0700 @@ -111,9 +107,18 @@ #define UB_MAX_LUNS 9 /* - */ + * The minor layout is: + * 19 - 11 0xFF800 + * 10 - 8 0x700 Upper 3 bits of partition number + * 7 - 3 0xF8 Host index, or same as "id". UB_MAX_HOSTS fit here. + * 2 - 0 0x7 Lower 3 bits of partition number + */ +#define UB_PARTS_PER_LUN 64 +#define UB_PARTS_LOW 8 +#define UB_MINORS 2048 -#define UB_PARTS_PER_LUN 8 +/* + */ #define UB_MAX_CDB_SIZE 16 /* Corresponds to Bulk */ @@ -384,6 +389,7 @@ static int ub_submit_clear_stall(struct static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd); static void ub_reset_enter(struct ub_dev *sc, int try); static void ub_reset_task(void *arg); +static unsigned int ub_bd_map(struct gendisk *disk, int partno); static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun); static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun, struct ub_capacity *ret); @@ -407,14 +413,10 @@ MODULE_DEVICE_TABLE(usb, ub_usb_ids); #endif /* CONFIG_USB_LIBUSUAL */ /* - * Find me a way to identify "next free minor" for add_disk(), - * and the array disappears the next day. However, the number of - * hosts has something to do with the naming and /proc/partitions. - * This has to be thought out in detail before changing. - * If UB_MAX_HOST was 1000, we'd use a bitmap. Or a better data structure. + * If UB_MAX_HOST were 1000, we'd use a better data structure. */ #define UB_MAX_HOSTS 26 -static char ub_hostv[UB_MAX_HOSTS]; +static struct ub_lun *ub_hostv[UB_MAX_HOSTS]; #define UB_QLOCK_NUM 5 static spinlock_t ub_qlockv[UB_QLOCK_NUM]; @@ -434,8 +436,8 @@ static int ub_id_get(void) spin_lock_irqsave(&ub_lock, flags); for (i = 0; i < UB_MAX_HOSTS; i++) { - if (ub_hostv[i] == 0) { - ub_hostv[i] = 1; + if (ub_hostv[i] == NULL) { + ub_hostv[i] = (struct ub_lun *) 1; spin_unlock_irqrestore(&ub_lock, flags); return i; } @@ -444,6 +446,15 @@ static int ub_id_get(void) return -1; } +static void ub_id_commit(int id, struct ub_lun *lun) +{ + unsigned long flags; + + spin_lock_irqsave(&ub_lock, flags); + ub_hostv[id] = lun; + spin_unlock_irqrestore(&ub_lock, flags); +} + static void ub_id_put(int id) { unsigned long flags; @@ -454,12 +465,12 @@ static void ub_id_put(int id) } spin_lock_irqsave(&ub_lock, flags); - if (ub_hostv[id] == 0) { + if (ub_hostv[id] == NULL) { spin_unlock_irqrestore(&ub_lock, flags); printk(KERN_ERR DRV_NAME ": freeing free host ID %d\n", id); return; } - ub_hostv[id] = 0; + ub_hostv[id] = NULL; spin_unlock_irqrestore(&ub_lock, flags); } @@ -1781,9 +1786,80 @@ static struct block_device_operations ub .ioctl = ub_bd_ioctl, .media_changed = ub_bd_media_changed, .revalidate_disk = ub_bd_revalidate, + .partmap = ub_bd_map, }; /* + * Since we want to remap minor bits, we have to use this weird API. + * It consists of two entries: lock and probe. Lock is called first + * grabs the relevant gendisk. The probe (usually called "match") + * remaps minor bits into an index for the array of partitions. + * + * The weird part is, if the lock succeeded, the match must not + * return NULL, or else kobj_lookup will try to lock again and things + * quickly unravel. All those NULL-returning paths are fake. + */ + +static int ub_blk_lock(dev_t dev, void *data) +{ + unsigned int minor = MINOR(dev); + unsigned int host; + struct ub_lun *lun; + unsigned long flags; + + host = (minor >> 3) & 0x1f; + if (host >= UB_MAX_HOSTS) + return -1; + + spin_lock_irqsave(&ub_lock, flags); + lun = ub_hostv[host]; + if (lun == NULL || (unsigned long)lun == 1) { + spin_unlock_irqrestore(&ub_lock, flags); + return -1; + } + spin_unlock_irqrestore(&ub_lock, flags); + + if (atomic_read(&lun->udev->poison)) + return -1; + + if (!get_disk(lun->disk)) + return -1; + return 0; +} + +static struct kobject *ub_blk_match(dev_t dev, int *part, void *data) +{ + unsigned int minor = MINOR(dev); + unsigned int host; + struct ub_lun *lun; + unsigned long flags; + + host = (minor >> 3) & 0x1f; + if (host >= UB_MAX_HOSTS) + return NULL; /* This never happens, no need for a printk */ + + spin_lock_irqsave(&ub_lock, flags); + lun = ub_hostv[host]; + if (lun == NULL || (unsigned long)lun == 1) { + spin_unlock_irqrestore(&ub_lock, flags); + printk(KERN_ERR DRV_NAME ": NULL lun for %u:%u\n", + (unsigned int) MAJOR(dev), minor); + return NULL; + } + spin_unlock_irqrestore(&ub_lock, flags); + + *part = ((minor & 0x700) >> 5) | (minor & 0x7); + return &lun->disk->kobj; +} + +static unsigned int ub_bd_map(struct gendisk *disk, int partno) +{ + struct ub_lun *lun = disk->private_data; + + return ((partno & 0x38) << 5) | (lun->id << 3) | (partno & 0x7); +} + +/* * Common ->done routine for commands executed synchronously. */ static void ub_probe_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) @@ -2318,7 +2368,6 @@ static int ub_probe_lun(struct ub_dev *s goto err_id; lun->udev = sc; - list_add(&lun->link, &sc->luns); snprintf(lun->name, 16, DRV_NAME "%c(%d.%d.%d)", lun->id + 'a', sc->dev->bus->busnum, sc->dev->devnum, lun->num); @@ -2331,14 +2380,14 @@ static int ub_probe_lun(struct ub_dev *s if ((disk = alloc_disk(UB_PARTS_PER_LUN)) == NULL) goto err_diskalloc; - lun->disk = disk; sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a'); sprintf(disk->devfs_name, DEVFS_NAME "/%c", lun->id + 'a'); disk->major = UB_MAJOR; - disk->first_minor = lun->id * UB_PARTS_PER_LUN; + disk->first_minor = lun->id * UB_PARTS_LOW; disk->fops = &ub_bd_fops; disk->private_data = lun; disk->driverfs_dev = &sc->intf->dev; + disk->flags |= GENHD_FL_SPARSE_MINORS; rc = -ENOMEM; if ((q = blk_init_queue(ub_request_fn, sc->lock)) == NULL) @@ -2353,12 +2402,15 @@ static int ub_probe_lun(struct ub_dev *s blk_queue_max_sectors(q, UB_MAX_SECTORS); blk_queue_hardsect_size(q, lun->capacity.bsize); + lun->disk = disk; q->queuedata = lun; + list_add(&lun->link, &sc->luns); set_capacity(disk, lun->capacity.nsec); if (lun->removable) disk->flags |= GENHD_FL_REMOVABLE; + ub_id_commit(lun->id, lun); add_disk(disk); return 0; @@ -2366,7 +2418,6 @@ static int ub_probe_lun(struct ub_dev *s err_blkqinit: put_disk(disk); err_diskalloc: - list_del(&lun->link); ub_id_put(lun->id); err_id: kfree(lun); @@ -2487,6 +2535,8 @@ static int __init ub_init(void) for (i = 0; i < UB_QLOCK_NUM; i++) spin_lock_init(&ub_qlockv[i]); + blk_register_region(MKDEV(UB_MAJOR, 0), UB_MINORS, THIS_MODULE, + ub_blk_match, ub_blk_lock, NULL); if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0) goto err_regblkdev; devfs_mk_dir(DEVFS_NAME); @@ -2501,6 +2551,7 @@ err_register: devfs_remove(DEVFS_NAME); unregister_blkdev(UB_MAJOR, DRV_NAME); err_regblkdev: + blk_unregister_region(MKDEV(UB_MAJOR, 0), UB_MINORS); return rc; } @@ -2511,6 +2562,7 @@ static void __exit ub_exit(void) devfs_remove(DEVFS_NAME); unregister_blkdev(UB_MAJOR, DRV_NAME); usb_usual_clear_present(USB_US_TYPE_UB); + blk_unregister_region(MKDEV(UB_MAJOR, 0), UB_MINORS); } module_init(ub_init); diff -urp -X dontdiff linux-2.6.17-rc5/fs/partitions/check.c linux-2.6.17-rc5-lem/fs/partitions/check.c --- linux-2.6.17-rc5/fs/partitions/check.c 2006-05-25 14:04:00.000000000 -0700 +++ linux-2.6.17-rc5-lem/fs/partitions/check.c 2006-06-14 22:50:23.000000000 -0700 @@ -236,7 +236,7 @@ static ssize_t part_uevent_store(struct static ssize_t part_dev_read(struct hd_struct * p, char *page) { struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj); - dev_t dev = MKDEV(disk->major, disk->first_minor + p->partno); + dev_t dev = MKDEV(disk->major, p->partmin); return print_dev_t(page, dev); } static ssize_t part_start_read(struct hd_struct * p, char *page) @@ -347,7 +347,10 @@ void add_partition(struct gendisk *disk, memset(p, 0, sizeof(*p)); p->start_sect = start; p->nr_sects = len; - p->partno = part; + if (disk->fops->partmap) + p->partmin = disk->fops->partmap(disk, part); + else + p->partmin = disk->first_minor + part; devfs_mk_bdev(MKDEV(disk->major, disk->first_minor + part), S_IFBLK|S_IRUSR|S_IWUSR, diff -urp -X dontdiff linux-2.6.17-rc5/include/linux/fs.h linux-2.6.17-rc5-lem/include/linux/fs.h --- linux-2.6.17-rc5/include/linux/fs.h 2006-05-25 14:04:10.000000000 -0700 +++ linux-2.6.17-rc5-lem/include/linux/fs.h 2006-06-14 22:47:23.000000000 -0700 @@ -977,6 +977,7 @@ struct block_device_operations { int (*media_changed) (struct gendisk *); int (*revalidate_disk) (struct gendisk *); int (*getgeo)(struct block_device *, struct hd_geometry *); + unsigned (*partmap)(struct gendisk *, int partno); struct module *owner; }; diff -urp -X dontdiff linux-2.6.17-rc5/include/linux/genhd.h linux-2.6.17-rc5-lem/include/linux/genhd.h --- linux-2.6.17-rc5/include/linux/genhd.h 2006-05-25 14:04:10.000000000 -0700 +++ linux-2.6.17-rc5-lem/include/linux/genhd.h 2006-06-14 22:22:37.000000000 -0700 @@ -80,7 +80,8 @@ struct hd_struct { struct kobject kobj; struct kobject *holder_dir; unsigned ios[2], sectors[2]; /* READs and WRITEs */ - int policy, partno; + int policy; + unsigned int partmin; }; #define GENHD_FL_REMOVABLE 1 @@ -88,6 +89,7 @@ struct hd_struct { #define GENHD_FL_CD 8 #define GENHD_FL_UP 16 #define GENHD_FL_SUPPRESS_PARTITION_INFO 32 +#define GENHD_FL_SPARSE_MINORS 64 struct disk_stats { unsigned long sectors[2]; /* READs and WRITEs */ - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |