dm_target.c revision 1.3 1 /* $NetBSD: dm_target.c,v 1.3 2008/12/19 16:30:41 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/kmem.h>
36
37 #include "netbsd-dm.h"
38 #include "dm.h"
39
40 static dm_target_t* dm_target_alloc(const char *);
41 static dm_target_t* dm_target_lookup_name(const char *);
42
43 TAILQ_HEAD(dm_target_head, dm_target);
44
45 static struct dm_target_head dm_target_list =
46 TAILQ_HEAD_INITIALIZER(dm_target_list);
47
48 kmutex_t dm_target_mutex;
49
50 /*
51 * Called indirectly from dm_table_load_ioct to mark target as used.
52 */
53 void
54 dm_target_busy(dm_target_t *target)
55 {
56 target->ref_cnt++;
57 }
58
59 void
60 dm_target_unbusy(dm_target_t *target)
61 {
62 target->ref_cnt--;
63 }
64
65 dm_target_t *
66 dm_target_lookup(const char *dm_target_name)
67 {
68 dm_target_t *dmt;
69
70 dmt = NULL;
71
72 mutex_enter(&dm_target_mutex);
73
74 if (dm_target_name != NULL)
75 dmt = dm_target_lookup_name(dm_target_name);
76
77 if (dmt != NULL)
78 dm_target_busy(dmt);
79
80 mutex_exit(&dm_target_mutex);
81
82 return dmt;
83 }
84
85 /*
86 * Search for name in TAIL and return apropriate pointer.
87 */
88 static dm_target_t*
89 dm_target_lookup_name(const char *dm_target_name)
90 {
91 dm_target_t *dm_target;
92 int dlen; int slen;
93
94 slen = strlen(dm_target_name) + 1;
95
96 TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) {
97 dlen = strlen(dm_target->name) + 1;
98
99 if (dlen != slen)
100 continue;
101
102 if (strncmp(dm_target_name, dm_target->name, slen) == 0){
103 return dm_target;
104 }
105 }
106
107 return NULL;
108 }
109
110 /*
111 * Insert new target struct into the TAIL.
112 * dm_target
113 * contains name, version, function pointer to specifif target functions.
114 */
115 int
116 dm_target_insert(dm_target_t *dm_target)
117 {
118 dm_target_t *dmt;
119
120 mutex_enter(&dm_target_mutex);
121
122 dmt = dm_target_lookup_name(dm_target->name);
123 if (dmt != NULL) {
124 mutex_exit(&dm_target_mutex);
125 return EEXIST;
126 }
127
128 TAILQ_INSERT_TAIL(&dm_target_list, dm_target, dm_target_next);
129
130 mutex_exit(&dm_target_mutex);
131
132 return 0;
133 }
134
135
136 /*
137 * Remove target from TAIL, target is selected with it's name.
138 */
139 int
140 dm_target_rem(char *dm_target_name)
141 {
142 dm_target_t *dmt;
143
144 KASSERT(dm_target_name != NULL);
145
146 mutex_enter(&dm_target_mutex);
147
148 dmt = dm_target_lookup_name(dm_target_name);
149 if (dmt == NULL) {
150 mutex_exit(&dm_target_mutex);
151 return ENOENT;
152 }
153
154 if (dmt->ref_cnt > 0) {
155 mutex_exit(&dm_target_mutex);
156 return EBUSY;
157 }
158
159 TAILQ_REMOVE(&dm_target_list,
160 dmt, dm_target_next);
161
162 mutex_exit(&dm_target_mutex);
163
164 (void)kmem_free(dmt, sizeof(dm_target_t));
165
166 return 0;
167 }
168
169 /*
170 * Destroy all targets and remove them from queue.
171 * This routine is called from dm_detach, before module
172 * is unloaded.
173 */
174
175 int
176 dm_target_destroy(void)
177 {
178 dm_target_t *dm_target;
179
180 mutex_enter(&dm_target_mutex);
181 while (TAILQ_FIRST(&dm_target_list) != NULL){
182
183 dm_target = TAILQ_FIRST(&dm_target_list);
184
185 TAILQ_REMOVE(&dm_target_list, TAILQ_FIRST(&dm_target_list),
186 dm_target_next);
187
188 (void)kmem_free(dm_target, sizeof(dm_target_t));
189 }
190 mutex_exit(&dm_target_mutex);
191
192 return 0;
193 }
194
195 /*
196 * Allocate new target entry.
197 */
198 dm_target_t*
199 dm_target_alloc(const char *name)
200 {
201 return kmem_zalloc(sizeof(dm_target_t), KM_NOSLEEP);
202 }
203
204 /*
205 * Return prop_array of dm_target dictionaries.
206 */
207 prop_array_t
208 dm_target_prop_list(void)
209 {
210 prop_array_t target_array,ver;
211 prop_dictionary_t target_dict;
212 dm_target_t *dm_target;
213
214 size_t i;
215
216 target_array = prop_array_create();
217
218 mutex_enter(&dm_target_mutex);
219
220 TAILQ_FOREACH (dm_target, &dm_target_list, dm_target_next){
221
222 target_dict = prop_dictionary_create();
223 ver = prop_array_create();
224 prop_dictionary_set_cstring(target_dict, DM_TARGETS_NAME,
225 dm_target->name);
226
227 for (i = 0; i < 3; i++)
228 prop_array_add_uint32(ver, dm_target->version[i]);
229
230 prop_dictionary_set(target_dict, DM_TARGETS_VERSION, ver);
231 prop_array_add(target_array, target_dict);
232
233 prop_object_release(ver);
234 prop_object_release(target_dict);
235 }
236
237 mutex_exit(&dm_target_mutex);
238
239 return target_array;
240 }
241
242 /* Initialize dm_target subsystem. */
243 int
244 dm_target_init(void)
245 {
246 dm_target_t *dmt,*dmt1,*dmt2,*dmt3,*dmt4,*dmt5,*dmt6;
247 int r;
248
249 r = 0;
250
251 mutex_init(&dm_target_mutex, MUTEX_DEFAULT, IPL_NONE);
252
253 dmt = dm_target_alloc("linear");
254 dmt1 = dm_target_alloc("zero");
255 dmt2 = dm_target_alloc("error");
256 dmt3 = dm_target_alloc("striped");
257 dmt4 = dm_target_alloc("mirror");
258 dmt5 = dm_target_alloc("snapshot");
259 dmt6 = dm_target_alloc("snapshot-origin");
260
261 dmt->version[0] = 1;
262 dmt->version[1] = 0;
263 dmt->version[2] = 2;
264 strlcpy(dmt->name, "linear", DM_MAX_TYPE_NAME);
265 dmt->init = &dm_target_linear_init;
266 dmt->status = &dm_target_linear_status;
267 dmt->strategy = &dm_target_linear_strategy;
268 dmt->deps = &dm_target_linear_deps;
269 dmt->destroy = &dm_target_linear_destroy;
270 dmt->upcall = &dm_target_linear_upcall;
271
272 r = dm_target_insert(dmt);
273
274 dmt1->version[0] = 1;
275 dmt1->version[1] = 0;
276 dmt1->version[2] = 0;
277 strlcpy(dmt1->name, "zero", DM_MAX_TYPE_NAME);
278 dmt1->init = &dm_target_zero_init;
279 dmt1->status = &dm_target_zero_status;
280 dmt1->strategy = &dm_target_zero_strategy;
281 dmt1->deps = &dm_target_zero_deps;
282 dmt1->destroy = &dm_target_zero_destroy;
283 dmt1->upcall = &dm_target_zero_upcall;
284
285 r = dm_target_insert(dmt1);
286
287 dmt2->version[0] = 1;
288 dmt2->version[1] = 0;
289 dmt2->version[2] = 0;
290 strlcpy(dmt2->name, "error", DM_MAX_TYPE_NAME);
291 dmt2->init = &dm_target_error_init;
292 dmt2->status = &dm_target_error_status;
293 dmt2->strategy = &dm_target_error_strategy;
294 dmt2->deps = &dm_target_error_deps;
295 dmt2->destroy = &dm_target_error_destroy;
296 dmt2->upcall = &dm_target_error_upcall;
297
298 r = dm_target_insert(dmt2);
299
300 dmt3->version[0] = 1;
301 dmt3->version[1] = 0;
302 dmt3->version[2] = 3;
303 strlcpy(dmt3->name, "striped", DM_MAX_TYPE_NAME);
304 dmt3->init = &dm_target_linear_init;
305 dmt3->status = &dm_target_linear_status;
306 dmt3->strategy = &dm_target_linear_strategy;
307 dmt3->deps = &dm_target_linear_deps;
308 dmt3->destroy = &dm_target_linear_destroy;
309 dmt3->upcall = NULL;
310
311 r = dm_target_insert(dmt3);
312
313 dmt4->version[0] = 1;
314 dmt4->version[1] = 0;
315 dmt4->version[2] = 3;
316 strlcpy(dmt4->name, "mirror", DM_MAX_TYPE_NAME);
317 dmt4->init = NULL;
318 dmt4->status = NULL;
319 dmt4->strategy = NULL;
320 dmt4->deps = NULL;
321 dmt4->destroy = NULL;
322 dmt4->upcall = NULL;
323
324 r = dm_target_insert(dmt4);
325
326 dmt5->version[0] = 1;
327 dmt5->version[1] = 0;
328 dmt5->version[2] = 5;
329 strlcpy(dmt5->name, "snapshot", DM_MAX_TYPE_NAME);
330 dmt5->init = &dm_target_snapshot_init;
331 dmt5->status = &dm_target_snapshot_status;
332 dmt5->strategy = &dm_target_snapshot_strategy;
333 dmt5->deps = &dm_target_snapshot_deps;
334 dmt5->destroy = &dm_target_snapshot_destroy;
335 dmt5->upcall = &dm_target_snapshot_upcall;
336
337 r = dm_target_insert(dmt5);
338
339 dmt6->version[0] = 1;
340 dmt6->version[1] = 0;
341 dmt6->version[2] = 5;
342 strlcpy(dmt6->name, "snapshot-origin", DM_MAX_TYPE_NAME);
343 dmt6->init = &dm_target_snapshot_orig_init;
344 dmt6->status = &dm_target_snapshot_orig_status;
345 dmt6->strategy = &dm_target_snapshot_orig_strategy;
346 dmt6->deps = &dm_target_snapshot_orig_deps;
347 dmt6->destroy = &dm_target_snapshot_orig_destroy;
348 dmt6->upcall = &dm_target_snapshot_orig_upcall;
349
350 r = dm_target_insert(dmt6);
351
352 return r;
353 }
354