Diff for /src/sys/kern/sys_pipe.c between versions 1.13 and 1.14

version 1.13, 2003/11/03 17:11:21 version 1.14, 2004/02/20 17:11:07
Line 52 Line 52
   
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/systm.h>  #include <sys/systm.h>
   #include <sys/kernel.h>
 #include <sys/proc.h>  #include <sys/proc.h>
 #include <sys/fcntl.h>  #include <sys/fcntl.h>
 #include <sys/file.h>  #include <sys/file.h>
Line 67 Line 68
 #include <sys/vnode.h>  #include <sys/vnode.h>
 #include <sys/uio.h>  #include <sys/uio.h>
 #include <sys/event.h>  #include <sys/event.h>
   #include <sys/globaldata.h>
   #include <sys/module.h>
   #include <sys/malloc.h>
   #include <sys/sysctl.h>
   
 #include <vm/vm.h>  #include <vm/vm.h>
 #include <vm/vm_param.h>  #include <vm/vm_param.h>
Line 118  static struct filterops pipe_rfiltops = Line 123  static struct filterops pipe_rfiltops =
 static struct filterops pipe_wfiltops =  static struct filterops pipe_wfiltops =
         { 1, NULL, filt_pipedetach, filt_pipewrite };          { 1, NULL, filt_pipedetach, filt_pipewrite };
   
   MALLOC_DEFINE(M_PIPE, "pipe", "pipe structures");
   
 /*  /*
  * Default pipe buffer size(s), this can be kind-of large now because pipe   * Default pipe buffer size(s), this can be kind-of large now because pipe
Line 144  static struct filterops pipe_wfiltops = Line 150  static struct filterops pipe_wfiltops =
  * Limit the number of "big" pipes   * Limit the number of "big" pipes
  */   */
 #define LIMITBIGPIPES   32  #define LIMITBIGPIPES   32
static int nbigpipe;#define PIPEQ_MAX_CACHE 16      /* per-cpu pipe structure cache */
   
static int amountpipekva;static int pipe_maxbig = LIMITBIGPIPES;
 static int pipe_maxcache = PIPEQ_MAX_CACHE;
 static int pipe_nbig;
 static int pipe_kva;
 static int pipe_bcache_alloc;
 static int pipe_bkmem_alloc;
 static int pipe_dcache_alloc;
 static int pipe_dkmem_alloc;
 
 SYSCTL_NODE(_kern, OID_AUTO, pipe, CTLFLAG_RW, 0, "Pipe operation");
 SYSCTL_INT(_kern_pipe, OID_AUTO, nbig,
         CTLFLAG_RD, &pipe_nbig, 0, "numer of big pipes allocated");
 SYSCTL_INT(_kern_pipe, OID_AUTO, kva,
         CTLFLAG_RD, &pipe_kva, 0, "kva reserved by pipes");
 SYSCTL_INT(_kern_pipe, OID_AUTO, maxcache,
         CTLFLAG_RW, &pipe_maxcache, 0, "max pipes cached per-cpu");
 SYSCTL_INT(_kern_pipe, OID_AUTO, maxbig,
         CTLFLAG_RW, &pipe_maxbig, 0, "max number of big pipes");
 #if !defined(NO_PIPE_SYSCTL_STATS)
 SYSCTL_INT(_kern_pipe, OID_AUTO, bcache_alloc,
         CTLFLAG_RW, &pipe_bcache_alloc, 0, "pipe buffer from pcpu cache");
 SYSCTL_INT(_kern_pipe, OID_AUTO, dcache_alloc,
         CTLFLAG_RW, &pipe_dcache_alloc, 0, "pipe direct buf from pcpu cache");
 SYSCTL_INT(_kern_pipe, OID_AUTO, bkmem_alloc,
         CTLFLAG_RW, &pipe_bkmem_alloc, 0, "pipe buffer from kmem");
 SYSCTL_INT(_kern_pipe, OID_AUTO, dkmem_alloc,
         CTLFLAG_RW, &pipe_dkmem_alloc, 0, "pipe direct buf from kmem");
 #endif
   
 static void pipeclose (struct pipe *cpipe);  static void pipeclose (struct pipe *cpipe);
 static void pipe_free_kmem (struct pipe *cpipe);  static void pipe_free_kmem (struct pipe *cpipe);
Line 162  static void pipe_clone_write_buffer (str Line 195  static void pipe_clone_write_buffer (str
 #endif  #endif
 static int pipespace (struct pipe *cpipe, int size);  static int pipespace (struct pipe *cpipe, int size);
   
 static vm_zone_t pipe_zone;  
   
 /*  /*
  * The pipe system call for the DTYPE_PIPE type of pipes   * The pipe system call for the DTYPE_PIPE type of pipes
  *   *
Line 184  pipe(struct pipe_args *uap) Line 215  pipe(struct pipe_args *uap)
         KKASSERT(p);          KKASSERT(p);
         fdp = p->p_fd;          fdp = p->p_fd;
   
         if (pipe_zone == NULL)  
                 pipe_zone = zinit("PIPE", sizeof(struct pipe), 0, 0, 4);  
   
         rpipe = wpipe = NULL;          rpipe = wpipe = NULL;
         if (pipe_create(&rpipe) || pipe_create(&wpipe)) {          if (pipe_create(&rpipe) || pipe_create(&wpipe)) {
                 pipeclose(rpipe);                   pipeclose(rpipe); 
Line 247  pipe(struct pipe_args *uap) Line 275  pipe(struct pipe_args *uap)
  * If it fails it will return ENOMEM.   * If it fails it will return ENOMEM.
  */   */
 static int  static int
pipespace(cpipe, size)pipespace(struct pipe *cpipe, int size)
        struct pipe *cpipe; 
        int size; 
 {  {
         struct vm_object *object;          struct vm_object *object;
         caddr_t buffer;          caddr_t buffer;
         int npages, error;          int npages, error;
   
        npages = round_page(size)/PAGE_SIZE;        npages = round_page(size) / PAGE_SIZE;
        /*        object = cpipe->pipe_buffer.object;
         * Create an object, I don't like the idea of paging to/from 
         * kernel_object. 
         * XXX -- minor change needed here for NetBSD/OpenBSD VM systems. 
         */ 
        object = vm_object_allocate(OBJT_DEFAULT, npages); 
        buffer = (caddr_t) vm_map_min(kernel_map); 
   
         /*          /*
         * Insert the object into the kernel map, and allocate kva for it.         * [re]create the object if necessary and reserve space for it
         * The map entry is, by default, pageable.         * in the kernel_map.  The object and memory are pageable.  On
         * XXX -- minor change needed here for NetBSD/OpenBSD VM systems.         * success, free the old resources before assigning the new
          * ones.
          */           */
        error = vm_map_find(kernel_map, object, 0,        if (object == NULL || object->size != npages) {
                (vm_offset_t *) &buffer, size, 1,                object = vm_object_allocate(OBJT_DEFAULT, npages);
                VM_PROT_ALL, VM_PROT_ALL, 0);                buffer = (caddr_t) vm_map_min(kernel_map);
        if (error != KERN_SUCCESS) {                error = vm_map_find(kernel_map, object, 0,
                vm_object_deallocate(object);                        (vm_offset_t *) &buffer, size, 1,
                return (ENOMEM);                        VM_PROT_ALL, VM_PROT_ALL, 0);
 
                 if (error != KERN_SUCCESS) {
                         vm_object_deallocate(object);
                         return (ENOMEM);
                 }
                 pipe_kva += size;
                 pipe_free_kmem(cpipe);
                 cpipe->pipe_buffer.object = object;
                 cpipe->pipe_buffer.buffer = buffer;
                 cpipe->pipe_buffer.size = size;
                 ++pipe_bkmem_alloc;
         } else {
                 ++pipe_bcache_alloc;
                 if (cpipe->pipe_map.kva)
                         ++pipe_dcache_alloc;
         }          }
   
         /* free old resources if we're resizing */  
         pipe_free_kmem(cpipe);  
         cpipe->pipe_buffer.object = object;  
         cpipe->pipe_buffer.buffer = buffer;  
         cpipe->pipe_buffer.size = size;  
         cpipe->pipe_buffer.in = 0;          cpipe->pipe_buffer.in = 0;
         cpipe->pipe_buffer.out = 0;          cpipe->pipe_buffer.out = 0;
         cpipe->pipe_buffer.cnt = 0;          cpipe->pipe_buffer.cnt = 0;
         amountpipekva += cpipe->pipe_buffer.size;  
         return (0);          return (0);
 }  }
   
 /*  /*
 * initialize and allocate VM and memory for pipe * Initialize and allocate VM and memory for pipe, pulling the pipe from
  * our per-cpu cache if possible.  For now make sure it is sized for the
  * smaller PIPE_SIZE default.
  */   */
 static int  static int
 pipe_create(cpipep)  pipe_create(cpipep)
         struct pipe **cpipep;          struct pipe **cpipep;
 {  {
           globaldata_t gd = mycpu;
         struct pipe *cpipe;          struct pipe *cpipe;
         int error;          int error;
   
        *cpipep = zalloc(pipe_zone);        if ((cpipe = gd->gd_pipeq) != NULL) {
        if (*cpipep == NULL)                gd->gd_pipeq = cpipe->pipe_peer;
                return (ENOMEM);                --gd->gd_pipeqcount;
                cpipe->pipe_peer = NULL;
        cpipe = *cpipep;        } else {
                        cpipe = malloc(sizeof(struct pipe), M_PIPE, M_WAITOK|M_ZERO);
        /* so pipespace()->pipe_free_kmem() doesn't follow junk pointer */        }
        cpipe->pipe_buffer.object = NULL;        *cpipep = cpipe;
#ifndef PIPE_NODIRECT        if ((error = pipespace(cpipe, PIPE_SIZE)) != 0)
        cpipe->pipe_map.kva = NULL; 
#endif 
        /* 
         * protect so pipeclose() doesn't follow a junk pointer 
         * if pipespace() fails. 
         */ 
        bzero(&cpipe->pipe_sel, sizeof(cpipe->pipe_sel)); 
        cpipe->pipe_state = 0; 
        cpipe->pipe_peer = NULL; 
        cpipe->pipe_busy = 0; 
 
#ifndef PIPE_NODIRECT 
        /* 
         * pipe data structure initializations to support direct pipe I/O 
         */ 
        cpipe->pipe_map.cnt = 0; 
        cpipe->pipe_map.kva = 0; 
        cpipe->pipe_map.pos = 0; 
        cpipe->pipe_map.npages = 0; 
        /* cpipe->pipe_map.ms[] = invalid */ 
#endif 
 
        error = pipespace(cpipe, PIPE_SIZE); 
        if (error) 
                 return (error);                  return (error);
   
         vfs_timestamp(&cpipe->pipe_ctime);          vfs_timestamp(&cpipe->pipe_ctime);
         cpipe->pipe_atime = cpipe->pipe_ctime;          cpipe->pipe_atime = cpipe->pipe_ctime;
         cpipe->pipe_mtime = cpipe->pipe_ctime;          cpipe->pipe_mtime = cpipe->pipe_ctime;
   
         return (0);          return (0);
 }  }
   
Line 593  pipe_build_write_buffer(wpipe, uio) Line 599  pipe_build_write_buffer(wpipe, uio)
                  */                   */
                 wpipe->pipe_map.kva = kmem_alloc_pageable(kernel_map,                  wpipe->pipe_map.kva = kmem_alloc_pageable(kernel_map,
                         wpipe->pipe_buffer.size + PAGE_SIZE);                          wpipe->pipe_buffer.size + PAGE_SIZE);
                amountpipekva += wpipe->pipe_buffer.size + PAGE_SIZE;                pipe_kva += wpipe->pipe_buffer.size + PAGE_SIZE;
                 ++pipe_dkmem_alloc;
         }          }
         pmap_qenter(wpipe->pipe_map.kva, wpipe->pipe_map.ms,          pmap_qenter(wpipe->pipe_map.kva, wpipe->pipe_map.ms,
                 wpipe->pipe_map.npages);                  wpipe->pipe_map.npages);
Line 623  pipe_destroy_write_buffer(wpipe) Line 630  pipe_destroy_write_buffer(wpipe)
         if (wpipe->pipe_map.kva) {          if (wpipe->pipe_map.kva) {
                 pmap_qremove(wpipe->pipe_map.kva, wpipe->pipe_map.npages);                  pmap_qremove(wpipe->pipe_map.kva, wpipe->pipe_map.npages);
   
                if (amountpipekva > MAXPIPEKVA) {                if (pipe_kva > MAXPIPEKVA) {
                         vm_offset_t kva = wpipe->pipe_map.kva;                          vm_offset_t kva = wpipe->pipe_map.kva;
                         wpipe->pipe_map.kva = 0;                          wpipe->pipe_map.kva = 0;
                         kmem_free(kernel_map, kva,                          kmem_free(kernel_map, kva,
                                 wpipe->pipe_buffer.size + PAGE_SIZE);                                  wpipe->pipe_buffer.size + PAGE_SIZE);
                        amountpipekva -= wpipe->pipe_buffer.size + PAGE_SIZE;                        pipe_kva -= wpipe->pipe_buffer.size + PAGE_SIZE;
                 }                  }
         }          }
         for (i = 0; i < wpipe->pipe_map.npages; i++)          for (i = 0; i < wpipe->pipe_map.npages; i++)
Line 777  pipe_write(struct file *fp, struct uio * Line 784  pipe_write(struct file *fp, struct uio *
          * so.           * so.
          */           */
         if ((uio->uio_resid > PIPE_SIZE) &&          if ((uio->uio_resid > PIPE_SIZE) &&
                (nbigpipe < LIMITBIGPIPES) &&                (pipe_nbig < pipe_maxbig) &&
                 (wpipe->pipe_state & PIPE_DIRECTW) == 0 &&                  (wpipe->pipe_state & PIPE_DIRECTW) == 0 &&
                 (wpipe->pipe_buffer.size <= PIPE_SIZE) &&                  (wpipe->pipe_buffer.size <= PIPE_SIZE) &&
                 (wpipe->pipe_buffer.cnt == 0)) {                  (wpipe->pipe_buffer.cnt == 0)) {
   
                 if ((error = pipelock(wpipe,1)) == 0) {                  if ((error = pipelock(wpipe,1)) == 0) {
                         if (pipespace(wpipe, BIG_PIPE_SIZE) == 0)                          if (pipespace(wpipe, BIG_PIPE_SIZE) == 0)
                                nbigpipe++;                                pipe_nbig++;
                         pipeunlock(wpipe);                          pipeunlock(wpipe);
                 }                  }
         }          }
Line 822  pipe_write(struct file *fp, struct uio * Line 829  pipe_write(struct file *fp, struct uio *
                  */                   */
                 if ((uio->uio_iov->iov_len >= PIPE_MINDIRECT) &&                  if ((uio->uio_iov->iov_len >= PIPE_MINDIRECT) &&
                     (fp->f_flag & FNONBLOCK) == 0 &&                      (fp->f_flag & FNONBLOCK) == 0 &&
                        (wpipe->pipe_map.kva || (amountpipekva < LIMITPIPEKVA)) &&                        (wpipe->pipe_map.kva || (pipe_kva < LIMITPIPEKVA)) &&
                         (uio->uio_iov->iov_len >= PIPE_MINDIRECT)) {                          (uio->uio_iov->iov_len >= PIPE_MINDIRECT)) {
                         error = pipe_direct_write( wpipe, uio);                          error = pipe_direct_write( wpipe, uio);
                         if (error)                          if (error)
Line 1145  pipe_close(struct file *fp, struct threa Line 1152  pipe_close(struct file *fp, struct threa
 static void  static void
 pipe_free_kmem(struct pipe *cpipe)  pipe_free_kmem(struct pipe *cpipe)
 {  {
   
         if (cpipe->pipe_buffer.buffer != NULL) {          if (cpipe->pipe_buffer.buffer != NULL) {
                 if (cpipe->pipe_buffer.size > PIPE_SIZE)                  if (cpipe->pipe_buffer.size > PIPE_SIZE)
                        --nbigpipe;                        --pipe_nbig;
                amountpipekva -= cpipe->pipe_buffer.size;                pipe_kva -= cpipe->pipe_buffer.size;
                 kmem_free(kernel_map,                  kmem_free(kernel_map,
                         (vm_offset_t)cpipe->pipe_buffer.buffer,                          (vm_offset_t)cpipe->pipe_buffer.buffer,
                         cpipe->pipe_buffer.size);                          cpipe->pipe_buffer.size);
                 cpipe->pipe_buffer.buffer = NULL;                  cpipe->pipe_buffer.buffer = NULL;
                   cpipe->pipe_buffer.object = NULL;
         }          }
 #ifndef PIPE_NODIRECT  #ifndef PIPE_NODIRECT
         if (cpipe->pipe_map.kva != NULL) {          if (cpipe->pipe_map.kva != NULL) {
                amountpipekva -= cpipe->pipe_buffer.size + PAGE_SIZE;                pipe_kva -= cpipe->pipe_buffer.size + PAGE_SIZE;
                 kmem_free(kernel_map,                  kmem_free(kernel_map,
                         cpipe->pipe_map.kva,                          cpipe->pipe_map.kva,
                         cpipe->pipe_buffer.size + PAGE_SIZE);                          cpipe->pipe_buffer.size + PAGE_SIZE);
Line 1175  pipe_free_kmem(struct pipe *cpipe) Line 1182  pipe_free_kmem(struct pipe *cpipe)
 static void  static void
 pipeclose(struct pipe *cpipe)  pipeclose(struct pipe *cpipe)
 {  {
           globaldata_t gd;
         struct pipe *ppipe;          struct pipe *ppipe;
   
        if (cpipe) {        if (cpipe == NULL)
                                return;
                pipeselwakeup(cpipe); 
   
                /*        pipeselwakeup(cpipe);
                 * If the other side is blocked, wake it up saying that 
                 * we want to close it down. 
                 */ 
                while (cpipe->pipe_busy) { 
                        wakeup(cpipe); 
                        cpipe->pipe_state |= PIPE_WANT | PIPE_EOF; 
                        tsleep(cpipe, 0, "pipecl", 0); 
                } 
   
                /*        /*
                 * Disconnect from peer         * If the other side is blocked, wake it up saying that
                 */         * we want to close it down.
                if ((ppipe = cpipe->pipe_peer) != NULL) {         */
                        pipeselwakeup(ppipe);        while (cpipe->pipe_busy) {
                 wakeup(cpipe);
                 cpipe->pipe_state |= PIPE_WANT | PIPE_EOF;
                 tsleep(cpipe, 0, "pipecl", 0);
         }
   
                        ppipe->pipe_state |= PIPE_EOF;        /*
                        wakeup(ppipe);         * Disconnect from peer
                        KNOTE(&ppipe->pipe_sel.si_note, 0);         */
                        ppipe->pipe_peer = NULL;        if ((ppipe = cpipe->pipe_peer) != NULL) {
                }                pipeselwakeup(ppipe);
                /*
                 * free resources                ppipe->pipe_state |= PIPE_EOF;
                 */                wakeup(ppipe);
                 KNOTE(&ppipe->pipe_sel.si_note, 0);
                 ppipe->pipe_peer = NULL;
         }
 
         /*
          * free or cache resources
          */
         gd = mycpu;
         if (gd->gd_pipeqcount >= pipe_maxcache ||
             cpipe->pipe_buffer.size != PIPE_SIZE
         ) {
                 pipe_free_kmem(cpipe);                  pipe_free_kmem(cpipe);
                zfree(pipe_zone, cpipe);                free(cpipe, M_PIPE);
         } else {
                 KKASSERT(cpipe->pipe_map.npages == 0);
 
                 cpipe->pipe_state = 0;
                 cpipe->pipe_busy = 0;
                 cpipe->pipe_map.cnt = 0;
                 cpipe->pipe_map.pos = 0;
                 cpipe->pipe_peer = gd->gd_pipeq;
                 gd->gd_pipeq = cpipe;
                 ++gd->gd_pipeqcount;
         }          }
 }  }
   

Removed from v.1.13  
changed lines
  Added in v.1.14