dm_dev.c revision 1.1.2.9 1 /* $NetBSD: dm_dev.c,v 1.1.2.9 2008/09/10 18:43:27 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
33 #include <sys/types.h>
34 #include <sys/param.h>
35
36 #include <sys/disklabel.h>
37 #include <sys/errno.h>
38 #include <sys/ioctl.h>
39 #include <sys/ioccom.h>
40 #include <sys/kmem.h>
41 #include <sys/lkm.h>
42 #include <sys/queue.h>
43
44 #include "netbsd-dm.h"
45 #include "dm.h"
46
47 static struct dm_dev* dm_dev_lookup_name(const char *);
48 static struct dm_dev* dm_dev_lookup_uuid(const char *);
49 static struct dm_dev* dm_dev_lookup_minor(int);
50
51 static struct dm_dev_head dm_dev_list =
52 TAILQ_HEAD_INITIALIZER(dm_dev_list);
53
54 kmutex_t dm_dev_mutex;
55
56 /*
57 * Locking architecture, for now I use mutexes later we can convert them to
58 * rw_locks. I use IPL_NONE for specifing IPL type for mutex.
59 * I will enter into mutex everytime I'm working with dm_dev_list.
60 */
61
62 /*
63 * Generic function used to lookup struct dm_dev. Calling with dm_dev_name
64 * and dm_dev_uuid NULL is allowed.
65 */
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
75 if (dm_dev_minor > 0)
76 if ((dmv = dm_dev_lookup_minor(dm_dev_minor)) != NULL)
77 return dmv;
78
79 if (dm_dev_name != NULL)
80 if ((dmv = dm_dev_lookup_name(dm_dev_name)) != NULL)
81 return dmv;
82
83 if (dm_dev_uuid != NULL)
84 if ((dmv = dm_dev_lookup_name(dm_dev_uuid)) != NULL)
85 return dmv;
86
87 return NULL;
88 }
89
90
91 /*
92 * Lookup device with its minor number.
93 */
94 static struct dm_dev*
95 dm_dev_lookup_minor(int dm_dev_minor)
96 {
97 struct dm_dev *dm_dev;
98
99 mutex_enter(&dm_dev_mutex);
100
101 TAILQ_FOREACH(dm_dev, &dm_dev_list, next_devlist){
102 if (dm_dev_minor == dm_dev->minor){
103 mutex_exit(&dm_dev_mutex);
104 return dm_dev;
105 }
106 }
107
108 mutex_exit(&dm_dev_mutex);
109
110 return NULL;
111 }
112
113 /*
114 * Lookup device with it's device name.
115 */
116 static struct dm_dev*
117 dm_dev_lookup_name(const char *dm_dev_name)
118 {
119 struct dm_dev *dm_dev;
120 int dlen; int slen;
121
122 slen = strlen(dm_dev_name);
123
124 if (slen == 0)
125 return NULL;
126
127 mutex_enter(&dm_dev_mutex);
128
129 TAILQ_FOREACH(dm_dev, &dm_dev_list, next_devlist){
130
131 dlen = strlen(dm_dev->name);
132
133 if(slen != dlen)
134 continue;
135
136 if (strncmp(dm_dev_name, dm_dev->name, slen) == 0) {
137 mutex_exit(&dm_dev_mutex);
138 return dm_dev;
139 }
140 }
141
142 mutex_exit(&dm_dev_mutex);
143
144 return NULL;
145 }
146
147 /*
148 * Lookup device with it's device uuid. Used mostly by LVM2tools.
149 */
150 static struct dm_dev*
151 dm_dev_lookup_uuid(const char *dm_dev_uuid)
152 {
153 struct dm_dev *dm_dev;
154 size_t len;
155
156 len = 0;
157
158 len = strlen(dm_dev_uuid);
159
160 if (len == 0)
161 return NULL;
162
163 mutex_enter(&dm_dev_mutex);
164
165 TAILQ_FOREACH(dm_dev, &dm_dev_list, next_devlist){
166
167 if (strlen(dm_dev->uuid) != len)
168 continue;
169
170 if (strncmp(dm_dev_uuid, dm_dev->uuid, strlen(dm_dev->uuid)) == 0){
171 mutex_exit(&dm_dev_mutex);
172 return dm_dev;
173 }
174 }
175 mutex_exit(&dm_dev_mutex);
176
177 return NULL;
178 }
179
180 /*
181 * Insert new device to the global list of devices.
182 */
183 int
184 dm_dev_insert(struct dm_dev *dev)
185 {
186 struct dm_dev *dmt;
187 int r;
188
189 dmt = NULL;
190 r = 0;
191
192 if (((dmt = dm_dev_lookup_uuid(dev->uuid)) == NULL) &&
193 ((dmt = dm_dev_lookup_name(dev->name)) == NULL) &&
194 ((dmt = dm_dev_lookup_minor(dev->minor)) == NULL)){
195
196 mutex_enter(&dm_dev_mutex);
197 TAILQ_INSERT_TAIL(&dm_dev_list, dev, next_devlist);
198 mutex_exit(&dm_dev_mutex);
199 } else
200 r = EEXIST;
201
202 return r;
203 }
204
205
206 /*
207 * Remove device selected with dm_dev from global list of devices.
208 */
209 int
210 dm_dev_rem(struct dm_dev *dm_dev)
211 {
212 mutex_enter(&dm_dev_mutex);
213
214 TAILQ_REMOVE(&dm_dev_list, dm_dev, next_devlist);
215
216 mutex_exit(&dm_dev_mutex);
217
218 return 0;
219 }
220
221 /*
222 * Destroy all devices created in device-mapper. Remove all tables
223 * free all allocated memmory.
224 */
225
226 int
227 dm_dev_destroy(void)
228 {
229 struct dm_dev *dm_dev;
230
231 /* XXX should I get rw_lock here ? */
232 mutex_enter(&dm_dev_mutex);
233
234 while (TAILQ_FIRST(&dm_dev_list) != NULL){
235
236 dm_dev = TAILQ_FIRST(&dm_dev_list);
237
238 TAILQ_REMOVE(&dm_dev_list, TAILQ_FIRST(&dm_dev_list),
239 next_devlist);
240
241 /* Destroy active table first. */
242 if (!SLIST_EMPTY(&dm_dev->tables[dm_dev->cur_active_table]))
243 dm_table_destroy(&dm_dev->tables[dm_dev->cur_active_table]);
244
245 /* Destroy unactive table if exits, too. */
246 if (!SLIST_EMPTY(&dm_dev->tables[1 - dm_dev->cur_active_table]))
247 dm_table_destroy(&dm_dev->tables[1 - dm_dev->cur_active_table]);
248
249 (void)kmem_free(dm_dev, sizeof(struct dm_dev));
250 }
251
252 mutex_exit(&dm_dev_mutex);
253
254 return 0;
255 }
256
257 /*
258 * Allocate new device entry.
259 */
260 struct dm_dev*
261 dm_dev_alloc()
262 {
263 return kmem_zalloc(sizeof(struct dm_dev), KM_NOSLEEP);
264 }
265
266 /*
267 * Freed device entry.
268 */
269 int
270 dm_dev_free(struct dm_dev *dmv)
271 {
272 if (dmv != NULL)
273 (void)kmem_free(dmv, sizeof(struct dm_dev));
274
275 return 0;
276 }
277
278
279 /*
280 * Return prop_array of dm_targer_list dictionaries.
281 */
282 prop_array_t
283 dm_dev_prop_list(void)
284 {
285 struct dm_dev *dmd;
286
287 int j;
288
289 prop_array_t dev_array;
290 prop_dictionary_t dev_dict;
291
292 j =0;
293
294 dev_array = prop_array_create();
295
296 mutex_enter(&dm_dev_mutex);
297
298 TAILQ_FOREACH(dmd, &dm_dev_list,next_devlist) {
299 dev_dict = prop_dictionary_create();
300
301 prop_dictionary_set_cstring(dev_dict, DM_DEV_NAME, dmd->name);
302
303 prop_dictionary_set_uint32(dev_dict, DM_DEV_DEV, dmd->minor);
304
305 prop_array_set(dev_array, j, dev_dict);
306
307 prop_object_release(dev_dict);
308
309 j++;
310 }
311
312 mutex_exit(&dm_dev_mutex);
313
314 return dev_array;
315 }
316
317 /*
318 * Initialize global device mutex.
319 */
320 int
321 dm_dev_init()
322 {
323 TAILQ_INIT(&dm_dev_list); /* initialize global dev list */
324
325 mutex_init(&dm_dev_mutex, MUTEX_DEFAULT, IPL_NONE);
326
327 return 0;
328 }
329