Branch data Line data Source code
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 : 0 : 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 : 0 : unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
37 : : unsigned index = MAJOR(dev);
38 : : unsigned i;
39 : : struct probe *p;
40 : :
41 [ # # ]: 0 : if (n > 255)
42 : : n = 255;
43 : :
44 : 0 : p = kmalloc(sizeof(struct probe) * n, GFP_KERNEL);
45 : :
46 [ # # ]: 0 : if (p == NULL)
47 : : return -ENOMEM;
48 : :
49 [ # # ]: 0 : for (i = 0; i < n; i++, p++) {
50 : 0 : p->owner = module;
51 : 0 : p->get = probe;
52 : 0 : p->lock = lock;
53 : 0 : p->dev = dev;
54 : 0 : p->range = range;
55 : 0 : p->data = data;
56 : : }
57 : 0 : mutex_lock(domain->lock);
58 [ # # ]: 0 : for (i = 0, p -= n; i < n; i++, p++, index++) {
59 : 0 : struct probe **s = &domain->probes[index % 255];
60 [ # # ][ # # ]: 0 : while (*s && (*s)->range < range)
61 : 0 : s = &(*s)->next;
62 : 0 : p->next = *s;
63 : 0 : *s = p;
64 : : }
65 : 0 : mutex_unlock(domain->lock);
66 : 0 : return 0;
67 : : }
68 : :
69 : 0 : void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
70 : : {
71 : 0 : unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
72 : : unsigned index = MAJOR(dev);
73 : : unsigned i;
74 : : struct probe *found = NULL;
75 : :
76 [ # # ]: 0 : if (n > 255)
77 : : n = 255;
78 : :
79 : 0 : mutex_lock(domain->lock);
80 [ # # ]: 0 : for (i = 0; i < n; i++, index++) {
81 : : struct probe **s;
82 [ # # ]: 0 : for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) {
83 : : struct probe *p = *s;
84 [ # # ][ # # ]: 0 : if (p->dev == dev && p->range == range) {
85 : 0 : *s = p->next;
86 [ # # ]: 0 : if (!found)
87 : : found = p;
88 : : break;
89 : : }
90 : : }
91 : : }
92 : 0 : mutex_unlock(domain->lock);
93 : 0 : kfree(found);
94 : 0 : }
95 : :
96 : 414 : 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 : 414 : mutex_lock(domain->lock);
104 [ + - ]: 1954 : 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 [ + + ][ - + ]: 1954 : if (p->dev > dev || p->dev + p->range - 1 < dev)
110 : 1540 : continue;
111 [ + ]: 414 : if (p->range - 1 >= best)
112 : : break;
113 [ - + ]: 414 : if (!try_module_get(p->owner))
114 : 0 : continue;
115 : 414 : owner = p->owner;
116 : 414 : data = p->data;
117 : 414 : probe = p->get;
118 : 414 : best = p->range - 1;
119 : 414 : *index = dev - p->dev;
120 [ + - ][ - + ]: 414 : if (p->lock && p->lock(dev, data) < 0) {
121 : 0 : module_put(owner);
122 : 0 : continue;
123 : : }
124 : 414 : mutex_unlock(domain->lock);
125 : 414 : kobj = probe(dev, index, data);
126 : : /* Currently ->owner protects _only_ ->probe() itself. */
127 : 414 : module_put(owner);
128 [ - + ]: 414 : if (kobj)
129 : : return kobj;
130 : : goto retry;
131 : : }
132 : 0 : mutex_unlock(domain->lock);
133 : 0 : return NULL;
134 : : }
135 : :
136 : 0 : 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 [ # # ]: 0 : if ((p == NULL) || (base == NULL)) {
143 : 0 : kfree(p);
144 : 0 : kfree(base);
145 : 0 : return NULL;
146 : : }
147 : :
148 : 0 : base->dev = 1;
149 : 0 : base->range = ~0;
150 : 0 : base->get = base_probe;
151 [ # # ]: 0 : for (i = 0; i < 255; i++)
152 : 0 : p->probes[i] = base;
153 : 0 : p->lock = lock;
154 : 0 : return p;
155 : : }
|