Patch from Andries.Brouwer@cwi.nl A patch for genhd.c: - removed outdated comments - removed MAX_BLKDEV In genhd.c the variable MAX_BLKDEV was only the size of a hash table, so I made it MAX_PROBE_HASH. It can be 1, or 23, or 256, or whatever one wants. Note that the current setup requires that every device number in a given range is mapped by dev_to_index() to the same index in the hash table, so this routine will have to be adapted in case one wants to register multimajor ranges. Discussion is possible about whether struct blk_probe needs a dev_t or a kdev_t, but I left things this time. If a range can end at precisely the end of [k]dev_t space, the old code was wrong since (p->dev + p->range) would be 0. That is why "p->dev + p->range <= dev" was replaced by "p->dev + p->range - 1 < dev". block/genhd.c | 78 ++++++++++++++++++++++++++++------------------------------ 1 files changed, 38 insertions(+), 40 deletions(-) diff -puN drivers/block/genhd.c~remove-MAX_BLKDEV-from-genhd drivers/block/genhd.c --- 25/drivers/block/genhd.c~remove-MAX_BLKDEV-from-genhd 2003-02-23 16:20:09.000000000 -0800 +++ 25-akpm/drivers/block/genhd.c 2003-02-23 16:20:10.000000000 -0800 @@ -1,17 +1,5 @@ /* - * Code extracted from - * linux/kernel/hd.c - * - * Copyright (C) 1991-1998 Linus Torvalds - * - * devfs support - jj, rgooch, 980122 - * - * Moved partition checking code to fs/partitions* - Russell King - * (linux@arm.uk.linux.org) - */ - -/* - * TODO: rip out the remaining init crap from this file --hch + * gendisk handling */ #include @@ -29,8 +17,9 @@ static struct subsystem block_subsys; +#define MAX_PROBE_HASH 23 /* random */ -struct blk_probe { +static struct blk_probe { struct blk_probe *next; dev_t dev; unsigned long range; @@ -38,21 +27,27 @@ struct blk_probe { struct gendisk *(*get)(dev_t dev, int *part, void *data); int (*lock)(dev_t, void *); void *data; -} *probes[MAX_BLKDEV]; +} *probes[MAX_PROBE_HASH]; -/* index in the above */ +/* index in the above - for now: assume no multimajor ranges */ static inline int dev_to_index(dev_t dev) { - return MAJOR(dev); + return MAJOR(dev) % MAX_PROBE_HASH; } +/* + * Register device numbers dev..(dev+range-1) + * range must be nonzero + * The hash chain is sorted on range, so that subranges can override. + */ void blk_register_region(dev_t dev, unsigned long range, struct module *module, - struct gendisk *(*probe)(dev_t, int *, void *), - int (*lock)(dev_t, void *), void *data) + struct gendisk *(*probe)(dev_t, int *, void *), + int (*lock)(dev_t, void *), void *data) { int index = dev_to_index(dev); struct blk_probe *p = kmalloc(sizeof(struct blk_probe), GFP_KERNEL); struct blk_probe **s; + p->owner = module; p->get = probe; p->lock = lock; @@ -71,6 +66,7 @@ void blk_unregister_region(dev_t dev, un { int index = dev_to_index(dev); struct blk_probe **s; + down_write(&block_subsys.rwsem); for (s = &probes[index]; *s; s = &(*s)->next) { struct blk_probe *p = *s; @@ -94,6 +90,7 @@ static struct gendisk *exact_match(dev_t static int exact_lock(dev_t dev, void *data) { struct gendisk *p = data; + if (!get_disk(p)) return -1; return 0; @@ -109,14 +106,14 @@ 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), disk->minors, - NULL, exact_match, exact_lock, disk); + blk_register_region(MKDEV(disk->major, disk->first_minor), + disk->minors, NULL, exact_match, exact_lock, disk); register_disk(disk); elv_register_queue(disk); } EXPORT_SYMBOL(add_disk); -EXPORT_SYMBOL(del_gendisk); +EXPORT_SYMBOL(del_gendisk); /* in partitions/check.c */ void unlink_gendisk(struct gendisk *disk) { @@ -146,18 +143,17 @@ retry: struct gendisk *(*probe)(dev_t, int *, void *); struct module *owner; void *data; - if (p->dev > dev || p->dev + p->range <= dev) + + if (p->dev > dev || p->dev + p->range - 1 < dev) continue; - if (p->range >= best) { - up_read(&block_subsys.rwsem); - return NULL; - } + if (p->range - 1 >= best) + break; if (!try_module_get(p->owner)) continue; owner = p->owner; data = p->data; probe = p->get; - best = p->range; + best = p->range - 1; *part = dev - p->dev; if (p->lock && p->lock(dev, data) < 0) { module_put(owner); @@ -169,7 +165,7 @@ retry: module_put(owner); if (disk) return disk; - goto retry; + goto retry; /* this terminates: best decreases */ } up_read(&block_subsys.rwsem); return NULL; @@ -245,7 +241,7 @@ extern int blk_dev_init(void); static struct gendisk *base_probe(dev_t dev, int *part, void *data) { - char name[20]; + char name[30]; sprintf(name, "block-major-%d", MAJOR(dev)); request_module(name); return NULL; @@ -256,11 +252,11 @@ int __init device_init(void) struct blk_probe *base = kmalloc(sizeof(struct blk_probe), GFP_KERNEL); int i; memset(base, 0, sizeof(struct blk_probe)); - base->dev = MKDEV(1,0); - base->range = MKDEV(MAX_BLKDEV-1, 255) - base->dev + 1; + base->dev = 1; + base->range = ~0; /* range 1 .. ~0 */ base->get = base_probe; - for (i = 1; i < MAX_BLKDEV; i++) - probes[i] = base; + for (i = 0; i < MAX_PROBE_HASH; i++) + probes[i] = base; /* must remain last in chain */ blk_dev_init(); subsystem_register(&block_subsys); return 0; @@ -281,12 +277,14 @@ struct disk_attribute { ssize_t (*show)(struct gendisk *, char *); }; -static ssize_t disk_attr_show(struct kobject * kobj, struct attribute * attr, - char * page) +static ssize_t disk_attr_show(struct kobject *kobj, struct attribute *attr, + char *page) { - struct gendisk * disk = to_disk(kobj); - struct disk_attribute * disk_attr = container_of(attr,struct disk_attribute,attr); + struct gendisk *disk = to_disk(kobj); + struct disk_attribute *disk_attr = + container_of(attr,struct disk_attribute,attr); ssize_t ret = 0; + if (disk_attr->show) ret = disk_attr->show(disk,page); return ret; @@ -303,11 +301,11 @@ static ssize_t disk_dev_read(struct gend } static ssize_t disk_range_read(struct gendisk * disk, char *page) { - return sprintf(page, "%d\n",disk->minors); + return sprintf(page, "%d\n", disk->minors); } static ssize_t disk_size_read(struct gendisk * disk, char *page) { - return sprintf(page, "%llu\n",(unsigned long long)get_capacity(disk)); + return sprintf(page, "%llu\n", (unsigned long long)get_capacity(disk)); } static inline unsigned jiffies_to_msec(unsigned jif) _