diff -urN C69-tty/drivers/base/Makefile C69-kobj_map/drivers/base/Makefile --- C69-tty/drivers/base/Makefile Mon May 5 03:27:59 2003 +++ C69-kobj_map/drivers/base/Makefile Mon May 5 10:26:51 2003 @@ -2,5 +2,5 @@ obj-y := core.o sys.o interface.o power.o bus.o \ driver.o class.o platform.o \ - cpu.o firmware.o init.o + cpu.o firmware.o init.o map.o obj-$(CONFIG_NUMA) += node.o memblk.o diff -urN C69-tty/drivers/base/map.c C69-kobj_map/drivers/base/map.c --- C69-tty/drivers/base/map.c Wed Dec 31 19:00:00 1969 +++ C69-kobj_map/drivers/base/map.c Mon May 5 10:26:51 2003 @@ -0,0 +1,154 @@ +/* + * linux/drivers/base/map.c + * + * (C) Copyright Al Viro 2002,2003 + * Released under GPL v2. + * + * NOTE: data structure needs to be changed. It works, but for large dev_t + * it will be too slow. It is isolated, though, so these changes will be + * local to that file. + */ + +#include +#include +#include +#include +#include + +struct kobj_map { + struct probe { + struct probe *next; + dev_t dev; + unsigned long range; + struct module *owner; + kobj_probe_t *get; + int (*lock)(dev_t, void *); + void *data; + } *probes[255]; + struct rw_semaphore *sem; +}; + +static inline int dev_to_index(dev_t dev) +{ + return MAJOR(dev) % 255; +} + +int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range, + struct module *module, kobj_probe_t *probe, + int (*lock)(dev_t, void *), void *data) +{ + unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1; + unsigned index = MAJOR(dev); + unsigned i; + struct probe *p; + + if (n > 255) + n = 255; + + p = kmalloc(sizeof(struct probe) * n, GFP_KERNEL); + + if (p == NULL) + return -ENOMEM; + + for (i = 0; i < n; i++, p++) { + p->owner = module; + p->get = probe; + p->lock = lock; + p->dev = dev; + p->range = range; + p->data = data; + } + down_write(domain->sem); + for (i = 0, p -= n; i < n; i++, p++, index++) { + struct probe **s = &domain->probes[index % 255]; + while (*s && (*s)->range < range) + s = &(*s)->next; + p->next = *s; + *s = p; + } + up_write(domain->sem); + return 0; +} + +void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range) +{ + unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1; + unsigned index = MAJOR(dev); + unsigned i; + struct probe *found = NULL; + + if (n > 255) + n = 255; + + down_write(domain->sem); + for (i = 0; i < n; i++, index++) { + struct probe **s; + for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) { + struct probe *p = *s; + if (p->dev == dev && p->range == range) { + *s = p->next; + if (!found) + found = p; + break; + } + } + } + up_write(domain->sem); + kfree(found); +} + +struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index) +{ + struct kobject *kobj; + struct probe *p; + unsigned best = ~0U; + +retry: + down_read(domain->sem); + for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) { + struct kobject *(*probe)(dev_t, int *, void *); + struct module *owner; + void *data; + + if (p->dev > dev || p->dev + p->range - 1 < dev) + continue; + 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 - 1; + *index = dev - p->dev; + if (p->lock && p->lock(dev, data) < 0) { + module_put(owner); + continue; + } + up_read(domain->sem); + kobj = probe(dev, index, data); + /* Currently ->owner protects _only_ ->probe() itself. */ + module_put(owner); + if (kobj) + return kobj; + goto retry; + } + up_read(domain->sem); + return NULL; +} + +struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, + struct subsystem *s) +{ + struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL); + struct probe *base = kmalloc(sizeof(struct probe), GFP_KERNEL); + int i; + memset(base, 0, sizeof(struct probe)); + base->dev = 1; + base->range = ~0; + base->get = base_probe; + for (i = 0; i < 255; i++) + p->probes[i] = base; + p->sem = &s->rwsem; + return p; +} diff -urN C69-tty/drivers/block/genhd.c C69-kobj_map/drivers/block/genhd.c --- C69-tty/drivers/block/genhd.c Mon May 5 10:26:50 2003 +++ C69-kobj_map/drivers/block/genhd.c Mon May 5 10:26:51 2003 @@ -13,13 +13,14 @@ #include #include #include +#include #define MAX_PROBE_HASH 255 /* random */ static struct subsystem block_subsys; /* - * Can be merged with blk_probe or deleted altogether. Later. + * Can be deleted altogether. Later. * * Modified under both block_subsys.rwsem and major_names_lock. */ @@ -31,27 +32,12 @@ static spinlock_t major_names_lock = SPIN_LOCK_UNLOCKED; -static struct blk_probe { - struct blk_probe *next; - dev_t dev; - unsigned long range; - struct module *owner; - struct kobject *(*get)(dev_t dev, int *part, void *data); - int (*lock)(dev_t, void *); - void *data; -} *probes[MAX_PROBE_HASH]; - /* index in the above - for now: assume no multimajor ranges */ static inline int major_to_index(int major) { return major % MAX_PROBE_HASH; } -static inline int dev_to_index(dev_t dev) -{ - return major_to_index(MAJOR(dev)); -} - /* get block device names in somewhat random order */ int get_blkdev_list(char *p) { @@ -156,6 +142,8 @@ return ret; } +static struct kobj_map *bdev_map; + /* * Register device numbers dev..(dev+range-1) * range must be nonzero @@ -165,42 +153,12 @@ struct kobject *(*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; - - if (p == NULL) - return; - - p->owner = module; - p->get = probe; - p->lock = lock; - p->dev = dev; - p->range = range; - p->data = data; - down_write(&block_subsys.rwsem); - for (s = &probes[index]; *s && (*s)->range < range; s = &(*s)->next) - ; - p->next = *s; - *s = p; - up_write(&block_subsys.rwsem); + kobj_map(bdev_map, dev, range, module, probe, lock, data); } void blk_unregister_region(dev_t dev, unsigned long range) { - 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; - if (p->dev == dev && p->range == range) { - *s = p->next; - kfree(p); - break; - } - } - up_write(&block_subsys.rwsem); + kobj_unmap(bdev_map, dev, range); } EXPORT_SYMBOL(blk_register_region); @@ -256,46 +214,10 @@ * This function gets the structure containing partitioning * information for the given device @dev. */ -struct gendisk * -get_gendisk(dev_t dev, int *part) +struct gendisk *get_gendisk(dev_t dev, int *part) { - int index = dev_to_index(dev); - struct kobject *kobj; - struct blk_probe *p; - unsigned best = ~0U; - -retry: - down_read(&block_subsys.rwsem); - for (p = probes[index]; p; p = p->next) { - struct kobject *(*probe)(dev_t, int *, void *); - struct module *owner; - void *data; - - if (p->dev > dev || p->dev + p->range - 1 < dev) - continue; - 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 - 1; - *part = dev - p->dev; - if (p->lock && p->lock(dev, data) < 0) { - module_put(owner); - continue; - } - up_read(&block_subsys.rwsem); - kobj = probe(dev, part, data); - /* Currently ->owner protects _only_ ->probe() itself. */ - module_put(owner); - if (kobj) - return to_disk(kobj); - goto retry; /* this terminates: best decreases */ - } - up_read(&block_subsys.rwsem); - return NULL; + struct kobject *kobj = kobj_lookup(bdev_map, dev, part); + return kobj ? to_disk(kobj) : NULL; } #ifdef CONFIG_PROC_FS @@ -378,14 +300,7 @@ 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 = 1; - base->range = ~0; /* range 1 .. ~0 */ - base->get = base_probe; - for (i = 0; i < MAX_PROBE_HASH; i++) - probes[i] = base; /* must remain last in chain */ + bdev_map = kobj_map_init(base_probe, &block_subsys); blk_dev_init(); subsystem_register(&block_subsys); return 0; diff -urN C69-tty/include/linux/kobj_map.h C69-kobj_map/include/linux/kobj_map.h --- C69-tty/include/linux/kobj_map.h Wed Dec 31 19:00:00 1969 +++ C69-kobj_map/include/linux/kobj_map.h Mon May 5 10:26:51 2003 @@ -0,0 +1,12 @@ +#ifdef __KERNEL__ + +typedef struct kobject *kobj_probe_t(dev_t, int *, void *); +struct kobj_map; + +int kobj_map(struct kobj_map *, dev_t, unsigned long, struct module *, + kobj_probe_t *, int (*)(dev_t, void *), void *); +void kobj_unmap(struct kobj_map *, dev_t, unsigned long); +struct kobject *kobj_lookup(struct kobj_map *, dev_t, int *); +struct kobj_map *kobj_map_init(kobj_probe_t *, struct subsystem *); + +#endif