]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/kern_subr.c
This commit was generated by cvs2svn to compensate for changes in r106163,
[FreeBSD/FreeBSD.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$
40  */
41
42 #include "opt_zero.h"
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/ktr.h>
48 #include <sys/lock.h>
49 #include <sys/mutex.h>
50 #include <sys/proc.h>
51 #include <sys/malloc.h>
52 #include <sys/resourcevar.h>
53 #include <sys/sched.h>
54 #include <sys/sysctl.h>
55 #include <sys/vnode.h>
56
57 #include <vm/vm.h>
58 #include <vm/vm_page.h>
59 #include <vm/vm_map.h>
60 #ifdef ZERO_COPY_SOCKETS
61 #include <vm/vm_param.h>
62 #endif
63 #if defined(ZERO_COPY_SOCKETS) || defined(ENABLE_VFS_IOOPT)
64 #include <vm/vm_object.h>
65 #endif
66
67 SYSCTL_INT(_kern, KERN_IOV_MAX, iov_max, CTLFLAG_RD, NULL, UIO_MAXIOV, 
68         "Maximum number of elements in an I/O vector; sysconf(_SC_IOV_MAX)");
69
70 #if defined(ZERO_COPY_SOCKETS) || defined(ENABLE_VFS_IOOPT)
71 static int userspaceco(caddr_t cp, u_int cnt, struct uio *uio,
72                        struct vm_object *obj, int disposable);
73 #endif
74
75 #ifdef ZERO_COPY_SOCKETS
76 /* Declared in uipc_socket.c */
77 extern int so_zero_copy_receive;
78
79 static int vm_pgmoveco(vm_map_t mapa, vm_object_t srcobj, vm_offset_t kaddr,
80                        vm_offset_t uaddr);
81
82 static int
83 vm_pgmoveco(mapa, srcobj,  kaddr, uaddr)
84         vm_map_t mapa;
85         vm_object_t srcobj;
86         vm_offset_t kaddr, uaddr;
87 {
88         vm_map_t map = mapa;
89         vm_page_t kern_pg, user_pg;
90         vm_object_t uobject;
91         vm_map_entry_t entry;
92         vm_pindex_t upindex, kpindex;
93         vm_prot_t prot;
94         boolean_t wired;
95
96         /*
97          * First lookup the kernel page.
98          */
99         kern_pg = PHYS_TO_VM_PAGE(vtophys(kaddr));
100
101         if ((vm_map_lookup(&map, uaddr,
102                            VM_PROT_READ, &entry, &uobject,
103                            &upindex, &prot, &wired)) != KERN_SUCCESS) {
104                 return(EFAULT);
105         }
106         if ((user_pg = vm_page_lookup(uobject, upindex)) != NULL) {
107                 vm_page_lock_queues();
108                 if (!vm_page_sleep_if_busy(user_pg, 1, "vm_pgmoveco"))
109                         vm_page_unlock_queues();
110                 pmap_remove(map->pmap, uaddr, uaddr+PAGE_SIZE);
111                 vm_page_lock_queues();
112                 vm_page_busy(user_pg);
113                 vm_page_free(user_pg);
114                 vm_page_unlock_queues();
115         }
116
117         if (kern_pg->busy || ((kern_pg->queue - kern_pg->pc) == PQ_FREE) ||
118             (kern_pg->hold_count != 0)|| (kern_pg->flags & PG_BUSY)) {
119                 printf("vm_pgmoveco: pindex(%lu), busy(%d), PG_BUSY(%d), "
120                        "hold(%d) paddr(0x%lx)\n", (u_long)kern_pg->pindex,
121                         kern_pg->busy, (kern_pg->flags & PG_BUSY) ? 1 : 0,
122                         kern_pg->hold_count, (u_long)kern_pg->phys_addr);
123                 if ((kern_pg->queue - kern_pg->pc) == PQ_FREE)
124                         panic("vm_pgmoveco: renaming free page");
125                 else
126                         panic("vm_pgmoveco: renaming busy page");
127         }
128         kpindex = kern_pg->pindex;
129         vm_page_busy(kern_pg);
130         vm_page_rename(kern_pg, uobject, upindex);
131         vm_page_flag_clear(kern_pg, PG_BUSY);
132         kern_pg->valid = VM_PAGE_BITS_ALL;
133         
134         vm_map_lookup_done(map, entry);
135         return(KERN_SUCCESS);
136 }
137 #endif /* ZERO_COPY_SOCKETS */
138
139 int
140 uiomove(cp, n, uio)
141         register caddr_t cp;
142         register int n;
143         register struct uio *uio;
144 {
145         struct thread *td = curthread;
146         register struct iovec *iov;
147         u_int cnt;
148         int error = 0;
149         int save = 0;
150
151         KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE,
152             ("uiomove: mode"));
153         KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread,
154             ("uiomove proc"));
155
156         if (td) {
157                 mtx_lock_spin(&sched_lock);
158                 save = td->td_flags & TDF_DEADLKTREAT;
159                 td->td_flags |= TDF_DEADLKTREAT;
160                 mtx_unlock_spin(&sched_lock);
161         }
162
163         while (n > 0 && uio->uio_resid) {
164                 iov = uio->uio_iov;
165                 cnt = iov->iov_len;
166                 if (cnt == 0) {
167                         uio->uio_iov++;
168                         uio->uio_iovcnt--;
169                         continue;
170                 }
171                 if (cnt > n)
172                         cnt = n;
173
174                 switch (uio->uio_segflg) {
175
176                 case UIO_USERSPACE:
177                         if (ticks - PCPU_GET(switchticks) >= hogticks)
178                                 uio_yield();
179                         if (uio->uio_rw == UIO_READ)
180                                 error = copyout(cp, iov->iov_base, cnt);
181                         else
182                                 error = copyin(iov->iov_base, cp, cnt);
183                         if (error)
184                                 goto out;
185                         break;
186
187                 case UIO_SYSSPACE:
188                         if (uio->uio_rw == UIO_READ)
189                                 bcopy(cp, iov->iov_base, cnt);
190                         else
191                                 bcopy(iov->iov_base, cp, cnt);
192                         break;
193                 case UIO_NOCOPY:
194                         break;
195                 }
196                 iov->iov_base = (char *)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 out:
204         if (td != curthread) printf("uiomove: IT CHANGED!");
205         td = curthread; /* Might things have changed in copyin/copyout? */
206         if (td) {
207                 mtx_lock_spin(&sched_lock);
208                 td->td_flags = (td->td_flags & ~TDF_DEADLKTREAT) | save;
209                 mtx_unlock_spin(&sched_lock);
210         }
211         return (error);
212 }
213
214 #if defined(ENABLE_VFS_IOOPT) || defined(ZERO_COPY_SOCKETS)
215 /*
216  * Experimental support for zero-copy I/O
217  */
218 static int
219 userspaceco(cp, cnt, uio, obj, disposable)
220         caddr_t cp;
221         u_int cnt;
222         struct uio *uio;
223         struct vm_object *obj;
224         int disposable;
225 {
226         struct iovec *iov;
227         int error;
228
229         iov = uio->uio_iov;
230
231 #ifdef ZERO_COPY_SOCKETS
232
233         if (uio->uio_rw == UIO_READ) {
234                 if ((so_zero_copy_receive != 0)
235                  && (obj != NULL)
236                  && ((cnt & PAGE_MASK) == 0)
237                  && ((((intptr_t) iov->iov_base) & PAGE_MASK) == 0)
238                  && ((uio->uio_offset & PAGE_MASK) == 0)
239                  && ((((intptr_t) cp) & PAGE_MASK) == 0)
240                  && (obj->type == OBJT_DEFAULT)
241                  && (disposable != 0)) {
242                         /* SOCKET: use page-trading */
243                         /*
244                          * We only want to call vm_pgmoveco() on
245                          * disposeable pages, since it gives the
246                          * kernel page to the userland process.
247                          */
248                         error = vm_pgmoveco(&curproc->p_vmspace->vm_map,
249                                             obj, (vm_offset_t)cp, 
250                                             (vm_offset_t)iov->iov_base);
251
252                         /*
253                          * If we get an error back, attempt
254                          * to use copyout() instead.  The
255                          * disposable page should be freed
256                          * automatically if we weren't able to move
257                          * it into userland.
258                          */
259                         if (error != 0)
260                                 error = copyout(cp, iov->iov_base, cnt);
261 #ifdef ENABLE_VFS_IOOPT
262                 } else if ((vfs_ioopt != 0)
263                  && ((cnt & PAGE_MASK) == 0)
264                  && ((((intptr_t) iov->iov_base) & PAGE_MASK) == 0)
265                  && ((uio->uio_offset & PAGE_MASK) == 0)
266                  && ((((intptr_t) cp) & PAGE_MASK) == 0)) {
267                         error = vm_uiomove(&curproc->p_vmspace->vm_map, obj,
268                                            uio->uio_offset, cnt,
269                                            (vm_offset_t) iov->iov_base, NULL);
270 #endif /* ENABLE_VFS_IOOPT */
271                 } else {
272                         error = copyout(cp, iov->iov_base, cnt);
273                 }
274         } else {
275                 error = copyin(iov->iov_base, cp, cnt);
276         }
277 #else /* ZERO_COPY_SOCKETS */
278         if (uio->uio_rw == UIO_READ) {
279 #ifdef ENABLE_VFS_IOOPT
280                 if ((vfs_ioopt != 0)
281                  && ((cnt & PAGE_MASK) == 0)
282                  && ((((intptr_t) iov->iov_base) & PAGE_MASK) == 0)
283                  && ((uio->uio_offset & PAGE_MASK) == 0)
284                  && ((((intptr_t) cp) & PAGE_MASK) == 0)) {
285                         error = vm_uiomove(&curproc->p_vmspace->vm_map, obj,
286                                            uio->uio_offset, cnt,
287                                            (vm_offset_t) iov->iov_base, NULL);
288                 } else
289 #endif /* ENABLE_VFS_IOOPT */
290                 {
291                         error = copyout(cp, iov->iov_base, cnt);
292                 }
293         } else {
294                 error = copyin(iov->iov_base, cp, cnt);
295         }
296 #endif /* ZERO_COPY_SOCKETS */
297
298         return (error);
299 }
300
301 int
302 uiomoveco(cp, n, uio, obj, disposable)
303         caddr_t cp;
304         int n;
305         struct uio *uio;
306         struct vm_object *obj;
307         int disposable;
308 {
309         struct iovec *iov;
310         u_int cnt;
311         int error;
312
313         KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE,
314             ("uiomoveco: mode"));
315         KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread,
316             ("uiomoveco proc"));
317
318         while (n > 0 && uio->uio_resid) {
319                 iov = uio->uio_iov;
320                 cnt = iov->iov_len;
321                 if (cnt == 0) {
322                         uio->uio_iov++;
323                         uio->uio_iovcnt--;
324                         continue;
325                 }
326                 if (cnt > n)
327                         cnt = n;
328
329                 switch (uio->uio_segflg) {
330
331                 case UIO_USERSPACE:
332                         if (ticks - PCPU_GET(switchticks) >= hogticks)
333                                 uio_yield();
334
335                         error = userspaceco(cp, cnt, uio, obj, disposable);
336
337                         if (error)
338                                 return (error);
339                         break;
340
341                 case UIO_SYSSPACE:
342                         if (uio->uio_rw == UIO_READ)
343                                 bcopy(cp, iov->iov_base, cnt);
344                         else
345                                 bcopy(iov->iov_base, cp, cnt);
346                         break;
347                 case UIO_NOCOPY:
348                         break;
349                 }
350                 iov->iov_base = (char *)iov->iov_base + cnt;
351                 iov->iov_len -= cnt;
352                 uio->uio_resid -= cnt;
353                 uio->uio_offset += cnt;
354                 cp += cnt;
355                 n -= cnt;
356         }
357         return (0);
358 }
359 #endif /* ENABLE_VFS_IOOPT || ZERO_COPY_SOCKETS */
360
361 #ifdef ENABLE_VFS_IOOPT
362
363 /*
364  * Experimental support for zero-copy I/O
365  */
366 int
367 uioread(n, uio, obj, nread)
368         int n;
369         struct uio *uio;
370         struct vm_object *obj;
371         int *nread;
372 {
373         int npagesmoved;
374         struct iovec *iov;
375         u_int cnt, tcnt;
376         int error;
377
378         *nread = 0;
379         if (vfs_ioopt < 2)
380                 return 0;
381
382         error = 0;
383
384         while (n > 0 && uio->uio_resid) {
385                 iov = uio->uio_iov;
386                 cnt = iov->iov_len;
387                 if (cnt == 0) {
388                         uio->uio_iov++;
389                         uio->uio_iovcnt--;
390                         continue;
391                 }
392                 if (cnt > n)
393                         cnt = n;
394
395                 if ((uio->uio_segflg == UIO_USERSPACE) &&
396                         ((((intptr_t) iov->iov_base) & PAGE_MASK) == 0) &&
397                                  ((uio->uio_offset & PAGE_MASK) == 0) ) {
398
399                         if (cnt < PAGE_SIZE)
400                                 break;
401
402                         cnt &= ~PAGE_MASK;
403
404                         if (ticks - PCPU_GET(switchticks) >= hogticks)
405                                 uio_yield();
406                         error = vm_uiomove(&curproc->p_vmspace->vm_map, obj,
407                                                 uio->uio_offset, cnt,
408                                                 (vm_offset_t) iov->iov_base, &npagesmoved);
409
410                         if (npagesmoved == 0)
411                                 break;
412
413                         tcnt = npagesmoved * PAGE_SIZE;
414                         cnt = tcnt;
415
416                         if (error)
417                                 break;
418
419                         iov->iov_base = (char *)iov->iov_base + cnt;
420                         iov->iov_len -= cnt;
421                         uio->uio_resid -= cnt;
422                         uio->uio_offset += cnt;
423                         *nread += cnt;
424                         n -= cnt;
425                 } else {
426                         break;
427                 }
428         }
429         return error;
430 }
431 #endif /* ENABLE_VFS_IOOPT */
432
433 /*
434  * Give next character to user as result of read.
435  */
436 int
437 ureadc(c, uio)
438         register int c;
439         register struct uio *uio;
440 {
441         register struct iovec *iov;
442         register char *iov_base;
443
444 again:
445         if (uio->uio_iovcnt == 0 || uio->uio_resid == 0)
446                 panic("ureadc");
447         iov = uio->uio_iov;
448         if (iov->iov_len == 0) {
449                 uio->uio_iovcnt--;
450                 uio->uio_iov++;
451                 goto again;
452         }
453         switch (uio->uio_segflg) {
454
455         case UIO_USERSPACE:
456                 if (subyte(iov->iov_base, c) < 0)
457                         return (EFAULT);
458                 break;
459
460         case UIO_SYSSPACE:
461                 iov_base = iov->iov_base;
462                 *iov_base = c;
463                 iov->iov_base = iov_base;
464                 break;
465
466         case UIO_NOCOPY:
467                 break;
468         }
469         iov->iov_base = (char *)iov->iov_base + 1;
470         iov->iov_len--;
471         uio->uio_resid--;
472         uio->uio_offset++;
473         return (0);
474 }
475
476 /*
477  * General routine to allocate a hash table.
478  */
479 void *
480 hashinit(elements, type, hashmask)
481         int elements;
482         struct malloc_type *type;
483         u_long *hashmask;
484 {
485         long hashsize;
486         LIST_HEAD(generic, generic) *hashtbl;
487         int i;
488
489         if (elements <= 0)
490                 panic("hashinit: bad elements");
491         for (hashsize = 1; hashsize <= elements; hashsize <<= 1)
492                 continue;
493         hashsize >>= 1;
494         hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK);
495         for (i = 0; i < hashsize; i++)
496                 LIST_INIT(&hashtbl[i]);
497         *hashmask = hashsize - 1;
498         return (hashtbl);
499 }
500
501 void
502 hashdestroy(vhashtbl, type, hashmask)
503         void *vhashtbl;
504         struct malloc_type *type;
505         u_long hashmask;
506 {
507         LIST_HEAD(generic, generic) *hashtbl, *hp;
508
509         hashtbl = vhashtbl;
510         for (hp = hashtbl; hp <= &hashtbl[hashmask]; hp++)
511                 if (!LIST_EMPTY(hp))
512                         panic("hashdestroy: hash not empty");
513         free(hashtbl, type);
514 }
515
516 static int primes[] = { 1, 13, 31, 61, 127, 251, 509, 761, 1021, 1531, 2039,
517                         2557, 3067, 3583, 4093, 4603, 5119, 5623, 6143, 6653,
518                         7159, 7673, 8191, 12281, 16381, 24571, 32749 };
519 #define NPRIMES (sizeof(primes) / sizeof(primes[0]))
520
521 /*
522  * General routine to allocate a prime number sized hash table.
523  */
524 void *
525 phashinit(elements, type, nentries)
526         int elements;
527         struct malloc_type *type;
528         u_long *nentries;
529 {
530         long hashsize;
531         LIST_HEAD(generic, generic) *hashtbl;
532         int i;
533
534         if (elements <= 0)
535                 panic("phashinit: bad elements");
536         for (i = 1, hashsize = primes[1]; hashsize <= elements;) {
537                 i++;
538                 if (i == NPRIMES)
539                         break;
540                 hashsize = primes[i];
541         }
542         hashsize = primes[i - 1];
543         hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK);
544         for (i = 0; i < hashsize; i++)
545                 LIST_INIT(&hashtbl[i]);
546         *nentries = hashsize;
547         return (hashtbl);
548 }
549
550 void
551 uio_yield()
552 {
553         struct thread *td;
554
555         td = curthread;
556         mtx_lock_spin(&sched_lock);
557         DROP_GIANT();
558         sched_prio(td, td->td_ksegrp->kg_user_pri); /* XXXKSE */
559         td->td_proc->p_stats->p_ru.ru_nivcsw++;
560         mi_switch();
561         mtx_unlock_spin(&sched_lock);
562         PICKUP_GIANT();
563 }
564
565 int
566 copyinfrom(const void *src, void *dst, size_t len, int seg)
567 {
568         int error = 0;
569
570         switch (seg) {
571         case UIO_USERSPACE:
572                 error = copyin(src, dst, len);
573                 break;
574         case UIO_SYSSPACE:
575                 bcopy(src, dst, len);
576                 break;
577         default:
578                 panic("copyinfrom: bad seg %d\n", seg);
579         }
580         return (error);
581 }
582
583 int
584 copyinstrfrom(const void *src, void *dst, size_t len, size_t *copied, int seg)
585 {
586         int error = 0;
587
588         switch (seg) {
589         case UIO_USERSPACE:
590                 error = copyinstr(src, dst, len, copied);
591                 break;
592         case UIO_SYSSPACE:
593                 error = copystr(src, dst, len, copied);
594                 break;
595         default:
596                 panic("copyinstrfrom: bad seg %d\n", seg);
597         }
598         return (error);
599 }