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