Commit 7bc4777d authored by Andrew Morton's avatar Andrew Morton Committed by Jeff Garzik

[PATCH] remove MAX_BLKDEV from genhd.c

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".
parent 51040fa7
/* /*
* Code extracted from * gendisk handling
* 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
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -29,8 +17,9 @@ ...@@ -29,8 +17,9 @@
static struct subsystem block_subsys; static struct subsystem block_subsys;
#define MAX_PROBE_HASH 23 /* random */
struct blk_probe { static struct blk_probe {
struct blk_probe *next; struct blk_probe *next;
dev_t dev; dev_t dev;
unsigned long range; unsigned long range;
...@@ -38,21 +27,27 @@ struct blk_probe { ...@@ -38,21 +27,27 @@ struct blk_probe {
struct gendisk *(*get)(dev_t dev, int *part, void *data); struct gendisk *(*get)(dev_t dev, int *part, void *data);
int (*lock)(dev_t, void *); int (*lock)(dev_t, void *);
void *data; 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) 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, void blk_register_region(dev_t dev, unsigned long range, struct module *module,
struct gendisk *(*probe)(dev_t, int *, void *), struct gendisk *(*probe)(dev_t, int *, void *),
int (*lock)(dev_t, void *), void *data) int (*lock)(dev_t, void *), void *data)
{ {
int index = dev_to_index(dev); int index = dev_to_index(dev);
struct blk_probe *p = kmalloc(sizeof(struct blk_probe), GFP_KERNEL); struct blk_probe *p = kmalloc(sizeof(struct blk_probe), GFP_KERNEL);
struct blk_probe **s; struct blk_probe **s;
p->owner = module; p->owner = module;
p->get = probe; p->get = probe;
p->lock = lock; p->lock = lock;
...@@ -71,6 +66,7 @@ void blk_unregister_region(dev_t dev, unsigned long range) ...@@ -71,6 +66,7 @@ void blk_unregister_region(dev_t dev, unsigned long range)
{ {
int index = dev_to_index(dev); int index = dev_to_index(dev);
struct blk_probe **s; struct blk_probe **s;
down_write(&block_subsys.rwsem); down_write(&block_subsys.rwsem);
for (s = &probes[index]; *s; s = &(*s)->next) { for (s = &probes[index]; *s; s = &(*s)->next) {
struct blk_probe *p = *s; struct blk_probe *p = *s;
...@@ -94,6 +90,7 @@ static struct gendisk *exact_match(dev_t dev, int *part, void *data) ...@@ -94,6 +90,7 @@ static struct gendisk *exact_match(dev_t dev, int *part, void *data)
static int exact_lock(dev_t dev, void *data) static int exact_lock(dev_t dev, void *data)
{ {
struct gendisk *p = data; struct gendisk *p = data;
if (!get_disk(p)) if (!get_disk(p))
return -1; return -1;
return 0; return 0;
...@@ -109,14 +106,14 @@ static int exact_lock(dev_t dev, void *data) ...@@ -109,14 +106,14 @@ static int exact_lock(dev_t dev, void *data)
void add_disk(struct gendisk *disk) void add_disk(struct gendisk *disk)
{ {
disk->flags |= GENHD_FL_UP; disk->flags |= GENHD_FL_UP;
blk_register_region(MKDEV(disk->major, disk->first_minor), disk->minors, blk_register_region(MKDEV(disk->major, disk->first_minor),
NULL, exact_match, exact_lock, disk); disk->minors, NULL, exact_match, exact_lock, disk);
register_disk(disk); register_disk(disk);
elv_register_queue(disk); elv_register_queue(disk);
} }
EXPORT_SYMBOL(add_disk); EXPORT_SYMBOL(add_disk);
EXPORT_SYMBOL(del_gendisk); EXPORT_SYMBOL(del_gendisk); /* in partitions/check.c */
void unlink_gendisk(struct gendisk *disk) void unlink_gendisk(struct gendisk *disk)
{ {
...@@ -146,18 +143,17 @@ get_gendisk(dev_t dev, int *part) ...@@ -146,18 +143,17 @@ get_gendisk(dev_t dev, int *part)
struct gendisk *(*probe)(dev_t, int *, void *); struct gendisk *(*probe)(dev_t, int *, void *);
struct module *owner; struct module *owner;
void *data; void *data;
if (p->dev > dev || p->dev + p->range <= dev)
if (p->dev > dev || p->dev + p->range - 1 < dev)
continue; continue;
if (p->range >= best) { if (p->range - 1 >= best)
up_read(&block_subsys.rwsem); break;
return NULL;
}
if (!try_module_get(p->owner)) if (!try_module_get(p->owner))
continue; continue;
owner = p->owner; owner = p->owner;
data = p->data; data = p->data;
probe = p->get; probe = p->get;
best = p->range; best = p->range - 1;
*part = dev - p->dev; *part = dev - p->dev;
if (p->lock && p->lock(dev, data) < 0) { if (p->lock && p->lock(dev, data) < 0) {
module_put(owner); module_put(owner);
...@@ -169,7 +165,7 @@ get_gendisk(dev_t dev, int *part) ...@@ -169,7 +165,7 @@ get_gendisk(dev_t dev, int *part)
module_put(owner); module_put(owner);
if (disk) if (disk)
return disk; return disk;
goto retry; goto retry; /* this terminates: best decreases */
} }
up_read(&block_subsys.rwsem); up_read(&block_subsys.rwsem);
return NULL; return NULL;
...@@ -245,7 +241,7 @@ extern int blk_dev_init(void); ...@@ -245,7 +241,7 @@ extern int blk_dev_init(void);
static struct gendisk *base_probe(dev_t dev, int *part, void *data) 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)); sprintf(name, "block-major-%d", MAJOR(dev));
request_module(name); request_module(name);
return NULL; return NULL;
...@@ -256,11 +252,11 @@ int __init device_init(void) ...@@ -256,11 +252,11 @@ int __init device_init(void)
struct blk_probe *base = kmalloc(sizeof(struct blk_probe), GFP_KERNEL); struct blk_probe *base = kmalloc(sizeof(struct blk_probe), GFP_KERNEL);
int i; int i;
memset(base, 0, sizeof(struct blk_probe)); memset(base, 0, sizeof(struct blk_probe));
base->dev = MKDEV(1,0); base->dev = 1;
base->range = MKDEV(MAX_BLKDEV-1, 255) - base->dev + 1; base->range = ~0; /* range 1 .. ~0 */
base->get = base_probe; base->get = base_probe;
for (i = 1; i < MAX_BLKDEV; i++) for (i = 0; i < MAX_PROBE_HASH; i++)
probes[i] = base; probes[i] = base; /* must remain last in chain */
blk_dev_init(); blk_dev_init();
subsystem_register(&block_subsys); subsystem_register(&block_subsys);
return 0; return 0;
...@@ -281,12 +277,14 @@ struct disk_attribute { ...@@ -281,12 +277,14 @@ struct disk_attribute {
ssize_t (*show)(struct gendisk *, char *); ssize_t (*show)(struct gendisk *, char *);
}; };
static ssize_t disk_attr_show(struct kobject * kobj, struct attribute * attr, static ssize_t disk_attr_show(struct kobject *kobj, struct attribute *attr,
char * page) char *page)
{ {
struct gendisk * disk = to_disk(kobj); struct gendisk *disk = to_disk(kobj);
struct disk_attribute * disk_attr = container_of(attr,struct disk_attribute,attr); struct disk_attribute *disk_attr =
container_of(attr,struct disk_attribute,attr);
ssize_t ret = 0; ssize_t ret = 0;
if (disk_attr->show) if (disk_attr->show)
ret = disk_attr->show(disk,page); ret = disk_attr->show(disk,page);
return ret; return ret;
...@@ -303,11 +301,11 @@ static ssize_t disk_dev_read(struct gendisk * disk, char *page) ...@@ -303,11 +301,11 @@ static ssize_t disk_dev_read(struct gendisk * disk, char *page)
} }
static ssize_t disk_range_read(struct gendisk * disk, char *page) 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) 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) static inline unsigned jiffies_to_msec(unsigned jif)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment