]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/nfs/nfs_socket.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_socket.c
index 55ba36619b3856754cd10cdeac79a782d24560d9..435bbb7826a0b41d35348fb883d4c5298aa3b60f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
@@ -65,6 +65,9 @@
  * FreeBSD-Id: nfs_socket.c,v 1.30 1997/10/28 15:59:07 bde Exp $
  */
 
+#include <nfs/nfs_conf.h>
+#if CONFIG_NFS
+
 /*
  * Socket operations for use by nfs
  */
 #include <sys/domain.h>
 #include <sys/protosw.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <sys/syslog.h>
 #include <sys/tprintf.h>
 #include <libkern/OSAtomic.h>
 
+#include <sys/reboot.h>
 #include <sys/time.h>
 #include <kern/clock.h>
 #include <kern/task.h>
 #include <nfs/nfsnode.h>
 
 #define NFS_SOCK_DBG(...) NFS_DBG(NFS_FAC_SOCK, 7, ## __VA_ARGS__)
+#define NFS_SOCK_DUMP_MBUF(msg, mb) if (NFS_IS_DBG(NFS_FAC_SOCK, 15)) nfs_dump_mbuf(__func__, __LINE__, (msg), (mb))
+
+#ifndef SUN_LEN
+#define SUN_LEN(su) \
+       (sizeof(*(su)) - sizeof((su)->sun_path) + strnlen((su)->sun_path, sizeof((su)->sun_path)))
+#endif /* SUN_LEN */
 
 /* XXX */
 boolean_t       current_thread_aborted(void);
 kern_return_t   thread_terminate(thread_t);
 
+ZONE_DECLARE(nfs_fhandle_zone, "fhandle", sizeof(struct fhandle), ZC_NONE);
+ZONE_DECLARE(nfs_req_zone, "NFS req", sizeof(struct nfsreq), ZC_NONE);
+ZONE_DECLARE(nfsrv_descript_zone, "NFSV3 srvdesc",
+    sizeof(struct nfsrv_descript), ZC_NONE);
+
 
-#if NFSSERVER
+#if CONFIG_NFS_SERVER
 int nfsrv_sock_max_rec_queue_length = 128; /* max # RPC records queued on (UDP) socket */
 
 int nfsrv_getstream(struct nfsrv_sock *, int);
 int nfsrv_getreq(struct nfsrv_descript *);
 extern int nfsv3_procid[NFS_NPROCS];
-#endif /* NFSSERVER */
+#endif /* CONFIG_NFS_SERVER */
 
 /*
  * compare two sockaddr structures
@@ -151,7 +167,7 @@ nfs_sockaddr_cmp(struct sockaddr *sa1, struct sockaddr *sa2)
        return -1;
 }
 
-#if NFSCLIENT
+#if CONFIG_NFS_CLIENT
 
 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);
@@ -203,8 +219,30 @@ int     nfs_is_dead(int, struct nfsmount *);
  * 3 - read
  * 4 - write
  */
-static int proct[NFS_NPROCS] = {
-       0, 1, 0, 2, 1, 3, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0
+static const int proct[] = {
+       [NFSPROC_NULL]                  =       0,
+       [NFSPROC_GETATTR]               =       1,
+       [NFSPROC_SETATTR]               =       0,
+       [NFSPROC_LOOKUP]                =       2,
+       [NFSPROC_ACCESS]                =       1,
+       [NFSPROC_READLINK]              =       3,
+       [NFSPROC_READ]                  =       3,
+       [NFSPROC_WRITE]                 =       4,
+       [NFSPROC_CREATE]                =       0,
+       [NFSPROC_MKDIR]                 =       0,
+       [NFSPROC_SYMLINK]               =       0,
+       [NFSPROC_MKNOD]                 =       0,
+       [NFSPROC_REMOVE]                =       0,
+       [NFSPROC_RMDIR]                 =       0,
+       [NFSPROC_RENAME]                =       0,
+       [NFSPROC_LINK]                  =       0,
+       [NFSPROC_READDIR]               =       3,
+       [NFSPROC_READDIRPLUS]           =       3,
+       [NFSPROC_FSSTAT]                =       0,
+       [NFSPROC_FSINFO]                =       0,
+       [NFSPROC_PATHCONF]              =       0,
+       [NFSPROC_COMMIT]                =       0,
+       [NFSPROC_NOOP]                  =       0,
 };
 
 /*
@@ -288,7 +326,7 @@ nfs_location_index_cmp(struct nfs_location_index *nlip1, struct nfs_location_ind
  * Get the mntfromname (or path portion only) for a given location.
  */
 void
-nfs_location_mntfromname(struct nfs_fs_locations *locs, struct nfs_location_index idx, char *s, int size, int pathonly)
+nfs_location_mntfromname(struct nfs_fs_locations *locs, struct nfs_location_index idx, char *s, size_t size, int pathonly)
 {
        struct nfs_fs_location *fsl = locs->nl_locations[idx.nli_loc];
        char *p;
@@ -296,7 +334,18 @@ nfs_location_mntfromname(struct nfs_fs_locations *locs, struct nfs_location_inde
 
        p = s;
        if (!pathonly) {
-               cnt = snprintf(p, size, "%s:", fsl->nl_servers[idx.nli_serv]->ns_name);
+               char *name = fsl->nl_servers[idx.nli_serv]->ns_name;
+               if (name == NULL) {
+                       name = "";
+               }
+               if (*name == '\0') {
+                       if (*fsl->nl_servers[idx.nli_serv]->ns_addresses[idx.nli_addr]) {
+                               name = fsl->nl_servers[idx.nli_serv]->ns_addresses[idx.nli_addr];
+                       }
+                       cnt = scnprintf(p, size, "<%s>:", name);
+               } else {
+                       cnt = scnprintf(p, size, "%s:", name);
+               }
                p += cnt;
                size -= cnt;
        }
@@ -310,7 +359,7 @@ nfs_location_mntfromname(struct nfs_fs_locations *locs, struct nfs_location_inde
        }
        /* append each server path component */
        for (i = 0; (size > 0) && (i < (int)fsl->nl_path.np_compcount); i++) {
-               cnt = snprintf(p, size, "/%s", fsl->nl_path.np_components[i]);
+               cnt = scnprintf(p, size, "/%s", fsl->nl_path.np_components[i]);
                p += cnt;
                size -= cnt;
        }
@@ -329,7 +378,7 @@ 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 flags = %8.8x\n", nso, nso->nso_flags);
                wakeup(nso->nso_wake);
                return;
        }
@@ -340,7 +389,7 @@ nfs_connect_upcall(socket_t so, void *arg, __unused int waitflag)
                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 %8.8x\n", nso, nso->nso_flags);
        nso->nso_flags |= NSO_UPCALL;
 
        /* loop while we make error-free progress */
@@ -353,6 +402,7 @@ nfs_connect_upcall(socket_t so, void *arg, __unused int waitflag)
                m = NULL;
                if (nso->nso_sotype == SOCK_STREAM) {
                        error = nfs_rpc_record_read(so, &nso->nso_rrs, MSG_DONTWAIT, &recv, &m);
+                       NFS_SOCK_DBG("nfs_rpc_record_read returned %d recv = %d\n", error, recv);
                } else {
                        rcvlen = 1000000;
                        error = sock_receivembuf(so, NULL, &m, MSG_DONTWAIT, &rcvlen);
@@ -365,6 +415,7 @@ nfs_connect_upcall(socket_t so, void *arg, __unused int waitflag)
                        uint32_t reply = 0, rxid = 0, verf_type, verf_len;
                        uint32_t reply_status, rejected_status, accepted_status;
 
+                       NFS_SOCK_DUMP_MBUF("Got mbuf from ping", m);
                        nfsm_chain_dissect_init(error, &nmrep, m);
                        nfsm_chain_get_32(error, &nmrep, rxid);
                        nfsm_chain_get_32(error, &nmrep, reply);
@@ -386,6 +437,7 @@ nfs_connect_upcall(socket_t so, void *arg, __unused int waitflag)
                        }
                        nfsm_chain_get_32(error, &nmrep, accepted_status);
                        nfsmout_if(error);
+                       NFS_SOCK_DBG("Recevied accepted_status of %d  nso_version = %d\n", accepted_status, nso->nso_version);
                        if ((accepted_status == RPC_PROGMISMATCH) && !nso->nso_version) {
                                uint32_t minvers, maxvers;
                                nfsm_chain_get_32(error, &nmrep, minvers);
@@ -454,6 +506,8 @@ nfs_connect_upcall(socket_t so, void *arg, __unused int waitflag)
 nfsmout:
                        nso->nso_flags &= ~NSO_PINGING;
                        if (error) {
+                               NFS_SOCK_DBG("nfs upcalled failed for %d program %d vers error = %d\n",
+                                   nso->nso_protocol, nso->nso_version, error);
                                nso->nso_error = error;
                                nso->nso_flags |= NSO_DEAD;
                        } else {
@@ -469,6 +523,7 @@ nfsmout:
        nso->nso_flags &= ~NSO_UPCALL;
        if ((error != EWOULDBLOCK) && (error || !recv)) {
                /* problems with the socket... */
+               NFS_SOCK_DBG("connect upcall failed %d\n", error);
                nso->nso_error = error ? error : EPIPE;
                nso->nso_flags |= NSO_DEAD;
                wakeup(nso->nso_wake);
@@ -486,7 +541,7 @@ int
 nfs_socket_create(
        struct nfsmount *nmp,
        struct sockaddr *sa,
-       int sotype,
+       uint8_t sotype,
        in_port_t port,
        uint32_t protocol,
        uint32_t vers,
@@ -496,17 +551,39 @@ nfs_socket_create(
        struct nfs_socket *nso;
        struct timeval now;
        int error;
+#define NFS_SOCKET_DEBUGGING
 #ifdef NFS_SOCKET_DEBUGGING
-       char naddr[MAX_IPv6_STR_LEN];
+       char naddr[sizeof((struct sockaddr_un *)0)->sun_path];
        void *sinaddr;
 
-       if (sa->sa_family == AF_INET) {
+       switch (sa->sa_family) {
+       case AF_INET:
+               if (sa->sa_len != sizeof(struct sockaddr_in)) {
+                       return EINVAL;
+               }
                sinaddr = &((struct sockaddr_in*)sa)->sin_addr;
-       } else {
+               if (inet_ntop(sa->sa_family, sinaddr, naddr, sizeof(naddr)) != naddr) {
+                       strlcpy(naddr, "<unknown>", sizeof(naddr));
+               }
+               break;
+       case AF_INET6:
+               if (sa->sa_len != sizeof(struct sockaddr_in6)) {
+                       return EINVAL;
+               }
                sinaddr = &((struct sockaddr_in6*)sa)->sin6_addr;
-       }
-       if (inet_ntop(sa->sa_family, sinaddr, naddr, sizeof(naddr)) != naddr) {
-               strlcpy(naddr, "<unknown>", sizeof(naddr));
+               if (inet_ntop(sa->sa_family, sinaddr, naddr, sizeof(naddr)) != naddr) {
+                       strlcpy(naddr, "<unknown>", sizeof(naddr));
+               }
+               break;
+       case AF_LOCAL:
+               if (sa->sa_len != sizeof(struct sockaddr_un) && sa->sa_len != SUN_LEN((struct sockaddr_un *)sa)) {
+                       return EINVAL;
+               }
+               strlcpy(naddr, ((struct sockaddr_un *)sa)->sun_path, sizeof(naddr));
+               break;
+       default:
+               strlcpy(naddr, "<unsupported address family>", sizeof(naddr));
+               break;
        }
 #else
        char naddr[1] =  { 0 };
@@ -525,7 +602,7 @@ nfs_socket_create(
                }
                return ENOMEM;
        }
-       lck_mtx_init(&nso->nso_lock, nfs_request_grp, LCK_ATTR_NULL);
+       lck_mtx_init(&nso->nso_lock, &nfs_request_grp, LCK_ATTR_NULL);
        nso->nso_sotype = sotype;
        if (nso->nso_sotype == SOCK_STREAM) {
                nfs_rpc_record_state_init(&nso->nso_rrs);
@@ -533,10 +610,17 @@ nfs_socket_create(
        microuptime(&now);
        nso->nso_timestamp = now.tv_sec;
        bcopy(sa, nso->nso_saddr, sa->sa_len);
-       if (sa->sa_family == AF_INET) {
-               ((struct sockaddr_in*)nso->nso_saddr)->sin_port = htons(port);
-       } else if (sa->sa_family == AF_INET6) {
-               ((struct sockaddr_in6*)nso->nso_saddr)->sin6_port = htons(port);
+       switch (sa->sa_family) {
+       case AF_INET:
+       case AF_INET6:
+               if (sa->sa_family == AF_INET) {
+                       ((struct sockaddr_in*)nso->nso_saddr)->sin_port = htons(port);
+               } else if (sa->sa_family == AF_INET6) {
+                       ((struct sockaddr_in6*)nso->nso_saddr)->sin6_port = htons(port);
+               }
+               break;
+       case AF_LOCAL:
+               break;
        }
        nso->nso_protocol = protocol;
        nso->nso_version = vers;
@@ -577,7 +661,7 @@ nfs_socket_create(
                    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);
                *nsop = nso;
@@ -591,8 +675,9 @@ nfs_socket_create(
 void
 nfs_socket_destroy(struct nfs_socket *nso)
 {
-       struct timespec ts = { 4, 0 };
+       struct timespec ts = { .tv_sec = 4, .tv_nsec = 0 };
 
+       NFS_SOCK_DBG("Destoring socket %p flags = %8.8x error = %d\n", nso, nso->nso_flags, nso->nso_error);
        lck_mtx_lock(&nso->nso_lock);
        nso->nso_flags |= NSO_DISCONNECTING;
        if (nso->nso_flags & NSO_UPCALL) { /* give upcall a chance to complete */
@@ -604,7 +689,7 @@ nfs_socket_destroy(struct nfs_socket *nso)
        if (nso->nso_sotype == SOCK_STREAM) {
                nfs_rpc_record_state_cleanup(&nso->nso_rrs);
        }
-       lck_mtx_destroy(&nso->nso_lock, nfs_request_grp);
+       lck_mtx_destroy(&nso->nso_lock, &nfs_request_grp);
        if (nso->nso_saddr) {
                FREE(nso->nso_saddr, M_SONAME);
        }
@@ -629,7 +714,7 @@ nfs_socket_options(struct nfsmount *nmp, struct nfs_socket *nso)
         *   Soft mounts will want to abort sooner.
         */
        struct timeval timeo;
-       int on = 1, proto;
+       int on = 1, proto, reserve, error;
 
        timeo.tv_usec = 0;
        timeo.tv_sec = (NMFLAG(nmp, SOFT) || nfs_can_squish(nmp)) ? 5 : 60;
@@ -644,11 +729,23 @@ nfs_socket_options(struct nfsmount *nmp, struct nfs_socket *nso)
                        sock_setsockopt(nso->nso_so, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
                }
        }
-       if (nso->nso_sotype == SOCK_DGRAM) { /* set socket buffer sizes for UDP */
-               int reserve = NFS_UDPSOCKBUF;
-               sock_setsockopt(nso->nso_so, SOL_SOCKET, SO_SNDBUF, &reserve, sizeof(reserve));
-               sock_setsockopt(nso->nso_so, SOL_SOCKET, SO_RCVBUF, &reserve, sizeof(reserve));
+
+       /* set socket buffer sizes for UDP/TCP */
+       reserve = (nso->nso_sotype == SOCK_DGRAM) ? NFS_UDPSOCKBUF : MAX(nfs_tcp_sockbuf, nmp->nm_wsize * 2);
+       {
+               error = sock_setsockopt(nso->nso_so, SOL_SOCKET, SO_SNDBUF, &reserve, sizeof(reserve));
+       }
+
+       if (error) {
+               log(LOG_INFO, "nfs_socket_options: error %d setting SO_SNDBUF to %u\n", error, reserve);
+       }
+
+       reserve = (nso->nso_sotype == SOCK_DGRAM) ? NFS_UDPSOCKBUF : MAX(nfs_tcp_sockbuf, nmp->nm_rsize * 2);
+       error = sock_setsockopt(nso->nso_so, SOL_SOCKET, SO_RCVBUF, &reserve, sizeof(reserve));
+       if (error) {
+               log(LOG_INFO, "nfs_socket_options: error %d setting SO_RCVBUF to %u\n", error, reserve);
        }
+
        /* set SO_NOADDRERR to detect network changes ASAP */
        sock_setsockopt(nso->nso_so, SOL_SOCKET, SO_NOADDRERR, &on, sizeof(on));
        /* just playin' it safe with upcalls */
@@ -765,7 +862,24 @@ nfs_connect_search_new_socket(struct nfsmount *nmp, struct nfs_socket_search *ns
                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];
+               NFS_SOCK_DBG("Trying address %s for program %d on port %d\n", addrstr, nss->nss_protocol, nss->nss_port);
+               if (*addrstr == '\0') {
+                       /*
+                        * We have an unspecified local domain address. We use the program to translate to
+                        * a well known local transport address. We only support PMAPROG and NFS for this.
+                        */
+                       if (nss->nss_protocol == PMAPPROG) {
+                               addrstr = (nss->nss_sotype == SOCK_DGRAM) ? RPCB_TICLTS_PATH : RPCB_TICOTSORD_PATH;
+                       } else if (nss->nss_protocol == NFS_PROG) {
+                               addrstr = nmp->nm_nfs_localport;
+                               if (!addrstr || *addrstr == '\0') {
+                                       addrstr = (nss->nss_sotype == SOCK_DGRAM) ? NFS_TICLTS_PATH : NFS_TICOTSORD_PATH;
+                               }
+                       }
+                       NFS_SOCK_DBG("Calling  prog %d with <%s>\n", nss->nss_protocol, addrstr);
+               }
                if (!nfs_uaddr2sockaddr(addrstr, (struct sockaddr*)&ss)) {
+                       NFS_SOCK_DBG("Could not convert address %s to socket\n", addrstr);
                        nfs_location_next(&nmp->nm_locations, &nss->nss_nextloc);
                        nss->nss_addrcnt -= 1;
                        nss->nss_last = -2;
@@ -773,6 +887,7 @@ nfs_connect_search_new_socket(struct nfsmount *nmp, struct nfs_socket_search *ns
                }
                /* Check that socket family is acceptable. */
                if (nmp->nm_sofamily && (ss.ss_family != nmp->nm_sofamily)) {
+                       NFS_SOCK_DBG("Skipping socket family %d, want mount family %d\n", ss.ss_family, nmp->nm_sofamily);
                        nfs_location_next(&nmp->nm_locations, &nss->nss_nextloc);
                        nss->nss_addrcnt -= 1;
                        nss->nss_last = -2;
@@ -791,6 +906,7 @@ nfs_connect_search_new_socket(struct nfsmount *nmp, struct nfs_socket_search *ns
                nso->nso_wake = nss;
                error = sock_setupcall(nso->nso_so, nfs_connect_upcall, nso);
                if (error) {
+                       NFS_SOCK_DBG("sock_setupcall failed for socket %p setting nfs_connect_upcall error = %d\n", nso, error);
                        lck_mtx_lock(&nso->nso_lock);
                        nso->nso_error = error;
                        nso->nso_flags |= NSO_DEAD;
@@ -834,9 +950,14 @@ nfs_connect_search_socket_connect(struct nfsmount *nmp, struct nfs_socket *nso,
                /* 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);
+               NFS_SOCK_DBG("nfs connect %s connecting socket %p %s\n",
+                   vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso,
+                   nso->nso_saddr->sa_family == AF_LOCAL ? ((struct sockaddr_un*)nso->nso_saddr)->sun_path : "");
                error = sock_connect(nso->nso_so, nso->nso_saddr, MSG_DONTWAIT);
+               if (error) {
+                       NFS_SOCK_DBG("nfs connect %s connecting socket %p returned %d\n",
+                           vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, error);
+               }
                lck_mtx_lock(&nso->nso_lock);
                if (error && (error != EINPROGRESS)) {
                        nso->nso_error = error;
@@ -896,6 +1017,7 @@ nfs_connect_search_ping(struct nfsmount *nmp, struct nfs_socket *nso, struct tim
                }
        }
        lck_mtx_unlock(&nso->nso_lock);
+       NFS_SOCK_DBG("Pinging  socket %p %d %d %d\n", nso, nso->nso_sotype, nso->nso_protocol, vers);
        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);
@@ -912,6 +1034,7 @@ nfs_connect_search_ping(struct nfsmount *nmp, struct nfs_socket *nso, struct tim
                        reqlen += mbuf_len(m);
                }
                lck_mtx_unlock(&nso->nso_lock);
+               NFS_SOCK_DUMP_MBUF("Sending ping packet", mreq);
                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);
@@ -975,8 +1098,8 @@ nfs_connect_search_socket_reap(struct nfsmount *nmp __unused, struct nfs_socket_
                        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 error = %d flags = %8.8x\n",
+                   vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, nso->nso_error, nso->nso_flags);
                nfs_socket_search_update_error(nss, nso->nso_error);
                TAILQ_REMOVE(&nss->nss_socklist, nso, nso_link);
                nss->nss_sockcnt--;
@@ -1113,13 +1236,16 @@ nfs_connect(struct nfsmount *nmp, int verbose, int timeo)
        struct sockaddr_storage ss;
        struct sockaddr *saddr, *oldsaddr;
        sock_upcall upcall;
-       struct timeval now, start;
+#if CONFIG_NFS4
+       struct timeval now;
+#endif
+       struct timeval start;
        int error, savederror, nfsvers;
        int tryv4 = 1;
        uint8_t sotype = nmp->nm_sotype ? nmp->nm_sotype : SOCK_STREAM;
        fhandle_t *fh = NULL;
        char *path = NULL;
-       in_port_t port;
+       in_port_t port = 0;
        int addrtotal = 0;
 
        /* paranoia... check that we have at least one address in the locations */
@@ -1167,26 +1293,34 @@ tryagain:
 
        /* First time connecting, we may need to negotiate some things */
        if (!(nmp->nm_sockflags & NMSOCK_HASCONNECTED)) {
+               NFS_SOCK_DBG("so_family = %d\n", nmp->nm_sofamily);
+               NFS_SOCK_DBG("nfs port = %d local: <%s>\n", nmp->nm_nfsport, nmp->nm_nfs_localport ? nmp->nm_nfs_localport : "");
+               NFS_SOCK_DBG("mount port = %d local: <%s>\n", nmp->nm_mountport, nmp->nm_mount_localport ? nmp->nm_mount_localport : "");
                if (!nmp->nm_vers) {
                        /* No NFS version specified... */
                        if (!nmp->nm_nfsport || (!NM_OMATTR_GIVEN(nmp, FH) && !nmp->nm_mountport)) {
+#if CONFIG_NFS4
                                if (PVER2MAJOR(nmp->nm_max_vers) >= NFS_VER4 && tryv4) {
                                        nss.nss_port = NFS_PORT;
                                        nss.nss_protocol = NFS_PROG;
                                        nss.nss_version = 4;
                                        nss.nss_flags |= NSS_FALLBACK2PMAP;
                                } else {
-                                       /* ...connect to portmapper first if we (may) need any ports. */
-                                       nss.nss_port = PMAPPORT;
-                                       nss.nss_protocol = PMAPPROG;
-                                       nss.nss_version = 0;
-                               }
+#endif
+                               /* ...connect to portmapper first if we (may) need any ports. */
+                               nss.nss_port = PMAPPORT;
+                               nss.nss_protocol = PMAPPROG;
+                               nss.nss_version = 0;
+#if CONFIG_NFS4
+                       }
+#endif
                        } else {
                                /* ...connect to NFS port first. */
                                nss.nss_port = nmp->nm_nfsport;
                                nss.nss_protocol = NFS_PROG;
                                nss.nss_version = 0;
                        }
+#if CONFIG_NFS4
                } else if (nmp->nm_vers >= NFS_VER4) {
                        if (tryv4) {
                                /* For NFSv4, we use the given (or default) port. */
@@ -1206,6 +1340,7 @@ tryagain:
                                nss.nss_protocol = PMAPPROG;
                                nss.nss_version = 0;
                        }
+#endif
                } else {
                        /* For NFSv3/v2... */
                        if (!nmp->nm_nfsport || (!NM_OMATTR_GIVEN(nmp, FH) && !nmp->nm_mountport)) {
@@ -1287,10 +1422,10 @@ keepsearching:
                            vfs_statfs(nmp->nm_mountp)->f_mntfromname);
                }
                if (fh) {
-                       FREE(fh, M_TEMP);
+                       NFS_ZFREE(nfs_fhandle_zone, fh);
                }
                if (path) {
-                       FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
+                       NFS_ZFREE(ZV_NAMEI, path);
                }
                NFS_SOCK_DBG("nfs connect %s search failed, returning %d\n",
                    vfs_statfs(nmp->nm_mountp)->f_mntfromname, error);
@@ -1304,9 +1439,14 @@ keepsearching:
        /* We may be speaking to portmap first... to determine port(s). */
        if (nso->nso_saddr->sa_family == AF_INET) {
                port = ntohs(((struct sockaddr_in*)nso->nso_saddr)->sin_port);
-       } else {
+       } else if (nso->nso_saddr->sa_family == AF_INET6) {
                port = ntohs(((struct sockaddr_in6*)nso->nso_saddr)->sin6_port);
+       } else if (nso->nso_saddr->sa_family == AF_LOCAL) {
+               if (nso->nso_protocol == PMAPPROG) {
+                       port = PMAPPORT;
+               }
        }
+
        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",
@@ -1325,29 +1465,46 @@ keepsearching:
                                ((struct sockaddr_in*)&ss)->sin_port = htons(0);
                        } else if (ss.ss_family == AF_INET6) {
                                ((struct sockaddr_in6*)&ss)->sin6_port = htons(0);
+                       } else if (ss.ss_family == AF_LOCAL) {
+                               if (((struct sockaddr_un*)&ss)->sun_path[0] == '/') {
+                                       NFS_SOCK_DBG("Looking up  NFS socket over %s\n", ((struct sockaddr_un*)&ss)->sun_path);
+                               }
                        }
                        for (; nfsvers >= (int)PVER2MAJOR(nmp->nm_min_vers); nfsvers--) {
                                if (nmp->nm_vers && nmp->nm_vers != nfsvers) {
                                        continue; /* Wrong version */
                                }
+#if CONFIG_NFS4
                                if (nfsvers == NFS_VER4 && nso->nso_sotype == SOCK_DGRAM) {
                                        continue; /* NFSv4 does not do UDP */
                                }
-                               error = nfs_portmap_lookup(nmp, vfs_context_current(), (struct sockaddr*)&ss,
-                                   nso->nso_so, NFS_PROG, nfsvers,
-                                   (nso->nso_sotype == SOCK_DGRAM) ? IPPROTO_UDP : IPPROTO_TCP, timeo);
+#endif
+                               if (ss.ss_family == AF_LOCAL && nmp->nm_nfs_localport) {
+                                       struct sockaddr_un *sun = (struct sockaddr_un *)&ss;
+                                       NFS_SOCK_DBG("Using supplied local address %s for NFS_PROG\n", nmp->nm_nfs_localport);
+                                       strlcpy(sun->sun_path, nmp->nm_nfs_localport, sizeof(sun->sun_path));
+                                       error = 0;
+                               } else {
+                                       NFS_SOCK_DBG("Calling Portmap/Rpcbind for NFS_PROG");
+                                       error = nfs_portmap_lookup(nmp, vfs_context_current(), (struct sockaddr*)&ss,
+                                           nso->nso_so, NFS_PROG, nfsvers, nso->nso_sotype, timeo);
+                               }
                                if (!error) {
                                        if (ss.ss_family == AF_INET) {
                                                port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
                                        } else if (ss.ss_family == AF_INET6) {
                                                port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port);
+                                       } else if (ss.ss_family == AF_LOCAL) {
+                                               port = ((struct sockaddr_un *)&ss)->sun_path[0] ? NFS_PORT : 0;
                                        }
                                        if (!port) {
                                                error = EPROGUNAVAIL;
                                        }
+#if CONFIG_NFS4
                                        if (port == NFS_PORT && nfsvers == NFS_VER4 && tryv4 == 0) {
                                                continue; /* We already tried this */
                                        }
+#endif
                                }
                                if (!error) {
                                        break;
@@ -1359,16 +1516,25 @@ keepsearching:
                        if (error) {
                                nfs_socket_search_update_error(&nss, error);
                                nfs_socket_destroy(nso);
+                               NFS_SOCK_DBG("Could not lookup NFS socket address for version %d error = %d\n", nfsvers, error);
                                goto keepsearching;
                        }
+               } else if (nmp->nm_nfs_localport) {
+                       strlcpy(((struct sockaddr_un*)&ss)->sun_path, nmp->nm_nfs_localport, sizeof(((struct sockaddr_un*)&ss)->sun_path));
+                       NFS_SOCK_DBG("Using supplied nfs_local_port %s for NFS_PROG\n", nmp->nm_nfs_localport);
                }
+
                /* Create NFS protocol socket and add it to the list of sockets. */
                /* N.B. If nfsvers is NFS_VER4 at this point then we're on a non standard port */
+               if (ss.ss_family == AF_LOCAL) {
+                       NFS_SOCK_DBG("Creating NFS socket for %s port = %d\n", ((struct sockaddr_un*)&ss)->sun_path, port);
+               }
                error = nfs_socket_create(nmp, (struct sockaddr*)&ss, nso->nso_sotype, port,
                    NFS_PROG, nfsvers, NMFLAG(nmp, RESVPORT), &nsonfs);
                if (error) {
                        nfs_socket_search_update_error(&nss, error);
                        nfs_socket_destroy(nso);
+                       NFS_SOCK_DBG("Could not create NFS socket: %d\n", error);
                        goto keepsearching;
                }
                nsonfs->nso_location = nso->nso_location;
@@ -1378,6 +1544,7 @@ keepsearching:
                        nfs_socket_search_update_error(&nss, error);
                        nfs_socket_destroy(nsonfs);
                        nfs_socket_destroy(nso);
+                       NFS_SOCK_DBG("Could not nfs_connect_upcall: %d", error);
                        goto keepsearching;
                }
                TAILQ_INSERT_TAIL(&nss.nss_socklist, nsonfs, nso_link);
@@ -1387,24 +1554,31 @@ keepsearching:
                        error = 0;
                        bcopy(nso->nso_saddr, &ss, nso->nso_saddr->sa_len);
                        port = nmp->nm_mountport;
+                       NFS_SOCK_DBG("mount port = %d\n", port);
                        if (ss.ss_family == AF_INET) {
                                ((struct sockaddr_in*)&ss)->sin_port = htons(port);
                        } else if (ss.ss_family == AF_INET6) {
                                ((struct sockaddr_in6*)&ss)->sin6_port = htons(port);
+                       } else if (ss.ss_family == AF_LOCAL && nmp->nm_mount_localport) {
+                               NFS_SOCK_DBG("Setting mount address to %s port = %d\n", nmp->nm_mount_localport, nmp->nm_mountport);
+                               strlcpy(((struct sockaddr_un*)&ss)->sun_path, nmp->nm_mount_localport, sizeof(((struct sockaddr_un*)&ss)->sun_path));
                        }
                        if (!port) {
                                /* Get port/sockaddr for MOUNT version corresponding to NFS version. */
                                /* If NFS version is unknown, optimistically choose for NFSv3. */
                                int mntvers = (nfsvers == NFS_VER2) ? RPCMNT_VER1 : RPCMNT_VER3;
                                int mntproto = (NM_OMFLAG(nmp, MNTUDP) || (nso->nso_sotype == SOCK_DGRAM)) ? IPPROTO_UDP : IPPROTO_TCP;
+                               NFS_SOCK_DBG("Looking up mount port with socket %p\n", nso->nso_so);
                                error = nfs_portmap_lookup(nmp, vfs_context_current(), (struct sockaddr*)&ss,
-                                   nso->nso_so, RPCPROG_MNT, mntvers, mntproto, timeo);
+                                   nso->nso_so, RPCPROG_MNT, mntvers, mntproto == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM, timeo);
                        }
                        if (!error) {
                                if (ss.ss_family == AF_INET) {
                                        port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
                                } else if (ss.ss_family == AF_INET6) {
                                        port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port);
+                               } else if (ss.ss_family == AF_LOCAL) {
+                                       port = (((struct sockaddr_un*)&ss)->sun_path[0] != '\0');
                                }
                                if (!port) {
                                        error = EPROGUNAVAIL;
@@ -1421,12 +1595,14 @@ keepsearching:
                                bcopy(&ss, nsonfs->nso_saddr2, ss.ss_len);
                        }
                        if (error) {
+                               NFS_SOCK_DBG("Could not create mount sockaet address %d", error);
                                lck_mtx_lock(&nsonfs->nso_lock);
                                nsonfs->nso_error = error;
                                nsonfs->nso_flags |= NSO_DEAD;
                                lck_mtx_unlock(&nsonfs->nso_lock);
                        }
                }
+               NFS_SOCK_DBG("Destroying socket %p so %p\n", nso, nso->nso_so);
                nfs_socket_destroy(nso);
                goto keepsearching;
        }
@@ -1443,19 +1619,23 @@ keepsearching:
                saddr = nso->nso_saddr2;
                if (!saddr) {
                        /* Need sockaddr for MOUNT port */
+                       NFS_SOCK_DBG("Getting mount address mountport = %d, mount_localport = %s\n", nmp->nm_mountport, nmp->nm_mount_localport);
                        bcopy(nso->nso_saddr, &ss, nso->nso_saddr->sa_len);
                        port = nmp->nm_mountport;
                        if (ss.ss_family == AF_INET) {
                                ((struct sockaddr_in*)&ss)->sin_port = htons(port);
                        } else if (ss.ss_family == AF_INET6) {
                                ((struct sockaddr_in6*)&ss)->sin6_port = htons(port);
+                       } else if (ss.ss_family == AF_LOCAL && nmp->nm_mount_localport) {
+                               NFS_SOCK_DBG("Setting mount address to %s port = %d\n", nmp->nm_mount_localport, nmp->nm_mountport);
+                               strlcpy(((struct sockaddr_un*)&ss)->sun_path, nmp->nm_mount_localport, sizeof(((struct sockaddr_un*)&ss)->sun_path));
                        }
                        if (!port) {
                                /* Get port/sockaddr for MOUNT version corresponding to NFS version. */
                                int mntvers = (nfsvers == NFS_VER2) ? RPCMNT_VER1 : RPCMNT_VER3;
-                               int mntproto = (NM_OMFLAG(nmp, MNTUDP) || (nso->nso_sotype == SOCK_DGRAM)) ? IPPROTO_UDP : IPPROTO_TCP;
+                               int so_type = NM_OMFLAG(nmp, MNTUDP) ? SOCK_DGRAM : nso->nso_sotype;
                                error = nfs_portmap_lookup(nmp, vfs_context_current(), (struct sockaddr*)&ss,
-                                   NULL, RPCPROG_MNT, mntvers, mntproto, timeo);
+                                   NULL, RPCPROG_MNT, mntvers, so_type, timeo);
                                if (ss.ss_family == AF_INET) {
                                        port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
                                } else if (ss.ss_family == AF_INET6) {
@@ -1470,24 +1650,30 @@ keepsearching:
                                }
                        }
                }
+               if (!error) {
+                       error = nfs3_check_lockmode(nmp, saddr, nso->nso_sotype, timeo);
+                       if (error) {
+                               nfs_socket_search_update_error(&nss, error);
+                               nfs_socket_destroy(nso);
+                               return error;
+                       }
+               }
                if (saddr) {
-                       MALLOC(fh, fhandle_t *, sizeof(fhandle_t), M_TEMP, M_WAITOK | M_ZERO);
+                       fh = zalloc(nfs_fhandle_zone);
                }
                if (saddr && fh) {
-                       MALLOC_ZONE(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
+                       path = zalloc(ZV_NAMEI);
                }
                if (!saddr || !fh || !path) {
                        if (!error) {
                                error = ENOMEM;
                        }
                        if (fh) {
-                               FREE(fh, M_TEMP);
+                               NFS_ZFREE(nfs_fhandle_zone, fh);
                        }
                        if (path) {
-                               FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
+                               NFS_ZFREE(ZV_NAMEI, path);
                        }
-                       fh = NULL;
-                       path = NULL;
                        nfs_socket_search_update_error(&nss, error);
                        nfs_socket_destroy(nso);
                        goto keepsearching;
@@ -1535,6 +1721,7 @@ keepsearching:
                                                if (found && (nmp->nm_auth == RPCAUTH_NONE)) {
                                                        found = 0;
                                                }
+                                               OS_FALLTHROUGH;
                                        case RPCAUTH_NONE:
                                        case RPCAUTH_KRB5:
                                        case RPCAUTH_KRB5I:
@@ -1549,17 +1736,15 @@ keepsearching:
                        }
                        error = !found ? EAUTH : 0;
                }
-               FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
-               path = NULL;
+               NFS_ZFREE(ZV_NAMEI, path);
                if (error) {
                        nfs_socket_search_update_error(&nss, error);
-                       FREE(fh, M_TEMP);
-                       fh = NULL;
+                       NFS_ZFREE(nfs_fhandle_zone, fh);
                        nfs_socket_destroy(nso);
                        goto keepsearching;
                }
                if (nmp->nm_fh) {
-                       FREE(nmp->nm_fh, M_TEMP);
+                       NFS_ZFREE(nfs_fhandle_zone, nmp->nm_fh);
                }
                nmp->nm_fh = fh;
                fh = NULL;
@@ -1588,6 +1773,7 @@ keepsearching:
                }
                if (!nmp->nm_vers) {
                        nmp->nm_vers = nfsvers;
+#if CONFIG_NFS4
                        /* If we negotiated NFSv4, set nm_nfsport if we ended up on the standard NFS port */
                        if ((nfsvers >= NFS_VER4) && !NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_NFS_PORT)) {
                                if (nso->nso_saddr->sa_family == AF_INET) {
@@ -1601,7 +1787,9 @@ keepsearching:
                                        nmp->nm_nfsport = NFS_PORT;
                                }
                        }
+#endif
                }
+#if CONFIG_NFS4
                /* do some version-specific pre-mount set up */
                if (nmp->nm_vers >= NFS_VER4) {
                        microtime(&now);
@@ -1610,6 +1798,7 @@ keepsearching:
                                nfs4_mount_callback_setup(nmp);
                        }
                }
+#endif
        }
 
        /* Initialize NFS socket state variables */
@@ -1648,21 +1837,21 @@ keepsearching:
                        if (!NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_SOCKET_TYPE)) {
                                nmp->nm_sotype = 0;
                        }
-                       if (!NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_NFS_VERSION)) {
-                               if (nmp->nm_vers >= NFS_VER4) {
-                                       if (!NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_NFS_PORT)) {
-                                               nmp->nm_nfsport = 0;
-                                       }
-                                       if (nmp->nm_cbid) {
-                                               nfs4_mount_callback_shutdown(nmp);
-                                       }
-                                       if (IS_VALID_CRED(nmp->nm_mcred)) {
-                                               kauth_cred_unref(&nmp->nm_mcred);
-                                       }
-                                       bzero(&nmp->nm_un, sizeof(nmp->nm_un));
+#if CONFIG_NFS4
+                       if (nmp->nm_vers >= NFS_VER4) {
+                               if (!NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_NFS_PORT)) {
+                                       nmp->nm_nfsport = 0;
+                               }
+                               if (nmp->nm_cbid) {
+                                       nfs4_mount_callback_shutdown(nmp);
                                }
-                               nmp->nm_vers = 0;
+                               if (IS_VALID_CRED(nmp->nm_mcred)) {
+                                       kauth_cred_unref(&nmp->nm_mcred);
+                               }
+                               bzero(&nmp->nm_un, sizeof(nmp->nm_un));
                        }
+#endif
+                       nmp->nm_vers = 0;
                }
                lck_mtx_unlock(&nmp->nm_lock);
                nmp->nm_nso = NULL;
@@ -1697,10 +1886,10 @@ keepsearching:
        nmp->nm_nss = NULL;
        nfs_socket_search_cleanup(&nss);
        if (fh) {
-               FREE(fh, M_TEMP);
+               NFS_ZFREE(nfs_fhandle_zone, fh);
        }
        if (path) {
-               FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
+               NFS_ZFREE(ZV_NAMEI, path);
        }
        NFS_SOCK_DBG("nfs connect %s success\n", vfs_statfs(nmp->nm_mountp)->f_mntfromname);
        return 0;
@@ -1709,10 +1898,14 @@ keepsearching:
 
 /* setup & confirm socket connection is functional */
 int
-nfs_connect_setup(struct nfsmount *nmp)
+nfs_connect_setup(
+#if !CONFIG_NFS4
+       __unused
+#endif
+       struct nfsmount *nmp)
 {
        int error = 0;
-
+#if CONFIG_NFS4
        if (nmp->nm_vers >= NFS_VER4) {
                if (nmp->nm_state & NFSSTA_CLIENTID) {
                        /* first, try to renew our current state */
@@ -1729,6 +1922,7 @@ nfs_connect_setup(struct nfsmount *nmp)
                }
                error = nfs4_setclientid(nmp);
        }
+#endif
        return error;
 }
 
@@ -1810,7 +2004,7 @@ nfs_reconnect(struct nfsmount *nmp)
         * as needing a resend.  (Though nfs_need_reconnect() probably
         * marked them all already.)
         */
-       lck_mtx_lock(nfs_request_mutex);
+       lck_mtx_lock(&nfs_request_mutex);
        TAILQ_FOREACH(rq, &nfs_reqq, r_chain) {
                if (rq->r_nmp == nmp) {
                        lck_mtx_lock(&rq->r_mtx);
@@ -1825,7 +2019,7 @@ nfs_reconnect(struct nfsmount *nmp)
                        lck_mtx_unlock(&rq->r_mtx);
                }
        }
-       lck_mtx_unlock(nfs_request_mutex);
+       lck_mtx_unlock(&nfs_request_mutex);
        return 0;
 }
 
@@ -1840,7 +2034,7 @@ nfs_disconnect(struct nfsmount *nmp)
        lck_mtx_lock(&nmp->nm_lock);
 tryagain:
        if (nmp->nm_nso) {
-               struct timespec ts = { 1, 0 };
+               struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
                if (nmp->nm_state & NFSSTA_SENDING) { /* wait for sending to complete */
                        nmp->nm_state |= NFSSTA_WANTSND;
                        msleep(&nmp->nm_state, &nmp->nm_lock, PZERO - 1, "nfswaitsending", &ts);
@@ -1883,7 +2077,7 @@ nfs_need_reconnect(struct nfsmount *nmp)
         * Loop through outstanding request list and
         * mark all requests as needing a resend.
         */
-       lck_mtx_lock(nfs_request_mutex);
+       lck_mtx_lock(&nfs_request_mutex);
        TAILQ_FOREACH(rq, &nfs_reqq, r_chain) {
                if (rq->r_nmp == nmp) {
                        lck_mtx_lock(&rq->r_mtx);
@@ -1898,7 +2092,7 @@ nfs_need_reconnect(struct nfsmount *nmp)
                        lck_mtx_unlock(&rq->r_mtx);
                }
        }
-       lck_mtx_unlock(nfs_request_mutex);
+       lck_mtx_unlock(&nfs_request_mutex);
 }
 
 
@@ -1909,7 +2103,7 @@ void
 nfs_mount_sock_thread(void *arg, __unused wait_result_t wr)
 {
        struct nfsmount *nmp = arg;
-       struct timespec ts = { 30, 0 };
+       struct timespec ts = { .tv_sec = 30, .tv_nsec = 0 };
        thread_t thd = current_thread();
        struct nfsreq *req;
        struct timeval now;
@@ -1949,7 +2143,7 @@ nfs_mount_sock_thread(void *arg, __unused wait_result_t wr)
                                if (error == EIO || error == EINTR) {
                                        lvl = (do_reconnect_sleep++ % 600) ? 7 : 0;
                                }
-                               nfs_printf(NFS_FAC_SOCK, lvl, "nfs reconnect %s: returned %d\n",
+                               NFS_DBG(NFS_FAC_SOCK, lvl, "nfs reconnect %s: returned %d\n",
                                    vfs_statfs(nmp->nm_mountp)->f_mntfromname, error);
                        } else {
                                nmp->nm_reconnect_start = 0;
@@ -1966,6 +2160,7 @@ nfs_mount_sock_thread(void *arg, __unused wait_result_t wr)
                        nfs_recover(nmp);
                        lck_mtx_lock(&nmp->nm_lock);
                }
+#if CONFIG_NFS4
                /* handle NFSv4 delegation returns */
                while ((nmp->nm_vers >= NFS_VER4) && !(nmp->nm_state & (NFSSTA_FORCE | NFSSTA_DEAD)) &&
                    (nmp->nm_sockflags & NMSOCK_READY) && !(nmp->nm_state & NFSSTA_RECOVER) &&
@@ -1974,6 +2169,7 @@ nfs_mount_sock_thread(void *arg, __unused wait_result_t wr)
                        nfs4_delegation_return(np, R_RECOVER, thd, nmp->nm_mcred);
                        lck_mtx_lock(&nmp->nm_lock);
                }
+#endif
                /* do resends, if necessary/possible */
                while ((((nmp->nm_sockflags & NMSOCK_READY) && !(nmp->nm_state & NFSSTA_RECOVER)) ||
                    (nmp->nm_state & (NFSSTA_FORCE | NFSSTA_DEAD))) &&
@@ -1987,14 +2183,21 @@ nfs_mount_sock_thread(void *arg, __unused wait_result_t wr)
                        if (!req) {
                                break;
                        }
+                       /* acquire both locks in the right order: first req->r_mtx and then nmp->nm_lock */
+                       lck_mtx_unlock(&nmp->nm_lock);
+                       lck_mtx_lock(&req->r_mtx);
+                       lck_mtx_lock(&nmp->nm_lock);
+                       if ((req->r_flags & R_RESENDQ) == 0 || (req->r_rchain.tqe_next == NFSREQNOLIST)) {
+                               lck_mtx_unlock(&req->r_mtx);
+                               continue;
+                       }
                        TAILQ_REMOVE(&nmp->nm_resendq, req, r_rchain);
+                       req->r_flags &= ~R_RESENDQ;
                        req->r_rchain.tqe_next = NFSREQNOLIST;
                        lck_mtx_unlock(&nmp->nm_lock);
-                       lck_mtx_lock(&req->r_mtx);
                        /* Note that we have a reference on the request that was taken nfs_asyncio_resend */
                        if (req->r_error || req->r_nmrep.nmc_mhead) {
                                dofinish = req->r_callback.rcb_func && !(req->r_flags & R_WAITSENT);
-                               req->r_flags &= ~R_RESENDQ;
                                wakeup(req);
                                lck_mtx_unlock(&req->r_mtx);
                                if (dofinish) {
@@ -2010,6 +2213,7 @@ nfs_mount_sock_thread(void *arg, __unused wait_result_t wr)
                                lck_mtx_unlock(&req->r_mtx);
                                /* async RPCs on GSS mounts need to be rebuilt and resent. */
                                nfs_reqdequeue(req);
+#if CONFIG_NFS_GSS
                                if (nfs_request_using_gss(req)) {
                                        nfs_gss_clnt_rpcdone(req);
                                        error = nfs_gss_clnt_args_restore(req);
@@ -2017,6 +2221,7 @@ nfs_mount_sock_thread(void *arg, __unused wait_result_t wr)
                                                req->r_xid = 0;
                                        }
                                }
+#endif /* CONFIG_NFS_GSS */
                                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);
@@ -2028,9 +2233,6 @@ nfs_mount_sock_thread(void *arg, __unused wait_result_t wr)
                                        error = nfs_request_send(req, 0);
                                }
                                lck_mtx_lock(&req->r_mtx);
-                               if (req->r_flags & R_RESENDQ) {
-                                       req->r_flags &= ~R_RESENDQ;
-                               }
                                if (error) {
                                        req->r_error = error;
                                }
@@ -2054,9 +2256,6 @@ nfs_mount_sock_thread(void *arg, __unused wait_result_t wr)
                                error = nfs_send(req, 0);
                                lck_mtx_lock(&req->r_mtx);
                                if (!error) {
-                                       if (req->r_flags & R_RESENDQ) {
-                                               req->r_flags &= ~R_RESENDQ;
-                                       }
                                        wakeup(req);
                                        lck_mtx_unlock(&req->r_mtx);
                                        nfs_request_rele(req);
@@ -2065,9 +2264,6 @@ nfs_mount_sock_thread(void *arg, __unused wait_result_t wr)
                                }
                        }
                        req->r_error = error;
-                       if (req->r_flags & R_RESENDQ) {
-                               req->r_flags &= ~R_RESENDQ;
-                       }
                        wakeup(req);
                        dofinish = req->r_callback.rcb_func && !(req->r_flags & R_WAITSENT);
                        lck_mtx_unlock(&req->r_mtx);
@@ -2227,6 +2423,7 @@ struct nfs_callback_socket {
 #define NCBSOCK_UPCALLWANT      0x0002
 #define NCBSOCK_DEAD            0x0004
 
+#if CONFIG_NFS4
 /*
  * NFS callback channel state
  *
@@ -2264,7 +2461,7 @@ nfs4_mount_callback_setup(struct nfsmount *nmp)
        int error, on = 1;
        in_port_t port;
 
-       lck_mtx_lock(nfs_global_mutex);
+       lck_mtx_lock(&nfs_global_mutex);
        if (nfs4_cb_id == 0) {
                TAILQ_INIT(&nfs4_cb_mounts);
                TAILQ_INIT(&nfs4_cb_socks);
@@ -2278,7 +2475,7 @@ nfs4_mount_callback_setup(struct nfsmount *nmp)
        TAILQ_INSERT_HEAD(&nfs4_cb_mounts, nmp, nm_cblink);
 
        if (nfs4_cb_so) {
-               lck_mtx_unlock(nfs_global_mutex);
+               lck_mtx_unlock(&nfs_global_mutex);
                return;
        }
 
@@ -2290,11 +2487,17 @@ nfs4_mount_callback_setup(struct nfsmount *nmp)
        }
        so = nfs4_cb_so;
 
+       if (NFS_PORT_INVALID(nfs_callback_port)) {
+               error = EINVAL;
+               log(LOG_INFO, "nfs callback setup: error %d nfs_callback_port %d is not valid\n", error, nfs_callback_port);
+               goto fail;
+       }
+
        sock_setsockopt(so, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
        sin.sin_len = sizeof(struct sockaddr_in);
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = htonl(INADDR_ANY);
-       sin.sin_port = htons(nfs_callback_port); /* try to use specified port */
+       sin.sin_port = htons((in_port_t)nfs_callback_port); /* try to use specified port */
        error = sock_bind(so, (struct sockaddr *)&sin);
        if (error) {
                log(LOG_INFO, "nfs callback setup: error %d binding listening IPv4 socket\n", error);
@@ -2340,7 +2543,7 @@ nfs4_mount_callback_setup(struct nfsmount *nmp)
        sock_setsockopt(so6, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
        sock_setsockopt(so6, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
        /* try to use specified port or same port as IPv4 */
-       port = nfs_callback_port ? nfs_callback_port : nfs4_cb_port;
+       port = nfs_callback_port ? (in_port_t)nfs_callback_port : nfs4_cb_port;
 ipv6_bind_again:
        sin6.sin6_len = sizeof(struct sockaddr_in6);
        sin6.sin6_family = AF_INET6;
@@ -2388,7 +2591,7 @@ ipv6_bind_again:
 fail:
        if (error) {
                nfs4_cb_so = nfs4_cb_so6 = NULL;
-               lck_mtx_unlock(nfs_global_mutex);
+               lck_mtx_unlock(&nfs_global_mutex);
                if (so) {
                        sock_shutdown(so, SHUT_RDWR);
                        sock_close(so);
@@ -2398,7 +2601,7 @@ fail:
                        sock_close(so6);
                }
        } else {
-               lck_mtx_unlock(nfs_global_mutex);
+               lck_mtx_unlock(&nfs_global_mutex);
        }
 }
 
@@ -2415,17 +2618,21 @@ nfs4_mount_callback_shutdown(struct nfsmount *nmp)
        struct nfs_callback_socket *ncbsp;
        socket_t so, so6;
        struct nfs4_cb_sock_list cb_socks;
-       struct timespec ts = {1, 0};
+       struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
 
-       lck_mtx_lock(nfs_global_mutex);
+       lck_mtx_lock(&nfs_global_mutex);
+       if (nmp->nm_cbid == 0) {
+               lck_mtx_unlock(&nfs_global_mutex);
+               return;
+       }
        TAILQ_REMOVE(&nfs4_cb_mounts, nmp, nm_cblink);
        /* wait for any callbacks in progress to complete */
        while (nmp->nm_cbrefs) {
-               msleep(&nmp->nm_cbrefs, nfs_global_mutex, PSOCK, "cbshutwait", &ts);
+               msleep(&nmp->nm_cbrefs, &nfs_global_mutex, PSOCK, "cbshutwait", &ts);
        }
        nmp->nm_cbid = 0;
        if (--nfs4_cb_so_usecount) {
-               lck_mtx_unlock(nfs_global_mutex);
+               lck_mtx_unlock(&nfs_global_mutex);
                return;
        }
        so = nfs4_cb_so;
@@ -2433,7 +2640,7 @@ nfs4_mount_callback_shutdown(struct nfsmount *nmp)
        nfs4_cb_so = nfs4_cb_so6 = NULL;
        TAILQ_INIT(&cb_socks);
        TAILQ_CONCAT(&cb_socks, &nfs4_cb_socks, ncbs_link);
-       lck_mtx_unlock(nfs_global_mutex);
+       lck_mtx_unlock(&nfs_global_mutex);
        if (so) {
                sock_shutdown(so, SHUT_RDWR);
                sock_close(so);
@@ -2463,10 +2670,10 @@ nfs4_callback_timer(__unused void *param0, __unused void *param1)
        struct timeval now;
 
 loop:
-       lck_mtx_lock(nfs_global_mutex);
+       lck_mtx_lock(&nfs_global_mutex);
        if (TAILQ_EMPTY(&nfs4_cb_socks)) {
                nfs4_callback_timer_on = 0;
-               lck_mtx_unlock(nfs_global_mutex);
+               lck_mtx_unlock(&nfs_global_mutex);
                return;
        }
        microuptime(&now);
@@ -2476,7 +2683,7 @@ loop:
                        continue;
                }
                TAILQ_REMOVE(&nfs4_cb_socks, ncbsp, ncbs_link);
-               lck_mtx_unlock(nfs_global_mutex);
+               lck_mtx_unlock(&nfs_global_mutex);
                sock_shutdown(ncbsp->ncbs_so, SHUT_RDWR);
                sock_close(ncbsp->ncbs_so);
                nfs_rpc_record_state_cleanup(&ncbsp->ncbs_rrs);
@@ -2486,7 +2693,7 @@ loop:
        nfs4_callback_timer_on = 1;
        nfs_interval_timer_start(nfs4_callback_timer_call,
            NFS4_CB_TIMER_PERIOD * 1000);
-       lck_mtx_unlock(nfs_global_mutex);
+       lck_mtx_unlock(&nfs_global_mutex);
 }
 
 /*
@@ -2550,7 +2757,7 @@ nfs4_cb_accept(socket_t so, __unused void *arg, __unused int waitflag)
        microuptime(&now);
        ncbsp->ncbs_stamp = now.tv_sec;
 
-       lck_mtx_lock(nfs_global_mutex);
+       lck_mtx_lock(&nfs_global_mutex);
 
        /* add it to the list */
        TAILQ_INSERT_HEAD(&nfs4_cb_socks, ncbsp, ncbs_link);
@@ -2581,7 +2788,7 @@ nfs4_cb_accept(socket_t so, __unused void *arg, __unused int waitflag)
                nfs_interval_timer_start(nfs4_callback_timer_call, 500);
        }
 
-       lck_mtx_unlock(nfs_global_mutex);
+       lck_mtx_unlock(&nfs_global_mutex);
 }
 
 /*
@@ -2592,19 +2799,19 @@ void
 nfs4_cb_rcv(socket_t so, void *arg, __unused int waitflag)
 {
        struct nfs_callback_socket *ncbsp = arg;
-       struct timespec ts = {1, 0};
+       struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
        struct timeval now;
        mbuf_t m;
        int error = 0, recv = 1;
 
-       lck_mtx_lock(nfs_global_mutex);
+       lck_mtx_lock(&nfs_global_mutex);
        while (ncbsp->ncbs_flags & NCBSOCK_UPCALL) {
                /* wait if upcall is already in progress */
                ncbsp->ncbs_flags |= NCBSOCK_UPCALLWANT;
-               msleep(ncbsp, nfs_global_mutex, PSOCK, "cbupcall", &ts);
+               msleep(ncbsp, &nfs_global_mutex, PSOCK, "cbupcall", &ts);
        }
        ncbsp->ncbs_flags |= NCBSOCK_UPCALL;
-       lck_mtx_unlock(nfs_global_mutex);
+       lck_mtx_unlock(&nfs_global_mutex);
 
        /* loop while we make error-free progress */
        while (!error && recv) {
@@ -2628,9 +2835,9 @@ nfs4_cb_rcv(socket_t so, void *arg, __unused int waitflag)
                ncbsp->ncbs_stamp = now.tv_sec;
        }
 
-       lck_mtx_lock(nfs_global_mutex);
+       lck_mtx_lock(&nfs_global_mutex);
        ncbsp->ncbs_flags &= ~NCBSOCK_UPCALL;
-       lck_mtx_unlock(nfs_global_mutex);
+       lck_mtx_unlock(&nfs_global_mutex);
        wakeup(ncbsp);
 }
 
@@ -2645,7 +2852,7 @@ nfs4_cb_handler(struct nfs_callback_socket *ncbsp, mbuf_t mreq)
        mbuf_t mhead = NULL, mrest = NULL, m;
        struct msghdr msg;
        struct nfsmount *nmp;
-       fhandle_t fh;
+       fhandle_t *fh;
        nfsnode_t np;
        nfs_stateid stateid;
        uint32_t bitmap[NFS_ATTR_BITMAP_LEN], rbitmap[NFS_ATTR_BITMAP_LEN], bmlen, truncate, attrbytes;
@@ -2656,6 +2863,7 @@ nfs4_cb_handler(struct nfs_callback_socket *ncbsp, mbuf_t mreq)
        size_t sentlen = 0;
 
        xid = numops = op = status = procnum = taglen = cbid = 0;
+       fh = zalloc(nfs_fhandle_zone);
 
        nfsm_chain_dissect_init(error, &nmreq, mreq);
        nfsm_chain_get_32(error, &nmreq, xid);          // RPC XID
@@ -2732,7 +2940,7 @@ nfs4_cb_handler(struct nfs_callback_socket *ncbsp, mbuf_t mreq)
                        goto nfsmout;
                }
                /* match the callback ID to a registered mount */
-               lck_mtx_lock(nfs_global_mutex);
+               lck_mtx_lock(&nfs_global_mutex);
                TAILQ_FOREACH(nmp, &nfs4_cb_mounts, nm_cblink) {
                        if (nmp->nm_cbid != cbid) {
                                continue;
@@ -2749,7 +2957,7 @@ nfs4_cb_handler(struct nfs_callback_socket *ncbsp, mbuf_t mreq)
                if (nmp) {
                        nmp->nm_cbrefs++;
                }
-               lck_mtx_unlock(nfs_global_mutex);
+               lck_mtx_unlock(&nfs_global_mutex);
                if (!nmp) {
                        /* if no mount match, just drop socket. */
                        error = EPERM;
@@ -2768,7 +2976,7 @@ nfs4_cb_handler(struct nfs_callback_socket *ncbsp, mbuf_t mreq)
                        case NFS_OP_CB_GETATTR:
                                // (FH, BITMAP) -> (STATUS, BITMAP, ATTRS)
                                np = NULL;
-                               nfsm_chain_get_fh(error, &nmreq, NFS_VER4, &fh);
+                               nfsm_chain_get_fh(error, &nmreq, NFS_VER4, fh);
                                bmlen = NFS_ATTR_BITMAP_LEN;
                                nfsm_chain_get_bitmap(error, &nmreq, bitmap, bmlen);
                                if (error) {
@@ -2777,7 +2985,7 @@ nfs4_cb_handler(struct nfs_callback_socket *ncbsp, mbuf_t mreq)
                                        numops = 0; /* don't process any more ops */
                                } else {
                                        /* find the node for the file handle */
-                                       error = nfs_nget(nmp->nm_mountp, NULL, NULL, fh.fh_data, fh.fh_len, NULL, NULL, RPCAUTH_UNKNOWN, NG_NOCREATE, &np);
+                                       error = nfs_nget(nmp->nm_mountp, NULL, NULL, fh->fh_data, fh->fh_len, NULL, NULL, RPCAUTH_UNKNOWN, NG_NOCREATE, &np);
                                        if (error || !np) {
                                                status = NFSERR_BADHANDLE;
                                                error = 0;
@@ -2834,14 +3042,14 @@ nfs4_cb_handler(struct nfs_callback_socket *ncbsp, mbuf_t mreq)
                                np = NULL;
                                nfsm_chain_get_stateid(error, &nmreq, &stateid);
                                nfsm_chain_get_32(error, &nmreq, truncate);
-                               nfsm_chain_get_fh(error, &nmreq, NFS_VER4, &fh);
+                               nfsm_chain_get_fh(error, &nmreq, NFS_VER4, fh);
                                if (error) {
                                        status = error;
                                        error = 0;
                                        numops = 0; /* don't process any more ops */
                                } else {
                                        /* find the node for the file handle */
-                                       error = nfs_nget(nmp->nm_mountp, NULL, NULL, fh.fh_data, fh.fh_len, NULL, NULL, RPCAUTH_UNKNOWN, NG_NOCREATE, &np);
+                                       error = nfs_nget(nmp->nm_mountp, NULL, NULL, fh->fh_data, fh->fh_len, NULL, NULL, RPCAUTH_UNKNOWN, NG_NOCREATE, &np);
                                        if (error || !np) {
                                                status = NFSERR_BADHANDLE;
                                                error = 0;
@@ -2895,12 +3103,12 @@ nfs4_cb_handler(struct nfs_callback_socket *ncbsp, mbuf_t mreq)
                nfsm_chain_null(&nmrep);
 
                /* drop the callback reference on the mount */
-               lck_mtx_lock(nfs_global_mutex);
+               lck_mtx_lock(&nfs_global_mutex);
                nmp->nm_cbrefs--;
                if (!nmp->nm_cbid) {
                        wakeup(&nmp->nm_cbrefs);
                }
-               lck_mtx_unlock(nfs_global_mutex);
+               lck_mtx_unlock(&nfs_global_mutex);
                break;
        }
 
@@ -2999,9 +3207,10 @@ out:
        if (mreq) {
                mbuf_freem(mreq);
        }
+       NFS_ZFREE(nfs_fhandle_zone, fh);
        return error;
 }
-
+#endif /* CONFIG_NFS4 */
 
 /*
  * Initialize an nfs_rpc_record_state structure.
@@ -3155,7 +3364,7 @@ nfs_send(struct nfsreq *req, int wait)
        struct sockaddr *sendnam;
        mbuf_t mreqcopy;
        size_t sentlen = 0;
-       struct timespec ts = { 2, 0 };
+       struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
 
 again:
        error = nfs_sndlock(req);
@@ -3345,6 +3554,7 @@ again:
                msg.msg_name = (caddr_t)sendnam;
                msg.msg_namelen = sendnam->sa_len;
        }
+       NFS_SOCK_DUMP_MBUF("Sending mbuf\n", mreqcopy);
        error = sock_sendmbuf(nso->nso_so, &msg, mreqcopy, 0, &sentlen);
        if (error || (sentlen != req->r_mreqlen)) {
                NFS_SOCK_DBG("nfs_send: 0x%llx sent %d/%d error %d\n",
@@ -3419,6 +3629,7 @@ again:
                if (sotype != SOCK_STREAM) {
                        break;
                }
+               OS_FALLTHROUGH;
        case EPIPE:
        case EADDRNOTAVAIL:
        case ENETDOWN:
@@ -3647,6 +3858,7 @@ nfs_request_match_reply(struct nfsmount *nmp, mbuf_t mrep)
        u_int32_t reply = 0, rxid = 0;
        int error = 0, asyncioq, t1;
 
+       bzero(&nmrep, sizeof(nmrep));
        /* Get the xid and check that it is an rpc reply */
        nfsm_chain_dissect_init(error, &nmrep, mrep);
        nfsm_chain_get_32(error, &nmrep, rxid);
@@ -3661,7 +3873,7 @@ nfs_request_match_reply(struct nfsmount *nmp, mbuf_t mrep)
         * Loop through the request list to match up the reply
         * Iff no match, just drop it.
         */
-       lck_mtx_lock(nfs_request_mutex);
+       lck_mtx_lock(&nfs_request_mutex);
        TAILQ_FOREACH(req, &nfs_reqq, r_chain) {
                if (req->r_nmrep.nmc_mhead || (rxid != R_XID32(req->r_xid))) {
                        continue;
@@ -3731,11 +3943,13 @@ nfs_request_match_reply(struct nfsmount *nmp, mbuf_t mrep)
                /* signal anyone waiting on this request */
                wakeup(req);
                asyncioq = (req->r_callback.rcb_func != NULL);
+#if CONFIG_NFS_GSS
                if (nfs_request_using_gss(req)) {
                        nfs_gss_clnt_rpcdone(req);
                }
+#endif /* CONFIG_NFS_GSS */
                lck_mtx_unlock(&req->r_mtx);
-               lck_mtx_unlock(nfs_request_mutex);
+               lck_mtx_unlock(&nfs_request_mutex);
                /* if it's an async RPC with a callback, queue it up */
                if (asyncioq) {
                        nfs_asyncio_finish(req);
@@ -3745,7 +3959,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);
+               lck_mtx_unlock(&nfs_request_mutex);
                OSAddAtomic64(1, &nfsstats.rpcunexpected);
                mbuf_freem(mrep);
        }
@@ -3758,7 +3972,7 @@ nfs_request_match_reply(struct nfsmount *nmp, mbuf_t mrep)
 int
 nfs_wait_reply(struct nfsreq *req)
 {
-       struct timespec ts = { 2, 0 };
+       struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
        int error = 0, slpflag, first = 1;
 
        if (req->r_nmp && NMFLAG(req->r_nmp, INTR) && req->r_thread && !(req->r_flags & R_NOINTR)) {
@@ -3857,16 +4071,10 @@ nfs_request_create(
        req = *reqp;
        if (!req) {
                /* allocate a new NFS request structure */
-               MALLOC_ZONE(newreq, struct nfsreq*, sizeof(*newreq), M_NFSREQ, M_WAITOK);
-               if (!newreq) {
-                       mbuf_freem(nmrest->nmc_mhead);
-                       nmrest->nmc_mhead = NULL;
-                       return ENOMEM;
-               }
-               req = newreq;
+               req = newreq = zalloc_flags(nfs_req_zone, Z_WAITOK | Z_ZERO);
+       } else {
+               bzero(req, sizeof(*req));
        }
-
-       bzero(req, sizeof(*req));
        if (req == newreq) {
                req->r_flags = R_ALLOCATED;
        }
@@ -3874,7 +4082,7 @@ nfs_request_create(
        nmp = VFSTONFS(np ? NFSTOMP(np) : mp);
        if (nfs_mount_gone(nmp)) {
                if (newreq) {
-                       FREE_ZONE(newreq, sizeof(*newreq), M_NFSREQ);
+                       NFS_ZFREE(nfs_req_zone, newreq);
                }
                return ENXIO;
        }
@@ -3885,7 +4093,7 @@ nfs_request_create(
                mbuf_freem(nmrest->nmc_mhead);
                nmrest->nmc_mhead = NULL;
                if (newreq) {
-                       FREE_ZONE(newreq, sizeof(*newreq), M_NFSREQ);
+                       NFS_ZFREE(nfs_req_zone, newreq);
                }
                return ENXIO;
        }
@@ -3897,7 +4105,7 @@ nfs_request_create(
                panic("nfs_request: invalid NFSv4 RPC request %d\n", procnum);
        }
 
-       lck_mtx_init(&req->r_mtx, nfs_request_grp, LCK_ATTR_NULL);
+       lck_mtx_init(&req->r_mtx, &nfs_request_grp, LCK_ATTR_NULL);
        req->r_nmp = nmp;
        nmp->nm_ref++;
        req->r_np = np;
@@ -3949,9 +4157,12 @@ void
 nfs_request_destroy(struct nfsreq *req)
 {
        struct nfsmount *nmp;
-       struct gss_seq *gsp, *ngsp;
        int clearjbtimeo = 0;
 
+#if CONFIG_NFS_GSS
+       struct gss_seq *gsp, *ngsp;
+#endif
+
        if (!req || !(req->r_flags & R_INITTED)) {
                return;
        }
@@ -3966,12 +4177,12 @@ nfs_request_destroy(struct nfsreq *req)
                 * Still on an async I/O queue?
                 * %%% But which one, we may be on a local iod.
                 */
-               lck_mtx_lock(nfsiod_mutex);
+               lck_mtx_lock(&nfsiod_mutex);
                if (nmp && req->r_achain.tqe_next != NFSREQNOLIST) {
                        TAILQ_REMOVE(&nmp->nm_iodq, req, r_achain);
                        req->r_achain.tqe_next = NFSREQNOLIST;
                }
-               lck_mtx_unlock(nfsiod_mutex);
+               lck_mtx_unlock(&nfsiod_mutex);
        }
 
        lck_mtx_lock(&req->r_mtx);
@@ -3989,14 +4200,11 @@ nfs_request_destroy(struct nfsreq *req)
                                wakeup(req2);
                        }
                }
-               assert((req->r_flags & R_RESENDQ) == 0);
                /* XXX should we just remove this conditional, we should have a reference if we're resending */
-               if (req->r_rchain.tqe_next != NFSREQNOLIST) {
+               if ((req->r_flags & R_RESENDQ) && req->r_rchain.tqe_next != NFSREQNOLIST) {
                        TAILQ_REMOVE(&nmp->nm_resendq, req, r_rchain);
+                       req->r_flags &= ~R_RESENDQ;
                        req->r_rchain.tqe_next = NFSREQNOLIST;
-                       if (req->r_flags & R_RESENDQ) {
-                               req->r_flags &= ~R_RESENDQ;
-                       }
                }
                if (req->r_cchain.tqe_next != NFSREQNOLIST) {
                        TAILQ_REMOVE(&nmp->nm_cwndq, req, r_cchain);
@@ -4025,6 +4233,7 @@ nfs_request_destroy(struct nfsreq *req)
        if (IS_VALID_CRED(req->r_cred)) {
                kauth_cred_unref(&req->r_cred);
        }
+#if CONFIG_NFS_GSS
        if (nfs_request_using_gss(req)) {
                nfs_gss_clnt_rpcdone(req);
        }
@@ -4033,15 +4242,16 @@ nfs_request_destroy(struct nfsreq *req)
        if (req->r_gss_ctx) {
                nfs_gss_clnt_ctx_unref(req);
        }
+#endif /* CONFIG_NFS_GSS */
        if (req->r_wrongsec) {
                FREE(req->r_wrongsec, M_TEMP);
        }
        if (nmp) {
                nfs_mount_rele(nmp);
        }
-       lck_mtx_destroy(&req->r_mtx, nfs_request_grp);
+       lck_mtx_destroy(&req->r_mtx, &nfs_request_grp);
        if (req->r_flags & R_ALLOCATED) {
-               FREE_ZONE(req, sizeof(*req), M_NFSREQ);
+               NFS_ZFREE(nfs_req_zone, req);
        }
 }
 
@@ -4136,11 +4346,11 @@ nfs_request_send(struct nfsreq *req, int wait)
        req->r_flags |= R_SENDING;
        lck_mtx_unlock(&req->r_mtx);
 
-       lck_mtx_lock(nfs_request_mutex);
+       lck_mtx_lock(&nfs_request_mutex);
 
        nmp = req->r_nmp;
        if (nfs_mount_gone(nmp)) {
-               lck_mtx_unlock(nfs_request_mutex);
+               lck_mtx_unlock(&nfs_request_mutex);
                return ENXIO;
        }
 
@@ -4153,6 +4363,18 @@ nfs_request_send(struct nfsreq *req, int wait)
 
        OSAddAtomic64(1, &nfsstats.rpcrequests);
 
+       /*
+        * Make sure the request is not in the queue.
+        */
+       if (req->r_lflags & RL_QUEUED) {
+#if DEVELOPMENT
+               panic("nfs_request_send: req %p is already in global requests queue", req);
+#else
+               TAILQ_REMOVE(&nfs_reqq, req, r_chain);
+               req->r_lflags &= ~RL_QUEUED;
+#endif /* DEVELOPMENT */
+       }
+
        /*
         * Chain request into list of outstanding requests. Be sure
         * to put it LAST so timer finds oldest requests first.
@@ -4166,7 +4388,7 @@ nfs_request_send(struct nfsreq *req, int wait)
                nfs_interval_timer_start(nfs_request_timer_call,
                    NFS_REQUESTDELAY);
        }
-       lck_mtx_unlock(nfs_request_mutex);
+       lck_mtx_unlock(&nfs_request_mutex);
 
        /* Send the request... */
        return nfs_send(req, wait);
@@ -4233,6 +4455,7 @@ nfs_request_finish(
                lck_mtx_unlock(&nmp->nm_lock);
        }
 
+#if CONFIG_NFS_GSS
        if (nfs_request_using_gss(req)) {
                /*
                 * If the request used an RPCSEC_GSS credential
@@ -4261,6 +4484,7 @@ nfs_request_finish(
                        goto nfsmout;
                }
        }
+#endif /* CONFIG_NFS_GSS */
 
        /*
         * If there was a successful reply, make sure to mark the mount as up.
@@ -4297,6 +4521,7 @@ nfs_request_finish(
                nfsm_chain_get_32(error, &nmrep, auth_status);
                nfsmout_if(error);
                switch (auth_status) {
+#if CONFIG_NFS_GSS
                case RPCSEC_GSS_CREDPROBLEM:
                case RPCSEC_GSS_CTXPROBLEM:
                        /*
@@ -4321,6 +4546,7 @@ nfs_request_finish(
                        req->r_xid = 0;         // get a new XID
                        req->r_flags |= R_RESTART;
                        goto nfsmout;
+#endif /* CONFIG_NFS_GSS */
                default:
                        error = EACCES;
                        break;
@@ -4342,12 +4568,14 @@ nfs_request_finish(
                }
                nfsm_chain_get_32(error, &nmrep, accepted_status);
                break;
+#if CONFIG_NFS_GSS
        case RPCAUTH_KRB5:
        case RPCAUTH_KRB5I:
        case RPCAUTH_KRB5P:
                error = nfs_gss_clnt_verf_get(req, &nmrep,
                    verf_type, verf_len, &accepted_status);
                break;
+#endif /* CONFIG_NFS_GSS */
        }
        nfsmout_if(error);
 
@@ -4432,6 +4660,7 @@ nfs_request_finish(
                        nfs_up(nmp, req->r_thread, clearjbtimeo, "resource available again");
                }
 
+#if CONFIG_NFS4
                if ((nmp->nm_vers >= NFS_VER4) && (*status == NFSERR_WRONGSEC)) {
                        /*
                         * Hmmm... we need to try a different security flavor.
@@ -4524,7 +4753,7 @@ nfs_request_finish(
                                req->r_np->n_auth = req->r_auth;
                        }
                }
-
+#endif /* CONFIG_NFS4 */
                if (*status == NFS_OK) {
                        /*
                         * Successful NFS request
@@ -4640,11 +4869,12 @@ nfs_request2(
        u_int64_t *xidp,
        int *status)
 {
-       struct nfsreq rq, *req = &rq;
+       struct nfsreq *req;
        int error;
 
+       req = zalloc_flags(nfs_req_zone, Z_WAITOK);
        if ((error = nfs_request_create(np, mp, nmrest, procnum, thd, cred, &req))) {
-               return error;
+               goto out_free;
        }
        req->r_flags |= (flags & (R_OPTMASK | R_SOFT));
        if (si) {
@@ -4672,10 +4902,13 @@ nfs_request2(
 
        FSDBG_BOT(273, R_XID32(req->r_xid), np, procnum, error);
        nfs_request_rele(req);
+out_free:
+       NFS_ZFREE(nfs_req_zone, req);
        return error;
 }
 
 
+#if CONFIG_NFS_GSS
 /*
  * Set up a new null proc request to exchange GSS context tokens with the
  * server. Associate the context that we are setting up with the request that we
@@ -4693,18 +4926,20 @@ nfs_request_gss(
        struct nfsm_chain *nmrepp,
        int *status)
 {
-       struct nfsreq rq, *req = &rq;
+       struct nfsreq *req;
        int error, wait = 1;
 
+       req = zalloc_flags(nfs_req_zone, Z_WAITOK);
        if ((error = nfs_request_create(NULL, mp, nmrest, NFSPROC_NULL, thd, cred, &req))) {
-               return error;
+               goto out_free;
        }
        req->r_flags |= (flags & R_OPTMASK);
 
        if (cp == NULL) {
                printf("nfs_request_gss request has no context\n");
                nfs_request_rele(req);
-               return NFSERR_EAUTH;
+               error = NFSERR_EAUTH;
+               goto out_free;
        }
        nfs_gss_clnt_ctx_ref(req, cp);
 
@@ -4741,9 +4976,11 @@ nfs_request_gss(
 
        nfs_gss_clnt_ctx_unref(req);
        nfs_request_rele(req);
-
+out_free:
+       NFS_ZFREE(nfs_req_zone, req);
        return error;
 }
+#endif /* CONFIG_NFS_GSS */
 
 /*
  * Create and start an asynchronous NFS request.
@@ -4790,22 +5027,20 @@ nfs_request_async(
                if (!error && !(req->r_flags & R_SENT) && req->r_callback.rcb_func) {
                        /* make sure to wait until this async I/O request gets sent */
                        int slpflag = (req->r_nmp && NMFLAG(req->r_nmp, INTR) && req->r_thread && !(req->r_flags & R_NOINTR)) ? PCATCH : 0;
-                       struct timespec ts = { 2, 0 };
+                       struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
                        while (!(req->r_flags & R_SENT)) {
                                nmp = req->r_nmp;
                                if ((req->r_flags & R_RESENDQ) && !nfs_mount_gone(nmp)) {
                                        lck_mtx_lock(&nmp->nm_lock);
-                                       if ((nmp->nm_state & NFSSTA_RECOVER) && (req->r_rchain.tqe_next != NFSREQNOLIST)) {
+                                       if ((req->r_flags & R_RESENDQ) && (nmp->nm_state & NFSSTA_RECOVER) && (req->r_rchain.tqe_next != NFSREQNOLIST)) {
                                                /*
                                                 * It's not going to get off the resend queue if we're in recovery.
                                                 * So, just take it off ourselves.  We could be holding mount state
                                                 * busy and thus holding up the start of recovery.
                                                 */
                                                TAILQ_REMOVE(&nmp->nm_resendq, req, r_rchain);
+                                               req->r_flags &= ~R_RESENDQ;
                                                req->r_rchain.tqe_next = NFSREQNOLIST;
-                                               if (req->r_flags & R_RESENDQ) {
-                                                       req->r_flags &= ~R_RESENDQ;
-                                               }
                                                lck_mtx_unlock(&nmp->nm_lock);
                                                req->r_flags |= R_SENDING;
                                                lck_mtx_unlock(&req->r_mtx);
@@ -4859,21 +5094,19 @@ nfs_request_async_finish(
                req->r_flags |= R_ASYNCWAIT;
        }
        while (req->r_flags & R_RESENDQ) {  /* wait until the request is off the resend queue */
-               struct timespec ts = { 2, 0 };
+               struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
 
                if ((nmp = req->r_nmp)) {
                        lck_mtx_lock(&nmp->nm_lock);
-                       if ((nmp->nm_state & NFSSTA_RECOVER) && (req->r_rchain.tqe_next != NFSREQNOLIST)) {
+                       if ((req->r_flags & R_RESENDQ) && (nmp->nm_state & NFSSTA_RECOVER) && (req->r_rchain.tqe_next != NFSREQNOLIST)) {
                                /*
                                 * It's not going to get off the resend queue if we're in recovery.
                                 * So, just take it off ourselves.  We could be holding mount state
                                 * busy and thus holding up the start of recovery.
                                 */
                                TAILQ_REMOVE(&nmp->nm_resendq, req, r_rchain);
+                               req->r_flags &= ~R_RESENDQ;
                                req->r_rchain.tqe_next = NFSREQNOLIST;
-                               if (req->r_flags & R_RESENDQ) {
-                                       req->r_flags &= ~R_RESENDQ;
-                               }
                                /* Remove the R_RESENDQ reference */
                                assert(req->r_refs > 0);
                                req->r_refs--;
@@ -4974,16 +5207,16 @@ nfs_softterm(struct nfsreq *req)
 void
 nfs_reqdequeue(struct nfsreq *req)
 {
-       lck_mtx_lock(nfs_request_mutex);
+       lck_mtx_lock(&nfs_request_mutex);
        while (req->r_lflags & RL_BUSY) {
                req->r_lflags |= RL_WAITING;
-               msleep(&req->r_lflags, nfs_request_mutex, PSOCK, "reqdeq", NULL);
+               msleep(&req->r_lflags, &nfs_request_mutex, PSOCK, "reqdeq", NULL);
        }
        if (req->r_lflags & RL_QUEUED) {
                TAILQ_REMOVE(&nfs_reqq, req, r_chain);
                req->r_lflags &= ~RL_QUEUED;
        }
-       lck_mtx_unlock(nfs_request_mutex);
+       lck_mtx_unlock(&nfs_request_mutex);
 }
 
 /*
@@ -5048,11 +5281,11 @@ nfs_request_timer(__unused void *param0, __unused void *param1)
        TAILQ_INIT(&nfs_mount_poke_queue);
 
 restart:
-       lck_mtx_lock(nfs_request_mutex);
+       lck_mtx_lock(&nfs_request_mutex);
        req = TAILQ_FIRST(&nfs_reqq);
        if (req == NULL) {      /* no requests - turn timer off */
                nfs_request_timer_on = 0;
-               lck_mtx_unlock(nfs_request_mutex);
+               lck_mtx_unlock(&nfs_request_mutex);
                return;
        }
 
@@ -5182,7 +5415,7 @@ restart:
                                        TAILQ_REMOVE(&nfs_mount_poke_queue, nmp, nm_pokeq);
                                }
                                /* Release our lock state, so we can become a zombie */
-                               lck_mtx_unlock(nfs_request_mutex);
+                               lck_mtx_unlock(&nfs_request_mutex);
 
                                /*
                                 * Note nfs_mount_make zombie(nmp) must be
@@ -5190,7 +5423,7 @@ restart:
                                 * work we release nm_lock in
                                 * nfs_make_mount_zombie with out acquiring any
                                 * other locks. (Later, in nfs_mount_zombie we
-                                * will acquire nfs_request_mutex, r_mtx,
+                                * will acquire &nfs_request_mutex, r_mtx,
                                 * nm_lock in that order). So we should not be
                                 * introducing deadlock here. We take a reference
                                 * on the mount so that its still there when we
@@ -5291,7 +5524,7 @@ restart:
                lck_mtx_unlock(&req->r_mtx);
        }
 
-       lck_mtx_unlock(nfs_request_mutex);
+       lck_mtx_unlock(&nfs_request_mutex);
 
        /* poke any sockets */
        while ((nmp = TAILQ_FIRST(&nfs_mount_poke_queue))) {
@@ -5318,6 +5551,7 @@ nfs_noremotehang(thread_t thd)
  * This is used to determine if we need to bail on a mount.
  * ETIMEDOUT is returned if there has been a soft timeout.
  * EINTR is returned if there is a signal pending that is not being ignored
+ * ESHUTDOWN is return if the system is in shutdown.
  * and the mount is interruptable, or if we are a thread that is in the process
  * of cancellation (also SIGKILL posted).
  */
@@ -5332,6 +5566,11 @@ nfs_sigintr(struct nfsmount *nmp, struct nfsreq *req, thread_t thd, int nmplocke
                return ENXIO;
        }
 
+       if (get_system_inshutdown()) {
+               NFS_SOCK_DBG("Shutdown in progress\n");
+               return ESHUTDOWN;
+       }
+
        if (req && (req->r_flags & R_SOFTTERM)) {
                return ETIMEDOUT; /* request has been terminated. */
        }
@@ -5409,7 +5648,7 @@ nfs_sndlock(struct nfsreq *req)
        struct nfsmount *nmp = req->r_nmp;
        int *statep;
        int error = 0, slpflag = 0;
-       struct timespec ts = { 0, 0 };
+       struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
 
        if (nfs_mount_gone(nmp)) {
                return ENXIO;
@@ -5486,7 +5725,7 @@ nfs_aux_request(
        int error = 0, on = 1, try, sendat = 2, soproto, recv, optlen, restoreto = 0;
        socket_t newso = NULL;
        struct sockaddr_storage ss;
-       struct timeval orig_rcvto, orig_sndto, tv = { 1, 0 };
+       struct timeval orig_rcvto, orig_sndto, tv = { .tv_sec = 1, .tv_usec = 0 };
        mbuf_t m, mrep = NULL;
        struct msghdr msg;
        uint32_t rxid = 0, reply = 0, reply_status, rejected_status;
@@ -5496,12 +5735,16 @@ nfs_aux_request(
 
        if (!so) {
                /* create socket and set options */
-               soproto = (sotype == SOCK_DGRAM) ? IPPROTO_UDP : IPPROTO_TCP;
+               if (saddr->sa_family == AF_LOCAL) {
+                       soproto = 0;
+               } else {
+                       soproto = (sotype == SOCK_DGRAM) ? IPPROTO_UDP : IPPROTO_TCP;
+               }
                if ((error = sock_socket(saddr->sa_family, sotype, soproto, NULL, NULL, &newso))) {
                        goto nfsmout;
                }
 
-               if (bindresv) {
+               if (bindresv && saddr->sa_family != AF_LOCAL) {
                        int level = (saddr->sa_family == AF_INET) ? IPPROTO_IP : IPPROTO_IPV6;
                        int optname = (saddr->sa_family == AF_INET) ? IP_PORTRANGE : IPV6_PORTRANGE;
                        int portrange = IP_PORTRANGE_LOW;
@@ -5673,18 +5916,27 @@ nfs_portmap_lookup(
        socket_t so,
        uint32_t protocol,
        uint32_t vers,
-       uint32_t ipproto,
+       uint32_t stype,
        int timeo)
 {
        thread_t thd = vfs_context_thread(ctx);
        kauth_cred_t cred = vfs_context_ucred(ctx);
        struct sockaddr_storage ss;
        struct sockaddr *saddr = (struct sockaddr*)&ss;
+       static struct sockaddr_un rpcbind_cots = {
+               sizeof(struct sockaddr_un),
+               AF_LOCAL,
+               RPCB_TICOTSORD_PATH
+       };
+       static struct sockaddr_un rpcbind_clts = {
+               sizeof(struct sockaddr_un),
+               AF_LOCAL,
+               RPCB_TICLTS_PATH
+       };
        struct nfsm_chain nmreq, nmrep;
        mbuf_t mreq;
        int error = 0, ip, pmprog, pmvers, pmproc;
-       uint32_t ualen = 0;
-       uint32_t port;
+       uint32_t ualen = 0, scopeid = 0, port32;
        uint64_t xid = 0;
        char uaddr[MAX_IPv6_STR_LEN + 16];
 
@@ -5699,6 +5951,13 @@ nfs_portmap_lookup(
                pmprog = RPCBPROG;
                pmvers = RPCBVERS4;
                pmproc = RPCBPROC_GETVERSADDR;
+       } else if (saddr->sa_family == AF_LOCAL) {
+               ip = 0;
+               pmprog = RPCBPROG;
+               pmvers = RPCBVERS4;
+               pmproc = RPCBPROC_GETVERSADDR;
+               NFS_SOCK_DBG("%s\n", ((struct sockaddr_un*)sa)->sun_path);
+               saddr = (struct sockaddr*)((stype == SOCK_STREAM) ? &rpcbind_cots : &rpcbind_clts);
        } else {
                return EINVAL;
        }
@@ -5709,39 +5968,56 @@ tryagain:
        /* send portmapper request to get port/uaddr */
        if (ip == 4) {
                ((struct sockaddr_in*)saddr)->sin_port = htons(PMAPPORT);
-       } else {
+       } else if (ip == 6) {
                ((struct sockaddr_in6*)saddr)->sin6_port = htons(PMAPPORT);
        }
        nfsm_chain_build_alloc_init(error, &nmreq, 8 * NFSX_UNSIGNED);
        nfsm_chain_add_32(error, &nmreq, protocol);
        nfsm_chain_add_32(error, &nmreq, vers);
        if (ip == 4) {
-               nfsm_chain_add_32(error, &nmreq, ipproto);
+               nfsm_chain_add_32(error, &nmreq, stype == SOCK_STREAM ? IPPROTO_TCP : IPPROTO_UDP);
                nfsm_chain_add_32(error, &nmreq, 0);
        } else {
-               if (ipproto == IPPROTO_TCP) {
-                       nfsm_chain_add_string(error, &nmreq, "tcp6", 4);
+               if (stype == SOCK_STREAM) {
+                       if (ip == 6) {
+                               nfsm_chain_add_string(error, &nmreq, "tcp6", 4);
+                       } else {
+                               nfsm_chain_add_string(error, &nmreq, "ticotsord", 9);
+                       }
                } else {
-                       nfsm_chain_add_string(error, &nmreq, "udp6", 4);
+                       if (ip == 6) {
+                               nfsm_chain_add_string(error, &nmreq, "udp6", 4);
+                       } else {
+                               nfsm_chain_add_string(error, &nmreq, "ticlts", 6);
+                       }
                }
                nfsm_chain_add_string(error, &nmreq, "", 0); /* uaddr */
                nfsm_chain_add_string(error, &nmreq, "", 0); /* owner */
        }
        nfsm_chain_build_done(error, &nmreq);
        nfsmout_if(error);
-       error = nfsm_rpchead2(nmp, (ipproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM,
-           pmprog, pmvers, pmproc, RPCAUTH_SYS, cred, NULL, nmreq.nmc_mhead,
-           &xid, &mreq);
+       error = nfsm_rpchead2(nmp, stype, pmprog, pmvers, pmproc,
+           RPCAUTH_SYS, cred, NULL, nmreq.nmc_mhead, &xid, &mreq);
        nfsmout_if(error);
        nmreq.nmc_mhead = NULL;
-       error = nfs_aux_request(nmp, thd, saddr, so, (ipproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM,
-           mreq, R_XID32(xid), 0, timeo, &nmrep);
+
+       NFS_SOCK_DUMP_MBUF("nfs_portmap_loockup request", mreq);
+       error = nfs_aux_request(nmp, thd, saddr, so,
+           stype, mreq, R_XID32(xid), 0, timeo, &nmrep);
+       NFS_SOCK_DUMP_MBUF("nfs_portmap_lookup reply", nmrep.nmc_mhead);
+       NFS_SOCK_DBG("rpcbind request returned %d for program %u vers %u: %s\n", error, protocol, vers,
+           (saddr->sa_family == AF_LOCAL) ? ((struct sockaddr_un *)saddr)->sun_path :
+           (saddr->sa_family == AF_INET6) ? "INET6 socket" : "INET socket");
 
        /* grab port from portmap response */
        if (ip == 4) {
-               nfsm_chain_get_32(error, &nmrep, port);
+               nfsm_chain_get_32(error, &nmrep, port32);
                if (!error) {
-                       ((struct sockaddr_in*)sa)->sin_port = htons(port);
+                       if (NFS_PORT_INVALID(port32)) {
+                               error = EBADRPC;
+                       } else {
+                               ((struct sockaddr_in*)sa)->sin_port = htons((in_port_t)port32);
+                       }
                }
        } else {
                /* get uaddr string and convert to sockaddr */
@@ -5753,14 +6029,27 @@ tryagain:
                        if (ualen < 1) {
                                /* program is not available, just return a zero port */
                                bcopy(sa, saddr, min(sizeof(ss), sa->sa_len));
-                               ((struct sockaddr_in6*)saddr)->sin6_port = htons(0);
+                               if (ip == 6) {
+                                       ((struct sockaddr_in6*)saddr)->sin6_port = htons(0);
+                               } else {
+                                       ((struct sockaddr_un*)saddr)->sun_path[0] = '\0';
+                               }
+                               NFS_SOCK_DBG("Program %u version %u unavailable", protocol, vers);
                        } else {
                                nfsm_chain_get_opaque(error, &nmrep, ualen, uaddr);
+                               NFS_SOCK_DBG("Got uaddr %s\n", uaddr);
                                if (!error) {
                                        uaddr[ualen] = '\0';
+                                       if (ip == 6) {
+                                               scopeid = ((struct sockaddr_in6*)saddr)->sin6_scope_id;
+                                       }
                                        if (!nfs_uaddr2sockaddr(uaddr, saddr)) {
                                                error = EIO;
                                        }
+                                       if (ip == 6 && scopeid != ((struct sockaddr_in6*)saddr)->sin6_scope_id) {
+                                               NFS_SOCK_DBG("Setting scope_id from %u to %u\n", ((struct sockaddr_in6*)saddr)->sin6_scope_id, scopeid);
+                                               ((struct sockaddr_in6*)saddr)->sin6_scope_id = scopeid;
+                                       }
                                }
                        }
                }
@@ -5785,6 +6074,8 @@ tryagain:
 nfsmout:
        nfsm_chain_cleanup(&nmreq);
        nfsm_chain_cleanup(&nmrep);
+       NFS_SOCK_DBG("Returned %d\n", error);
+
        return error;
 }
 
@@ -5818,6 +6109,7 @@ nfs_msg(thread_t thd,
 #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;
+uint32_t nfs_tcp_sockbuf = 128 * 1024;          /* Default value of tcp_sendspace and tcp_recvspace */
 int32_t nfs_is_mobile;
 
 #define NFS_SQUISHY_DEADTIMEOUT         8       /* Dead time out for squishy mounts */
@@ -6105,9 +6397,9 @@ nfs_up(struct nfsmount *nmp, thread_t thd, int flags, const char *msg)
 }
 
 
-#endif /* NFSCLIENT */
+#endif /* CONFIG_NFS_CLIENT */
 
-#if NFSSERVER
+#if CONFIG_NFS_SERVER
 
 /*
  * Generate the rpc reply header
@@ -6247,6 +6539,9 @@ nfsrv_send(struct nfsrv_sock *slp, mbuf_t nam, mbuf_t top)
                        msg.msg_namelen = sendnam->sa_len;
                }
        }
+       if (NFS_IS_DBG(NFS_FAC_SRV, 15)) {
+               nfs_dump_mbuf(__func__, __LINE__, "nfsrv_send\n", top);
+       }
        error = sock_sendmbuf(so, &msg, top, 0, NULL);
        if (!error) {
                return 0;
@@ -6412,9 +6707,9 @@ dorecs:
                int wake = (slp->ns_flag & SLP_WORKTODO);
                lck_rw_done(&slp->ns_rwlock);
                if (wake && nfsd_thread_count) {
-                       lck_mtx_lock(nfsd_mutex);
+                       lck_mtx_lock(&nfsd_mutex);
                        nfsrv_wakenfsd(slp);
-                       lck_mtx_unlock(nfsd_mutex);
+                       lck_mtx_unlock(&nfsd_mutex);
                }
        }
 }
@@ -6429,7 +6724,8 @@ nfsrv_getstream(struct nfsrv_sock *slp, int waitflag)
 {
        mbuf_t m;
        char *cp1, *cp2, *mdata;
-       int len, mlen, error;
+       int error;
+       size_t len, mlen;
        mbuf_t om, m2, recm;
        u_int32_t recmark;
 
@@ -6591,11 +6887,7 @@ nfsrv_dorec(
        if (!(slp->ns_flag & (SLP_VALID | SLP_DOREC)) || (slp->ns_rec == NULL)) {
                return ENOBUFS;
        }
-       MALLOC_ZONE(nd, struct nfsrv_descript *,
-           sizeof(struct nfsrv_descript), M_NFSRVDESC, M_WAITOK);
-       if (!nd) {
-               return ENOMEM;
-       }
+       nd = zalloc(nfsrv_descript_zone);
        m = slp->ns_rec;
        slp->ns_rec = mbuf_nextpkt(m);
        if (slp->ns_rec) {
@@ -6626,7 +6918,7 @@ nfsrv_dorec(
                if (nd->nd_gss_context) {
                        nfs_gss_svc_ctx_deref(nd->nd_gss_context);
                }
-               FREE_ZONE(nd, sizeof(*nd), M_NFSRVDESC);
+               NFS_ZFREE(nfsrv_descript_zone, nd);
                return error;
        }
        nd->nd_mrep = NULL;
@@ -6649,7 +6941,7 @@ nfsrv_getreq(struct nfsrv_descript *nd)
        int error = 0;
        uid_t user_id;
        gid_t group_id;
-       int ngroups;
+       short ngroups;
        uint32_t val;
 
        nd->nd_cr = NULL;
@@ -6741,7 +7033,7 @@ nfsrv_getreq(struct nfsrv_descript *nd)
                        }
                }
                nfsmout_if(error);
-               ngroups = (len >= NGROUPS) ? NGROUPS : (len + 1);
+               ngroups = (len >= NGROUPS) ? NGROUPS : (short)(len + 1);
                if (ngroups > 1) {
                        nfsrv_group_sort(&temp_pcred.cr_groups[0], ngroups);
                }
@@ -6824,4 +7116,6 @@ nfsrv_wakenfsd(struct nfsrv_sock *slp)
        wakeup(nd);
 }
 
-#endif /* NFSSERVER */
+#endif /* CONFIG_NFS_SERVER */
+
+#endif /* CONFIG_NFS */