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