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