aboutsummaryrefslogtreecommitdiff
path: root/sys/nfs/nfs_bio.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/nfs/nfs_bio.c')
-rw-r--r--sys/nfs/nfs_bio.c120
1 files changed, 85 insertions, 35 deletions
diff --git a/sys/nfs/nfs_bio.c b/sys/nfs/nfs_bio.c
index c57db679a21f..da03a9d121ea 100644
--- a/sys/nfs/nfs_bio.c
+++ b/sys/nfs/nfs_bio.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* @(#)nfs_bio.c 8.5 (Berkeley) 1/4/94
- * $Id: nfs_bio.c,v 1.27 1996/10/12 17:39:39 bde Exp $
+ * $Id: nfs_bio.c,v 1.28 1996/10/21 10:07:48 dfr Exp $
*/
#include <sys/param.h>
@@ -62,13 +62,9 @@
static struct buf *nfs_getcacheblk __P((struct vnode *vp, daddr_t bn, int size,
struct proc *p));
-extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
extern int nfs_numasync;
extern struct nfsstats nfsstats;
-static int nfs_dwrite = 1;
-SYSCTL_INT(_vfs_nfs, OID_AUTO, dwrite, CTLFLAG_RW, &nfs_dwrite, 0, "");
-
/*
* Ifdefs for FreeBSD-current's merged VM/buffer cache. It is unfortunate
* that this isn't done inside getblk() and brelse() so these calls
@@ -727,12 +723,87 @@ nfs_asyncio(bp, cred)
register struct buf *bp;
struct ucred *cred;
{
- register int i;
+ struct nfsmount *nmp;
+ int i;
+ int gotiod;
+ int slpflag = 0;
+ int slptimeo = 0;
+ int error;
if (nfs_numasync == 0)
return (EIO);
+
+ nmp = VFSTONFS(bp->b_vp->v_mount);
+again:
+ if (nmp->nm_flag & NFSMNT_INT)
+ slpflag = PCATCH;
+ gotiod = FALSE;
+
+ /*
+ * Find a free iod to process this request.
+ */
for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
- if (nfs_iodwant[i]) {
+ if (nfs_iodwant[i]) {
+ /*
+ * Found one, so wake it up and tell it which
+ * mount to process.
+ */
+ NFS_DPF(ASYNCIO,
+ ("nfs_asyncio: waking iod %d for mount %p\n",
+ i, nmp));
+ nfs_iodwant[i] = (struct proc *)0;
+ nfs_iodmount[i] = nmp;
+ nmp->nm_bufqiods++;
+ wakeup((caddr_t)&nfs_iodwant[i]);
+ gotiod = TRUE;
+ }
+
+ /*
+ * If none are free, we may already have an iod working on this mount
+ * point. If so, it will process our request.
+ */
+ if (!gotiod) {
+ if (nmp->nm_bufqiods > 0) {
+ NFS_DPF(ASYNCIO,
+ ("nfs_asyncio: %d iods are already processing mount %p\n",
+ nmp->nm_bufqiods, nmp));
+ gotiod = TRUE;
+ }
+ }
+
+ /*
+ * If we have an iod which can process the request, then queue
+ * the buffer.
+ */
+ if (gotiod) {
+ /*
+ * Ensure that the queue never grows too large.
+ */
+ while (nmp->nm_bufqlen >= 2*nfs_numasync) {
+ NFS_DPF(ASYNCIO,
+ ("nfs_asyncio: waiting for mount %p queue to drain\n", nmp));
+ nmp->nm_bufqwant = TRUE;
+ error = tsleep(&nmp->nm_bufq, slpflag | PRIBIO,
+ "nfsaio", slptimeo);
+ if (error) {
+ if (nfs_sigintr(nmp, NULL, bp->b_proc))
+ return (EINTR);
+ if (slpflag == PCATCH) {
+ slpflag = 0;
+ slptimeo = 2 * hz;
+ }
+ }
+ /*
+ * We might have lost our iod while sleeping,
+ * so check and loop if nescessary.
+ */
+ if (nmp->nm_bufqiods == 0) {
+ NFS_DPF(ASYNCIO,
+ ("nfs_asyncio: no iods after mount %p queue was drained, looping\n", nmp));
+ goto again;
+ }
+ }
+
if (bp->b_flags & B_READ) {
if (bp->b_rcred == NOCRED && cred != NOCRED) {
crhold(cred);
@@ -746,38 +817,17 @@ nfs_asyncio(bp, cred)
}
}
- TAILQ_INSERT_TAIL(&nfs_bufq, bp, b_freelist);
- nfs_iodwant[i] = (struct proc *)0;
- wakeup((caddr_t)&nfs_iodwant[i]);
+ TAILQ_INSERT_TAIL(&nmp->nm_bufq, bp, b_freelist);
+ nmp->nm_bufqlen++;
return (0);
- }
-
- /*
- * If it is a read or a write already marked B_WRITEINPROG or B_NOCACHE
- * return EIO so the process will call nfs_doio() and do it
- * synchronously.
- */
- if (bp->b_flags & (B_READ | B_WRITEINPROG | B_NOCACHE))
- return (EIO);
-
- /*
- * Allow the administrator to override the choice of using a delayed
- * write since it is a pessimization for some servers, notably some
- * Solaris servers.
- */
- if (!nfs_dwrite)
- return (EIO);
+ }
/*
- * Just turn the async write into a delayed write, instead of
- * doing in synchronously. Hopefully, at least one of the nfsiods
- * is currently doing a write for this file and will pick up the
- * delayed writes before going back to sleep.
+ * All the iods are busy on other mounts, so return EIO to
+ * force the caller to process the i/o synchronously.
*/
- bp->b_flags |= B_DELWRI;
- reassignbuf(bp, bp->b_vp);
- biodone(bp);
- return (0);
+ NFS_DPF(ASYNCIO, ("nfs_asyncio: no iods available, i/o is synchronous\n"));
+ return (EIO);
}
/*