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