1 /* 2 * linux/drivers/base/map.c 3 * 4 * (C) Copyright Al Viro 2002,2003 5 * Released under GPL v2. 6 * 7 * NOTE: data structure needs to be changed. It works, but for large dev_t 8 * it will be too slow. It is isolated, though, so these changes will be 9 * local to that file. 10 */ 11 12 #include <linux/module.h> 13 #include <linux/slab.h> 14 #include <linux/mutex.h> 15 #include <linux/kdev_t.h> 16 #include <linux/kobject.h> 17 #include <linux/kobj_map.h> 18 19 struct kobj_map { 20 struct probe { 21 struct probe *next; 22 dev_t dev; 23 unsigned long range; 24 struct module *owner; 25 kobj_probe_t *get; 26 int (*lock)(dev_t, void *); 27 void *data; 28 } *probes[255]; 29 struct mutex *lock; 30 }; 31 32 int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range, 33 struct module *module, kobj_probe_t *probe, 34 int (*lock)(dev_t, void *), void *data) 35 { 36 unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1; 37 unsigned index = MAJOR(dev); 38 unsigned i; 39 struct probe *p; 40 41 if (n > 255) 42 n = 255; 43 44 p = kmalloc(sizeof(struct probe) * n, GFP_KERNEL); 45 46 if (p == NULL) 47 return -ENOMEM; 48 49 for (i = 0; i < n; i++, p++) { 50 p->owner = module; 51 p->get = probe; 52 p->lock = lock; 53 p->dev = dev; 54 p->range = range; 55 p->data = data; 56 } 57 mutex_lock(domain->lock); 58 for (i = 0, p -= n; i < n; i++, p++, index++) { 59 struct probe **s = &domain->probes[index % 255]; 60 while (*s && (*s)->range < range) 61 s = &(*s)->next; 62 p->next = *s; 63 *s = p; 64 } 65 mutex_unlock(domain->lock); 66 return 0; 67 } 68 69 void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range) 70 { 71 unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1; 72 unsigned index = MAJOR(dev); 73 unsigned i; 74 struct probe *found = NULL; 75 76 if (n > 255) 77 n = 255; 78 79 mutex_lock(domain->lock); 80 for (i = 0; i < n; i++, index++) { 81 struct probe **s; 82 for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) { 83 struct probe *p = *s; 84 if (p->dev == dev && p->range == range) { 85 *s = p->next; 86 if (!found) 87 found = p; 88 break; 89 } 90 } 91 } 92 mutex_unlock(domain->lock); 93 kfree(found); 94 } 95 96 struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index) 97 { 98 struct kobject *kobj; 99 struct probe *p; 100 unsigned long best = ~0UL; 101 102 retry: 103 mutex_lock(domain->lock); 104 for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) { 105 struct kobject *(*probe)(dev_t, int *, void *); 106 struct module *owner; 107 void *data; 108 109 if (p->dev > dev || p->dev + p->range - 1 < dev) 110 continue; 111 if (p->range - 1 >= best) 112 break; 113 if (!try_module_get(p->owner)) 114 continue; 115 owner = p->owner; 116 data = p->data; 117 probe = p->get; 118 best = p->range - 1; 119 *index = dev - p->dev; 120 if (p->lock && p->lock(dev, data) < 0) { 121 module_put(owner); 122 continue; 123 } 124 mutex_unlock(domain->lock); 125 kobj = probe(dev, index, data); 126 /* Currently ->owner protects _only_ ->probe() itself. */ 127 module_put(owner); 128 if (kobj) 129 return kobj; 130 goto retry; 131 } 132 mutex_unlock(domain->lock); 133 return NULL; 134 } 135 136 struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock) 137 { 138 struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL); 139 struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL); 140 int i; 141 142 if ((p == NULL) || (base == NULL)) { 143 kfree(p); 144 kfree(base); 145 return NULL; 146 } 147 148 base->dev = 1; 149 base->range = ~0; 150 base->get = base_probe; 151 for (i = 0; i < 255; i++) 152 p->probes[i] = base; 153 p->lock = lock; 154 return p; 155 } 156