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