1 /* $NetBSD: dm_dev.c,v 1.8 2010/01/04 00:19:08 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/disk.h> 36 #include <sys/disklabel.h> 37 #include <sys/ioccom.h> 38 #include <sys/malloc.h> 39 #include <dev/disk/dm/dm.h> 40 41 #include "netbsd-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 struct lock dm_dev_mutex; 51 52 /* dm_dev_mutex must be holdby caller before using disable_dev. */ 53 static void 54 disable_dev(dm_dev_t * dmv) 55 { 56 TAILQ_REMOVE(&dm_dev_list, dmv, next_devlist); 57 lockmgr(&dmv->dev_mtx, LK_EXCLUSIVE); 58 lockmgr(&dm_dev_mutex, LK_RELEASE); 59 while (dmv->ref_cnt != 0) 60 cv_wait(&dmv->dev_cv, &dmv->dev_mtx); 61 lockmgr(&dmv->dev_mtx, LK_RELEASE); 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 lockmgr(&dm_dev_mutex, LK_EXCLUSIVE); 75 76 /* KKASSERT(dm_dev_name != NULL && dm_dev_uuid != NULL && dm_dev_minor 77 * > 0); */ 78 if (dm_dev_minor > 0) 79 if ((dmv = dm_dev_lookup_minor(dm_dev_minor)) != NULL) { 80 dm_dev_busy(dmv); 81 lockmgr(&dm_dev_mutex, LK_RELEASE); 82 return dmv; 83 } 84 if (dm_dev_name != NULL) 85 if ((dmv = dm_dev_lookup_name(dm_dev_name)) != NULL) { 86 dm_dev_busy(dmv); 87 lockmgr(&dm_dev_mutex, LK_RELEASE); 88 return dmv; 89 } 90 if (dm_dev_uuid != NULL) 91 if ((dmv = dm_dev_lookup_uuid(dm_dev_uuid)) != NULL) { 92 dm_dev_busy(dmv); 93 lockmgr(&dm_dev_mutex, LK_RELEASE); 94 return dmv; 95 } 96 lockmgr(&dm_dev_mutex, LK_RELEASE); 97 return NULL; 98 } 99 100 101 /* 102 * Lookup device with its minor number. 103 */ 104 static dm_dev_t * 105 dm_dev_lookup_minor(int dm_dev_minor) 106 { 107 dm_dev_t *dmv; 108 109 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) { 110 if (dm_dev_minor == dmv->minor) 111 return dmv; 112 } 113 114 return NULL; 115 } 116 /* 117 * Lookup device with it's device name. 118 */ 119 static dm_dev_t * 120 dm_dev_lookup_name(const char *dm_dev_name) 121 { 122 dm_dev_t *dmv; 123 124 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) { 125 if (strcmp(dm_dev_name, dmv->name) == 0) 126 return dmv; 127 } 128 129 return NULL; 130 } 131 /* 132 * Lookup device with it's device uuid. Used mostly by LVM2tools. 133 */ 134 static dm_dev_t * 135 dm_dev_lookup_uuid(const char *dm_dev_uuid) 136 { 137 dm_dev_t *dmv; 138 139 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) { 140 if (strcmp(dm_dev_uuid, dmv->uuid) == 0) 141 return dmv; 142 } 143 144 return NULL; 145 } 146 /* 147 * Insert new device to the global list of devices. 148 */ 149 int 150 dm_dev_insert(dm_dev_t * dev) 151 { 152 dm_dev_t *dmv; 153 int r; 154 155 dmv = NULL; 156 r = 0; 157 158 KKASSERT(dev != NULL); 159 lockmgr(&dm_dev_mutex, LK_EXCLUSIVE); 160 if (((dmv = dm_dev_lookup_uuid(dev->uuid)) == NULL) && 161 ((dmv = dm_dev_lookup_name(dev->name)) == NULL) && 162 ((dmv = dm_dev_lookup_minor(dev->minor)) == NULL)) { 163 164 TAILQ_INSERT_TAIL(&dm_dev_list, dev, next_devlist); 165 166 } else 167 r = EEXIST; 168 169 lockmgr(&dm_dev_mutex, LK_RELEASE); 170 return r; 171 } 172 173 /* 174 * Remove device selected with dm_dev from global list of devices. 175 */ 176 dm_dev_t * 177 dm_dev_rem(dm_dev_t *dmv, const char *dm_dev_name, const char *dm_dev_uuid, 178 int dm_dev_minor) 179 { 180 lockmgr(&dm_dev_mutex, LK_EXCLUSIVE); 181 182 if (dmv != NULL) { 183 disable_dev(dmv); 184 return dmv; 185 } 186 187 if (dm_dev_minor > 0) 188 if ((dmv = dm_dev_lookup_minor(dm_dev_minor)) != NULL) { 189 disable_dev(dmv); 190 return dmv; 191 } 192 if (dm_dev_name != NULL) 193 if ((dmv = dm_dev_lookup_name(dm_dev_name)) != NULL) { 194 disable_dev(dmv); 195 return dmv; 196 } 197 if (dm_dev_uuid != NULL) 198 if ((dmv = dm_dev_lookup_name(dm_dev_uuid)) != NULL) { 199 disable_dev(dmv); 200 return dmv; 201 } 202 lockmgr(&dm_dev_mutex, LK_RELEASE); 203 204 return NULL; 205 } 206 /* 207 * Destroy all devices created in device-mapper. Remove all tables 208 * free all allocated memmory. 209 */ 210 int 211 dm_dev_destroy(void) 212 { 213 dm_dev_t *dmv; 214 lockmgr(&dm_dev_mutex, LK_EXCLUSIVE); 215 216 while (TAILQ_FIRST(&dm_dev_list) != NULL) { 217 218 dmv = TAILQ_FIRST(&dm_dev_list); 219 220 TAILQ_REMOVE(&dm_dev_list, TAILQ_FIRST(&dm_dev_list), 221 next_devlist); 222 223 lockmgr(&dmv->dev_mtx, LK_EXCLUSIVE); 224 225 while (dmv->ref_cnt != 0) 226 cv_wait(&dmv->dev_cv, &dmv->dev_mtx); 227 228 /* Destroy active table first. */ 229 dm_table_destroy(&dmv->table_head, DM_TABLE_ACTIVE); 230 231 /* Destroy inactive table if exits, too. */ 232 dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); 233 234 dm_table_head_destroy(&dmv->table_head); 235 236 lockmgr(&dmv->dev_mtx, LK_RELEASE); 237 lockuninit(&dmv->dev_mtx); 238 cv_destroy(&dmv->dev_cv); 239 240 (void) kfree(dmv, M_DM); 241 } 242 lockmgr(&dm_dev_mutex, LK_RELEASE); 243 244 lockuninit(&dm_dev_mutex); 245 return 0; 246 } 247 /* 248 * Allocate new device entry. 249 */ 250 dm_dev_t * 251 dm_dev_alloc(void) 252 { 253 dm_dev_t *dmv; 254 255 dmv = kmalloc(sizeof(dm_dev_t), M_DM, M_WAITOK | M_ZERO); 256 257 if (dmv != NULL) 258 dmv->diskp = kmalloc(sizeof(struct disk), M_DM, M_WAITOK | M_ZERO); 259 260 return dmv; 261 } 262 /* 263 * Freed device entry. 264 */ 265 int 266 dm_dev_free(dm_dev_t * dmv) 267 { 268 KKASSERT(dmv != NULL); 269 270 lockuninit(&dmv->dev_mtx); 271 lockuninit(&dmv->diskp_mtx); 272 cv_destroy(&dmv->dev_cv); 273 274 if (dmv->diskp != NULL) 275 (void) kfree(dmv->diskp, M_DM); 276 277 (void) kfree(dmv, M_DM); 278 279 return 0; 280 } 281 282 void 283 dm_dev_busy(dm_dev_t * dmv) 284 { 285 lockmgr(&dmv->dev_mtx, LK_EXCLUSIVE); 286 dmv->ref_cnt++; 287 lockmgr(&dmv->dev_mtx, LK_RELEASE); 288 } 289 290 void 291 dm_dev_unbusy(dm_dev_t * dmv) 292 { 293 KKASSERT(dmv->ref_cnt != 0); 294 295 lockmgr(&dmv->dev_mtx, LK_EXCLUSIVE); 296 if (--dmv->ref_cnt == 0) 297 cv_broadcast(&dmv->dev_cv); 298 lockmgr(&dmv->dev_mtx, LK_RELEASE); 299 } 300 /* 301 * Return prop_array of dm_targer_list dictionaries. 302 */ 303 prop_array_t 304 dm_dev_prop_list(void) 305 { 306 dm_dev_t *dmv; 307 prop_array_t dev_array; 308 prop_dictionary_t dev_dict; 309 310 dev_array = prop_array_create(); 311 312 lockmgr(&dm_dev_mutex, LK_EXCLUSIVE); 313 314 TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) { 315 dev_dict = prop_dictionary_create(); 316 317 prop_dictionary_set_cstring(dev_dict, DM_DEV_NAME, dmv->name); 318 prop_dictionary_set_uint32(dev_dict, DM_DEV_DEV, dmv->minor); 319 320 prop_array_add(dev_array, dev_dict); 321 prop_object_release(dev_dict); 322 } 323 324 lockmgr(&dm_dev_mutex, LK_RELEASE); 325 return dev_array; 326 } 327 /* 328 * Initialize global device mutex. 329 */ 330 int 331 dm_dev_init(void) 332 { 333 TAILQ_INIT(&dm_dev_list); /* initialize global dev list */ 334 lockinit(&dm_dev_mutex, "dmdevlist", 0, LK_CANRECURSE); 335 return 0; 336 } 337