dm_dev.c revision 1.1.2.12 1 /* $NetBSD: dm_dev.c,v 1.1.2.12 2008/10/16 23:43:03 haad Exp $ */
2
3 /*
4 * Copyright (c) 1996, 1997, 1998, 1999, 2002 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 struct dm_dev* dm_dev_lookup_name(const char *);
44 static struct dm_dev* dm_dev_lookup_uuid(const char *);
45 static struct dm_dev* 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(struct dm_dev *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 struct dm_dev. Calling with dm_dev_name
65 * and dm_dev_uuid NULL is allowed.
66 */
67 struct dm_dev*
68 dm_dev_lookup(const char *dm_dev_name, const char *dm_dev_uuid,
69 int dm_dev_minor)
70 {
71 struct dm_dev *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 struct dm_dev*
106 dm_dev_lookup_minor(int dm_dev_minor)
107 {
108 struct dm_dev *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 struct dm_dev*
122 dm_dev_lookup_name(const char *dm_dev_name)
123 {
124 struct dm_dev *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 struct dm_dev*
150 dm_dev_lookup_uuid(const char *dm_dev_uuid)
151 {
152 struct dm_dev *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(struct dm_dev *dev)
178 {
179 struct dm_dev *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
201
202
203 /*
204 * Lookup device with its minor number.
205 */
206 int
207 dm_dev_test_minor(int dm_dev_minor)
208 {
209 struct dm_dev *dmv;
210
211 mutex_enter(&dm_dev_mutex);
212 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){
213 if (dm_dev_minor == dmv->minor){
214 mutex_exit(&dm_dev_mutex);
215 return 1;
216 }
217 }
218 mutex_exit(&dm_dev_mutex);
219
220 return 0;
221 }
222
223 /*
224 * Remove device selected with dm_dev from global list of devices.
225 */
226 struct dm_dev*
227 dm_dev_rem(const char *dm_dev_name, const char *dm_dev_uuid,
228 int dm_dev_minor)
229 {
230 struct dm_dev *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 struct dm_dev *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(struct dm_dev));
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 struct dm_dev*
303 dm_dev_alloc()
304 {
305 struct dm_dev *dmv;
306
307 dmv = kmem_zalloc(sizeof(struct dm_dev), KM_NOSLEEP);
308 dmv->dk_label = kmem_zalloc(sizeof(struct disklabel), KM_NOSLEEP);
309
310 return dmv;
311 }
312
313 /*
314 * Freed device entry.
315 */
316 int
317 dm_dev_free(struct dm_dev *dmv)
318 {
319 KASSERT(dmv != NULL);
320
321 if (dmv->dk_label != NULL)
322 (void)kmem_free(dmv->dk_label, sizeof(struct disklabel));
323
324 (void)kmem_free(dmv, sizeof(struct dm_dev));
325
326 return 0;
327 }
328
329 void
330 dm_dev_busy(struct dm_dev *dmv)
331 {
332 mutex_enter(&dmv->dev_mtx);
333 dmv->ref_cnt++;
334 mutex_exit(&dmv->dev_mtx);
335 }
336
337 void
338 dm_dev_unbusy(struct dm_dev *dmv)
339 {
340 KASSERT(dmv->ref_cnt != 0);
341
342 mutex_enter(&dmv->dev_mtx);
343 if (--dmv->ref_cnt == 0)
344 cv_broadcast(&dmv->dev_cv);
345 mutex_exit(&dmv->dev_mtx);
346 }
347
348 /*
349 * Return prop_array of dm_targer_list dictionaries.
350 */
351 prop_array_t
352 dm_dev_prop_list(void)
353 {
354 struct dm_dev *dmv;
355
356 int j;
357
358 prop_array_t dev_array;
359 prop_dictionary_t dev_dict;
360
361 j =0;
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
372 prop_dictionary_set_uint32(dev_dict, DM_DEV_DEV, dmv->minor);
373
374 prop_array_set(dev_array, j, dev_dict);
375
376 prop_object_release(dev_dict);
377
378 j++;
379 }
380
381 mutex_exit(&dm_dev_mutex);
382 return dev_array;
383 }
384
385 /*
386 * Initialize global device mutex.
387 */
388 int
389 dm_dev_init()
390 {
391 TAILQ_INIT(&dm_dev_list); /* initialize global dev list */
392 mutex_init(&dm_dev_mutex, MUTEX_DEFAULT, IPL_NONE);
393 return 0;
394 }
395