1 /* $NetBSD: dm_target.c,v 1.12 2010/01/04 00:14:41 haad 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 32 #include <sys/types.h> 33 #include <sys/param.h> 34 35 #include <sys/malloc.h> 36 #include <sys/module.h> 37 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 struct lock 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 atomic_add_int(&target->ref_cnt, 1); 58 } 59 /* 60 * Release reference counter on target. 61 */ 62 void 63 dm_target_unbusy(dm_target_t * target) 64 { 65 KKASSERT(target->ref_cnt > 0); 66 atomic_subtract_int(&target->ref_cnt, 1); 67 } 68 /* 69 * Try to autoload target module if it was not found in current 70 * target list. 71 */ 72 dm_target_t * 73 dm_target_autoload(const char *dm_target_name) 74 { 75 #if 0 76 char name[30]; 77 u_int gen; 78 dm_target_t *dmt; 79 80 ksnprintf(name, sizeof(name), "dm_target_%s", dm_target_name); 81 name[29] = '\0'; 82 83 do { 84 gen = module_gen; 85 86 /* Try to autoload target module */ 87 lockmgr(&module_lock, LK_EXCLUSIVE); 88 (void) module_autoload(name, MODULE_CLASS_MISC); 89 lockmgr(&module_lock, LK_RELEASE); 90 } while (gen != module_gen); 91 92 lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 93 dmt = dm_target_lookup_name(dm_target_name); 94 if (dmt != NULL) 95 dm_target_busy(dmt); 96 lockmgr(&dm_target_mutex, LK_RELEASE); 97 98 return dmt; 99 #endif 100 return NULL; 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 dmt = NULL; 111 112 if (dm_target_name == NULL) 113 return NULL; 114 115 lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 116 117 dmt = dm_target_lookup_name(dm_target_name); 118 if (dmt != NULL) 119 dm_target_busy(dmt); 120 121 lockmgr(&dm_target_mutex, LK_RELEASE); 122 123 return dmt; 124 } 125 /* 126 * Search for name in TAIL and return apropriate pointer. 127 */ 128 static dm_target_t * 129 dm_target_lookup_name(const char *dm_target_name) 130 { 131 dm_target_t *dm_target; 132 int dlen; 133 int slen; 134 135 slen = strlen(dm_target_name) + 1; 136 137 TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 138 dlen = strlen(dm_target->name) + 1; 139 if (dlen != slen) 140 continue; 141 142 if (strncmp(dm_target_name, dm_target->name, slen) == 0) 143 return dm_target; 144 } 145 146 return NULL; 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 lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 159 160 dmt = dm_target_lookup_name(dm_target->name); 161 if (dmt != NULL) { 162 kprintf("uhoh, target_insert EEXIST\n"); 163 lockmgr(&dm_target_mutex, LK_RELEASE); 164 return EEXIST; 165 } 166 TAILQ_INSERT_TAIL(&dm_target_list, dm_target, dm_target_next); 167 168 lockmgr(&dm_target_mutex, LK_RELEASE); 169 170 return 0; 171 } 172 173 174 /* 175 * Remove target from TAIL, target is selected with it's name. 176 */ 177 int 178 dm_target_rem(char *dm_target_name) 179 { 180 dm_target_t *dmt; 181 182 KKASSERT(dm_target_name != NULL); 183 184 lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 185 186 dmt = dm_target_lookup_name(dm_target_name); 187 if (dmt == NULL) { 188 lockmgr(&dm_target_mutex, LK_RELEASE); 189 return ENOENT; 190 } 191 if (dmt->ref_cnt > 0) { 192 lockmgr(&dm_target_mutex, LK_RELEASE); 193 return EBUSY; 194 } 195 TAILQ_REMOVE(&dm_target_list, 196 dmt, dm_target_next); 197 198 lockmgr(&dm_target_mutex, LK_RELEASE); 199 200 (void) kfree(dmt, M_DM); 201 202 return 0; 203 } 204 /* 205 * Destroy all targets and remove them from queue. 206 * This routine is called from dm_detach, before module 207 * is unloaded. 208 */ 209 int 210 dm_target_destroy(void) 211 { 212 dm_target_t *dm_target; 213 214 lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 215 while (TAILQ_FIRST(&dm_target_list) != NULL) { 216 217 dm_target = TAILQ_FIRST(&dm_target_list); 218 219 TAILQ_REMOVE(&dm_target_list, TAILQ_FIRST(&dm_target_list), 220 dm_target_next); 221 222 (void) kfree(dm_target, M_DM); 223 } 224 lockmgr(&dm_target_mutex, LK_RELEASE); 225 226 lockuninit(&dm_target_mutex); 227 228 return 0; 229 } 230 /* 231 * Allocate new target entry. 232 */ 233 dm_target_t * 234 dm_target_alloc(const char *name) 235 { 236 return kmalloc(sizeof(dm_target_t), M_DM, M_WAITOK | M_ZERO); 237 } 238 /* 239 * Return prop_array of dm_target dictionaries. 240 */ 241 prop_array_t 242 dm_target_prop_list(void) 243 { 244 prop_array_t target_array, ver; 245 prop_dictionary_t target_dict; 246 dm_target_t *dm_target; 247 248 size_t i; 249 250 target_array = prop_array_create(); 251 252 lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 253 254 TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 255 256 target_dict = prop_dictionary_create(); 257 ver = prop_array_create(); 258 prop_dictionary_set_cstring(target_dict, DM_TARGETS_NAME, 259 dm_target->name); 260 261 for (i = 0; i < 3; i++) 262 prop_array_add_uint32(ver, dm_target->version[i]); 263 264 prop_dictionary_set(target_dict, DM_TARGETS_VERSION, ver); 265 prop_array_add(target_array, target_dict); 266 267 prop_object_release(ver); 268 prop_object_release(target_dict); 269 } 270 271 lockmgr(&dm_target_mutex, LK_RELEASE); 272 273 return target_array; 274 } 275 /* Initialize dm_target subsystem. */ 276 int 277 dm_target_init(void) 278 { 279 dm_target_t *dmt, *dmt3, *dmt5; 280 int r; 281 282 r = 0; 283 284 lockinit(&dm_target_mutex, "dmtrgt", 0, LK_CANRECURSE); 285 286 dmt = dm_target_alloc("linear"); 287 dmt3 = dm_target_alloc("striped"); 288 dmt5 = dm_target_alloc("crypt"); 289 290 dmt->version[0] = 1; 291 dmt->version[1] = 0; 292 dmt->version[2] = 2; 293 strlcpy(dmt->name, "linear", DM_MAX_TYPE_NAME); 294 dmt->init = &dm_target_linear_init; 295 dmt->status = &dm_target_linear_status; 296 dmt->strategy = &dm_target_linear_strategy; 297 dmt->deps = &dm_target_linear_deps; 298 dmt->destroy = &dm_target_linear_destroy; 299 dmt->upcall = &dm_target_linear_upcall; 300 301 r = dm_target_insert(dmt); 302 303 dmt3->version[0] = 1; 304 dmt3->version[1] = 0; 305 dmt3->version[2] = 3; 306 strlcpy(dmt3->name, "striped", DM_MAX_TYPE_NAME); 307 dmt3->init = &dm_target_stripe_init; 308 dmt3->status = &dm_target_stripe_status; 309 dmt3->strategy = &dm_target_stripe_strategy; 310 dmt3->deps = &dm_target_stripe_deps; 311 dmt3->destroy = &dm_target_stripe_destroy; 312 dmt3->upcall = &dm_target_stripe_upcall; 313 314 r = dm_target_insert(dmt3); 315 316 dmt5->version[0] = 1; 317 dmt5->version[1] = 0; 318 dmt5->version[2] = 0; 319 strlcpy(dmt5->name, "crypt", DM_MAX_TYPE_NAME); 320 dmt5->init = &dm_target_crypt_init; 321 dmt5->status = &dm_target_crypt_status; 322 dmt5->strategy = &dm_target_crypt_strategy; 323 dmt5->deps = &dm_target_crypt_deps; 324 dmt5->destroy = &dm_target_crypt_destroy; 325 dmt5->upcall = &dm_target_crypt_upcall; 326 327 r = dm_target_insert(dmt5); 328 329 330 return r; 331 } 332