1 1.42 andvar /* $NetBSD: dm_target.c,v 1.42 2021/08/21 22:23:33 andvar Exp $ */ 2 1.2 haad 3 1.2 haad /* 4 1.2 haad * Copyright (c) 2008 The NetBSD Foundation, Inc. 5 1.2 haad * All rights reserved. 6 1.2 haad * 7 1.2 haad * This code is derived from software contributed to The NetBSD Foundation 8 1.2 haad * by Adam Hamsik. 9 1.2 haad * 10 1.2 haad * Redistribution and use in source and binary forms, with or without 11 1.2 haad * modification, are permitted provided that the following conditions 12 1.2 haad * are met: 13 1.2 haad * 1. Redistributions of source code Must retain the above copyright 14 1.2 haad * notice, this list of conditions and the following disclaimer. 15 1.2 haad * 2. Redistributions in binary form must reproduce the above copyright 16 1.2 haad * notice, this list of conditions and the following disclaimer in the 17 1.2 haad * documentation and/or other materials provided with the distribution. 18 1.2 haad * 19 1.2 haad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.2 haad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.2 haad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.2 haad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.2 haad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.2 haad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.2 haad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.2 haad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.2 haad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.2 haad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.2 haad * POSSIBILITY OF SUCH DAMAGE. 30 1.2 haad */ 31 1.20 christos #include <sys/cdefs.h> 32 1.42 andvar __KERNEL_RCSID(0, "$NetBSD: dm_target.c,v 1.42 2021/08/21 22:23:33 andvar Exp $"); 33 1.2 haad 34 1.2 haad #include <sys/types.h> 35 1.2 haad #include <sys/param.h> 36 1.2 haad #include <sys/kmem.h> 37 1.7 haad #include <sys/module.h> 38 1.7 haad 39 1.2 haad #include "netbsd-dm.h" 40 1.2 haad #include "dm.h" 41 1.2 haad 42 1.12 haad static dm_target_t *dm_target_lookup_name(const char *); 43 1.2 haad 44 1.2 haad TAILQ_HEAD(dm_target_head, dm_target); 45 1.2 haad 46 1.2 haad static struct dm_target_head dm_target_list = 47 1.2 haad TAILQ_HEAD_INITIALIZER(dm_target_list); 48 1.2 haad 49 1.21 tkusumi static kmutex_t dm_target_mutex; 50 1.3 haad 51 1.3 haad /* 52 1.10 yamt * Called indirectly from dm_table_load_ioctl to mark target as used. 53 1.3 haad */ 54 1.3 haad void 55 1.25 tkusumi dm_target_busy(dm_target_t *target) 56 1.3 haad { 57 1.32 tkusumi 58 1.7 haad atomic_inc_32(&target->ref_cnt); 59 1.3 haad } 60 1.20 christos 61 1.7 haad /* 62 1.7 haad * Release reference counter on target. 63 1.7 haad */ 64 1.3 haad void 65 1.25 tkusumi dm_target_unbusy(dm_target_t *target) 66 1.3 haad { 67 1.32 tkusumi 68 1.7 haad KASSERT(target->ref_cnt > 0); 69 1.7 haad atomic_dec_32(&target->ref_cnt); 70 1.3 haad } 71 1.20 christos 72 1.7 haad /* 73 1.7 haad * Try to autoload target module if it was not found in current 74 1.7 haad * target list. 75 1.7 haad */ 76 1.7 haad dm_target_t * 77 1.7 haad dm_target_autoload(const char *dm_target_name) 78 1.7 haad { 79 1.8 haad char name[30]; 80 1.34 tkusumi unsigned int gen; 81 1.7 haad dm_target_t *dmt; 82 1.7 haad 83 1.8 haad snprintf(name, sizeof(name), "dm_target_%s", dm_target_name); 84 1.12 haad name[29] = '\0'; 85 1.12 haad 86 1.7 haad do { 87 1.7 haad gen = module_gen; 88 1.12 haad 89 1.7 haad /* Try to autoload target module */ 90 1.28 tkusumi module_autoload(name, MODULE_CLASS_MISC); 91 1.12 haad } while (gen != module_gen); 92 1.7 haad 93 1.7 haad mutex_enter(&dm_target_mutex); 94 1.7 haad dmt = dm_target_lookup_name(dm_target_name); 95 1.9 haad if (dmt != NULL) 96 1.9 haad dm_target_busy(dmt); 97 1.7 haad mutex_exit(&dm_target_mutex); 98 1.12 haad 99 1.7 haad return dmt; 100 1.7 haad } 101 1.20 christos 102 1.7 haad /* 103 1.7 haad * Lookup for target in global target list. 104 1.7 haad */ 105 1.3 haad dm_target_t * 106 1.3 haad dm_target_lookup(const char *dm_target_name) 107 1.3 haad { 108 1.3 haad dm_target_t *dmt; 109 1.3 haad 110 1.7 haad if (dm_target_name == NULL) 111 1.7 haad return NULL; 112 1.7 haad 113 1.3 haad mutex_enter(&dm_target_mutex); 114 1.3 haad 115 1.7 haad dmt = dm_target_lookup_name(dm_target_name); 116 1.3 haad if (dmt != NULL) 117 1.3 haad dm_target_busy(dmt); 118 1.12 haad 119 1.3 haad mutex_exit(&dm_target_mutex); 120 1.12 haad 121 1.12 haad return dmt; 122 1.3 haad } 123 1.20 christos 124 1.2 haad /* 125 1.42 andvar * Search for name in TAIL and return appropriate pointer. 126 1.2 haad */ 127 1.12 haad static dm_target_t * 128 1.2 haad dm_target_lookup_name(const char *dm_target_name) 129 1.2 haad { 130 1.2 haad dm_target_t *dm_target; 131 1.20 christos size_t dlen; 132 1.20 christos size_t slen; 133 1.2 haad 134 1.3 haad slen = strlen(dm_target_name) + 1; 135 1.2 haad 136 1.3 haad TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 137 1.3 haad dlen = strlen(dm_target->name) + 1; 138 1.2 haad if (dlen != slen) 139 1.2 haad continue; 140 1.12 haad 141 1.7 haad if (strncmp(dm_target_name, dm_target->name, slen) == 0) 142 1.3 haad return dm_target; 143 1.2 haad } 144 1.2 haad 145 1.2 haad return NULL; 146 1.2 haad } 147 1.20 christos 148 1.2 haad /* 149 1.2 haad * Insert new target struct into the TAIL. 150 1.2 haad * dm_target 151 1.42 andvar * contains name, version, function pointer to specific target functions. 152 1.2 haad */ 153 1.2 haad int 154 1.25 tkusumi dm_target_insert(dm_target_t *dm_target) 155 1.2 haad { 156 1.2 haad dm_target_t *dmt; 157 1.12 haad 158 1.18 ahoka /* Sanity check for any missing function */ 159 1.27 tkusumi if (dm_target->init == NULL) { 160 1.27 tkusumi printf("%s missing init\n", dm_target->name); 161 1.27 tkusumi return EINVAL; 162 1.27 tkusumi } 163 1.27 tkusumi if (dm_target->strategy == NULL) { 164 1.27 tkusumi printf("%s missing strategy\n", dm_target->name); 165 1.27 tkusumi return EINVAL; 166 1.27 tkusumi } 167 1.27 tkusumi if (dm_target->destroy == NULL) { 168 1.27 tkusumi printf("%s missing destroy\n", dm_target->name); 169 1.27 tkusumi return EINVAL; 170 1.27 tkusumi } 171 1.40 tkusumi #if 0 172 1.27 tkusumi if (dm_target->upcall == NULL) { 173 1.27 tkusumi printf("%s missing upcall\n", dm_target->name); 174 1.27 tkusumi return EINVAL; 175 1.27 tkusumi } 176 1.40 tkusumi #endif 177 1.18 ahoka 178 1.3 haad mutex_enter(&dm_target_mutex); 179 1.2 haad 180 1.2 haad dmt = dm_target_lookup_name(dm_target->name); 181 1.3 haad if (dmt != NULL) { 182 1.3 haad mutex_exit(&dm_target_mutex); 183 1.2 haad return EEXIST; 184 1.3 haad } 185 1.2 haad TAILQ_INSERT_TAIL(&dm_target_list, dm_target, dm_target_next); 186 1.3 haad 187 1.3 haad mutex_exit(&dm_target_mutex); 188 1.12 haad 189 1.2 haad return 0; 190 1.2 haad } 191 1.2 haad 192 1.2 haad /* 193 1.19 snj * Remove target from TAIL, target is selected with its name. 194 1.2 haad */ 195 1.2 haad int 196 1.26 tkusumi dm_target_rem(const char *dm_target_name) 197 1.2 haad { 198 1.3 haad dm_target_t *dmt; 199 1.12 haad 200 1.2 haad KASSERT(dm_target_name != NULL); 201 1.3 haad 202 1.3 haad mutex_enter(&dm_target_mutex); 203 1.12 haad 204 1.3 haad dmt = dm_target_lookup_name(dm_target_name); 205 1.3 haad if (dmt == NULL) { 206 1.3 haad mutex_exit(&dm_target_mutex); 207 1.2 haad return ENOENT; 208 1.3 haad } 209 1.3 haad if (dmt->ref_cnt > 0) { 210 1.3 haad mutex_exit(&dm_target_mutex); 211 1.3 haad return EBUSY; 212 1.3 haad } 213 1.22 tkusumi TAILQ_REMOVE(&dm_target_list, dmt, dm_target_next); 214 1.3 haad 215 1.3 haad mutex_exit(&dm_target_mutex); 216 1.12 haad 217 1.28 tkusumi kmem_free(dmt, sizeof(dm_target_t)); 218 1.2 haad 219 1.2 haad return 0; 220 1.2 haad } 221 1.20 christos 222 1.2 haad /* 223 1.2 haad * Destroy all targets and remove them from queue. 224 1.2 haad * This routine is called from dm_detach, before module 225 1.2 haad * is unloaded. 226 1.2 haad */ 227 1.2 haad int 228 1.2 haad dm_target_destroy(void) 229 1.2 haad { 230 1.2 haad dm_target_t *dm_target; 231 1.2 haad 232 1.3 haad mutex_enter(&dm_target_mutex); 233 1.12 haad 234 1.24 tkusumi while ((dm_target = TAILQ_FIRST(&dm_target_list)) != NULL) { 235 1.24 tkusumi TAILQ_REMOVE(&dm_target_list, dm_target, dm_target_next); 236 1.28 tkusumi kmem_free(dm_target, sizeof(dm_target_t)); 237 1.2 haad } 238 1.24 tkusumi KASSERT(TAILQ_EMPTY(&dm_target_list)); 239 1.24 tkusumi 240 1.3 haad mutex_exit(&dm_target_mutex); 241 1.12 haad 242 1.4 haad mutex_destroy(&dm_target_mutex); 243 1.39 tkusumi #if 0 244 1.39 tkusumi /* Target specific module destroy routine. */ 245 1.39 tkusumi dm_target_delay_pool_destroy(); 246 1.39 tkusumi #endif 247 1.2 haad return 0; 248 1.2 haad } 249 1.20 christos 250 1.2 haad /* 251 1.2 haad * Allocate new target entry. 252 1.2 haad */ 253 1.12 haad dm_target_t * 254 1.2 haad dm_target_alloc(const char *name) 255 1.2 haad { 256 1.23 tkusumi dm_target_t *dmt; 257 1.23 tkusumi 258 1.23 tkusumi dmt = kmem_zalloc(sizeof(dm_target_t), KM_SLEEP); 259 1.23 tkusumi if (dmt == NULL) 260 1.23 tkusumi return NULL; 261 1.23 tkusumi 262 1.23 tkusumi if (name) 263 1.23 tkusumi strlcpy(dmt->name, name, sizeof(dmt->name)); 264 1.23 tkusumi 265 1.23 tkusumi return dmt; 266 1.2 haad } 267 1.20 christos 268 1.2 haad /* 269 1.2 haad * Return prop_array of dm_target dictionaries. 270 1.2 haad */ 271 1.2 haad prop_array_t 272 1.2 haad dm_target_prop_list(void) 273 1.2 haad { 274 1.32 tkusumi prop_array_t target_array; 275 1.2 haad dm_target_t *dm_target; 276 1.2 haad 277 1.2 haad target_array = prop_array_create(); 278 1.3 haad 279 1.3 haad mutex_enter(&dm_target_mutex); 280 1.2 haad 281 1.12 haad TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 282 1.32 tkusumi prop_array_t ver; 283 1.32 tkusumi prop_dictionary_t target_dict; 284 1.32 tkusumi int i; 285 1.32 tkusumi 286 1.12 haad target_dict = prop_dictionary_create(); 287 1.2 haad ver = prop_array_create(); 288 1.41 thorpej prop_dictionary_set_string(target_dict, DM_TARGETS_NAME, 289 1.2 haad dm_target->name); 290 1.2 haad 291 1.2 haad for (i = 0; i < 3; i++) 292 1.2 haad prop_array_add_uint32(ver, dm_target->version[i]); 293 1.2 haad 294 1.2 haad prop_dictionary_set(target_dict, DM_TARGETS_VERSION, ver); 295 1.2 haad prop_array_add(target_array, target_dict); 296 1.2 haad 297 1.2 haad prop_object_release(ver); 298 1.2 haad prop_object_release(target_dict); 299 1.2 haad } 300 1.2 haad 301 1.3 haad mutex_exit(&dm_target_mutex); 302 1.12 haad 303 1.2 haad return target_array; 304 1.2 haad } 305 1.20 christos 306 1.32 tkusumi /* 307 1.32 tkusumi * Initialize dm_target subsystem. 308 1.32 tkusumi */ 309 1.2 haad int 310 1.2 haad dm_target_init(void) 311 1.2 haad { 312 1.33 tkusumi dm_target_t *dmt; 313 1.2 haad 314 1.3 haad mutex_init(&dm_target_mutex, MUTEX_DEFAULT, IPL_NONE); 315 1.12 haad 316 1.2 haad dmt = dm_target_alloc("linear"); 317 1.2 haad dmt->version[0] = 1; 318 1.2 haad dmt->version[1] = 0; 319 1.2 haad dmt->version[2] = 2; 320 1.2 haad dmt->init = &dm_target_linear_init; 321 1.29 tkusumi dmt->table = &dm_target_linear_table; 322 1.2 haad dmt->strategy = &dm_target_linear_strategy; 323 1.13 haad dmt->sync = &dm_target_linear_sync; 324 1.2 haad dmt->destroy = &dm_target_linear_destroy; 325 1.40 tkusumi //dmt->upcall = &dm_target_linear_upcall; 326 1.15 mlelstv dmt->secsize = &dm_target_linear_secsize; 327 1.33 tkusumi if (dm_target_insert(dmt)) 328 1.33 tkusumi printf("Failed to insert linear\n"); 329 1.12 haad 330 1.33 tkusumi dmt = dm_target_alloc("striped"); 331 1.33 tkusumi dmt->version[0] = 1; 332 1.33 tkusumi dmt->version[1] = 0; 333 1.33 tkusumi dmt->version[2] = 3; 334 1.33 tkusumi dmt->init = &dm_target_stripe_init; 335 1.36 tkusumi dmt->info = &dm_target_stripe_info; 336 1.33 tkusumi dmt->table = &dm_target_stripe_table; 337 1.33 tkusumi dmt->strategy = &dm_target_stripe_strategy; 338 1.33 tkusumi dmt->sync = &dm_target_stripe_sync; 339 1.33 tkusumi dmt->destroy = &dm_target_stripe_destroy; 340 1.40 tkusumi //dmt->upcall = &dm_target_stripe_upcall; 341 1.33 tkusumi dmt->secsize = &dm_target_stripe_secsize; 342 1.33 tkusumi if (dm_target_insert(dmt)) 343 1.33 tkusumi printf("Failed to insert striped\n"); 344 1.12 haad 345 1.33 tkusumi dmt = dm_target_alloc("error"); 346 1.33 tkusumi dmt->version[0] = 1; 347 1.33 tkusumi dmt->version[1] = 0; 348 1.33 tkusumi dmt->version[2] = 0; 349 1.33 tkusumi dmt->init = &dm_target_error_init; 350 1.33 tkusumi dmt->strategy = &dm_target_error_strategy; 351 1.33 tkusumi dmt->destroy = &dm_target_error_destroy; 352 1.40 tkusumi //dmt->upcall = &dm_target_error_upcall; 353 1.33 tkusumi if (dm_target_insert(dmt)) 354 1.33 tkusumi printf("Failed to insert error\n"); 355 1.12 haad 356 1.33 tkusumi dmt = dm_target_alloc("zero"); 357 1.33 tkusumi dmt->version[0] = 1; 358 1.33 tkusumi dmt->version[1] = 0; 359 1.33 tkusumi dmt->version[2] = 0; 360 1.33 tkusumi dmt->init = &dm_target_zero_init; 361 1.33 tkusumi dmt->strategy = &dm_target_zero_strategy; 362 1.33 tkusumi dmt->destroy = &dm_target_zero_destroy; 363 1.40 tkusumi //dmt->upcall = &dm_target_zero_upcall; 364 1.33 tkusumi if (dm_target_insert(dmt)) 365 1.33 tkusumi printf("Failed to insert zero\n"); 366 1.38 tkusumi #if 0 367 1.39 tkusumi dmt = dm_target_alloc("delay"); 368 1.39 tkusumi dmt->version[0] = 1; 369 1.39 tkusumi dmt->version[1] = 0; 370 1.39 tkusumi dmt->version[2] = 0; 371 1.39 tkusumi dmt->init = &dm_target_delay_init; 372 1.39 tkusumi dmt->info = &dm_target_delay_info; 373 1.39 tkusumi dmt->table = &dm_target_delay_table; 374 1.39 tkusumi dmt->strategy = &dm_target_delay_strategy; 375 1.39 tkusumi dmt->sync = &dm_target_delay_sync; 376 1.39 tkusumi dmt->destroy = &dm_target_delay_destroy; 377 1.40 tkusumi //dmt->upcall = &dm_target_delay_upcall; 378 1.39 tkusumi dmt->secsize = &dm_target_delay_secsize; 379 1.39 tkusumi if (dm_target_insert(dmt)) 380 1.39 tkusumi printf("Failed to insert delay\n"); 381 1.39 tkusumi dm_target_delay_pool_create(); 382 1.39 tkusumi 383 1.38 tkusumi dmt = dm_target_alloc("flakey"); 384 1.38 tkusumi dmt->version[0] = 1; 385 1.38 tkusumi dmt->version[1] = 0; 386 1.38 tkusumi dmt->version[2] = 0; 387 1.38 tkusumi dmt->init = &dm_target_flakey_init; 388 1.38 tkusumi dmt->table = &dm_target_flakey_table; 389 1.38 tkusumi dmt->strategy = &dm_target_flakey_strategy; 390 1.38 tkusumi dmt->sync = &dm_target_flakey_sync; 391 1.38 tkusumi dmt->destroy = &dm_target_flakey_destroy; 392 1.40 tkusumi //dmt->upcall = &dm_target_flakey_upcall; 393 1.38 tkusumi dmt->secsize = &dm_target_flakey_secsize; 394 1.38 tkusumi if (dm_target_insert(dmt)) 395 1.38 tkusumi printf("Failed to insert flakey\n"); 396 1.38 tkusumi #endif 397 1.33 tkusumi return 0; 398 1.2 haad } 399