1 /* 2 * Copyright (c) 1982, 1986, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)kern_subr.c 8.3 (Berkeley) 1/21/94 39 * $FreeBSD: src/sys/kern/kern_subr.c,v 1.31.2.2 2002/04/21 08:09:37 bde Exp $ 40 * $DragonFly: src/sys/kern/kern_subr.c,v 1.16 2004/05/02 07:59:34 dillon Exp $ 41 */ 42 43 #include "opt_ddb.h" 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/kernel.h> 48 #include <sys/proc.h> 49 #include <sys/malloc.h> 50 #include <sys/lock.h> 51 #include <sys/resourcevar.h> 52 #include <sys/vnode.h> 53 #include <machine/limits.h> 54 55 #include <vm/vm.h> 56 #include <vm/vm_page.h> 57 #include <vm/vm_map.h> 58 59 /* 60 * UIO_READ: copy the kernelspace cp to the user or kernelspace UIO 61 * UIO_WRITE: copy the user or kernelspace UIO to cp 62 * 63 * For userspace UIO's, uio_td must be the current thread. 64 */ 65 int 66 uiomove(caddr_t cp, int n, struct uio *uio) 67 { 68 struct iovec *iov; 69 u_int cnt; 70 int error = 0; 71 int save = 0; 72 int baseticks = ticks; 73 74 KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE, 75 ("uiomove: mode")); 76 KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread, 77 ("uiomove proc")); 78 79 if (curproc) { 80 save = curproc->p_flag & P_DEADLKTREAT; 81 curproc->p_flag |= P_DEADLKTREAT; 82 } 83 84 while (n > 0 && uio->uio_resid) { 85 iov = uio->uio_iov; 86 cnt = iov->iov_len; 87 if (cnt == 0) { 88 uio->uio_iov++; 89 uio->uio_iovcnt--; 90 continue; 91 } 92 if (cnt > n) 93 cnt = n; 94 95 switch (uio->uio_segflg) { 96 97 case UIO_USERSPACE: 98 case UIO_USERISPACE: 99 if (ticks - baseticks >= hogticks) { 100 uio_yield(); 101 baseticks = ticks; 102 } 103 if (uio->uio_rw == UIO_READ) 104 error = copyout(cp, iov->iov_base, cnt); 105 else 106 error = copyin(iov->iov_base, cp, cnt); 107 if (error) 108 break; 109 break; 110 111 case UIO_SYSSPACE: 112 if (uio->uio_rw == UIO_READ) 113 bcopy((caddr_t)cp, iov->iov_base, cnt); 114 else 115 bcopy(iov->iov_base, (caddr_t)cp, cnt); 116 break; 117 case UIO_NOCOPY: 118 break; 119 } 120 iov->iov_base += cnt; 121 iov->iov_len -= cnt; 122 uio->uio_resid -= cnt; 123 uio->uio_offset += cnt; 124 cp += cnt; 125 n -= cnt; 126 } 127 if (curproc) 128 curproc->p_flag = (curproc->p_flag & ~P_DEADLKTREAT) | save; 129 return (error); 130 } 131 /* 132 * Wrapper for uiomove() that validates the arguments against a known-good 133 * kernel buffer. Currently, uiomove accepts a signed (n) argument, which 134 * is almost definitely a bad thing, so we catch that here as well. We 135 * return a runtime failure, but it might be desirable to generate a runtime 136 * assertion failure instead. 137 */ 138 int 139 uiomove_frombuf(void *buf, int buflen, struct uio *uio) 140 { 141 unsigned int offset, n; 142 143 if (uio->uio_offset < 0 || uio->uio_resid < 0 || 144 (offset = uio->uio_offset) != uio->uio_offset) 145 return (EINVAL); 146 if (buflen <= 0 || offset >= buflen) 147 return (0); 148 if ((n = buflen - offset) > INT_MAX) 149 return (EINVAL); 150 return (uiomove((char *)buf + offset, n, uio)); 151 } 152 153 154 int 155 uiomoveco(cp, n, uio, obj) 156 caddr_t cp; 157 int n; 158 struct uio *uio; 159 struct vm_object *obj; 160 { 161 struct iovec *iov; 162 u_int cnt; 163 int error; 164 int baseticks = ticks; 165 166 KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE, 167 ("uiomoveco: mode")); 168 KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread, 169 ("uiomoveco proc")); 170 171 while (n > 0 && uio->uio_resid) { 172 iov = uio->uio_iov; 173 cnt = iov->iov_len; 174 if (cnt == 0) { 175 uio->uio_iov++; 176 uio->uio_iovcnt--; 177 continue; 178 } 179 if (cnt > n) 180 cnt = n; 181 182 switch (uio->uio_segflg) { 183 184 case UIO_USERSPACE: 185 case UIO_USERISPACE: 186 if (ticks - baseticks >= hogticks) { 187 uio_yield(); 188 baseticks = ticks; 189 } 190 if (uio->uio_rw == UIO_READ) { 191 #ifdef ENABLE_VFS_IOOPT 192 if (vfs_ioopt && ((cnt & PAGE_MASK) == 0) && 193 ((((intptr_t) iov->iov_base) & PAGE_MASK) == 0) && 194 ((uio->uio_offset & PAGE_MASK) == 0) && 195 ((((intptr_t) cp) & PAGE_MASK) == 0)) { 196 error = vm_uiomove(&curproc->p_vmspace->vm_map, obj, 197 uio->uio_offset, cnt, 198 (vm_offset_t) iov->iov_base, NULL); 199 } else 200 #endif 201 { 202 error = copyout(cp, iov->iov_base, cnt); 203 } 204 } else { 205 error = copyin(iov->iov_base, cp, cnt); 206 } 207 if (error) 208 return (error); 209 break; 210 211 case UIO_SYSSPACE: 212 if (uio->uio_rw == UIO_READ) 213 bcopy((caddr_t)cp, iov->iov_base, cnt); 214 else 215 bcopy(iov->iov_base, (caddr_t)cp, cnt); 216 break; 217 case UIO_NOCOPY: 218 break; 219 } 220 iov->iov_base += cnt; 221 iov->iov_len -= cnt; 222 uio->uio_resid -= cnt; 223 uio->uio_offset += cnt; 224 cp += cnt; 225 n -= cnt; 226 } 227 return (0); 228 } 229 230 #ifdef ENABLE_VFS_IOOPT 231 232 int 233 uioread(n, uio, obj, nread) 234 int n; 235 struct uio *uio; 236 struct vm_object *obj; 237 int *nread; 238 { 239 int npagesmoved; 240 struct iovec *iov; 241 u_int cnt, tcnt; 242 int error; 243 int baseticks = ticks; 244 245 *nread = 0; 246 if (vfs_ioopt < 2) 247 return 0; 248 249 error = 0; 250 251 while (n > 0 && uio->uio_resid) { 252 iov = uio->uio_iov; 253 cnt = iov->iov_len; 254 if (cnt == 0) { 255 uio->uio_iov++; 256 uio->uio_iovcnt--; 257 continue; 258 } 259 if (cnt > n) 260 cnt = n; 261 262 if ((uio->uio_segflg == UIO_USERSPACE) && 263 ((((intptr_t) iov->iov_base) & PAGE_MASK) == 0) && 264 ((uio->uio_offset & PAGE_MASK) == 0) ) { 265 266 if (cnt < PAGE_SIZE) 267 break; 268 269 cnt &= ~PAGE_MASK; 270 271 if (ticks - baseticks >= hogticks) { 272 uio_yield(); 273 baseticks = ticks; 274 } 275 error = vm_uiomove(&curproc->p_vmspace->vm_map, obj, 276 uio->uio_offset, cnt, 277 (vm_offset_t) iov->iov_base, &npagesmoved); 278 279 if (npagesmoved == 0) 280 break; 281 282 tcnt = npagesmoved * PAGE_SIZE; 283 cnt = tcnt; 284 285 if (error) 286 break; 287 288 iov->iov_base += cnt; 289 iov->iov_len -= cnt; 290 uio->uio_resid -= cnt; 291 uio->uio_offset += cnt; 292 *nread += cnt; 293 n -= cnt; 294 } else { 295 break; 296 } 297 } 298 return error; 299 } 300 301 #endif 302 303 /* 304 * Give next character to user as result of read. 305 */ 306 int 307 ureadc(c, uio) 308 int c; 309 struct uio *uio; 310 { 311 struct iovec *iov; 312 313 again: 314 if (uio->uio_iovcnt == 0 || uio->uio_resid == 0) 315 panic("ureadc"); 316 iov = uio->uio_iov; 317 if (iov->iov_len == 0) { 318 uio->uio_iovcnt--; 319 uio->uio_iov++; 320 goto again; 321 } 322 switch (uio->uio_segflg) { 323 324 case UIO_USERSPACE: 325 if (subyte(iov->iov_base, c) < 0) 326 return (EFAULT); 327 break; 328 329 case UIO_SYSSPACE: 330 *iov->iov_base = c; 331 break; 332 333 case UIO_USERISPACE: 334 if (suibyte(iov->iov_base, c) < 0) 335 return (EFAULT); 336 break; 337 case UIO_NOCOPY: 338 break; 339 } 340 iov->iov_base++; 341 iov->iov_len--; 342 uio->uio_resid--; 343 uio->uio_offset++; 344 return (0); 345 } 346 347 #ifdef vax /* unused except by ct.c, other oddities XXX */ 348 /* 349 * Get next character written in by user from uio. 350 */ 351 int 352 uwritec(uio) 353 struct uio *uio; 354 { 355 struct iovec *iov; 356 int c; 357 358 if (uio->uio_resid <= 0) 359 return (-1); 360 again: 361 if (uio->uio_iovcnt <= 0) 362 panic("uwritec"); 363 iov = uio->uio_iov; 364 if (iov->iov_len == 0) { 365 uio->uio_iov++; 366 if (--uio->uio_iovcnt == 0) 367 return (-1); 368 goto again; 369 } 370 switch (uio->uio_segflg) { 371 372 case UIO_USERSPACE: 373 c = fubyte(iov->iov_base); 374 break; 375 376 case UIO_SYSSPACE: 377 c = *(u_char *) iov->iov_base; 378 break; 379 380 case UIO_USERISPACE: 381 c = fuibyte(iov->iov_base); 382 break; 383 } 384 if (c < 0) 385 return (-1); 386 iov->iov_base++; 387 iov->iov_len--; 388 uio->uio_resid--; 389 uio->uio_offset++; 390 return (c); 391 } 392 #endif /* vax */ 393 394 /* 395 * General routine to allocate a hash table. Make the hash table size a 396 * power of 2 greater or equal to the number of elements requested, and 397 * store the masking value in *hashmask. 398 */ 399 void * 400 hashinit(elements, type, hashmask) 401 int elements; 402 struct malloc_type *type; 403 u_long *hashmask; 404 { 405 long hashsize; 406 LIST_HEAD(generic, generic) *hashtbl; 407 int i; 408 409 if (elements <= 0) 410 panic("hashinit: bad elements"); 411 for (hashsize = 2; hashsize < elements; hashsize <<= 1) 412 continue; 413 hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK); 414 for (i = 0; i < hashsize; i++) 415 LIST_INIT(&hashtbl[i]); 416 *hashmask = hashsize - 1; 417 return (hashtbl); 418 } 419 420 static int primes[] = { 1, 13, 31, 61, 127, 251, 509, 761, 1021, 1531, 2039, 421 2557, 3067, 3583, 4093, 4603, 5119, 5623, 6143, 6653, 422 7159, 7673, 8191, 12281, 16381, 24571, 32749 }; 423 #define NPRIMES (sizeof(primes) / sizeof(primes[0])) 424 425 /* 426 * General routine to allocate a prime number sized hash table. 427 */ 428 void * 429 phashinit(elements, type, nentries) 430 int elements; 431 struct malloc_type *type; 432 u_long *nentries; 433 { 434 long hashsize; 435 LIST_HEAD(generic, generic) *hashtbl; 436 int i; 437 438 if (elements <= 0) 439 panic("phashinit: bad elements"); 440 for (i = 1, hashsize = primes[1]; hashsize <= elements;) { 441 i++; 442 if (i == NPRIMES) 443 break; 444 hashsize = primes[i]; 445 } 446 hashsize = primes[i - 1]; 447 hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK); 448 for (i = 0; i < hashsize; i++) 449 LIST_INIT(&hashtbl[i]); 450 *nentries = hashsize; 451 return (hashtbl); 452 } 453 454 /* 455 * Copyin an iovec. If the iovec array fits, use the preallocated small 456 * iovec structure. If it is too big, dynamically allocate an iovec array 457 * of sufficient size. 458 */ 459 int 460 iovec_copyin(struct iovec *uiov, struct iovec **kiov, struct iovec *siov, 461 size_t iov_cnt, size_t *iov_len) 462 { 463 struct iovec *iovp; 464 int error, i; 465 466 if (iov_cnt >= UIO_MAXIOV) 467 return EMSGSIZE; 468 if (iov_cnt >= UIO_SMALLIOV) { 469 MALLOC(*kiov, struct iovec *, sizeof(struct iovec) * iov_cnt, 470 M_IOV, M_WAITOK); 471 } else { 472 *kiov = siov; 473 } 474 error = copyin(uiov, *kiov, iov_cnt * sizeof(struct iovec)); 475 if (error) 476 goto cleanup; 477 *iov_len = 0; 478 for (i = 0, iovp = *kiov; i < iov_cnt; i++, iovp++) 479 *iov_len += iovp->iov_len; 480 481 cleanup: 482 if (error) 483 iovec_free(kiov, siov); 484 return (error); 485 } 486