subr_hash.c revision 65557
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: head/sys/kern/kern_subr.c 65557 2000-09-07 01:33:02Z jasone $ 40 */ 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/kernel.h> 45#include <sys/ktr.h> 46#include <sys/proc.h> 47#include <sys/malloc.h> 48#include <sys/lock.h> 49#include <sys/resourcevar.h> 50#include <sys/vnode.h> 51 52#include <vm/vm.h> 53#include <vm/vm_page.h> 54#include <vm/vm_map.h> 55 56#include <machine/mutex.h> 57 58static void uio_yield __P((void)); 59 60int 61uiomove(cp, n, uio) 62 register caddr_t cp; 63 register int n; 64 register struct uio *uio; 65{ 66 register struct iovec *iov; 67 u_int cnt; 68 int error = 0; 69 int save = 0; 70 71 KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE, 72 ("uiomove: mode")); 73 KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_procp == curproc, 74 ("uiomove proc")); 75 76 if (curproc) { 77 save = curproc->p_flag & P_DEADLKTREAT; 78 curproc->p_flag |= P_DEADLKTREAT; 79 } 80 81 while (n > 0 && uio->uio_resid) { 82 iov = uio->uio_iov; 83 cnt = iov->iov_len; 84 if (cnt == 0) { 85 uio->uio_iov++; 86 uio->uio_iovcnt--; 87 continue; 88 } 89 if (cnt > n) 90 cnt = n; 91 92 switch (uio->uio_segflg) { 93 94 case UIO_USERSPACE: 95 case UIO_USERISPACE: 96 if (ticks - switchticks >= hogticks) 97 uio_yield(); 98 if (uio->uio_rw == UIO_READ) 99 error = copyout(cp, iov->iov_base, cnt); 100 else 101 error = copyin(iov->iov_base, cp, cnt); 102 if (error) 103 break; 104 break; 105 106 case UIO_SYSSPACE: 107 if (uio->uio_rw == UIO_READ) 108 bcopy((caddr_t)cp, iov->iov_base, cnt); 109 else 110 bcopy(iov->iov_base, (caddr_t)cp, cnt); 111 break; 112 case UIO_NOCOPY: 113 break; 114 } 115 iov->iov_base += cnt; 116 iov->iov_len -= cnt; 117 uio->uio_resid -= cnt; 118 uio->uio_offset += cnt; 119 cp += cnt; 120 n -= cnt; 121 } 122 if (curproc) 123 curproc->p_flag = (curproc->p_flag & ~P_DEADLKTREAT) | save; 124 return (error); 125} 126 127int 128uiomoveco(cp, n, uio, obj) 129 caddr_t cp; 130 int n; 131 struct uio *uio; 132 struct vm_object *obj; 133{ 134 struct iovec *iov; 135 u_int cnt; 136 int error; 137 138 KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE, 139 ("uiomoveco: mode")); 140 KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_procp == curproc, 141 ("uiomoveco proc")); 142 143 while (n > 0 && uio->uio_resid) { 144 iov = uio->uio_iov; 145 cnt = iov->iov_len; 146 if (cnt == 0) { 147 uio->uio_iov++; 148 uio->uio_iovcnt--; 149 continue; 150 } 151 if (cnt > n) 152 cnt = n; 153 154 switch (uio->uio_segflg) { 155 156 case UIO_USERSPACE: 157 case UIO_USERISPACE: 158 if (ticks - switchticks >= hogticks) 159 uio_yield(); 160 if (uio->uio_rw == UIO_READ) { 161#ifdef ENABLE_VFS_IOOPT 162 if (vfs_ioopt && ((cnt & PAGE_MASK) == 0) && 163 ((((intptr_t) iov->iov_base) & PAGE_MASK) == 0) && 164 ((uio->uio_offset & PAGE_MASK) == 0) && 165 ((((intptr_t) cp) & PAGE_MASK) == 0)) { 166 error = vm_uiomove(&curproc->p_vmspace->vm_map, obj, 167 uio->uio_offset, cnt, 168 (vm_offset_t) iov->iov_base, NULL); 169 } else 170#endif 171 { 172 error = copyout(cp, iov->iov_base, cnt); 173 } 174 } else { 175 error = copyin(iov->iov_base, cp, cnt); 176 } 177 if (error) 178 return (error); 179 break; 180 181 case UIO_SYSSPACE: 182 if (uio->uio_rw == UIO_READ) 183 bcopy((caddr_t)cp, iov->iov_base, cnt); 184 else 185 bcopy(iov->iov_base, (caddr_t)cp, cnt); 186 break; 187 case UIO_NOCOPY: 188 break; 189 } 190 iov->iov_base += cnt; 191 iov->iov_len -= cnt; 192 uio->uio_resid -= cnt; 193 uio->uio_offset += cnt; 194 cp += cnt; 195 n -= cnt; 196 } 197 return (0); 198} 199 200#ifdef ENABLE_VFS_IOOPT 201 202int 203uioread(n, uio, obj, nread) 204 int n; 205 struct uio *uio; 206 struct vm_object *obj; 207 int *nread; 208{ 209 int npagesmoved; 210 struct iovec *iov; 211 u_int cnt, tcnt; 212 int error; 213 214 *nread = 0; 215 if (vfs_ioopt < 2) 216 return 0; 217 218 error = 0; 219 220 while (n > 0 && uio->uio_resid) { 221 iov = uio->uio_iov; 222 cnt = iov->iov_len; 223 if (cnt == 0) { 224 uio->uio_iov++; 225 uio->uio_iovcnt--; 226 continue; 227 } 228 if (cnt > n) 229 cnt = n; 230 231 if ((uio->uio_segflg == UIO_USERSPACE) && 232 ((((intptr_t) iov->iov_base) & PAGE_MASK) == 0) && 233 ((uio->uio_offset & PAGE_MASK) == 0) ) { 234 235 if (cnt < PAGE_SIZE) 236 break; 237 238 cnt &= ~PAGE_MASK; 239 240 if (ticks - switchticks >= hogticks) 241 uio_yield(); 242 error = vm_uiomove(&curproc->p_vmspace->vm_map, obj, 243 uio->uio_offset, cnt, 244 (vm_offset_t) iov->iov_base, &npagesmoved); 245 246 if (npagesmoved == 0) 247 break; 248 249 tcnt = npagesmoved * PAGE_SIZE; 250 cnt = tcnt; 251 252 if (error) 253 break; 254 255 iov->iov_base += cnt; 256 iov->iov_len -= cnt; 257 uio->uio_resid -= cnt; 258 uio->uio_offset += cnt; 259 *nread += cnt; 260 n -= cnt; 261 } else { 262 break; 263 } 264 } 265 return error; 266} 267 268#endif 269 270/* 271 * Give next character to user as result of read. 272 */ 273int 274ureadc(c, uio) 275 register int c; 276 register struct uio *uio; 277{ 278 register struct iovec *iov; 279 280again: 281 if (uio->uio_iovcnt == 0 || uio->uio_resid == 0) 282 panic("ureadc"); 283 iov = uio->uio_iov; 284 if (iov->iov_len == 0) { 285 uio->uio_iovcnt--; 286 uio->uio_iov++; 287 goto again; 288 } 289 switch (uio->uio_segflg) { 290 291 case UIO_USERSPACE: 292 if (subyte(iov->iov_base, c) < 0) 293 return (EFAULT); 294 break; 295 296 case UIO_SYSSPACE: 297 *iov->iov_base = c; 298 break; 299 300 case UIO_USERISPACE: 301 if (suibyte(iov->iov_base, c) < 0) 302 return (EFAULT); 303 break; 304 case UIO_NOCOPY: 305 break; 306 } 307 iov->iov_base++; 308 iov->iov_len--; 309 uio->uio_resid--; 310 uio->uio_offset++; 311 return (0); 312} 313 314#ifdef vax /* unused except by ct.c, other oddities XXX */ 315/* 316 * Get next character written in by user from uio. 317 */ 318int 319uwritec(uio) 320 struct uio *uio; 321{ 322 register struct iovec *iov; 323 register int c; 324 325 if (uio->uio_resid <= 0) 326 return (-1); 327again: 328 if (uio->uio_iovcnt <= 0) 329 panic("uwritec"); 330 iov = uio->uio_iov; 331 if (iov->iov_len == 0) { 332 uio->uio_iov++; 333 if (--uio->uio_iovcnt == 0) 334 return (-1); 335 goto again; 336 } 337 switch (uio->uio_segflg) { 338 339 case UIO_USERSPACE: 340 c = fubyte(iov->iov_base); 341 break; 342 343 case UIO_SYSSPACE: 344 c = *(u_char *) iov->iov_base; 345 break; 346 347 case UIO_USERISPACE: 348 c = fuibyte(iov->iov_base); 349 break; 350 } 351 if (c < 0) 352 return (-1); 353 iov->iov_base++; 354 iov->iov_len--; 355 uio->uio_resid--; 356 uio->uio_offset++; 357 return (c); 358} 359#endif /* vax */ 360 361/* 362 * General routine to allocate a hash table. 363 */ 364void * 365hashinit(elements, type, hashmask) 366 int elements; 367 struct malloc_type *type; 368 u_long *hashmask; 369{ 370 long hashsize; 371 LIST_HEAD(generic, generic) *hashtbl; 372 int i; 373 374 if (elements <= 0) 375 panic("hashinit: bad elements"); 376 for (hashsize = 1; hashsize <= elements; hashsize <<= 1) 377 continue; 378 hashsize >>= 1; 379 hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK); 380 for (i = 0; i < hashsize; i++) 381 LIST_INIT(&hashtbl[i]); 382 *hashmask = hashsize - 1; 383 return (hashtbl); 384} 385 386static int primes[] = { 1, 13, 31, 61, 127, 251, 509, 761, 1021, 1531, 2039, 387 2557, 3067, 3583, 4093, 4603, 5119, 5623, 6143, 6653, 388 7159, 7673, 8191, 12281, 16381, 24571, 32749 }; 389#define NPRIMES (sizeof(primes) / sizeof(primes[0])) 390 391/* 392 * General routine to allocate a prime number sized hash table. 393 */ 394void * 395phashinit(elements, type, nentries) 396 int elements; 397 struct malloc_type *type; 398 u_long *nentries; 399{ 400 long hashsize; 401 LIST_HEAD(generic, generic) *hashtbl; 402 int i; 403 404 if (elements <= 0) 405 panic("phashinit: bad elements"); 406 for (i = 1, hashsize = primes[1]; hashsize <= elements;) { 407 i++; 408 if (i == NPRIMES) 409 break; 410 hashsize = primes[i]; 411 } 412 hashsize = primes[i - 1]; 413 hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK); 414 for (i = 0; i < hashsize; i++) 415 LIST_INIT(&hashtbl[i]); 416 *nentries = hashsize; 417 return (hashtbl); 418} 419 420static void 421uio_yield() 422{ 423 struct proc *p; 424 int s; 425 426 p = curproc; 427 s = splhigh(); 428 mtx_enter(&sched_lock, MTX_SPIN); 429 p->p_priority = p->p_usrpri; 430 setrunqueue(p); 431 p->p_stats->p_ru.ru_nivcsw++; 432 mi_switch(); 433 mtx_exit(&sched_lock, MTX_SPIN); 434 splx(s); 435} 436