subr_uio.c revision 42408
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1982, 1986, 1991, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * (c) UNIX System Laboratories, Inc. 51541Srgrimes * All or some portions of this file are derived from material licensed 61541Srgrimes * to the University of California by American Telephone and Telegraph 71541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 81541Srgrimes * the permission of UNIX System Laboratories, Inc. 91541Srgrimes * 101541Srgrimes * Redistribution and use in source and binary forms, with or without 111541Srgrimes * modification, are permitted provided that the following conditions 121541Srgrimes * are met: 131541Srgrimes * 1. Redistributions of source code must retain the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer. 151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161541Srgrimes * notice, this list of conditions and the following disclaimer in the 171541Srgrimes * documentation and/or other materials provided with the distribution. 181541Srgrimes * 3. All advertising materials mentioning features or use of this software 191541Srgrimes * must display the following acknowledgement: 201541Srgrimes * This product includes software developed by the University of 211541Srgrimes * California, Berkeley and its contributors. 221541Srgrimes * 4. Neither the name of the University nor the names of its contributors 231541Srgrimes * may be used to endorse or promote products derived from this software 241541Srgrimes * without specific prior written permission. 251541Srgrimes * 261541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 271541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 281541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 291541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 301541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 311541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 321541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 331541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 341541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 351541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 361541Srgrimes * SUCH DAMAGE. 371541Srgrimes * 381541Srgrimes * @(#)kern_subr.c 8.3 (Berkeley) 1/21/94 3942408Seivind * $Id: kern_subr.c,v 1.22 1998/08/04 09:21:04 phk Exp $ 401541Srgrimes */ 411541Srgrimes 421541Srgrimes#include <sys/param.h> 431541Srgrimes#include <sys/systm.h> 441541Srgrimes#include <sys/proc.h> 451541Srgrimes#include <sys/malloc.h> 4631853Sdyson#include <sys/lock.h> 4732702Sdyson#include <sys/vnode.h> 481541Srgrimes 4931853Sdyson#include <vm/vm.h> 5031853Sdyson#include <vm/vm_prot.h> 5131853Sdyson#include <vm/vm_page.h> 5231853Sdyson#include <vm/vm_map.h> 5331853Sdyson 541549Srgrimesint 551541Srgrimesuiomove(cp, n, uio) 561541Srgrimes register caddr_t cp; 571541Srgrimes register int n; 581541Srgrimes register struct uio *uio; 591541Srgrimes{ 601541Srgrimes register struct iovec *iov; 611541Srgrimes u_int cnt; 626324Sdg int error; 631541Srgrimes 6442408Seivind KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE, 6542408Seivind ("uiomove: mode")); 6642408Seivind KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_procp == curproc, 6742408Seivind ("uiomove proc")); 6842408Seivind 691541Srgrimes while (n > 0 && uio->uio_resid) { 701541Srgrimes iov = uio->uio_iov; 711541Srgrimes cnt = iov->iov_len; 721541Srgrimes if (cnt == 0) { 731541Srgrimes uio->uio_iov++; 741541Srgrimes uio->uio_iovcnt--; 751541Srgrimes continue; 761541Srgrimes } 771541Srgrimes if (cnt > n) 781541Srgrimes cnt = n; 796324Sdg 801541Srgrimes switch (uio->uio_segflg) { 811541Srgrimes 821541Srgrimes case UIO_USERSPACE: 831541Srgrimes case UIO_USERISPACE: 841541Srgrimes if (uio->uio_rw == UIO_READ) 851541Srgrimes error = copyout(cp, iov->iov_base, cnt); 861541Srgrimes else 871541Srgrimes error = copyin(iov->iov_base, cp, cnt); 881541Srgrimes if (error) 891541Srgrimes return (error); 901541Srgrimes break; 911541Srgrimes 921541Srgrimes case UIO_SYSSPACE: 931541Srgrimes if (uio->uio_rw == UIO_READ) 941541Srgrimes bcopy((caddr_t)cp, iov->iov_base, cnt); 951541Srgrimes else 961541Srgrimes bcopy(iov->iov_base, (caddr_t)cp, cnt); 971541Srgrimes break; 987611Sdg case UIO_NOCOPY: 997611Sdg break; 1001541Srgrimes } 1011541Srgrimes iov->iov_base += cnt; 1021541Srgrimes iov->iov_len -= cnt; 1031541Srgrimes uio->uio_resid -= cnt; 1041541Srgrimes uio->uio_offset += cnt; 1051541Srgrimes cp += cnt; 1061541Srgrimes n -= cnt; 1071541Srgrimes } 1086324Sdg return (0); 1091541Srgrimes} 1101541Srgrimes 11131853Sdysonint 11231853Sdysonuiomoveco(cp, n, uio, obj) 11331853Sdyson caddr_t cp; 11431853Sdyson int n; 11531853Sdyson struct uio *uio; 11631853Sdyson struct vm_object *obj; 11731853Sdyson{ 11831853Sdyson struct iovec *iov; 11931853Sdyson u_int cnt; 12031853Sdyson int error; 12131853Sdyson 12242408Seivind KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE, 12342408Seivind ("uiomoveco: mode")); 12442408Seivind KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_procp == curproc, 12542408Seivind ("uiomoveco proc")); 12642408Seivind 12731853Sdyson while (n > 0 && uio->uio_resid) { 12831853Sdyson iov = uio->uio_iov; 12931853Sdyson cnt = iov->iov_len; 13031853Sdyson if (cnt == 0) { 13131853Sdyson uio->uio_iov++; 13231853Sdyson uio->uio_iovcnt--; 13331853Sdyson continue; 13431853Sdyson } 13531853Sdyson if (cnt > n) 13631853Sdyson cnt = n; 13731853Sdyson 13831853Sdyson switch (uio->uio_segflg) { 13931853Sdyson 14031853Sdyson case UIO_USERSPACE: 14131853Sdyson case UIO_USERISPACE: 14231853Sdyson if (uio->uio_rw == UIO_READ) { 14332702Sdyson if (vfs_ioopt && ((cnt & PAGE_MASK) == 0) && 14437649Sbde ((((intptr_t) iov->iov_base) & PAGE_MASK) == 0) && 14531853Sdyson ((uio->uio_offset & PAGE_MASK) == 0) && 14637649Sbde ((((intptr_t) cp) & PAGE_MASK) == 0)) { 14731853Sdyson error = vm_uiomove(&curproc->p_vmspace->vm_map, obj, 14831853Sdyson uio->uio_offset, cnt, 14932286Sdyson (vm_offset_t) iov->iov_base, NULL); 15031853Sdyson } else { 15131853Sdyson error = copyout(cp, iov->iov_base, cnt); 15231853Sdyson } 15331853Sdyson } else { 15431853Sdyson error = copyin(iov->iov_base, cp, cnt); 15531853Sdyson } 15631853Sdyson if (error) 15731853Sdyson return (error); 15831853Sdyson break; 15931853Sdyson 16031853Sdyson case UIO_SYSSPACE: 16131853Sdyson if (uio->uio_rw == UIO_READ) 16231853Sdyson bcopy((caddr_t)cp, iov->iov_base, cnt); 16331853Sdyson else 16431853Sdyson bcopy(iov->iov_base, (caddr_t)cp, cnt); 16531853Sdyson break; 16631853Sdyson case UIO_NOCOPY: 16731853Sdyson break; 16831853Sdyson } 16931853Sdyson iov->iov_base += cnt; 17031853Sdyson iov->iov_len -= cnt; 17131853Sdyson uio->uio_resid -= cnt; 17231853Sdyson uio->uio_offset += cnt; 17331853Sdyson cp += cnt; 17431853Sdyson n -= cnt; 17531853Sdyson } 17631853Sdyson return (0); 17731853Sdyson} 17831853Sdyson 17932286Sdysonint 18032286Sdysonuioread(n, uio, obj, nread) 18132286Sdyson int n; 18232286Sdyson struct uio *uio; 18332286Sdyson struct vm_object *obj; 18432286Sdyson int *nread; 18532286Sdyson{ 18632286Sdyson int npagesmoved; 18732286Sdyson struct iovec *iov; 18832286Sdyson u_int cnt, tcnt; 18932286Sdyson int error; 19032286Sdyson 19132286Sdyson *nread = 0; 19233109Sdyson if (vfs_ioopt < 2) 19332702Sdyson return 0; 19433109Sdyson 19532286Sdyson error = 0; 19632286Sdyson 19732286Sdyson while (n > 0 && uio->uio_resid) { 19832286Sdyson iov = uio->uio_iov; 19932286Sdyson cnt = iov->iov_len; 20032286Sdyson if (cnt == 0) { 20132286Sdyson uio->uio_iov++; 20232286Sdyson uio->uio_iovcnt--; 20332286Sdyson continue; 20432286Sdyson } 20532286Sdyson if (cnt > n) 20632286Sdyson cnt = n; 20732286Sdyson 20832286Sdyson if ((uio->uio_segflg == UIO_USERSPACE) && 20937649Sbde ((((intptr_t) iov->iov_base) & PAGE_MASK) == 0) && 21032286Sdyson ((uio->uio_offset & PAGE_MASK) == 0) ) { 21132286Sdyson 21232286Sdyson if (cnt < PAGE_SIZE) 21332286Sdyson break; 21432286Sdyson 21532286Sdyson cnt &= ~PAGE_MASK; 21632286Sdyson 21732286Sdyson error = vm_uiomove(&curproc->p_vmspace->vm_map, obj, 21832286Sdyson uio->uio_offset, cnt, 21932286Sdyson (vm_offset_t) iov->iov_base, &npagesmoved); 22032286Sdyson 22132286Sdyson if (npagesmoved == 0) 22232286Sdyson break; 22332286Sdyson 22432286Sdyson tcnt = npagesmoved * PAGE_SIZE; 22538068Sphk cnt = tcnt; 22632286Sdyson 22732286Sdyson if (error) 22832286Sdyson break; 22932286Sdyson 23032286Sdyson iov->iov_base += cnt; 23132286Sdyson iov->iov_len -= cnt; 23232286Sdyson uio->uio_resid -= cnt; 23332286Sdyson uio->uio_offset += cnt; 23432286Sdyson *nread += cnt; 23532286Sdyson n -= cnt; 23632286Sdyson } else { 23732286Sdyson break; 23832286Sdyson } 23932286Sdyson } 24032286Sdyson return error; 24132286Sdyson} 24232286Sdyson 2431541Srgrimes/* 2441541Srgrimes * Give next character to user as result of read. 2451541Srgrimes */ 2461549Srgrimesint 2471541Srgrimesureadc(c, uio) 2481541Srgrimes register int c; 2491541Srgrimes register struct uio *uio; 2501541Srgrimes{ 2511541Srgrimes register struct iovec *iov; 2521541Srgrimes 2531541Srgrimesagain: 2541541Srgrimes if (uio->uio_iovcnt == 0 || uio->uio_resid == 0) 2551541Srgrimes panic("ureadc"); 2561541Srgrimes iov = uio->uio_iov; 2571541Srgrimes if (iov->iov_len == 0) { 2581541Srgrimes uio->uio_iovcnt--; 2591541Srgrimes uio->uio_iov++; 2601541Srgrimes goto again; 2611541Srgrimes } 2621541Srgrimes switch (uio->uio_segflg) { 2631541Srgrimes 2641541Srgrimes case UIO_USERSPACE: 2651541Srgrimes if (subyte(iov->iov_base, c) < 0) 2661541Srgrimes return (EFAULT); 2671541Srgrimes break; 2681541Srgrimes 2691541Srgrimes case UIO_SYSSPACE: 2701541Srgrimes *iov->iov_base = c; 2711541Srgrimes break; 2721541Srgrimes 2731541Srgrimes case UIO_USERISPACE: 2741541Srgrimes if (suibyte(iov->iov_base, c) < 0) 2751541Srgrimes return (EFAULT); 2761541Srgrimes break; 2778177Sdg case UIO_NOCOPY: 2788177Sdg break; 2791541Srgrimes } 2801541Srgrimes iov->iov_base++; 2811541Srgrimes iov->iov_len--; 2821541Srgrimes uio->uio_resid--; 2831541Srgrimes uio->uio_offset++; 2841541Srgrimes return (0); 2851541Srgrimes} 2861541Srgrimes 2871541Srgrimes#ifdef vax /* unused except by ct.c, other oddities XXX */ 2881541Srgrimes/* 2891541Srgrimes * Get next character written in by user from uio. 2901541Srgrimes */ 2911549Srgrimesint 2921541Srgrimesuwritec(uio) 2931541Srgrimes struct uio *uio; 2941541Srgrimes{ 2951541Srgrimes register struct iovec *iov; 2961541Srgrimes register int c; 2971541Srgrimes 2981541Srgrimes if (uio->uio_resid <= 0) 2991541Srgrimes return (-1); 3001541Srgrimesagain: 3011541Srgrimes if (uio->uio_iovcnt <= 0) 3021541Srgrimes panic("uwritec"); 3031541Srgrimes iov = uio->uio_iov; 3041541Srgrimes if (iov->iov_len == 0) { 3051541Srgrimes uio->uio_iov++; 3061541Srgrimes if (--uio->uio_iovcnt == 0) 3071541Srgrimes return (-1); 3081541Srgrimes goto again; 3091541Srgrimes } 3101541Srgrimes switch (uio->uio_segflg) { 3111541Srgrimes 3121541Srgrimes case UIO_USERSPACE: 3131541Srgrimes c = fubyte(iov->iov_base); 3141541Srgrimes break; 3151541Srgrimes 3161541Srgrimes case UIO_SYSSPACE: 3171541Srgrimes c = *(u_char *) iov->iov_base; 3181541Srgrimes break; 3191541Srgrimes 3201541Srgrimes case UIO_USERISPACE: 3211541Srgrimes c = fuibyte(iov->iov_base); 3221541Srgrimes break; 3231541Srgrimes } 3241541Srgrimes if (c < 0) 3251541Srgrimes return (-1); 3261541Srgrimes iov->iov_base++; 3271541Srgrimes iov->iov_len--; 3281541Srgrimes uio->uio_resid--; 3291541Srgrimes uio->uio_offset++; 3301541Srgrimes return (c); 3311541Srgrimes} 3321541Srgrimes#endif /* vax */ 3331541Srgrimes 3341541Srgrimes/* 3351541Srgrimes * General routine to allocate a hash table. 3361541Srgrimes */ 3371541Srgrimesvoid * 3381541Srgrimeshashinit(elements, type, hashmask) 33930281Sphk int elements; 34030281Sphk struct malloc_type *type; 3411541Srgrimes u_long *hashmask; 3421541Srgrimes{ 3431541Srgrimes long hashsize; 3441541Srgrimes LIST_HEAD(generic, generic) *hashtbl; 3451541Srgrimes int i; 3461541Srgrimes 3471541Srgrimes if (elements <= 0) 3488364Sdg panic("hashinit: bad elements"); 3491541Srgrimes for (hashsize = 1; hashsize <= elements; hashsize <<= 1) 3501541Srgrimes continue; 3511541Srgrimes hashsize >>= 1; 3521541Srgrimes hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK); 3531541Srgrimes for (i = 0; i < hashsize; i++) 3541541Srgrimes LIST_INIT(&hashtbl[i]); 3551541Srgrimes *hashmask = hashsize - 1; 3561541Srgrimes return (hashtbl); 3571541Srgrimes} 3587611Sdg 3597683Sdgstatic int primes[] = { 1, 13, 31, 61, 127, 251, 509, 761, 1021, 1531, 2039, 3607683Sdg 2557, 3067, 3583, 4093, 4603, 5119, 5623, 6143, 6653, 3617611Sdg 7159, 7673, 8191, 12281, 16381, 24571, 32749 }; 36226205Salex#define NPRIMES (sizeof(primes) / sizeof(primes[0])) 3637611Sdg 3647611Sdg/* 3657611Sdg * General routine to allocate a prime number sized hash table. 3667611Sdg */ 3677611Sdgvoid * 3687611Sdgphashinit(elements, type, nentries) 36930281Sphk int elements; 37030281Sphk struct malloc_type *type; 3717611Sdg u_long *nentries; 3727611Sdg{ 3737611Sdg long hashsize; 3747611Sdg LIST_HEAD(generic, generic) *hashtbl; 3757611Sdg int i; 3767611Sdg 3777611Sdg if (elements <= 0) 3788364Sdg panic("phashinit: bad elements"); 3797611Sdg for (i = 1, hashsize = primes[1]; hashsize <= elements;) { 3807611Sdg i++; 3817611Sdg if (i == NPRIMES) 3827611Sdg break; 3837611Sdg hashsize = primes[i]; 3847611Sdg } 3857611Sdg hashsize = primes[i - 1]; 3867611Sdg hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK); 3877611Sdg for (i = 0; i < hashsize; i++) 3887611Sdg LIST_INIT(&hashtbl[i]); 3897611Sdg *nentries = hashsize; 3907611Sdg return (hashtbl); 3917611Sdg} 392