From 104db2fbb89ba01fba8759aee3aa0c09eb13f9bf Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Thu, 16 Sep 2010 10:03:30 -0700 Subject: [PATCH] kernel - Fix NFS panic * nfs_write() was not wrapped with a token, leading to races. * Add some queueing assertions while we are here. Reported-by: Thomas Nikolajsen --- sys/vfs/nfs/nfs_bio.c | 37 ++++++++++++++++++++++++++----------- sys/vfs/nfs/nfs_iod.c | 1 - sys/vfs/nfs/nfs_socket.c | 1 + 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/sys/vfs/nfs/nfs_bio.c b/sys/vfs/nfs/nfs_bio.c index bfeab6a639..5e20bb4a76 100644 --- a/sys/vfs/nfs/nfs_bio.c +++ b/sys/vfs/nfs/nfs_bio.c @@ -506,13 +506,18 @@ nfs_write(struct vop_write_args *ap) #endif if (vp->v_type != VREG) return (EIO); + + lwkt_gettoken(&nmp->nm_token); + if (np->n_flag & NWRITEERR) { np->n_flag &= ~NWRITEERR; + lwkt_reltoken(&nmp->nm_token); return (np->n_error); } if ((nmp->nm_flag & NFSMNT_NFSV3) != 0 && - (nmp->nm_state & NFSSTA_GOTFSINFO) == 0) + (nmp->nm_state & NFSSTA_GOTFSINFO) == 0) { (void)nfs_fsinfo(nmp, vp, td); + } /* * Synchronously flush pending buffers if we are in synchronous @@ -524,7 +529,7 @@ nfs_write(struct vop_write_args *ap) error = nfs_flush(vp, MNT_WAIT, td, 0); /* error = nfs_vinvalbuf(vp, V_SAVE, 1); */ if (error) - return (error); + goto done; } } @@ -537,16 +542,22 @@ restart: np->n_attrstamp = 0; error = VOP_GETATTR(vp, &vattr); if (error) - return (error); + goto done; uio->uio_offset = np->n_size; } - if (uio->uio_offset < 0) - return (EINVAL); - if ((uio->uio_offset + uio->uio_resid) > nmp->nm_maxfilesize) - return (EFBIG); - if (uio->uio_resid == 0) - return (0); + if (uio->uio_offset < 0) { + error = EINVAL; + goto done; + } + if ((uio->uio_offset + uio->uio_resid) > nmp->nm_maxfilesize) { + error = EFBIG; + goto done; + } + if (uio->uio_resid == 0) { + error = 0; + goto done; + } /* * We need to obtain the rslock if we intend to modify np->n_size @@ -570,7 +581,8 @@ restart: /* not reached */ case EINTR: case ERESTART: - return(EINTR); + error = EINTR; + goto done; /* not reached */ default: break; @@ -587,7 +599,8 @@ restart: lwpsignal(td->td_proc, td->td_lwp, SIGXFSZ); if (haverslock) nfs_rsunlock(np); - return (EFBIG); + error = EFBIG; + goto done; } biosize = vp->v_mount->mnt_stat.f_iosize; @@ -773,6 +786,8 @@ again: if (haverslock) nfs_rsunlock(np); +done: + lwkt_reltoken(&nmp->nm_token); return (error); } diff --git a/sys/vfs/nfs/nfs_iod.c b/sys/vfs/nfs/nfs_iod.c index 1df710d7a1..8b8c8538c8 100644 --- a/sys/vfs/nfs/nfs_iod.c +++ b/sys/vfs/nfs/nfs_iod.c @@ -58,7 +58,6 @@ #include #include #include -#include #include #include diff --git a/sys/vfs/nfs/nfs_socket.c b/sys/vfs/nfs/nfs_socket.c index 1b78052a0c..628c1b5b7a 100644 --- a/sys/vfs/nfs/nfs_socket.c +++ b/sys/vfs/nfs/nfs_socket.c @@ -1289,6 +1289,7 @@ nfs_request_try(struct nfsreq *rep) */ crit_enter(); mtx_link_init(&rep->r_link); + KKASSERT((rep->r_flags & R_ONREQQ) == 0); TAILQ_INSERT_TAIL(&nmp->nm_reqq, rep, r_chain); rep->r_flags |= R_ONREQQ; ++nmp->nm_reqqlen; -- 2.41.0