kernel - Fix two NFS crashes
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 18 Jul 2014 03:54:42 +0000 (20:54 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 18 Jul 2014 03:54:42 +0000 (20:54 -0700)
* 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.

sys/vfs/nfs/nfs_socket.c
sys/vfs/nfs/nfs_vnops.c

index 8a9950f..adf290d 100644 (file)
@@ -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) &&
index 64f891c..d91c32f 100644 (file)
@@ -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));
 }