Blame view
drivers/base/map.c
3.29 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* * 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 <linux/module.h> #include <linux/slab.h> |
58383af62 [PATCH] kobj_map ... |
14 |
#include <linux/mutex.h> |
1da177e4c Linux-2.6.12-rc2 |
15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#include <linux/kdev_t.h> #include <linux/kobject.h> #include <linux/kobj_map.h> 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]; |
58383af62 [PATCH] kobj_map ... |
29 |
struct mutex *lock; |
1da177e4c Linux-2.6.12-rc2 |
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
}; 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; } |
58383af62 [PATCH] kobj_map ... |
57 |
mutex_lock(domain->lock); |
1da177e4c Linux-2.6.12-rc2 |
58 59 60 61 62 63 64 |
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; } |
58383af62 [PATCH] kobj_map ... |
65 |
mutex_unlock(domain->lock); |
1da177e4c Linux-2.6.12-rc2 |
66 67 68 69 70 71 72 73 74 75 76 77 |
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; |
58383af62 [PATCH] kobj_map ... |
78 |
mutex_lock(domain->lock); |
1da177e4c Linux-2.6.12-rc2 |
79 80 81 82 83 84 85 86 87 88 89 90 |
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; } } } |
58383af62 [PATCH] kobj_map ... |
91 |
mutex_unlock(domain->lock); |
1da177e4c Linux-2.6.12-rc2 |
92 93 94 95 96 97 98 99 100 101 |
kfree(found); } struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index) { struct kobject *kobj; struct probe *p; unsigned long best = ~0UL; retry: |
58383af62 [PATCH] kobj_map ... |
102 |
mutex_lock(domain->lock); |
1da177e4c Linux-2.6.12-rc2 |
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
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; } |
58383af62 [PATCH] kobj_map ... |
123 |
mutex_unlock(domain->lock); |
1da177e4c Linux-2.6.12-rc2 |
124 125 126 127 128 129 130 |
kobj = probe(dev, index, data); /* Currently ->owner protects _only_ ->probe() itself. */ module_put(owner); if (kobj) return kobj; goto retry; } |
58383af62 [PATCH] kobj_map ... |
131 |
mutex_unlock(domain->lock); |
1da177e4c Linux-2.6.12-rc2 |
132 133 |
return NULL; } |
58383af62 [PATCH] kobj_map ... |
134 |
struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock) |
1da177e4c Linux-2.6.12-rc2 |
135 136 |
{ struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL); |
4aed0644d [PATCH] drivers/b... |
137 |
struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
138 139 140 141 142 143 144 |
int i; if ((p == NULL) || (base == NULL)) { kfree(p); kfree(base); return NULL; } |
1da177e4c Linux-2.6.12-rc2 |
145 146 147 148 149 |
base->dev = 1; base->range = ~0; base->get = base_probe; for (i = 0; i < 255; i++) p->probes[i] = base; |
58383af62 [PATCH] kobj_map ... |
150 |
p->lock = lock; |
1da177e4c Linux-2.6.12-rc2 |
151 152 |
return p; } |