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