diff options
author | Thordur I. Bjornsson <thib@cvs.openbsd.org> | 2009-09-02 18:20:55 +0000 |
---|---|---|
committer | Thordur I. Bjornsson <thib@cvs.openbsd.org> | 2009-09-02 18:20:55 +0000 |
commit | 17a472fb8f7ec24b10b391b1db7dc7d2998bdec8 (patch) | |
tree | 6f2cdeeac65b655ebe48a2373bb695b3a730fb84 | |
parent | 64dce1b62dbae5d0b90eb2fd54e23a0eeacbdf4d (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/files | 4 | ||||
-rw-r--r-- | sys/nfs/nfs.h | 7 | ||||
-rw-r--r-- | sys/nfs/nfs_bio.c | 79 | ||||
-rw-r--r-- | sys/nfs/nfs_subs.c | 6 | ||||
-rw-r--r-- | sys/nfs/nfs_syscalls.c | 136 | ||||
-rw-r--r-- | sys/nfs/nfs_var.h | 10 | ||||
-rw-r--r-- | sys/nfs/nfs_vfsops.c | 29 | ||||
-rw-r--r-- | sys/nfs/nfs_vnops.c | 4 | ||||
-rw-r--r-- | sys/nfs/nfsmount.h | 5 | ||||
-rw-r--r-- | sys/nfs/nfsnode.h | 29 |
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_ */ |