1 /* $NetBSD: dm_target.c,v 1.6 2009/01/02 11:03:24 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 37 #include "netbsd-dm.h" 38 #include "dm.h" 39 40 static dm_target_t* dm_target_lookup_name(const char *); 41 42 TAILQ_HEAD(dm_target_head, dm_target); 43 44 static struct dm_target_head dm_target_list = 45 TAILQ_HEAD_INITIALIZER(dm_target_list); 46 47 kmutex_t dm_target_mutex; 48 49 /* 50 * Called indirectly from dm_table_load_ioct to mark target as used. 51 */ 52 void 53 dm_target_busy(dm_target_t *target) 54 { 55 target->ref_cnt++; 56 } 57 58 void 59 dm_target_unbusy(dm_target_t *target) 60 { 61 target->ref_cnt--; 62 } 63 64 dm_target_t * 65 dm_target_lookup(const char *dm_target_name) 66 { 67 dm_target_t *dmt; 68 69 dmt = NULL; 70 71 mutex_enter(&dm_target_mutex); 72 73 if (dm_target_name != NULL) 74 dmt = dm_target_lookup_name(dm_target_name); 75 76 if (dmt != NULL) 77 dm_target_busy(dmt); 78 79 mutex_exit(&dm_target_mutex); 80 81 return dmt; 82 } 83 84 /* 85 * Search for name in TAIL and return apropriate pointer. 86 */ 87 static dm_target_t* 88 dm_target_lookup_name(const char *dm_target_name) 89 { 90 dm_target_t *dm_target; 91 int dlen; int slen; 92 93 slen = strlen(dm_target_name) + 1; 94 95 TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 96 dlen = strlen(dm_target->name) + 1; 97 98 if (dlen != slen) 99 continue; 100 101 if (strncmp(dm_target_name, dm_target->name, slen) == 0){ 102 return dm_target; 103 } 104 } 105 106 return NULL; 107 } 108 109 /* 110 * Insert new target struct into the TAIL. 111 * dm_target 112 * contains name, version, function pointer to specifif target functions. 113 */ 114 int 115 dm_target_insert(dm_target_t *dm_target) 116 { 117 dm_target_t *dmt; 118 119 mutex_enter(&dm_target_mutex); 120 121 dmt = dm_target_lookup_name(dm_target->name); 122 if (dmt != NULL) { 123 mutex_exit(&dm_target_mutex); 124 return EEXIST; 125 } 126 127 TAILQ_INSERT_TAIL(&dm_target_list, dm_target, dm_target_next); 128 129 mutex_exit(&dm_target_mutex); 130 131 return 0; 132 } 133 134 135 /* 136 * Remove target from TAIL, target is selected with it's name. 137 */ 138 int 139 dm_target_rem(char *dm_target_name) 140 { 141 dm_target_t *dmt; 142 143 KASSERT(dm_target_name != NULL); 144 145 mutex_enter(&dm_target_mutex); 146 147 dmt = dm_target_lookup_name(dm_target_name); 148 if (dmt == NULL) { 149 mutex_exit(&dm_target_mutex); 150 return ENOENT; 151 } 152 153 if (dmt->ref_cnt > 0) { 154 mutex_exit(&dm_target_mutex); 155 return EBUSY; 156 } 157 158 TAILQ_REMOVE(&dm_target_list, 159 dmt, dm_target_next); 160 161 mutex_exit(&dm_target_mutex); 162 163 (void)kmem_free(dmt, sizeof(dm_target_t)); 164 165 return 0; 166 } 167 168 /* 169 * Destroy all targets and remove them from queue. 170 * This routine is called from dm_detach, before module 171 * is unloaded. 172 */ 173 174 int 175 dm_target_destroy(void) 176 { 177 dm_target_t *dm_target; 178 179 mutex_enter(&dm_target_mutex); 180 while (TAILQ_FIRST(&dm_target_list) != NULL){ 181 182 dm_target = TAILQ_FIRST(&dm_target_list); 183 184 TAILQ_REMOVE(&dm_target_list, TAILQ_FIRST(&dm_target_list), 185 dm_target_next); 186 187 (void)kmem_free(dm_target, sizeof(dm_target_t)); 188 } 189 mutex_exit(&dm_target_mutex); 190 191 mutex_destroy(&dm_target_mutex); 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 kmem_zalloc(sizeof(dm_target_t), KM_NOSLEEP); 203 } 204 205 /* 206 * Return prop_array of dm_target dictionaries. 207 */ 208 prop_array_t 209 dm_target_prop_list(void) 210 { 211 prop_array_t target_array,ver; 212 prop_dictionary_t target_dict; 213 dm_target_t *dm_target; 214 215 size_t i; 216 217 target_array = prop_array_create(); 218 219 mutex_enter(&dm_target_mutex); 220 221 TAILQ_FOREACH (dm_target, &dm_target_list, dm_target_next){ 222 223 target_dict = prop_dictionary_create(); 224 ver = prop_array_create(); 225 prop_dictionary_set_cstring(target_dict, DM_TARGETS_NAME, 226 dm_target->name); 227 228 for (i = 0; i < 3; i++) 229 prop_array_add_uint32(ver, dm_target->version[i]); 230 231 prop_dictionary_set(target_dict, DM_TARGETS_VERSION, ver); 232 prop_array_add(target_array, target_dict); 233 234 prop_object_release(ver); 235 prop_object_release(target_dict); 236 } 237 238 mutex_exit(&dm_target_mutex); 239 240 return target_array; 241 } 242 243 /* Initialize dm_target subsystem. */ 244 int 245 dm_target_init(void) 246 { 247 dm_target_t *dmt,*dmt3; 248 int r; 249 250 r = 0; 251 252 mutex_init(&dm_target_mutex, MUTEX_DEFAULT, IPL_NONE); 253 254 dmt = dm_target_alloc("linear"); 255 dmt3 = dm_target_alloc("striped"); 256 257 dmt->version[0] = 1; 258 dmt->version[1] = 0; 259 dmt->version[2] = 2; 260 strlcpy(dmt->name, "linear", DM_MAX_TYPE_NAME); 261 dmt->init = &dm_target_linear_init; 262 dmt->status = &dm_target_linear_status; 263 dmt->strategy = &dm_target_linear_strategy; 264 dmt->deps = &dm_target_linear_deps; 265 dmt->destroy = &dm_target_linear_destroy; 266 dmt->upcall = &dm_target_linear_upcall; 267 268 r = dm_target_insert(dmt); 269 270 dmt3->version[0] = 1; 271 dmt3->version[1] = 0; 272 dmt3->version[2] = 3; 273 strlcpy(dmt3->name, "striped", DM_MAX_TYPE_NAME); 274 dmt3->init = &dm_target_stripe_init; 275 dmt3->status = &dm_target_stripe_status; 276 dmt3->strategy = &dm_target_stripe_strategy; 277 dmt3->deps = &dm_target_stripe_deps; 278 dmt3->destroy = &dm_target_stripe_destroy; 279 dmt3->upcall = &dm_target_stripe_upcall; 280 281 r = dm_target_insert(dmt3); 282 283 #ifdef notyet 284 dmt5->version[0] = 1; 285 dmt5->version[1] = 0; 286 dmt5->version[2] = 5; 287 strlcpy(dmt5->name, "snapshot", DM_MAX_TYPE_NAME); 288 dmt5->init = &dm_target_snapshot_init; 289 dmt5->status = &dm_target_snapshot_status; 290 dmt5->strategy = &dm_target_snapshot_strategy; 291 dmt5->deps = &dm_target_snapshot_deps; 292 dmt5->destroy = &dm_target_snapshot_destroy; 293 dmt5->upcall = &dm_target_snapshot_upcall; 294 295 r = dm_target_insert(dmt5); 296 297 dmt6->version[0] = 1; 298 dmt6->version[1] = 0; 299 dmt6->version[2] = 5; 300 strlcpy(dmt6->name, "snapshot-origin", DM_MAX_TYPE_NAME); 301 dmt6->init = &dm_target_snapshot_orig_init; 302 dmt6->status = &dm_target_snapshot_orig_status; 303 dmt6->strategy = &dm_target_snapshot_orig_strategy; 304 dmt6->deps = &dm_target_snapshot_orig_deps; 305 dmt6->destroy = &dm_target_snapshot_orig_destroy; 306 dmt6->upcall = &dm_target_snapshot_orig_upcall; 307 308 r = dm_target_insert(dmt6); 309 #endif 310 311 return r; 312 } 313