1 /* $NetBSD: dm_target.c,v 1.20 2018/01/05 14:22:26 christos 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.20 2018/01/05 14:22:26 christos 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 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 (void) 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 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 size_t dlen; 134 size_t slen; 135 136 slen = strlen(dm_target_name) + 1; 137 138 TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 139 dlen = strlen(dm_target->name) + 1; 140 if (dlen != slen) 141 continue; 142 143 if (strncmp(dm_target_name, dm_target->name, slen) == 0) 144 return dm_target; 145 } 146 147 return NULL; 148 } 149 150 /* 151 * Insert new target struct into the TAIL. 152 * dm_target 153 * contains name, version, function pointer to specifif target functions. 154 */ 155 int 156 dm_target_insert(dm_target_t * dm_target) 157 { 158 dm_target_t *dmt; 159 160 /* Sanity check for any missing function */ 161 KASSERT(dm_target->init != NULL); 162 KASSERT(dm_target->status != NULL); 163 KASSERT(dm_target->strategy != NULL); 164 KASSERT(dm_target->deps != NULL); 165 KASSERT(dm_target->destroy != NULL); 166 KASSERT(dm_target->upcall != NULL); 167 KASSERT(dm_target->sync != NULL); 168 KASSERT(dm_target->secsize != NULL); 169 170 mutex_enter(&dm_target_mutex); 171 172 dmt = dm_target_lookup_name(dm_target->name); 173 if (dmt != NULL) { 174 mutex_exit(&dm_target_mutex); 175 return EEXIST; 176 } 177 TAILQ_INSERT_TAIL(&dm_target_list, dm_target, dm_target_next); 178 179 mutex_exit(&dm_target_mutex); 180 181 return 0; 182 } 183 184 /* 185 * Remove target from TAIL, target is selected with its name. 186 */ 187 int 188 dm_target_rem(char *dm_target_name) 189 { 190 dm_target_t *dmt; 191 192 KASSERT(dm_target_name != NULL); 193 194 mutex_enter(&dm_target_mutex); 195 196 dmt = dm_target_lookup_name(dm_target_name); 197 if (dmt == NULL) { 198 mutex_exit(&dm_target_mutex); 199 return ENOENT; 200 } 201 if (dmt->ref_cnt > 0) { 202 mutex_exit(&dm_target_mutex); 203 return EBUSY; 204 } 205 TAILQ_REMOVE(&dm_target_list, 206 dmt, dm_target_next); 207 208 mutex_exit(&dm_target_mutex); 209 210 (void) kmem_free(dmt, sizeof(dm_target_t)); 211 212 return 0; 213 } 214 215 /* 216 * Destroy all targets and remove them from queue. 217 * This routine is called from dm_detach, before module 218 * is unloaded. 219 */ 220 int 221 dm_target_destroy(void) 222 { 223 dm_target_t *dm_target; 224 225 mutex_enter(&dm_target_mutex); 226 while (TAILQ_FIRST(&dm_target_list) != NULL) { 227 228 dm_target = TAILQ_FIRST(&dm_target_list); 229 230 TAILQ_REMOVE(&dm_target_list, TAILQ_FIRST(&dm_target_list), 231 dm_target_next); 232 233 (void) kmem_free(dm_target, sizeof(dm_target_t)); 234 } 235 mutex_exit(&dm_target_mutex); 236 237 mutex_destroy(&dm_target_mutex); 238 239 return 0; 240 } 241 242 /* 243 * Allocate new target entry. 244 */ 245 dm_target_t * 246 dm_target_alloc(const char *name) 247 { 248 return kmem_zalloc(sizeof(dm_target_t), KM_SLEEP); 249 } 250 251 /* 252 * Return prop_array of dm_target dictionaries. 253 */ 254 prop_array_t 255 dm_target_prop_list(void) 256 { 257 prop_array_t target_array, ver; 258 prop_dictionary_t target_dict; 259 dm_target_t *dm_target; 260 261 size_t i; 262 263 target_array = prop_array_create(); 264 265 mutex_enter(&dm_target_mutex); 266 267 TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 268 269 target_dict = prop_dictionary_create(); 270 ver = prop_array_create(); 271 prop_dictionary_set_cstring(target_dict, DM_TARGETS_NAME, 272 dm_target->name); 273 274 for (i = 0; i < 3; i++) 275 prop_array_add_uint32(ver, dm_target->version[i]); 276 277 prop_dictionary_set(target_dict, DM_TARGETS_VERSION, ver); 278 prop_array_add(target_array, target_dict); 279 280 prop_object_release(ver); 281 prop_object_release(target_dict); 282 } 283 284 mutex_exit(&dm_target_mutex); 285 286 return target_array; 287 } 288 289 /* Initialize dm_target subsystem. */ 290 int 291 dm_target_init(void) 292 { 293 dm_target_t *dmt, *dmt3; 294 int r; 295 296 r = 0; 297 298 mutex_init(&dm_target_mutex, MUTEX_DEFAULT, IPL_NONE); 299 300 dmt = dm_target_alloc("linear"); 301 dmt3 = dm_target_alloc("striped"); 302 303 dmt->version[0] = 1; 304 dmt->version[1] = 0; 305 dmt->version[2] = 2; 306 strlcpy(dmt->name, "linear", DM_MAX_TYPE_NAME); 307 dmt->init = &dm_target_linear_init; 308 dmt->status = &dm_target_linear_status; 309 dmt->strategy = &dm_target_linear_strategy; 310 dmt->sync = &dm_target_linear_sync; 311 dmt->deps = &dm_target_linear_deps; 312 dmt->destroy = &dm_target_linear_destroy; 313 dmt->upcall = &dm_target_linear_upcall; 314 dmt->secsize = &dm_target_linear_secsize; 315 316 r = dm_target_insert(dmt); 317 318 dmt3->version[0] = 1; 319 dmt3->version[1] = 0; 320 dmt3->version[2] = 3; 321 strlcpy(dmt3->name, "striped", DM_MAX_TYPE_NAME); 322 dmt3->init = &dm_target_stripe_init; 323 dmt3->status = &dm_target_stripe_status; 324 dmt3->strategy = &dm_target_stripe_strategy; 325 dmt3->sync = &dm_target_stripe_sync; 326 dmt3->deps = &dm_target_stripe_deps; 327 dmt3->destroy = &dm_target_stripe_destroy; 328 dmt3->upcall = &dm_target_stripe_upcall; 329 dmt3->secsize = &dm_target_stripe_secsize; 330 331 r = dm_target_insert(dmt3); 332 333 return r; 334 } 335