[BACK]Return to uipc_socket.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/kern/uipc_socket.c between version 1.116.6.1 and 1.134.2.2

version 1.116.6.1, 2006/05/24 15:50:41 version 1.134.2.2, 2007/04/10 13:26:42
Line 1 
Line 1 
 /*      $NetBSD$        */  /*      $NetBSD$        */
   
 /*-  /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.   * Copyright (c) 2002, 2007 The NetBSD Foundation, Inc.
  * All rights reserved.   * All rights reserved.
  *   *
  * This code is derived from software contributed to The NetBSD Foundation   * This code is derived from software contributed to The NetBSD Foundation
Line 92  __KERNEL_RCSID(0, "$NetBSD$");
Line 92  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/event.h>  #include <sys/event.h>
 #include <sys/poll.h>  #include <sys/poll.h>
 #include <sys/kauth.h>  #include <sys/kauth.h>
   #include <sys/mutex.h>
   #include <sys/condvar.h>
   
 #include <uvm/uvm.h>  #include <uvm/uvm.h>
   
 POOL_INIT(socket_pool, sizeof(struct socket), 0, 0, 0, "sockpl", NULL);  POOL_INIT(socket_pool, sizeof(struct socket), 0, 0, 0, "sockpl", NULL,
       IPL_SOFTNET);
   
 MALLOC_DEFINE(M_SOOPTS, "soopts", "socket options");  MALLOC_DEFINE(M_SOOPTS, "soopts", "socket options");
 MALLOC_DEFINE(M_SONAME, "soname", "socket name");  MALLOC_DEFINE(M_SONAME, "soname", "socket name");
Line 127  EVCNT_ATTACH_STATIC(sosend_kvalimit);
Line 130  EVCNT_ATTACH_STATIC(sosend_kvalimit);
   
 #endif /* SOSEND_COUNTERS */  #endif /* SOSEND_COUNTERS */
   
 void  static struct callback_entry sokva_reclaimerentry;
 soinit(void)  
 {  
   
         /* Set the initial adjusted socket buffer size. */  
         if (sb_max_set(sb_max))  
                 panic("bad initial sb_max value: %lu", sb_max);  
   
 }  
   
 #ifdef SOSEND_NO_LOAN  #ifdef SOSEND_NO_LOAN
 int use_sosend_loan = 0;  int sock_loan_thresh = -1;
 #else  #else
 int use_sosend_loan = 1;  int sock_loan_thresh = 4096;
 #endif  #endif
   
 static struct simplelock so_pendfree_slock = SIMPLELOCK_INITIALIZER;  static kmutex_t so_pendfree_lock;
 static struct mbuf *so_pendfree;  static struct mbuf *so_pendfree;
   
 #ifndef SOMAXKVA  #ifndef SOMAXKVA
Line 151  static struct mbuf *so_pendfree;
Line 146  static struct mbuf *so_pendfree;
 #endif  #endif
 int somaxkva = SOMAXKVA;  int somaxkva = SOMAXKVA;
 static int socurkva;  static int socurkva;
 static int sokvawaiters;  static kcondvar_t socurkva_cv;
   
 #define SOCK_LOAN_THRESH        4096  
 #define SOCK_LOAN_CHUNK         65536  #define SOCK_LOAN_CHUNK         65536
   
 static size_t sodopendfree(void);  static size_t sodopendfree(void);
Line 162  static size_t sodopendfreel(void);
Line 156  static size_t sodopendfreel(void);
 static vsize_t  static vsize_t
 sokvareserve(struct socket *so, vsize_t len)  sokvareserve(struct socket *so, vsize_t len)
 {  {
         int s;  
         int error;          int error;
   
         s = splvm();          mutex_enter(&so_pendfree_lock);
         simple_lock(&so_pendfree_slock);  
         while (socurkva + len > somaxkva) {          while (socurkva + len > somaxkva) {
                 size_t freed;                  size_t freed;
   
Line 184  sokvareserve(struct socket *so, vsize_t 
Line 176  sokvareserve(struct socket *so, vsize_t 
                         continue;                          continue;
   
                 SOSEND_COUNTER_INCR(&sosend_kvalimit);                  SOSEND_COUNTER_INCR(&sosend_kvalimit);
                 sokvawaiters++;                  error = cv_wait_sig(&socurkva_cv, &so_pendfree_lock);
                 error = ltsleep(&socurkva, PVM | PCATCH, "sokva", 0,  
                     &so_pendfree_slock);  
                 sokvawaiters--;  
                 if (error) {                  if (error) {
                         len = 0;                          len = 0;
                         break;                          break;
                 }                  }
         }          }
         socurkva += len;          socurkva += len;
         simple_unlock(&so_pendfree_slock);          mutex_exit(&so_pendfree_lock);
         splx(s);  
         return len;          return len;
 }  }
   
 static void  static void
 sokvaunreserve(vsize_t len)  sokvaunreserve(vsize_t len)
 {  {
         int s;  
   
         s = splvm();          mutex_enter(&so_pendfree_lock);
         simple_lock(&so_pendfree_slock);  
         socurkva -= len;          socurkva -= len;
         if (sokvawaiters)          cv_broadcast(&socurkva_cv);
                 wakeup(&socurkva);          mutex_exit(&so_pendfree_lock);
         simple_unlock(&so_pendfree_slock);  
         splx(s);  
 }  }
   
 /*  /*
Line 264  sokvafree(vaddr_t sva, vsize_t len)
Line 248  sokvafree(vaddr_t sva, vsize_t len)
 }  }
   
 static void  static void
 sodoloanfree(struct vm_page **pgs, caddr_t buf, size_t size)  sodoloanfree(struct vm_page **pgs, void *buf, size_t size)
 {  {
         vaddr_t va, sva, eva;          vaddr_t va, sva, eva;
         vsize_t len;          vsize_t len;
Line 280  sodoloanfree(struct vm_page **pgs, caddr
Line 264  sodoloanfree(struct vm_page **pgs, caddr
                 pgs = alloca(npgs * sizeof(*pgs));                  pgs = alloca(npgs * sizeof(*pgs));
   
                 for (i = 0, va = sva; va < eva; i++, va += PAGE_SIZE) {                  for (i = 0, va = sva; va < eva; i++, va += PAGE_SIZE) {
                         if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)                          if (pmap_extract(pmap_kernel(), va, &pa) == false)
                                 panic("sodoloanfree: va 0x%lx not mapped", va);                                  panic("sodoloanfree: va 0x%lx not mapped", va);
                         pgs[i] = PHYS_TO_VM_PAGE(pa);                          pgs[i] = PHYS_TO_VM_PAGE(pa);
                 }                  }
Line 295  sodoloanfree(struct vm_page **pgs, caddr
Line 279  sodoloanfree(struct vm_page **pgs, caddr
 static size_t  static size_t
 sodopendfree()  sodopendfree()
 {  {
         int s;  
         size_t rv;          size_t rv;
   
         s = splvm();          mutex_enter(&so_pendfree_lock);
         simple_lock(&so_pendfree_slock);  
         rv = sodopendfreel();          rv = sodopendfreel();
         simple_unlock(&so_pendfree_slock);          mutex_exit(&so_pendfree_lock);
         splx(s);  
   
         return rv;          return rv;
 }  }
   
 /*  /*
  * sodopendfreel: free mbufs on "pendfree" list.   * sodopendfreel: free mbufs on "pendfree" list.
  * unlock and relock so_pendfree_slock when freeing mbufs.   * unlock and relock so_pendfree_lock when freeing mbufs.
  *   *
  * => called with so_pendfree_slock held.   * => called with so_pendfree_lock held.
  * => called at splvm.  
  */   */
   
 static size_t  static size_t
 sodopendfreel()  sodopendfreel()
 {  {
           struct mbuf *m, *next;
         size_t rv = 0;          size_t rv = 0;
           int s;
   
         LOCK_ASSERT(simple_lock_held(&so_pendfree_slock));          KASSERT(mutex_owned(&so_pendfree_lock));
   
         for (;;) {  
                 struct mbuf *m;  
                 struct mbuf *next;  
   
           while (so_pendfree != NULL) {
                 m = so_pendfree;                  m = so_pendfree;
                 if (m == NULL)  
                         break;  
                 so_pendfree = NULL;                  so_pendfree = NULL;
                 simple_unlock(&so_pendfree_slock);                  mutex_exit(&so_pendfree_lock);
                 /* XXX splx */  
   
                 for (; m != NULL; m = next) {                  for (; m != NULL; m = next) {
                         next = m->m_next;                          next = m->m_next;
Line 340  sodopendfreel()
Line 316  sodopendfreel()
                         sodoloanfree((m->m_flags & M_EXT_PAGES) ?                          sodoloanfree((m->m_flags & M_EXT_PAGES) ?
                             m->m_ext.ext_pgs : NULL, m->m_ext.ext_buf,                              m->m_ext.ext_pgs : NULL, m->m_ext.ext_buf,
                             m->m_ext.ext_size);                              m->m_ext.ext_size);
                           s = splvm();
                         pool_cache_put(&mbpool_cache, m);                          pool_cache_put(&mbpool_cache, m);
                           splx(s);
                 }                  }
   
                 /* XXX splvm */                  mutex_enter(&so_pendfree_lock);
                 simple_lock(&so_pendfree_slock);  
         }          }
   
         return (rv);          return (rv);
 }  }
   
 void  void
 soloanfree(struct mbuf *m, caddr_t buf, size_t size, void *arg)  soloanfree(struct mbuf *m, void *buf, size_t size, void *arg)
 {  {
         int s;  
   
         if (m == NULL) {          if (m == NULL) {
   
Line 372  soloanfree(struct mbuf *m, caddr_t buf, 
Line 348  soloanfree(struct mbuf *m, caddr_t buf, 
          * because we need to put kva back to kernel_map.           * because we need to put kva back to kernel_map.
          */           */
   
         s = splvm();          mutex_enter(&so_pendfree_lock);
         simple_lock(&so_pendfree_slock);  
         m->m_next = so_pendfree;          m->m_next = so_pendfree;
         so_pendfree = m;          so_pendfree = m;
         if (sokvawaiters)          cv_broadcast(&socurkva_cv);
                 wakeup(&socurkva);          mutex_exit(&so_pendfree_lock);
         simple_unlock(&so_pendfree_slock);  
         splx(s);  
 }  }
   
 static long  static long
Line 425  sosend_loan(struct socket *so, struct ui
Line 398  sosend_loan(struct socket *so, struct ui
   
         lva += (vaddr_t) iov->iov_base & PAGE_MASK;          lva += (vaddr_t) iov->iov_base & PAGE_MASK;
   
         MEXTADD(m, (caddr_t) lva, space, M_MBUF, soloanfree, so);          MEXTADD(m, (void *) lva, space, M_MBUF, soloanfree, so);
         m->m_flags |= M_EXT_PAGES | M_EXT_ROMAP;          m->m_flags |= M_EXT_PAGES | M_EXT_ROMAP;
   
         uio->uio_resid -= space;          uio->uio_resid -= space;
         /* uio_offset not updated, not set/used for write(2) */          /* uio_offset not updated, not set/used for write(2) */
         uio->uio_iov->iov_base = (caddr_t) uio->uio_iov->iov_base + space;          uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + space;
         uio->uio_iov->iov_len -= space;          uio->uio_iov->iov_len -= space;
         if (uio->uio_iov->iov_len == 0) {          if (uio->uio_iov->iov_len == 0) {
                 uio->uio_iov++;                  uio->uio_iov++;
Line 440  sosend_loan(struct socket *so, struct ui
Line 413  sosend_loan(struct socket *so, struct ui
         return (space);          return (space);
 }  }
   
   static int
   sokva_reclaim_callback(struct callback_entry *ce, void *obj, void *arg)
   {
   
           KASSERT(ce == &sokva_reclaimerentry);
           KASSERT(obj == NULL);
   
           sodopendfree();
           if (!vm_map_starved_p(kernel_map)) {
                   return CALLBACK_CHAIN_ABORT;
           }
           return CALLBACK_CHAIN_CONTINUE;
   }
   
   void
   soinit(void)
   {
   
           mutex_init(&so_pendfree_lock, MUTEX_DRIVER, IPL_VM);
           cv_init(&socurkva_cv, "sokva");
   
           /* Set the initial adjusted socket buffer size. */
           if (sb_max_set(sb_max))
                   panic("bad initial sb_max value: %lu", sb_max);
   
           callback_register(&vm_map_to_kernel(kernel_map)->vmk_reclaim_callback,
               &sokva_reclaimerentry, NULL, sokva_reclaim_callback);
   }
   
 /*  /*
  * Socket operation routines.   * Socket operation routines.
  * These routines are called by the routines in   * These routines are called by the routines in
Line 456  socreate(int dom, struct socket **aso, i
Line 458  socreate(int dom, struct socket **aso, i
         uid_t           uid;          uid_t           uid;
         int             error, s;          int             error, s;
   
           error = kauth_authorize_network(l->l_cred, KAUTH_NETWORK_SOCKET,
               KAUTH_REQ_NETWORK_SOCKET_OPEN, KAUTH_ARG(dom), KAUTH_ARG(type),
               KAUTH_ARG(proto));
           if (error)
                   return (error);
   
         if (proto)          if (proto)
                 prp = pffindproto(dom, proto, type);                  prp = pffindproto(dom, proto, type);
         else          else
                 prp = pffindtype(dom, type);                  prp = pffindtype(dom, type);
         if (prp == 0 || prp->pr_usrreq == 0)          if (prp == 0) {
                   /* no support for domain */
                   if (pffinddomain(dom) == 0)
                           return (EAFNOSUPPORT);
                   /* no support for socket type */
                   if (proto == 0 && type != 0)
                           return (EPROTOTYPE);
                   return (EPROTONOSUPPORT);
           }
           if (prp->pr_usrreq == 0)
                 return (EPROTONOSUPPORT);                  return (EPROTONOSUPPORT);
         if (prp->pr_type != type)          if (prp->pr_type != type)
                 return (EPROTOTYPE);                  return (EPROTOTYPE);
         s = splsoftnet();          s = splsoftnet();
         so = pool_get(&socket_pool, PR_WAITOK);          so = pool_get(&socket_pool, PR_WAITOK);
         memset((caddr_t)so, 0, sizeof(*so));          memset((void *)so, 0, sizeof(*so));
         TAILQ_INIT(&so->so_q0);          TAILQ_INIT(&so->so_q0);
         TAILQ_INIT(&so->so_q);          TAILQ_INIT(&so->so_q);
         so->so_type = type;          so->so_type = type;
Line 478  socreate(int dom, struct socket **aso, i
Line 495  socreate(int dom, struct socket **aso, i
         so->so_snd.sb_mowner = &prp->pr_domain->dom_mowner;          so->so_snd.sb_mowner = &prp->pr_domain->dom_mowner;
         so->so_mowner = &prp->pr_domain->dom_mowner;          so->so_mowner = &prp->pr_domain->dom_mowner;
 #endif  #endif
         if (l != NULL) {          uid = kauth_cred_geteuid(l->l_cred);
                 uid = kauth_cred_geteuid(l->l_proc->p_cred);  
         } else {  
                 uid = 0;  
         }  
         so->so_uidinfo = uid_find(uid);          so->so_uidinfo = uid_find(uid);
         error = (*prp->pr_usrreq)(so, PRU_ATTACH, (struct mbuf *)0,          error = (*prp->pr_usrreq)(so, PRU_ATTACH, (struct mbuf *)0,
             (struct mbuf *)(long)proto, (struct mbuf *)0, l);              (struct mbuf *)(long)proto, (struct mbuf *)0, l);
Line 592  soclose(struct socket *so)
Line 605  soclose(struct socket *so)
                             (so->so_state & SS_NBIO))                              (so->so_state & SS_NBIO))
                                 goto drop;                                  goto drop;
                         while (so->so_state & SS_ISCONNECTED) {                          while (so->so_state & SS_ISCONNECTED) {
                                 error = tsleep((caddr_t)&so->so_timeo,                                  error = tsleep((void *)&so->so_timeo,
                                                PSOCK | PCATCH, netcls,                                                 PSOCK | PCATCH, netcls,
                                                so->so_linger * hz);                                                 so->so_linger * hz);
                                 if (error)                                  if (error)
Line 826  sosend(struct socket *so, struct mbuf *a
Line 839  sosend(struct socket *so, struct mbuf *a
                                         mlen = MLEN;                                          mlen = MLEN;
                                 }                                  }
                                 MCLAIM(m, so->so_snd.sb_mowner);                                  MCLAIM(m, so->so_snd.sb_mowner);
                                 if (use_sosend_loan &&                                  if (sock_loan_thresh >= 0 &&
                                     uio->uio_iov->iov_len >= SOCK_LOAN_THRESH &&                                      uio->uio_iov->iov_len >= sock_loan_thresh &&
                                     space >= SOCK_LOAN_THRESH &&                                      space >= sock_loan_thresh &&
                                     (len = sosend_loan(so, uio, m,                                      (len = sosend_loan(so, uio, m,
                                                        space)) != 0) {                                                         space)) != 0) {
                                         SOSEND_COUNTER_INCR(&sosend_loan_big);                                          SOSEND_COUNTER_INCR(&sosend_loan_big);
Line 860  sosend(struct socket *so, struct mbuf *a
Line 873  sosend(struct socket *so, struct mbuf *a
                                         if (atomic && top == 0 && len < mlen)                                          if (atomic && top == 0 && len < mlen)
                                                 MH_ALIGN(m, len);                                                  MH_ALIGN(m, len);
                                 }                                  }
                                 error = uiomove(mtod(m, caddr_t), (int)len,                                  error = uiomove(mtod(m, void *), (int)len,
                                     uio);                                      uio);
  have_data:   have_data:
                                 resid = uio->uio_resid;                                  resid = uio->uio_resid;
Line 966  soreceive(struct socket *so, struct mbuf
Line 979  soreceive(struct socket *so, struct mbuf
                 if (error)                  if (error)
                         goto bad;                          goto bad;
                 do {                  do {
                         error = uiomove(mtod(m, caddr_t),                          error = uiomove(mtod(m, void *),
                             (int) min(uio->uio_resid, m->m_len), uio);                              (int) min(uio->uio_resid, m->m_len), uio);
                         m = m_free(m);                          m = m_free(m);
                 } while (uio->uio_resid && error == 0 && m);                  } while (uio->uio_resid && error == 0 && m);
Line 1180  soreceive(struct socket *so, struct mbuf
Line 1193  soreceive(struct socket *so, struct mbuf
                         SBLASTRECORDCHK(&so->so_rcv, "soreceive uiomove");                          SBLASTRECORDCHK(&so->so_rcv, "soreceive uiomove");
                         SBLASTMBUFCHK(&so->so_rcv, "soreceive uiomove");                          SBLASTMBUFCHK(&so->so_rcv, "soreceive uiomove");
                         splx(s);                          splx(s);
                         error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio);                          error = uiomove(mtod(m, char *) + moff, (int)len, uio);
                         s = splsoftnet();                          s = splsoftnet();
                         if (error) {                          if (error) {
                                 /*                                  /*
Line 1391  sosetopt(struct socket *so, int level, i
Line 1404  sosetopt(struct socket *so, int level, i
 {  {
         int             error;          int             error;
         struct mbuf     *m;          struct mbuf     *m;
           struct linger   *l;
   
         error = 0;          error = 0;
         m = m0;          m = m0;
Line 1407  sosetopt(struct socket *so, int level, i
Line 1421  sosetopt(struct socket *so, int level, i
                                 error = EINVAL;                                  error = EINVAL;
                                 goto bad;                                  goto bad;
                         }                          }
                         if (mtod(m, struct linger *)->l_linger < 0 ||                          l = mtod(m, struct linger *);
                             mtod(m, struct linger *)->l_linger > (INT_MAX / hz)) {                          if (l->l_linger < 0 || l->l_linger > USHRT_MAX ||
                               l->l_linger > (INT_MAX / hz)) {
                                 error = EDOM;                                  error = EDOM;
                                 goto bad;                                  goto bad;
                         }                          }
                         so->so_linger = mtod(m, struct linger *)->l_linger;                          so->so_linger = l->l_linger;
                         /* fall thru... */                          if (l->l_onoff)
                                   so->so_options |= SO_LINGER;
                           else
                                   so->so_options &= ~SO_LINGER;
                           break;
   
                 case SO_DEBUG:                  case SO_DEBUG:
                 case SO_KEEPALIVE:                  case SO_KEEPALIVE:
Line 1553  sogetopt(struct socket *so, int level, i
Line 1572  sogetopt(struct socket *so, int level, i
                 case SO_LINGER:                  case SO_LINGER:
                         m->m_len = sizeof(struct linger);                          m->m_len = sizeof(struct linger);
                         mtod(m, struct linger *)->l_onoff =                          mtod(m, struct linger *)->l_onoff =
                                 so->so_options & SO_LINGER;                              (so->so_options & SO_LINGER) ? 1 : 0;
                         mtod(m, struct linger *)->l_linger = so->so_linger;                          mtod(m, struct linger *)->l_linger = so->so_linger;
                         break;                          break;
   
Line 1566  sogetopt(struct socket *so, int level, i
Line 1585  sogetopt(struct socket *so, int level, i
                 case SO_BROADCAST:                  case SO_BROADCAST:
                 case SO_OOBINLINE:                  case SO_OOBINLINE:
                 case SO_TIMESTAMP:                  case SO_TIMESTAMP:
                         *mtod(m, int *) = so->so_options & optname;                          *mtod(m, int *) = (so->so_options & optname) ? 1 : 0;
                         break;                          break;
   
                 case SO_TYPE:                  case SO_TYPE:
Line 1756  sysctl_kern_somaxkva(SYSCTLFN_ARGS)
Line 1775  sysctl_kern_somaxkva(SYSCTLFN_ARGS)
 {  {
         int error, new_somaxkva;          int error, new_somaxkva;
         struct sysctlnode node;          struct sysctlnode node;
         int s;  
   
         new_somaxkva = somaxkva;          new_somaxkva = somaxkva;
         node = *rnode;          node = *rnode;
Line 1768  sysctl_kern_somaxkva(SYSCTLFN_ARGS)
Line 1786  sysctl_kern_somaxkva(SYSCTLFN_ARGS)
         if (new_somaxkva < (16 * 1024 * 1024)) /* sanity */          if (new_somaxkva < (16 * 1024 * 1024)) /* sanity */
                 return (EINVAL);                  return (EINVAL);
   
         s = splvm();          mutex_enter(&so_pendfree_lock);
         simple_lock(&so_pendfree_slock);  
         somaxkva = new_somaxkva;          somaxkva = new_somaxkva;
         wakeup(&socurkva);          cv_broadcast(&socurkva_cv);
         simple_unlock(&so_pendfree_slock);          mutex_exit(&so_pendfree_lock);
         splx(s);  
   
         return (error);          return (error);
 }  }

Legend:
Removed from v.1.116.6.1  
changed lines
  Added in v.1.134.2.2

CVSweb <webmaster@jp.NetBSD.org>