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