nfssvc_nfsd: reduce a chance for a slow peer to capture all our threads.

instead of sleeping to wait for the socket to send our reply,
just hand-off our reply to the thread which is holding the socket.
This commit is contained in:
yamt 2006-01-03 12:30:01 +00:00
parent a5da6cae5b
commit 7416ebb551
3 changed files with 60 additions and 32 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs.h,v 1.53 2006/01/03 11:41:03 yamt Exp $ */
/* $NetBSD: nfs.h,v 1.54 2006/01/03 12:30:01 yamt Exp $ */
/*
* Copyright (c) 1989, 1993, 1995
* The Regents of the University of California. All rights reserved.
@ -444,6 +444,7 @@ struct nfssvc_sock {
int ns_reclen;
int ns_numuids;
u_int32_t ns_sref;
SIMPLEQ_HEAD(, nfsrv_descript) ns_sendq; /* send reply list */
LIST_HEAD(, nfsrv_descript) ns_tq; /* Write gather lists */
LIST_HEAD(, nfsuid) ns_uidhashtbl[NFS_UIDHASHSIZ];
LIST_HEAD(nfsrvw_delayhash, nfsrv_descript) ns_wdelayhashtbl[NFS_WDELAYHASHSIZ];
@ -457,6 +458,7 @@ struct nfssvc_sock {
#define SLP_BUSY 0x10
#define SLP_WANT 0x20
#define SLP_LASTFRAG 0x40
#define SLP_SENDING 0x80
extern TAILQ_HEAD(nfssvc_sockhead, nfssvc_sock) nfssvc_sockhead;
extern struct nfssvc_sockhead nfssvc_sockpending;
@ -467,6 +469,7 @@ extern int nfssvc_sockhead_flag;
int nfsdsock_lock(struct nfssvc_sock *, boolean_t);
void nfsdsock_unlock(struct nfssvc_sock *);
int nfsdsock_drain(struct nfssvc_sock *);
int nfsdsock_sendreply(struct nfssvc_sock *, struct nfsrv_descript *);
/*
* One of these structures is allocated for each nfsd.
@ -499,6 +502,7 @@ struct nfsrv_descript {
LIST_ENTRY(nfsrv_descript) nd_hash; /* Hash list */
LIST_ENTRY(nfsrv_descript) nd_tq; /* and timer list */
LIST_HEAD(,nfsrv_descript) nd_coalesce; /* coalesced writes */
SIMPLEQ_ENTRY(nfsrv_descript) nd_sendq; /* send reply list */
struct mbuf *nd_mrep; /* Request mbuf list */
struct mbuf *nd_md; /* Current dissect mbuf */
struct mbuf *nd_mreq; /* Reply mbuf list */

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_socket.c,v 1.121 2006/01/03 11:41:03 yamt Exp $ */
/* $NetBSD: nfs_socket.c,v 1.122 2006/01/03 12:30:01 yamt Exp $ */
/*
* Copyright (c) 1989, 1991, 1993, 1995
@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nfs_socket.c,v 1.121 2006/01/03 11:41:03 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: nfs_socket.c,v 1.122 2006/01/03 12:30:01 yamt Exp $");
#include "fs_nfs.h"
#include "opt_nfs.h"
@ -2562,4 +2562,45 @@ nfsrv_wakenfsd(slp)
TAILQ_INSERT_TAIL(&nfssvc_sockpending, slp, ns_pending);
simple_unlock(&nfsd_slock);
}
int
nfsdsock_sendreply(struct nfssvc_sock *slp, struct nfsrv_descript *nd)
{
int error;
if (nd->nd_mrep != NULL) {
m_freem(nd->nd_mrep);
nd->nd_mrep = NULL;
}
simple_lock(&slp->ns_lock);
if ((slp->ns_flag & SLP_SENDING) != 0) {
SIMPLEQ_INSERT_TAIL(&slp->ns_sendq, nd, nd_sendq);
simple_unlock(&slp->ns_lock);
return 0;
}
KASSERT(SIMPLEQ_EMPTY(&slp->ns_sendq));
slp->ns_flag |= SLP_SENDING;
simple_unlock(&slp->ns_lock);
again:
error = nfs_send(slp->ns_so, nd->nd_nam2, nd->nd_mreq, NULL, curlwp);
if (nd->nd_nam2) {
m_free(nd->nd_nam2);
}
pool_put(&nfs_srvdesc_pool, nd);
simple_lock(&slp->ns_lock);
KASSERT((slp->ns_flag & SLP_SENDING) != 0);
nd = SIMPLEQ_FIRST(&slp->ns_sendq);
if (nd != NULL) {
SIMPLEQ_REMOVE_HEAD(&slp->ns_sendq, nd_sendq);
simple_unlock(&slp->ns_lock);
goto again;
}
slp->ns_flag &= ~SLP_SENDING;
simple_unlock(&slp->ns_lock);
return error;
}
#endif /* NFSSERVER */

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_syscalls.c,v 1.85 2006/01/03 11:41:03 yamt Exp $ */
/* $NetBSD: nfs_syscalls.c,v 1.86 2006/01/03 12:30:01 yamt Exp $ */
/*
* Copyright (c) 1989, 1993
@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nfs_syscalls.c,v 1.85 2006/01/03 11:41:03 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: nfs_syscalls.c,v 1.86 2006/01/03 12:30:01 yamt Exp $");
#include "fs_nfs.h"
#include "opt_nfs.h"
@ -128,9 +128,9 @@ int nfs_niothreads = -1; /* == "0, and has never been set" */
#endif
#ifdef NFSSERVER
static void nfsd_rt __P((int, struct nfsrv_descript *, int));
static struct nfssvc_sock *nfsrv_sockalloc __P((void));
static void nfsrv_sockfree __P((struct nfssvc_sock *));
static void nfsd_rt __P((int, struct nfsrv_descript *, int));
#endif
/*
@ -397,6 +397,8 @@ nfsrv_sockalloc()
memset(slp, 0, sizeof (struct nfssvc_sock));
simple_lock_init(&slp->ns_lock);
TAILQ_INIT(&slp->ns_uidlruhead);
LIST_INIT(&slp->ns_tq);
SIMPLEQ_INIT(&slp->ns_sendq);
s = splsoftnet();
simple_lock(&nfsd_slock);
TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain);
@ -526,8 +528,6 @@ nfssvc_nfsd(nsd, argp, l)
struct mbuf *m;
int siz;
struct nfssvc_sock *slp;
struct socket *so;
int *solockp;
struct nfsd *nfsd = nsd->nsd_nfsd;
struct nfsrv_descript *nd = NULL;
struct mbuf *mreq;
@ -633,12 +633,7 @@ nfssvc_nfsd(nsd, argp, l)
continue;
}
splx(s);
so = slp->ns_so;
sotype = so->so_type;
if (so->so_proto->pr_flags & PR_CONNREQUIRED)
solockp = &slp->ns_solock;
else
solockp = NULL;
sotype = slp->ns_so->so_type;
if (nd) {
nd->nd_starttime = time;
if (nd->nd_nam2)
@ -791,27 +786,16 @@ nfssvc_nfsd(nsd, argp, l)
*mtod(m, u_int32_t *) =
htonl(0x80000000 | siz);
}
if (solockp)
nfs_sndlock(solockp, NULL);
if (slp->ns_flag & SLP_VALID) {
error = nfs_send(so, nd->nd_nam2,
m, NULL, l);
} else {
error = EPIPE;
m_freem(m);
nd->nd_mreq = m;
if (nfsrtton) {
nfsd_rt(slp->ns_so->so_type, nd,
cacherep);
}
if (solockp)
nfs_sndunlock(solockp);
if (nfsrtton)
nfsd_rt(sotype, nd, cacherep);
if (nd->nd_nam2)
m_free(nd->nd_nam2);
if (nd->nd_mrep)
m_freem(nd->nd_mrep);
error = nfsdsock_sendreply(slp, nd);
nd = NULL;
if (error == EPIPE)
nfsrv_zapsock(slp);
if (error == EINTR || error == ERESTART) {
pool_put(&nfs_srvdesc_pool, nd);
nfsrv_slpderef(slp);
s = splsoftnet();
goto done;
@ -916,7 +900,6 @@ nfsrv_zapsock(slp)
LIST_REMOVE(nwp, nd_tq);
pool_put(&nfs_srvdesc_pool, nwp);
}
LIST_INIT(&slp->ns_tq);
splx(s);
}