From bcf2e4f22f046bb0af415d03bb765647b7197aec Mon Sep 17 00:00:00 2001 From: yamt Date: Tue, 3 Jun 2003 14:27:48 +0000 Subject: [PATCH] fix a problem in 'protected' case of writerpc. retransmitted mbufs can survive even after requests themselves finished. so, before unbusy pages, make sure that mbufs referring them go away. pointed by enami tsugutomo on port-mips. --- sys/nfs/nfs_vnops.c | 50 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/sys/nfs/nfs_vnops.c b/sys/nfs/nfs_vnops.c index d9f07a1662b6..a904f2508ef6 100644 --- a/sys/nfs/nfs_vnops.c +++ b/sys/nfs/nfs_vnops.c @@ -1,4 +1,4 @@ -/* $NetBSD: nfs_vnops.c,v 1.170 2003/05/27 14:41:06 yamt Exp $ */ +/* $NetBSD: nfs_vnops.c,v 1.171 2003/06/03 14:27:48 yamt Exp $ */ /* * Copyright (c) 1989, 1993 @@ -43,7 +43,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: nfs_vnops.c,v 1.170 2003/05/27 14:41:06 yamt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nfs_vnops.c,v 1.171 2003/06/03 14:27:48 yamt Exp $"); #include "opt_nfs.h" #include "opt_uvmhist.h" @@ -1209,15 +1209,28 @@ nfsmout: return (error); } +struct nfs_writerpc_context { + struct simplelock nwc_slock; + volatile int nwc_mbufcount; +}; + /* * free mbuf used to refer protected pages while write rpc call. + * called at splvm. */ static void nfs_writerpc_extfree(struct mbuf *m, caddr_t buf, size_t size, void *arg) { + struct nfs_writerpc_context *ctx = arg; KASSERT(m != NULL); + KASSERT(ctx != NULL); pool_cache_put(&mbpool_cache, m); + simple_lock(&ctx->nwc_slock); + if (--ctx->nwc_mbufcount == 0) { + wakeup(ctx); + } + simple_unlock(&ctx->nwc_slock); } /* @@ -1241,6 +1254,12 @@ nfs_writerpc(vp, uiop, iomode, pageprotected, stalewriteverf) const int v3 = NFS_ISV3(vp); int committed = NFSV3WRITE_FILESYNC; struct nfsnode *np = VTONFS(vp); + struct nfs_writerpc_context ctx; + int s; + struct lwp *l; + + simple_lock_init(&ctx.nwc_slock); + ctx.nwc_mbufcount = 1; if (vp->v_mount->mnt_flag & MNT_RDONLY) { panic("writerpc readonly vp %p", vp); @@ -1253,6 +1272,10 @@ nfs_writerpc(vp, uiop, iomode, pageprotected, stalewriteverf) tsiz = uiop->uio_resid; if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize) return (EFBIG); + if (pageprotected) { + l = curlwp; + PHOLD(l); + } while (tsiz > 0) { int datalen; @@ -1293,7 +1316,7 @@ nfs_writerpc(vp, uiop, iomode, pageprotected, stalewriteverf) m = m_get(M_WAIT, MT_DATA); MCLAIM(m, &nfs_mowner); MEXTADD(m, iovp->iov_base, len, M_MBUF, - nfs_writerpc_extfree, NULL); + nfs_writerpc_extfree, &ctx); m->m_flags |= M_EXT_ROMAP; m->m_len = len; mb->m_next = m; @@ -1309,6 +1332,11 @@ nfs_writerpc(vp, uiop, iomode, pageprotected, stalewriteverf) iovp->iov_len -= len; uiop->uio_offset += len; uiop->uio_resid -= len; + s = splvm(); + simple_lock(&ctx.nwc_slock); + ctx.nwc_mbufcount++; + simple_unlock(&ctx.nwc_slock); + splx(s); } else { nfsm_uiotom(uiop, len); } @@ -1371,6 +1399,22 @@ nfs_writerpc(vp, uiop, iomode, pageprotected, stalewriteverf) break; tsiz -= len; } + if (pageprotected) { + /* + * wait until mbufs go away. + * retransmitted mbufs can survive longer than rpc requests + * themselves. + */ + s = splvm(); + simple_lock(&ctx.nwc_slock); + ctx.nwc_mbufcount--; + while (ctx.nwc_mbufcount > 0) { + ltsleep(&ctx, PRIBIO, "nfsmblk", 0, &ctx.nwc_slock); + } + simple_unlock(&ctx.nwc_slock); + splx(s); + PRELE(l); + } nfsmout: *iomode = committed; if (error)