dm - Add crypt target
[dragonfly.git] / sys / dev / disk / dm / dm_target.c
1 /*        $NetBSD: dm_target.c,v 1.12 2010/01/04 00:14: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/malloc.h>
36 #include <sys/module.h>
37
38
39 #include "netbsd-dm.h"
40 #include "dm.h"
41
42 static dm_target_t *dm_target_lookup_name(const char *);
43
44 TAILQ_HEAD(dm_target_head, dm_target);
45
46 static struct dm_target_head dm_target_list =
47 TAILQ_HEAD_INITIALIZER(dm_target_list);
48
49 MALLOC_DECLARE(M_DM);
50
51 struct lock dm_target_mutex;
52
53 /*
54  * Called indirectly from dm_table_load_ioctl to mark target as used.
55  */
56 void
57 dm_target_busy(dm_target_t * target)
58 {
59         atomic_add_int(&target->ref_cnt, 1);
60 }
61 /*
62  * Release reference counter on target.
63  */
64 void
65 dm_target_unbusy(dm_target_t * target)
66 {
67         KKASSERT(target->ref_cnt > 0);
68         atomic_subtract_int(&target->ref_cnt, 1);
69 }
70 /*
71  * Try to autoload target module if it was not found in current
72  * target list.
73  */
74 dm_target_t *
75 dm_target_autoload(const char *dm_target_name)
76 {
77 #if 0
78         char name[30];
79         u_int gen;
80         dm_target_t *dmt;
81
82         ksnprintf(name, sizeof(name), "dm_target_%s", dm_target_name);
83         name[29] = '\0';
84
85         do {
86                 gen = module_gen;
87
88                 /* Try to autoload target module */
89                 lockmgr(&module_lock, LK_EXCLUSIVE);
90                 (void) module_autoload(name, MODULE_CLASS_MISC);
91                 lockmgr(&module_lock, LK_RELEASE);
92         } while (gen != module_gen);
93
94         lockmgr(&dm_target_mutex, LK_EXCLUSIVE);
95         dmt = dm_target_lookup_name(dm_target_name);
96         if (dmt != NULL)
97                 dm_target_busy(dmt);
98         lockmgr(&dm_target_mutex, LK_RELEASE);
99
100         return dmt;
101 #endif
102         return NULL;
103 }
104 /*
105  * Lookup for target in global target list.
106  */
107 dm_target_t *
108 dm_target_lookup(const char *dm_target_name)
109 {
110         dm_target_t *dmt;
111
112         dmt = NULL;
113
114         if (dm_target_name == NULL)
115                 return NULL;
116
117         lockmgr(&dm_target_mutex, LK_EXCLUSIVE);
118
119         dmt = dm_target_lookup_name(dm_target_name);
120         if (dmt != NULL)
121                 dm_target_busy(dmt);
122
123         lockmgr(&dm_target_mutex, LK_RELEASE);
124
125         return dmt;
126 }
127 /*
128  * Search for name in TAIL and return apropriate pointer.
129  */
130 static dm_target_t *
131 dm_target_lookup_name(const char *dm_target_name)
132 {
133         dm_target_t *dm_target;
134         int dlen;
135         int slen;
136
137         slen = strlen(dm_target_name) + 1;
138
139         TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) {
140                 dlen = strlen(dm_target->name) + 1;
141                 if (dlen != slen)
142                         continue;
143
144                 if (strncmp(dm_target_name, dm_target->name, slen) == 0)
145                         return dm_target;
146         }
147
148         return NULL;
149 }
150 /*
151  * Insert new target struct into the TAIL.
152  * dm_target
153  *   contains name, version, function pointer to specifif target functions.
154  */
155 int
156 dm_target_insert(dm_target_t * dm_target)
157 {
158         dm_target_t *dmt;
159
160         lockmgr(&dm_target_mutex, LK_EXCLUSIVE);
161
162         dmt = dm_target_lookup_name(dm_target->name);
163         if (dmt != NULL) {
164                 kprintf("uhoh, target_insert EEXIST\n");
165                 lockmgr(&dm_target_mutex, LK_RELEASE);
166                 return EEXIST;
167         }
168         TAILQ_INSERT_TAIL(&dm_target_list, dm_target, dm_target_next);
169
170         lockmgr(&dm_target_mutex, LK_RELEASE);
171
172         return 0;
173 }
174
175
176 /*
177  * Remove target from TAIL, target is selected with it's name.
178  */
179 int
180 dm_target_rem(char *dm_target_name)
181 {
182         dm_target_t *dmt;
183
184         KKASSERT(dm_target_name != NULL);
185
186         lockmgr(&dm_target_mutex, LK_EXCLUSIVE);
187
188         dmt = dm_target_lookup_name(dm_target_name);
189         if (dmt == NULL) {
190                 lockmgr(&dm_target_mutex, LK_RELEASE);
191                 return ENOENT;
192         }
193         if (dmt->ref_cnt > 0) {
194                 lockmgr(&dm_target_mutex, LK_RELEASE);
195                 return EBUSY;
196         }
197         TAILQ_REMOVE(&dm_target_list,
198             dmt, dm_target_next);
199
200         lockmgr(&dm_target_mutex, LK_RELEASE);
201
202         (void) kfree(dmt, M_DM);
203
204         return 0;
205 }
206 /*
207  * Destroy all targets and remove them from queue.
208  * This routine is called from dm_detach, before module
209  * is unloaded.
210  */
211 int
212 dm_target_destroy(void)
213 {
214         dm_target_t *dm_target;
215
216         lockmgr(&dm_target_mutex, LK_EXCLUSIVE);
217         while (TAILQ_FIRST(&dm_target_list) != NULL) {
218
219                 dm_target = TAILQ_FIRST(&dm_target_list);
220
221                 TAILQ_REMOVE(&dm_target_list, TAILQ_FIRST(&dm_target_list),
222                     dm_target_next);
223
224                 (void) kfree(dm_target, M_DM);
225         }
226         lockmgr(&dm_target_mutex, LK_RELEASE);
227
228         lockuninit(&dm_target_mutex);
229
230         return 0;
231 }
232 /*
233  * Allocate new target entry.
234  */
235 dm_target_t *
236 dm_target_alloc(const char *name)
237 {
238         return kmalloc(sizeof(dm_target_t), M_DM, M_WAITOK | M_ZERO);
239 }
240 /*
241  * Return prop_array of dm_target dictionaries.
242  */
243 prop_array_t
244 dm_target_prop_list(void)
245 {
246         prop_array_t target_array, ver;
247         prop_dictionary_t target_dict;
248         dm_target_t *dm_target;
249
250         size_t i;
251
252         target_array = prop_array_create();
253
254         lockmgr(&dm_target_mutex, LK_EXCLUSIVE);
255
256         TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) {
257
258                 target_dict = prop_dictionary_create();
259                 ver = prop_array_create();
260                 prop_dictionary_set_cstring(target_dict, DM_TARGETS_NAME,
261                     dm_target->name);
262
263                 for (i = 0; i < 3; i++)
264                         prop_array_add_uint32(ver, dm_target->version[i]);
265
266                 prop_dictionary_set(target_dict, DM_TARGETS_VERSION, ver);
267                 prop_array_add(target_array, target_dict);
268
269                 prop_object_release(ver);
270                 prop_object_release(target_dict);
271         }
272
273         lockmgr(&dm_target_mutex, LK_RELEASE);
274
275         return target_array;
276 }
277 /* Initialize dm_target subsystem. */
278 int
279 dm_target_init(void)
280 {
281         dm_target_t *dmt, *dmt3, *dmt5;
282         int r;
283
284         r = 0;
285
286         lockinit(&dm_target_mutex, "dmtrgt", 0, LK_CANRECURSE);
287
288         dmt = dm_target_alloc("linear");
289         dmt3 = dm_target_alloc("striped");
290         dmt5 = dm_target_alloc("crypt");
291
292         dmt->version[0] = 1;
293         dmt->version[1] = 0;
294         dmt->version[2] = 2;
295         strlcpy(dmt->name, "linear", DM_MAX_TYPE_NAME);
296         dmt->init = &dm_target_linear_init;
297         dmt->status = &dm_target_linear_status;
298         dmt->strategy = &dm_target_linear_strategy;
299         dmt->deps = &dm_target_linear_deps;
300         dmt->destroy = &dm_target_linear_destroy;
301         dmt->upcall = &dm_target_linear_upcall;
302
303         r = dm_target_insert(dmt);
304
305         dmt3->version[0] = 1;
306         dmt3->version[1] = 0;
307         dmt3->version[2] = 3;
308         strlcpy(dmt3->name, "striped", DM_MAX_TYPE_NAME);
309         dmt3->init = &dm_target_stripe_init;
310         dmt3->status = &dm_target_stripe_status;
311         dmt3->strategy = &dm_target_stripe_strategy;
312         dmt3->deps = &dm_target_stripe_deps;
313         dmt3->destroy = &dm_target_stripe_destroy;
314         dmt3->upcall = &dm_target_stripe_upcall;
315
316         r = dm_target_insert(dmt3);
317         
318         dmt5->version[0] = 1;
319         dmt5->version[1] = 0;
320         dmt5->version[2] = 0;
321         strlcpy(dmt5->name, "crypt", DM_MAX_TYPE_NAME);
322         dmt5->init = &dm_target_crypt_init;
323         dmt5->status = &dm_target_crypt_status;
324         dmt5->strategy = &dm_target_crypt_strategy;
325         dmt5->deps = &dm_target_crypt_deps;
326         dmt5->destroy = &dm_target_crypt_destroy;
327         dmt5->upcall = &dm_target_crypt_upcall;
328
329         r = dm_target_insert(dmt5);
330
331
332         return r;
333 }