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