Home | History | Annotate | Line # | Download | only in kern
      1  1.1     haad 
      2  1.1     haad /*
      3  1.1     haad  * CDDL HEADER START
      4  1.1     haad  *
      5  1.1     haad  * The contents of this file are subject to the terms of the
      6  1.1     haad  * Common Development and Distribution License, Version 1.0 only
      7  1.1     haad  * (the "License").  You may not use this file except in compliance
      8  1.1     haad  * with the License.
      9  1.1     haad  *
     10  1.1     haad  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     11  1.1     haad  * or http://www.opensolaris.org/os/licensing.
     12  1.1     haad  * See the License for the specific language governing permissions
     13  1.1     haad  * and limitations under the License.
     14  1.1     haad  *
     15  1.1     haad  * When distributing Covered Code, include this CDDL HEADER in each
     16  1.1     haad  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     17  1.1     haad  * If applicable, add the following below this CDDL HEADER, with the
     18  1.1     haad  * fields enclosed by brackets "[]" replaced with your own identifying
     19  1.1     haad  * information: Portions Copyright [yyyy] [name of copyright owner]
     20  1.1     haad  *
     21  1.1     haad  * CDDL HEADER END
     22  1.1     haad  */
     23  1.1     haad /*
     24  1.1     haad  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
     25  1.1     haad  * Use is subject to license terms.
     26  1.1     haad  */
     27  1.1     haad 
     28  1.1     haad /*	Copyright (c) 1988 AT&T	*/
     29  1.1     haad /*	All Rights Reserved */
     30  1.1     haad 
     31  1.6      chs /*-
     32  1.6      chs  * Copyright (c) 2010 Pawel Jakub Dawidek <pjd (at) FreeBSD.org>
     33  1.6      chs  * All rights reserved.
     34  1.6      chs  *
     35  1.6      chs  * Redistribution and use in source and binary forms, with or without
     36  1.6      chs  * modification, are permitted provided that the following conditions
     37  1.6      chs  * are met:
     38  1.6      chs  * 1. Redistributions of source code must retain the above copyright
     39  1.6      chs  *    notice, this list of conditions and the following disclaimer.
     40  1.6      chs  * 2. Redistributions in binary form must reproduce the above copyright
     41  1.6      chs  *    notice, this list of conditions and the following disclaimer in the
     42  1.6      chs  *    documentation and/or other materials provided with the distribution.
     43  1.6      chs  *
     44  1.6      chs  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
     45  1.6      chs  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     46  1.6      chs  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     47  1.6      chs  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
     48  1.6      chs  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     49  1.6      chs  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     50  1.6      chs  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     51  1.6      chs  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     52  1.6      chs  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     53  1.6      chs  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     54  1.6      chs  * SUCH DAMAGE.
     55  1.6      chs  */
     56  1.1     haad 
     57  1.1     haad #include <sys/types.h>
     58  1.6      chs #include <sys/sunddi.h>
     59  1.4     haad #include <sys/debug.h>
     60  1.1     haad #include <sys/errno.h>
     61  1.1     haad #include <sys/param.h>
     62  1.5      riz #include <sys/lwp.h>
     63  1.3     haad #include <sys/kernel.h>
     64  1.1     haad #include <sys/kmem.h>
     65  1.1     haad #include <sys/cmn_err.h>
     66  1.1     haad #include <sys/namei.h>
     67  1.1     haad #include <sys/stat.h>
     68  1.7  hannken #include <sys/vnode.h>
     69  1.1     haad #include <sys/vfs_syscalls.h>
     70  1.1     haad 
     71  1.1     haad __strong_alias(ddi_strtol,ddi_strtoul)
     72  1.1     haad 
     73  1.1     haad /*
     74  1.1     haad  * String to integer conversion routines.
     75  1.1     haad  *
     76  1.1     haad  * This file is derived from usr/src/common/util/strtol.c
     77  1.1     haad  *
     78  1.1     haad  * We cannot use the user land versions as there is no errno to report
     79  1.1     haad  * error in kernel.  So the return value is used to return an error,
     80  1.1     haad  * and the result is stored in an extra parameter passed by reference.
     81  1.1     haad  * Otherwise, the following functions are identical to the user land
     82  1.1     haad  * versions.
     83  1.1     haad  */
     84  1.1     haad 
     85  1.1     haad /*
     86  1.1     haad  * We should have a kernel version of ctype.h.
     87  1.1     haad  */
     88  1.1     haad #define	isalnum(ch)	(isalpha(ch) || isdigit(ch))
     89  1.1     haad #define	isalpha(ch)	(isupper(ch) || islower(ch))
     90  1.1     haad #define	isdigit(ch)	((ch) >= '0' && (ch) <= '9')
     91  1.1     haad #define	islower(ch)	((ch) >= 'a' && (ch) <= 'z')
     92  1.1     haad #define	isspace(ch)	(((ch) == ' ') || ((ch) == '\r') || ((ch) == '\n') || \
     93  1.1     haad 			((ch) == '\t') || ((ch) == '\f'))
     94  1.1     haad #define	isupper(ch)	((ch) >= 'A' && (ch) <= 'Z')
     95  1.1     haad #define	isxdigit(ch)	(isdigit(ch) || ((ch) >= 'a' && (ch) <= 'f') || \
     96  1.1     haad 			((ch) >= 'A' && (ch) <= 'F'))
     97  1.1     haad 
     98  1.1     haad #define	DIGIT(x)	\
     99  1.1     haad 	(isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
    100  1.1     haad 
    101  1.1     haad #define	MBASE	('z' - 'a' + 1 + 10)
    102  1.1     haad 
    103  1.1     haad /*
    104  1.1     haad  * The following macro is a local version of isalnum() which limits
    105  1.1     haad  * alphabetic characters to the ranges a-z and A-Z; locale dependent
    106  1.1     haad  * characters will not return 1. The members of a-z and A-Z are
    107  1.1     haad  * assumed to be in ascending order and contiguous
    108  1.1     haad  */
    109  1.1     haad #define	lisalnum(x)	\
    110  1.1     haad 	(isdigit(x) || ((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z'))
    111  1.1     haad 
    112  1.1     haad static int
    113  1.1     haad do_mkdirp(const char *path)
    114  1.1     haad {
    115  1.1     haad 	struct lwp *l = curlwp;
    116  1.1     haad 	int mode;
    117  1.1     haad 	int error;
    118  1.1     haad 	register_t ret;
    119  1.1     haad 
    120  1.1     haad 	const char *s, *e;
    121  1.1     haad 	char *here;
    122  1.1     haad 
    123  1.1     haad 	error = 0;
    124  1.1     haad 	mode = 493;
    125  1.1     haad 
    126  1.1     haad 	if (*path != '/')
    127  1.1     haad 		panic("Not an absolute path");
    128  1.1     haad 
    129  1.1     haad 	here = PNBUF_GET();
    130  1.1     haad 	for (s = path;; s = e) {
    131  1.1     haad 		e = strchr(s + 1, '/');
    132  1.1     haad 		if (e == NULL)
    133  1.1     haad 			break;
    134  1.1     haad 
    135  1.1     haad 		strlcpy(here, path, e - path + 1);
    136  1.2     haad 		error = do_sys_mkdir((const char *)here, mode, UIO_SYSSPACE);
    137  1.1     haad 	}
    138  1.1     haad 	PNBUF_PUT(here);
    139  1.1     haad 
    140  1.1     haad 	if (error == EEXIST)
    141  1.1     haad 		error = 0;
    142  1.1     haad 
    143  1.1     haad 	return error;
    144  1.1     haad }
    145  1.1     haad 
    146  1.7  hannken static void
    147  1.7  hannken do_rmdirp(const char *path)
    148  1.7  hannken {
    149  1.7  hannken 	struct pathbuf *pb;
    150  1.7  hannken 	struct nameidata nd;
    151  1.7  hannken 	char *here, *e;
    152  1.7  hannken 	int error;
    153  1.7  hannken 
    154  1.7  hannken 	here = PNBUF_GET();
    155  1.7  hannken 	strlcpy(here, path, MAXPATHLEN);
    156  1.7  hannken 	while ((e = strrchr(here, '/')) && e != here) {
    157  1.7  hannken 		*e = '\0';
    158  1.7  hannken 		pb = pathbuf_create(here);
    159  1.7  hannken 		if (pb == NULL)
    160  1.7  hannken 			break;
    161  1.7  hannken 		/* XXX need do_sys_rmdir()? */
    162  1.7  hannken 		NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | TRYEMULROOT, pb);
    163  1.7  hannken 		error = namei(&nd);
    164  1.7  hannken 		if (error) {
    165  1.7  hannken 			pathbuf_destroy(pb);
    166  1.7  hannken 			break;
    167  1.7  hannken 		}
    168  1.7  hannken 		if ((nd.ni_vp->v_vflag & VV_ROOT) ||
    169  1.7  hannken 		    nd.ni_vp->v_type != VDIR ||
    170  1.7  hannken 		    nd.ni_vp->v_mountedhere ||
    171  1.7  hannken 		    nd.ni_vp == nd.ni_dvp) {
    172  1.7  hannken 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
    173  1.7  hannken 			if (nd.ni_vp == nd.ni_dvp)
    174  1.7  hannken 				vrele(nd.ni_dvp);
    175  1.7  hannken 			else
    176  1.7  hannken 				vput(nd.ni_dvp);
    177  1.7  hannken 			vput(nd.ni_vp);
    178  1.7  hannken 			pathbuf_destroy(pb);
    179  1.7  hannken 			break;
    180  1.7  hannken 		}
    181  1.7  hannken 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
    182  1.7  hannken 		vput(nd.ni_dvp);
    183  1.7  hannken 		pathbuf_destroy(pb);
    184  1.7  hannken 		if (error)
    185  1.7  hannken 			break;
    186  1.7  hannken 	}
    187  1.7  hannken 	PNBUF_PUT(here);
    188  1.7  hannken }
    189  1.7  hannken 
    190  1.1     haad int
    191  1.1     haad ddi_strtoul(const char *str, char **nptr, int base, unsigned long *result)
    192  1.1     haad {
    193  1.1     haad 	unsigned long val;
    194  1.1     haad 	int c;
    195  1.1     haad 	int xx;
    196  1.1     haad 	unsigned long	multmax;
    197  1.1     haad 	int neg = 0;
    198  1.1     haad 	const char **ptr = (const char **)nptr;
    199  1.1     haad 	const unsigned char	*ustr = (const unsigned char *)str;
    200  1.1     haad 
    201  1.1     haad 	if (ptr != (const char **)0)
    202  1.1     haad 		*ptr = (char *)ustr; /* in case no number is formed */
    203  1.1     haad 	if (base < 0 || base > MBASE || base == 1) {
    204  1.1     haad 		/* base is invalid -- should be a fatal error */
    205  1.1     haad 		return (EINVAL);
    206  1.1     haad 	}
    207  1.1     haad 	if (!isalnum(c = *ustr)) {
    208  1.1     haad 		while (isspace(c))
    209  1.1     haad 			c = *++ustr;
    210  1.1     haad 		switch (c) {
    211  1.1     haad 		case '-':
    212  1.1     haad 			neg++;
    213  1.1     haad 			/* FALLTHROUGH */
    214  1.1     haad 		case '+':
    215  1.1     haad 			c = *++ustr;
    216  1.1     haad 		}
    217  1.1     haad 	}
    218  1.1     haad 	if (base == 0)
    219  1.1     haad 		if (c != '0')
    220  1.1     haad 			base = 10;
    221  1.1     haad 		else if (ustr[1] == 'x' || ustr[1] == 'X')
    222  1.1     haad 			base = 16;
    223  1.1     haad 		else
    224  1.1     haad 			base = 8;
    225  1.1     haad 	/*
    226  1.1     haad 	 * for any base > 10, the digits incrementally following
    227  1.1     haad 	 *	9 are assumed to be "abc...z" or "ABC...Z"
    228  1.1     haad 	 */
    229  1.1     haad 	if (!lisalnum(c) || (xx = DIGIT(c)) >= base)
    230  1.1     haad 		return (EINVAL); /* no number formed */
    231  1.1     haad 	if (base == 16 && c == '0' && (ustr[1] == 'x' || ustr[1] == 'X') &&
    232  1.1     haad 	    isxdigit(ustr[2]))
    233  1.1     haad 		c = *(ustr += 2); /* skip over leading "0x" or "0X" */
    234  1.1     haad 
    235  1.1     haad 	multmax = ULONG_MAX / (unsigned long)base;
    236  1.1     haad 	val = DIGIT(c);
    237  1.1     haad 	for (c = *++ustr; lisalnum(c) && (xx = DIGIT(c)) < base; ) {
    238  1.1     haad 		if (val > multmax)
    239  1.1     haad 			goto overflow;
    240  1.1     haad 		val *= base;
    241  1.1     haad 		if (ULONG_MAX - val < xx)
    242  1.1     haad 			goto overflow;
    243  1.1     haad 		val += xx;
    244  1.1     haad 		c = *++ustr;
    245  1.1     haad 	}
    246  1.1     haad 	if (ptr != (const char **)0)
    247  1.1     haad 		*ptr = (char *)ustr;
    248  1.1     haad 	*result = neg ? -val : val;
    249  1.1     haad 	return (0);
    250  1.1     haad 
    251  1.1     haad overflow:
    252  1.1     haad 	for (c = *++ustr; lisalnum(c) && (xx = DIGIT(c)) < base; (c = *++ustr))
    253  1.1     haad 		;
    254  1.1     haad 	if (ptr != (const char **)0)
    255  1.1     haad 		*ptr = (char *)ustr;
    256  1.1     haad 	return (ERANGE);
    257  1.1     haad }
    258  1.1     haad 
    259  1.6      chs int
    260  1.6      chs ddi_strtoull(const char *str, char **nptr, int base, unsigned long long *result)
    261  1.6      chs {
    262  1.6      chs 
    263  1.6      chs 	*result = (unsigned long long)strtoull(str, nptr, base);
    264  1.6      chs 	if (*result == 0)
    265  1.6      chs 		return (EINVAL);
    266  1.6      chs 	else if (*result == ULLONG_MAX)
    267  1.6      chs 		return (ERANGE);
    268  1.6      chs 	return (0);
    269  1.6      chs }
    270  1.6      chs 
    271  1.1     haad /*
    272  1.1     haad  * Find first bit set in a mask (returned counting from 1 up)
    273  1.1     haad  */
    274  1.1     haad 
    275  1.1     haad int
    276  1.1     haad ddi_ffs(long mask)
    277  1.1     haad {
    278  1.1     haad 	return (ffs(mask));
    279  1.1     haad }
    280  1.1     haad 
    281  1.1     haad /*
    282  1.1     haad  * Find last bit set. Take mask and clear
    283  1.1     haad  * all but the most significant bit, and
    284  1.1     haad  * then let ffs do the rest of the work.
    285  1.1     haad  *
    286  1.1     haad  * Algorithm courtesy of Steve Chessin.
    287  1.1     haad  */
    288  1.1     haad 
    289  1.1     haad int
    290  1.1     haad ddi_fls(long mask)
    291  1.1     haad {
    292  1.1     haad 	while (mask) {
    293  1.1     haad 		long nx;
    294  1.1     haad 
    295  1.1     haad 		if ((nx = (mask & (mask - 1))) == 0)
    296  1.1     haad 			break;
    297  1.1     haad 		mask = nx;
    298  1.1     haad 	}
    299  1.1     haad 	return (ffs(mask));
    300  1.1     haad }
    301  1.1     haad 
    302  1.1     haad /*
    303  1.1     haad  * The next five routines comprise generic storage management utilities
    304  1.1     haad  * for driver soft state structures (in "the old days," this was done
    305  1.1     haad  * with a statically sized array - big systems and dynamic loading
    306  1.1     haad  * and unloading make heap allocation more attractive)
    307  1.1     haad  */
    308  1.1     haad 
    309  1.1     haad /*
    310  1.1     haad  * Allocate a set of pointers to 'n_items' objects of size 'size'
    311  1.1     haad  * bytes.  Each pointer is initialized to nil.
    312  1.1     haad  *
    313  1.1     haad  * The 'size' and 'n_items' values are stashed in the opaque
    314  1.1     haad  * handle returned to the caller.
    315  1.1     haad  *
    316  1.1     haad  * This implementation interprets 'set of pointers' to mean 'array
    317  1.1     haad  * of pointers' but note that nothing in the interface definition
    318  1.1     haad  * precludes an implementation that uses, for example, a linked list.
    319  1.1     haad  * However there should be a small efficiency gain from using an array
    320  1.1     haad  * at lookup time.
    321  1.1     haad  *
    322  1.1     haad  * NOTE	As an optimization, we make our growable array allocations in
    323  1.1     haad  *	powers of two (bytes), since that's how much kmem_alloc (currently)
    324  1.1     haad  *	gives us anyway.  It should save us some free/realloc's ..
    325  1.1     haad  *
    326  1.1     haad  *	As a further optimization, we make the growable array start out
    327  1.1     haad  *	with MIN_N_ITEMS in it.
    328  1.1     haad  */
    329  1.1     haad 
    330  1.1     haad /*
    331  1.1     haad  * This data structure is entirely private to the soft state allocator.
    332  1.1     haad  */
    333  1.1     haad struct i_ddi_soft_state {
    334  1.1     haad 	void		**array;	/* the array of pointers */
    335  1.1     haad 	kmutex_t	lock;	/* serialize access to this struct */
    336  1.1     haad 	size_t		size;	/* how many bytes per state struct */
    337  1.1     haad 	size_t		n_items;	/* how many structs herein */
    338  1.1     haad 	struct i_ddi_soft_state *next;	/* 'dirty' elements */
    339  1.1     haad };
    340  1.1     haad 
    341  1.1     haad #define	MIN_N_ITEMS	8	/* 8 void *'s == 32 bytes */
    342  1.1     haad 
    343  1.1     haad int
    344  1.1     haad ddi_soft_state_init(void **state_p, size_t size, size_t n_items)
    345  1.1     haad {
    346  1.1     haad 	struct i_ddi_soft_state *ss;
    347  1.1     haad 
    348  1.1     haad 	if (state_p == NULL || *state_p != NULL || size == 0)
    349  1.1     haad 		return (EINVAL);
    350  1.1     haad 
    351  1.1     haad 	ss = kmem_zalloc(sizeof (*ss), KM_SLEEP);
    352  1.1     haad 	mutex_init(&ss->lock, NULL, MUTEX_DRIVER, NULL);
    353  1.1     haad 	ss->size = size;
    354  1.1     haad 
    355  1.1     haad 	if (n_items < MIN_N_ITEMS)
    356  1.1     haad 		ss->n_items = MIN_N_ITEMS;
    357  1.1     haad 	else {
    358  1.1     haad 		int bitlog;
    359  1.1     haad 
    360  1.1     haad 		if ((bitlog = ddi_fls(n_items)) == ddi_ffs(n_items))
    361  1.1     haad 			bitlog--;
    362  1.1     haad 		ss->n_items = 1 << bitlog;
    363  1.1     haad 	}
    364  1.1     haad 
    365  1.1     haad 	ASSERT(ss->n_items >= n_items);
    366  1.1     haad 
    367  1.1     haad 	ss->array = kmem_zalloc(ss->n_items * sizeof (void *), KM_SLEEP);
    368  1.1     haad 
    369  1.1     haad 	*state_p = ss;
    370  1.1     haad 
    371  1.1     haad 	return (0);
    372  1.1     haad }
    373  1.1     haad 
    374  1.1     haad 
    375  1.1     haad /*
    376  1.1     haad  * Allocate a state structure of size 'size' to be associated
    377  1.1     haad  * with item 'item'.
    378  1.1     haad  *
    379  1.1     haad  * In this implementation, the array is extended to
    380  1.1     haad  * allow the requested offset, if needed.
    381  1.1     haad  */
    382  1.1     haad int
    383  1.1     haad ddi_soft_state_zalloc(void *state, int item)
    384  1.1     haad {
    385  1.1     haad 	struct i_ddi_soft_state *ss;
    386  1.1     haad 	void **array;
    387  1.1     haad 	void *new_element;
    388  1.1     haad 
    389  1.1     haad 	if ((ss = state) == NULL || item < 0)
    390  1.1     haad 		return (DDI_FAILURE);
    391  1.1     haad 
    392  1.1     haad 	mutex_enter(&ss->lock);
    393  1.1     haad 	if (ss->size == 0) {
    394  1.1     haad 		mutex_exit(&ss->lock);
    395  1.1     haad 		cmn_err(CE_WARN, "ddi_soft_state_zalloc: bad handle");
    396  1.1     haad 		return (DDI_FAILURE);
    397  1.1     haad 	}
    398  1.1     haad 
    399  1.1     haad 	array = ss->array;	/* NULL if ss->n_items == 0 */
    400  1.1     haad 	ASSERT(ss->n_items != 0 && array != NULL);
    401  1.1     haad 
    402  1.1     haad 	/*
    403  1.1     haad 	 * refuse to tread on an existing element
    404  1.1     haad 	 */
    405  1.1     haad 	if (item < ss->n_items && array[item] != NULL) {
    406  1.1     haad 		mutex_exit(&ss->lock);
    407  1.1     haad 		return (DDI_FAILURE);
    408  1.1     haad 	}
    409  1.1     haad 
    410  1.1     haad 	/*
    411  1.1     haad 	 * Allocate a new element to plug in
    412  1.1     haad 	 */
    413  1.1     haad 	new_element = kmem_zalloc(ss->size, KM_SLEEP);
    414  1.1     haad 
    415  1.1     haad 	/*
    416  1.1     haad 	 * Check if the array is big enough, if not, grow it.
    417  1.1     haad 	 */
    418  1.1     haad 	if (item >= ss->n_items) {
    419  1.1     haad 		void	**new_array;
    420  1.1     haad 		size_t	new_n_items;
    421  1.1     haad 		struct i_ddi_soft_state *dirty;
    422  1.1     haad 
    423  1.1     haad 		/*
    424  1.1     haad 		 * Allocate a new array of the right length, copy
    425  1.1     haad 		 * all the old pointers to the new array, then
    426  1.1     haad 		 * if it exists at all, put the old array on the
    427  1.1     haad 		 * dirty list.
    428  1.1     haad 		 *
    429  1.1     haad 		 * Note that we can't kmem_free() the old array.
    430  1.1     haad 		 *
    431  1.1     haad 		 * Why -- well the 'get' operation is 'mutex-free', so we
    432  1.1     haad 		 * can't easily catch a suspended thread that is just about
    433  1.1     haad 		 * to dereference the array we just grew out of.  So we
    434  1.1     haad 		 * cons up a header and put it on a list of 'dirty'
    435  1.1     haad 		 * pointer arrays.  (Dirty in the sense that there may
    436  1.1     haad 		 * be suspended threads somewhere that are in the middle
    437  1.1     haad 		 * of referencing them).  Fortunately, we -can- garbage
    438  1.1     haad 		 * collect it all at ddi_soft_state_fini time.
    439  1.1     haad 		 */
    440  1.1     haad 		new_n_items = ss->n_items;
    441  1.1     haad 		while (new_n_items < (1 + item))
    442  1.1     haad 			new_n_items <<= 1;	/* double array size .. */
    443  1.1     haad 
    444  1.1     haad 		ASSERT(new_n_items >= (1 + item));	/* sanity check! */
    445  1.1     haad 
    446  1.1     haad 		new_array = kmem_zalloc(new_n_items * sizeof (void *),
    447  1.1     haad 		    KM_SLEEP);
    448  1.1     haad 		/*
    449  1.1     haad 		 * Copy the pointers into the new array
    450  1.1     haad 		 */
    451  1.1     haad 		bcopy(array, new_array, ss->n_items * sizeof (void *));
    452  1.1     haad 
    453  1.1     haad 		/*
    454  1.1     haad 		 * Save the old array on the dirty list
    455  1.1     haad 		 */
    456  1.1     haad 		dirty = kmem_zalloc(sizeof (*dirty), KM_SLEEP);
    457  1.1     haad 		dirty->array = ss->array;
    458  1.1     haad 		dirty->n_items = ss->n_items;
    459  1.1     haad 		dirty->next = ss->next;
    460  1.1     haad 		ss->next = dirty;
    461  1.1     haad 
    462  1.1     haad 		ss->array = (array = new_array);
    463  1.1     haad 		ss->n_items = new_n_items;
    464  1.1     haad 	}
    465  1.1     haad 
    466  1.1     haad 	ASSERT(array != NULL && item < ss->n_items && array[item] == NULL);
    467  1.1     haad 
    468  1.1     haad 	array[item] = new_element;
    469  1.1     haad 
    470  1.1     haad 	mutex_exit(&ss->lock);
    471  1.1     haad 	return (DDI_SUCCESS);
    472  1.1     haad }
    473  1.1     haad 
    474  1.1     haad 
    475  1.1     haad /*
    476  1.1     haad  * Fetch a pointer to the allocated soft state structure.
    477  1.1     haad  *
    478  1.1     haad  * This is designed to be cheap.
    479  1.1     haad  *
    480  1.1     haad  * There's an argument that there should be more checking for
    481  1.1     haad  * nil pointers and out of bounds on the array.. but we do a lot
    482  1.1     haad  * of that in the alloc/free routines.
    483  1.1     haad  *
    484  1.1     haad  * An array has the convenience that we don't need to lock read-access
    485  1.1     haad  * to it c.f. a linked list.  However our "expanding array" strategy
    486  1.1     haad  * means that we should hold a readers lock on the i_ddi_soft_state
    487  1.1     haad  * structure.
    488  1.1     haad  *
    489  1.1     haad  * However, from a performance viewpoint, we need to do it without
    490  1.1     haad  * any locks at all -- this also makes it a leaf routine.  The algorithm
    491  1.1     haad  * is 'lock-free' because we only discard the pointer arrays at
    492  1.1     haad  * ddi_soft_state_fini() time.
    493  1.1     haad  */
    494  1.1     haad void *
    495  1.1     haad ddi_get_soft_state(void *state, int item)
    496  1.1     haad {
    497  1.1     haad 	struct i_ddi_soft_state *ss = state;
    498  1.1     haad 
    499  1.1     haad 	ASSERT(ss != NULL && item >= 0);
    500  1.1     haad 
    501  1.1     haad 	if (item < ss->n_items && ss->array != NULL)
    502  1.1     haad 		return (ss->array[item]);
    503  1.1     haad 	return (NULL);
    504  1.1     haad }
    505  1.1     haad 
    506  1.1     haad /*
    507  1.1     haad  * Free the state structure corresponding to 'item.'   Freeing an
    508  1.1     haad  * element that has either gone or was never allocated is not
    509  1.1     haad  * considered an error.  Note that we free the state structure, but
    510  1.1     haad  * we don't shrink our pointer array, or discard 'dirty' arrays,
    511  1.1     haad  * since even a few pointers don't really waste too much memory.
    512  1.1     haad  *
    513  1.1     haad  * Passing an item number that is out of bounds, or a null pointer will
    514  1.1     haad  * provoke an error message.
    515  1.1     haad  */
    516  1.1     haad void
    517  1.1     haad ddi_soft_state_free(void *state, int item)
    518  1.1     haad {
    519  1.1     haad 	struct i_ddi_soft_state *ss;
    520  1.1     haad 	void **array;
    521  1.1     haad 	void *element;
    522  1.1     haad 	static char msg[] = "ddi_soft_state_free:";
    523  1.1     haad 
    524  1.1     haad 	if ((ss = state) == NULL) {
    525  1.1     haad 		cmn_err(CE_WARN, "%s null handle",
    526  1.1     haad 		    msg);
    527  1.1     haad 		return;
    528  1.1     haad 	}
    529  1.1     haad 
    530  1.1     haad 	element = NULL;
    531  1.1     haad 
    532  1.1     haad 	mutex_enter(&ss->lock);
    533  1.1     haad 
    534  1.1     haad 	if ((array = ss->array) == NULL || ss->size == 0) {
    535  1.1     haad 		cmn_err(CE_WARN, "%s bad handle",
    536  1.1     haad 		    msg);
    537  1.1     haad 	} else if (item < 0 || item >= ss->n_items) {
    538  1.1     haad 		cmn_err(CE_WARN, "%s item %d not in range [0..%lu]",
    539  1.1     haad 		    msg, item, ss->n_items - 1);
    540  1.1     haad 	} else if (array[item] != NULL) {
    541  1.1     haad 		element = array[item];
    542  1.1     haad 		array[item] = NULL;
    543  1.1     haad 	}
    544  1.1     haad 
    545  1.1     haad 	mutex_exit(&ss->lock);
    546  1.1     haad 
    547  1.1     haad 	if (element)
    548  1.1     haad 		kmem_free(element, ss->size);
    549  1.1     haad }
    550  1.1     haad 
    551  1.1     haad 
    552  1.1     haad /*
    553  1.1     haad  * Free the entire set of pointers, and any
    554  1.1     haad  * soft state structures contained therein.
    555  1.1     haad  *
    556  1.1     haad  * Note that we don't grab the ss->lock mutex, even though
    557  1.1     haad  * we're inspecting the various fields of the data structure.
    558  1.1     haad  *
    559  1.1     haad  * There is an implicit assumption that this routine will
    560  1.1     haad  * never run concurrently with any of the above on this
    561  1.1     haad  * particular state structure i.e. by the time the driver
    562  1.1     haad  * calls this routine, there should be no other threads
    563  1.1     haad  * running in the driver.
    564  1.1     haad  */
    565  1.1     haad void
    566  1.1     haad ddi_soft_state_fini(void **state_p)
    567  1.1     haad {
    568  1.1     haad 	struct i_ddi_soft_state *ss, *dirty;
    569  1.1     haad 	int item;
    570  1.1     haad 	static char msg[] = "ddi_soft_state_fini:";
    571  1.1     haad 
    572  1.1     haad 	if (state_p == NULL || (ss = *state_p) == NULL) {
    573  1.1     haad 		cmn_err(CE_WARN, "%s null handle",
    574  1.1     haad 		    msg);
    575  1.1     haad 		return;
    576  1.1     haad 	}
    577  1.1     haad 
    578  1.1     haad 	if (ss->size == 0) {
    579  1.1     haad 		cmn_err(CE_WARN, "%s bad handle",
    580  1.1     haad 		    msg);
    581  1.1     haad 		return;
    582  1.1     haad 	}
    583  1.1     haad 
    584  1.1     haad 	if (ss->n_items > 0) {
    585  1.1     haad 		for (item = 0; item < ss->n_items; item++)
    586  1.1     haad 			ddi_soft_state_free(ss, item);
    587  1.1     haad 		kmem_free(ss->array, ss->n_items * sizeof (void *));
    588  1.1     haad 	}
    589  1.1     haad 
    590  1.1     haad 	/*
    591  1.1     haad 	 * Now delete any dirty arrays from previous 'grow' operations
    592  1.1     haad 	 */
    593  1.1     haad 	for (dirty = ss->next; dirty; dirty = ss->next) {
    594  1.1     haad 		ss->next = dirty->next;
    595  1.1     haad 		kmem_free(dirty->array, dirty->n_items * sizeof (void *));
    596  1.1     haad 		kmem_free(dirty, sizeof (*dirty));
    597  1.1     haad 	}
    598  1.1     haad 
    599  1.1     haad 	mutex_destroy(&ss->lock);
    600  1.1     haad 	kmem_free(ss, sizeof (*ss));
    601  1.1     haad 
    602  1.1     haad 	*state_p = NULL;
    603  1.1     haad }
    604  1.1     haad 
    605  1.1     haad int
    606  1.1     haad ddi_create_minor_node(dev_info_t *dip, char *name, int spec_type,
    607  1.1     haad     minor_t minor_num, char *node_type, int flag)
    608  1.1     haad {
    609  1.1     haad 	struct lwp *l = curlwp;
    610  1.7  hannken 	vnode_t *vp;
    611  1.7  hannken 	enum vtype vtype;
    612  1.7  hannken 	struct stat sb;
    613  1.1     haad 	char *pn;
    614  1.1     haad 	dev_t dev;
    615  1.1     haad 	int error;
    616  1.1     haad 
    617  1.1     haad 	pn = PNBUF_GET();
    618  1.7  hannken 	if (spec_type == S_IFCHR) {
    619  1.7  hannken 		vtype = VCHR;
    620  1.7  hannken 		dev = makedev(dip->di_cmajor, minor_num);
    621  1.1     haad 		snprintf(pn, MAXPATHLEN, "/dev/zvol/rdsk/%s", name);
    622  1.7  hannken 	} else if (spec_type == S_IFBLK) {
    623  1.7  hannken 		vtype = VBLK;
    624  1.7  hannken 		dev = makedev(dip->di_bmajor, minor_num);
    625  1.1     haad 		snprintf(pn, MAXPATHLEN, "/dev/zvol/dsk/%s", name);
    626  1.7  hannken 	} else {
    627  1.7  hannken 		panic("bad spectype %#x", spec_type);
    628  1.7  hannken 	}
    629  1.7  hannken 	spec_type |= (S_IRUSR | S_IWUSR);
    630  1.1     haad 
    631  1.7  hannken 	/* Create missing directories. */
    632  1.1     haad 	if ((error = do_mkdirp(pn)) != 0)
    633  1.1     haad 		goto exit;
    634  1.7  hannken 
    635  1.7  hannken 	/*
    636  1.7  hannken 	 * If node exists and has correct type and rdev all done,
    637  1.7  hannken 	 * otherwise unlink the node.
    638  1.7  hannken 	 */
    639  1.7  hannken 	if (namei_simple_kernel(pn, NSM_NOFOLLOW_NOEMULROOT, &vp) == 0) {
    640  1.7  hannken 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    641  1.7  hannken 		error = vn_stat(vp, &sb);
    642  1.7  hannken 		VOP_UNLOCK(vp, 0);
    643  1.7  hannken 		if (error == 0 && vp->v_type == vtype && sb.st_rdev == dev) {
    644  1.7  hannken 			vrele(vp);
    645  1.7  hannken 			return 0;
    646  1.7  hannken 		}
    647  1.7  hannken 		vrele(vp);
    648  1.7  hannken 		(void)do_sys_unlink(pn, UIO_SYSSPACE);
    649  1.7  hannken 	}
    650  1.7  hannken 
    651  1.8    kamil 	error = do_sys_mknod(l, pn, spec_type, dev, UIO_SYSSPACE);
    652  1.1     haad 
    653  1.1     haad exit:
    654  1.1     haad 	PNBUF_PUT(pn);
    655  1.1     haad 
    656  1.1     haad 	return error;
    657  1.1     haad }
    658  1.1     haad 
    659  1.1     haad void
    660  1.1     haad ddi_remove_minor_node(dev_info_t *dip, char *name)
    661  1.1     haad {
    662  1.1     haad 	char *pn;
    663  1.1     haad 
    664  1.7  hannken 	/* Unlink block device and remove empty directories. */
    665  1.1     haad 	pn = PNBUF_GET();
    666  1.1     haad 	snprintf(pn, MAXPATHLEN, "/dev/zvol/dsk/%s", name);
    667  1.1     haad 	(void)do_sys_unlink(pn, UIO_SYSSPACE);
    668  1.7  hannken 	do_rmdirp(pn);
    669  1.1     haad 	PNBUF_PUT(pn);
    670  1.1     haad 
    671  1.7  hannken 	/* Unlink raw device and remove empty directories. */
    672  1.1     haad 	pn = PNBUF_GET();
    673  1.1     haad 	snprintf(pn, MAXPATHLEN, "/dev/zvol/rdsk/%s", name);
    674  1.1     haad 	(void)do_sys_unlink(pn, UIO_SYSSPACE);
    675  1.7  hannken 	do_rmdirp(pn);
    676  1.1     haad 	PNBUF_PUT(pn);
    677  1.1     haad }
    678