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