1/* $NetBSD: dm_target.c,v 1.42 2021/08/21 22:23:33 andvar 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#include <sys/cdefs.h> 32__KERNEL_RCSID(0, "$NetBSD: dm_target.c,v 1.42 2021/08/21 22:23:33 andvar Exp $"); 33 34#include <sys/types.h> 35#include <sys/param.h> 36#include <sys/kmem.h> 37#include <sys/module.h> 38 39#include "netbsd-dm.h" 40#include "dm.h" 41 42static dm_target_t *dm_target_lookup_name(const char *); 43 44TAILQ_HEAD(dm_target_head, dm_target); 45 46static struct dm_target_head dm_target_list = 47TAILQ_HEAD_INITIALIZER(dm_target_list); 48 49static kmutex_t dm_target_mutex; 50 51/* 52 * Called indirectly from dm_table_load_ioctl to mark target as used. 53 */ 54void 55dm_target_busy(dm_target_t *target) 56{ 57 58 atomic_inc_32(&target->ref_cnt); 59} 60 61/* 62 * Release reference counter on target. 63 */ 64void 65dm_target_unbusy(dm_target_t *target) 66{ 67 68 KASSERT(target->ref_cnt > 0); 69 atomic_dec_32(&target->ref_cnt); 70} 71 72/* 73 * Try to autoload target module if it was not found in current 74 * target list. 75 */ 76dm_target_t * 77dm_target_autoload(const char *dm_target_name) 78{ 79 char name[30]; 80 unsigned int gen; 81 dm_target_t *dmt; 82 83 snprintf(name, sizeof(name), "dm_target_%s", dm_target_name); 84 name[29] = '\0'; 85 86 do { 87 gen = module_gen; 88 89 /* Try to autoload target module */ 90 module_autoload(name, MODULE_CLASS_MISC); 91 } while (gen != module_gen); 92 93 mutex_enter(&dm_target_mutex); 94 dmt = dm_target_lookup_name(dm_target_name); 95 if (dmt != NULL) 96 dm_target_busy(dmt); 97 mutex_exit(&dm_target_mutex); 98 99 return dmt; 100} 101 102/* 103 * Lookup for target in global target list. 104 */ 105dm_target_t * 106dm_target_lookup(const char *dm_target_name) 107{ 108 dm_target_t *dmt; 109 110 if (dm_target_name == NULL) 111 return NULL; 112 113 mutex_enter(&dm_target_mutex); 114 115 dmt = dm_target_lookup_name(dm_target_name); 116 if (dmt != NULL) 117 dm_target_busy(dmt); 118 119 mutex_exit(&dm_target_mutex); 120 121 return dmt; 122} 123 124/* 125 * Search for name in TAIL and return appropriate pointer. 126 */ 127static dm_target_t * 128dm_target_lookup_name(const char *dm_target_name) 129{ 130 dm_target_t *dm_target; 131 size_t dlen; 132 size_t slen; 133 134 slen = strlen(dm_target_name) + 1; 135 136 TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 137 dlen = strlen(dm_target->name) + 1; 138 if (dlen != slen) 139 continue; 140 141 if (strncmp(dm_target_name, dm_target->name, slen) == 0) 142 return dm_target; 143 } 144 145 return NULL; 146} 147 148/* 149 * Insert new target struct into the TAIL. 150 * dm_target 151 * contains name, version, function pointer to specific target functions. 152 */ 153int 154dm_target_insert(dm_target_t *dm_target) 155{ 156 dm_target_t *dmt; 157 158 /* Sanity check for any missing function */ 159 if (dm_target->init == NULL) { 160 printf("%s missing init\n", dm_target->name); 161 return EINVAL; 162 } 163 if (dm_target->strategy == NULL) { 164 printf("%s missing strategy\n", dm_target->name); 165 return EINVAL; 166 } 167 if (dm_target->destroy == NULL) { 168 printf("%s missing destroy\n", dm_target->name); 169 return EINVAL; 170 } 171#if 0 172 if (dm_target->upcall == NULL) { 173 printf("%s missing upcall\n", dm_target->name); 174 return EINVAL; 175 } 176#endif 177 178 mutex_enter(&dm_target_mutex); 179 180 dmt = dm_target_lookup_name(dm_target->name); 181 if (dmt != NULL) { 182 mutex_exit(&dm_target_mutex); 183 return EEXIST; 184 } 185 TAILQ_INSERT_TAIL(&dm_target_list, dm_target, dm_target_next); 186 187 mutex_exit(&dm_target_mutex); 188 189 return 0; 190} 191 192/* 193 * Remove target from TAIL, target is selected with its name. 194 */ 195int 196dm_target_rem(const char *dm_target_name) 197{ 198 dm_target_t *dmt; 199 200 KASSERT(dm_target_name != NULL); 201 202 mutex_enter(&dm_target_mutex); 203 204 dmt = dm_target_lookup_name(dm_target_name); 205 if (dmt == NULL) { 206 mutex_exit(&dm_target_mutex); 207 return ENOENT; 208 } 209 if (dmt->ref_cnt > 0) { 210 mutex_exit(&dm_target_mutex); 211 return EBUSY; 212 } 213 TAILQ_REMOVE(&dm_target_list, dmt, dm_target_next); 214 215 mutex_exit(&dm_target_mutex); 216 217 kmem_free(dmt, sizeof(dm_target_t)); 218 219 return 0; 220} 221 222/* 223 * Destroy all targets and remove them from queue. 224 * This routine is called from dm_detach, before module 225 * is unloaded. 226 */ 227int 228dm_target_destroy(void) 229{ 230 dm_target_t *dm_target; 231 232 mutex_enter(&dm_target_mutex); 233 234 while ((dm_target = TAILQ_FIRST(&dm_target_list)) != NULL) { 235 TAILQ_REMOVE(&dm_target_list, dm_target, dm_target_next); 236 kmem_free(dm_target, sizeof(dm_target_t)); 237 } 238 KASSERT(TAILQ_EMPTY(&dm_target_list)); 239 240 mutex_exit(&dm_target_mutex); 241 242 mutex_destroy(&dm_target_mutex); 243#if 0 244 /* Target specific module destroy routine. */ 245 dm_target_delay_pool_destroy(); 246#endif 247 return 0; 248} 249 250/* 251 * Allocate new target entry. 252 */ 253dm_target_t * 254dm_target_alloc(const char *name) 255{ 256 dm_target_t *dmt; 257 258 dmt = kmem_zalloc(sizeof(dm_target_t), KM_SLEEP); 259 if (dmt == NULL) 260 return NULL; 261 262 if (name) 263 strlcpy(dmt->name, name, sizeof(dmt->name)); 264 265 return dmt; 266} 267 268/* 269 * Return prop_array of dm_target dictionaries. 270 */ 271prop_array_t 272dm_target_prop_list(void) 273{ 274 prop_array_t target_array; 275 dm_target_t *dm_target; 276 277 target_array = prop_array_create(); 278 279 mutex_enter(&dm_target_mutex); 280 281 TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 282 prop_array_t ver; 283 prop_dictionary_t target_dict; 284 int i; 285 286 target_dict = prop_dictionary_create(); 287 ver = prop_array_create(); 288 prop_dictionary_set_string(target_dict, DM_TARGETS_NAME, 289 dm_target->name); 290 291 for (i = 0; i < 3; i++) 292 prop_array_add_uint32(ver, dm_target->version[i]); 293 294 prop_dictionary_set(target_dict, DM_TARGETS_VERSION, ver); 295 prop_array_add(target_array, target_dict); 296 297 prop_object_release(ver); 298 prop_object_release(target_dict); 299 } 300 301 mutex_exit(&dm_target_mutex); 302 303 return target_array; 304} 305 306/* 307 * Initialize dm_target subsystem. 308 */ 309int 310dm_target_init(void) 311{ 312 dm_target_t *dmt; 313 314 mutex_init(&dm_target_mutex, MUTEX_DEFAULT, IPL_NONE); 315 316 dmt = dm_target_alloc("linear"); 317 dmt->version[0] = 1; 318 dmt->version[1] = 0; 319 dmt->version[2] = 2; 320 dmt->init = &dm_target_linear_init; 321 dmt->table = &dm_target_linear_table; 322 dmt->strategy = &dm_target_linear_strategy; 323 dmt->sync = &dm_target_linear_sync; 324 dmt->destroy = &dm_target_linear_destroy; 325 //dmt->upcall = &dm_target_linear_upcall; 326 dmt->secsize = &dm_target_linear_secsize; 327 if (dm_target_insert(dmt)) 328 printf("Failed to insert linear\n"); 329 330 dmt = dm_target_alloc("striped"); 331 dmt->version[0] = 1; 332 dmt->version[1] = 0; 333 dmt->version[2] = 3; 334 dmt->init = &dm_target_stripe_init; 335 dmt->info = &dm_target_stripe_info; 336 dmt->table = &dm_target_stripe_table; 337 dmt->strategy = &dm_target_stripe_strategy; 338 dmt->sync = &dm_target_stripe_sync; 339 dmt->destroy = &dm_target_stripe_destroy; 340 //dmt->upcall = &dm_target_stripe_upcall; 341 dmt->secsize = &dm_target_stripe_secsize; 342 if (dm_target_insert(dmt)) 343 printf("Failed to insert striped\n"); 344 345 dmt = dm_target_alloc("error"); 346 dmt->version[0] = 1; 347 dmt->version[1] = 0; 348 dmt->version[2] = 0; 349 dmt->init = &dm_target_error_init; 350 dmt->strategy = &dm_target_error_strategy; 351 dmt->destroy = &dm_target_error_destroy; 352 //dmt->upcall = &dm_target_error_upcall; 353 if (dm_target_insert(dmt)) 354 printf("Failed to insert error\n"); 355 356 dmt = dm_target_alloc("zero"); 357 dmt->version[0] = 1; 358 dmt->version[1] = 0; 359 dmt->version[2] = 0; 360 dmt->init = &dm_target_zero_init; 361 dmt->strategy = &dm_target_zero_strategy; 362 dmt->destroy = &dm_target_zero_destroy; 363 //dmt->upcall = &dm_target_zero_upcall; 364 if (dm_target_insert(dmt)) 365 printf("Failed to insert zero\n"); 366#if 0 367 dmt = dm_target_alloc("delay"); 368 dmt->version[0] = 1; 369 dmt->version[1] = 0; 370 dmt->version[2] = 0; 371 dmt->init = &dm_target_delay_init; 372 dmt->info = &dm_target_delay_info; 373 dmt->table = &dm_target_delay_table; 374 dmt->strategy = &dm_target_delay_strategy; 375 dmt->sync = &dm_target_delay_sync; 376 dmt->destroy = &dm_target_delay_destroy; 377 //dmt->upcall = &dm_target_delay_upcall; 378 dmt->secsize = &dm_target_delay_secsize; 379 if (dm_target_insert(dmt)) 380 printf("Failed to insert delay\n"); 381 dm_target_delay_pool_create(); 382 383 dmt = dm_target_alloc("flakey"); 384 dmt->version[0] = 1; 385 dmt->version[1] = 0; 386 dmt->version[2] = 0; 387 dmt->init = &dm_target_flakey_init; 388 dmt->table = &dm_target_flakey_table; 389 dmt->strategy = &dm_target_flakey_strategy; 390 dmt->sync = &dm_target_flakey_sync; 391 dmt->destroy = &dm_target_flakey_destroy; 392 //dmt->upcall = &dm_target_flakey_upcall; 393 dmt->secsize = &dm_target_flakey_secsize; 394 if (dm_target_insert(dmt)) 395 printf("Failed to insert flakey\n"); 396#endif 397 return 0; 398} 399