Home | History | Annotate | Line # | Download | only in dm
      1  1.23    andvar /*        $NetBSD: dm_pdev.c,v 1.23 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.10  christos #include <sys/cdefs.h>
     32  1.23    andvar __KERNEL_RCSID(0, "$NetBSD: dm_pdev.c,v 1.23 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.2      haad #include <sys/disk.h>
     37   1.2      haad #include <sys/fcntl.h>
     38   1.2      haad #include <sys/kmem.h>
     39   1.2      haad #include <sys/namei.h>
     40   1.2      haad 
     41   1.2      haad #include <dev/dkvar.h>
     42   1.2      haad 
     43   1.2      haad #include "dm.h"
     44   1.2      haad 
     45  1.15   tkusumi static SLIST_HEAD(dm_pdevs, dm_pdev) dm_pdev_list;
     46   1.2      haad 
     47  1.13   tkusumi static kmutex_t dm_pdev_mutex;
     48   1.2      haad 
     49  1.10  christos static dm_pdev_t *dm_pdev_alloc(const char *);
     50  1.10  christos static int dm_pdev_rem(dm_pdev_t *);
     51  1.10  christos static dm_pdev_t *dm_pdev_lookup_name(const char *);
     52   1.2      haad 
     53   1.2      haad /*
     54  1.10  christos * Find used pdev with name == dm_pdev_name.
     55  1.10  christos */
     56  1.10  christos dm_pdev_t *
     57  1.10  christos dm_pdev_lookup_name(const char *dm_pdev_name)
     58   1.2      haad {
     59   1.2      haad 	dm_pdev_t *dm_pdev;
     60  1.10  christos 	size_t dlen;
     61  1.10  christos 	size_t slen;
     62   1.2      haad 
     63   1.2      haad 	KASSERT(dm_pdev_name != NULL);
     64   1.2      haad 
     65   1.2      haad 	slen = strlen(dm_pdev_name);
     66   1.2      haad 
     67   1.2      haad 	SLIST_FOREACH(dm_pdev, &dm_pdev_list, next_pdev) {
     68   1.2      haad 		dlen = strlen(dm_pdev->name);
     69   1.2      haad 
     70   1.2      haad 		if (slen != dlen)
     71   1.2      haad 			continue;
     72   1.6      haad 
     73   1.2      haad 		if (strncmp(dm_pdev_name, dm_pdev->name, slen) == 0)
     74   1.2      haad 			return dm_pdev;
     75   1.2      haad 	}
     76   1.2      haad 
     77   1.2      haad 	return NULL;
     78   1.2      haad }
     79  1.10  christos 
     80   1.2      haad /*
     81   1.2      haad  * Create entry for device with name dev_name and open vnode for it.
     82   1.2      haad  * If entry already exists in global SLIST I will only increment
     83   1.2      haad  * reference counter.
     84   1.2      haad  */
     85   1.6      haad dm_pdev_t *
     86   1.2      haad dm_pdev_insert(const char *dev_name)
     87   1.2      haad {
     88   1.7  dholland 	struct pathbuf *dev_pb;
     89   1.2      haad 	dm_pdev_t *dmp;
     90   1.2      haad 	int error;
     91   1.6      haad 
     92   1.2      haad 	KASSERT(dev_name != NULL);
     93   1.6      haad 
     94   1.2      haad 	mutex_enter(&dm_pdev_mutex);
     95   1.2      haad 	dmp = dm_pdev_lookup_name(dev_name);
     96   1.2      haad 
     97   1.2      haad 	if (dmp != NULL) {
     98   1.2      haad 		dmp->ref_cnt++;
     99  1.10  christos 		aprint_debug("%s: pdev %s already in tree\n",
    100  1.10  christos 		    __func__, dev_name);
    101   1.2      haad 		mutex_exit(&dm_pdev_mutex);
    102   1.2      haad 		return dmp;
    103   1.2      haad 	}
    104   1.6      haad 
    105  1.11   tkusumi 	if ((dmp = dm_pdev_alloc(dev_name)) == NULL) {
    106  1.11   tkusumi 		mutex_exit(&dm_pdev_mutex);
    107   1.2      haad 		return NULL;
    108  1.11   tkusumi 	}
    109   1.2      haad 
    110   1.7  dholland 	dev_pb = pathbuf_create(dev_name);
    111   1.7  dholland 	if (dev_pb == NULL) {
    112  1.10  christos 		aprint_debug("%s: pathbuf_create on device: %s failed!\n",
    113  1.10  christos 		    __func__, dev_name);
    114  1.11   tkusumi 		mutex_exit(&dm_pdev_mutex);
    115   1.7  dholland 		kmem_free(dmp, sizeof(dm_pdev_t));
    116   1.7  dholland 		return NULL;
    117   1.7  dholland 	}
    118  1.19   mlelstv 	error = vn_bdev_openpath(dev_pb, &dmp->pdev_vnode, curlwp);
    119   1.7  dholland 	pathbuf_destroy(dev_pb);
    120   1.2      haad 	if (error) {
    121  1.19   mlelstv 		aprint_debug("%s: lookup on device: %s (error %d)\n",
    122  1.10  christos 		    __func__, dev_name, error);
    123  1.11   tkusumi 		mutex_exit(&dm_pdev_mutex);
    124   1.2      haad 		kmem_free(dmp, sizeof(dm_pdev_t));
    125   1.2      haad 		return NULL;
    126   1.2      haad 	}
    127   1.8   mlelstv 	getdisksize(dmp->pdev_vnode, &dmp->pdev_numsec, &dmp->pdev_secsize);
    128   1.6      haad 	dmp->ref_cnt = 1;
    129   1.2      haad 
    130  1.22   tkusumi 	snprintf(dmp->udev_name, sizeof(dmp->udev_name), "%d:%d",
    131  1.22   tkusumi 	    major(dmp->pdev_vnode->v_rdev), minor(dmp->pdev_vnode->v_rdev));
    132  1.22   tkusumi 	aprint_debug("%s: %s %s\n", __func__, dev_name, dmp->udev_name);
    133  1.22   tkusumi 
    134   1.2      haad 	SLIST_INSERT_HEAD(&dm_pdev_list, dmp, next_pdev);
    135   1.2      haad 	mutex_exit(&dm_pdev_mutex);
    136   1.2      haad 
    137   1.2      haad 	return dmp;
    138   1.2      haad }
    139  1.10  christos 
    140   1.2      haad /*
    141   1.2      haad  * Initialize pdev subsystem.
    142   1.2      haad  */
    143   1.2      haad int
    144   1.2      haad dm_pdev_init(void)
    145   1.2      haad {
    146  1.21   tkusumi 
    147   1.6      haad 	SLIST_INIT(&dm_pdev_list);	/* initialize global pdev list */
    148   1.2      haad 	mutex_init(&dm_pdev_mutex, MUTEX_DEFAULT, IPL_NONE);
    149   1.6      haad 
    150   1.2      haad 	return 0;
    151   1.2      haad }
    152  1.10  christos 
    153   1.2      haad /*
    154   1.2      haad  * Allocat new pdev structure if is not already present and
    155   1.2      haad  * set name.
    156   1.2      haad  */
    157   1.6      haad static dm_pdev_t *
    158   1.2      haad dm_pdev_alloc(const char *name)
    159   1.2      haad {
    160   1.2      haad 	dm_pdev_t *dmp;
    161   1.2      haad 
    162  1.10  christos 	dmp = kmem_zalloc(sizeof(*dmp), KM_SLEEP);
    163  1.10  christos 	strlcpy(dmp->name, name, sizeof(dmp->name));
    164   1.2      haad 	dmp->ref_cnt = 0;
    165   1.2      haad 	dmp->pdev_vnode = NULL;
    166   1.6      haad 
    167   1.2      haad 	return dmp;
    168   1.2      haad }
    169  1.10  christos 
    170   1.2      haad /*
    171   1.2      haad  * Destroy allocated dm_pdev.
    172   1.2      haad  */
    173   1.2      haad static int
    174  1.18   tkusumi dm_pdev_rem(dm_pdev_t *dmp)
    175   1.2      haad {
    176   1.2      haad 
    177   1.2      haad 	KASSERT(dmp != NULL);
    178   1.6      haad 
    179   1.2      haad 	if (dmp->pdev_vnode != NULL) {
    180  1.10  christos 		int error = vn_close(dmp->pdev_vnode, FREAD | FWRITE, FSCRED);
    181  1.20   tkusumi 		if (error != 0) {
    182  1.20   tkusumi 			kmem_free(dmp, sizeof(*dmp));
    183  1.10  christos 			return error;
    184  1.20   tkusumi 		}
    185   1.2      haad 	}
    186   1.2      haad 	kmem_free(dmp, sizeof(*dmp));
    187   1.6      haad 
    188   1.2      haad 	return 0;
    189   1.2      haad }
    190  1.10  christos 
    191   1.2      haad /*
    192   1.2      haad  * Destroy all existing pdev's in device-mapper.
    193   1.2      haad  */
    194   1.2      haad int
    195   1.2      haad dm_pdev_destroy(void)
    196   1.2      haad {
    197  1.17   tkusumi 	dm_pdev_t *dmp;
    198   1.2      haad 
    199   1.2      haad 	mutex_enter(&dm_pdev_mutex);
    200   1.6      haad 
    201  1.17   tkusumi 	while ((dmp = SLIST_FIRST(&dm_pdev_list)) != NULL) {
    202  1.17   tkusumi 		SLIST_REMOVE(&dm_pdev_list, dmp, dm_pdev, next_pdev);
    203  1.17   tkusumi 		dm_pdev_rem(dmp);
    204  1.17   tkusumi 	}
    205  1.17   tkusumi 	KASSERT(SLIST_EMPTY(&dm_pdev_list));
    206   1.2      haad 
    207   1.2      haad 	mutex_exit(&dm_pdev_mutex);
    208   1.2      haad 
    209   1.2      haad 	mutex_destroy(&dm_pdev_mutex);
    210   1.2      haad 	return 0;
    211   1.2      haad }
    212  1.10  christos 
    213   1.2      haad /*
    214  1.23    andvar  * This function is called from dm_dev_remove_ioctl.
    215   1.2      haad  * When I'm removing device from list, I have to decrement
    216   1.2      haad  * reference counter. If reference counter is 0 I will remove
    217   1.2      haad  * dmp from global list and from device list to. And I will CLOSE
    218   1.2      haad  * dmp vnode too.
    219   1.2      haad  */
    220   1.2      haad 
    221   1.2      haad /*
    222   1.2      haad  * Decrement pdev reference counter if 0 remove it.
    223   1.2      haad  */
    224   1.2      haad int
    225  1.18   tkusumi dm_pdev_decr(dm_pdev_t *dmp)
    226   1.2      haad {
    227  1.21   tkusumi 
    228   1.2      haad 	KASSERT(dmp != NULL);
    229   1.2      haad 	/*
    230   1.2      haad 	 * If this was last reference remove dmp from
    231   1.2      haad 	 * global list also.
    232   1.2      haad 	 */
    233   1.2      haad 	mutex_enter(&dm_pdev_mutex);
    234   1.6      haad 
    235   1.2      haad 	if (--dmp->ref_cnt == 0) {
    236   1.6      haad 		SLIST_REMOVE(&dm_pdev_list, dmp, dm_pdev, next_pdev);
    237   1.2      haad 		mutex_exit(&dm_pdev_mutex);
    238   1.2      haad 		dm_pdev_rem(dmp);
    239   1.2      haad 		return 0;
    240   1.2      haad 	}
    241  1.21   tkusumi 
    242   1.2      haad 	mutex_exit(&dm_pdev_mutex);
    243   1.2      haad 	return 0;
    244   1.2      haad }
    245  1.10  christos 
    246  1.10  christos #if 0
    247  1.10  christos static int
    248  1.10  christos dm_pdev_dump_list(void)
    249  1.10  christos {
    250  1.10  christos 	dm_pdev_t *dmp;
    251  1.16   tkusumi 
    252  1.10  christos 	aprint_verbose("Dumping dm_pdev_list\n");
    253  1.16   tkusumi 
    254  1.10  christos 	SLIST_FOREACH(dmp, &dm_pdev_list, next_pdev) {
    255  1.10  christos 		aprint_verbose("dm_pdev_name %s ref_cnt %d list_rf_cnt %d\n",
    256  1.10  christos 		dmp->name, dmp->ref_cnt, dmp->list_ref_cnt);
    257  1.10  christos 	}
    258  1.16   tkusumi 
    259  1.10  christos 	return 0;
    260  1.10  christos }
    261  1.10  christos #endif
    262