Home | History | Annotate | Line # | Download | only in dm
      1  1.19    andvar /*        $NetBSD: dm_dev.c,v 1.19 2021/08/21 22:23:33 andvar Exp $      */
      2   1.2      haad 
      3   1.2      haad /*
      4   1.2      haad  * Copyright (c) 2008 The NetBSD Foundation, Inc.
      5   1.2      haad  * All rights reserved.
      6   1.2      haad  *
      7   1.2      haad  * This code is derived from software contributed to The NetBSD Foundation
      8   1.2      haad  * by Adam Hamsik.
      9   1.2      haad  *
     10   1.2      haad  * Redistribution and use in source and binary forms, with or without
     11   1.2      haad  * modification, are permitted provided that the following conditions
     12   1.2      haad  * are met:
     13   1.2      haad  * 1. Redistributions of source code must retain the above copyright
     14   1.2      haad  *    notice, this list of conditions and the following disclaimer.
     15   1.2      haad  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.2      haad  *    notice, this list of conditions and the following disclaimer in the
     17   1.2      haad  *    documentation and/or other materials provided with the distribution.
     18   1.2      haad  *
     19   1.2      haad  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.2      haad  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.2      haad  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.2      haad  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.2      haad  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.2      haad  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.2      haad  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.2      haad  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.2      haad  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.2      haad  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.2      haad  * POSSIBILITY OF SUCH DAMAGE.
     30   1.2      haad  */
     31  1.11  christos #include <sys/cdefs.h>
     32  1.19    andvar __KERNEL_RCSID(0, "$NetBSD: dm_dev.c,v 1.19 2021/08/21 22:23:33 andvar Exp $");
     33   1.2      haad 
     34   1.2      haad #include <sys/types.h>
     35   1.2      haad #include <sys/param.h>
     36   1.3      haad #include <sys/disk.h>
     37   1.2      haad #include <sys/disklabel.h>
     38   1.2      haad #include <sys/ioctl.h>
     39   1.2      haad #include <sys/ioccom.h>
     40   1.2      haad #include <sys/kmem.h>
     41   1.2      haad 
     42   1.2      haad #include "netbsd-dm.h"
     43   1.2      haad #include "dm.h"
     44   1.2      haad 
     45   1.8      haad static dm_dev_t *dm_dev_lookup_name(const char *);
     46   1.8      haad static dm_dev_t *dm_dev_lookup_uuid(const char *);
     47   1.8      haad static dm_dev_t *dm_dev_lookup_minor(int);
     48   1.2      haad 
     49  1.16   tkusumi static struct dm_dev_head dm_dev_list = TAILQ_HEAD_INITIALIZER(dm_dev_list);
     50   1.2      haad 
     51  1.12   tkusumi static kmutex_t dm_dev_mutex;
     52   1.2      haad 
     53   1.7      haad /* dm_dev_mutex must be holdby caller before using disable_dev. */
     54  1.17   tkusumi static void
     55  1.14   tkusumi disable_dev(dm_dev_t *dmv)
     56   1.2      haad {
     57  1.16   tkusumi 
     58   1.8      haad 	TAILQ_REMOVE(&dm_dev_list, dmv, next_devlist);
     59   1.8      haad 	mutex_enter(&dmv->dev_mtx);
     60   1.8      haad 	mutex_exit(&dm_dev_mutex);
     61   1.8      haad 	while (dmv->ref_cnt != 0)
     62   1.8      haad 		cv_wait(&dmv->dev_cv, &dmv->dev_mtx);
     63   1.8      haad 	mutex_exit(&dmv->dev_mtx);
     64   1.8      haad }
     65  1.11  christos 
     66   1.2      haad /*
     67   1.8      haad  * Generic function used to lookup dm_dev_t. Calling with dm_dev_name
     68   1.2      haad  * and dm_dev_uuid NULL is allowed.
     69   1.2      haad  */
     70   1.8      haad dm_dev_t *
     71   1.2      haad dm_dev_lookup(const char *dm_dev_name, const char *dm_dev_uuid,
     72   1.8      haad     int dm_dev_minor)
     73   1.2      haad {
     74   1.2      haad 	dm_dev_t *dmv;
     75   1.8      haad 
     76   1.2      haad 	mutex_enter(&dm_dev_mutex);
     77   1.8      haad 	/* KASSERT(dm_dev_name != NULL && dm_dev_uuid != NULL && dm_dev_minor
     78   1.8      haad 	 * > 0); */
     79   1.2      haad 	if (dm_dev_minor > 0)
     80   1.8      haad 		if ((dmv = dm_dev_lookup_minor(dm_dev_minor)) != NULL) {
     81   1.2      haad 			dm_dev_busy(dmv);
     82   1.2      haad 			mutex_exit(&dm_dev_mutex);
     83   1.2      haad 			return dmv;
     84   1.2      haad 		}
     85   1.8      haad 	if (dm_dev_name != NULL)
     86   1.8      haad 		if ((dmv = dm_dev_lookup_name(dm_dev_name)) != NULL) {
     87   1.2      haad 			dm_dev_busy(dmv);
     88   1.2      haad 			mutex_exit(&dm_dev_mutex);
     89   1.8      haad 			return dmv;
     90   1.2      haad 		}
     91   1.2      haad 	if (dm_dev_uuid != NULL)
     92   1.8      haad 		if ((dmv = dm_dev_lookup_uuid(dm_dev_uuid)) != NULL) {
     93   1.2      haad 			dm_dev_busy(dmv);
     94   1.2      haad 			mutex_exit(&dm_dev_mutex);
     95   1.2      haad 			return dmv;
     96   1.2      haad 		}
     97   1.8      haad 	mutex_exit(&dm_dev_mutex);
     98  1.16   tkusumi 
     99   1.8      haad 	return NULL;
    100   1.2      haad }
    101   1.2      haad 
    102   1.2      haad /*
    103   1.2      haad  * Lookup device with its minor number.
    104   1.2      haad  */
    105   1.8      haad static dm_dev_t *
    106   1.2      haad dm_dev_lookup_minor(int dm_dev_minor)
    107   1.2      haad {
    108   1.2      haad 	dm_dev_t *dmv;
    109   1.8      haad 
    110  1.16   tkusumi 	TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist)
    111   1.2      haad 		if (dm_dev_minor == dmv->minor)
    112   1.2      haad 			return dmv;
    113   1.8      haad 
    114   1.2      haad 	return NULL;
    115   1.2      haad }
    116  1.11  christos 
    117   1.2      haad /*
    118   1.9       snj  * Lookup device with its device name.
    119   1.2      haad  */
    120   1.8      haad static dm_dev_t *
    121   1.2      haad dm_dev_lookup_name(const char *dm_dev_name)
    122   1.2      haad {
    123   1.2      haad 	dm_dev_t *dmv;
    124  1.11  christos 	size_t dlen;
    125  1.11  christos 	size_t slen;
    126   1.2      haad 
    127   1.2      haad 	slen = strlen(dm_dev_name);
    128   1.2      haad 
    129   1.2      haad 	if (slen == 0)
    130   1.2      haad 		return NULL;
    131   1.8      haad 
    132   1.8      haad 	TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) {
    133   1.2      haad 		dlen = strlen(dmv->name);
    134   1.8      haad 
    135   1.8      haad 		if (slen != dlen)
    136   1.2      haad 			continue;
    137   1.2      haad 
    138   1.2      haad 		if (strncmp(dm_dev_name, dmv->name, slen) == 0)
    139   1.2      haad 			return dmv;
    140   1.2      haad 	}
    141   1.2      haad 
    142   1.2      haad 	return NULL;
    143   1.2      haad }
    144  1.11  christos 
    145   1.2      haad /*
    146   1.9       snj  * Lookup device with its device uuid. Used mostly by LVM2tools.
    147   1.2      haad  */
    148   1.8      haad static dm_dev_t *
    149   1.2      haad dm_dev_lookup_uuid(const char *dm_dev_uuid)
    150   1.2      haad {
    151   1.2      haad 	dm_dev_t *dmv;
    152   1.2      haad 	size_t len;
    153   1.8      haad 
    154   1.2      haad 	len = 0;
    155   1.2      haad 	len = strlen(dm_dev_uuid);
    156   1.8      haad 
    157   1.2      haad 	if (len == 0)
    158   1.2      haad 		return NULL;
    159   1.2      haad 
    160   1.8      haad 	TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) {
    161   1.2      haad 		if (strlen(dmv->uuid) != len)
    162   1.2      haad 			continue;
    163   1.8      haad 
    164   1.2      haad 		if (strncmp(dm_dev_uuid, dmv->uuid, strlen(dmv->uuid)) == 0)
    165   1.2      haad 			return dmv;
    166   1.2      haad 	}
    167   1.2      haad 
    168   1.2      haad 	return NULL;
    169   1.2      haad }
    170  1.11  christos 
    171   1.2      haad /*
    172   1.2      haad  * Insert new device to the global list of devices.
    173   1.2      haad  */
    174   1.2      haad int
    175  1.14   tkusumi dm_dev_insert(dm_dev_t *dev)
    176   1.2      haad {
    177   1.2      haad 	dm_dev_t *dmv;
    178   1.2      haad 	int r;
    179   1.2      haad 
    180   1.2      haad 	dmv = NULL;
    181   1.2      haad 	r = 0;
    182   1.8      haad 
    183   1.2      haad 	KASSERT(dev != NULL);
    184   1.2      haad 	mutex_enter(&dm_dev_mutex);
    185   1.2      haad 	if (((dmv = dm_dev_lookup_uuid(dev->uuid)) == NULL) &&
    186   1.2      haad 	    ((dmv = dm_dev_lookup_name(dev->name)) == NULL) &&
    187   1.8      haad 	    ((dmv = dm_dev_lookup_minor(dev->minor)) == NULL)) {
    188   1.2      haad 		TAILQ_INSERT_TAIL(&dm_dev_list, dev, next_devlist);
    189   1.2      haad 	} else
    190   1.2      haad 		r = EEXIST;
    191  1.16   tkusumi 	mutex_exit(&dm_dev_mutex);
    192   1.8      haad 
    193   1.2      haad 	return r;
    194   1.2      haad }
    195  1.11  christos 
    196   1.8      haad #ifdef notyet
    197   1.2      haad /*
    198   1.2      haad  * Lookup device with its minor number.
    199   1.2      haad  */
    200   1.2      haad int
    201   1.2      haad dm_dev_test_minor(int dm_dev_minor)
    202   1.2      haad {
    203   1.2      haad 	dm_dev_t *dmv;
    204   1.8      haad 
    205   1.2      haad 	mutex_enter(&dm_dev_mutex);
    206   1.8      haad 	TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) {
    207   1.8      haad 		if (dm_dev_minor == dmv->minor) {
    208   1.2      haad 			mutex_exit(&dm_dev_mutex);
    209   1.2      haad 			return 1;
    210   1.2      haad 		}
    211   1.2      haad 	}
    212   1.2      haad 	mutex_exit(&dm_dev_mutex);
    213   1.8      haad 
    214   1.2      haad 	return 0;
    215   1.2      haad }
    216   1.2      haad #endif
    217   1.2      haad 
    218   1.7      haad /*
    219   1.7      haad  * dm_dev_lookup_devt look for selected device_t. We keep this routine
    220   1.7      haad  * outside of dm_dev_lookup because it is a temporally solution.
    221   1.7      haad  *
    222   1.7      haad  * TODO: This is a hack autoconf should be more flexible.
    223   1.7      haad  */
    224   1.7      haad dm_dev_t *
    225   1.7      haad dm_dev_detach(device_t devt)
    226   1.7      haad {
    227   1.7      haad 	dm_dev_t *dmv;
    228   1.8      haad 
    229   1.7      haad 	mutex_enter(&dm_dev_mutex);
    230   1.8      haad 	TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) {
    231   1.8      haad 		if (devt == dmv->devt) {
    232   1.7      haad 			disable_dev(dmv);
    233   1.7      haad 			return dmv;
    234   1.7      haad 		}
    235   1.7      haad 	}
    236   1.7      haad 	mutex_exit(&dm_dev_mutex);
    237   1.8      haad 
    238   1.7      haad 	return NULL;
    239   1.7      haad }
    240  1.11  christos 
    241   1.8      haad /*
    242   1.8      haad  * Remove device selected with dm_dev from global list of devices.
    243   1.2      haad  */
    244   1.8      haad dm_dev_t *
    245   1.2      haad dm_dev_rem(const char *dm_dev_name, const char *dm_dev_uuid,
    246   1.8      haad     int dm_dev_minor)
    247   1.8      haad {
    248   1.2      haad 	dm_dev_t *dmv;
    249   1.8      haad 
    250   1.2      haad 	mutex_enter(&dm_dev_mutex);
    251   1.2      haad 	if (dm_dev_minor > 0)
    252   1.8      haad 		if ((dmv = dm_dev_lookup_minor(dm_dev_minor)) != NULL) {
    253   1.2      haad 			disable_dev(dmv);
    254   1.2      haad 			return dmv;
    255   1.2      haad 		}
    256   1.8      haad 	if (dm_dev_name != NULL)
    257   1.8      haad 		if ((dmv = dm_dev_lookup_name(dm_dev_name)) != NULL) {
    258   1.2      haad 			disable_dev(dmv);
    259   1.2      haad 			return dmv;
    260   1.2      haad 		}
    261   1.2      haad 	if (dm_dev_uuid != NULL)
    262   1.8      haad 		if ((dmv = dm_dev_lookup_name(dm_dev_uuid)) != NULL) {
    263   1.2      haad 			disable_dev(dmv);
    264   1.2      haad 			return dmv;
    265   1.2      haad 		}
    266   1.2      haad 	mutex_exit(&dm_dev_mutex);
    267   1.2      haad 
    268   1.2      haad 	return NULL;
    269   1.2      haad }
    270  1.11  christos 
    271   1.2      haad /*
    272   1.2      haad  * Destroy all devices created in device-mapper. Remove all tables
    273  1.19    andvar  * free all allocated memory.
    274   1.2      haad  */
    275   1.2      haad int
    276   1.2      haad dm_dev_destroy(void)
    277   1.2      haad {
    278   1.2      haad 	dm_dev_t *dmv;
    279  1.16   tkusumi 
    280   1.2      haad 	mutex_enter(&dm_dev_mutex);
    281   1.8      haad 	while (TAILQ_FIRST(&dm_dev_list) != NULL) {
    282   1.2      haad 		dmv = TAILQ_FIRST(&dm_dev_list);
    283   1.8      haad 
    284   1.2      haad 		TAILQ_REMOVE(&dm_dev_list, TAILQ_FIRST(&dm_dev_list),
    285   1.2      haad 		    next_devlist);
    286   1.2      haad 
    287   1.2      haad 		mutex_enter(&dmv->dev_mtx);
    288   1.2      haad 
    289   1.2      haad 		while (dmv->ref_cnt != 0)
    290   1.2      haad 			cv_wait(&dmv->dev_cv, &dmv->dev_mtx);
    291   1.8      haad 
    292   1.2      haad 		/* Destroy active table first.  */
    293   1.2      haad 		dm_table_destroy(&dmv->table_head, DM_TABLE_ACTIVE);
    294   1.2      haad 
    295   1.2      haad 		/* Destroy inactive table if exits, too. */
    296   1.2      haad 		dm_table_destroy(&dmv->table_head, DM_TABLE_INACTIVE);
    297   1.2      haad 
    298   1.2      haad 		dm_table_head_destroy(&dmv->table_head);
    299   1.2      haad 
    300   1.2      haad 		mutex_exit(&dmv->dev_mtx);
    301   1.2      haad 		mutex_destroy(&dmv->dev_mtx);
    302   1.2      haad 		cv_destroy(&dmv->dev_cv);
    303   1.8      haad 
    304  1.15   tkusumi 		kmem_free(dmv, sizeof(dm_dev_t));
    305   1.2      haad 	}
    306   1.2      haad 	mutex_exit(&dm_dev_mutex);
    307   1.2      haad 
    308   1.2      haad 	mutex_destroy(&dm_dev_mutex);
    309   1.8      haad 	return 0;
    310   1.2      haad }
    311  1.11  christos 
    312   1.2      haad /*
    313   1.2      haad  * Allocate new device entry.
    314   1.2      haad  */
    315   1.8      haad dm_dev_t *
    316   1.4    cegger dm_dev_alloc(void)
    317   1.2      haad {
    318   1.2      haad 	dm_dev_t *dmv;
    319   1.8      haad 
    320   1.6      haad 	dmv = kmem_zalloc(sizeof(dm_dev_t), KM_SLEEP);
    321  1.10       chs 	dmv->diskp = kmem_zalloc(sizeof(struct disk), KM_SLEEP);
    322   1.2      haad 	return dmv;
    323   1.2      haad }
    324  1.11  christos 
    325   1.2      haad /*
    326   1.2      haad  * Freed device entry.
    327   1.2      haad  */
    328   1.2      haad int
    329  1.14   tkusumi dm_dev_free(dm_dev_t *dmv)
    330   1.2      haad {
    331  1.16   tkusumi 
    332   1.2      haad 	KASSERT(dmv != NULL);
    333   1.3      haad 
    334   1.5      haad 	mutex_destroy(&dmv->dev_mtx);
    335   1.7      haad 	mutex_destroy(&dmv->diskp_mtx);
    336   1.5      haad 	cv_destroy(&dmv->dev_cv);
    337   1.5      haad 
    338   1.8      haad 	if (dmv->diskp != NULL)
    339  1.15   tkusumi 		kmem_free(dmv->diskp, sizeof(struct disk));
    340   1.8      haad 
    341  1.15   tkusumi 	kmem_free(dmv, sizeof(dm_dev_t));
    342   1.8      haad 
    343   1.2      haad 	return 0;
    344   1.2      haad }
    345   1.2      haad 
    346   1.2      haad void
    347  1.14   tkusumi dm_dev_busy(dm_dev_t *dmv)
    348   1.2      haad {
    349  1.16   tkusumi 
    350   1.2      haad 	mutex_enter(&dmv->dev_mtx);
    351   1.2      haad 	dmv->ref_cnt++;
    352   1.2      haad 	mutex_exit(&dmv->dev_mtx);
    353   1.8      haad }
    354   1.2      haad 
    355   1.2      haad void
    356  1.14   tkusumi dm_dev_unbusy(dm_dev_t *dmv)
    357   1.2      haad {
    358  1.16   tkusumi 
    359   1.2      haad 	KASSERT(dmv->ref_cnt != 0);
    360   1.8      haad 
    361   1.2      haad 	mutex_enter(&dmv->dev_mtx);
    362   1.2      haad 	if (--dmv->ref_cnt == 0)
    363   1.2      haad 		cv_broadcast(&dmv->dev_cv);
    364   1.2      haad 	mutex_exit(&dmv->dev_mtx);
    365   1.2      haad }
    366  1.11  christos 
    367   1.2      haad /*
    368   1.2      haad  * Return prop_array of dm_targer_list dictionaries.
    369   1.2      haad  */
    370   1.2      haad prop_array_t
    371   1.2      haad dm_dev_prop_list(void)
    372   1.2      haad {
    373   1.2      haad 	dm_dev_t *dmv;
    374   1.2      haad 	prop_array_t dev_array;
    375   1.2      haad 	prop_dictionary_t dev_dict;
    376   1.8      haad 
    377   1.2      haad 	dev_array = prop_array_create();
    378   1.8      haad 
    379   1.2      haad 	mutex_enter(&dm_dev_mutex);
    380   1.8      haad 
    381   1.2      haad 	TAILQ_FOREACH(dmv, &dm_dev_list, next_devlist) {
    382   1.8      haad 		dev_dict = prop_dictionary_create();
    383   1.8      haad 
    384  1.18   thorpej 		prop_dictionary_set_string(dev_dict, DM_DEV_NAME, dmv->name);
    385   1.2      haad 		prop_dictionary_set_uint32(dev_dict, DM_DEV_DEV, dmv->minor);
    386   1.2      haad 
    387   1.2      haad 		prop_array_add(dev_array, dev_dict);
    388   1.2      haad 		prop_object_release(dev_dict);
    389   1.2      haad 	}
    390   1.2      haad 
    391   1.8      haad 	mutex_exit(&dm_dev_mutex);
    392   1.2      haad 	return dev_array;
    393   1.2      haad }
    394  1.11  christos 
    395   1.2      haad /*
    396   1.2      haad  * Initialize global device mutex.
    397   1.2      haad  */
    398   1.2      haad int
    399   1.4    cegger dm_dev_init(void)
    400   1.2      haad {
    401  1.16   tkusumi 
    402   1.8      haad 	TAILQ_INIT(&dm_dev_list);	/* initialize global dev list */
    403   1.2      haad 	mutex_init(&dm_dev_mutex, MUTEX_DEFAULT, IPL_NONE);
    404   1.2      haad 	return 0;
    405   1.2      haad }
    406