1 /* $NetBSD: dm_target.c,v 1.37 2019/12/23 16:17:35 tkusumi 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.37 2019/12/23 16:17:35 tkusumi 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 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 static kmutex_t dm_target_mutex; 50 51 /* 52 * Called indirectly from dm_table_load_ioctl to mark target as used. 53 */ 54 void 55 dm_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 */ 64 void 65 dm_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 */ 76 dm_target_t * 77 dm_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 */ 105 dm_target_t * 106 dm_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 apropriate pointer. 126 */ 127 static dm_target_t * 128 dm_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 specifif target functions. 152 */ 153 int 154 dm_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 (dm_target->upcall == NULL) { 172 printf("%s missing upcall\n", dm_target->name); 173 return EINVAL; 174 } 175 176 mutex_enter(&dm_target_mutex); 177 178 dmt = dm_target_lookup_name(dm_target->name); 179 if (dmt != NULL) { 180 mutex_exit(&dm_target_mutex); 181 return EEXIST; 182 } 183 TAILQ_INSERT_TAIL(&dm_target_list, dm_target, dm_target_next); 184 185 mutex_exit(&dm_target_mutex); 186 187 return 0; 188 } 189 190 /* 191 * Remove target from TAIL, target is selected with its name. 192 */ 193 int 194 dm_target_rem(const char *dm_target_name) 195 { 196 dm_target_t *dmt; 197 198 KASSERT(dm_target_name != NULL); 199 200 mutex_enter(&dm_target_mutex); 201 202 dmt = dm_target_lookup_name(dm_target_name); 203 if (dmt == NULL) { 204 mutex_exit(&dm_target_mutex); 205 return ENOENT; 206 } 207 if (dmt->ref_cnt > 0) { 208 mutex_exit(&dm_target_mutex); 209 return EBUSY; 210 } 211 TAILQ_REMOVE(&dm_target_list, dmt, dm_target_next); 212 213 mutex_exit(&dm_target_mutex); 214 215 kmem_free(dmt, sizeof(dm_target_t)); 216 217 return 0; 218 } 219 220 /* 221 * Destroy all targets and remove them from queue. 222 * This routine is called from dm_detach, before module 223 * is unloaded. 224 */ 225 int 226 dm_target_destroy(void) 227 { 228 dm_target_t *dm_target; 229 230 mutex_enter(&dm_target_mutex); 231 232 while ((dm_target = TAILQ_FIRST(&dm_target_list)) != NULL) { 233 TAILQ_REMOVE(&dm_target_list, dm_target, dm_target_next); 234 kmem_free(dm_target, sizeof(dm_target_t)); 235 } 236 KASSERT(TAILQ_EMPTY(&dm_target_list)); 237 238 mutex_exit(&dm_target_mutex); 239 240 mutex_destroy(&dm_target_mutex); 241 242 return 0; 243 } 244 245 /* 246 * Allocate new target entry. 247 */ 248 dm_target_t * 249 dm_target_alloc(const char *name) 250 { 251 dm_target_t *dmt; 252 253 dmt = kmem_zalloc(sizeof(dm_target_t), KM_SLEEP); 254 if (dmt == NULL) 255 return NULL; 256 257 if (name) 258 strlcpy(dmt->name, name, sizeof(dmt->name)); 259 260 return dmt; 261 } 262 263 /* 264 * Return prop_array of dm_target dictionaries. 265 */ 266 prop_array_t 267 dm_target_prop_list(void) 268 { 269 prop_array_t target_array; 270 dm_target_t *dm_target; 271 272 target_array = prop_array_create(); 273 274 mutex_enter(&dm_target_mutex); 275 276 TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 277 prop_array_t ver; 278 prop_dictionary_t target_dict; 279 int i; 280 281 target_dict = prop_dictionary_create(); 282 ver = prop_array_create(); 283 prop_dictionary_set_cstring(target_dict, DM_TARGETS_NAME, 284 dm_target->name); 285 286 for (i = 0; i < 3; i++) 287 prop_array_add_uint32(ver, dm_target->version[i]); 288 289 prop_dictionary_set(target_dict, DM_TARGETS_VERSION, ver); 290 prop_array_add(target_array, target_dict); 291 292 prop_object_release(ver); 293 prop_object_release(target_dict); 294 } 295 296 mutex_exit(&dm_target_mutex); 297 298 return target_array; 299 } 300 301 /* 302 * Initialize dm_target subsystem. 303 */ 304 int 305 dm_target_init(void) 306 { 307 dm_target_t *dmt; 308 309 mutex_init(&dm_target_mutex, MUTEX_DEFAULT, IPL_NONE); 310 311 dmt = dm_target_alloc("linear"); 312 dmt->version[0] = 1; 313 dmt->version[1] = 0; 314 dmt->version[2] = 2; 315 dmt->init = &dm_target_linear_init; 316 dmt->table = &dm_target_linear_table; 317 dmt->strategy = &dm_target_linear_strategy; 318 dmt->sync = &dm_target_linear_sync; 319 dmt->destroy = &dm_target_linear_destroy; 320 dmt->upcall = &dm_target_linear_upcall; 321 dmt->secsize = &dm_target_linear_secsize; 322 if (dm_target_insert(dmt)) 323 printf("Failed to insert linear\n"); 324 325 dmt = dm_target_alloc("striped"); 326 dmt->version[0] = 1; 327 dmt->version[1] = 0; 328 dmt->version[2] = 3; 329 dmt->init = &dm_target_stripe_init; 330 dmt->info = &dm_target_stripe_info; 331 dmt->table = &dm_target_stripe_table; 332 dmt->strategy = &dm_target_stripe_strategy; 333 dmt->sync = &dm_target_stripe_sync; 334 dmt->destroy = &dm_target_stripe_destroy; 335 dmt->upcall = &dm_target_stripe_upcall; 336 dmt->secsize = &dm_target_stripe_secsize; 337 if (dm_target_insert(dmt)) 338 printf("Failed to insert striped\n"); 339 340 dmt = dm_target_alloc("error"); 341 dmt->version[0] = 1; 342 dmt->version[1] = 0; 343 dmt->version[2] = 0; 344 dmt->init = &dm_target_error_init; 345 dmt->strategy = &dm_target_error_strategy; 346 dmt->destroy = &dm_target_error_destroy; 347 dmt->upcall = &dm_target_error_upcall; 348 if (dm_target_insert(dmt)) 349 printf("Failed to insert error\n"); 350 351 dmt = dm_target_alloc("zero"); 352 dmt->version[0] = 1; 353 dmt->version[1] = 0; 354 dmt->version[2] = 0; 355 dmt->init = &dm_target_zero_init; 356 dmt->strategy = &dm_target_zero_strategy; 357 dmt->destroy = &dm_target_zero_destroy; 358 dmt->upcall = &dm_target_zero_upcall; 359 if (dm_target_insert(dmt)) 360 printf("Failed to insert zero\n"); 361 362 return 0; 363 } 364