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