1 /* $NetBSD: dm_target.c,v 1.28 2019/12/14 10:49:30 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.28 2019/12/14 10:49:30 tkusumi Exp $"); 33 34 #include <sys/types.h> 35 #include <sys/param.h> 36 37 #include <sys/kmem.h> 38 #include <sys/module.h> 39 40 41 #include "netbsd-dm.h" 42 #include "dm.h" 43 44 static dm_target_t *dm_target_lookup_name(const char *); 45 46 TAILQ_HEAD(dm_target_head, dm_target); 47 48 static struct dm_target_head dm_target_list = 49 TAILQ_HEAD_INITIALIZER(dm_target_list); 50 51 static kmutex_t dm_target_mutex; 52 53 /* 54 * Called indirectly from dm_table_load_ioctl to mark target as used. 55 */ 56 void 57 dm_target_busy(dm_target_t *target) 58 { 59 atomic_inc_32(&target->ref_cnt); 60 } 61 62 /* 63 * Release reference counter on target. 64 */ 65 void 66 dm_target_unbusy(dm_target_t *target) 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 u_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->status == NULL) { 164 printf("%s missing status\n", dm_target->name); 165 return EINVAL; 166 } 167 if (dm_target->strategy == NULL) { 168 printf("%s missing strategy\n", dm_target->name); 169 return EINVAL; 170 } 171 if (dm_target->deps == NULL) { 172 printf("%s missing deps\n", dm_target->name); 173 return EINVAL; 174 } 175 if (dm_target->destroy == NULL) { 176 printf("%s missing destroy\n", dm_target->name); 177 return EINVAL; 178 } 179 if (dm_target->upcall == NULL) { 180 printf("%s missing upcall\n", dm_target->name); 181 return EINVAL; 182 } 183 if (dm_target->sync == NULL) { 184 printf("%s missing sync\n", dm_target->name); 185 return EINVAL; 186 } 187 if (dm_target->secsize == NULL) { 188 printf("%s missing secsize\n", dm_target->name); 189 return EINVAL; 190 } 191 192 mutex_enter(&dm_target_mutex); 193 194 dmt = dm_target_lookup_name(dm_target->name); 195 if (dmt != NULL) { 196 mutex_exit(&dm_target_mutex); 197 return EEXIST; 198 } 199 TAILQ_INSERT_TAIL(&dm_target_list, dm_target, dm_target_next); 200 201 mutex_exit(&dm_target_mutex); 202 203 return 0; 204 } 205 206 /* 207 * Remove target from TAIL, target is selected with its name. 208 */ 209 int 210 dm_target_rem(const char *dm_target_name) 211 { 212 dm_target_t *dmt; 213 214 KASSERT(dm_target_name != NULL); 215 216 mutex_enter(&dm_target_mutex); 217 218 dmt = dm_target_lookup_name(dm_target_name); 219 if (dmt == NULL) { 220 mutex_exit(&dm_target_mutex); 221 return ENOENT; 222 } 223 if (dmt->ref_cnt > 0) { 224 mutex_exit(&dm_target_mutex); 225 return EBUSY; 226 } 227 TAILQ_REMOVE(&dm_target_list, dmt, dm_target_next); 228 229 mutex_exit(&dm_target_mutex); 230 231 kmem_free(dmt, sizeof(dm_target_t)); 232 233 return 0; 234 } 235 236 /* 237 * Destroy all targets and remove them from queue. 238 * This routine is called from dm_detach, before module 239 * is unloaded. 240 */ 241 int 242 dm_target_destroy(void) 243 { 244 dm_target_t *dm_target; 245 246 mutex_enter(&dm_target_mutex); 247 248 while ((dm_target = TAILQ_FIRST(&dm_target_list)) != NULL) { 249 TAILQ_REMOVE(&dm_target_list, dm_target, dm_target_next); 250 kmem_free(dm_target, sizeof(dm_target_t)); 251 } 252 KASSERT(TAILQ_EMPTY(&dm_target_list)); 253 254 mutex_exit(&dm_target_mutex); 255 256 mutex_destroy(&dm_target_mutex); 257 258 return 0; 259 } 260 261 /* 262 * Allocate new target entry. 263 */ 264 dm_target_t * 265 dm_target_alloc(const char *name) 266 { 267 dm_target_t *dmt; 268 269 dmt = kmem_zalloc(sizeof(dm_target_t), KM_SLEEP); 270 if (dmt == NULL) 271 return NULL; 272 273 if (name) 274 strlcpy(dmt->name, name, sizeof(dmt->name)); 275 276 return dmt; 277 } 278 279 /* 280 * Return prop_array of dm_target dictionaries. 281 */ 282 prop_array_t 283 dm_target_prop_list(void) 284 { 285 prop_array_t target_array, ver; 286 prop_dictionary_t target_dict; 287 dm_target_t *dm_target; 288 289 size_t i; 290 291 target_array = prop_array_create(); 292 293 mutex_enter(&dm_target_mutex); 294 295 TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 296 target_dict = prop_dictionary_create(); 297 ver = prop_array_create(); 298 prop_dictionary_set_cstring(target_dict, DM_TARGETS_NAME, 299 dm_target->name); 300 301 for (i = 0; i < 3; i++) 302 prop_array_add_uint32(ver, dm_target->version[i]); 303 304 prop_dictionary_set(target_dict, DM_TARGETS_VERSION, ver); 305 prop_array_add(target_array, target_dict); 306 307 prop_object_release(ver); 308 prop_object_release(target_dict); 309 } 310 311 mutex_exit(&dm_target_mutex); 312 313 return target_array; 314 } 315 316 /* Initialize dm_target subsystem. */ 317 int 318 dm_target_init(void) 319 { 320 dm_target_t *dmt, *dmt3; 321 int r; 322 323 r = 0; 324 325 mutex_init(&dm_target_mutex, MUTEX_DEFAULT, IPL_NONE); 326 327 dmt = dm_target_alloc("linear"); 328 dmt3 = dm_target_alloc("striped"); 329 330 dmt->version[0] = 1; 331 dmt->version[1] = 0; 332 dmt->version[2] = 2; 333 dmt->init = &dm_target_linear_init; 334 dmt->status = &dm_target_linear_status; 335 dmt->strategy = &dm_target_linear_strategy; 336 dmt->sync = &dm_target_linear_sync; 337 dmt->deps = &dm_target_linear_deps; 338 dmt->destroy = &dm_target_linear_destroy; 339 dmt->upcall = &dm_target_linear_upcall; 340 dmt->secsize = &dm_target_linear_secsize; 341 342 r = dm_target_insert(dmt); 343 344 dmt3->version[0] = 1; 345 dmt3->version[1] = 0; 346 dmt3->version[2] = 3; 347 dmt3->init = &dm_target_stripe_init; 348 dmt3->status = &dm_target_stripe_status; 349 dmt3->strategy = &dm_target_stripe_strategy; 350 dmt3->sync = &dm_target_stripe_sync; 351 dmt3->deps = &dm_target_stripe_deps; 352 dmt3->destroy = &dm_target_stripe_destroy; 353 dmt3->upcall = &dm_target_stripe_upcall; 354 dmt3->secsize = &dm_target_stripe_secsize; 355 356 r = dm_target_insert(dmt3); 357 358 return r; 359 } 360