dm_dev.c revision 1.4 1 /* $NetBSD: dm_dev.c,v 1.4 2009/03/18 10:22:39 cegger Exp $ */
2
3 /*
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Adam Hamsik.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/types.h>
33 #include <sys/param.h>
34
35 #include <sys/disk.h>
36 #include <sys/disklabel.h>
37 #include <sys/ioctl.h>
38 #include <sys/ioccom.h>
39 #include <sys/kmem.h>
40
41 #include "netbsd-dm.h"
42 #include "dm.h"
43
44 static dm_dev_t* dm_dev_lookup_name(const char *);
45 static dm_dev_t* dm_dev_lookup_uuid(const char *);
46 static dm_dev_t* dm_dev_lookup_minor(int);
47
48 static struct dm_dev_head dm_dev_list =
49 TAILQ_HEAD_INITIALIZER(dm_dev_list);
50
51 kmutex_t dm_dev_mutex;
52
53 __inline static void
54 disable_dev(dm_dev_t *dmv)
55 {
56 TAILQ_REMOVE(&dm_dev_list, dmv, next_devlist);
57 mutex_enter(&dmv->dev_mtx);
58 mutex_exit(&dm_dev_mutex);
59 while(dmv->ref_cnt != 0)
60 cv_wait(&dmv->dev_cv, &dmv->dev_mtx);
61 mutex_exit(&dmv->dev_mtx);
62 }
63
64 /*
65 * Generic function used to lookup dm_dev_t. Calling with dm_dev_name
66 * and dm_dev_uuid NULL is allowed.
67 */
68 dm_dev_t*
69 dm_dev_lookup(const char *dm_dev_name, const char *dm_dev_uuid,
70 int dm_dev_minor)
71 {
72 dm_dev_t *dmv;
73
74 dmv = NULL;
75 mutex_enter(&dm_dev_mutex);
76
77 /* KASSERT(dm_dev_name != NULL && dm_dev_uuid != NULL && dm_dev_minor > 0); */
78 if (dm_dev_minor > 0)
79 if ((dmv = dm_dev_lookup_minor(dm_dev_minor)) != NULL){
80 dm_dev_busy(dmv);
81 mutex_exit(&dm_dev_mutex);
82 return dmv;
83 }
84
85 if (dm_dev_name != NULL)
86 if ((dmv = dm_dev_lookup_name(dm_dev_name)) != NULL){
87 dm_dev_busy(dmv);
88 mutex_exit(&dm_dev_mutex);
89 return dmv;
90 }
91
92 if (dm_dev_uuid != NULL)
93 if ((dmv = dm_dev_lookup_uuid(dm_dev_uuid)) != NULL){
94 dm_dev_busy(dmv);
95 mutex_exit(&dm_dev_mutex);
96 return dmv;
97 }
98 mutex_exit(&dm_dev_mutex);
99 return NULL;
100 }
101
102
103 /*
104 * Lookup device with its minor number.
105 */
106 static dm_dev_t*
107 dm_dev_lookup_minor(int dm_dev_minor)
108 {
109 dm_dev_t *dmv;
110
111 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){
112 if (dm_dev_minor == dmv->minor)
113 return dmv;
114 }
115
116 return NULL;
117 }
118
119 /*
120 * Lookup device with it's device name.
121 */
122 static dm_dev_t*
123 dm_dev_lookup_name(const char *dm_dev_name)
124 {
125 dm_dev_t *dmv;
126 int dlen; int slen;
127
128 slen = strlen(dm_dev_name);
129
130 if (slen == 0)
131 return NULL;
132
133 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){
134
135 dlen = strlen(dmv->name);
136
137 if(slen != dlen)
138 continue;
139
140 if (strncmp(dm_dev_name, dmv->name, slen) == 0)
141 return dmv;
142 }
143
144 return NULL;
145 }
146
147 /*
148 * Lookup device with it's device uuid. Used mostly by LVM2tools.
149 */
150 static dm_dev_t*
151 dm_dev_lookup_uuid(const char *dm_dev_uuid)
152 {
153 dm_dev_t *dmv;
154 size_t len;
155
156 len = 0;
157 len = strlen(dm_dev_uuid);
158
159 if (len == 0)
160 return NULL;
161
162 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){
163
164 if (strlen(dmv->uuid) != len)
165 continue;
166
167 if (strncmp(dm_dev_uuid, dmv->uuid, strlen(dmv->uuid)) == 0)
168 return dmv;
169 }
170
171 return NULL;
172 }
173
174 /*
175 * Insert new device to the global list of devices.
176 */
177 int
178 dm_dev_insert(dm_dev_t *dev)
179 {
180 dm_dev_t *dmv;
181 int r;
182
183 dmv = NULL;
184 r = 0;
185
186 KASSERT(dev != NULL);
187 mutex_enter(&dm_dev_mutex);
188 if (((dmv = dm_dev_lookup_uuid(dev->uuid)) == NULL) &&
189 ((dmv = dm_dev_lookup_name(dev->name)) == NULL) &&
190 ((dmv = dm_dev_lookup_minor(dev->minor)) == NULL)){
191
192 TAILQ_INSERT_TAIL(&dm_dev_list, dev, next_devlist);
193
194 } else
195 r = EEXIST;
196
197 mutex_exit(&dm_dev_mutex);
198 return r;
199 }
200
201 #ifdef notyet
202 /*
203 * Lookup device with its minor number.
204 */
205 int
206 dm_dev_test_minor(int dm_dev_minor)
207 {
208 dm_dev_t *dmv;
209
210 mutex_enter(&dm_dev_mutex);
211 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){
212 if (dm_dev_minor == dmv->minor){
213 mutex_exit(&dm_dev_mutex);
214 return 1;
215 }
216 }
217 mutex_exit(&dm_dev_mutex);
218
219 return 0;
220 }
221 #endif
222
223 /*
224 * Remove device selected with dm_dev from global list of devices.
225 */
226 dm_dev_t*
227 dm_dev_rem(const char *dm_dev_name, const char *dm_dev_uuid,
228 int dm_dev_minor)
229 {
230 dm_dev_t *dmv;
231 dmv = NULL;
232
233 mutex_enter(&dm_dev_mutex);
234
235 if (dm_dev_minor > 0)
236 if ((dmv = dm_dev_lookup_minor(dm_dev_minor)) != NULL){
237 disable_dev(dmv);
238 return dmv;
239 }
240
241 if (dm_dev_name != NULL)
242 if ((dmv = dm_dev_lookup_name(dm_dev_name)) != NULL){
243 disable_dev(dmv);
244 return dmv;
245 }
246
247 if (dm_dev_uuid != NULL)
248 if ((dmv = dm_dev_lookup_name(dm_dev_uuid)) != NULL){
249 disable_dev(dmv);
250 return dmv;
251 }
252 mutex_exit(&dm_dev_mutex);
253
254 return NULL;
255 }
256
257 /*
258 * Destroy all devices created in device-mapper. Remove all tables
259 * free all allocated memmory.
260 */
261 int
262 dm_dev_destroy(void)
263 {
264 dm_dev_t *dmv;
265 mutex_enter(&dm_dev_mutex);
266
267 while (TAILQ_FIRST(&dm_dev_list) != NULL){
268
269 dmv = TAILQ_FIRST(&dm_dev_list);
270
271 TAILQ_REMOVE(&dm_dev_list, TAILQ_FIRST(&dm_dev_list),
272 next_devlist);
273
274 mutex_enter(&dmv->dev_mtx);
275
276 while (dmv->ref_cnt != 0)
277 cv_wait(&dmv->dev_cv, &dmv->dev_mtx);
278
279 /* Destroy active table first. */
280 dm_table_destroy(&dmv->table_head, DM_TABLE_ACTIVE);
281
282 /* Destroy inactive table if exits, too. */
283 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
284
285 dm_table_head_destroy(&dmv->table_head);
286
287 mutex_exit(&dmv->dev_mtx);
288 mutex_destroy(&dmv->dev_mtx);
289 cv_destroy(&dmv->dev_cv);
290
291 (void)kmem_free(dmv, sizeof(dm_dev_t));
292 }
293 mutex_exit(&dm_dev_mutex);
294
295 mutex_destroy(&dm_dev_mutex);
296 return 0;
297 }
298
299 /*
300 * Allocate new device entry.
301 */
302 dm_dev_t*
303 dm_dev_alloc(void)
304 {
305 dm_dev_t *dmv;
306
307 dmv = kmem_zalloc(sizeof(dm_dev_t), KM_NOSLEEP);
308
309 if(dmv != NULL)
310 dmv->diskp = kmem_zalloc(sizeof(struct disk), KM_NOSLEEP);
311
312 return dmv;
313 }
314
315 /*
316 * Freed device entry.
317 */
318 int
319 dm_dev_free(dm_dev_t *dmv)
320 {
321 KASSERT(dmv != NULL);
322
323 if(dmv->diskp != NULL)
324 (void)kmem_free(dmv->diskp, sizeof(struct disk));
325
326 (void)kmem_free(dmv, sizeof(dm_dev_t));
327
328 return 0;
329 }
330
331 void
332 dm_dev_busy(dm_dev_t *dmv)
333 {
334 mutex_enter(&dmv->dev_mtx);
335 dmv->ref_cnt++;
336 mutex_exit(&dmv->dev_mtx);
337 }
338
339 void
340 dm_dev_unbusy(dm_dev_t *dmv)
341 {
342 KASSERT(dmv->ref_cnt != 0);
343
344 mutex_enter(&dmv->dev_mtx);
345 if (--dmv->ref_cnt == 0)
346 cv_broadcast(&dmv->dev_cv);
347 mutex_exit(&dmv->dev_mtx);
348 }
349
350 /*
351 * Return prop_array of dm_targer_list dictionaries.
352 */
353 prop_array_t
354 dm_dev_prop_list(void)
355 {
356 dm_dev_t *dmv;
357 prop_array_t dev_array;
358 prop_dictionary_t dev_dict;
359
360 dev_array = prop_array_create();
361
362 mutex_enter(&dm_dev_mutex);
363
364 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) {
365 dev_dict = prop_dictionary_create();
366
367 prop_dictionary_set_cstring(dev_dict, DM_DEV_NAME, dmv->name);
368 prop_dictionary_set_uint32(dev_dict, DM_DEV_DEV, dmv->minor);
369
370 prop_array_add(dev_array, dev_dict);
371 prop_object_release(dev_dict);
372 }
373
374 mutex_exit(&dm_dev_mutex);
375 return dev_array;
376 }
377
378 /*
379 * Initialize global device mutex.
380 */
381 int
382 dm_dev_init(void)
383 {
384 TAILQ_INIT(&dm_dev_list); /* initialize global dev list */
385 mutex_init(&dm_dev_mutex, MUTEX_DEFAULT, IPL_NONE);
386 return 0;
387 }
388