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