Root/drivers/base/map.c

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
19struct 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
32int 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
69void 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
96struct 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
102retry:
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
136struct 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

Archive Download this file



interactive