1 /* $NetBSD: dm_target.c,v 1.9 2009/02/20 11:14:11 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/kmem.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 kmutex_t dm_target_mutex; 50 51 /* 52 * Called indirectly from dm_table_load_ioct to mark target as used. 53 */ 54 void 55 dm_target_busy(dm_target_t *target) 56 { 57 atomic_inc_32(&target->ref_cnt); 58 } 59 60 /* 61 * Release reference counter on target. 62 */ 63 void 64 dm_target_unbusy(dm_target_t *target) 65 { 66 KASSERT(target->ref_cnt > 0); 67 atomic_dec_32(&target->ref_cnt); 68 } 69 70 /* 71 * Try to autoload target module if it was not found in current 72 * target list. 73 */ 74 dm_target_t * 75 dm_target_autoload(const char *dm_target_name) 76 { 77 char name[30]; 78 u_int gen; 79 dm_target_t *dmt; 80 81 snprintf(name, sizeof(name), "dm_target_%s", dm_target_name); 82 name[29]='\0'; 83 84 do { 85 gen = module_gen; 86 87 /* Try to autoload target module */ 88 mutex_enter(&module_lock); 89 (void) module_autoload(name, MODULE_CLASS_MISC); 90 mutex_exit(&module_lock); 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 dmt = NULL; 111 112 if (dm_target_name == NULL) 113 return NULL; 114 115 mutex_enter(&dm_target_mutex); 116 117 dmt = dm_target_lookup_name(dm_target_name); 118 if (dmt != NULL) 119 dm_target_busy(dmt); 120 121 mutex_exit(&dm_target_mutex); 122 123 return dmt; 124 } 125 126 /* 127 * Search for name in TAIL and return apropriate pointer. 128 */ 129 static dm_target_t* 130 dm_target_lookup_name(const char *dm_target_name) 131 { 132 dm_target_t *dm_target; 133 int dlen; 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 /* 150 * Insert new target struct into the TAIL. 151 * dm_target 152 * contains name, version, function pointer to specifif target functions. 153 */ 154 int 155 dm_target_insert(dm_target_t *dm_target) 156 { 157 dm_target_t *dmt; 158 159 mutex_enter(&dm_target_mutex); 160 161 dmt = dm_target_lookup_name(dm_target->name); 162 if (dmt != NULL) { 163 mutex_exit(&dm_target_mutex); 164 return EEXIST; 165 } 166 167 TAILQ_INSERT_TAIL(&dm_target_list, dm_target, dm_target_next); 168 169 mutex_exit(&dm_target_mutex); 170 171 return 0; 172 } 173 174 175 /* 176 * Remove target from TAIL, target is selected with it's name. 177 */ 178 int 179 dm_target_rem(char *dm_target_name) 180 { 181 dm_target_t *dmt; 182 183 KASSERT(dm_target_name != NULL); 184 185 mutex_enter(&dm_target_mutex); 186 187 dmt = dm_target_lookup_name(dm_target_name); 188 if (dmt == NULL) { 189 mutex_exit(&dm_target_mutex); 190 return ENOENT; 191 } 192 193 if (dmt->ref_cnt > 0) { 194 mutex_exit(&dm_target_mutex); 195 return EBUSY; 196 } 197 198 TAILQ_REMOVE(&dm_target_list, 199 dmt, dm_target_next); 200 201 mutex_exit(&dm_target_mutex); 202 203 (void)kmem_free(dmt, sizeof(dm_target_t)); 204 205 return 0; 206 } 207 208 /* 209 * Destroy all targets and remove them from queue. 210 * This routine is called from dm_detach, before module 211 * is unloaded. 212 */ 213 int 214 dm_target_destroy(void) 215 { 216 dm_target_t *dm_target; 217 218 mutex_enter(&dm_target_mutex); 219 while (TAILQ_FIRST(&dm_target_list) != NULL){ 220 221 dm_target = TAILQ_FIRST(&dm_target_list); 222 223 TAILQ_REMOVE(&dm_target_list, TAILQ_FIRST(&dm_target_list), 224 dm_target_next); 225 226 (void)kmem_free(dm_target, sizeof(dm_target_t)); 227 } 228 mutex_exit(&dm_target_mutex); 229 230 mutex_destroy(&dm_target_mutex); 231 232 return 0; 233 } 234 235 /* 236 * Allocate new target entry. 237 */ 238 dm_target_t* 239 dm_target_alloc(const char *name) 240 { 241 return kmem_zalloc(sizeof(dm_target_t), KM_NOSLEEP); 242 } 243 244 /* 245 * Return prop_array of dm_target dictionaries. 246 */ 247 prop_array_t 248 dm_target_prop_list(void) 249 { 250 prop_array_t target_array,ver; 251 prop_dictionary_t target_dict; 252 dm_target_t *dm_target; 253 254 size_t i; 255 256 target_array = prop_array_create(); 257 258 mutex_enter(&dm_target_mutex); 259 260 TAILQ_FOREACH (dm_target, &dm_target_list, dm_target_next){ 261 262 target_dict = prop_dictionary_create(); 263 ver = prop_array_create(); 264 prop_dictionary_set_cstring(target_dict, DM_TARGETS_NAME, 265 dm_target->name); 266 267 for (i = 0; i < 3; i++) 268 prop_array_add_uint32(ver, dm_target->version[i]); 269 270 prop_dictionary_set(target_dict, DM_TARGETS_VERSION, ver); 271 prop_array_add(target_array, target_dict); 272 273 prop_object_release(ver); 274 prop_object_release(target_dict); 275 } 276 277 mutex_exit(&dm_target_mutex); 278 279 return target_array; 280 } 281 282 /* Initialize dm_target subsystem. */ 283 int 284 dm_target_init(void) 285 { 286 dm_target_t *dmt,*dmt3; 287 int r; 288 289 r = 0; 290 291 mutex_init(&dm_target_mutex, MUTEX_DEFAULT, IPL_NONE); 292 293 dmt = dm_target_alloc("linear"); 294 dmt3 = dm_target_alloc("striped"); 295 296 dmt->version[0] = 1; 297 dmt->version[1] = 0; 298 dmt->version[2] = 2; 299 strlcpy(dmt->name, "linear", DM_MAX_TYPE_NAME); 300 dmt->init = &dm_target_linear_init; 301 dmt->status = &dm_target_linear_status; 302 dmt->strategy = &dm_target_linear_strategy; 303 dmt->deps = &dm_target_linear_deps; 304 dmt->destroy = &dm_target_linear_destroy; 305 dmt->upcall = &dm_target_linear_upcall; 306 307 r = dm_target_insert(dmt); 308 309 dmt3->version[0] = 1; 310 dmt3->version[1] = 0; 311 dmt3->version[2] = 3; 312 strlcpy(dmt3->name, "striped", DM_MAX_TYPE_NAME); 313 dmt3->init = &dm_target_stripe_init; 314 dmt3->status = &dm_target_stripe_status; 315 dmt3->strategy = &dm_target_stripe_strategy; 316 dmt3->deps = &dm_target_stripe_deps; 317 dmt3->destroy = &dm_target_stripe_destroy; 318 dmt3->upcall = &dm_target_stripe_upcall; 319 320 r = dm_target_insert(dmt3); 321 322 #ifdef notyet 323 dmt5->version[0] = 1; 324 dmt5->version[1] = 0; 325 dmt5->version[2] = 5; 326 strlcpy(dmt5->name, "snapshot", DM_MAX_TYPE_NAME); 327 dmt5->init = &dm_target_snapshot_init; 328 dmt5->status = &dm_target_snapshot_status; 329 dmt5->strategy = &dm_target_snapshot_strategy; 330 dmt5->deps = &dm_target_snapshot_deps; 331 dmt5->destroy = &dm_target_snapshot_destroy; 332 dmt5->upcall = &dm_target_snapshot_upcall; 333 334 r = dm_target_insert(dmt5); 335 336 dmt6->version[0] = 1; 337 dmt6->version[1] = 0; 338 dmt6->version[2] = 5; 339 strlcpy(dmt6->name, "snapshot-origin", DM_MAX_TYPE_NAME); 340 dmt6->init = &dm_target_snapshot_orig_init; 341 dmt6->status = &dm_target_snapshot_orig_status; 342 dmt6->strategy = &dm_target_snapshot_orig_strategy; 343 dmt6->deps = &dm_target_snapshot_orig_deps; 344 dmt6->destroy = &dm_target_snapshot_orig_destroy; 345 dmt6->upcall = &dm_target_snapshot_orig_upcall; 346 347 r = dm_target_insert(dmt6); 348 #endif 349 350 return r; 351 } 352