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/kdev_t.h> 15 #include <linux/kobject.h> 16 #include <linux/kobj_map.h> 17 18 struct kobj_map { 19 struct probe { 20 struct probe *next; 21 dev_t dev; 22 unsigned long range; 23 struct module *owner; 24 kobj_probe_t *get; 25 int (*lock)(dev_t, void *); 26 void *data; 27 } *probes[255]; 28 struct semaphore *sem; 29 }; 30 31 int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range, 32 struct module *module, kobj_probe_t *probe, 33 int (*lock)(dev_t, void *), void *data) 34 { 35 unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1; 36 unsigned index = MAJOR(dev); 37 unsigned i; 38 struct probe *p; 39 40 if (n > 255) 41 n = 255; 42 43 p = kmalloc(sizeof(struct probe) * n, GFP_KERNEL); 44 45 if (p == NULL) 46 return -ENOMEM; 47 48 for (i = 0; i < n; i++, p++) { 49 p->owner = module; 50 p->get = probe; 51 p->lock = lock; 52 p->dev = dev; 53 p->range = range; 54 p->data = data; 55 } 56 down(domain->sem); 57 for (i = 0, p -= n; i < n; i++, p++, index++) { 58 struct probe **s = &domain->probes[index % 255]; 59 while (*s && (*s)->range < range) 60 s = &(*s)->next; 61 p->next = *s; 62 *s = p; 63 } 64 up(domain->sem); 65 return 0; 66 } 67 68 void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range) 69 { 70 unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1; 71 unsigned index = MAJOR(dev); 72 unsigned i; 73 struct probe *found = NULL; 74 75 if (n > 255) 76 n = 255; 77 78 down(domain->sem); 79 for (i = 0; i < n; i++, index++) { 80 struct probe **s; 81 for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) { 82 struct probe *p = *s; 83 if (p->dev == dev && p->range == range) { 84 *s = p->next; 85 if (!found) 86 found = p; 87 break; 88 } 89 } 90 } 91 up(domain->sem); 92 kfree(found); 93 } 94 95 struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index) 96 { 97 struct kobject *kobj; 98 struct probe *p; 99 unsigned long best = ~0UL; 100 101 retry: 102 down(domain->sem); 103 for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) { 104 struct kobject *(*probe)(dev_t, int *, void *); 105 struct module *owner; 106 void *data; 107 108 if (p->dev > dev || p->dev + p->range - 1 < dev) 109 continue; 110 if (p->range - 1 >= best) 111 break; 112 if (!try_module_get(p->owner)) 113 continue; 114 owner = p->owner; 115 data = p->data; 116 probe = p->get; 117 best = p->range - 1; 118 *index = dev - p->dev; 119 if (p->lock && p->lock(dev, data) < 0) { 120 module_put(owner); 121 continue; 122 } 123 up(domain->sem); 124 kobj = probe(dev, index, data); 125 /* Currently ->owner protects _only_ ->probe() itself. */ 126 module_put(owner); 127 if (kobj) 128 return kobj; 129 goto retry; 130 } 131 up(domain->sem); 132 return NULL; 133 } 134 135 struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem) 136 { 137 struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL); 138 struct probe *base = kmalloc(sizeof(struct probe), GFP_KERNEL); 139 int i; 140 141 if ((p == NULL) || (base == NULL)) { 142 kfree(p); 143 kfree(base); 144 return NULL; 145 } 146 147 memset(base, 0, sizeof(struct probe)); 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->sem = sem; 154 return p; 155 } 156