dm_dev.c revision 1.5.2.2 1 /* $NetBSD: dm_dev.c,v 1.5.2.2 2009/05/04 08:12:36 yamt 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 mutex_destroy(&dmv->dev_mtx);
324 cv_destroy(&dmv->dev_cv);
325
326 if(dmv->diskp != NULL)
327 (void)kmem_free(dmv->diskp, sizeof(struct disk));
328
329 (void)kmem_free(dmv, sizeof(dm_dev_t));
330
331 return 0;
332 }
333
334 void
335 dm_dev_busy(dm_dev_t *dmv)
336 {
337 mutex_enter(&dmv->dev_mtx);
338 dmv->ref_cnt++;
339 mutex_exit(&dmv->dev_mtx);
340 }
341
342 void
343 dm_dev_unbusy(dm_dev_t *dmv)
344 {
345 KASSERT(dmv->ref_cnt != 0);
346
347 mutex_enter(&dmv->dev_mtx);
348 if (--dmv->ref_cnt == 0)
349 cv_broadcast(&dmv->dev_cv);
350 mutex_exit(&dmv->dev_mtx);
351 }
352
353 /*
354 * Return prop_array of dm_targer_list dictionaries.
355 */
356 prop_array_t
357 dm_dev_prop_list(void)
358 {
359 dm_dev_t *dmv;
360 prop_array_t dev_array;
361 prop_dictionary_t dev_dict;
362
363 dev_array = prop_array_create();
364
365 mutex_enter(&dm_dev_mutex);
366
367 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) {
368 dev_dict = prop_dictionary_create();
369
370 prop_dictionary_set_cstring(dev_dict, DM_DEV_NAME, dmv->name);
371 prop_dictionary_set_uint32(dev_dict, DM_DEV_DEV, dmv->minor);
372
373 prop_array_add(dev_array, dev_dict);
374 prop_object_release(dev_dict);
375 }
376
377 mutex_exit(&dm_dev_mutex);
378 return dev_array;
379 }
380
381 /*
382 * Initialize global device mutex.
383 */
384 int
385 dm_dev_init(void)
386 {
387 TAILQ_INIT(&dm_dev_list); /* initialize global dev list */
388 mutex_init(&dm_dev_mutex, MUTEX_DEFAULT, IPL_NONE);
389 return 0;
390 }
391