1 /* $NetBSD: dm_dev.c,v 1.4 2009/03/18 10:22:39 cegger 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/disk.h> 36 #include <sys/disklabel.h> 37 #include <sys/ioctl.h> 38 #include <sys/ioccom.h> 39 #include <sys/kmem.h> 40 41 #include "netbsd-dm.h" 42 #include "dm.h" 43 44 static dm_dev_t* dm_dev_lookup_name(const char *); 45 static dm_dev_t* dm_dev_lookup_uuid(const char *); 46 static dm_dev_t* dm_dev_lookup_minor(int); 47 48 static struct dm_dev_head dm_dev_list = 49 TAILQ_HEAD_INITIALIZER(dm_dev_list); 50 51 kmutex_t dm_dev_mutex; 52 53 __inline static void 54 disable_dev(dm_dev_t *dmv) 55 { 56 TAILQ_REMOVE(&dm_dev_list, dmv, next_devlist); 57 mutex_enter(&dmv->dev_mtx); 58 mutex_exit(&dm_dev_mutex); 59 while(dmv->ref_cnt != 0) 60 cv_wait(&dmv->dev_cv, &dmv->dev_mtx); 61 mutex_exit(&dmv->dev_mtx); 62 } 63 64 /* 65 * Generic function used to lookup dm_dev_t. Calling with dm_dev_name 66 * and dm_dev_uuid NULL is allowed. 67 */ 68 dm_dev_t* 69 dm_dev_lookup(const char *dm_dev_name, const char *dm_dev_uuid, 70 int dm_dev_minor) 71 { 72 dm_dev_t *dmv; 73 74 dmv = NULL; 75 mutex_enter(&dm_dev_mutex); 76 77 /* KASSERT(dm_dev_name != NULL && dm_dev_uuid != NULL && dm_dev_minor > 0); */ 78 if (dm_dev_minor > 0) 79 if ((dmv = dm_dev_lookup_minor(dm_dev_minor)) != NULL){ 80 dm_dev_busy(dmv); 81 mutex_exit(&dm_dev_mutex); 82 return dmv; 83 } 84 85 if (dm_dev_name != NULL) 86 if ((dmv = dm_dev_lookup_name(dm_dev_name)) != NULL){ 87 dm_dev_busy(dmv); 88 mutex_exit(&dm_dev_mutex); 89 return dmv; 90 } 91 92 if (dm_dev_uuid != NULL) 93 if ((dmv = dm_dev_lookup_uuid(dm_dev_uuid)) != NULL){ 94 dm_dev_busy(dmv); 95 mutex_exit(&dm_dev_mutex); 96 return dmv; 97 } 98 mutex_exit(&dm_dev_mutex); 99 return NULL; 100 } 101 102 103 /* 104 * Lookup device with its minor number. 105 */ 106 static dm_dev_t* 107 dm_dev_lookup_minor(int dm_dev_minor) 108 { 109 dm_dev_t *dmv; 110 111 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){ 112 if (dm_dev_minor == dmv->minor) 113 return dmv; 114 } 115 116 return NULL; 117 } 118 119 /* 120 * Lookup device with it's device name. 121 */ 122 static dm_dev_t* 123 dm_dev_lookup_name(const char *dm_dev_name) 124 { 125 dm_dev_t *dmv; 126 int dlen; int slen; 127 128 slen = strlen(dm_dev_name); 129 130 if (slen == 0) 131 return NULL; 132 133 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){ 134 135 dlen = strlen(dmv->name); 136 137 if(slen != dlen) 138 continue; 139 140 if (strncmp(dm_dev_name, dmv->name, slen) == 0) 141 return dmv; 142 } 143 144 return NULL; 145 } 146 147 /* 148 * Lookup device with it's device uuid. Used mostly by LVM2tools. 149 */ 150 static dm_dev_t* 151 dm_dev_lookup_uuid(const char *dm_dev_uuid) 152 { 153 dm_dev_t *dmv; 154 size_t len; 155 156 len = 0; 157 len = strlen(dm_dev_uuid); 158 159 if (len == 0) 160 return NULL; 161 162 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){ 163 164 if (strlen(dmv->uuid) != len) 165 continue; 166 167 if (strncmp(dm_dev_uuid, dmv->uuid, strlen(dmv->uuid)) == 0) 168 return dmv; 169 } 170 171 return NULL; 172 } 173 174 /* 175 * Insert new device to the global list of devices. 176 */ 177 int 178 dm_dev_insert(dm_dev_t *dev) 179 { 180 dm_dev_t *dmv; 181 int r; 182 183 dmv = NULL; 184 r = 0; 185 186 KASSERT(dev != NULL); 187 mutex_enter(&dm_dev_mutex); 188 if (((dmv = dm_dev_lookup_uuid(dev->uuid)) == NULL) && 189 ((dmv = dm_dev_lookup_name(dev->name)) == NULL) && 190 ((dmv = dm_dev_lookup_minor(dev->minor)) == NULL)){ 191 192 TAILQ_INSERT_TAIL(&dm_dev_list, dev, next_devlist); 193 194 } else 195 r = EEXIST; 196 197 mutex_exit(&dm_dev_mutex); 198 return r; 199 } 200 201 #ifdef notyet 202 /* 203 * Lookup device with its minor number. 204 */ 205 int 206 dm_dev_test_minor(int dm_dev_minor) 207 { 208 dm_dev_t *dmv; 209 210 mutex_enter(&dm_dev_mutex); 211 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){ 212 if (dm_dev_minor == dmv->minor){ 213 mutex_exit(&dm_dev_mutex); 214 return 1; 215 } 216 } 217 mutex_exit(&dm_dev_mutex); 218 219 return 0; 220 } 221 #endif 222 223 /* 224 * Remove device selected with dm_dev from global list of devices. 225 */ 226 dm_dev_t* 227 dm_dev_rem(const char *dm_dev_name, const char *dm_dev_uuid, 228 int dm_dev_minor) 229 { 230 dm_dev_t *dmv; 231 dmv = NULL; 232 233 mutex_enter(&dm_dev_mutex); 234 235 if (dm_dev_minor > 0) 236 if ((dmv = dm_dev_lookup_minor(dm_dev_minor)) != NULL){ 237 disable_dev(dmv); 238 return dmv; 239 } 240 241 if (dm_dev_name != NULL) 242 if ((dmv = dm_dev_lookup_name(dm_dev_name)) != NULL){ 243 disable_dev(dmv); 244 return dmv; 245 } 246 247 if (dm_dev_uuid != NULL) 248 if ((dmv = dm_dev_lookup_name(dm_dev_uuid)) != NULL){ 249 disable_dev(dmv); 250 return dmv; 251 } 252 mutex_exit(&dm_dev_mutex); 253 254 return NULL; 255 } 256 257 /* 258 * Destroy all devices created in device-mapper. Remove all tables 259 * free all allocated memmory. 260 */ 261 int 262 dm_dev_destroy(void) 263 { 264 dm_dev_t *dmv; 265 mutex_enter(&dm_dev_mutex); 266 267 while (TAILQ_FIRST(&dm_dev_list) != NULL){ 268 269 dmv = TAILQ_FIRST(&dm_dev_list); 270 271 TAILQ_REMOVE(&dm_dev_list, TAILQ_FIRST(&dm_dev_list), 272 next_devlist); 273 274 mutex_enter(&dmv->dev_mtx); 275 276 while (dmv->ref_cnt != 0) 277 cv_wait(&dmv->dev_cv, &dmv->dev_mtx); 278 279 /* Destroy active table first. */ 280 dm_table_destroy(&dmv->table_head, DM_TABLE_ACTIVE); 281 282 /* Destroy inactive table if exits, too. */ 283 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); 284 285 dm_table_head_destroy(&dmv->table_head); 286 287 mutex_exit(&dmv->dev_mtx); 288 mutex_destroy(&dmv->dev_mtx); 289 cv_destroy(&dmv->dev_cv); 290 291 (void)kmem_free(dmv, sizeof(dm_dev_t)); 292 } 293 mutex_exit(&dm_dev_mutex); 294 295 mutex_destroy(&dm_dev_mutex); 296 return 0; 297 } 298 299 /* 300 * Allocate new device entry. 301 */ 302 dm_dev_t* 303 dm_dev_alloc(void) 304 { 305 dm_dev_t *dmv; 306 307 dmv = kmem_zalloc(sizeof(dm_dev_t), KM_NOSLEEP); 308 309 if(dmv != NULL) 310 dmv->diskp = kmem_zalloc(sizeof(struct disk), KM_NOSLEEP); 311 312 return dmv; 313 } 314 315 /* 316 * Freed device entry. 317 */ 318 int 319 dm_dev_free(dm_dev_t *dmv) 320 { 321 KASSERT(dmv != NULL); 322 323 if(dmv->diskp != NULL) 324 (void)kmem_free(dmv->diskp, sizeof(struct disk)); 325 326 (void)kmem_free(dmv, sizeof(dm_dev_t)); 327 328 return 0; 329 } 330 331 void 332 dm_dev_busy(dm_dev_t *dmv) 333 { 334 mutex_enter(&dmv->dev_mtx); 335 dmv->ref_cnt++; 336 mutex_exit(&dmv->dev_mtx); 337 } 338 339 void 340 dm_dev_unbusy(dm_dev_t *dmv) 341 { 342 KASSERT(dmv->ref_cnt != 0); 343 344 mutex_enter(&dmv->dev_mtx); 345 if (--dmv->ref_cnt == 0) 346 cv_broadcast(&dmv->dev_cv); 347 mutex_exit(&dmv->dev_mtx); 348 } 349 350 /* 351 * Return prop_array of dm_targer_list dictionaries. 352 */ 353 prop_array_t 354 dm_dev_prop_list(void) 355 { 356 dm_dev_t *dmv; 357 prop_array_t dev_array; 358 prop_dictionary_t dev_dict; 359 360 dev_array = prop_array_create(); 361 362 mutex_enter(&dm_dev_mutex); 363 364 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) { 365 dev_dict = prop_dictionary_create(); 366 367 prop_dictionary_set_cstring(dev_dict, DM_DEV_NAME, dmv->name); 368 prop_dictionary_set_uint32(dev_dict, DM_DEV_DEV, dmv->minor); 369 370 prop_array_add(dev_array, dev_dict); 371 prop_object_release(dev_dict); 372 } 373 374 mutex_exit(&dm_dev_mutex); 375 return dev_array; 376 } 377 378 /* 379 * Initialize global device mutex. 380 */ 381 int 382 dm_dev_init(void) 383 { 384 TAILQ_INIT(&dm_dev_list); /* initialize global dev list */ 385 mutex_init(&dm_dev_mutex, MUTEX_DEFAULT, IPL_NONE); 386 return 0; 387 } 388