diff options
Diffstat (limited to 'sys/dev/dm/dm_dev.c')
| -rw-r--r-- | sys/dev/dm/dm_dev.c | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/sys/dev/dm/dm_dev.c b/sys/dev/dm/dm_dev.c new file mode 100644 index 00000000000..fa5ce67636b --- /dev/null +++ b/sys/dev/dm/dm_dev.c @@ -0,0 +1,384 @@ +/* $NetBSD: dm_dev.c,v 1.2 2008/12/19 15:24:03 haad Exp $ */ + +/* + * Copyright (c) 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Adam Hamsik. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/param.h> + +#include <sys/disklabel.h> +#include <sys/ioctl.h> +#include <sys/ioccom.h> +#include <sys/kmem.h> + +#include "netbsd-dm.h" +#include "dm.h" + +static dm_dev_t* dm_dev_lookup_name(const char *); +static dm_dev_t* dm_dev_lookup_uuid(const char *); +static dm_dev_t* dm_dev_lookup_minor(int); + +static struct dm_dev_head dm_dev_list = +TAILQ_HEAD_INITIALIZER(dm_dev_list); + +kmutex_t dm_dev_mutex; + +__inline static void +disable_dev(dm_dev_t *dmv) +{ + TAILQ_REMOVE(&dm_dev_list, dmv, next_devlist); + mutex_enter(&dmv->dev_mtx); + mutex_exit(&dm_dev_mutex); + while(dmv->ref_cnt != 0) + cv_wait(&dmv->dev_cv, &dmv->dev_mtx); + mutex_exit(&dmv->dev_mtx); +} + +/* + * Generic function used to lookup dm_dev_t. Calling with dm_dev_name + * and dm_dev_uuid NULL is allowed. + */ +dm_dev_t* +dm_dev_lookup(const char *dm_dev_name, const char *dm_dev_uuid, + int dm_dev_minor) +{ + dm_dev_t *dmv; + + dmv = NULL; + mutex_enter(&dm_dev_mutex); + + /* KASSERT(dm_dev_name != NULL && dm_dev_uuid != NULL && dm_dev_minor > 0); */ + if (dm_dev_minor > 0) + if ((dmv = dm_dev_lookup_minor(dm_dev_minor)) != NULL){ + dm_dev_busy(dmv); + mutex_exit(&dm_dev_mutex); + return dmv; + } + + if (dm_dev_name != NULL) + if ((dmv = dm_dev_lookup_name(dm_dev_name)) != NULL){ + dm_dev_busy(dmv); + mutex_exit(&dm_dev_mutex); + return dmv; + } + + if (dm_dev_uuid != NULL) + if ((dmv = dm_dev_lookup_name(dm_dev_uuid)) != NULL){ + dm_dev_busy(dmv); + mutex_exit(&dm_dev_mutex); + return dmv; + } + mutex_exit(&dm_dev_mutex); + return NULL; +} + + +/* + * Lookup device with its minor number. + */ +static dm_dev_t* +dm_dev_lookup_minor(int dm_dev_minor) +{ + dm_dev_t *dmv; + + TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){ + if (dm_dev_minor == dmv->minor) + return dmv; + } + + return NULL; +} + +/* + * Lookup device with it's device name. + */ +static dm_dev_t* +dm_dev_lookup_name(const char *dm_dev_name) +{ + dm_dev_t *dmv; + int dlen; int slen; + + slen = strlen(dm_dev_name); + + if (slen == 0) + return NULL; + + TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){ + + dlen = strlen(dmv->name); + + if(slen != dlen) + continue; + + if (strncmp(dm_dev_name, dmv->name, slen) == 0) + return dmv; + } + + return NULL; +} + +/* + * Lookup device with it's device uuid. Used mostly by LVM2tools. + */ +static dm_dev_t* +dm_dev_lookup_uuid(const char *dm_dev_uuid) +{ + dm_dev_t *dmv; + size_t len; + + len = 0; + len = strlen(dm_dev_uuid); + + if (len == 0) + return NULL; + + TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){ + + if (strlen(dmv->uuid) != len) + continue; + + if (strncmp(dm_dev_uuid, dmv->uuid, strlen(dmv->uuid)) == 0) + return dmv; + } + + return NULL; +} + +/* + * Insert new device to the global list of devices. + */ +int +dm_dev_insert(dm_dev_t *dev) +{ + dm_dev_t *dmv; + int r; + + dmv = NULL; + r = 0; + + KASSERT(dev != NULL); + mutex_enter(&dm_dev_mutex); + if (((dmv = dm_dev_lookup_uuid(dev->uuid)) == NULL) && + ((dmv = dm_dev_lookup_name(dev->name)) == NULL) && + ((dmv = dm_dev_lookup_minor(dev->minor)) == NULL)){ + + TAILQ_INSERT_TAIL(&dm_dev_list, dev, next_devlist); + + } else + r = EEXIST; + + mutex_exit(&dm_dev_mutex); + return r; +} + +#ifdef notyet +/* + * Lookup device with its minor number. + */ +int +dm_dev_test_minor(int dm_dev_minor) +{ + dm_dev_t *dmv; + + mutex_enter(&dm_dev_mutex); + TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist){ + if (dm_dev_minor == dmv->minor){ + mutex_exit(&dm_dev_mutex); + return 1; + } + } + mutex_exit(&dm_dev_mutex); + + return 0; +} +#endif + +/* + * Remove device selected with dm_dev from global list of devices. + */ +dm_dev_t* +dm_dev_rem(const char *dm_dev_name, const char *dm_dev_uuid, + int dm_dev_minor) +{ + dm_dev_t *dmv; + dmv = NULL; + + mutex_enter(&dm_dev_mutex); + + if (dm_dev_minor > 0) + if ((dmv = dm_dev_lookup_minor(dm_dev_minor)) != NULL){ + disable_dev(dmv); + return dmv; + } + + if (dm_dev_name != NULL) + if ((dmv = dm_dev_lookup_name(dm_dev_name)) != NULL){ + disable_dev(dmv); + return dmv; + } + + if (dm_dev_uuid != NULL) + if ((dmv = dm_dev_lookup_name(dm_dev_uuid)) != NULL){ + disable_dev(dmv); + return dmv; + } + mutex_exit(&dm_dev_mutex); + + return NULL; +} + +/* + * Destroy all devices created in device-mapper. Remove all tables + * free all allocated memmory. + */ +int +dm_dev_destroy(void) +{ + dm_dev_t *dmv; + mutex_enter(&dm_dev_mutex); + + while (TAILQ_FIRST(&dm_dev_list) != NULL){ + + dmv = TAILQ_FIRST(&dm_dev_list); + + TAILQ_REMOVE(&dm_dev_list, TAILQ_FIRST(&dm_dev_list), + next_devlist); + + mutex_enter(&dmv->dev_mtx); + + while (dmv->ref_cnt != 0) + cv_wait(&dmv->dev_cv, &dmv->dev_mtx); + + /* Destroy active table first. */ + dm_table_destroy(&dmv->table_head, DM_TABLE_ACTIVE); + + /* Destroy inactive table if exits, too. */ + dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE); + + dm_table_head_destroy(&dmv->table_head); + + mutex_exit(&dmv->dev_mtx); + mutex_destroy(&dmv->dev_mtx); + cv_destroy(&dmv->dev_cv); + + (void)kmem_free(dmv, sizeof(dm_dev_t)); + } + mutex_exit(&dm_dev_mutex); + + mutex_destroy(&dm_dev_mutex); + return 0; +} + +/* + * Allocate new device entry. + */ +dm_dev_t* +dm_dev_alloc() +{ + dm_dev_t *dmv; + + dmv = kmem_zalloc(sizeof(dm_dev_t), KM_NOSLEEP); + dmv->dk_label = kmem_zalloc(sizeof(struct disklabel), KM_NOSLEEP); + + return dmv; +} + +/* + * Freed device entry. + */ +int +dm_dev_free(dm_dev_t *dmv) +{ + KASSERT(dmv != NULL); + + if (dmv->dk_label != NULL) + (void)kmem_free(dmv->dk_label, sizeof(struct disklabel)); + + (void)kmem_free(dmv, sizeof(dm_dev_t)); + + return 0; +} + +void +dm_dev_busy(dm_dev_t *dmv) +{ + mutex_enter(&dmv->dev_mtx); + dmv->ref_cnt++; + mutex_exit(&dmv->dev_mtx); +} + +void +dm_dev_unbusy(dm_dev_t *dmv) +{ + KASSERT(dmv->ref_cnt != 0); + + mutex_enter(&dmv->dev_mtx); + if (--dmv->ref_cnt == 0) + cv_broadcast(&dmv->dev_cv); + mutex_exit(&dmv->dev_mtx); +} + +/* + * Return prop_array of dm_targer_list dictionaries. + */ +prop_array_t +dm_dev_prop_list(void) +{ + dm_dev_t *dmv; + prop_array_t dev_array; + prop_dictionary_t dev_dict; + + dev_array = prop_array_create(); + + mutex_enter(&dm_dev_mutex); + + TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) { + dev_dict = prop_dictionary_create(); + + prop_dictionary_set_cstring(dev_dict, DM_DEV_NAME, dmv->name); + prop_dictionary_set_uint32(dev_dict, DM_DEV_DEV, dmv->minor); + + prop_array_add(dev_array, dev_dict); + prop_object_release(dev_dict); + } + + mutex_exit(&dm_dev_mutex); + return dev_array; +} + +/* + * Initialize global device mutex. + */ +int +dm_dev_init() +{ + TAILQ_INIT(&dm_dev_list); /* initialize global dev list */ + mutex_init(&dm_dev_mutex, MUTEX_DEFAULT, IPL_NONE); + return 0; +} |
