xref: /netbsd-src/sys/dev/dm/dm_target.c (revision a70f355bc2c327c41018b50acc01533825c62c50)
1*a70f355bSandvar /*        $NetBSD: dm_target.c,v 1.42 2021/08/21 22:23:33 andvar Exp $      */
2c9d0c62aShaad 
3c9d0c62aShaad /*
4c9d0c62aShaad  * Copyright (c) 2008 The NetBSD Foundation, Inc.
5c9d0c62aShaad  * All rights reserved.
6c9d0c62aShaad  *
7c9d0c62aShaad  * This code is derived from software contributed to The NetBSD Foundation
8c9d0c62aShaad  * by Adam Hamsik.
9c9d0c62aShaad  *
10c9d0c62aShaad  * Redistribution and use in source and binary forms, with or without
11c9d0c62aShaad  * modification, are permitted provided that the following conditions
12c9d0c62aShaad  * are met:
13c9d0c62aShaad  * 1. Redistributions of source code Must retain the above copyright
14c9d0c62aShaad  *    notice, this list of conditions and the following disclaimer.
15c9d0c62aShaad  * 2. Redistributions in binary form must reproduce the above copyright
16c9d0c62aShaad  *    notice, this list of conditions and the following disclaimer in the
17c9d0c62aShaad  *    documentation and/or other materials provided with the distribution.
18c9d0c62aShaad  *
19c9d0c62aShaad  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20c9d0c62aShaad  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21c9d0c62aShaad  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22c9d0c62aShaad  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23c9d0c62aShaad  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24c9d0c62aShaad  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25c9d0c62aShaad  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26c9d0c62aShaad  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27c9d0c62aShaad  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28c9d0c62aShaad  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29c9d0c62aShaad  * POSSIBILITY OF SUCH DAMAGE.
30c9d0c62aShaad  */
31249cf593Schristos #include <sys/cdefs.h>
32*a70f355bSandvar __KERNEL_RCSID(0, "$NetBSD: dm_target.c,v 1.42 2021/08/21 22:23:33 andvar Exp $");
33c9d0c62aShaad 
34c9d0c62aShaad #include <sys/types.h>
35c9d0c62aShaad #include <sys/param.h>
36c9d0c62aShaad #include <sys/kmem.h>
3717599f37Shaad #include <sys/module.h>
3817599f37Shaad 
39c9d0c62aShaad #include "netbsd-dm.h"
40c9d0c62aShaad #include "dm.h"
41c9d0c62aShaad 
4278284dcaShaad static dm_target_t *dm_target_lookup_name(const char *);
43c9d0c62aShaad 
44c9d0c62aShaad TAILQ_HEAD(dm_target_head, dm_target);
45c9d0c62aShaad 
46c9d0c62aShaad static struct dm_target_head dm_target_list =
47c9d0c62aShaad TAILQ_HEAD_INITIALIZER(dm_target_list);
48c9d0c62aShaad 
496664a499Stkusumi static kmutex_t dm_target_mutex;
5078284dcaShaad 
5178284dcaShaad /*
5283723a32Syamt  * Called indirectly from dm_table_load_ioctl to mark target as used.
5378284dcaShaad  */
5478284dcaShaad void
dm_target_busy(dm_target_t * target)5578284dcaShaad dm_target_busy(dm_target_t *target)
5678284dcaShaad {
5746f14759Stkusumi 
5817599f37Shaad 	atomic_inc_32(&target->ref_cnt);
5978284dcaShaad }
60249cf593Schristos 
6117599f37Shaad /*
6217599f37Shaad  * Release reference counter on target.
6317599f37Shaad  */
6478284dcaShaad void
dm_target_unbusy(dm_target_t * target)6578284dcaShaad dm_target_unbusy(dm_target_t *target)
6678284dcaShaad {
6746f14759Stkusumi 
6817599f37Shaad 	KASSERT(target->ref_cnt > 0);
6917599f37Shaad 	atomic_dec_32(&target->ref_cnt);
7078284dcaShaad }
71249cf593Schristos 
7217599f37Shaad /*
7317599f37Shaad  * Try to autoload target module if it was not found in current
7417599f37Shaad  * target list.
7517599f37Shaad  */
7617599f37Shaad dm_target_t *
dm_target_autoload(const char * dm_target_name)7717599f37Shaad dm_target_autoload(const char *dm_target_name)
7817599f37Shaad {
79d624725aShaad 	char name[30];
80d2a47630Stkusumi 	unsigned int gen;
8117599f37Shaad 	dm_target_t *dmt;
8217599f37Shaad 
83d624725aShaad 	snprintf(name, sizeof(name), "dm_target_%s", dm_target_name);
84d624725aShaad 	name[29] = '\0';
85d624725aShaad 
8617599f37Shaad 	do {
8717599f37Shaad 		gen = module_gen;
8817599f37Shaad 
8917599f37Shaad 		/* Try to autoload target module */
90d9c59a05Stkusumi 		module_autoload(name, MODULE_CLASS_MISC);
9117599f37Shaad 	} while (gen != module_gen);
9217599f37Shaad 
9317599f37Shaad 	mutex_enter(&dm_target_mutex);
9417599f37Shaad 	dmt = dm_target_lookup_name(dm_target_name);
95e654dd3dShaad 	if (dmt != NULL)
9617599f37Shaad 		dm_target_busy(dmt);
97e654dd3dShaad 	mutex_exit(&dm_target_mutex);
9817599f37Shaad 
9917599f37Shaad 	return dmt;
10017599f37Shaad }
101249cf593Schristos 
10217599f37Shaad /*
10317599f37Shaad  * Lookup for target in global target list.
10417599f37Shaad  */
10578284dcaShaad dm_target_t *
dm_target_lookup(const char * dm_target_name)10678284dcaShaad dm_target_lookup(const char *dm_target_name)
10778284dcaShaad {
10878284dcaShaad 	dm_target_t *dmt;
10978284dcaShaad 
11017599f37Shaad 	if (dm_target_name == NULL)
11117599f37Shaad 		return NULL;
11217599f37Shaad 
11378284dcaShaad 	mutex_enter(&dm_target_mutex);
11478284dcaShaad 
11578284dcaShaad 	dmt = dm_target_lookup_name(dm_target_name);
11678284dcaShaad 	if (dmt != NULL)
11778284dcaShaad 		dm_target_busy(dmt);
11878284dcaShaad 
11978284dcaShaad 	mutex_exit(&dm_target_mutex);
12078284dcaShaad 
12178284dcaShaad 	return dmt;
12278284dcaShaad }
123249cf593Schristos 
124c9d0c62aShaad /*
125*a70f355bSandvar  * Search for name in TAIL and return appropriate pointer.
126c9d0c62aShaad  */
12778284dcaShaad static dm_target_t *
dm_target_lookup_name(const char * dm_target_name)128c9d0c62aShaad dm_target_lookup_name(const char *dm_target_name)
129c9d0c62aShaad {
130c9d0c62aShaad 	dm_target_t *dm_target;
131249cf593Schristos 	size_t dlen;
132249cf593Schristos 	size_t slen;
133c9d0c62aShaad 
134c9d0c62aShaad 	slen = strlen(dm_target_name) + 1;
135c9d0c62aShaad 
136c9d0c62aShaad 	TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) {
137c9d0c62aShaad 		dlen = strlen(dm_target->name) + 1;
138c9d0c62aShaad 		if (dlen != slen)
139c9d0c62aShaad 			continue;
140c9d0c62aShaad 
14117599f37Shaad 		if (strncmp(dm_target_name, dm_target->name, slen) == 0)
142c9d0c62aShaad 			return dm_target;
143c9d0c62aShaad 	}
144c9d0c62aShaad 
145c9d0c62aShaad 	return NULL;
146c9d0c62aShaad }
147249cf593Schristos 
148c9d0c62aShaad /*
149c9d0c62aShaad  * Insert new target struct into the TAIL.
150c9d0c62aShaad  * dm_target
151*a70f355bSandvar  *   contains name, version, function pointer to specific target functions.
152c9d0c62aShaad  */
153c9d0c62aShaad int
dm_target_insert(dm_target_t * dm_target)154c9d0c62aShaad dm_target_insert(dm_target_t *dm_target)
155c9d0c62aShaad {
156c9d0c62aShaad 	dm_target_t *dmt;
157c9d0c62aShaad 
1587cc36507Sahoka 	/* Sanity check for any missing function */
1599a83c98bStkusumi 	if (dm_target->init == NULL) {
1609a83c98bStkusumi 		printf("%s missing init\n", dm_target->name);
1619a83c98bStkusumi 		return EINVAL;
1629a83c98bStkusumi 	}
1639a83c98bStkusumi 	if (dm_target->strategy == NULL) {
1649a83c98bStkusumi 		printf("%s missing strategy\n", dm_target->name);
1659a83c98bStkusumi 		return EINVAL;
1669a83c98bStkusumi 	}
1679a83c98bStkusumi 	if (dm_target->destroy == NULL) {
1689a83c98bStkusumi 		printf("%s missing destroy\n", dm_target->name);
1699a83c98bStkusumi 		return EINVAL;
1709a83c98bStkusumi 	}
17167de4a93Stkusumi #if 0
1729a83c98bStkusumi 	if (dm_target->upcall == NULL) {
1739a83c98bStkusumi 		printf("%s missing upcall\n", dm_target->name);
1749a83c98bStkusumi 		return EINVAL;
1759a83c98bStkusumi 	}
17667de4a93Stkusumi #endif
1777cc36507Sahoka 
17878284dcaShaad 	mutex_enter(&dm_target_mutex);
179c9d0c62aShaad 
18078284dcaShaad 	dmt = dm_target_lookup_name(dm_target->name);
18178284dcaShaad 	if (dmt != NULL) {
18278284dcaShaad 		mutex_exit(&dm_target_mutex);
183c9d0c62aShaad 		return EEXIST;
18478284dcaShaad 	}
185c9d0c62aShaad 	TAILQ_INSERT_TAIL(&dm_target_list, dm_target, dm_target_next);
186c9d0c62aShaad 
18778284dcaShaad 	mutex_exit(&dm_target_mutex);
18878284dcaShaad 
189c9d0c62aShaad 	return 0;
190c9d0c62aShaad }
191c9d0c62aShaad 
192c9d0c62aShaad /*
193f0a7346dSsnj  * Remove target from TAIL, target is selected with its name.
194c9d0c62aShaad  */
195c9d0c62aShaad int
dm_target_rem(const char * dm_target_name)1961c486dc6Stkusumi dm_target_rem(const char *dm_target_name)
197c9d0c62aShaad {
19878284dcaShaad 	dm_target_t *dmt;
199c9d0c62aShaad 
200c9d0c62aShaad 	KASSERT(dm_target_name != NULL);
201c9d0c62aShaad 
20278284dcaShaad 	mutex_enter(&dm_target_mutex);
20378284dcaShaad 
20478284dcaShaad 	dmt = dm_target_lookup_name(dm_target_name);
20578284dcaShaad 	if (dmt == NULL) {
20678284dcaShaad 		mutex_exit(&dm_target_mutex);
207c9d0c62aShaad 		return ENOENT;
20878284dcaShaad 	}
20978284dcaShaad 	if (dmt->ref_cnt > 0) {
21078284dcaShaad 		mutex_exit(&dm_target_mutex);
21178284dcaShaad 		return EBUSY;
21278284dcaShaad 	}
2139dea6936Stkusumi 	TAILQ_REMOVE(&dm_target_list, dmt, dm_target_next);
214c9d0c62aShaad 
21578284dcaShaad 	mutex_exit(&dm_target_mutex);
21678284dcaShaad 
217d9c59a05Stkusumi 	kmem_free(dmt, sizeof(dm_target_t));
218c9d0c62aShaad 
219c9d0c62aShaad 	return 0;
220c9d0c62aShaad }
221249cf593Schristos 
222c9d0c62aShaad /*
223c9d0c62aShaad  * Destroy all targets and remove them from queue.
224c9d0c62aShaad  * This routine is called from dm_detach, before module
225c9d0c62aShaad  * is unloaded.
226c9d0c62aShaad  */
227c9d0c62aShaad int
dm_target_destroy(void)228c9d0c62aShaad dm_target_destroy(void)
229c9d0c62aShaad {
230c9d0c62aShaad 	dm_target_t *dm_target;
231c9d0c62aShaad 
23278284dcaShaad 	mutex_enter(&dm_target_mutex);
233c9d0c62aShaad 
234312beb09Stkusumi 	while ((dm_target = TAILQ_FIRST(&dm_target_list)) != NULL) {
235312beb09Stkusumi 		TAILQ_REMOVE(&dm_target_list, dm_target, dm_target_next);
236d9c59a05Stkusumi 		kmem_free(dm_target, sizeof(dm_target_t));
237c9d0c62aShaad 	}
238312beb09Stkusumi 	KASSERT(TAILQ_EMPTY(&dm_target_list));
239312beb09Stkusumi 
24078284dcaShaad 	mutex_exit(&dm_target_mutex);
241c9d0c62aShaad 
242cca8fb31Shaad 	mutex_destroy(&dm_target_mutex);
243ea24dc8dStkusumi #if 0
244ea24dc8dStkusumi 	/* Target specific module destroy routine. */
245ea24dc8dStkusumi 	dm_target_delay_pool_destroy();
246ea24dc8dStkusumi #endif
247c9d0c62aShaad 	return 0;
248c9d0c62aShaad }
249249cf593Schristos 
250c9d0c62aShaad /*
251c9d0c62aShaad  * Allocate new target entry.
252c9d0c62aShaad  */
253c9d0c62aShaad dm_target_t *
dm_target_alloc(const char * name)254c9d0c62aShaad dm_target_alloc(const char *name)
255c9d0c62aShaad {
256592bc735Stkusumi 	dm_target_t *dmt;
257592bc735Stkusumi 
258592bc735Stkusumi 	dmt = kmem_zalloc(sizeof(dm_target_t), KM_SLEEP);
259592bc735Stkusumi 	if (dmt == NULL)
260592bc735Stkusumi 		return NULL;
261592bc735Stkusumi 
262592bc735Stkusumi 	if (name)
263592bc735Stkusumi 		strlcpy(dmt->name, name, sizeof(dmt->name));
264592bc735Stkusumi 
265592bc735Stkusumi 	return dmt;
266c9d0c62aShaad }
267249cf593Schristos 
268c9d0c62aShaad /*
269c9d0c62aShaad  * Return prop_array of dm_target dictionaries.
270c9d0c62aShaad  */
271c9d0c62aShaad prop_array_t
dm_target_prop_list(void)272c9d0c62aShaad dm_target_prop_list(void)
273c9d0c62aShaad {
27446f14759Stkusumi 	prop_array_t target_array;
275c9d0c62aShaad 	dm_target_t *dm_target;
276c9d0c62aShaad 
277c9d0c62aShaad 	target_array = prop_array_create();
278c9d0c62aShaad 
27978284dcaShaad 	mutex_enter(&dm_target_mutex);
28078284dcaShaad 
281c9d0c62aShaad 	TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) {
28246f14759Stkusumi 		prop_array_t ver;
28346f14759Stkusumi 		prop_dictionary_t target_dict;
28446f14759Stkusumi 		int i;
28546f14759Stkusumi 
286c9d0c62aShaad 		target_dict = prop_dictionary_create();
287c9d0c62aShaad 		ver = prop_array_create();
288b5a91dc2Sthorpej 		prop_dictionary_set_string(target_dict, DM_TARGETS_NAME,
289c9d0c62aShaad 		    dm_target->name);
290c9d0c62aShaad 
291c9d0c62aShaad 		for (i = 0; i < 3; i++)
292c9d0c62aShaad 			prop_array_add_uint32(ver, dm_target->version[i]);
293c9d0c62aShaad 
294c9d0c62aShaad 		prop_dictionary_set(target_dict, DM_TARGETS_VERSION, ver);
295c9d0c62aShaad 		prop_array_add(target_array, target_dict);
296c9d0c62aShaad 
297c9d0c62aShaad 		prop_object_release(ver);
298c9d0c62aShaad 		prop_object_release(target_dict);
299c9d0c62aShaad 	}
300c9d0c62aShaad 
30178284dcaShaad 	mutex_exit(&dm_target_mutex);
30278284dcaShaad 
303c9d0c62aShaad 	return target_array;
304c9d0c62aShaad }
305249cf593Schristos 
30646f14759Stkusumi /*
30746f14759Stkusumi  * Initialize dm_target subsystem.
30846f14759Stkusumi  */
309c9d0c62aShaad int
dm_target_init(void)310c9d0c62aShaad dm_target_init(void)
311c9d0c62aShaad {
31284d45206Stkusumi 	dm_target_t *dmt;
313c9d0c62aShaad 
31478284dcaShaad 	mutex_init(&dm_target_mutex, MUTEX_DEFAULT, IPL_NONE);
31578284dcaShaad 
316c9d0c62aShaad 	dmt = dm_target_alloc("linear");
317c9d0c62aShaad 	dmt->version[0] = 1;
318c9d0c62aShaad 	dmt->version[1] = 0;
319c9d0c62aShaad 	dmt->version[2] = 2;
320c9d0c62aShaad 	dmt->init = &dm_target_linear_init;
3218026110eStkusumi 	dmt->table = &dm_target_linear_table;
322c9d0c62aShaad 	dmt->strategy = &dm_target_linear_strategy;
323fb8751abShaad 	dmt->sync = &dm_target_linear_sync;
324c9d0c62aShaad 	dmt->destroy = &dm_target_linear_destroy;
32567de4a93Stkusumi 	//dmt->upcall = &dm_target_linear_upcall;
32675268cffSmlelstv 	dmt->secsize = &dm_target_linear_secsize;
32784d45206Stkusumi 	if (dm_target_insert(dmt))
32884d45206Stkusumi 		printf("Failed to insert linear\n");
329c9d0c62aShaad 
33084d45206Stkusumi 	dmt = dm_target_alloc("striped");
33184d45206Stkusumi 	dmt->version[0] = 1;
33284d45206Stkusumi 	dmt->version[1] = 0;
33384d45206Stkusumi 	dmt->version[2] = 3;
33484d45206Stkusumi 	dmt->init = &dm_target_stripe_init;
335c2813277Stkusumi 	dmt->info = &dm_target_stripe_info;
33684d45206Stkusumi 	dmt->table = &dm_target_stripe_table;
33784d45206Stkusumi 	dmt->strategy = &dm_target_stripe_strategy;
33884d45206Stkusumi 	dmt->sync = &dm_target_stripe_sync;
33984d45206Stkusumi 	dmt->destroy = &dm_target_stripe_destroy;
34067de4a93Stkusumi 	//dmt->upcall = &dm_target_stripe_upcall;
34184d45206Stkusumi 	dmt->secsize = &dm_target_stripe_secsize;
34284d45206Stkusumi 	if (dm_target_insert(dmt))
34384d45206Stkusumi 		printf("Failed to insert striped\n");
344c9d0c62aShaad 
34584d45206Stkusumi 	dmt = dm_target_alloc("error");
34684d45206Stkusumi 	dmt->version[0] = 1;
34784d45206Stkusumi 	dmt->version[1] = 0;
34884d45206Stkusumi 	dmt->version[2] = 0;
34984d45206Stkusumi 	dmt->init = &dm_target_error_init;
35084d45206Stkusumi 	dmt->strategy = &dm_target_error_strategy;
35184d45206Stkusumi 	dmt->destroy = &dm_target_error_destroy;
35267de4a93Stkusumi 	//dmt->upcall = &dm_target_error_upcall;
35384d45206Stkusumi 	if (dm_target_insert(dmt))
35484d45206Stkusumi 		printf("Failed to insert error\n");
355c9d0c62aShaad 
35684d45206Stkusumi 	dmt = dm_target_alloc("zero");
35784d45206Stkusumi 	dmt->version[0] = 1;
35884d45206Stkusumi 	dmt->version[1] = 0;
35984d45206Stkusumi 	dmt->version[2] = 0;
36084d45206Stkusumi 	dmt->init = &dm_target_zero_init;
36184d45206Stkusumi 	dmt->strategy = &dm_target_zero_strategy;
36284d45206Stkusumi 	dmt->destroy = &dm_target_zero_destroy;
36367de4a93Stkusumi 	//dmt->upcall = &dm_target_zero_upcall;
36484d45206Stkusumi 	if (dm_target_insert(dmt))
36584d45206Stkusumi 		printf("Failed to insert zero\n");
3668dab45b6Stkusumi #if 0
367ea24dc8dStkusumi 	dmt = dm_target_alloc("delay");
368ea24dc8dStkusumi 	dmt->version[0] = 1;
369ea24dc8dStkusumi 	dmt->version[1] = 0;
370ea24dc8dStkusumi 	dmt->version[2] = 0;
371ea24dc8dStkusumi 	dmt->init = &dm_target_delay_init;
372ea24dc8dStkusumi 	dmt->info = &dm_target_delay_info;
373ea24dc8dStkusumi 	dmt->table = &dm_target_delay_table;
374ea24dc8dStkusumi 	dmt->strategy = &dm_target_delay_strategy;
375ea24dc8dStkusumi 	dmt->sync = &dm_target_delay_sync;
376ea24dc8dStkusumi 	dmt->destroy = &dm_target_delay_destroy;
37767de4a93Stkusumi 	//dmt->upcall = &dm_target_delay_upcall;
378ea24dc8dStkusumi 	dmt->secsize = &dm_target_delay_secsize;
379ea24dc8dStkusumi 	if (dm_target_insert(dmt))
380ea24dc8dStkusumi 		printf("Failed to insert delay\n");
381ea24dc8dStkusumi 	dm_target_delay_pool_create();
382ea24dc8dStkusumi 
3838dab45b6Stkusumi 	dmt = dm_target_alloc("flakey");
3848dab45b6Stkusumi 	dmt->version[0] = 1;
3858dab45b6Stkusumi 	dmt->version[1] = 0;
3868dab45b6Stkusumi 	dmt->version[2] = 0;
3878dab45b6Stkusumi 	dmt->init = &dm_target_flakey_init;
3888dab45b6Stkusumi 	dmt->table = &dm_target_flakey_table;
3898dab45b6Stkusumi 	dmt->strategy = &dm_target_flakey_strategy;
3908dab45b6Stkusumi 	dmt->sync = &dm_target_flakey_sync;
3918dab45b6Stkusumi 	dmt->destroy = &dm_target_flakey_destroy;
39267de4a93Stkusumi 	//dmt->upcall = &dm_target_flakey_upcall;
3938dab45b6Stkusumi 	dmt->secsize = &dm_target_flakey_secsize;
3948dab45b6Stkusumi 	if (dm_target_insert(dmt))
3958dab45b6Stkusumi 		printf("Failed to insert flakey\n");
3968dab45b6Stkusumi #endif
39784d45206Stkusumi 	return 0;
398c9d0c62aShaad }
399