summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThordur I. Bjornsson <thib@cvs.openbsd.org>2009-09-02 18:20:55 +0000
committerThordur I. Bjornsson <thib@cvs.openbsd.org>2009-09-02 18:20:55 +0000
commit17a472fb8f7ec24b10b391b1db7dc7d2998bdec8 (patch)
tree6f2cdeeac65b655ebe48a2373bb695b3a730fb84
parent64dce1b62dbae5d0b90eb2fd54e23a0eeacbdf4d (diff)
Backout the asyncio/aiod change, as it causes buf's to get hung.
problem noticed by deraadt@ ok beck@
-rw-r--r--sys/conf/files4
-rw-r--r--sys/nfs/nfs.h7
-rw-r--r--sys/nfs/nfs_bio.c79
-rw-r--r--sys/nfs/nfs_subs.c6
-rw-r--r--sys/nfs/nfs_syscalls.c136
-rw-r--r--sys/nfs/nfs_var.h10
-rw-r--r--sys/nfs/nfs_vfsops.c29
-rw-r--r--sys/nfs/nfs_vnops.c4
-rw-r--r--sys/nfs/nfsmount.h5
-rw-r--r--sys/nfs/nfsnode.h29
10 files changed, 186 insertions, 123 deletions
diff --git a/sys/conf/files b/sys/conf/files
index 7b5b5741fd6..fe983e3a3a5 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.473 2009/08/29 21:12:55 kettenis Exp $
+# $OpenBSD: files,v 1.474 2009/09/02 18:20:54 thib Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -907,7 +907,7 @@ file netnatm/natm_pcb.c natm
file netnatm/natm_proto.c natm
file netnatm/natm.c natm
file nfs/krpc_subr.c nfsclient
-file nfs/nfs_aiod.c nfsclient
+#file nfs/nfs_aiod.c nfsclient
file nfs/nfs_bio.c nfsclient
file nfs/nfs_boot.c nfsclient
file nfs/nfs_debug.c nfsclient & ddb
diff --git a/sys/nfs/nfs.h b/sys/nfs/nfs.h
index c3bb1ca00a2..1dcaa29cbcf 100644
--- a/sys/nfs/nfs.h
+++ b/sys/nfs/nfs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfs.h,v 1.50 2009/08/25 13:41:29 thib Exp $ */
+/* $OpenBSD: nfs.h,v 1.51 2009/09/02 18:20:54 thib Exp $ */
/* $NetBSD: nfs.h,v 1.10.4.1 1996/05/27 11:23:56 fvdl Exp $ */
/*
@@ -55,8 +55,7 @@
#define NFS_READDIRSIZE 8192 /* Def. readdir size */
#define NFS_DEFRAHEAD 1 /* Def. read ahead # blocks */
#define NFS_MAXRAHEAD 4 /* Max. read ahead # blocks */
-#define NFS_MAXASYNCDAEMON 64 /* Max. # of aiods runnable. */
-#define NFS_DEFASYNCDAEMON 4 /* Def. # of aiods runnable. */
+#define NFS_MAXASYNCDAEMON 20 /* Max. number async_daemons runable */
/*
* Ideally, NFS_DIRBLKSIZ should be bigger, but I've seen servers with
@@ -190,6 +189,8 @@ struct nfsstats {
* by them and break.
*/
#ifdef _KERNEL
+extern int nfs_niothreads;
+
struct uio; struct buf; struct vattr; struct nameidata; /* XXX */
#define NFSINT_SIGMASK (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGKILL)| \
diff --git a/sys/nfs/nfs_bio.c b/sys/nfs/nfs_bio.c
index 45e827946f1..f670a997e02 100644
--- a/sys/nfs/nfs_bio.c
+++ b/sys/nfs/nfs_bio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfs_bio.c,v 1.66 2009/08/27 23:39:46 thib Exp $ */
+/* $OpenBSD: nfs_bio.c,v 1.67 2009/09/02 18:20:54 thib Exp $ */
/* $NetBSD: nfs_bio.c,v 1.25.4.2 1996/07/08 20:47:04 jtc Exp $ */
/*
@@ -57,7 +57,10 @@
#include <nfs/nfsnode.h>
#include <nfs/nfs_var.h>
+extern int nfs_numasync;
extern struct nfsstats nfsstats;
+struct nfs_bufqhead nfs_bufq;
+uint32_t nfs_bufqmax, nfs_bufqlen;
/*
* Vnode op for read using bio
@@ -147,7 +150,7 @@ nfs_bioread(vp, uio, ioflag, cred)
/*
* Start the read ahead(s), as required.
*/
- if (nfs_numaiods > 0 && nmp->nm_readahead > 0) {
+ if (nfs_numasync > 0 && nmp->nm_readahead > 0) {
for (nra = 0; nra < nmp->nm_readahead &&
(lbn + 1 + nra) * biosize < np->n_size; nra++) {
rabn = (lbn + 1 + nra) * (biosize / DEV_BSIZE);
@@ -503,75 +506,25 @@ nfs_vinvalbuf(struct vnode *vp, int flags, struct ucred *cred, struct proc *p)
* are all hung on a dead server.
*/
int
-nfs_asyncio(struct buf *bp)
+nfs_asyncio(bp)
+ struct buf *bp;
{
- struct nfs_aiod *aiod;
- struct nfsmount *nmp;
- int gotone, error;
-
- aiod = NULL;
- nmp = VFSTONFS(bp->b_vp->v_mount);
- gotone = error = 0;
-
- mtx_enter(&nfs_aiodl_mtx);
- aiod = LIST_FIRST(&nfs_aiods_idle);
- if (aiod) {
- /*
- * Found an available aiod, wake it up and send
- * it to work on this mount.
- */
- LIST_REMOVE(aiod, nad_idle);
- mtx_leave(&nfs_aiodl_mtx);
-
- aiod->nad_flags |= NFSAIOD_WAKEUP;
- gotone = 1;
- KASSERT(aiod->nad_mnt == NULL);
- aiod->nad_mnt = nmp;
- nmp->nm_naiods++;
- wakeup_one(aiod);
- } else {
- mtx_leave(&nfs_aiodl_mtx);
- }
-
- /*
- * If no aiod's are available, check if theres already an
- * aiod assoicated with this mount, if so it will process
- * this buf.
- */
- if (!gotone && nmp->nm_naiods > 0)
- gotone = 1;
-
- /*
- * If we still don't have an aiod to process this buffer,
- * force it sync.
- */
- if (!gotone)
+ if (nfs_numasync == 0)
goto out;
+ if (nfs_bufqlen > nfs_bufqmax)
+ goto out; /* too many bufs in use, force sync */
- /*
- * Make sure we don't queue up too much.
- * TODO: Look into implementing migration for aiods.
- */
- if (nmp->nm_bufqlen >= nfs_aiodbufqmax) {
- if (aiod != NULL) {
- aiod->nad_flags &= ~NFSAIOD_WAKEUP;
- aiod->nad_mnt = NULL;
- mtx_enter(&nfs_aiodl_mtx);
- LIST_INSERT_HEAD(&nfs_aiods_idle, aiod, nad_idle);
- mtx_leave(&nfs_aiodl_mtx);
- }
- goto out;
+ if ((bp->b_flags & B_READ) == 0) {
+ bp->b_flags |= B_WRITEINPROG;
}
- /* Finally, queue the buffer and return. */
+ TAILQ_INSERT_TAIL(&nfs_bufq, bp, b_freelist);
+ nfs_bufqlen++;
- if ((bp->b_flags & B_READ) == 0)
- bp->b_flags |= B_WRITEINPROG;
-
- TAILQ_INSERT_TAIL(&nmp->nm_bufq, bp, b_freelist);
- nmp->nm_bufqlen++;
+ wakeup_one(&nfs_bufq);
return (0);
+
out:
nfsstats.forcedsync++;
return (EIO);
diff --git a/sys/nfs/nfs_subs.c b/sys/nfs/nfs_subs.c
index a55ec8b6158..43e2b0c4e4a 100644
--- a/sys/nfs/nfs_subs.c
+++ b/sys/nfs/nfs_subs.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfs_subs.c,v 1.105 2009/08/25 13:41:29 thib Exp $ */
+/* $OpenBSD: nfs_subs.c,v 1.106 2009/09/02 18:20:54 thib Exp $ */
/* $NetBSD: nfs_subs.c,v 1.27.4.3 1996/07/08 20:34:24 jtc Exp $ */
/*
@@ -925,9 +925,7 @@ nfs_vfs_init(struct vfsconf *vfsp)
{
extern struct pool nfs_node_pool;
- LIST_INIT(&nfs_aiods_all);
- LIST_INIT(&nfs_aiods_idle);
- mtx_init(&nfs_aiodl_mtx, IPL_BIO);
+ TAILQ_INIT(&nfs_bufq);
pool_init(&nfs_node_pool, sizeof(struct nfsnode), 0, 0, 0,
"nfsnodepl", NULL);
diff --git a/sys/nfs/nfs_syscalls.c b/sys/nfs/nfs_syscalls.c
index 2820038399c..9e5aa218ef9 100644
--- a/sys/nfs/nfs_syscalls.c
+++ b/sys/nfs/nfs_syscalls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfs_syscalls.c,v 1.86 2009/08/20 15:04:24 thib Exp $ */
+/* $OpenBSD: nfs_syscalls.c,v 1.87 2009/09/02 18:20:54 thib Exp $ */
/* $NetBSD: nfs_syscalls.c,v 1.19 1996/02/18 11:53:52 fvdl Exp $ */
/*
@@ -73,6 +73,7 @@
#include <nfs/nfs_var.h>
/* Global defs. */
+extern int nfs_numasync;
extern struct nfsstats nfsstats;
struct nfssvc_sock *nfs_udpsock;
int nfsd_waiting = 0;
@@ -117,6 +118,11 @@ struct nfsdhead nfsd_head;
int nfssvc_sockhead_flag;
int nfsd_head_flag;
+#ifdef NFSCLIENT
+struct proc *nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
+int nfs_niothreads = -1;
+#endif
+
/*
* NFS server pseudo system call for the nfsd's
* Based on the flag value it either:
@@ -550,7 +556,135 @@ nfsrv_init(terminating)
pool_init(&nfsrv_descript_pl, sizeof(struct nfsrv_descript), 0, 0, 0,
"ndscpl", &pool_allocator_nointr);
}
+#endif /* NFSSERVER */
+
+#ifdef NFSCLIENT
+/*
+ * Asynchronous I/O threads for client nfs.
+ * They do read-ahead and write-behind operations on the block I/O cache.
+ * Never returns unless it fails or gets killed.
+ */
+void
+nfssvc_iod(void *arg)
+{
+ struct proc *p = (struct proc *)arg;
+ struct buf *bp, *nbp;
+ int i, myiod;
+ struct vnode *vp;
+ int error = 0, s, bufcount;
+
+ bufcount = 256; /* XXX: Big enough? sysctl, constant ? */
+
+ /* Assign my position or return error if too many already running. */
+ myiod = -1;
+ for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
+ if (nfs_asyncdaemon[i] == NULL) {
+ myiod = i;
+ break;
+ }
+ }
+ if (myiod == -1)
+ kthread_exit(EBUSY);
+
+ nfs_asyncdaemon[myiod] = p;
+ nfs_numasync++;
+
+ /* Upper limit on how many bufs we'll queue up for this iod. */
+ if (nfs_bufqmax > bcstats.numbufs / 4) {
+ nfs_bufqmax = bcstats.numbufs / 4; /* limit to 1/4 of bufs */
+ bufcount = 0;
+ }
+
+ nfs_bufqmax += bufcount;
+
+ /* Just loop around doin our stuff until SIGKILL. */
+ for (;;) {
+ while (TAILQ_FIRST(&nfs_bufq) == NULL && error == 0) {
+ error = tsleep(&nfs_bufq,
+ PWAIT | PCATCH, "nfsidl", 0);
+ }
+ while ((bp = TAILQ_FIRST(&nfs_bufq)) != NULL) {
+ /* Take one off the front of the list */
+ TAILQ_REMOVE(&nfs_bufq, bp, b_freelist);
+ nfs_bufqlen--;
+ if (bp->b_flags & B_READ)
+ (void) nfs_doio(bp, NULL);
+ else do {
+ /*
+ * Look for a delayed write for the same vnode, so I can do
+ * it now. We must grab it before calling nfs_doio() to
+ * avoid any risk of the vnode getting vclean()'d while
+ * we are doing the write rpc.
+ */
+ vp = bp->b_vp;
+ s = splbio();
+ LIST_FOREACH(nbp, &vp->v_dirtyblkhd, b_vnbufs) {
+ if ((nbp->b_flags &
+ (B_BUSY|B_DELWRI|B_NEEDCOMMIT|B_NOCACHE))!=B_DELWRI)
+ continue;
+ nbp->b_flags |= B_ASYNC;
+ bremfree(nbp);
+ buf_acquire(nbp);
+ break;
+ }
+ /*
+ * For the delayed write, do the first part of nfs_bwrite()
+ * up to, but not including nfs_strategy().
+ */
+ if (nbp) {
+ nbp->b_flags &= ~(B_READ|B_DONE|B_ERROR);
+ buf_undirty(nbp);
+ nbp->b_vp->v_numoutput++;
+ }
+ splx(s);
+
+ (void) nfs_doio(bp, NULL);
+ } while ((bp = nbp) != NULL);
+ }
+ if (error) {
+ nfs_asyncdaemon[myiod] = NULL;
+ nfs_numasync--;
+ nfs_bufqmax -= bufcount;
+ kthread_exit(error);
+ }
+ }
+}
+
+void
+nfs_getset_niothreads(set)
+ int set;
+{
+ struct proc *p;
+ int i, have, start;
+
+ for (have = 0, i = 0; i < NFS_MAXASYNCDAEMON; i++)
+ if (nfs_asyncdaemon[i] != NULL)
+ have++;
+
+ if (set) {
+ /* clamp to sane range */
+ nfs_niothreads = max(0, min(nfs_niothreads, NFS_MAXASYNCDAEMON));
+
+ start = nfs_niothreads - have;
+
+ while (start > 0) {
+ kthread_create(nfssvc_iod, p, &p, "nfsio");
+ start--;
+ }
+
+ for (i = 0; (start < 0) && (i < NFS_MAXASYNCDAEMON); i++)
+ if (nfs_asyncdaemon[i] != NULL) {
+ psignal(nfs_asyncdaemon[i], SIGKILL);
+ start++;
+ }
+ } else {
+ if (nfs_niothreads >= 0)
+ nfs_niothreads = have;
+ }
+}
+#endif /* NFSCLIENT */
+#ifdef NFSSERVER
/*
* Find an nfssrv_sock for nfsd, sleeping if needed.
*/
diff --git a/sys/nfs/nfs_var.h b/sys/nfs/nfs_var.h
index adaf5e2772f..56fb97a615d 100644
--- a/sys/nfs/nfs_var.h
+++ b/sys/nfs/nfs_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfs_var.h,v 1.57 2009/08/20 15:04:24 thib Exp $ */
+/* $OpenBSD: nfs_var.h,v 1.58 2009/09/02 18:20:54 thib Exp $ */
/* $NetBSD: nfs_var.h,v 1.3 1996/02/18 11:53:54 fvdl Exp $ */
/*
@@ -44,11 +44,6 @@ struct componentname;
struct nfs_diskless;
struct nfsm_info;
-/* nfs_aiod.c */
-void nfs_aiod(void *);
-int nfs_set_naiod(int);
-void nfs_init_aiod(void);
-
/* nfs_bio.c */
int nfs_bioread(struct vnode *, struct uio *, int, struct ucred *);
int nfs_write(void *);
@@ -261,6 +256,9 @@ int nfssvc_nfsd(struct nfsd *);
void nfsrv_zapsock(struct nfssvc_sock *);
void nfsrv_slpderef(struct nfssvc_sock *);
void nfsrv_init(int);
+void nfssvc_iod(void *);
+void start_nfsio(void *);
+void nfs_getset_niothreads(int);
/* nfs_kq.c */
int nfs_kqfilter(void *);
diff --git a/sys/nfs/nfs_vfsops.c b/sys/nfs/nfs_vfsops.c
index b872cfd2a56..5c570f1efb8 100644
--- a/sys/nfs/nfs_vfsops.c
+++ b/sys/nfs/nfs_vfsops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfs_vfsops.c,v 1.90 2009/08/25 13:41:29 thib Exp $ */
+/* $OpenBSD: nfs_vfsops.c,v 1.91 2009/09/02 18:20:54 thib Exp $ */
/* $NetBSD: nfs_vfsops.c,v 1.46.4.1 1996/05/25 22:40:35 fvdl Exp $ */
/*
@@ -611,10 +611,9 @@ nfs_mount(mp, path, data, ndp, p)
if ((args.flags & (NFSMNT_NFSV3|NFSMNT_RDIRPLUS)) == NFSMNT_RDIRPLUS)
return (EINVAL);
- if (nfs_numaiods == -1) {
- error = nfs_set_naiod(NFS_DEFASYNCDAEMON);
- if (error)
- return (error);
+ if (nfs_niothreads < 0) {
+ nfs_niothreads = 4;
+ nfs_getset_niothreads(1);
}
if (mp->mnt_flag & MNT_UPDATE) {
@@ -672,9 +671,9 @@ mountnfs(argp, mp, nam, pth, hst)
m_freem(nam);
return (0);
} else {
- nmp = malloc(sizeof(*nmp), M_NFSMNT, M_WAITOK|M_ZERO);
- mp->mnt_data = nmp;
- TAILQ_INIT(&nmp->nm_bufq);
+ nmp = malloc(sizeof(struct nfsmount), M_NFSMNT,
+ M_WAITOK|M_ZERO);
+ mp->mnt_data = (qaddr_t)nmp;
}
vfs_getnewfsid(mp);
@@ -840,7 +839,7 @@ int
nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
size_t newlen, struct proc *p)
{
- int rv, naiods;
+ int rv;
/*
* All names at this level are terminal.
@@ -872,13 +871,11 @@ nfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
return 0;
case NFS_NIOTHREADS:
- naiods = nfs_numaiods;
- rv = sysctl_int(oldp, oldlenp, newp, newlen, &naiods);
- if (newp && rv == 0) {
- if (naiods < 0)
- return (EINVAL);
- rv = nfs_set_naiod(naiods);
- }
+ nfs_getset_niothreads(0);
+
+ rv = sysctl_int(oldp, oldlenp, newp, newlen, &nfs_niothreads);
+ if (newp)
+ nfs_getset_niothreads(1);
return rv;
diff --git a/sys/nfs/nfs_vnops.c b/sys/nfs/nfs_vnops.c
index 47eeda6a711..4e32e84259b 100644
--- a/sys/nfs/nfs_vnops.c
+++ b/sys/nfs/nfs_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfs_vnops.c,v 1.123 2009/08/20 15:04:24 thib Exp $ */
+/* $OpenBSD: nfs_vnops.c,v 1.124 2009/09/02 18:20:54 thib Exp $ */
/* $NetBSD: nfs_vnops.c,v 1.62.4.1 1996/07/08 20:26:52 jtc Exp $ */
/*
@@ -184,6 +184,8 @@ extern u_int32_t nfs_true, nfs_false;
extern u_int32_t nfs_xdrneg1;
extern struct nfsstats nfsstats;
extern nfstype nfsv3_type[9];
+int nfs_numasync = 0;
+
void
nfs_cache_enter(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
diff --git a/sys/nfs/nfsmount.h b/sys/nfs/nfsmount.h
index 2fc13680897..fc6fcf9bc05 100644
--- a/sys/nfs/nfsmount.h
+++ b/sys/nfs/nfsmount.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfsmount.h,v 1.23 2009/08/25 13:41:29 thib Exp $ */
+/* $OpenBSD: nfsmount.h,v 1.24 2009/09/02 18:20:54 thib Exp $ */
/* $NetBSD: nfsmount.h,v 1.10 1996/02/18 11:54:03 fvdl Exp $ */
/*
@@ -71,9 +71,6 @@ struct nfsmount {
int nm_wsize; /* Max size of write rpc */
int nm_readdirsize; /* Size of a readdir rpc */
int nm_readahead; /* Num. of blocks to readahead */
- TAILQ_HEAD(, buf) nm_bufq; /* async io buffer queue. */
- int nm_bufqlen; /* number of buffers in nm_bufq */
- int nm_naiods; /* # of aiods processing this mount */
u_char nm_verf[NFSX_V3WRITEVERF]; /* V3 write verifier */
u_short nm_acregmin; /* Attr cache file recently modified */
u_short nm_acregmax; /* ac file not recently modified */
diff --git a/sys/nfs/nfsnode.h b/sys/nfs/nfsnode.h
index b0f00b77b73..85d411c9ba5 100644
--- a/sys/nfs/nfsnode.h
+++ b/sys/nfs/nfsnode.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfsnode.h,v 1.37 2009/08/27 23:26:56 thib Exp $ */
+/* $OpenBSD: nfsnode.h,v 1.38 2009/09/02 18:20:54 thib Exp $ */
/* $NetBSD: nfsnode.h,v 1.16 1996/02/18 11:54:04 fvdl Exp $ */
/*
@@ -137,27 +137,10 @@ struct nfsnode {
#define VTONFS(vp) ((struct nfsnode *)(vp)->v_data)
#define NFSTOV(np) ((np)->n_vnode)
-/* nfs aiod datas. */
-struct nfs_aiod {
- LIST_ENTRY(nfs_aiod) nad_all;
- LIST_ENTRY(nfs_aiod) nad_idle;
- struct nfsmount *nad_mnt;
- int nad_flags;
-};
-
-/* Flags for nad_flags. */
-#define NFSAIOD_EXIT 0x0001 /* aiod being asked to exit. */
-#define NFSAIOD_WAKEUP 0x0002 /* aiod being asked to wakeup. */
-/* used by nfs_set_naiod(), for convience. */
-#define NFSAIOD_QUIT (NFSAIOD_EXIT|NFSAIOD_WAKEUP) /* aiod must quit. */
-
-
-LIST_HEAD(nfs_aiodhead, nfs_aiod);
-
-extern struct mutex nfs_aiodl_mtx;
-extern struct nfs_aiodhead nfs_aiods_all;
-extern struct nfs_aiodhead nfs_aiods_idle;
-extern int nfs_numaiods;
-extern int nfs_aiodbufqmax;
+/*
+ * Queue head for nfsiod's
+ */
+extern TAILQ_HEAD(nfs_bufqhead, buf) nfs_bufq;
+extern uint32_t nfs_bufqlen, nfs_bufqmax;
#endif /* _NFS_NFSNODE_H_ */