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