xref: /dflybsd-src/sys/dev/disk/dm/dm_dev.c (revision bc73772033acf16cec326bfb764d6fd9dc1dc660)
1 /*        $NetBSD: dm_dev.c,v 1.8 2010/01/04 00:19:08 haad 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/ioccom.h>
38 #include <sys/malloc.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 MALLOC_DECLARE(M_DM);
48 
49 static struct dm_dev_head dm_dev_list =
50 TAILQ_HEAD_INITIALIZER(dm_dev_list);
51 
52 struct lock dm_dev_mutex;
53 
54 /* dm_dev_mutex must be holdby caller before using disable_dev. */
55 void
56 disable_dev(dm_dev_t * dmv)
57 {
58 	TAILQ_REMOVE(&dm_dev_list, dmv, next_devlist);
59 	lockmgr(&dmv->dev_mtx, LK_EXCLUSIVE);
60 	lockmgr(&dm_dev_mutex, LK_RELEASE);
61 	while (dmv->ref_cnt != 0)
62 		cv_wait(&dmv->dev_cv, &dmv->dev_mtx);
63 	lockmgr(&dmv->dev_mtx, LK_RELEASE);
64 }
65 /*
66  * Generic function used to lookup dm_dev_t. Calling with dm_dev_name
67  * and dm_dev_uuid NULL is allowed.
68  */
69 dm_dev_t *
70 dm_dev_lookup(const char *dm_dev_name, const char *dm_dev_uuid,
71     int dm_dev_minor)
72 {
73 	dm_dev_t *dmv;
74 
75 	dmv = NULL;
76 	lockmgr(&dm_dev_mutex, LK_EXCLUSIVE);
77 
78 	/* KKASSERT(dm_dev_name != NULL && dm_dev_uuid != NULL && dm_dev_minor
79 	 * > 0); */
80 	if (dm_dev_minor > 0)
81 		if ((dmv = dm_dev_lookup_minor(dm_dev_minor)) != NULL) {
82 			dm_dev_busy(dmv);
83 			lockmgr(&dm_dev_mutex, LK_RELEASE);
84 			return dmv;
85 		}
86 	if (dm_dev_name != NULL)
87 		if ((dmv = dm_dev_lookup_name(dm_dev_name)) != NULL) {
88 			dm_dev_busy(dmv);
89 			lockmgr(&dm_dev_mutex, LK_RELEASE);
90 			return dmv;
91 		}
92 	if (dm_dev_uuid != NULL)
93 		if ((dmv = dm_dev_lookup_uuid(dm_dev_uuid)) != NULL) {
94 			dm_dev_busy(dmv);
95 			lockmgr(&dm_dev_mutex, LK_RELEASE);
96 			return dmv;
97 		}
98 	lockmgr(&dm_dev_mutex, LK_RELEASE);
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  * 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;
126 	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  * 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  * Insert new device to the global list of devices.
174  */
175 int
176 dm_dev_insert(dm_dev_t * dev)
177 {
178 	dm_dev_t *dmv;
179 	int r;
180 
181 	dmv = NULL;
182 	r = 0;
183 
184 	KKASSERT(dev != NULL);
185 	lockmgr(&dm_dev_mutex, LK_EXCLUSIVE);
186 	if (((dmv = dm_dev_lookup_uuid(dev->uuid)) == NULL) &&
187 	    ((dmv = dm_dev_lookup_name(dev->name)) == NULL) &&
188 	    ((dmv = dm_dev_lookup_minor(dev->minor)) == NULL)) {
189 
190 		TAILQ_INSERT_TAIL(&dm_dev_list, dev, next_devlist);
191 
192 	} else
193 		r = EEXIST;
194 
195 	lockmgr(&dm_dev_mutex, LK_RELEASE);
196 	return r;
197 }
198 #ifdef notyet
199 /*
200  * Lookup device with its minor number.
201  */
202 int
203 dm_dev_test_minor(int dm_dev_minor)
204 {
205 	dm_dev_t *dmv;
206 
207 	lockmgr(&dm_dev_mutex, LK_EXCLUSIVE);
208 	TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) {
209 		if (dm_dev_minor == dmv->minor) {
210 			lockmgr(&dm_dev_mutex, LK_RELEASE);
211 			return 1;
212 		}
213 	}
214 	lockmgr(&dm_dev_mutex, LK_RELEASE);
215 
216 	return 0;
217 }
218 #endif
219 
220 #if 0
221 /*
222  * dm_dev_lookup_devt look for selected device_t. We keep this routine
223  * outside of dm_dev_lookup because it is a temporally solution.
224  *
225  * TODO: This is a hack autoconf should be more flexible.
226  */
227 dm_dev_t *
228 dm_dev_detach(device_t devt)
229 {
230        dm_dev_t *dmv;
231 
232        lockmgr(&dm_dev_mutex, LK_EXCLUSIVE);
233        TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) {
234                if (devt == dmv->devt) {
235                        disable_dev(dmv);
236                        lockmgr(&dm_dev_mutex, LK_RELEASE);
237                        return dmv;
238                }
239        }
240        lockmgr(&dm_dev_mutex, LK_RELEASE);
241 
242        return NULL;
243 }
244 #endif
245 
246 /*
247  * Remove device selected with dm_dev from global list of devices.
248  */
249 dm_dev_t *
250 dm_dev_rem(const char *dm_dev_name, const char *dm_dev_uuid,
251     int dm_dev_minor)
252 {
253 	dm_dev_t *dmv;
254 	dmv = NULL;
255 
256 	lockmgr(&dm_dev_mutex, LK_EXCLUSIVE);
257 
258 	if (dm_dev_minor > 0)
259 		if ((dmv = dm_dev_lookup_minor(dm_dev_minor)) != NULL) {
260 			disable_dev(dmv);
261 			return dmv;
262 		}
263 	if (dm_dev_name != NULL)
264 		if ((dmv = dm_dev_lookup_name(dm_dev_name)) != NULL) {
265 			disable_dev(dmv);
266 			return dmv;
267 		}
268 	if (dm_dev_uuid != NULL)
269 		if ((dmv = dm_dev_lookup_name(dm_dev_uuid)) != NULL) {
270 			disable_dev(dmv);
271 			return dmv;
272 		}
273 	lockmgr(&dm_dev_mutex, LK_RELEASE);
274 
275 	return NULL;
276 }
277 /*
278  * Destroy all devices created in device-mapper. Remove all tables
279  * free all allocated memmory.
280  */
281 int
282 dm_dev_destroy(void)
283 {
284 	dm_dev_t *dmv;
285 	lockmgr(&dm_dev_mutex, LK_EXCLUSIVE);
286 
287 	while (TAILQ_FIRST(&dm_dev_list) != NULL) {
288 
289 		dmv = TAILQ_FIRST(&dm_dev_list);
290 
291 		TAILQ_REMOVE(&dm_dev_list, TAILQ_FIRST(&dm_dev_list),
292 		    next_devlist);
293 
294 		lockmgr(&dmv->dev_mtx, LK_EXCLUSIVE);
295 
296 		while (dmv->ref_cnt != 0)
297 			cv_wait(&dmv->dev_cv, &dmv->dev_mtx);
298 
299 		/* Destroy active table first.  */
300 		dm_table_destroy(&dmv->table_head, DM_TABLE_ACTIVE);
301 
302 		/* Destroy inactive table if exits, too. */
303 		dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
304 
305 		dm_table_head_destroy(&dmv->table_head);
306 
307 		lockmgr(&dmv->dev_mtx, LK_RELEASE);
308 		lockuninit(&dmv->dev_mtx);
309 		cv_destroy(&dmv->dev_cv);
310 
311 		(void) kfree(dmv, M_DM);
312 	}
313 	lockmgr(&dm_dev_mutex, LK_RELEASE);
314 
315 	lockuninit(&dm_dev_mutex);
316 	return 0;
317 }
318 /*
319  * Allocate new device entry.
320  */
321 dm_dev_t *
322 dm_dev_alloc(void)
323 {
324 	dm_dev_t *dmv;
325 
326 	dmv = kmalloc(sizeof(dm_dev_t), M_DM, M_WAITOK | M_ZERO);
327 
328 	if (dmv != NULL)
329 		dmv->diskp = kmalloc(sizeof(struct disk), M_DM, M_WAITOK | M_ZERO);
330 
331 	return dmv;
332 }
333 /*
334  * Freed device entry.
335  */
336 int
337 dm_dev_free(dm_dev_t * dmv)
338 {
339 	KKASSERT(dmv != NULL);
340 
341 	lockuninit(&dmv->dev_mtx);
342 	lockuninit(&dmv->diskp_mtx);
343 	cv_destroy(&dmv->dev_cv);
344 
345 	if (dmv->diskp != NULL)
346 		(void) kfree(dmv->diskp, M_DM);
347 
348 	(void) kfree(dmv, M_DM);
349 
350 	return 0;
351 }
352 
353 void
354 dm_dev_busy(dm_dev_t * dmv)
355 {
356 	lockmgr(&dmv->dev_mtx, LK_EXCLUSIVE);
357 	dmv->ref_cnt++;
358 	lockmgr(&dmv->dev_mtx, LK_RELEASE);
359 }
360 
361 void
362 dm_dev_unbusy(dm_dev_t * dmv)
363 {
364 	KKASSERT(dmv->ref_cnt != 0);
365 
366 	lockmgr(&dmv->dev_mtx, LK_EXCLUSIVE);
367 	if (--dmv->ref_cnt == 0)
368 		cv_broadcast(&dmv->dev_cv);
369 	lockmgr(&dmv->dev_mtx, LK_RELEASE);
370 }
371 /*
372  * Return prop_array of dm_targer_list dictionaries.
373  */
374 prop_array_t
375 dm_dev_prop_list(void)
376 {
377 	dm_dev_t *dmv;
378 	prop_array_t dev_array;
379 	prop_dictionary_t dev_dict;
380 
381 	dev_array = prop_array_create();
382 
383 	lockmgr(&dm_dev_mutex, LK_EXCLUSIVE);
384 
385 	TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) {
386 		dev_dict = prop_dictionary_create();
387 
388 		prop_dictionary_set_cstring(dev_dict, DM_DEV_NAME, dmv->name);
389 		prop_dictionary_set_uint32(dev_dict, DM_DEV_DEV, dmv->minor);
390 
391 		prop_array_add(dev_array, dev_dict);
392 		prop_object_release(dev_dict);
393 	}
394 
395 	lockmgr(&dm_dev_mutex, LK_RELEASE);
396 	return dev_array;
397 }
398 /*
399  * Initialize global device mutex.
400  */
401 int
402 dm_dev_init(void)
403 {
404 	TAILQ_INIT(&dm_dev_list);	/* initialize global dev list */
405 	lockinit(&dm_dev_mutex, "dmdevlist", 0, LK_CANRECURSE);
406 	return 0;
407 }
408