1 /* $NetBSD: dm_target.c,v 1.12 2010/01/04 00:14:41 haad Exp $ */ 2 3 /* 4 * Copyright (c) 2010-2011 Alex Hornung <alex@alexhornung.com> 5 * Copyright (c) 2008 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Adam Hamsik. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code Must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/param.h> 35 36 #include <sys/malloc.h> 37 #include <sys/module.h> 38 #include <sys/linker.h> 39 #include <dev/disk/dm/dm.h> 40 41 #include "netbsd-dm.h" 42 43 static dm_target_t *dm_target_lookup_name(const char *); 44 45 TAILQ_HEAD(dm_target_head, dm_target); 46 47 static struct dm_target_head dm_target_list = 48 TAILQ_HEAD_INITIALIZER(dm_target_list); 49 50 struct lock dm_target_mutex; 51 52 /* 53 * Called indirectly from dm_table_load_ioctl to mark target as used. 54 */ 55 void 56 dm_target_busy(dm_target_t * target) 57 { 58 atomic_add_int(&target->ref_cnt, 1); 59 } 60 /* 61 * Release reference counter on target. 62 */ 63 void 64 dm_target_unbusy(dm_target_t * target) 65 { 66 KKASSERT(target->ref_cnt > 0); 67 atomic_subtract_int(&target->ref_cnt, 1); 68 } 69 70 /* 71 * Try to autoload the module for the requested target. 72 */ 73 dm_target_t * 74 dm_target_autoload(const char *dm_target_name) 75 { 76 char mod_name[128]; 77 dm_target_t *dmt; 78 linker_file_t linker_file; 79 int error; 80 81 ksnprintf(mod_name, sizeof(mod_name), "dm_target_%s", dm_target_name); 82 error = linker_reference_module(mod_name, NULL, &linker_file); 83 if (error != 0) { 84 kprintf("dm: could not autoload module for target %s\n", 85 dm_target_name); 86 return NULL; 87 } 88 89 dmt = dm_target_lookup(dm_target_name); 90 if (dmt == NULL) { 91 linker_release_module(NULL, NULL, linker_file); 92 return NULL; 93 } 94 95 /* XXX: extra-big hack to allow users to kldunload the module */ 96 linker_file->userrefs = 1; 97 98 return dmt; 99 } 100 101 /* 102 * Lookup for target in global target list. 103 */ 104 dm_target_t * 105 dm_target_lookup(const char *dm_target_name) 106 { 107 dm_target_t *dmt; 108 109 dmt = NULL; 110 111 if (dm_target_name == NULL) 112 return NULL; 113 114 lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 115 116 dmt = dm_target_lookup_name(dm_target_name); 117 if (dmt != NULL) 118 dm_target_busy(dmt); 119 120 lockmgr(&dm_target_mutex, LK_RELEASE); 121 122 return dmt; 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 132 TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 133 if (strcmp(dm_target_name, dm_target->name) == 0) 134 return dm_target; 135 } 136 137 return NULL; 138 } 139 /* 140 * Insert new target struct into the TAIL. 141 * dm_target 142 * contains name, version, function pointer to specifif target functions. 143 */ 144 int 145 dm_target_insert(dm_target_t * dm_target) 146 { 147 dm_target_t *dmt; 148 149 lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 150 151 dmt = dm_target_lookup_name(dm_target->name); 152 if (dmt != NULL) { 153 kprintf("uhoh, target_insert EEXIST\n"); 154 lockmgr(&dm_target_mutex, LK_RELEASE); 155 return EEXIST; 156 } 157 TAILQ_INSERT_TAIL(&dm_target_list, dm_target, dm_target_next); 158 159 lockmgr(&dm_target_mutex, LK_RELEASE); 160 161 return 0; 162 } 163 164 165 /* 166 * Remove target from TAIL, target is selected with it's name. 167 */ 168 int 169 dm_target_rem(char *dm_target_name) 170 { 171 dm_target_t *dmt; 172 173 KKASSERT(dm_target_name != NULL); 174 175 lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 176 177 dmt = dm_target_lookup_name(dm_target_name); 178 if (dmt == NULL) { 179 lockmgr(&dm_target_mutex, LK_RELEASE); 180 return ENOENT; 181 } 182 if (dmt->ref_cnt > 0) { 183 lockmgr(&dm_target_mutex, LK_RELEASE); 184 return EBUSY; 185 } 186 TAILQ_REMOVE(&dm_target_list, 187 dmt, dm_target_next); 188 189 lockmgr(&dm_target_mutex, LK_RELEASE); 190 191 (void) kfree(dmt, M_DM); 192 193 return 0; 194 } 195 196 /* 197 * Allocate new target entry. 198 */ 199 dm_target_t * 200 dm_target_alloc(const char *name) 201 { 202 return kmalloc(sizeof(dm_target_t), M_DM, M_WAITOK | M_ZERO); 203 } 204 /* 205 * Return prop_array of dm_target dictionaries. 206 */ 207 prop_array_t 208 dm_target_prop_list(void) 209 { 210 prop_array_t target_array, ver; 211 prop_dictionary_t target_dict; 212 dm_target_t *dm_target; 213 214 size_t i; 215 216 target_array = prop_array_create(); 217 218 lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 219 220 TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 221 222 target_dict = prop_dictionary_create(); 223 ver = prop_array_create(); 224 prop_dictionary_set_cstring(target_dict, DM_TARGETS_NAME, 225 dm_target->name); 226 227 for (i = 0; i < 3; i++) 228 prop_array_add_uint32(ver, dm_target->version[i]); 229 230 prop_dictionary_set(target_dict, DM_TARGETS_VERSION, ver); 231 prop_array_add(target_array, target_dict); 232 233 prop_object_release(ver); 234 prop_object_release(target_dict); 235 } 236 237 lockmgr(&dm_target_mutex, LK_RELEASE); 238 239 return target_array; 240 } 241 242 /* Initialize dm_target subsystem. */ 243 int 244 dm_target_init(void) 245 { 246 lockinit(&dm_target_mutex, "dmtrgt", 0, LK_CANRECURSE); 247 248 return 0; 249 } 250 251 /* 252 * Destroy all targets and remove them from queue. 253 * This routine is called from dm_detach, before module 254 * is unloaded. 255 */ 256 int 257 dm_target_uninit(void) 258 { 259 dm_target_t *dm_target; 260 261 lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 262 while (TAILQ_FIRST(&dm_target_list) != NULL) { 263 264 dm_target = TAILQ_FIRST(&dm_target_list); 265 266 TAILQ_REMOVE(&dm_target_list, TAILQ_FIRST(&dm_target_list), 267 dm_target_next); 268 269 (void) kfree(dm_target, M_DM); 270 } 271 lockmgr(&dm_target_mutex, LK_RELEASE); 272 273 lockuninit(&dm_target_mutex); 274 275 return 0; 276 } 277