dm_dev.c revision 1.2.2.2 1 /* $NetBSD: dm_dev.c,v 1.2.2.2 2009/01/17 13:28:53 mjf 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/disklabel.h>
36 #include <sys/ioctl.h>
37 #include <sys/ioccom.h>
38 #include <sys/kmem.h>
39
40 #include "netbsd-dm.h"
41 #include "dm.h"
42
43 static dm_dev_t* dm_dev_lookup_name(const char *);
44 static dm_dev_t* dm_dev_lookup_uuid(const char *);
45 static dm_dev_t* dm_dev_lookup_minor(int);
46
47 static struct dm_dev_head dm_dev_list =
48 TAILQ_HEAD_INITIALIZER(dm_dev_list);
49
50 kmutex_t dm_dev_mutex;
51
52 __inline static void
53 disable_dev(dm_dev_t *dmv)
54 {
55 TAILQ_REMOVE(&dm_dev_list, dmv, next_devlist);
56 mutex_enter(&dmv->dev_mtx);
57 mutex_exit(&dm_dev_mutex);
58 while(dmv->ref_cnt != 0)
59 cv_wait(&dmv->dev_cv, &dmv->dev_mtx);
60 mutex_exit(&dmv->dev_mtx);
61 }
62
63 /*
64 * Generic function used to lookup dm_dev_t. Calling with dm_dev_name
65 * and dm_dev_uuid NULL is allowed.
66 */
67 dm_dev_t*
68 dm_dev_lookup(const char *dm_dev_name, const char *dm_dev_uuid,
69 int dm_dev_minor)
70 {
71 dm_dev_t *dmv;
72
73 dmv = NULL;
74 mutex_enter(&dm_dev_mutex);
75
76 /* KASSERT(dm_dev_name != NULL && dm_dev_uuid != NULL && dm_dev_minor > 0); */
77 if (dm_dev_minor > 0)
78 if ((dmv = dm_dev_lookup_minor(dm_dev_minor)) != NULL){
79 dm_dev_busy(dmv);
80 mutex_exit(&dm_dev_mutex);
81 return dmv;
82 }
83
84 if (dm_dev_name != NULL)
85 if ((dmv = dm_dev_lookup_name(dm_dev_name)) != NULL){
86 dm_dev_busy(dmv);
87 mutex_exit(&dm_dev_mutex);
88 return dmv;
89 }
90
91 if (dm_dev_uuid != NULL)
92 if ((dmv = dm_dev_lookup_name(dm_dev_uuid)) != NULL){
93 dm_dev_busy(dmv);
94 mutex_exit(&dm_dev_mutex);
95 return dmv;
96 }
97 mutex_exit(&dm_dev_mutex);
98 return NULL;
99 }
100
101
102 /*
103 * Lookup device with its minor number.
104 */
105 static dm_dev_t*
106 dm_dev_lookup_minor(int dm_dev_minor)
107 {
108 dm_dev_t *dmv;
109
110 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){
111 if (dm_dev_minor == dmv->minor)
112 return dmv;
113 }
114
115 return NULL;
116 }
117
118 /*
119 * Lookup device with it's device name.
120 */
121 static dm_dev_t*
122 dm_dev_lookup_name(const char *dm_dev_name)
123 {
124 dm_dev_t *dmv;
125 int dlen; int slen;
126
127 slen = strlen(dm_dev_name);
128
129 if (slen == 0)
130 return NULL;
131
132 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){
133
134 dlen = strlen(dmv->name);
135
136 if(slen != dlen)
137 continue;
138
139 if (strncmp(dm_dev_name, dmv->name, slen) == 0)
140 return dmv;
141 }
142
143 return NULL;
144 }
145
146 /*
147 * Lookup device with it's device uuid. Used mostly by LVM2tools.
148 */
149 static dm_dev_t*
150 dm_dev_lookup_uuid(const char *dm_dev_uuid)
151 {
152 dm_dev_t *dmv;
153 size_t len;
154
155 len = 0;
156 len = strlen(dm_dev_uuid);
157
158 if (len == 0)
159 return NULL;
160
161 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){
162
163 if (strlen(dmv->uuid) != len)
164 continue;
165
166 if (strncmp(dm_dev_uuid, dmv->uuid, strlen(dmv->uuid)) == 0)
167 return dmv;
168 }
169
170 return NULL;
171 }
172
173 /*
174 * Insert new device to the global list of devices.
175 */
176 int
177 dm_dev_insert(dm_dev_t *dev)
178 {
179 dm_dev_t *dmv;
180 int r;
181
182 dmv = NULL;
183 r = 0;
184
185 KASSERT(dev != NULL);
186 mutex_enter(&dm_dev_mutex);
187 if (((dmv = dm_dev_lookup_uuid(dev->uuid)) == NULL) &&
188 ((dmv = dm_dev_lookup_name(dev->name)) == NULL) &&
189 ((dmv = dm_dev_lookup_minor(dev->minor)) == NULL)){
190
191 TAILQ_INSERT_TAIL(&dm_dev_list, dev, next_devlist);
192
193 } else
194 r = EEXIST;
195
196 mutex_exit(&dm_dev_mutex);
197 return r;
198 }
199
200 #ifdef notyet
201 /*
202 * Lookup device with its minor number.
203 */
204 int
205 dm_dev_test_minor(int dm_dev_minor)
206 {
207 dm_dev_t *dmv;
208
209 mutex_enter(&dm_dev_mutex);
210 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){
211 if (dm_dev_minor == dmv->minor){
212 mutex_exit(&dm_dev_mutex);
213 return 1;
214 }
215 }
216 mutex_exit(&dm_dev_mutex);
217
218 return 0;
219 }
220 #endif
221
222 /*
223 * Remove device selected with dm_dev from global list of devices.
224 */
225 dm_dev_t*
226 dm_dev_rem(const char *dm_dev_name, const char *dm_dev_uuid,
227 int dm_dev_minor)
228 {
229 dm_dev_t *dmv;
230 dmv = NULL;
231
232 mutex_enter(&dm_dev_mutex);
233
234 if (dm_dev_minor > 0)
235 if ((dmv = dm_dev_lookup_minor(dm_dev_minor)) != NULL){
236 disable_dev(dmv);
237 return dmv;
238 }
239
240 if (dm_dev_name != NULL)
241 if ((dmv = dm_dev_lookup_name(dm_dev_name)) != NULL){
242 disable_dev(dmv);
243 return dmv;
244 }
245
246 if (dm_dev_uuid != NULL)
247 if ((dmv = dm_dev_lookup_name(dm_dev_uuid)) != NULL){
248 disable_dev(dmv);
249 return dmv;
250 }
251 mutex_exit(&dm_dev_mutex);
252
253 return NULL;
254 }
255
256 /*
257 * Destroy all devices created in device-mapper. Remove all tables
258 * free all allocated memmory.
259 */
260 int
261 dm_dev_destroy(void)
262 {
263 dm_dev_t *dmv;
264 mutex_enter(&dm_dev_mutex);
265
266 while (TAILQ_FIRST(&dm_dev_list) != NULL){
267
268 dmv = TAILQ_FIRST(&dm_dev_list);
269
270 TAILQ_REMOVE(&dm_dev_list, TAILQ_FIRST(&dm_dev_list),
271 next_devlist);
272
273 mutex_enter(&dmv->dev_mtx);
274
275 while (dmv->ref_cnt != 0)
276 cv_wait(&dmv->dev_cv, &dmv->dev_mtx);
277
278 /* Destroy active table first. */
279 dm_table_destroy(&dmv->table_head, DM_TABLE_ACTIVE);
280
281 /* Destroy inactive table if exits, too. */
282 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
283
284 dm_table_head_destroy(&dmv->table_head);
285
286 mutex_exit(&dmv->dev_mtx);
287 mutex_destroy(&dmv->dev_mtx);
288 cv_destroy(&dmv->dev_cv);
289
290 (void)kmem_free(dmv, sizeof(dm_dev_t));
291 }
292 mutex_exit(&dm_dev_mutex);
293
294 mutex_destroy(&dm_dev_mutex);
295 return 0;
296 }
297
298 /*
299 * Allocate new device entry.
300 */
301 dm_dev_t*
302 dm_dev_alloc()
303 {
304 dm_dev_t *dmv;
305
306 dmv = kmem_zalloc(sizeof(dm_dev_t), KM_NOSLEEP);
307 dmv->dk_label = kmem_zalloc(sizeof(struct disklabel), KM_NOSLEEP);
308
309 return dmv;
310 }
311
312 /*
313 * Freed device entry.
314 */
315 int
316 dm_dev_free(dm_dev_t *dmv)
317 {
318 KASSERT(dmv != NULL);
319
320 if (dmv->dk_label != NULL)
321 (void)kmem_free(dmv->dk_label, sizeof(struct disklabel));
322
323 (void)kmem_free(dmv, sizeof(dm_dev_t));
324
325 return 0;
326 }
327
328 void
329 dm_dev_busy(dm_dev_t *dmv)
330 {
331 mutex_enter(&dmv->dev_mtx);
332 dmv->ref_cnt++;
333 mutex_exit(&dmv->dev_mtx);
334 }
335
336 void
337 dm_dev_unbusy(dm_dev_t *dmv)
338 {
339 KASSERT(dmv->ref_cnt != 0);
340
341 mutex_enter(&dmv->dev_mtx);
342 if (--dmv->ref_cnt == 0)
343 cv_broadcast(&dmv->dev_cv);
344 mutex_exit(&dmv->dev_mtx);
345 }
346
347 /*
348 * Return prop_array of dm_targer_list dictionaries.
349 */
350 prop_array_t
351 dm_dev_prop_list(void)
352 {
353 dm_dev_t *dmv;
354 prop_array_t dev_array;
355 prop_dictionary_t dev_dict;
356
357 dev_array = prop_array_create();
358
359 mutex_enter(&dm_dev_mutex);
360
361 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) {
362 dev_dict = prop_dictionary_create();
363
364 prop_dictionary_set_cstring(dev_dict, DM_DEV_NAME, dmv->name);
365 prop_dictionary_set_uint32(dev_dict, DM_DEV_DEV, dmv->minor);
366
367 prop_array_add(dev_array, dev_dict);
368 prop_object_release(dev_dict);
369 }
370
371 mutex_exit(&dm_dev_mutex);
372 return dev_array;
373 }
374
375 /*
376 * Initialize global device mutex.
377 */
378 int
379 dm_dev_init()
380 {
381 TAILQ_INIT(&dm_dev_list); /* initialize global dev list */
382 mutex_init(&dm_dev_mutex, MUTEX_DEFAULT, IPL_NONE);
383 return 0;
384 }
385