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