| version 1.177, 2008/10/14 13:45:26 |
version 1.177.4.4, 2011/08/08 19:45:57 |
|
|
| /* $NetBSD$ */ |
/* $NetBSD$ */ |
| |
|
| /*- |
/*- |
| * Copyright (c) 2002, 2007, 2008 The NetBSD Foundation, Inc. |
* Copyright (c) 2002, 2007, 2008, 2009 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 |
| * by Jason R. Thorpe of Wasabi Systems, Inc. |
* by Jason R. Thorpe of Wasabi Systems, Inc, and by Andrew Doran. |
| * |
* |
| * Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
* modification, are permitted provided that the following conditions |
| Line 91 __KERNEL_RCSID(0, "$NetBSD$"); |
|
| Line 91 __KERNEL_RCSID(0, "$NetBSD$"); |
|
| #include <sys/kauth.h> |
#include <sys/kauth.h> |
| #include <sys/mutex.h> |
#include <sys/mutex.h> |
| #include <sys/condvar.h> |
#include <sys/condvar.h> |
| |
#include <sys/kthread.h> |
| |
|
| #include <uvm/uvm.h> |
#include <uvm/uvm.h> |
| |
|
| Line 136 int sock_loan_thresh = 4096; |
|
| Line 137 int sock_loan_thresh = 4096; |
|
| #endif |
#endif |
| |
|
| static kmutex_t so_pendfree_lock; |
static kmutex_t so_pendfree_lock; |
| static struct mbuf *so_pendfree; |
static struct mbuf *so_pendfree = NULL; |
| |
|
| #ifndef SOMAXKVA |
#ifndef SOMAXKVA |
| #define SOMAXKVA (16 * 1024 * 1024) |
#define SOMAXKVA (16 * 1024 * 1024) |
| Line 147 static kcondvar_t socurkva_cv; |
|
| Line 148 static kcondvar_t socurkva_cv; |
|
| |
|
| #define SOCK_LOAN_CHUNK 65536 |
#define SOCK_LOAN_CHUNK 65536 |
| |
|
| static size_t sodopendfree(void); |
static void sopendfree_thread(void *); |
| static size_t sodopendfreel(void); |
static kcondvar_t pendfree_thread_cv; |
| |
static lwp_t *sopendfree_lwp; |
| |
|
| static vsize_t |
static vsize_t |
| sokvareserve(struct socket *so, vsize_t len) |
sokvareserve(struct socket *so, vsize_t len) |
| Line 157 sokvareserve(struct socket *so, vsize_t |
|
| Line 159 sokvareserve(struct socket *so, vsize_t |
|
| |
|
| mutex_enter(&so_pendfree_lock); |
mutex_enter(&so_pendfree_lock); |
| while (socurkva + len > somaxkva) { |
while (socurkva + len > somaxkva) { |
| size_t freed; |
|
| |
|
| /* |
|
| * try to do pendfree. |
|
| */ |
|
| |
|
| freed = sodopendfreel(); |
|
| |
|
| /* |
|
| * if some kva was freed, try again. |
|
| */ |
|
| |
|
| if (freed) |
|
| continue; |
|
| |
|
| SOSEND_COUNTER_INCR(&sosend_kvalimit); |
SOSEND_COUNTER_INCR(&sosend_kvalimit); |
| error = cv_wait_sig(&socurkva_cv, &so_pendfree_lock); |
error = cv_wait_sig(&socurkva_cv, &so_pendfree_lock); |
| if (error) { |
if (error) { |
| Line 264 sodoloanfree(struct vm_page **pgs, void |
|
| Line 251 sodoloanfree(struct vm_page **pgs, void |
|
| sokvafree(sva, len); |
sokvafree(sva, len); |
| } |
} |
| |
|
| static size_t |
|
| sodopendfree(void) |
|
| { |
|
| size_t rv; |
|
| |
|
| if (__predict_true(so_pendfree == NULL)) |
|
| return 0; |
|
| |
|
| mutex_enter(&so_pendfree_lock); |
|
| rv = sodopendfreel(); |
|
| mutex_exit(&so_pendfree_lock); |
|
| |
|
| return rv; |
|
| } |
|
| |
|
| /* |
/* |
| * sodopendfreel: free mbufs on "pendfree" list. |
* sopendfree_thread: free mbufs on "pendfree" list. |
| * unlock and relock so_pendfree_lock when freeing mbufs. |
* unlock and relock so_pendfree_lock when freeing mbufs. |
| * |
|
| * => called with so_pendfree_lock held. |
|
| */ |
*/ |
| |
|
| static size_t |
static void |
| sodopendfreel(void) |
sopendfree_thread(void *v) |
| { |
{ |
| struct mbuf *m, *next; |
struct mbuf *m, *next; |
| size_t rv = 0; |
size_t rv; |
| |
|
| KASSERT(mutex_owned(&so_pendfree_lock)); |
|
| |
|
| while (so_pendfree != NULL) { |
mutex_enter(&so_pendfree_lock); |
| m = so_pendfree; |
|
| so_pendfree = NULL; |
|
| mutex_exit(&so_pendfree_lock); |
|
| |
|
| for (; m != NULL; m = next) { |
for (;;) { |
| next = m->m_next; |
rv = 0; |
| KASSERT((~m->m_flags & (M_EXT|M_EXT_PAGES)) == 0); |
while (so_pendfree != NULL) { |
| KASSERT(m->m_ext.ext_refcnt == 0); |
m = so_pendfree; |
| |
so_pendfree = NULL; |
| |
mutex_exit(&so_pendfree_lock); |
| |
|
| |
for (; m != NULL; m = next) { |
| |
next = m->m_next; |
| |
KASSERT((~m->m_flags & (M_EXT|M_EXT_PAGES)) == 0); |
| |
KASSERT(m->m_ext.ext_refcnt == 0); |
| |
|
| |
rv += m->m_ext.ext_size; |
| |
sodoloanfree(m->m_ext.ext_pgs, m->m_ext.ext_buf, |
| |
m->m_ext.ext_size); |
| |
pool_cache_put(mb_cache, m); |
| |
} |
| |
|
| rv += m->m_ext.ext_size; |
mutex_enter(&so_pendfree_lock); |
| sodoloanfree(m->m_ext.ext_pgs, m->m_ext.ext_buf, |
|
| m->m_ext.ext_size); |
|
| pool_cache_put(mb_cache, m); |
|
| } |
} |
| |
if (rv) |
| mutex_enter(&so_pendfree_lock); |
cv_broadcast(&socurkva_cv); |
| |
cv_wait(&pendfree_thread_cv, &so_pendfree_lock); |
| } |
} |
| |
panic("sopendfree_thread"); |
| return (rv); |
/* NOTREACHED */ |
| } |
} |
| |
|
| void |
void |
| Line 332 soloanfree(struct mbuf *m, void *buf, si |
|
| Line 308 soloanfree(struct mbuf *m, void *buf, si |
|
| mutex_enter(&so_pendfree_lock); |
mutex_enter(&so_pendfree_lock); |
| m->m_next = so_pendfree; |
m->m_next = so_pendfree; |
| so_pendfree = m; |
so_pendfree = m; |
| cv_broadcast(&socurkva_cv); |
cv_signal(&pendfree_thread_cv); |
| mutex_exit(&so_pendfree_lock); |
mutex_exit(&so_pendfree_lock); |
| } |
} |
| |
|
| Line 402 sokva_reclaim_callback(struct callback_e |
|
| Line 378 sokva_reclaim_callback(struct callback_e |
|
| KASSERT(ce == &sokva_reclaimerentry); |
KASSERT(ce == &sokva_reclaimerentry); |
| KASSERT(obj == NULL); |
KASSERT(obj == NULL); |
| |
|
| sodopendfree(); |
|
| if (!vm_map_starved_p(kernel_map)) { |
if (!vm_map_starved_p(kernel_map)) { |
| return CALLBACK_CHAIN_ABORT; |
return CALLBACK_CHAIN_ABORT; |
| } |
} |
| Line 420 getsombuf(struct socket *so, int type) |
|
| Line 395 getsombuf(struct socket *so, int type) |
|
| } |
} |
| |
|
| void |
void |
| soinit(void) |
soinit() |
| { |
{ |
| |
|
| mutex_init(&so_pendfree_lock, MUTEX_DEFAULT, IPL_VM); |
mutex_init(&so_pendfree_lock, MUTEX_DEFAULT, IPL_VM); |
| softnet_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); |
softnet_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); |
| cv_init(&socurkva_cv, "sokva"); |
cv_init(&socurkva_cv, "sokva"); |
| |
cv_init(&pendfree_thread_cv, "sopendfr"); |
| soinit2(); |
soinit2(); |
| |
|
| |
|
| /* Set the initial adjusted socket buffer size. */ |
/* Set the initial adjusted socket buffer size. */ |
| if (sb_max_set(sb_max)) |
if (sb_max_set(sb_max)) |
| panic("bad initial sb_max value: %lu", sb_max); |
panic("bad initial sb_max value: %lu", sb_max); |
|
|
| &sokva_reclaimerentry, NULL, sokva_reclaim_callback); |
&sokva_reclaimerentry, NULL, sokva_reclaim_callback); |
| } |
} |
| |
|
| |
void |
| |
soinit1(void) |
| |
{ |
| |
int error = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, |
| |
sopendfree_thread, NULL, &sopendfree_lwp, "sopendfree"); |
| |
if (error) |
| |
panic("soinit1 %d", error); |
| |
} |
| |
|
| /* |
/* |
| * Socket operation routines. |
* Socket operation routines. |
| * These routines are called by the routines in |
* These routines are called by the routines in |
| Line 669 soclose(struct socket *so) |
|
| Line 654 soclose(struct socket *so) |
|
| if ((so->so_state & SS_ISDISCONNECTING) && so->so_nbio) |
if ((so->so_state & SS_ISDISCONNECTING) && so->so_nbio) |
| goto drop; |
goto drop; |
| while (so->so_state & SS_ISCONNECTED) { |
while (so->so_state & SS_ISCONNECTED) { |
| error = sowait(so, so->so_linger * hz); |
error = sowait(so, true, so->so_linger * hz); |
| if (error) |
if (error) |
| break; |
break; |
| } |
} |
| Line 787 sodisconnect(struct socket *so) |
|
| Line 772 sodisconnect(struct socket *so) |
|
| error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, |
error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, |
| NULL, NULL, NULL, NULL); |
NULL, NULL, NULL, NULL); |
| } |
} |
| sodopendfree(); |
|
| return (error); |
return (error); |
| } |
} |
| |
|
| Line 819 sosend(struct socket *so, struct mbuf *a |
|
| Line 803 sosend(struct socket *so, struct mbuf *a |
|
| int error, s, dontroute, atomic; |
int error, s, dontroute, atomic; |
| |
|
| p = l->l_proc; |
p = l->l_proc; |
| sodopendfree(); |
|
| clen = 0; |
clen = 0; |
| |
|
| /* |
/* |
| Line 1088 soreceive(struct socket *so, struct mbuf |
|
| Line 1071 soreceive(struct socket *so, struct mbuf |
|
| else |
else |
| flags = 0; |
flags = 0; |
| |
|
| if ((flags & MSG_DONTWAIT) == 0) |
|
| sodopendfree(); |
|
| |
|
| if (flags & MSG_OOB) { |
if (flags & MSG_OOB) { |
| m = m_get(M_WAIT, MT_DATA); |
m = m_get(M_WAIT, MT_DATA); |
| solock(so); |
solock(so); |
| Line 1536 soshutdown(struct socket *so, int how) |
|
| Line 1516 soshutdown(struct socket *so, int how) |
|
| return error; |
return error; |
| } |
} |
| |
|
| |
int |
| |
sodrain(struct socket *so) |
| |
{ |
| |
int error; |
| |
|
| |
solock(so); |
| |
so->so_state |= SS_ISDRAINING; |
| |
cv_broadcast(&so->so_cv); |
| |
error = soshutdown(so, SHUT_RDWR); |
| |
sounlock(so); |
| |
|
| |
return error; |
| |
} |
| |
|
| void |
void |
| sorflush(struct socket *so) |
sorflush(struct socket *so) |
| { |
{ |
| Line 2029 sohasoutofband(struct socket *so) |
|
| Line 2023 sohasoutofband(struct socket *so) |
|
| { |
{ |
| |
|
| fownsignal(so->so_pgid, SIGURG, POLL_PRI, POLLPRI|POLLRDBAND, so); |
fownsignal(so->so_pgid, SIGURG, POLL_PRI, POLLPRI|POLLRDBAND, so); |
| selnotify(&so->so_rcv.sb_sel, POLLPRI | POLLRDBAND, 0); |
selnotify(&so->so_rcv.sb_sel, POLLPRI | POLLRDBAND, NOTE_SUBMIT); |
| } |
} |
| |
|
| static void |
static void |