Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/base/map.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* linux/drivers/base/map.c
4
*
5
* (C) Copyright Al Viro 2002,2003
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 int n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
37
unsigned int index = MAJOR(dev);
38
unsigned int i;
39
struct probe *p;
40
41
if (n > 255)
42
n = 255;
43
44
p = kmalloc_array(n, sizeof(struct probe), GFP_KERNEL);
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
mutex_lock(domain->lock);
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
mutex_unlock(domain->lock);
65
return 0;
66
}
67
68
void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range)
69
{
70
unsigned int n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
71
unsigned int index = MAJOR(dev);
72
unsigned int i;
73
struct probe *found = NULL;
74
75
if (n > 255)
76
n = 255;
77
78
mutex_lock(domain->lock);
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
mutex_unlock(domain->lock);
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
mutex_lock(domain->lock);
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
mutex_unlock(domain->lock);
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
mutex_unlock(domain->lock);
132
return NULL;
133
}
134
135
struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock)
136
{
137
struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
138
struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL);
139
int i;
140
141
if ((p == NULL) || (base == NULL)) {
142
kfree(p);
143
kfree(base);
144
return NULL;
145
}
146
147
base->dev = 1;
148
base->range = ~0;
149
base->get = base_probe;
150
for (i = 0; i < 255; i++)
151
p->probes[i] = base;
152
p->lock = lock;
153
return p;
154
}
155
156