]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/nfs/nfs_socket.c
xnu-2422.90.20.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_socket.c
index 71b6e5c447a228f104cfaab97cf3950e7cf6a5ce..c163bfa04e395f1381d3199e1132d6e29dbfa07b 100644 (file)
 #include <nfs/nfsmount.h>
 #include <nfs/nfsnode.h>
 
+#define NFS_SOCK_DBG(...) NFS_DBG(NFS_FAC_SOCK, 7, ## __VA_ARGS__)
+
 /* XXX */
 boolean_t      current_thread_aborted(void);
 kern_return_t  thread_terminate(thread_t);
@@ -145,6 +147,12 @@ nfs_sockaddr_cmp(struct sockaddr *sa1, struct sockaddr *sa2)
 
 #if NFSCLIENT
 
+int    nfs_connect_search_new_socket(struct nfsmount *, struct nfs_socket_search *, struct timeval *);
+int    nfs_connect_search_socket_connect(struct nfsmount *, struct nfs_socket *, int);
+int    nfs_connect_search_ping(struct nfsmount *, struct nfs_socket *, struct timeval *);
+void   nfs_connect_search_socket_found(struct nfsmount *, struct nfs_socket_search *, struct nfs_socket *);
+void   nfs_connect_search_socket_reap(struct nfsmount *, struct nfs_socket_search *, struct timeval *);
+int    nfs_connect_search_check(struct nfsmount *, struct nfs_socket_search *, struct timeval *);
 int    nfs_reconnect(struct nfsmount *);
 int    nfs_connect_setup(struct nfsmount *);
 void   nfs_mount_sock_thread(void *, wait_result_t);
@@ -157,12 +165,9 @@ void       nfs_reqbusy(struct nfsreq *);
 struct nfsreq *nfs_reqnext(struct nfsreq *);
 int    nfs_wait_reply(struct nfsreq *);
 void   nfs_softterm(struct nfsreq *);
-
-#ifdef NFS_SOCKET_DEBUGGING
-#define NFS_SOCK_DBG(X)        printf X
-#else
-#define NFS_SOCK_DBG(X)
-#endif
+int    nfs_can_squish(struct nfsmount *);
+int    nfs_is_squishy(struct nfsmount *);
+int    nfs_is_dead(int, struct nfsmount *);
 
 /*
  * Estimate rto for an nfs rpc sent via. an unreliable datagram.
@@ -313,18 +318,18 @@ nfs_connect_upcall(socket_t so, void *arg, __unused int waitflag)
        int error = 0, recv = 1;
 
        if (nso->nso_flags & NSO_CONNECTING) {
-               NFS_SOCK_DBG(("nfs connect - socket %p upcall - connecting\n", nso));
+               NFS_SOCK_DBG("nfs connect - socket %p upcall - connecting\n", nso);
                wakeup(nso->nso_wake);
                return;
        }
 
        lck_mtx_lock(&nso->nso_lock);
        if ((nso->nso_flags & (NSO_UPCALL|NSO_DISCONNECTING|NSO_DEAD)) || !(nso->nso_flags & NSO_PINGING)) {
-               NFS_SOCK_DBG(("nfs connect - socket %p upcall - nevermind\n", nso));
+               NFS_SOCK_DBG("nfs connect - socket %p upcall - nevermind\n", nso);
                lck_mtx_unlock(&nso->nso_lock);
                return;
        }
-       NFS_SOCK_DBG(("nfs connect - socket %p upcall\n", nso));
+       NFS_SOCK_DBG("nfs connect - socket %p upcall\n", nso);
        nso->nso_flags |= NSO_UPCALL;
 
        /* loop while we make error-free progress */
@@ -473,6 +478,8 @@ nfs_socket_create(
                sinaddr = &((struct sockaddr_in6*)sa)->sin6_addr;
        if (inet_ntop(sa->sa_family, sinaddr, naddr, sizeof(naddr)) != naddr)
                strlcpy(naddr, "<unknown>", sizeof(naddr));
+#else
+       char naddr[1] =  { 0 };
 #endif
 
        *nsop = NULL;
@@ -528,14 +535,14 @@ nfs_socket_create(
        }
 
        if (error) {
-               NFS_SOCK_DBG(("nfs connect %s error %d creating socket %p %s type %d%s port %d prot %d %d\n",
+               NFS_SOCK_DBG("nfs connect %s error %d creating socket %p %s type %d%s port %d prot %d %d\n",
                        vfs_statfs(nmp->nm_mountp)->f_mntfromname, error, nso, naddr, sotype,
-                       resvport ? "r" : "", port, protocol, vers));
+                       resvport ? "r" : "", port, protocol, vers);
                nfs_socket_destroy(nso);
        } else {
-               NFS_SOCK_DBG(("nfs connect %s created socket %p %s type %d%s port %d prot %d %d\n",
+               NFS_SOCK_DBG("nfs connect %s created socket %p %s type %d%s port %d prot %d %d\n",
                        vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, naddr,
-                       sotype, resvport ? "r" : "", port, protocol, vers));
+                       sotype, resvport ? "r" : "", port, protocol, vers);
                *nsop = nso;
        }
        return (error);
@@ -563,7 +570,7 @@ nfs_socket_destroy(struct nfs_socket *nso)
                FREE(nso->nso_saddr, M_SONAME);
        if (nso->nso_saddr2)
                FREE(nso->nso_saddr2, M_SONAME);
-       NFS_SOCK_DBG(("nfs connect - socket %p destroyed\n", nso));
+       NFS_SOCK_DBG("nfs connect - socket %p destroyed\n", nso);
        FREE(nso, M_TEMP);
 }
 
@@ -584,7 +591,7 @@ nfs_socket_options(struct nfsmount *nmp, struct nfs_socket *nso)
        int on = 1, proto;
 
        timeo.tv_usec = 0;
-       timeo.tv_sec = NMFLAG(nmp, SOFT) ? 5 : 60;
+       timeo.tv_sec = (NMFLAG(nmp, SOFT) || nfs_can_squish(nmp)) ? 5 : 60;
        sock_setsockopt(nso->nso_so, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
        sock_setsockopt(nso->nso_so, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo));
        if (nso->nso_sotype == SOCK_STREAM) {
@@ -677,50 +684,52 @@ nfs_socket_search_update_error(struct nfs_socket_search *nss, int error)
                nss->nss_error = error;
 }
 
-/*
- * Continue the socket search until we have something to report.
+/* nfs_connect_search_new_socket:
+ *     Given a socket search structure for an nfs mount try to find a new socket from the set of addresses specified
+ *     by nss.
+ *
+ *     nss_last is set to -1 at initialization to indicate the first time. Its set to -2 if address was found but
+ *     could not be used or if a socket timed out.
  */
 int
-nfs_connect_search_loop(struct nfsmount *nmp, struct nfs_socket_search *nss)
+nfs_connect_search_new_socket(struct nfsmount *nmp, struct nfs_socket_search *nss, struct timeval *now)
 {
-       struct nfs_socket *nso, *nsonext;
-       struct timeval now;
        struct nfs_fs_location *fsl;
        struct nfs_fs_server *fss;
        struct sockaddr_storage ss;
+       struct nfs_socket *nso;
        char *addrstr;
-       int error, nomore = 0;
+       int error = 0;
+       
 
-loop:
-       microuptime(&now);
-       NFS_SOCK_DBG(("nfs connect %s search %ld\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname, now.tv_sec));
+       NFS_SOCK_DBG("nfs connect %s nss_addrcnt = %d\n",
+                             vfs_statfs(nmp->nm_mountp)->f_mntfromname, nss->nss_addrcnt);
 
-       /* Time to start another socket? */
-       while ((nss->nss_last < 0) || (nss->nss_sockcnt == 0) ||
-              ((nss->nss_sockcnt < 4) && (now.tv_sec >= (nss->nss_last + 2)))) {
+       /*
+        * while there are addresses and:
+        *      we have no sockets or
+        *      the last address failed and did not produce a socket (nss_last < 0) or
+        *      Its been a while (2 seconds) and we have less than the max number of concurrent sockets to search (4)
+        *      then attempt to create a socket with the current address.
+        */
+       while (nss->nss_addrcnt > 0 && ((nss->nss_last < 0) || (nss->nss_sockcnt == 0) ||
+                                   ((nss->nss_sockcnt < 4) && (now->tv_sec >= (nss->nss_last + 2))))) {
                if (nmp->nm_sockflags & NMSOCK_UNMOUNT)
                        return (EINTR);
-               /* Find the next address to try... */
-               /* Have we run out of locations? */
-               if (!nomore && (nss->nss_last != -1) && !nfs_location_index_cmp(&nss->nss_nextloc, &nss->nss_startloc))
-                       nomore = 1;
-               if (nomore) {
-                       if (nss->nss_last < 0)
-                               nss->nss_last = now.tv_sec;
-                       break;
-               }
                /* Can we convert the address to a sockaddr? */
                fsl = nmp->nm_locations.nl_locations[nss->nss_nextloc.nli_loc];
                fss = fsl->nl_servers[nss->nss_nextloc.nli_serv];
                addrstr = fss->ns_addresses[nss->nss_nextloc.nli_addr];
                if (!nfs_uaddr2sockaddr(addrstr, (struct sockaddr*)&ss)) {
                        nfs_location_next(&nmp->nm_locations, &nss->nss_nextloc);
+                       nss->nss_addrcnt -= 1;
                        nss->nss_last = -2;
                        continue;
                }
                /* Check that socket family is acceptable. */
                if (nmp->nm_sofamily && (ss.ss_family != nmp->nm_sofamily)) {
                        nfs_location_next(&nmp->nm_locations, &nss->nss_nextloc);
+                       nss->nss_addrcnt -= 1;
                        nss->nss_last = -2;
                        continue;
                }
@@ -745,136 +754,166 @@ loop:
                TAILQ_INSERT_TAIL(&nss->nss_socklist, nso, nso_link);
                nss->nss_sockcnt++;
                nfs_location_next(&nmp->nm_locations, &nss->nss_nextloc);
-
-               nss->nss_last = now.tv_sec;
+               nss->nss_addrcnt -= 1;
+               
+               nss->nss_last = now->tv_sec;
        }
 
-       /* check each active socket and try to push it along */
-       TAILQ_FOREACH(nso, &nss->nss_socklist, nso_link) {
+       if (nss->nss_addrcnt == 0 && nss->nss_last < 0)
+               nss->nss_last = now->tv_sec;
+       
+       return (error);
+}
+
+/*
+ * nfs_connect_search_socket_connect:  Connect an nfs socket nso for nfsmount nmp.
+ *                                     If successful set the socket options for the socket as require from the mount.
+ *
+ * Assumes:                            nso->nso_lock is held on entry and return.
+ */
+int
+nfs_connect_search_socket_connect(struct nfsmount *nmp, struct nfs_socket *nso, int verbose)
+{
+       int error;
+       
+       if ((nso->nso_sotype != SOCK_STREAM) && NMFLAG(nmp, NOCONNECT)) {
+               /* no connection needed, just say it's already connected */
+               NFS_SOCK_DBG("nfs connect %s UDP socket %p noconnect\n",
+                             vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso);
+               nso->nso_flags |= NSO_CONNECTED;
+               nfs_socket_options(nmp, nso);
+               return (1);   /* Socket is connected and setup */
+       } else if (!(nso->nso_flags & NSO_CONNECTING)) {
+               /* initiate the connection */
+               nso->nso_flags |= NSO_CONNECTING;
+               lck_mtx_unlock(&nso->nso_lock);
+               NFS_SOCK_DBG("nfs connect %s connecting socket %p\n",
+                             vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso);
+               error = sock_connect(nso->nso_so, nso->nso_saddr, MSG_DONTWAIT);
                lck_mtx_lock(&nso->nso_lock);
-               if (!(nso->nso_flags & NSO_CONNECTED)) {
-                       if ((nso->nso_sotype != SOCK_STREAM) && NMFLAG(nmp, NOCONNECT)) {
-                               /* no connection needed, just say it's already connected */
-                               nso->nso_flags |= NSO_CONNECTED;
-                               NFS_SOCK_DBG(("nfs connect %s UDP socket %p noconnect\n",
-                                       vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso));
-                       } else if (!(nso->nso_flags & NSO_CONNECTING)) {
-                               /* initiate the connection */
-                               nso->nso_flags |= NSO_CONNECTING;
-                               lck_mtx_unlock(&nso->nso_lock);
-                               NFS_SOCK_DBG(("nfs connect %s connecting socket %p\n",
-                                       vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso));
-                               error = sock_connect(nso->nso_so, nso->nso_saddr, MSG_DONTWAIT);
-                               lck_mtx_lock(&nso->nso_lock);
-                               if (error && (error != EINPROGRESS)) {
-                                       nso->nso_error = error;
-                                       nso->nso_flags |= NSO_DEAD;
-                                       lck_mtx_unlock(&nso->nso_lock);
-                                       continue;
-                               }
-                       }
-                       if (nso->nso_flags & NSO_CONNECTING) {
-                               /* check the connection */
-                               if (sock_isconnected(nso->nso_so)) {
-                                       NFS_SOCK_DBG(("nfs connect %s socket %p is connected\n",
-                                               vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso));
-                                       nso->nso_flags &= ~NSO_CONNECTING;
-                                       nso->nso_flags |= NSO_CONNECTED;
-                               } else {
-                                       int optlen = sizeof(error);
-                                       error = 0;
-                                       sock_getsockopt(nso->nso_so, SOL_SOCKET, SO_ERROR, &error, &optlen);
-                                       if (error) { /* we got an error on the socket */
-                                               NFS_SOCK_DBG(("nfs connect %s socket %p connection error %d\n",
-                                                       vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, error));
-                                               if (nss->nss_flags & NSS_VERBOSE)
-                                                       log(LOG_INFO, "nfs_connect: socket error %d for %s\n",
-                                                               error, vfs_statfs(nmp->nm_mountp)->f_mntfromname);
-                                               nso->nso_error = error;
-                                               nso->nso_flags |= NSO_DEAD;
-                                               lck_mtx_unlock(&nso->nso_lock);
-                                               continue;
-                                       }
-                               }
-                       }
-                       if (nso->nso_flags & NSO_CONNECTED)
-                               nfs_socket_options(nmp, nso);
-               }
-               if (!(nso->nso_flags & NSO_CONNECTED)) {
-                       lck_mtx_unlock(&nso->nso_lock);
-                       continue;
+               if (error && (error != EINPROGRESS)) {
+                       nso->nso_error = error;
+                       nso->nso_flags |= NSO_DEAD;
+                       return (0);
                }
-               if (!(nso->nso_flags & (NSO_PINGING|NSO_VERIFIED)) ||
-                   ((nso->nso_sotype == SOCK_DGRAM) && (now.tv_sec >= nso->nso_reqtimestamp+2))) {
-                       /* initiate a NULL RPC request */
-                       uint64_t xid = nso->nso_pingxid;
-                       mbuf_t m, mreq = NULL;
-                       struct msghdr msg;
-                       size_t reqlen, sentlen;
-                       uint32_t vers;
-
-                       if (!(vers = nso->nso_version)) {
-                               if (nso->nso_protocol == PMAPPROG)
-                                       vers = (nso->nso_saddr->sa_family == AF_INET) ? PMAPVERS : RPCBVERS4;
-                               else if (nso->nso_protocol == NFS_PROG)
-                                       vers = NFS_VER3;
-                       }
-                       lck_mtx_unlock(&nso->nso_lock);
-                       error = nfsm_rpchead2(nmp, nso->nso_sotype, nso->nso_protocol, vers, 0, RPCAUTH_SYS,
-                                       vfs_context_ucred(vfs_context_kernel()), NULL, NULL, &xid, &mreq);
-                       lck_mtx_lock(&nso->nso_lock);
-                       if (!error) {
-                               nso->nso_flags |= NSO_PINGING;
-                               nso->nso_pingxid = R_XID32(xid);
-                               nso->nso_reqtimestamp = now.tv_sec;
-                               bzero(&msg, sizeof(msg));
-                               if ((nso->nso_sotype != SOCK_STREAM) && !sock_isconnected(nso->nso_so)) {
-                                       msg.msg_name = nso->nso_saddr;
-                                       msg.msg_namelen = nso->nso_saddr->sa_len;
-                               }
-                               for (reqlen=0, m=mreq; m; m = mbuf_next(m))
-                                       reqlen += mbuf_len(m);
-                               lck_mtx_unlock(&nso->nso_lock);
-                               error = sock_sendmbuf(nso->nso_so, &msg, mreq, 0, &sentlen);
-                               NFS_SOCK_DBG(("nfs connect %s verifying socket %p send rv %d\n",
-                                       vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, error));
-                               lck_mtx_lock(&nso->nso_lock);
-                               if (!error && (sentlen != reqlen))
-                                       error = ETIMEDOUT;
-                       }
-                       if (error) {
+       }
+       if (nso->nso_flags & NSO_CONNECTING) {
+               /* check the connection */
+               if (sock_isconnected(nso->nso_so)) {
+                       NFS_SOCK_DBG("nfs connect %s socket %p is connected\n",
+                                     vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso);
+                       nso->nso_flags &= ~NSO_CONNECTING;
+                       nso->nso_flags |= NSO_CONNECTED;
+                       nfs_socket_options(nmp, nso);
+                       return (1);   /* Socket is connected and setup */
+               } else {
+                       int optlen = sizeof(error);
+                       error = 0;
+                       sock_getsockopt(nso->nso_so, SOL_SOCKET, SO_ERROR, &error, &optlen);
+                       if (error) { /* we got an error on the socket */
+                               NFS_SOCK_DBG("nfs connect %s socket %p connection error %d\n",
+                                             vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, error);
+                               if (verbose)
+                                       printf("nfs connect socket error %d for %s\n",
+                                           error, vfs_statfs(nmp->nm_mountp)->f_mntfromname);
                                nso->nso_error = error;
                                nso->nso_flags |= NSO_DEAD;
-                               lck_mtx_unlock(&nso->nso_lock);
-                               continue;
+                               return (0);
                        }
                }
-               if (nso->nso_flags & NSO_VERIFIED) {
-                       /* WOOHOO!! This socket looks good! */
-                       NFS_SOCK_DBG(("nfs connect %s socket %p verified\n",
-                               vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso));
-                       if (!nso->nso_version) {
-                               /* If the version isn't set, the default must have worked. */
-                               if (nso->nso_protocol == PMAPPROG)
-                                       nso->nso_version = (nso->nso_saddr->sa_family == AF_INET) ? PMAPVERS : RPCBVERS4;
-                               if (nso->nso_protocol == NFS_PROG)
-                                       nso->nso_version = NFS_VER3;
-                       }
-                       lck_mtx_unlock(&nso->nso_lock);
-                       TAILQ_REMOVE(&nss->nss_socklist, nso, nso_link);
-                       nss->nss_sockcnt--;
-                       nss->nss_sock = nso;
-                       break;
+       }
+       
+       return (0);  /* Waiting to be connected */
+}
+
+/*
+ * nfs_connect_search_ping:    Send a null proc on the nso socket.
+ */
+int
+nfs_connect_search_ping(struct nfsmount *nmp, struct nfs_socket *nso, struct timeval *now)
+{
+       /* initiate a NULL RPC request */
+       uint64_t xid = nso->nso_pingxid;
+       mbuf_t m, mreq = NULL;
+       struct msghdr msg;
+       size_t reqlen, sentlen;
+       uint32_t vers = nso->nso_version;
+       int error;
+
+       if (!vers) {
+               if (nso->nso_protocol == PMAPPROG)
+                       vers = (nso->nso_saddr->sa_family == AF_INET) ? PMAPVERS : RPCBVERS4;
+               else if (nso->nso_protocol == NFS_PROG)
+                       vers = NFS_VER3;
+       }
+       lck_mtx_unlock(&nso->nso_lock);
+       error = nfsm_rpchead2(nmp, nso->nso_sotype, nso->nso_protocol, vers, 0, RPCAUTH_SYS,
+                             vfs_context_ucred(vfs_context_kernel()), NULL, NULL, &xid, &mreq);
+       lck_mtx_lock(&nso->nso_lock);
+       if (!error) {
+               nso->nso_flags |= NSO_PINGING;
+               nso->nso_pingxid = R_XID32(xid);
+               nso->nso_reqtimestamp = now->tv_sec;
+               bzero(&msg, sizeof(msg));
+               if ((nso->nso_sotype != SOCK_STREAM) && !sock_isconnected(nso->nso_so)) {
+                       msg.msg_name = nso->nso_saddr;
+                       msg.msg_namelen = nso->nso_saddr->sa_len;
                }
+               for (reqlen=0, m=mreq; m; m = mbuf_next(m))
+                       reqlen += mbuf_len(m);
                lck_mtx_unlock(&nso->nso_lock);
+               error = sock_sendmbuf(nso->nso_so, &msg, mreq, 0, &sentlen);
+               NFS_SOCK_DBG("nfs connect %s verifying socket %p send rv %d\n",
+                             vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, error);
+               lck_mtx_lock(&nso->nso_lock);
+               if (!error && (sentlen != reqlen))
+                       error = ETIMEDOUT;
        }
+       if (error) {
+               nso->nso_error = error;
+               nso->nso_flags |= NSO_DEAD;
+               return (0);
+       }
+
+       return (1);
+}
+
+/*
+ * nfs_connect_search_socket_found:    Take the found socket of the socket search list and assign it to the searched socket.
+ *                                     Set the nfs socket protocol and version if needed. 
+ */
+void
+nfs_connect_search_socket_found(struct nfsmount *nmp __unused, struct nfs_socket_search *nss, struct nfs_socket *nso)
+{
+       NFS_SOCK_DBG("nfs connect %s socket %p verified\n",
+                     vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso);
+       if (!nso->nso_version) {
+               /* If the version isn't set, the default must have worked. */
+               if (nso->nso_protocol == PMAPPROG)
+                       nso->nso_version = (nso->nso_saddr->sa_family == AF_INET) ? PMAPVERS : RPCBVERS4;
+               if (nso->nso_protocol == NFS_PROG)
+                       nso->nso_version = NFS_VER3;
+       }
+       TAILQ_REMOVE(&nss->nss_socklist, nso, nso_link);
+       nss->nss_sockcnt--;
+       nss->nss_sock = nso;
+}
 
+/*
+ * nfs_connect_search_socket_reap:     For each socket in the search list mark any timed out socket as dead and remove from
+ *                                     the list. Dead socket are then destroyed.
+ */
+void
+nfs_connect_search_socket_reap(struct nfsmount *nmp __unused, struct nfs_socket_search *nss, struct timeval *now)
+{
+       struct nfs_socket *nso, *nsonext;
+       
        TAILQ_FOREACH_SAFE(nso, &nss->nss_socklist, nso_link, nsonext) {
                lck_mtx_lock(&nso->nso_lock);
-               if (now.tv_sec >= (nso->nso_timestamp + nss->nss_timeo)) {
+               if (now->tv_sec >= (nso->nso_timestamp + nss->nss_timeo)) {
                        /* took too long */
-                       NFS_SOCK_DBG(("nfs connect %s socket %p timed out\n",
-                               vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso));
+                       NFS_SOCK_DBG("nfs connect %s socket %p timed out\n",
+                               vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso);
                        nso->nso_error = ETIMEDOUT;
                        nso->nso_flags |= NSO_DEAD;
                }
@@ -883,38 +922,112 @@ loop:
                        continue;
                }
                lck_mtx_unlock(&nso->nso_lock);
-               NFS_SOCK_DBG(("nfs connect %s reaping socket %p %d\n",
-                       vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, nso->nso_error));
+               NFS_SOCK_DBG("nfs connect %s reaping socket %p %d\n",
+                       vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, nso->nso_error);
                nfs_socket_search_update_error(nss, nso->nso_error);
                TAILQ_REMOVE(&nss->nss_socklist, nso, nso_link);
                nss->nss_sockcnt--;
                nfs_socket_destroy(nso);
-               if (!nomore)
+               /* If there are more sockets to try, force the starting of another socket */
+               if (nss->nss_addrcnt > 0)
                        nss->nss_last = -2;
        }
+}
+
+/*
+ * nfs_connect_search_check:   Check on the status of search and wait for replies if needed.
+ */
+int
+nfs_connect_search_check(struct nfsmount *nmp, struct nfs_socket_search *nss, struct timeval *now)
+{
+       int error;
+
+       /* log a warning if connect is taking a while */
+       if (((now->tv_sec - nss->nss_timestamp) >= 8) && ((nss->nss_flags & (NSS_VERBOSE|NSS_WARNED)) == NSS_VERBOSE)) {
+               printf("nfs_connect: socket connect taking a while for %s\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname);
+               nss->nss_flags |= NSS_WARNED;
+       }
+       if (nmp->nm_sockflags & NMSOCK_UNMOUNT)
+               return (EINTR);
+       if ((error = nfs_sigintr(nmp, NULL, current_thread(), 0)))
+               return (error);
+
+       /* If we were succesfull at sending a ping, wait up to a second for a reply  */
+       if (nss->nss_last >= 0)
+               tsleep(nss, PSOCK, "nfs_connect_search_wait", hz);
+       
+       return (0);
+}
+
+
+/*
+ * Continue the socket search until we have something to report.
+ */
+int
+nfs_connect_search_loop(struct nfsmount *nmp, struct nfs_socket_search *nss)
+{
+       struct nfs_socket *nso;
+       struct timeval now;
+       int error;
+       int verbose = (nss->nss_flags & NSS_VERBOSE);
+       
+loop:
+       microuptime(&now);
+       NFS_SOCK_DBG("nfs connect %s search %ld\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname, now.tv_sec);
+
+       /* add a new socket to the socket list if needed and available */
+       error = nfs_connect_search_new_socket(nmp, nss, &now);
+       if (error) {
+               NFS_SOCK_DBG("nfs connect returned %d\n", error);
+               return (error);
+       }
+       
+       /* check each active socket on the list and try to push it along */
+       TAILQ_FOREACH(nso, &nss->nss_socklist, nso_link) {
+               lck_mtx_lock(&nso->nso_lock);
+
+               /* If not connected connect it */
+               if (!(nso->nso_flags & NSO_CONNECTED)) {
+                       if (!nfs_connect_search_socket_connect(nmp, nso, verbose)) {
+                               lck_mtx_unlock(&nso->nso_lock);
+                               continue;
+                       }
+               }
 
+               /* If the socket hasn't been verified or in a ping, ping it. We also handle UDP retransmits */
+               if (!(nso->nso_flags & (NSO_PINGING|NSO_VERIFIED)) ||
+                   ((nso->nso_sotype == SOCK_DGRAM) && (now.tv_sec >= nso->nso_reqtimestamp+2))) {
+                       if (!nfs_connect_search_ping(nmp, nso, &now)) {
+                               lck_mtx_unlock(&nso->nso_lock);
+                               continue;
+                       }
+               }
+
+               /* Has the socket been verified by the up call routine? */
+               if (nso->nso_flags & NSO_VERIFIED) {
+                       /* WOOHOO!! This socket looks good! */
+                       nfs_connect_search_socket_found(nmp, nss, nso);
+                       lck_mtx_unlock(&nso->nso_lock);
+                       break;
+               }
+               lck_mtx_unlock(&nso->nso_lock);
+       }
+       
+       /* Check for timed out sockets and mark as dead and then remove all dead sockets. */
+       nfs_connect_search_socket_reap(nmp, nss, &now);
+       
        /*
         * Keep looping if we haven't found a socket yet and we have more
         * sockets to (continue to) try.
         */
        error = 0;
-       if (!nss->nss_sock && (!TAILQ_EMPTY(&nss->nss_socklist) || !nomore)) {
-               /* log a warning if connect is taking a while */
-               if (((now.tv_sec - nss->nss_timestamp) >= 30) && ((nss->nss_flags & (NSS_VERBOSE|NSS_WARNED)) == NSS_VERBOSE)) {
-                       log(LOG_INFO, "nfs_connect: socket connect taking a while for %s\n",
-                               vfs_statfs(nmp->nm_mountp)->f_mntfromname);
-                       nss->nss_flags |= NSS_WARNED;
-               }
-               if (nmp->nm_sockflags & NMSOCK_UNMOUNT)
-                       return (EINTR);
-               if ((error = nfs_sigintr(nmp, NULL, current_thread(), 0)))
-                       return (error);
-               if (nss->nss_last >= 0)
-                       tsleep(nss, PSOCK, "nfs_connect_search_wait", hz);
-               goto loop;
+       if (!nss->nss_sock && (!TAILQ_EMPTY(&nss->nss_socklist) || nss->nss_addrcnt)) {
+               error = nfs_connect_search_check(nmp, nss, &now);
+               if (!error)
+                       goto loop;
        }
 
-       NFS_SOCK_DBG(("nfs connect %s returning %d\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname, error));
+       NFS_SOCK_DBG("nfs connect %s returning %d\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname, error);
        return (error);
 }
 
@@ -947,25 +1060,27 @@ nfs_connect(struct nfsmount *nmp, int verbose, int timeo)
        fhandle_t *fh = NULL;
        char *path = NULL;
        in_port_t port;
-
+       int addrtotal = 0;
+       
        /* paranoia... check that we have at least one address in the locations */
        uint32_t loc, serv;
        for (loc=0; loc < nmp->nm_locations.nl_numlocs; loc++) {
                for (serv=0; serv < nmp->nm_locations.nl_locations[loc]->nl_servcount; serv++) {
-                       if (nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_addrcount)
-                               break;
-                       NFS_SOCK_DBG(("nfs connect %s search, server %s has no addresses\n",
-                               vfs_statfs(nmp->nm_mountp)->f_mntfromname,
-                               nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_name));
+                       addrtotal += nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_addrcount;
+                       if (nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_addrcount == 0)
+                               NFS_SOCK_DBG("nfs connect %s search, server %s has no addresses\n",
+                                             vfs_statfs(nmp->nm_mountp)->f_mntfromname,
+                                             nmp->nm_locations.nl_locations[loc]->nl_servers[serv]->ns_name);
                }
-               if (serv < nmp->nm_locations.nl_locations[loc]->nl_servcount)
-                       break;
        }
-       if (loc >= nmp->nm_locations.nl_numlocs) {
-               NFS_SOCK_DBG(("nfs connect %s search failed, no addresses\n",
-                       vfs_statfs(nmp->nm_mountp)->f_mntfromname));
+
+       if (addrtotal == 0) {
+               NFS_SOCK_DBG("nfs connect %s search failed, no addresses\n",
+                       vfs_statfs(nmp->nm_mountp)->f_mntfromname);
                return (EINVAL);
-       }
+       } else 
+               NFS_SOCK_DBG("nfs connect %s has %d addresses\n",
+                             vfs_statfs(nmp->nm_mountp)->f_mntfromname, addrtotal);
 
        lck_mtx_lock(&nmp->nm_lock);
        nmp->nm_sockflags |= NMSOCK_CONNECTING;
@@ -977,6 +1092,7 @@ nfs_connect(struct nfsmount *nmp, int verbose, int timeo)
 tryagain:
        /* initialize socket search state */
        bzero(&nss, sizeof(nss));
+       nss.nss_addrcnt = addrtotal;
        nss.nss_error = savederror;
        TAILQ_INIT(&nss.nss_socklist);
        nss.nss_sotype = sotype;
@@ -1020,9 +1136,9 @@ tryagain:
                                nss.nss_version = nmp->nm_vers;
                        }
                }
-               NFS_SOCK_DBG(("nfs connect first %s, so type %d port %d prot %d %d\n",
+               NFS_SOCK_DBG("nfs connect first %s, so type %d port %d prot %d %d\n",
                        vfs_statfs(nmp->nm_mountp)->f_mntfromname, nss.nss_sotype, nss.nss_port,
-                       nss.nss_protocol, nss.nss_version));
+                       nss.nss_protocol, nss.nss_version);
        } else {
                /* we've connected before, just connect to NFS port */
                if (!nmp->nm_nfsport) {
@@ -1035,9 +1151,9 @@ tryagain:
                        nss.nss_protocol = NFS_PROG;
                        nss.nss_version = nmp->nm_vers;
                }
-               NFS_SOCK_DBG(("nfs connect %s, so type %d port %d prot %d %d\n",
+               NFS_SOCK_DBG("nfs connect %s, so type %d port %d prot %d %d\n",
                        vfs_statfs(nmp->nm_mountp)->f_mntfromname, nss.nss_sotype, nss.nss_port,
-                       nss.nss_protocol, nss.nss_version));
+                       nss.nss_protocol, nss.nss_version);
        }
 
        /* Set next location to first valid location. */
@@ -1047,8 +1163,8 @@ tryagain:
            (nss.nss_nextloc.nli_addr >= nmp->nm_locations.nl_locations[nss.nss_nextloc.nli_loc]->nl_servers[nss.nss_nextloc.nli_serv]->ns_addrcount)) {
                nfs_location_next(&nmp->nm_locations, &nss.nss_nextloc);
                if (!nfs_location_index_cmp(&nss.nss_nextloc, &nss.nss_startloc)) {
-                       NFS_SOCK_DBG(("nfs connect %s search failed, couldn't find a valid location index\n",
-                               vfs_statfs(nmp->nm_mountp)->f_mntfromname));
+                       NFS_SOCK_DBG("nfs connect %s search failed, couldn't find a valid location index\n",
+                               vfs_statfs(nmp->nm_mountp)->f_mntfromname);
                        return (ENOENT);
                }
        }
@@ -1064,8 +1180,8 @@ keepsearching:
                        /* Try using UDP */
                        sotype = SOCK_DGRAM;
                        savederror = nss.nss_error;
-                       NFS_SOCK_DBG(("nfs connect %s TCP failed %d %d, trying UDP\n",
-                               vfs_statfs(nmp->nm_mountp)->f_mntfromname, error, nss.nss_error));
+                       NFS_SOCK_DBG("nfs connect %s TCP failed %d %d, trying UDP\n",
+                               vfs_statfs(nmp->nm_mountp)->f_mntfromname, error, nss.nss_error);
                        goto tryagain;
                }
                if (!error)
@@ -1081,8 +1197,8 @@ keepsearching:
                        FREE(fh, M_TEMP);
                if (path)
                        FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
-               NFS_SOCK_DBG(("nfs connect %s search failed, returning %d\n",
-                       vfs_statfs(nmp->nm_mountp)->f_mntfromname, error));
+               NFS_SOCK_DBG("nfs connect %s search failed, returning %d\n",
+                       vfs_statfs(nmp->nm_mountp)->f_mntfromname, error);
                return (error);
        }
 
@@ -1097,8 +1213,8 @@ keepsearching:
                port = ntohs(((struct sockaddr_in6*)nso->nso_saddr)->sin6_port);
        if (port == PMAPPORT) {
                /* Use this portmapper port to get the port #s we need. */
-               NFS_SOCK_DBG(("nfs connect %s got portmapper socket %p\n",
-                       vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso));
+               NFS_SOCK_DBG("nfs connect %s got portmapper socket %p\n",
+                       vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso);
 
                /* remove the connect upcall so nfs_portmap_lookup() can use this socket */
                sock_setupcall(nso->nso_so, NULL, NULL);
@@ -1115,7 +1231,7 @@ keepsearching:
                        else if (ss.ss_family == AF_INET6)
                                ((struct sockaddr_in6*)&ss)->sin6_port = htons(0);
                        error = nfs_portmap_lookup(nmp, vfs_context_current(), (struct sockaddr*)&ss,
-                                       nso->nso_so, NFS_PROG, nfsvers, 
+                                       nso->nso_so, NFS_PROG, nfsvers,
                                        (nso->nso_sotype == SOCK_DGRAM) ? IPPROTO_UDP : IPPROTO_TCP, timeo);
                        if (!error) {
                                if (ss.ss_family == AF_INET)
@@ -1128,7 +1244,7 @@ keepsearching:
                        if (error && !nmp->nm_vers) {
                                nfsvers = NFS_VER2;
                                error = nfs_portmap_lookup(nmp, vfs_context_current(), (struct sockaddr*)&ss,
-                                               nso->nso_so, NFS_PROG, nfsvers, 
+                                               nso->nso_so, NFS_PROG, nfsvers,
                                                (nso->nso_sotype == SOCK_DGRAM) ? IPPROTO_UDP : IPPROTO_TCP, timeo);
                                if (!error) {
                                        if (ss.ss_family == AF_INET)
@@ -1208,7 +1324,7 @@ keepsearching:
        }
 
        /* nso is an NFS socket */
-       NFS_SOCK_DBG(("nfs connect %s got NFS socket %p\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso));
+       NFS_SOCK_DBG("nfs connect %s got NFS socket %p\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso);
 
        /* If NFS version wasn't specified, it was determined during the connect. */
        nfsvers = nmp->nm_vers ? nmp->nm_vers : (int)nso->nso_version;
@@ -1246,7 +1362,7 @@ keepsearching:
                if (saddr)
                        MALLOC(fh, fhandle_t *, sizeof(fhandle_t), M_TEMP, M_WAITOK|M_ZERO);
                if (saddr && fh)
-                       MALLOC_ZONE(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 
+                       MALLOC_ZONE(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
                if (!saddr || !fh || !path) {
                        if (!error)
                                error = ENOMEM;
@@ -1263,8 +1379,8 @@ keepsearching:
                nfs_location_mntfromname(&nmp->nm_locations, nso->nso_location, path, MAXPATHLEN, 1);
                error = nfs3_mount_rpc(nmp, saddr, nso->nso_sotype, nfsvers,
                                path, vfs_context_current(), timeo, fh, &nmp->nm_servsec);
-               NFS_SOCK_DBG(("nfs connect %s socket %p mount %d\n",
-                       vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, error));
+               NFS_SOCK_DBG("nfs connect %s socket %p mount %d\n",
+                       vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, error);
                if (!error) {
                        /* Make sure we can agree on a security flavor. */
                        int o, s;  /* indices into mount option and server security flavor lists */
@@ -1397,8 +1513,8 @@ keepsearching:
                wakeup(&nmp->nm_sockflags);
        }
        if (error) {
-               NFS_SOCK_DBG(("nfs connect %s socket %p setup failed %d\n",
-                       vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, error));
+               NFS_SOCK_DBG("nfs connect %s socket %p setup failed %d\n",
+                       vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, error);
                nfs_socket_search_update_error(&nss, error);
                nmp->nm_saddr = oldsaddr;
                if (!(nmp->nm_sockflags & NMSOCK_HASCONNECTED)) {
@@ -1452,7 +1568,7 @@ keepsearching:
                FREE(fh, M_TEMP);
        if (path)
                FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
-       NFS_SOCK_DBG(("nfs connect %s success\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname));
+       NFS_SOCK_DBG("nfs connect %s success\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname);
        return (0);
 }
 
@@ -1498,13 +1614,19 @@ nfs_reconnect(struct nfsmount *nmp)
        thread_t thd = current_thread();
        int error, wentdown = 0, verbose = 1;
        time_t lastmsg;
+       int timeo;
 
        microuptime(&now);
        lastmsg = now.tv_sec - (nmp->nm_tprintf_delay - nmp->nm_tprintf_initial_delay);
 
        nfs_disconnect(nmp);
 
-       while ((error = nfs_connect(nmp, verbose, 30))) {
+
+       lck_mtx_lock(&nmp->nm_lock);
+       timeo = nfs_is_squishy(nmp) ? 8 : 30;
+       lck_mtx_unlock(&nmp->nm_lock);
+
+       while ((error = nfs_connect(nmp, verbose, timeo))) {
                verbose = 0;
                nfs_disconnect(nmp);
                if ((error == EINTR) || (error == ERESTART))
@@ -1522,6 +1644,7 @@ nfs_reconnect(struct nfsmount *nmp)
                        /* we're not yet completely mounted and */
                        /* we can't reconnect, so we fail */
                        lck_mtx_unlock(&nmp->nm_lock);
+                       NFS_SOCK_DBG("Not mounted returning %d\n", error);
                        return (error);
                }
                nfs_mount_check_dead_timeout(nmp);
@@ -1530,7 +1653,7 @@ nfs_reconnect(struct nfsmount *nmp)
                        return (error);
                }
                lck_mtx_unlock(&nmp->nm_lock);
-               tsleep(&lbolt, PSOCK, "nfs_reconnect_delay", 0);
+               tsleep(nfs_reconnect, PSOCK, "nfs_reconnect_delay", 2*hz);
                if ((error = nfs_sigintr(nmp, NULL, thd, 0)))
                        return (error);
        }
@@ -1645,6 +1768,7 @@ nfs_mount_sock_thread(void *arg, __unused wait_result_t wr)
        struct timeval now;
        int error, dofinish;
        nfsnode_t np;
+       int do_reconnect_sleep = 0;
 
        lck_mtx_lock(&nmp->nm_lock);
 
@@ -1664,9 +1788,26 @@ nfs_mount_sock_thread(void *arg, __unused wait_result_t wr)
                                nmp->nm_reconnect_start = now.tv_sec;
                        }
                        lck_mtx_unlock(&nmp->nm_lock);
-                       NFS_SOCK_DBG(("nfs reconnect %s\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname));
-                       if (nfs_reconnect(nmp) == 0)
+                       NFS_SOCK_DBG("nfs reconnect %s\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname);
+                       /*
+                        * XXX We don't want to call reconnect again right away if returned errors 
+                        * before that may not have blocked. This has caused spamming null procs
+                        * from machines in the pass.
+                        */
+                       if (do_reconnect_sleep)
+                               tsleep(nfs_mount_sock_thread, PSOCK, "nfs_reconnect_sock_thread_delay", hz);
+                       error = nfs_reconnect(nmp);
+                       if (error) {
+                               int lvl = 7;
+                               if (error == EIO || error == EINTR) {
+                                       lvl = (do_reconnect_sleep++ % 600) ? 7 : 0;
+                               }
+                               nfs_printf(NFS_FAC_SOCK, lvl, "nfs reconnect %s: returned %d\n",
+                                          vfs_statfs(nmp->nm_mountp)->f_mntfromname, error);
+                       } else {
                                nmp->nm_reconnect_start = 0;
+                               do_reconnect_sleep = 0;
+                       }
                        lck_mtx_lock(&nmp->nm_lock);
                }
                if ((nmp->nm_sockflags & NMSOCK_READY) &&
@@ -1721,9 +1862,9 @@ nfs_mount_sock_thread(void *arg, __unused wait_result_t wr)
                                        if (error == ENEEDAUTH)
                                                req->r_xid = 0;
                                }
-                               NFS_SOCK_DBG(("nfs async%s restart: p %d x 0x%llx f 0x%x rtt %d\n",
+                               NFS_SOCK_DBG("nfs async%s restart: p %d x 0x%llx f 0x%x rtt %d\n",
                                        nfs_request_using_gss(req) ? " gss" : "", req->r_procnum, req->r_xid,
-                                       req->r_flags, req->r_rtt));
+                                       req->r_flags, req->r_rtt);
                                error = !req->r_nmp ? ENXIO : 0;        /* unmounted? */
                                if (!error)
                                        error = nfs_sigintr(nmp, req, req->r_thread, 0);
@@ -1745,8 +1886,8 @@ nfs_mount_sock_thread(void *arg, __unused wait_result_t wr)
                                error = 0;
                                continue;
                        }
-                       NFS_SOCK_DBG(("nfs async resend: p %d x 0x%llx f 0x%x rtt %d\n",
-                               req->r_procnum, req->r_xid, req->r_flags, req->r_rtt));
+                       NFS_SOCK_DBG("nfs async resend: p %d x 0x%llx f 0x%x rtt %d\n",
+                               req->r_procnum, req->r_xid, req->r_flags, req->r_rtt);
                        error = !req->r_nmp ? ENXIO : 0;        /* unmounted? */
                        if (!error)
                                error = nfs_sigintr(nmp, req, req->r_thread, 0);
@@ -1849,16 +1990,18 @@ nfs_mount_check_dead_timeout(struct nfsmount *nmp)
 {
        struct timeval now;
 
-       if (nmp->nm_deadtimeout <= 0)
-               return;
        if (nmp->nm_deadto_start == 0)
                return;
        if (nmp->nm_state & NFSSTA_DEAD)
                return;
+       nfs_is_squishy(nmp);
+       if (nmp->nm_curdeadtimeout <= 0)
+               return;
        microuptime(&now);
-       if ((now.tv_sec - nmp->nm_deadto_start) < nmp->nm_deadtimeout)
+       if ((now.tv_sec - nmp->nm_deadto_start) < nmp->nm_curdeadtimeout)
                return;
-       printf("nfs server %s: dead\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname);
+       printf("nfs server %s: %sdead\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname,
+              (nmp->nm_curdeadtimeout != nmp->nm_deadtimeout) ? "squished " : "");
        nmp->nm_state |= NFSSTA_DEAD;
        vfs_event_signal(&vfs_statfs(nmp->nm_mountp)->f_fsid, VQ_DEAD, 0);
 }
@@ -2360,7 +2503,7 @@ nfs4_cb_handler(struct nfs_callback_socket *ncbsp, mbuf_t mreq)
                                status = error;
                        else if ((error == ENOBUFS) || (error == ENOMEM))
                                status = NFSERR_RESOURCE;
-                       else 
+                       else
                                status = NFSERR_SERVERFAULT;
                        error = 0;
                        nfsm_chain_null(&nmrep);
@@ -2508,7 +2651,7 @@ nfs4_cb_handler(struct nfs_callback_socket *ncbsp, mbuf_t mreq)
                                status = error;
                        else if ((error == ENOBUFS) || (error == ENOMEM))
                                status = NFSERR_RESOURCE;
-                       else 
+                       else
                                status = NFSERR_SERVERFAULT;
                        error = 0;
                }
@@ -2529,7 +2672,7 @@ nfs4_cb_handler(struct nfs_callback_socket *ncbsp, mbuf_t mreq)
 
 nfsmout:
        if (status == EBADRPC)
-               OSAddAtomic(1, &nfsstats.rpcinvalid);
+               OSAddAtomic64(1, &nfsstats.rpcinvalid);
 
        /* build reply header */
        error = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &mhead);
@@ -2821,7 +2964,7 @@ again:
                        lck_mtx_unlock(&req->r_mtx);
                        return (0);
                }
-               NFS_SOCK_DBG(("nfs_send: 0x%llx wait reconnect\n", req->r_xid));
+               NFS_SOCK_DBG("nfs_send: 0x%llx wait reconnect\n", req->r_xid);
                lck_mtx_lock(&req->r_mtx);
                req->r_flags &= ~R_MUSTRESEND;
                req->r_rtt = 0;
@@ -2838,7 +2981,7 @@ again:
                                microuptime(&now);
                                if ((now.tv_sec - nmp->nm_reconnect_start) >= 8) {
                                        /* soft mount in reconnect for a while... terminate ASAP */
-                                       OSAddAtomic(1, &nfsstats.rpctimeouts);
+                                       OSAddAtomic64(1, &nfsstats.rpctimeouts);
                                        req->r_flags |= R_SOFTTERM;
                                        req->r_error = error = ETIMEDOUT;
                                        break;
@@ -2918,7 +3061,7 @@ again:
                } else {
                        /*
                         * When retransmitting, turn timing off
-                        * and divide congestion window by 2. 
+                        * and divide congestion window by 2.
                         */
                        req->r_flags &= ~R_TIMING;
                        nmp->nm_cwnd >>= 1;
@@ -2953,8 +3096,8 @@ again:
        error = sock_sendmbuf(nso->nso_so, &msg, mreqcopy, 0, &sentlen);
 #ifdef NFS_SOCKET_DEBUGGING
        if (error || (sentlen != req->r_mreqlen))
-               NFS_SOCK_DBG(("nfs_send: 0x%llx sent %d/%d error %d\n",
-                       req->r_xid, (int)sentlen, (int)req->r_mreqlen, error));
+               NFS_SOCK_DBG("nfs_send: 0x%llx sent %d/%d error %d\n",
+                       req->r_xid, (int)sentlen, (int)req->r_mreqlen, error);
 #endif
        if (!error && (sentlen != req->r_mreqlen))
                error = EWOULDBLOCK;
@@ -2970,7 +3113,7 @@ again:
                /* SUCCESS */
                req->r_flags &= ~R_RESENDERR;
                if (rexmit)
-                       OSAddAtomic(1, &nfsstats.rpcretries);
+                       OSAddAtomic64(1, &nfsstats.rpcretries);
                req->r_flags |= R_SENT;
                if (req->r_flags & R_WAITSENT) {
                        req->r_flags &= ~R_WAITSENT;
@@ -3005,8 +3148,8 @@ again:
                        sock_getsockopt(nso->nso_so, SOL_SOCKET, SO_ERROR, &clearerror, &optlen);
 #ifdef NFS_SOCKET_DEBUGGING
                        if (clearerror)
-                               NFS_SOCK_DBG(("nfs_send: ignoring UDP socket error %d so %d\n",
-                                       error, clearerror));
+                               NFS_SOCK_DBG("nfs_send: ignoring UDP socket error %d so %d\n",
+                                       error, clearerror);
 #endif
                }
        }
@@ -3033,7 +3176,7 @@ again:
                break;
        }
        if (needrecon && (nso == nmp->nm_nso)) { /* mark socket as needing reconnect */
-               NFS_SOCK_DBG(("nfs_send: 0x%llx need reconnect %d\n", req->r_xid, error));
+               NFS_SOCK_DBG("nfs_send: 0x%llx need reconnect %d\n", req->r_xid, error);
                nfs_need_reconnect(nmp);
        }
 
@@ -3052,6 +3195,9 @@ again:
                        !req->r_nmp ? "<unmounted>" :
                        vfs_statfs(req->r_nmp->nm_mountp)->f_mntfromname);
 
+       if (nfs_is_dead(error, nmp))
+               error = EIO;
+
        /* prefer request termination error over other errors */
        error2 = nfs_sigintr(req->r_nmp, req, req->r_thread, 0);
        if (error2)
@@ -3104,7 +3250,7 @@ nfs_udp_rcv(socket_t so, void *arg, __unused int waitflag)
 
        if (error && (error != EWOULDBLOCK)) {
                /* problems with the socket... mark for reconnection */
-               NFS_SOCK_DBG(("nfs_udp_rcv: need reconnect %d\n", error));
+               NFS_SOCK_DBG("nfs_udp_rcv: need reconnect %d\n", error);
                nfs_need_reconnect(nmp);
        }
 }
@@ -3164,12 +3310,12 @@ nfs_tcp_rcv(socket_t so, void *arg, __unused int waitflag)
        }
 #ifdef NFS_SOCKET_DEBUGGING
        if (!recv && (error != EWOULDBLOCK))
-               NFS_SOCK_DBG(("nfs_tcp_rcv: got nothing, error %d, got FIN?\n", error));
+               NFS_SOCK_DBG("nfs_tcp_rcv: got nothing, error %d, got FIN?\n", error);
 #endif
        /* note: no error and no data indicates server closed its end */
        if ((error != EWOULDBLOCK) && (error || !recv)) {
                /* problems with the socket... mark for reconnection */
-               NFS_SOCK_DBG(("nfs_tcp_rcv: need reconnect %d\n", error));
+               NFS_SOCK_DBG("nfs_tcp_rcv: need reconnect %d\n", error);
                nfs_need_reconnect(nmp);
        }
 }
@@ -3200,7 +3346,8 @@ nfs_sock_poke(struct nfsmount *nmp)
        msg.msg_iov = &aio;
        msg.msg_iovlen = 1;
        error = sock_send(nmp->nm_nso->nso_so, &msg, MSG_DONTWAIT, &len);
-       NFS_SOCK_DBG(("nfs_sock_poke: error %d\n", error));
+       NFS_SOCK_DBG("nfs_sock_poke: error %d\n", error);
+       nfs_is_dead(error, nmp);
 }
 
 /*
@@ -3219,7 +3366,7 @@ nfs_request_match_reply(struct nfsmount *nmp, mbuf_t mrep)
        nfsm_chain_get_32(error, &nmrep, rxid);
        nfsm_chain_get_32(error, &nmrep, reply);
        if (error || (reply != RPC_REPLY)) {
-               OSAddAtomic(1, &nfsstats.rpcinvalid);
+               OSAddAtomic64(1, &nfsstats.rpcinvalid);
                mbuf_freem(mrep);
                return;
        }
@@ -3307,7 +3454,7 @@ nfs_request_match_reply(struct nfsmount *nmp, mbuf_t mrep)
        if (!req) {
                /* not matched to a request, so drop it. */
                lck_mtx_unlock(nfs_request_mutex);
-               OSAddAtomic(1, &nfsstats.rpcunexpected);
+               OSAddAtomic64(1, &nfsstats.rpcunexpected);
                mbuf_freem(mrep);
        }
 }
@@ -3335,8 +3482,8 @@ nfs_wait_reply(struct nfsreq *req)
                        break;
                /* check if we need to resend */
                if (req->r_flags & R_MUSTRESEND) {
-                       NFS_SOCK_DBG(("nfs wait resend: p %d x 0x%llx f 0x%x rtt %d\n",
-                               req->r_procnum, req->r_xid, req->r_flags, req->r_rtt));
+                       NFS_SOCK_DBG("nfs wait resend: p %d x 0x%llx f 0x%x rtt %d\n",
+                               req->r_procnum, req->r_xid, req->r_flags, req->r_rtt);
                        req->r_flags |= R_SENDING;
                        lck_mtx_unlock(&req->r_mtx);
                        if (nfs_request_using_gss(req)) {
@@ -3353,8 +3500,8 @@ nfs_wait_reply(struct nfsreq *req)
                        }
                        error = nfs_send(req, 1);
                        lck_mtx_lock(&req->r_mtx);
-                       NFS_SOCK_DBG(("nfs wait resend: p %d x 0x%llx f 0x%x rtt %d err %d\n",
-                               req->r_procnum, req->r_xid, req->r_flags, req->r_rtt, error));
+                       NFS_SOCK_DBG("nfs wait resend: p %d x 0x%llx f 0x%x rtt %d err %d\n",
+                               req->r_procnum, req->r_xid, req->r_flags, req->r_rtt, error);
                        if (error)
                                break;
                        if (((error = req->r_error)) || req->r_nmrep.nmc_mhead)
@@ -3443,7 +3590,7 @@ nfs_request_create(
        }
 
        if ((nmp->nm_vers != NFS_VER4) && (procnum >= 0) && (procnum < NFS_NPROCS))
-               OSAddAtomic(1, &nfsstats.rpccnt[procnum]);
+               OSAddAtomic64(1, &nfsstats.rpccnt[procnum]);
        if ((nmp->nm_vers == NFS_VER4) && (procnum != NFSPROC4_COMPOUND) && (procnum != NFSPROC4_NULL))
                panic("nfs_request: invalid NFSv4 RPC request %d\n", procnum);
 
@@ -3667,7 +3814,7 @@ nfs_request_send(struct nfsreq *req, int wait)
                    ((nmp->nm_tprintf_delay) - (nmp->nm_tprintf_initial_delay));
        }
 
-       OSAddAtomic(1, &nfsstats.rpcrequests);
+       OSAddAtomic64(1, &nfsstats.rpcrequests);
 
        /*
         * Chain request into list of outstanding requests. Be sure
@@ -3884,7 +4031,7 @@ nfs_request_finish(
                        if ((req->r_delay >= 30) && !(nmp->nm_state & NFSSTA_MOUNTED)) {
                                /* we're not yet completely mounted and */
                                /* we can't complete an RPC, so we fail */
-                               OSAddAtomic(1, &nfsstats.rpctimeouts);
+                               OSAddAtomic64(1, &nfsstats.rpctimeouts);
                                nfs_softterm(req);
                                error = req->r_error;
                                goto nfsmout;
@@ -3904,7 +4051,7 @@ nfs_request_finish(
                        }
                        if (NMFLAG(nmp, SOFT) && (req->r_delay == 30) && !(req->r_flags & R_NOINTR)) {
                                /* for soft mounts, just give up after a short while */
-                               OSAddAtomic(1, &nfsstats.rpctimeouts);
+                               OSAddAtomic64(1, &nfsstats.rpctimeouts);
                                nfs_softterm(req);
                                error = req->r_error;
                                goto nfsmout;
@@ -3918,7 +4065,7 @@ nfs_request_finish(
                                do {
                                        if ((error = nfs_sigintr(req->r_nmp, req, req->r_thread, 0)))
                                                goto nfsmout;
-                                       tsleep(&lbolt, PSOCK|slpflag, "nfs_jukebox_trylater", 0);
+                                       tsleep(nfs_request_finish, PSOCK|slpflag, "nfs_jukebox_trylater", hz);
                                        slpflag = 0;
                                } while (--delay > 0);
                        }
@@ -4174,7 +4321,7 @@ nfs_request2(
  * server. Associate the context that we are setting up with the request that we
  * are sending.
  */
+
 int
 nfs_request_gss(
                mount_t mp,
@@ -4192,7 +4339,7 @@ nfs_request_gss(
        if ((error = nfs_request_create(NULL, mp, nmrest, NFSPROC_NULL, thd, cred, &req)))
                return (error);
        req->r_flags |= (flags & R_OPTMASK);
-       
+
        if (cp == NULL) {
                printf("nfs_request_gss request has no context\n");
                nfs_request_rele(req);
@@ -4218,7 +4365,7 @@ nfs_request_gss(
        nfs_request_rele(req);
        return (error);
 }
-       
+
 /*
  * Create and start an asynchronous NFS request.
  */
@@ -4533,7 +4680,7 @@ nfs_request_timer(__unused void *param0, __unused void *param1)
                                lck_mtx_unlock(&nmp->nm_lock);
                                /* we're not yet completely mounted and */
                                /* we can't complete an RPC, so we fail */
-                               OSAddAtomic(1, &nfsstats.rpctimeouts);
+                               OSAddAtomic64(1, &nfsstats.rpctimeouts);
                                nfs_softterm(req);
                                finish_asyncio = ((req->r_callback.rcb_func != NULL) && !(req->r_flags & R_WAITSENT));
                                wakeup(req);
@@ -4549,10 +4696,10 @@ nfs_request_timer(__unused void *param0, __unused void *param1)
                 * Put a reasonable limit on the maximum timeout,
                 * and reduce that limit when soft mounts get timeouts or are in reconnect.
                 */
-               if (!NMFLAG(nmp, SOFT))
+               if (!NMFLAG(nmp, SOFT) && !nfs_can_squish(nmp))
                        maxtime = NFS_MAXTIMEO;
                else if ((req->r_flags & (R_SETUP|R_RECOVER)) ||
-                        ((nmp->nm_reconnect_start <= 0) || ((now.tv_sec - nmp->nm_reconnect_start) < 8)))
+                        ((nmp->nm_reconnect_start <= 0) || ((now.tv_sec - nmp->nm_reconnect_start) < 8)))
                        maxtime = (NFS_MAXTIMEO / (nmp->nm_timeouts+1))/2;
                else
                        maxtime = NFS_MINTIMEO/4;
@@ -4589,10 +4736,10 @@ nfs_request_timer(__unused void *param0, __unused void *param1)
                                continue;
                        }
                        /* The request has timed out */
-                       NFS_SOCK_DBG(("nfs timeout: proc %d %d xid %llx rtt %d to %d # %d, t %ld/%d\n",
+                       NFS_SOCK_DBG("nfs timeout: proc %d %d xid %llx rtt %d to %d # %d, t %ld/%d\n",
                                req->r_procnum, proct[req->r_procnum],
                                req->r_xid, req->r_rtt, timeo, nmp->nm_timeouts,
-                               (now.tv_sec - req->r_start)*NFS_HZ, maxtime));
+                               (now.tv_sec - req->r_start)*NFS_HZ, maxtime);
                        if (nmp->nm_timeouts < 8)
                                nmp->nm_timeouts++;
                        nfs_mount_check_dead_timeout(nmp);
@@ -4608,10 +4755,10 @@ nfs_request_timer(__unused void *param0, __unused void *param1)
                }
 
                /* For soft mounts (& SETUPs/RECOVERs), check for too many retransmits/timeout. */
-               if ((NMFLAG(nmp, SOFT) || (req->r_flags & (R_SETUP|R_RECOVER))) &&
+               if ((NMFLAG(nmp, SOFT) ||  (req->r_flags & (R_SETUP|R_RECOVER))) &&
                    ((req->r_rexmit >= req->r_retry) || /* too many */
                     ((now.tv_sec - req->r_start)*NFS_HZ > maxtime))) { /* too long */
-                       OSAddAtomic(1, &nfsstats.rpctimeouts);
+                       OSAddAtomic64(1, &nfsstats.rpctimeouts);
                        lck_mtx_lock(&nmp->nm_lock);
                        if (!(nmp->nm_state & NFSSTA_TIMEO)) {
                                lck_mtx_unlock(&nmp->nm_lock);
@@ -4629,9 +4776,9 @@ nfs_request_timer(__unused void *param0, __unused void *param1)
                                lck_mtx_unlock(&req->r_mtx);
                                continue;
                        }
-                       NFS_SOCK_DBG(("nfs timer TERMINATE: p %d x 0x%llx f 0x%x rtt %d t %ld\n",
+                       NFS_SOCK_DBG("nfs timer TERMINATE: p %d x 0x%llx f 0x%x rtt %d t %ld\n",
                                req->r_procnum, req->r_xid, req->r_flags, req->r_rtt,
-                               now.tv_sec - req->r_start));
+                               now.tv_sec - req->r_start);
                        nfs_softterm(req);
                        finish_asyncio = ((req->r_callback.rcb_func != NULL) && !(req->r_flags & R_WAITSENT));
                        wakeup(req);
@@ -4658,8 +4805,8 @@ nfs_request_timer(__unused void *param0, __unused void *param1)
                        lck_mtx_unlock(&req->r_mtx);
                        continue;
                }
-               NFS_SOCK_DBG(("nfs timer mark resend: p %d x 0x%llx f 0x%x rtt %d\n",
-                       req->r_procnum, req->r_xid, req->r_flags, req->r_rtt));
+               NFS_SOCK_DBG("nfs timer mark resend: p %d x 0x%llx f 0x%x rtt %d\n",
+                       req->r_procnum, req->r_xid, req->r_flags, req->r_rtt);
                req->r_flags |= R_MUSTRESEND;
                req->r_rtt = -1;
                wakeup(req);
@@ -4735,7 +4882,8 @@ nfs_sigintr(struct nfsmount *nmp, struct nfsreq *req, thread_t thd, int nmplocke
         * If the mount is hung and we've requested not to hang
         * on remote filesystems, then bail now.
         */
-       if (!error && (nmp->nm_state & NFSSTA_TIMEO) && nfs_noremotehang(thd))
+       if (current_proc() != kernproc &&
+           !error && (nmp->nm_state & NFSSTA_TIMEO) && nfs_noremotehang(thd))
                error = EIO;
 
        if (!nmplocked)
@@ -4744,7 +4892,7 @@ nfs_sigintr(struct nfsmount *nmp, struct nfsreq *req, thread_t thd, int nmplocke
                return (error);
 
        /* may not have a thread for async I/O */
-       if (thd == NULL)
+       if (thd == NULL || current_proc() == kernproc)
                return (0);
 
        /*
@@ -5037,7 +5185,7 @@ nfs_portmap_lookup(
                pmvers = RPCBVERS4;
                pmproc = RPCBPROC_GETVERSADDR;
        } else {
-               return (EINVAL);
+               return (EINVAL);
        }
        nfsm_chain_null(&nmreq);
        nfsm_chain_null(&nmrep);
@@ -5140,6 +5288,145 @@ nfs_msg(thread_t thd,
        return (0);
 }
 
+#define        NFS_SQUISH_MOBILE_ONLY          0x0001          /* Squish mounts only on mobile machines */
+#define NFS_SQUISH_AUTOMOUNTED_ONLY    0x0002          /* Squish mounts only if the are automounted */
+#define NFS_SQUISH_SOFT                        0x0004          /* Treat all soft mounts as though they were on a mobile machine */
+#define NFS_SQUISH_QUICK               0x0008          /* Try to squish mounts more quickly. */
+#define NFS_SQUISH_SHUTDOWN            0x1000          /* Squish all mounts on shutdown. Currently not implemented */
+
+uint32_t nfs_squishy_flags = NFS_SQUISH_MOBILE_ONLY | NFS_SQUISH_AUTOMOUNTED_ONLY | NFS_SQUISH_QUICK;
+int32_t nfs_is_mobile;
+
+#define        NFS_SQUISHY_DEADTIMEOUT         8       /* Dead time out for squishy mounts */
+#define NFS_SQUISHY_QUICKTIMEOUT       4       /* Quicker dead time out when nfs_squish_flags NFS_SQUISH_QUICK bit is set*/
+
+/*
+ * Could this mount be squished?
+ */
+int
+nfs_can_squish(struct nfsmount *nmp)
+{
+       uint64_t flags = vfs_flags(nmp->nm_mountp);
+       int softsquish = ((nfs_squishy_flags & NFS_SQUISH_SOFT) & NMFLAG(nmp, SOFT));
+
+       if (!softsquish && (nfs_squishy_flags & NFS_SQUISH_MOBILE_ONLY) && nfs_is_mobile == 0)
+               return (0);
+
+       if ((nfs_squishy_flags & NFS_SQUISH_AUTOMOUNTED_ONLY) && (flags & MNT_AUTOMOUNTED) == 0)
+               return (0);
+
+       return (1);
+}
+
+/*
+ * NFS mounts default to "rw,hard" - but frequently on mobile clients
+ * the mount may become "not responding".  It's desirable to be able
+ * to unmount these dead mounts, but only if there is no risk of
+ * losing data or crashing applications.  A "squishy" NFS mount is one
+ * that can be force unmounted with little risk of harm.
+ *
+ * nfs_is_squishy checks if a mount is in a squishy state.  A mount is
+ * in a squishy state iff it is allowed to be squishy and there are no
+ * dirty pages and there are no mmapped files and there are no files
+ * open for write. Mounts are allowed to be squishy is controlled by
+ * the settings of the nfs_squishy_flags and its mobility state. These
+ * flags can be set by sysctls.
+ *
+ * If nfs_is_squishy determines that we are in a squishy state we will
+ * update the current dead timeout to at least NFS_SQUISHY_DEADTIMEOUT
+ * (or NFS_SQUISHY_QUICKTIMEOUT if NFS_SQUISH_QUICK is set) (see
+ * above) or 1/8th of the mount's nm_deadtimeout value, otherwise we just
+ * update the current dead timeout with the mount's nm_deadtimeout
+ * value set at mount time.
+ *
+ * Assumes that nm_lock is held.
+ *
+ * Note this routine is racey, but its effects on setting the
+ * dead timeout only have effects when we're in trouble and are likely
+ * to stay that way. Since by default its only for automounted
+ * volumes on mobile machines; this is a reasonable trade off between
+ * data integrity and user experience. It can be disabled or set via
+ * nfs.conf file.
+ */
+
+int
+nfs_is_squishy(struct nfsmount *nmp)
+{
+       mount_t mp = nmp->nm_mountp;
+       int squishy = 0;
+       int timeo = (nfs_squishy_flags & NFS_SQUISH_QUICK) ? NFS_SQUISHY_QUICKTIMEOUT : NFS_SQUISHY_DEADTIMEOUT;
+
+       NFS_SOCK_DBG("%s: nm_curdeadtiemout = %d, nfs_is_mobile = %d\n",
+                     vfs_statfs(mp)->f_mntfromname, nmp->nm_curdeadtimeout,  nfs_is_mobile);
+
+       if (!nfs_can_squish(nmp))
+               goto out;
+
+       timeo =  (nmp->nm_deadtimeout > timeo) ? max(nmp->nm_deadtimeout/8, timeo) : timeo;
+       NFS_SOCK_DBG("nm_writers = %d  nm_mappers = %d timeo = %d\n", nmp->nm_writers, nmp->nm_mappers, timeo);
+
+       if (nmp->nm_writers == 0 && nmp->nm_mappers == 0) {
+               uint64_t flags = mp ? vfs_flags(mp) : 0;
+               squishy = 1;
+               
+               /* 
+                * Walk the nfs nodes and check for dirty buffers it we're not 
+                * RDONLY and we've not already been declared as squishy since
+                * this can be a bit expensive.
+                */
+               if (!(flags & MNT_RDONLY) && !(nmp->nm_state & NFSSTA_SQUISHY)) 
+                       squishy = !nfs_mount_is_dirty(mp);
+       }
+
+out:
+       if (squishy)
+               nmp->nm_state |= NFSSTA_SQUISHY;
+       else
+               nmp->nm_state &= ~NFSSTA_SQUISHY;
+
+       nmp->nm_curdeadtimeout = squishy ? timeo : nmp->nm_deadtimeout;
+                       
+       NFS_SOCK_DBG("nm_curdeadtimeout = %d\n", nmp->nm_curdeadtimeout);
+
+       return (squishy);
+}
+
+/*
+ * On a send operation, if we can't reach the server and we've got only one server to talk to
+ * and NFS_SQUISH_QUICK flag is set and we are in a squishy state then mark the mount as dead
+ * and ask to be forcibly unmounted. Return 1 if we're dead and 0 otherwise.
+ */
+static int
+nfs_is_dead_lock(int error, struct nfsmount *nmp)
+{
+       if (nmp->nm_state & NFSSTA_DEAD)
+               return (1);
+
+       if ((error != ENETUNREACH && error != EHOSTUNREACH && error != EADDRNOTAVAIL) ||
+           !(nmp->nm_locations.nl_numlocs == 1 && nmp->nm_locations.nl_locations[0]->nl_servcount == 1))
+               return (0);
+
+       if ((nfs_squishy_flags & NFS_SQUISH_QUICK) && nfs_is_squishy(nmp)) {
+               printf("nfs_is_dead: nfs server %s: unreachable. Squished dead\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname);
+               nmp->nm_state |= NFSSTA_DEAD;
+               vfs_event_signal(&vfs_statfs(nmp->nm_mountp)->f_fsid, VQ_DEAD, 0);
+               return (1);
+       }
+       return (0);
+}
+
+int
+nfs_is_dead(int error, struct nfsmount *nmp)
+{
+       int is_dead;
+
+       lck_mtx_lock(&nmp->nm_lock);
+       is_dead = nfs_is_dead_lock(error, nmp);
+       lck_mtx_unlock(&nmp->nm_lock);
+
+       return (is_dead);
+}
+
 void
 nfs_down(struct nfsmount *nmp, thread_t thd, int error, int flags, const char *msg)
 {
@@ -5169,14 +5456,17 @@ nfs_down(struct nfsmount *nmp, thread_t thd, int error, int flags, const char *m
 
        unresponsive = (nmp->nm_state & timeoutmask);
 
-       if (unresponsive && (nmp->nm_deadtimeout > 0)) {
+       nfs_is_squishy(nmp);
+
+       if (unresponsive && (nmp->nm_curdeadtimeout > 0)) {
                microuptime(&now);
                if (!wasunresponsive) {
                        nmp->nm_deadto_start = now.tv_sec;
                        nfs_mount_sock_thread_wake(nmp);
-               } else if ((now.tv_sec - nmp->nm_deadto_start) > nmp->nm_deadtimeout) {
+               } else if ((now.tv_sec - nmp->nm_deadto_start) > nmp->nm_curdeadtimeout) {
                        if (!(nmp->nm_state & NFSSTA_DEAD))
-                               printf("nfs server %s: dead\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname);
+                               printf("nfs server %s: %sdead\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname,
+                                      (nmp->nm_curdeadtimeout != nmp->nm_deadtimeout) ? "squished " : "");
                        nmp->nm_state |= NFSSTA_DEAD;
                }
        }
@@ -5225,8 +5515,9 @@ nfs_up(struct nfsmount *nmp, thread_t thd, int flags, const char *msg)
 
        unresponsive = (nmp->nm_state & timeoutmask);
 
-       if (nmp->nm_deadto_start)
-               nmp->nm_deadto_start = 0;
+       nmp->nm_deadto_start = 0;
+       nmp->nm_curdeadtimeout = nmp->nm_deadtimeout;
+       nmp->nm_state &= ~NFSSTA_SQUISHY;
        lck_mtx_unlock(&nmp->nm_lock);
 
        if (softnobrowse)
@@ -5350,7 +5641,7 @@ done:
 
        *nmrepp = nmrep;
        if ((err != 0) && (err != NFSERR_RETVOID))
-               OSAddAtomic(1, &nfsstats.srvrpc_errs);
+               OSAddAtomic64(1, &nfsstats.srvrpc_errs);
        return (0);
 }
 
@@ -5487,11 +5778,11 @@ nfsrv_rcv_locked(socket_t so, struct nfsrv_sock *slp, int waitflag)
                        ns_flag = SLP_NEEDQ;
                        goto dorecs;
                }
-               
+
                bzero(&msg, sizeof(msg));
                msg.msg_name = (caddr_t)&nam;
                msg.msg_namelen = sizeof(nam);
-               
+
                do {
                        bytes_read = 1000000000;
                        error = sock_receivembuf(so, &msg, &mp, MSG_DONTWAIT | MSG_NEEDSA, &bytes_read);
@@ -5670,7 +5961,7 @@ nfsrv_getstream(struct nfsrv_sock *slp, int waitflag)
            if (slp->ns_frag == NULL) {
                slp->ns_frag = recm;
            } else {
-               m = slp->ns_frag;
+               m = slp->ns_frag;
                while ((m2 = mbuf_next(m)))
                    m = m2;
                if ((error = mbuf_setnext(m, recm)))
@@ -5918,4 +6209,3 @@ nfsrv_wakenfsd(struct nfsrv_sock *slp)
 }
 
 #endif /* NFSSERVER */
-