DDB updates:
[dragonfly.git] / sys / kern / kern_subr.c
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 }