xref: /dflybsd-src/sys/vfs/devfs/devfs_helper.c (revision 6507240b2fcfebaacc0f92f997dad76922e1d8c0)
1 /*
2  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Alex Hornung <ahornung@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <machine/limits.h>
40 #include <vfs/devfs/devfs.h>
41 
42 MALLOC_DECLARE(M_DEVFS);
43 
44 static struct devfs_unit_hash *devfs_clone_hash_get(int, cdev_t);
45 #if 0
46 static void devfs_clone_hash_put(struct devfs_unit_hash *);
47 #endif
48 static int devfs_clone_hash_add(struct devfs_unit_hash **, struct devfs_unit_hash *);
49 static struct devfs_unit_hash *devfs_clone_hash_del(struct devfs_unit_hash **, int);
50 
51 /*
52  * DEVFS clone hash functions
53  */
54 
55 static struct devfs_unit_hash *
56 devfs_clone_hash_get(int unit_no, cdev_t dev)
57 {
58 	struct devfs_unit_hash *hash = (struct devfs_unit_hash *)kmalloc(sizeof(struct devfs_unit_hash), M_DEVFS, M_WAITOK);
59 	hash->next = NULL;
60 	hash->unit_no = unit_no;
61 	hash->dev = dev;
62 
63 	return hash;
64 }
65 
66 
67 #if 0
68 
69 static void
70 devfs_clone_hash_put(struct devfs_unit_hash *hash)
71 {
72 	kfree(hash, M_DEVFS);
73 }
74 
75 #endif
76 
77 static int
78 devfs_clone_hash_add(struct devfs_unit_hash **devfs_hash_array, struct devfs_unit_hash *hash)
79 {
80         struct devfs_unit_hash **hashp;
81         hashp = &devfs_hash_array[hash->unit_no &
82                           DEVFS_UNIT_HMASK];
83         while (*hashp) {
84                 if ((*hashp)->unit_no ==
85                           hash->unit_no)
86                         return(EEXIST);
87                 hashp = &(*hashp)->next;
88         }
89         hash->next = NULL;
90         *hashp = hash;
91         return (0);
92 }
93 
94 
95 static struct devfs_unit_hash *
96 devfs_clone_hash_del(struct devfs_unit_hash **devfs_hash_array, int unit_no)
97 {
98         struct devfs_unit_hash **hashp;
99 		struct devfs_unit_hash *hash;
100         hashp = &devfs_hash_array[unit_no &
101                           DEVFS_UNIT_HMASK];
102 		hash = *hashp;
103         while ((*hashp)->unit_no != unit_no) {
104                 KKASSERT(*hashp != NULL);
105                 hashp = &(*hashp)->next;
106 				hash = *hashp;
107         }
108         *hashp = hash->next;
109 
110 		return hash;
111 }
112 
113 /*
114  * DEVFS clone bitmap functions
115  */
116 void
117 devfs_clone_bitmap_init(struct devfs_bitmap *bitmap)
118 {
119 	bitmap->bitmap = (unsigned long *)kmalloc(DEVFS_BITMAP_INITIAL_SIZE*sizeof(unsigned long), M_DEVFS, M_WAITOK);
120 	bitmap->chunks = DEVFS_BITMAP_INITIAL_SIZE;
121 	memset(bitmap->bitmap, ULONG_MAX, DEVFS_BITMAP_INITIAL_SIZE*sizeof(unsigned long));
122 }
123 
124 
125 void
126 devfs_clone_bitmap_uninit(struct devfs_bitmap *bitmap)
127 {
128 	kfree(bitmap->bitmap, M_DEVFS);
129 }
130 
131 
132 void
133 devfs_clone_bitmap_resize(struct devfs_bitmap *bitmap, int newchunks)
134 {
135 	int oldchunks = bitmap->chunks;
136 	bitmap->chunks = newchunks+2;
137 	bitmap->bitmap = (unsigned long *)krealloc(bitmap->bitmap, sizeof(unsigned long)*bitmap->chunks, M_DEVFS, M_WAITOK);
138 
139 	devfs_debug(DEVFS_DEBUG_DEBUG, "%d vs %d (oldchunks=%d)\n", bitmap->bitmap, bitmap->bitmap + oldchunks, oldchunks);
140 	memset(bitmap->bitmap + oldchunks, ULONG_MAX, sizeof(unsigned long)*(bitmap->chunks - oldchunks));
141 }
142 
143 
144 int
145 devfs_clone_bitmap_fff(struct devfs_bitmap *bitmap)
146 {
147 	unsigned long 	curbitmap;
148 	int bit, i;
149 	int chunks = bitmap->chunks;
150 
151 	for (i = 0; i < chunks+1; i++) {
152 		if (i == chunks)
153 			devfs_clone_bitmap_resize(bitmap, i);
154 		curbitmap = bitmap->bitmap[i];
155 
156 		if (curbitmap > 0) {
157 			curbitmap &= (~curbitmap)+1;
158 			for (bit = 1; curbitmap != 1; bit++)
159 				curbitmap = (unsigned long)curbitmap >> 1;
160 
161 			return bit-1 + (i<<3) * sizeof(unsigned long);
162 		}
163 	}
164 
165 	/* Should never happen as we dynamically resize as needed */
166 	return -1;
167 }
168 
169 
170 int
171 devfs_clone_bitmap_chk(struct devfs_bitmap *bitmap, int unit)
172 {
173 	int chunk = unit / (sizeof(unsigned long)<<3);
174 	unit -= chunk<<3 * sizeof(unsigned long);
175 
176 	if (chunk >= bitmap->chunks)
177 		return 1;
178 
179 	return !((bitmap->bitmap[chunk]) & (1<<(unit)));
180 }
181 
182 
183 void
184 devfs_clone_bitmap_set(struct devfs_bitmap *bitmap, int unit)
185 {
186 	int chunk = unit / (sizeof(unsigned long)<<3);
187 	unit -= chunk<<3 * sizeof(unsigned long);
188 
189 	if (chunk >= bitmap->chunks) {
190 		devfs_clone_bitmap_resize(bitmap, chunk);
191 	}
192 
193 	bitmap->bitmap[chunk] &= ~(1<<unit);
194 }
195 
196 
197 void
198 devfs_clone_bitmap_rst(struct devfs_bitmap *bitmap, int unit)
199 {
200 	int chunk = unit / (sizeof(unsigned long)<<3);
201 	unit -= chunk<<3 * sizeof(unsigned long);
202 
203 	if (chunk >= bitmap->chunks)
204 		return;
205 
206 	bitmap->bitmap[chunk] |= (1<<unit);
207 }
208 
209 
210 int
211 devfs_clone_bitmap_get(struct devfs_bitmap *bitmap, int limit)
212 {
213 	int unit;
214 	unit = devfs_clone_bitmap_fff(bitmap);
215 	KKASSERT(unit != -1);
216 
217 	if ((limit > 0) && (unit > limit))
218 		return -1;
219 
220 	devfs_clone_bitmap_set(bitmap, unit);
221 
222 	return unit;
223 }
224 
225 /*
226  * DEVFS clone helper functions
227  */
228 
229 void
230 devfs_clone_helper_init(struct devfs_clone_helper *helper)
231 {
232 	devfs_clone_bitmap_init(&helper->DEVFS_CLONE_BITMAP(generic));
233 	memset(&helper->DEVFS_CLONE_HASHLIST(generic), 0, DEVFS_UNIT_HSIZE*sizeof(void *));
234 }
235 
236 
237 void
238 devfs_clone_helper_uninit(struct devfs_clone_helper *helper)
239 {
240 	devfs_clone_bitmap_uninit(&helper->DEVFS_CLONE_BITMAP(generic));
241 	//XXX: free all elements in helper->DEVFS_HASHLIST(generic)
242 }
243 
244 
245 int
246 devfs_clone_helper_insert(struct devfs_clone_helper *helper, cdev_t dev)
247 {
248 	struct devfs_unit_hash *hash;
249 	int error = 0;
250 	int unit_no;
251 
252 try_again:
253 	unit_no = devfs_clone_bitmap_fff(&helper->DEVFS_CLONE_BITMAP(generic));
254 
255 	devfs_clone_bitmap_set(&helper->DEVFS_CLONE_BITMAP(generic), unit_no);
256 	hash = devfs_clone_hash_get(unit_no, dev);
257 
258 	error = devfs_clone_hash_add(helper->DEVFS_CLONE_HASHLIST(generic), hash);
259 	KKASSERT(!error);
260 
261 	if (error)
262 		goto try_again;
263 
264 	dev->si_uminor = unit_no;
265 	return unit_no;
266 }
267 
268 
269 int
270 devfs_clone_helper_remove(struct devfs_clone_helper *helper, int unit_no)
271 {
272 	struct devfs_unit_hash *hash;
273 	hash = devfs_clone_hash_del(helper->DEVFS_CLONE_HASHLIST(generic), unit_no);
274 	devfs_clone_bitmap_rst(&helper->DEVFS_CLONE_BITMAP(generic), unit_no);
275 	kfree(hash, M_DEVFS);
276 
277 	return 0;
278 }
279