Blame view

drivers/base/map.c 3.29 KB
1da177e4c   Linus Torvalds   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   Jes Sorensen   [PATCH] kobj_map ...
14
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   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   Jes Sorensen   [PATCH] kobj_map ...
29
  	struct mutex *lock;
1da177e4c   Linus Torvalds   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   Jes Sorensen   [PATCH] kobj_map ...
57
  	mutex_lock(domain->lock);
1da177e4c   Linus Torvalds   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   Jes Sorensen   [PATCH] kobj_map ...
65
  	mutex_unlock(domain->lock);
1da177e4c   Linus Torvalds   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   Jes Sorensen   [PATCH] kobj_map ...
78
  	mutex_lock(domain->lock);
1da177e4c   Linus Torvalds   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   Jes Sorensen   [PATCH] kobj_map ...
91
  	mutex_unlock(domain->lock);
1da177e4c   Linus Torvalds   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   Jes Sorensen   [PATCH] kobj_map ...
102
  	mutex_lock(domain->lock);
1da177e4c   Linus Torvalds   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   Jes Sorensen   [PATCH] kobj_map ...
123
  		mutex_unlock(domain->lock);
1da177e4c   Linus Torvalds   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   Jes Sorensen   [PATCH] kobj_map ...
131
  	mutex_unlock(domain->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
  	return NULL;
  }
58383af62   Jes Sorensen   [PATCH] kobj_map ...
134
  struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
  {
  	struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
4aed0644d   Jiri Slaby   [PATCH] drivers/b...
137
  	struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL);
1da177e4c   Linus Torvalds   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   Linus Torvalds   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   Jes Sorensen   [PATCH] kobj_map ...
150
  	p->lock = lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
  	return p;
  }