From: Matthew Dillon Date: Fri, 18 Jul 2014 03:54:42 +0000 (-0700) Subject: kernel - Fix two NFS crashes X-Git-Tag: v4.1.0~404 X-Git-Url: https://gitweb.dragonflybsd.org/~tuxillo/dragonfly.git/commitdiff_plain/966299f632b47957bccab788e2eca8bde4c2c2b6 kernel - Fix two NFS crashes * Fix a bug during unmount when sillyrenames are being terminated. When doing a forced unmount, the sillyrename vnode(s) may be VBAD. Do not attempt to flush the sillyrename in this case. * Fix a bug for 'soft' mounts. Soft failures do not properly set the error code which can lead to a NULL pointer dereference in the rpc processing code. Set the error code to EINTR for soft mounts whos retries have been exceeded. --- diff --git a/sys/vfs/nfs/nfs_socket.c b/sys/vfs/nfs/nfs_socket.c index 8a9950f9e6..adf290dd87 100644 --- a/sys/vfs/nfs/nfs_socket.c +++ b/sys/vfs/nfs/nfs_socket.c @@ -1280,6 +1280,8 @@ nfs_request_try(struct nfsreq *rep) if (nmp->nm_flag & NFSMNT_FORCE) { rep->r_flags |= R_SOFTTERM; rep->r_flags &= ~R_LOCKED; + if (rep->r_info) + rep->r_info->error = EINTR; return (0); } rep->r_flags |= R_NEEDSXMIT; /* in case send lock races us */ @@ -1428,12 +1430,19 @@ nfs_request_processreply(nfsm_info_t info, int error) * tprintf a response. */ if (error == 0 && (req->r_flags & R_TPRINTFMSG)) { - nfs_msg(req->r_td, nmp->nm_mountp->mnt_stat.f_mntfromname, - "is alive again"); + nfs_msg(req->r_td, + nmp->nm_mountp->mnt_stat.f_mntfromname, + "is alive again"); } + + /* + * Assign response and handle any pre-process error. Response + * fields can be NULL if an error is already pending. + */ info->mrep = req->r_mrep; info->md = req->r_md; info->dpos = req->r_dpos; + if (error) { m_freem(req->r_mreq); req->r_mreq = NULL; @@ -1973,6 +1982,8 @@ static void nfs_softterm(struct nfsreq *rep, int islocked) { rep->r_flags |= R_SOFTTERM; + if (rep->r_info) + rep->r_info->error = EINTR; nfs_hardterm(rep, islocked); } @@ -2015,6 +2026,12 @@ nfs_hardterm(struct nfsreq *rep, int islocked) TAILQ_INSERT_TAIL(&nmp->nm_reqrxq, rep, r_chain); KKASSERT(rep->r_info->state == NFSM_STATE_TRY || rep->r_info->state == NFSM_STATE_WAITREPLY); + + /* + * When setting the state to PROCESSREPLY we must + * roll-up any error not related to the contents of + * the reply (i.e. if there is no contents). + */ rep->r_info->state = NFSM_STATE_PROCESSREPLY; nfssvc_iod_reader_wakeup(nmp); if (TAILQ_FIRST(&nmp->nm_bioq) && diff --git a/sys/vfs/nfs/nfs_vnops.c b/sys/vfs/nfs/nfs_vnops.c index 64f891c726..d91c32ffcc 100644 --- a/sys/vfs/nfs/nfs_vnops.c +++ b/sys/vfs/nfs/nfs_vnops.c @@ -1838,10 +1838,14 @@ nfs_remove(struct vop_old_remove_args *ap) /* * nfs file remove rpc called from nfs_inactive + * + * NOTE: s_dvp can be VBAD during a forced unmount. */ int nfs_removeit(struct sillyrename *sp) { + if (sp->s_dvp->v_type == VBAD) + return(0); return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred, NULL)); }