]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/nfs/nfs_subs.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_subs.c
index e0e9446bf6c0872586b4e1090b8af123e4e25b7b..a58fc7869ea8f271cc002ad6a8a6a42b3a2fbfa6 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * unlawful or unlicensed copies of an Apple operating system, or to
  * circumvent, violate, or enable the circumvention or violation of, any
  * terms of an Apple operating system software license agreement.
- * 
+ *
  * Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -22,7 +22,7 @@
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
@@ -65,6 +65,9 @@
  * FreeBSD-Id: nfs_subs.c,v 1.47 1997/11/07 08:53:24 phk Exp $
  */
 
+#include <nfs/nfs_conf.h>
+#if CONFIG_NFS
+
 /*
  * These functions support the macros and help fiddle mbuf chains for
  * the nfs op functions. They do things like create the rpc header and
@@ -79,6 +82,7 @@
 #include <sys/vnode_internal.h>
 #include <sys/kpi_mbuf.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <sys/stat.h>
 #include <sys/malloc.h>
 #include <sys/syscall.h>
@@ -88,6 +92,7 @@
 #include <sys/domain.h>
 #include <libkern/OSAtomic.h>
 #include <kern/thread_call.h>
+#include <kern/task.h>
 
 #include <sys/vm.h>
 #include <sys/vmparam.h>
 #include <nfs/nfsproto.h>
 #include <nfs/nfs.h>
 #include <nfs/nfsnode.h>
-#if NFSCLIENT
+#if CONFIG_NFS_CLIENT
 #define _NFS_XDR_SUBS_FUNCS_ /* define this to get xdrbuf function definitions */
 #endif
 #include <nfs/xdr_subs.h>
 /*
  * NFS globals
  */
-struct nfsstats        __attribute__((aligned(8))) nfsstats;
+struct nfsstats __attribute__((aligned(8))) nfsstats;
 size_t nfs_mbuf_mhlen = 0, nfs_mbuf_minclsize = 0;
 
 /*
@@ -141,11 +146,15 @@ vtonfs_type(enum vtype vtype, int nfsvers)
        case VLNK:
                return NFLNK;
        case VSOCK:
-               if (nfsvers > NFS_VER2)
+               if (nfsvers > NFS_VER2) {
                        return NFSOCK;
+               }
+               return NFNON;
        case VFIFO:
-               if (nfsvers > NFS_VER2)
+               if (nfsvers > NFS_VER2) {
                        return NFFIFO;
+               }
+               return NFNON;
        case VBAD:
        case VSTR:
        case VCPLX:
@@ -171,17 +180,25 @@ nfstov_type(nfstype nvtype, int nfsvers)
        case NFLNK:
                return VLNK;
        case NFSOCK:
-               if (nfsvers > NFS_VER2)
+               if (nfsvers > NFS_VER2) {
                        return VSOCK;
+               }
+               OS_FALLTHROUGH;
        case NFFIFO:
-               if (nfsvers > NFS_VER2)
+               if (nfsvers > NFS_VER2) {
                        return VFIFO;
+               }
+               OS_FALLTHROUGH;
        case NFATTRDIR:
-               if (nfsvers > NFS_VER3)
+               if (nfsvers > NFS_VER3) {
                        return VDIR;
+               }
+               OS_FALLTHROUGH;
        case NFNAMEDATTR:
-               if (nfsvers > NFS_VER3)
+               if (nfsvers > NFS_VER3) {
                        return VREG;
+               }
+               OS_FALLTHROUGH;
        default:
                return VNON;
        }
@@ -209,7 +226,7 @@ vtonfsv2_mode(enum vtype vtype, mode_t m)
        }
 }
 
-#if NFSSERVER
+#if CONFIG_NFS_SERVER
 
 /*
  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
@@ -240,7 +257,7 @@ int nfsv3_procid[NFS_NPROCS] = {
        NFSPROC_NOOP
 };
 
-#endif /* NFSSERVER */
+#endif /* CONFIG_NFS_SERVER */
 
 /*
  * and the reverse mapping from generic to Version 2 procedure numbers
@@ -285,7 +302,7 @@ nfs_mbuf_init(void)
        nfs_mbuf_minclsize = ms.minclsize;
 }
 
-#if NFSSERVER
+#if CONFIG_NFS_SERVER
 
 /*
  * allocate a list of mbufs to hold the given amount of data
@@ -302,18 +319,21 @@ nfsm_mbuf_get_list(size_t size, mbuf_t *mp, int *mbcnt)
        len = 0;
 
        while (len < size) {
-               nfsm_mbuf_get(error, &m, (size - len));
-               if (error)
+               nfsm_mbuf_getcluster(error, &m, (size - len));
+               if (error) {
                        break;
-               if (!mhead)
+               }
+               if (!mhead) {
                        mhead = m;
+               }
                if (mlast && ((error = mbuf_setnext(mlast, m)))) {
                        mbuf_free(m);
                        break;
                }
                mlen = mbuf_maxlen(m);
-               if ((len + mlen) > size)
+               if ((len + mlen) > size) {
                        mlen = size - len;
+               }
                mbuf_setlen(m, mlen);
                len += mlen;
                cnt++;
@@ -324,10 +344,10 @@ nfsm_mbuf_get_list(size_t size, mbuf_t *mp, int *mbcnt)
                *mp = mhead;
                *mbcnt = cnt;
        }
-       return (error);
+       return error;
 }
 
-#endif /* NFSSERVER */
+#endif /* CONFIG_NFS_SERVER */
 
 /*
  * nfsm_chain_new_mbuf()
@@ -340,15 +360,18 @@ nfsm_chain_new_mbuf(struct nfsm_chain *nmc, size_t sizehint)
        mbuf_t mb;
        int error = 0;
 
-       if (nmc->nmc_flags & NFSM_CHAIN_FLAG_ADD_CLUSTERS)
+       if (nmc->nmc_flags & NFSM_CHAIN_FLAG_ADD_CLUSTERS) {
                sizehint = nfs_mbuf_minclsize;
+       }
 
        /* allocate a new mbuf */
-       nfsm_mbuf_get(error, &mb, sizehint);
-       if (error)
-               return (error);
-       if (mb == NULL)
+       nfsm_mbuf_getcluster(error, &mb, sizehint);
+       if (error) {
+               return error;
+       }
+       if (mb == NULL) {
                panic("got NULL mbuf?");
+       }
 
        /* do we have a current mbuf? */
        if (nmc->nmc_mcur) {
@@ -358,7 +381,7 @@ nfsm_chain_new_mbuf(struct nfsm_chain *nmc, size_t sizehint)
                error = mbuf_setnext(nmc->nmc_mcur, mb);
                if (error) {
                        mbuf_free(mb);
-                       return (error);
+                       return error;
                }
        }
 
@@ -367,7 +390,7 @@ nfsm_chain_new_mbuf(struct nfsm_chain *nmc, size_t sizehint)
        nmc->nmc_ptr = mbuf_data(mb);
        nmc->nmc_left = mbuf_trailingspace(mb);
 
-       return (0);
+       return 0;
 }
 
 /*
@@ -376,9 +399,9 @@ nfsm_chain_new_mbuf(struct nfsm_chain *nmc, size_t sizehint)
  * Add "len" bytes of opaque data pointed to by "buf" to the given chain.
  */
 int
-nfsm_chain_add_opaque_f(struct nfsm_chain *nmc, const u_char *buf, uint32_t len)
+nfsm_chain_add_opaque_f(struct nfsm_chain *nmc, const u_char *buf, size_t len)
 {
-       uint32_t paddedlen, tlen;
+       size_t paddedlen, tlen;
        int error;
 
        paddedlen = nfsm_rndup(len);
@@ -386,14 +409,16 @@ nfsm_chain_add_opaque_f(struct nfsm_chain *nmc, const u_char *buf, uint32_t len)
        while (paddedlen) {
                if (!nmc->nmc_left) {
                        error = nfsm_chain_new_mbuf(nmc, paddedlen);
-                       if (error)
-                               return (error);
+                       if (error) {
+                               return error;
+                       }
                }
                tlen = MIN(nmc->nmc_left, paddedlen);
                if (tlen) {
                        if (len) {
-                               if (tlen > len)
+                               if (tlen > len) {
                                        tlen = len;
+                               }
                                bcopy(buf, nmc->nmc_ptr, tlen);
                        } else {
                                bzero(nmc->nmc_ptr, tlen);
@@ -407,7 +432,7 @@ nfsm_chain_add_opaque_f(struct nfsm_chain *nmc, const u_char *buf, uint32_t len)
                        }
                }
        }
-       return (0);
+       return 0;
 }
 
 /*
@@ -417,16 +442,17 @@ nfsm_chain_add_opaque_f(struct nfsm_chain *nmc, const u_char *buf, uint32_t len)
  * Do not XDR pad.
  */
 int
-nfsm_chain_add_opaque_nopad_f(struct nfsm_chain *nmc, const u_char *buf, uint32_t len)
+nfsm_chain_add_opaque_nopad_f(struct nfsm_chain *nmc, const u_char *buf, size_t len)
 {
-       uint32_t tlen;
+       size_t tlen;
        int error;
 
        while (len > 0) {
                if (nmc->nmc_left <= 0) {
                        error = nfsm_chain_new_mbuf(nmc, len);
-                       if (error)
-                               return (error);
+                       if (error) {
+                               return error;
+                       }
                }
                tlen = MIN(nmc->nmc_left, len);
                bcopy(buf, nmc->nmc_ptr, tlen);
@@ -435,7 +461,7 @@ nfsm_chain_add_opaque_nopad_f(struct nfsm_chain *nmc, const u_char *buf, uint32_
                len -= tlen;
                buf += tlen;
        }
-       return (0);
+       return 0;
 }
 
 /*
@@ -444,9 +470,9 @@ nfsm_chain_add_opaque_nopad_f(struct nfsm_chain *nmc, const u_char *buf, uint32_
  * Add "len" bytes of data from "uio" to the given chain.
  */
 int
-nfsm_chain_add_uio(struct nfsm_chain *nmc, uio_t uio, uint32_t len)
+nfsm_chain_add_uio(struct nfsm_chain *nmc, uio_t uio, size_t len)
 {
-       uint32_t paddedlen, tlen;
+       size_t paddedlen, tlen;
        int error;
 
        paddedlen = nfsm_rndup(len);
@@ -454,45 +480,47 @@ nfsm_chain_add_uio(struct nfsm_chain *nmc, uio_t uio, uint32_t len)
        while (paddedlen) {
                if (!nmc->nmc_left) {
                        error = nfsm_chain_new_mbuf(nmc, paddedlen);
-                       if (error)
-                               return (error);
+                       if (error) {
+                               return error;
+                       }
                }
                tlen = MIN(nmc->nmc_left, paddedlen);
                if (tlen) {
                        if (len) {
-                               if (tlen > len)
-                                       tlen = len;
-                               uiomove(nmc->nmc_ptr, tlen, uio);
+                               tlen = MIN(INT32_MAX, MIN(tlen, len));
+                               uiomove(nmc->nmc_ptr, (int)tlen, uio);
                        } else {
                                bzero(nmc->nmc_ptr, tlen);
                        }
                        nmc->nmc_ptr += tlen;
                        nmc->nmc_left -= tlen;
                        paddedlen -= tlen;
-                       if (len)
+                       if (len) {
                                len -= tlen;
+                       }
                }
        }
-       return (0);
+       return 0;
 }
 
 /*
  * Find the length of the NFS mbuf chain
  * up to the current encoding/decoding offset.
  */
-int
+size_t
 nfsm_chain_offset(struct nfsm_chain *nmc)
 {
        mbuf_t mb;
-       int len = 0;
+       size_t len = 0;
 
        for (mb = nmc->nmc_mhead; mb; mb = mbuf_next(mb)) {
-               if (mb == nmc->nmc_mcur)
-                       return (len + (nmc->nmc_ptr - (caddr_t) mbuf_data(mb)));
+               if (mb == nmc->nmc_mcur) {
+                       return len + (nmc->nmc_ptr - (caddr_t) mbuf_data(mb));
+               }
                len += mbuf_len(mb);
        }
 
-       return (len);
+       return len;
 }
 
 /*
@@ -501,7 +529,7 @@ nfsm_chain_offset(struct nfsm_chain *nmc)
  * Advance an nfsm_chain by "len" bytes.
  */
 int
-nfsm_chain_advance(struct nfsm_chain *nmc, uint32_t len)
+nfsm_chain_advance(struct nfsm_chain *nmc, size_t len)
 {
        mbuf_t mb;
 
@@ -509,17 +537,18 @@ nfsm_chain_advance(struct nfsm_chain *nmc, uint32_t len)
                if (nmc->nmc_left >= len) {
                        nmc->nmc_left -= len;
                        nmc->nmc_ptr += len;
-                       return (0);
+                       return 0;
                }
                len -= nmc->nmc_left;
                nmc->nmc_mcur = mb = mbuf_next(nmc->nmc_mcur);
-               if (!mb)
-                       return (EBADRPC);
+               if (!mb) {
+                       return EBADRPC;
+               }
                nmc->nmc_ptr = mbuf_data(mb);
                nmc->nmc_left = mbuf_len(mb);
        }
 
-       return (0);
+       return 0;
 }
 
 /*
@@ -528,24 +557,25 @@ nfsm_chain_advance(struct nfsm_chain *nmc, uint32_t len)
  * Reverse decode offset in an nfsm_chain by "len" bytes.
  */
 int
-nfsm_chain_reverse(struct nfsm_chain *nmc, uint32_t len)
+nfsm_chain_reverse(struct nfsm_chain *nmc, size_t len)
 {
-       uint32_t mlen, new_offset;
+       size_t mlen, new_offset;
        int error = 0;
 
        mlen = nmc->nmc_ptr - (caddr_t) mbuf_data(nmc->nmc_mcur);
        if (len <= mlen) {
                nmc->nmc_ptr -= len;
                nmc->nmc_left += len;
-               return (0);
+               return 0;
        }
 
        new_offset = nfsm_chain_offset(nmc) - len;
        nfsm_chain_dissect_init(error, nmc, nmc->nmc_mhead);
-       if (error)
-               return (error);
+       if (error) {
+               return error;
+       }
 
-       return (nfsm_chain_advance(nmc, new_offset));
+       return nfsm_chain_advance(nmc, new_offset);
 }
 
 /*
@@ -561,7 +591,8 @@ int
 nfsm_chain_get_opaque_pointer_f(struct nfsm_chain *nmc, uint32_t len, u_char **pptr)
 {
        mbuf_t mbcur, mb;
-       uint32_t left, need, mblen, cplen, padlen;
+       uint32_t padlen;
+       size_t mblen, cplen, need, left;
        u_char *ptr;
        int error = 0;
 
@@ -569,21 +600,23 @@ nfsm_chain_get_opaque_pointer_f(struct nfsm_chain *nmc, uint32_t len, u_char **p
        while (nmc->nmc_mcur && (nmc->nmc_left == 0)) {
                mb = mbuf_next(nmc->nmc_mcur);
                nmc->nmc_mcur = mb;
-               if (!mb)
+               if (!mb) {
                        break;
+               }
                nmc->nmc_ptr = mbuf_data(mb);
                nmc->nmc_left = mbuf_len(mb);
        }
        /* check if we've run out of data */
-       if (!nmc->nmc_mcur)
-               return (EBADRPC);
+       if (!nmc->nmc_mcur) {
+               return EBADRPC;
+       }
 
        /* do we already have a contiguous buffer? */
        if (nmc->nmc_left >= len) {
                /* the returned pointer will be the current pointer */
                *pptr = (u_char*)nmc->nmc_ptr;
                error = nfsm_chain_advance(nmc, nfsm_rndup(len));
-               return (error);
+               return error;
        }
 
        padlen = nfsm_rndup(len) - len;
@@ -598,13 +631,14 @@ nfsm_chain_get_opaque_pointer_f(struct nfsm_chain *nmc, uint32_t len, u_char **p
                 * The needed bytes won't fit in the current mbuf so we'll
                 * allocate a new mbuf to hold the contiguous range of data.
                 */
-               nfsm_mbuf_get(error, &mb, len);
-               if (error)
-                       return (error);
+               nfsm_mbuf_getcluster(error, &mb, len);
+               if (error) {
+                       return error;
+               }
                /* double check that this mbuf can hold all the data */
                if (mbuf_maxlen(mb) < len) {
                        mbuf_free(mb);
-                       return (EOVERFLOW);
+                       return EOVERFLOW;
                }
 
                /* the returned pointer will be the new mbuf's data pointer */
@@ -617,11 +651,12 @@ nfsm_chain_get_opaque_pointer_f(struct nfsm_chain *nmc, uint32_t len, u_char **p
 
                /* insert the new mbuf between the current and next mbufs */
                error = mbuf_setnext(mb, mbuf_next(mbcur));
-               if (!error)
+               if (!error) {
                        error = mbuf_setnext(mbcur, mb);
+               }
                if (error) {
                        mbuf_free(mb);
-                       return (error);
+                       return error;
                }
 
                /* reduce current mbuf's length by "left" */
@@ -673,21 +708,22 @@ nfsm_chain_get_opaque_pointer_f(struct nfsm_chain *nmc, uint32_t len, u_char **p
                        error = mbuf_setdata(mb, ptr + cplen, mblen - cplen);
                        if (error) {
                                mbuf_setlen(mbcur, mbuf_len(mbcur) - need);
-                               return (error);
+                               return error;
                        }
                        /* update pointer/need */
                        nmc->nmc_ptr += cplen;
                        need -= cplen;
                }
                /* if more needed, go to next mbuf */
-               if (need)
+               if (need) {
                        mb = mbuf_next(mb);
+               }
        }
 
        /* did we run out of data in the mbuf chain? */
        if (need) {
                mbuf_setlen(mbcur, mbuf_len(mbcur) - need);
-               return (EBADRPC);
+               return EBADRPC;
        }
 
        /*
@@ -701,10 +737,11 @@ nfsm_chain_get_opaque_pointer_f(struct nfsm_chain *nmc, uint32_t len, u_char **p
        nmc->nmc_left = mbuf_len(mb);
 
        /* move past any padding */
-       if (padlen)
+       if (padlen) {
                error = nfsm_chain_advance(nmc, padlen);
+       }
 
-       return (error);
+       return error;
 }
 
 /*
@@ -714,9 +751,9 @@ nfsm_chain_get_opaque_pointer_f(struct nfsm_chain *nmc, uint32_t len, u_char **p
  * The nfsm_chain is advanced by nfsm_rndup("len") bytes.
  */
 int
-nfsm_chain_get_opaque_f(struct nfsm_chain *nmc, uint32_t len, u_char *buf)
+nfsm_chain_get_opaque_f(struct nfsm_chain *nmc, size_t len, u_char *buf)
 {
-       uint32_t cplen, padlen;
+       size_t cplen, padlen;
        int error = 0;
 
        padlen = nfsm_rndup(len) - len;
@@ -742,13 +779,15 @@ nfsm_chain_get_opaque_f(struct nfsm_chain *nmc, uint32_t len, u_char *buf)
        }
 
        /* did we run out of data in the mbuf chain? */
-       if (len)
-               return (EBADRPC);
+       if (len) {
+               return EBADRPC;
+       }
 
-       if (padlen)
+       if (padlen) {
                nfsm_chain_adv(error, nmc, padlen);
+       }
 
-       return (error);
+       return error;
 }
 
 /*
@@ -758,9 +797,9 @@ nfsm_chain_get_opaque_f(struct nfsm_chain *nmc, uint32_t len, u_char *buf)
  * The nfsm_chain is advanced by nfsm_rndup("len") bytes.
  */
 int
-nfsm_chain_get_uio(struct nfsm_chain *nmc, uint32_t len, uio_t uio)
+nfsm_chain_get_uio(struct nfsm_chain *nmc, size_t len, uio_t uio)
 {
-       uint32_t cplen, padlen;
+       size_t cplen, padlen;
        int error = 0;
 
        padlen = nfsm_rndup(len) - len;
@@ -770,9 +809,11 @@ nfsm_chain_get_uio(struct nfsm_chain *nmc, uint32_t len, uio_t uio)
                /* copy as much as we need/can */
                cplen = MIN(nmc->nmc_left, len);
                if (cplen) {
-                       error = uiomove(nmc->nmc_ptr, cplen, uio);
-                       if (error)
-                               return (error);
+                       cplen = MIN(cplen, INT32_MAX);
+                       error = uiomove(nmc->nmc_ptr, (int)cplen, uio);
+                       if (error) {
+                               return error;
+                       }
                        nmc->nmc_ptr += cplen;
                        nmc->nmc_left -= cplen;
                        len -= cplen;
@@ -787,42 +828,45 @@ nfsm_chain_get_uio(struct nfsm_chain *nmc, uint32_t len, uio_t uio)
        }
 
        /* did we run out of data in the mbuf chain? */
-       if (len)
-               return (EBADRPC);
+       if (len) {
+               return EBADRPC;
+       }
 
-       if (padlen)
+       if (padlen) {
                nfsm_chain_adv(error, nmc, padlen);
+       }
 
-       return (error);
+       return error;
 }
 
-#if NFSCLIENT
+#if CONFIG_NFS_CLIENT
 
 int
-nfsm_chain_add_string_nfc(struct nfsm_chain *nmc, const uint8_t *s, uint32_t slen)
+nfsm_chain_add_string_nfc(struct nfsm_chain *nmc, const uint8_t *s, size_t slen)
 {
        uint8_t smallbuf[64];
        uint8_t *nfcname = smallbuf;
        size_t buflen = sizeof(smallbuf), nfclen;
        int error;
 
-       error = utf8_normalizestr(s, slen, nfcname, &nfclen, buflen, UTF_PRECOMPOSED|UTF_NO_NULL_TERM);
+       error = utf8_normalizestr(s, slen, nfcname, &nfclen, buflen, UTF_PRECOMPOSED | UTF_NO_NULL_TERM);
        if (error == ENAMETOOLONG) {
                buflen = MAXPATHLEN;
-               MALLOC_ZONE(nfcname, uint8_t *, MAXPATHLEN, M_NAMEI, M_WAITOK);
-               if (nfcname)
-                       error = utf8_normalizestr(s, slen, nfcname, &nfclen, buflen, UTF_PRECOMPOSED|UTF_NO_NULL_TERM);
+               nfcname = zalloc(ZV_NAMEI);
+               error = utf8_normalizestr(s, slen, nfcname, &nfclen, buflen, UTF_PRECOMPOSED | UTF_NO_NULL_TERM);
        }
 
        /* if we got an error, just use the original string */
-       if (error)
+       if (error) {
                nfsm_chain_add_string(error, nmc, s, slen);
-       else
+       } else {
                nfsm_chain_add_string(error, nmc, nfcname, nfclen);
+       }
 
-       if (nfcname && (nfcname != smallbuf))
-               FREE_ZONE(nfcname, MAXPATHLEN, M_NAMEI);
-       return (error);
+       if (nfcname && (nfcname != smallbuf)) {
+               NFS_ZFREE(ZV_NAMEI, nfcname);
+       }
+       return error;
 }
 
 /*
@@ -834,27 +878,30 @@ nfsm_chain_add_v2sattr_f(struct nfsm_chain *nmc, struct vnode_attr *vap, uint32_
        int error = 0;
 
        nfsm_chain_add_32(error, nmc, vtonfsv2_mode(vap->va_type,
-               (VATTR_IS_ACTIVE(vap, va_mode) ? vap->va_mode : 0600)));
+           (VATTR_IS_ACTIVE(vap, va_mode) ? vap->va_mode : 0600)));
        nfsm_chain_add_32(error, nmc,
-               VATTR_IS_ACTIVE(vap, va_uid) ? vap->va_uid : (uint32_t)-1);
+           VATTR_IS_ACTIVE(vap, va_uid) ? vap->va_uid : (uint32_t)-1);
        nfsm_chain_add_32(error, nmc,
-               VATTR_IS_ACTIVE(vap, va_gid) ? vap->va_gid : (uint32_t)-1);
+           VATTR_IS_ACTIVE(vap, va_gid) ? vap->va_gid : (uint32_t)-1);
        nfsm_chain_add_32(error, nmc, szrdev);
        nfsm_chain_add_v2time(error, nmc,
-               VATTR_IS_ACTIVE(vap, va_access_time) ?
-               &vap->va_access_time : NULL);
+           VATTR_IS_ACTIVE(vap, va_access_time) ?
+           &vap->va_access_time : NULL);
        nfsm_chain_add_v2time(error, nmc,
-               VATTR_IS_ACTIVE(vap, va_modify_time) ?
-               &vap->va_modify_time : NULL);
+           VATTR_IS_ACTIVE(vap, va_modify_time) ?
+           &vap->va_modify_time : NULL);
 
-       return (error);
+       return error;
 }
 
 /*
  * Add an NFSv3 "sattr" structure to an mbuf chain
  */
 int
-nfsm_chain_add_v3sattr_f(struct nfsm_chain *nmc, struct vnode_attr *vap)
+nfsm_chain_add_v3sattr_f(
+       __unused struct nfsmount *nmp,
+       struct nfsm_chain *nmc,
+       struct vnode_attr *vap)
 {
        int error = 0;
 
@@ -902,7 +949,8 @@ nfsm_chain_add_v3sattr_f(struct nfsm_chain *nmc, struct vnode_attr *vap)
                }
        }
 
-       return (error);
+
+       return error;
 }
 
 
@@ -913,6 +961,7 @@ nfsm_chain_add_v3sattr_f(struct nfsm_chain *nmc, struct vnode_attr *vap)
  */
 int
 nfsm_chain_get_fh_attr(
+       struct nfsmount *nmp,
        struct nfsm_chain *nmc,
        nfsnode_t dnp,
        vfs_context_t ctx,
@@ -925,20 +974,24 @@ nfsm_chain_get_fh_attr(
 
        gotfh = gotattr = 1;
 
-       if (nfsvers == NFS_VER3) /* check for file handle */
+       if (nfsvers == NFS_VER3) /* check for file handle */
                nfsm_chain_get_32(error, nmc, gotfh);
-       if (!error && gotfh) /* get file handle */
+       }
+       if (!error && gotfh) { /* get file handle */
                nfsm_chain_get_fh(error, nmc, nfsvers, fhp);
-       else
+       } else {
                fhp->fh_len = 0;
-       if (nfsvers == NFS_VER3) /* check for file attributes */
+       }
+       if (nfsvers == NFS_VER3) { /* check for file attributes */
                nfsm_chain_get_32(error, nmc, gotattr);
+       }
        nfsmout_if(error);
        if (gotattr) {
-               if (!gotfh) /* skip attributes */
+               if (!gotfh) /* skip attributes */
                        nfsm_chain_adv(error, nmc, NFSX_V3FATTR);
-               else /* get attributes */
-                       error = nfs_parsefattr(nmc, nfsvers, nvap);
+               } else { /* get attributes */
+                       error = nfs_parsefattr(nmp, nmc, nfsvers, nvap);
+               }
        } else if (gotfh) {
                /* we need valid attributes in order to call nfs_nget() */
                if (nfs3_getattr_rpc(NULL, NFSTOMP(dnp), fhp->fh_data, fhp->fh_len, 0, ctx, nvap, xidp)) {
@@ -947,7 +1000,7 @@ nfsm_chain_get_fh_attr(
                }
        }
 nfsmout:
-       return (error);
+       return error;
 }
 
 /*
@@ -976,7 +1029,7 @@ nfsm_chain_get_wcc_data_f(
        }
        nfsm_chain_postop_attr_update_flag(error, nmc, np, *newpostattr, xidp);
 
-       return (error);
+       return error;
 }
 
 /*
@@ -987,7 +1040,7 @@ nfs_get_xid(uint64_t *xidp)
 {
        struct timeval tv;
 
-       lck_mtx_lock(nfs_request_mutex);
+       lck_mtx_lock(&nfs_request_mutex);
        if (!nfs_xid) {
                /*
                 * Derive initial xid from system time.
@@ -1005,8 +1058,8 @@ nfs_get_xid(uint64_t *xidp)
                nfs_xidwrap++;
                nfs_xid++;
        }
-       *xidp = nfs_xid + ((uint64_t)nfs_xidwrap << 32);
-       lck_mtx_unlock(nfs_request_mutex);
+       *xidp = nfs_xid + (nfs_xidwrap << 32);
+       lck_mtx_unlock(&nfs_request_mutex);
 }
 
 /*
@@ -1026,71 +1079,121 @@ nfsm_rpchead(
        int proc = ((nfsvers == NFS_VER2) ? nfsv2_procid[req->r_procnum] : (int)req->r_procnum);
 
        return nfsm_rpchead2(nmp, nmp->nm_sotype, NFS_PROG, nfsvers, proc,
-                       req->r_auth, req->r_cred, req, mrest, xidp, mreqp);
+                  req->r_auth, req->r_cred, req, mrest, xidp, mreqp);
+}
+
+/*
+ * get_auiliary_groups:        Gets the supplementary groups from a credential.
+ *
+ * IN:         cred:   credential to get the associated groups from.
+ * OUT:                groups: An array of gids of NGROUPS size.
+ * IN:         count:  The number of groups to get; i.e.; the number of groups the server supports
+ *
+ * returns:    The number of groups found.
+ *
+ * Just a wrapper around kauth_cred_getgroups to handle the case of a server supporting less
+ * than NGROUPS.
+ */
+static size_t
+get_auxiliary_groups(kauth_cred_t cred, gid_t groups[NGROUPS], size_t count)
+{
+       gid_t pgid;
+       size_t maxcount = count < NGROUPS ? count + 1 : NGROUPS;
+       size_t i;
+
+       for (i = 0; i < NGROUPS; i++) {
+               groups[i] = -2; /* Initialize to the nobody group */
+       }
+       (void)kauth_cred_getgroups(cred, groups, &maxcount);
+       if (maxcount < 1) {
+               return maxcount;
+       }
+
+       /*
+        * kauth_get_groups returns the primary group followed by the
+        * users auxiliary groups. If the number of groups the server supports
+        * is less than NGROUPS, then we will drop the first group so that
+        * we can send one more group over the wire.
+        */
+
+
+       if (count < NGROUPS) {
+               pgid = kauth_cred_getgid(cred);
+               if (pgid == groups[0]) {
+                       maxcount -= 1;
+                       for (i = 0; i < maxcount; i++) {
+                               groups[i] = groups[i + 1];
+                       }
+               }
+       }
+
+       return maxcount;
 }
 
 int
-nfsm_rpchead2(struct nfsmount *nmp, int sotype, int prog, int vers, int proc, int auth_type,
-       kauth_cred_t cred, struct nfsreq *req, mbuf_t mrest, u_int64_t *xidp, mbuf_t *mreqp)
+nfsm_rpchead2(__unused struct nfsmount *nmp, int sotype, int prog, int vers, int proc, int auth_type,
+    kauth_cred_t cred, struct nfsreq *req, mbuf_t mrest, u_int64_t *xidp, mbuf_t *mreqp)
 {
        mbuf_t mreq, mb;
-       int error, i, grpsiz, auth_len = 0, authsiz, reqlen;
+       size_t i;
+       int error, auth_len = 0, authsiz, reqlen;
        size_t headlen;
        struct nfsm_chain nmreq;
+       gid_t grouplist[NGROUPS];
+       size_t groupcount = 0;
 
        /* calculate expected auth length */
        switch (auth_type) {
-               case RPCAUTH_NONE:
-                       auth_len = 0;
-                       break;
-               case RPCAUTH_SYS:
-                   {
-                       gid_t grouplist[NGROUPS];
-                       int groupcount = NGROUPS;
-
-                       if (!cred)
-                               return (EINVAL);
-
-                       (void)kauth_cred_getgroups(cred, grouplist, &groupcount);
-                       if (groupcount < 1)
-                               return (EINVAL);
+       case RPCAUTH_NONE:
+               auth_len = 0;
+               break;
+       case RPCAUTH_SYS:
+       {
+               size_t count = nmp->nm_numgrps < NGROUPS ? nmp->nm_numgrps : NGROUPS;
 
-                       auth_len = (((((uint32_t)groupcount - 1) > nmp->nm_numgrps) ?
-                               nmp->nm_numgrps : (groupcount - 1)) << 2) +
-                               5 * NFSX_UNSIGNED;
-                       break;
-                   }
-               case RPCAUTH_KRB5:
-               case RPCAUTH_KRB5I:
-               case RPCAUTH_KRB5P:
-                       if (!req || !cred)
-                               return (EINVAL);
-                       auth_len = 5 * NFSX_UNSIGNED + 0; // zero context handle for now
-                       break;
-               default:
-                       return (EINVAL);
+               if (!cred) {
+                       return EINVAL;
                }
+               groupcount = get_auxiliary_groups(cred, grouplist, count);
+               auth_len = ((uint32_t)groupcount + 5) * NFSX_UNSIGNED;
+               break;
+       }
+#if CONFIG_NFS_GSS
+       case RPCAUTH_KRB5:
+       case RPCAUTH_KRB5I:
+       case RPCAUTH_KRB5P:
+               if (!req || !cred) {
+                       return EINVAL;
+               }
+               auth_len = 5 * NFSX_UNSIGNED + 0;         // zero context handle for now
+               break;
+#endif /* CONFIG_NFS_GSS */
+       default:
+               return EINVAL;
+       }
        authsiz = nfsm_rndup(auth_len);
 
        /* allocate the packet */
        headlen = authsiz + 10 * NFSX_UNSIGNED;
-       if (sotype == SOCK_STREAM) /* also include room for any RPC Record Mark */
+       if (sotype == SOCK_STREAM) /* also include room for any RPC Record Mark */
                headlen += NFSX_UNSIGNED;
+       }
        if (headlen >= nfs_mbuf_minclsize) {
                error = mbuf_getpacket(MBUF_WAITOK, &mreq);
        } else {
                error = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &mreq);
                if (!error) {
-                       if (headlen < nfs_mbuf_mhlen)
+                       if (headlen < nfs_mbuf_mhlen) {
                                mbuf_align_32(mreq, headlen);
-                       else
+                       } else {
                                mbuf_align_32(mreq, 8 * NFSX_UNSIGNED);
+                       }
                }
        }
        if (error) {
                /* unable to allocate packet */
                /* XXX should we keep statistics for these errors? */
-               return (error);
+               return error;
        }
 
        /*
@@ -1098,15 +1201,17 @@ nfsm_rpchead2(struct nfsmount *nmp, int sotype, int prog, int vers, int proc, in
         * it may be a higher-level resend with a GSSAPI credential.
         * Otherwise, allocate a new one.
         */
-       if (*xidp == 0)
+       if (*xidp == 0) {
                nfs_get_xid(xidp);
+       }
 
        /* build the header(s) */
        nfsm_chain_init(&nmreq, mreq);
 
        /* First, if it's a TCP stream insert space for an RPC record mark */
-       if (sotype == SOCK_STREAM)
+       if (sotype == SOCK_STREAM) {
                nfsm_chain_add_32(error, &nmreq, 0);
+       }
 
        /* Then the RPC header. */
        nfsm_chain_add_32(error, &nmreq, (*xidp & 0xffffffff));
@@ -1116,81 +1221,84 @@ nfsm_rpchead2(struct nfsmount *nmp, int sotype, int prog, int vers, int proc, in
        nfsm_chain_add_32(error, &nmreq, vers);
        nfsm_chain_add_32(error, &nmreq, proc);
 
+#if CONFIG_NFS_GSS
 add_cred:
+#endif
        switch (auth_type) {
        case RPCAUTH_NONE:
                nfsm_chain_add_32(error, &nmreq, RPCAUTH_NONE); /* auth */
-               nfsm_chain_add_32(error, &nmreq, 0);            /* length */
-               nfsm_chain_add_32(error, &nmreq, RPCAUTH_NONE); /* verf */
-               nfsm_chain_add_32(error, &nmreq, 0);            /* length */
+               nfsm_chain_add_32(error, &nmreq, 0);            /* length */
+               nfsm_chain_add_32(error, &nmreq, RPCAUTH_NONE); /* verf */
+               nfsm_chain_add_32(error, &nmreq, 0);            /* length */
                nfsm_chain_build_done(error, &nmreq);
                /* Append the args mbufs */
-               if (!error)
+               if (!error) {
                        error = mbuf_setnext(nmreq.nmc_mcur, mrest);
+               }
                break;
        case RPCAUTH_SYS: {
-               gid_t grouplist[NGROUPS];
-               int groupcount;
-
                nfsm_chain_add_32(error, &nmreq, RPCAUTH_SYS);
                nfsm_chain_add_32(error, &nmreq, authsiz);
-               nfsm_chain_add_32(error, &nmreq, 0);    /* stamp */
-               nfsm_chain_add_32(error, &nmreq, 0);    /* zero-length hostname */
-               nfsm_chain_add_32(error, &nmreq, kauth_cred_getuid(cred));      /* UID */
-               nfsm_chain_add_32(error, &nmreq, kauth_cred_getgid(cred));      /* GID */
-               grpsiz = (auth_len >> 2) - 5;
-               nfsm_chain_add_32(error, &nmreq, grpsiz);/* additional GIDs */
-               memset(grouplist, 0, sizeof(grouplist));
-               groupcount = grpsiz;
-               (void)kauth_cred_getgroups(cred, grouplist, &groupcount);
-               for (i = 1; i <= grpsiz; i++)
+               {
+                       nfsm_chain_add_32(error, &nmreq, 0);    /* stamp */
+               }
+               nfsm_chain_add_32(error, &nmreq, 0);    /* zero-length hostname */
+               nfsm_chain_add_32(error, &nmreq, kauth_cred_getuid(cred));      /* UID */
+               nfsm_chain_add_32(error, &nmreq, kauth_cred_getgid(cred));      /* GID */
+               nfsm_chain_add_32(error, &nmreq, groupcount);/* additional GIDs */
+               for (i = 0; i < groupcount; i++) {
                        nfsm_chain_add_32(error, &nmreq, grouplist[i]);
+               }
 
                /* And the verifier... */
-               nfsm_chain_add_32(error, &nmreq, RPCAUTH_NONE); /* flavor */
-               nfsm_chain_add_32(error, &nmreq, 0);            /* length */
+               nfsm_chain_add_32(error, &nmreq, RPCAUTH_NONE); /* flavor */
+               nfsm_chain_add_32(error, &nmreq, 0);            /* length */
                nfsm_chain_build_done(error, &nmreq);
 
                /* Append the args mbufs */
-               if (!error)
+               if (!error) {
                        error = mbuf_setnext(nmreq.nmc_mcur, mrest);
+               }
                break;
        }
+#if CONFIG_NFS_GSS
        case RPCAUTH_KRB5:
        case RPCAUTH_KRB5I:
        case RPCAUTH_KRB5P:
                error = nfs_gss_clnt_cred_put(req, &nmreq, mrest);
                if (error == ENEEDAUTH) {
-                       gid_t grouplist[NGROUPS];
-                       int groupcount = NGROUPS;
+                       size_t count = nmp->nm_numgrps < NGROUPS ? nmp->nm_numgrps : NGROUPS;
+
                        /*
                         * Use sec=sys for this user
                         */
                        error = 0;
                        req->r_auth = auth_type = RPCAUTH_SYS;
-                       (void)kauth_cred_getgroups(cred, grouplist, &groupcount);
-                       auth_len = (((((uint32_t)groupcount - 1) > nmp->nm_numgrps) ?
-                               nmp->nm_numgrps : (groupcount - 1)) << 2) +
-                               5 * NFSX_UNSIGNED;
+                       groupcount = get_auxiliary_groups(cred, grouplist, count);
+                       auth_len = ((uint32_t)groupcount + 5) * NFSX_UNSIGNED;
                        authsiz = nfsm_rndup(auth_len);
                        goto add_cred;
                }
                break;
-       };
+#endif /* CONFIG_NFS_GSS */
+       }
+       ;
 
        /* finish setting up the packet */
-       if (!error)
+       if (!error) {
                error = mbuf_pkthdr_setrcvif(mreq, 0);
+       }
 
        if (error) {
                mbuf_freem(mreq);
-               return (error);
+               return error;
        }
 
        /* Calculate the size of the request */
        reqlen = 0;
-       for (mb = nmreq.nmc_mhead; mb; mb = mbuf_next(mb))
+       for (mb = nmreq.nmc_mhead; mb; mb = mbuf_next(mb)) {
                reqlen += mbuf_len(mb);
+       }
 
        mbuf_pkthdr_setlen(mreq, reqlen);
 
@@ -1200,25 +1308,29 @@ add_cred:
         * The record mark count doesn't include itself
         * and the last fragment bit is set.
         */
-       if (sotype == SOCK_STREAM)
+       if (sotype == SOCK_STREAM) {
                nfsm_chain_set_recmark(error, &nmreq,
-                       (reqlen - NFSX_UNSIGNED) | 0x80000000);
+                   (reqlen - NFSX_UNSIGNED) | 0x80000000);
+       }
 
        *mreqp = mreq;
-       return (0);
+       return 0;
 }
 
 /*
  * Parse an NFS file attribute structure out of an mbuf chain.
  */
 int
-nfs_parsefattr(struct nfsm_chain *nmc, int nfsvers, struct nfs_vattr *nvap)
+nfs_parsefattr(
+       __unused struct nfsmount *nmp,
+       struct nfsm_chain *nmc,
+       int nfsvers,
+       struct nfs_vattr *nvap)
 {
        int error = 0;
        enum vtype vtype;
        nfstype nvtype;
-       u_short vmode;
-       uint32_t val, val2;
+       uint32_t vmode, val, val2;
        dev_t rdev;
 
        val = val2 = 0;
@@ -1263,8 +1375,9 @@ nfs_parsefattr(struct nfsm_chain *nmc, int nfsvers, struct nfs_vattr *nvap)
                 * sockets and FIFOs for fa_type).
                 */
                vtype = nfstov_type(nvtype, nfsvers);
-               if ((vtype == VNON) || ((vtype == VREG) && ((vmode & S_IFMT) != 0)))
+               if ((vtype == VNON) || ((vtype == VREG) && ((vmode & S_IFMT) != 0))) {
                        vtype = IFTOVT(vmode);
+               }
                nvap->nva_type = vtype;
        }
 
@@ -1301,22 +1414,25 @@ nfs_parsefattr(struct nfsm_chain *nmc, int nfsvers, struct nfs_vattr *nvap)
                nfsmout_if(error);
                nvap->nva_fileid = (uint64_t)val;
                /* Really ugly NFSv2 kludge. */
-               if ((vtype == VCHR) && (rdev == (dev_t)0xffffffff))
+               if ((vtype == VCHR) && (rdev == (dev_t)0xffffffff)) {
                        nvap->nva_type = VFIFO;
+               }
        }
        nfsm_chain_get_time(error, nmc, nfsvers,
-               nvap->nva_timesec[NFSTIME_ACCESS],
-               nvap->nva_timensec[NFSTIME_ACCESS]);
+           nvap->nva_timesec[NFSTIME_ACCESS],
+           nvap->nva_timensec[NFSTIME_ACCESS]);
        nfsm_chain_get_time(error, nmc, nfsvers,
-               nvap->nva_timesec[NFSTIME_MODIFY],
-               nvap->nva_timensec[NFSTIME_MODIFY]);
+           nvap->nva_timesec[NFSTIME_MODIFY],
+           nvap->nva_timensec[NFSTIME_MODIFY]);
        nfsm_chain_get_time(error, nmc, nfsvers,
-               nvap->nva_timesec[NFSTIME_CHANGE],
-               nvap->nva_timensec[NFSTIME_CHANGE]);
+           nvap->nva_timesec[NFSTIME_CHANGE],
+           nvap->nva_timensec[NFSTIME_CHANGE]);
+
 nfsmout:
-       return (error);
+       return error;
 }
 
+
 /*
  * Load the attribute cache (that lives in the nfsnode entry) with
  * the value pointed to by nvap, unless the file type in the attribute
@@ -1357,7 +1473,7 @@ nfs_loadattrcache(
 
        if (!((nmp = VFSTONFS(mp)))) {
                FSDBG_BOT(527, ENXIO, 1, 0, *xidp);
-               return (ENXIO);
+               return ENXIO;
        }
 
        if (*xidp < np->n_xid) {
@@ -1374,7 +1490,7 @@ nfs_loadattrcache(
                NATTRINVALIDATE(np);
                FSDBG_BOT(527, 0, np, np->n_xid, *xidp);
                *xidp = 0;
-               return (0);
+               return 0;
        }
 
        if (vp && (nvap->nva_type != vnode_vtype(vp))) {
@@ -1400,10 +1516,11 @@ nfs_loadattrcache(
                 * object type.
                 */
                printf("nfs loadattrcache vnode changed type, was %d now %d\n",
-                       vnode_vtype(vp), nvap->nva_type);
+                   vnode_vtype(vp), nvap->nva_type);
                error = ESTALE;
-               if (monitored)
+               if (monitored) {
                        events |= VNODE_EVENT_DELETE;
+               }
                goto out;
        }
 
@@ -1422,73 +1539,104 @@ nfs_loadattrcache(
                 * For monitored nodes, check for attribute changes that should generate events.
                 */
                if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_NUMLINKS) &&
-                   (nvap->nva_nlink != npnvap->nva_nlink))
+                   (nvap->nva_nlink != npnvap->nva_nlink)) {
                        events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_LINK;
-               if (events & VNODE_EVENT_PERMS)
+               }
+               if (events & VNODE_EVENT_PERMS) {
                        /* no need to do all the checking if it's already set */;
-               else if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_MODE) &&
-                        (nvap->nva_mode != npnvap->nva_mode))
+               else if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_MODE) &&
+                   (nvap->nva_mode != npnvap->nva_mode)) {
                        events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_PERMS;
-               else if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER) &&
-                        (nvap->nva_uid != npnvap->nva_uid))
+               else if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER) &&
+                   (nvap->nva_uid != npnvap->nva_uid)) {
                        events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_PERMS;
-               else if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER_GROUP) &&
-                        (nvap->nva_gid != npnvap->nva_gid))
+               else if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER_GROUP) &&
+                   (nvap->nva_gid != npnvap->nva_gid)) {
                        events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_PERMS;
-               else if (nmp->nm_vers >= NFS_VER4) {
+#if CONFIG_NFS4
+               } else if (nmp->nm_vers >= NFS_VER4) {
                        if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER) &&
-                           !kauth_guid_equal(&nvap->nva_uuuid, &npnvap->nva_uuuid))
+                           !kauth_guid_equal(&nvap->nva_uuuid, &npnvap->nva_uuuid)) {
                                events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_PERMS;
-                       else if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER_GROUP) &&
-                                !kauth_guid_equal(&nvap->nva_guuid, &npnvap->nva_guuid))
+                       else if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER_GROUP) &&
+                           !kauth_guid_equal(&nvap->nva_guuid, &npnvap->nva_guuid)) {
                                events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_PERMS;
-                       else if ((NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_ACL) &&
-                                nvap->nva_acl && npnvap->nva_acl &&
-                                ((nvap->nva_acl->acl_entrycount != npnvap->nva_acl->acl_entrycount) ||
-                                 bcmp(nvap->nva_acl, npnvap->nva_acl, KAUTH_ACL_COPYSIZE(nvap->nva_acl)))))
+                       else if ((NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_ACL) &&
+                           nvap->nva_acl && npnvap->nva_acl &&
+                           ((nvap->nva_acl->acl_entrycount != npnvap->nva_acl->acl_entrycount) ||
+                           bcmp(nvap->nva_acl, npnvap->nva_acl, KAUTH_ACL_COPYSIZE(nvap->nva_acl))))) {
                                events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_PERMS;
+                       }
+#endif
                }
-               if (((nmp->nm_vers >= NFS_VER4) && (nvap->nva_change != npnvap->nva_change)) ||
-                  (NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_TIME_MODIFY) &&
-                   ((nvap->nva_timesec[NFSTIME_MODIFY] != npnvap->nva_timesec[NFSTIME_MODIFY]) ||
-                    (nvap->nva_timensec[NFSTIME_MODIFY] != npnvap->nva_timensec[NFSTIME_MODIFY]))))
+               if (/* Oh, C... */
+#if CONFIG_NFS4
+                       ((nmp->nm_vers >= NFS_VER4) && NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_CHANGE) && (nvap->nva_change != npnvap->nva_change)) ||
+#endif
+                       (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_TIME_MODIFY) &&
+                       ((nvap->nva_timesec[NFSTIME_MODIFY] != npnvap->nva_timesec[NFSTIME_MODIFY]) ||
+                       (nvap->nva_timensec[NFSTIME_MODIFY] != npnvap->nva_timensec[NFSTIME_MODIFY])))) {
                        events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_WRITE;
-               if (!events && NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_RAWDEV) &&
+               }
+               if (!events && NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_RAWDEV) &&
                    ((nvap->nva_rawdev.specdata1 != npnvap->nva_rawdev.specdata1) ||
-                    (nvap->nva_rawdev.specdata2 != npnvap->nva_rawdev.specdata2)))
+                   (nvap->nva_rawdev.specdata2 != npnvap->nva_rawdev.specdata2))) {
                        events |= VNODE_EVENT_ATTRIB;
-               if (!events && NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_FILEID) &&
-                   (nvap->nva_fileid != npnvap->nva_fileid))
+               }
+               if (!events && NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_FILEID) &&
+                   (nvap->nva_fileid != npnvap->nva_fileid)) {
                        events |= VNODE_EVENT_ATTRIB;
-               if (!events && NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_ARCHIVE) &&
-                   ((nvap->nva_flags & NFS_FFLAG_ARCHIVED) != (npnvap->nva_flags & NFS_FFLAG_ARCHIVED)))
+               }
+               if (!events && NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_ARCHIVE) &&
+                   ((nvap->nva_flags & NFS_FFLAG_ARCHIVED) != (npnvap->nva_flags & NFS_FFLAG_ARCHIVED))) {
                        events |= VNODE_EVENT_ATTRIB;
-               if (!events && NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_HIDDEN) &&
-                   ((nvap->nva_flags & NFS_FFLAG_HIDDEN) != (npnvap->nva_flags & NFS_FFLAG_HIDDEN)))
+               }
+               if (!events && NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_HIDDEN) &&
+                   ((nvap->nva_flags & NFS_FFLAG_HIDDEN) != (npnvap->nva_flags & NFS_FFLAG_HIDDEN))) {
                        events |= VNODE_EVENT_ATTRIB;
-               if (!events && NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_TIME_CREATE) &&
+               }
+               if (!events && NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_TIME_CREATE) &&
                    ((nvap->nva_timesec[NFSTIME_CREATE] != npnvap->nva_timesec[NFSTIME_CREATE]) ||
-                    (nvap->nva_timensec[NFSTIME_CREATE] != npnvap->nva_timensec[NFSTIME_CREATE])))
+                   (nvap->nva_timensec[NFSTIME_CREATE] != npnvap->nva_timensec[NFSTIME_CREATE]))) {
                        events |= VNODE_EVENT_ATTRIB;
-               if (!events && NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_TIME_BACKUP) &&
+               }
+               if (!events && NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_TIME_BACKUP) &&
                    ((nvap->nva_timesec[NFSTIME_BACKUP] != npnvap->nva_timesec[NFSTIME_BACKUP]) ||
-                    (nvap->nva_timensec[NFSTIME_BACKUP] != npnvap->nva_timensec[NFSTIME_BACKUP])))
+                   (nvap->nva_timensec[NFSTIME_BACKUP] != npnvap->nva_timensec[NFSTIME_BACKUP]))) {
                        events |= VNODE_EVENT_ATTRIB;
+               }
        }
 
+#if CONFIG_NFS4
        /* Copy the attributes to the attribute cache */
-       bcopy((caddr_t)nvap, (caddr_t)npnvap, sizeof(*nvap));
+       if (nmp->nm_vers >= NFS_VER4 && npnvap->nva_flags & NFS_FFLAG_PARTIAL_WRITE) {
+               /*
+                * NFSv4 WRITE RPCs contain partial GETATTR requests - only type, change, size, metadatatime and modifytime are requested.
+                * In such cases,  we do not update the time stamp - but the requested attributes.
+                */
+               NFS_BITMAP_COPY_ATTR(nvap, npnvap, TYPE, type);
+               NFS_BITMAP_COPY_ATTR(nvap, npnvap, CHANGE, change);
+               NFS_BITMAP_COPY_ATTR(nvap, npnvap, SIZE, size);
+               NFS_BITMAP_COPY_TIME(nvap, npnvap, METADATA, CHANGE);
+               NFS_BITMAP_COPY_TIME(nvap, npnvap, MODIFY, MODIFY);
+       } else
+#endif /* CONFIG_NFS4 */
+       {
+               bcopy((caddr_t)nvap, (caddr_t)npnvap, sizeof(*nvap));
+               microuptime(&now);
+               np->n_attrstamp = now.tv_sec;
+       }
 
-       microuptime(&now);
-       np->n_attrstamp = now.tv_sec;
        np->n_xid = *xidp;
        /* NFS_FFLAG_IS_ATTR and NFS_FFLAG_TRIGGER_REFERRAL need to be sticky... */
-       if (vp && xattr)
+       if (vp && xattr) {
                nvap->nva_flags |= xattr;
-       if (vp && referral)
+       }
+       if (vp && referral) {
                nvap->nva_flags |= referral;
+       }
 
-       if (NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_ACL)) {
+       if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_ACL)) {
                /* we're updating the ACL */
                if (nvap->nva_acl) {
                        /* make a copy of the acl for the cache */
@@ -1507,17 +1655,19 @@ nfs_loadattrcache(
                        acl = NULL;
                }
        }
-       if (NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_ACL)) {
+       if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_ACL)) {
                /* update the ACL timestamp */
                np->n_aclstamp = now.tv_sec;
        } else {
                /* we aren't updating the ACL, so restore original values */
-               if (aclbit)
+               if (aclbit) {
                        NFS_BITMAP_SET(npnvap->nva_bitmap, NFS_FATTR_ACL);
+               }
                npnvap->nva_acl = acl;
        }
 
 #if CONFIG_TRIGGERS
+#if CONFIG_NFS4
        /*
         * For NFSv4, if the fsid doesn't match the fsid for the mount, then
         * this node is for a different file system on the server.  So we mark
@@ -1525,9 +1675,11 @@ nfs_loadattrcache(
         */
        if ((nmp->nm_vers >= NFS_VER4) && (nvap->nva_type == VDIR) &&
            ((np->n_vattr.nva_fsid.major != nmp->nm_fsid.major) ||
-            (np->n_vattr.nva_fsid.minor != nmp->nm_fsid.minor)))
+           (np->n_vattr.nva_fsid.minor != nmp->nm_fsid.minor))) {
                np->n_vattr.nva_flags |= NFS_FFLAG_TRIGGER;
-#endif
+       }
+#endif /* CONFIG_NFS4 */
+#endif /* CONFIG_TRIGGERS */
 
        if (!vp || (nvap->nva_type != VREG)) {
                np->n_size = nvap->nva_size;
@@ -1552,8 +1704,9 @@ nfs_loadattrcache(
                         */
                        np->n_newsize = nvap->nva_size;
                        SET(np->n_flag, NUPDATESIZE);
-                       if (monitored)
+                       if (monitored) {
                                events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_EXTEND;
+                       }
                }
        }
 
@@ -1569,33 +1722,38 @@ nfs_loadattrcache(
        }
 
 out:
-       if (monitored && events)
+       if (monitored && events) {
                nfs_vnode_notify(np, events);
+       }
        FSDBG_BOT(527, error, np, np->n_size, *xidp);
-       return (error);
+       return error;
 }
 
 /*
  * Calculate the attribute timeout based on
  * how recently the file has been modified.
  */
-int
+long
 nfs_attrcachetimeout(nfsnode_t np)
 {
        struct nfsmount *nmp;
        struct timeval now;
        int isdir;
-       uint32_t timeo;
+       long timeo;
 
-       if (!(nmp = NFSTONMP(np)))
-               return (0);
+       nmp = NFSTONMP(np);
+       if (nfs_mount_gone(nmp)) {
+               return 0;
+       }
 
        isdir = vnode_isdir(NFSTOV(np));
-
+#if CONFIG_NFS4
        if ((nmp->nm_vers >= NFS_VER4) && (np->n_openflags & N_DELEG_MASK)) {
                /* If we have a delegation, we always use the max timeout. */
                timeo = isdir ? nmp->nm_acdirmax : nmp->nm_acregmax;
-       } else if ((np)->n_flag & NMODIFIED) {
+       } else
+#endif
+       if ((np)->n_flag & NMODIFIED) {
                /* If we have modifications, we always use the min timeout. */
                timeo = isdir ? nmp->nm_acdirmin : nmp->nm_acregmin;
        } else {
@@ -1605,19 +1763,21 @@ nfs_attrcachetimeout(nfsnode_t np)
                microtime(&now);
                timeo = (now.tv_sec - (np)->n_vattr.nva_timesec[NFSTIME_MODIFY]) / 10;
                if (isdir) {
-                       if (timeo < nmp->nm_acdirmin)
+                       if (timeo < nmp->nm_acdirmin) {
                                timeo = nmp->nm_acdirmin;
-                       else if (timeo > nmp->nm_acdirmax)
+                       } else if (timeo > nmp->nm_acdirmax) {
                                timeo = nmp->nm_acdirmax;
+                       }
                } else {
-                       if (timeo < nmp->nm_acregmin)
+                       if (timeo < nmp->nm_acregmin) {
                                timeo = nmp->nm_acregmin;
-                       else if (timeo > nmp->nm_acregmax)
+                       } else if (timeo > nmp->nm_acregmax) {
                                timeo = nmp->nm_acregmax;
+                       }
                }
        }
 
-       return (timeo);
+       return timeo;
 }
 
 /*
@@ -1631,27 +1791,45 @@ nfs_getattrcache(nfsnode_t np, struct nfs_vattr *nvaper, int flags)
 {
        struct nfs_vattr *nvap;
        struct timeval nowup;
-       int32_t timeo;
+       long timeo;
+       struct nfsmount *nmp;
 
        /* Check if the attributes are valid. */
        if (!NATTRVALID(np) || ((flags & NGA_ACL) && !NACLVALID(np))) {
                FSDBG(528, np, 0, 0xffffff01, ENOENT);
                OSAddAtomic64(1, &nfsstats.attrcache_misses);
-               return (ENOENT);
+               return ENOENT;
        }
 
-       /* Verify the cached attributes haven't timed out. */
-       timeo = nfs_attrcachetimeout(np);
-       microuptime(&nowup);
-       if ((nowup.tv_sec - np->n_attrstamp) >= timeo) {
-               FSDBG(528, np, 0, 0xffffff02, ENOENT);
-               OSAddAtomic64(1, &nfsstats.attrcache_misses);
-               return (ENOENT);
+       nmp = NFSTONMP(np);
+       if (nfs_mount_gone(nmp)) {
+               return ENXIO;
        }
-       if ((flags & NGA_ACL) && ((nowup.tv_sec - np->n_aclstamp) >= timeo)) {
-               FSDBG(528, np, 0, 0xffffff02, ENOENT);
-               OSAddAtomic64(1, &nfsstats.attrcache_misses);
-               return (ENOENT);
+       /*
+        * Verify the cached attributes haven't timed out.
+        * If the server isn't responding, skip the check
+        * and return cached attributes.
+        */
+       if (!nfs_use_cache(nmp)) {
+               microuptime(&nowup);
+               if (np->n_attrstamp > nowup.tv_sec) {
+                       printf("NFS: Attribute time stamp is in the future by %ld seconds. Invalidating cache\n",
+                           np->n_attrstamp - nowup.tv_sec);
+                       NATTRINVALIDATE(np);
+                       NACCESSINVALIDATE(np);
+                       return ENOENT;
+               }
+               timeo = nfs_attrcachetimeout(np);
+               if ((nowup.tv_sec - np->n_attrstamp) >= timeo) {
+                       FSDBG(528, np, 0, 0xffffff02, ENOENT);
+                       OSAddAtomic64(1, &nfsstats.attrcache_misses);
+                       return ENOENT;
+               }
+               if ((flags & NGA_ACL) && ((nowup.tv_sec - np->n_aclstamp) >= timeo)) {
+                       FSDBG(528, np, 0, 0xffffff02, ENOENT);
+                       OSAddAtomic64(1, &nfsstats.attrcache_misses);
+                       return ENOENT;
+               }
        }
 
        nvap = &np->n_vattr;
@@ -1691,14 +1869,15 @@ nfs_getattrcache(nfsnode_t np, struct nfs_vattr *nvaper, int flags)
        if (nvap->nva_acl) {
                if (flags & NGA_ACL) {
                        nvaper->nva_acl = kauth_acl_alloc(nvap->nva_acl->acl_entrycount);
-                       if (!nvaper->nva_acl)
-                               return (ENOMEM);
+                       if (!nvaper->nva_acl) {
+                               return ENOMEM;
+                       }
                        bcopy(nvap->nva_acl, nvaper->nva_acl, KAUTH_ACL_COPYSIZE(nvap->nva_acl));
                } else {
                        nvaper->nva_acl = NULL;
                }
        }
-       return (0);
+       return 0;
 }
 
 /*
@@ -1768,36 +1947,47 @@ nfs_avoid_needless_id_setting_on_create(nfsnode_t dnp, struct vnode_attr *vap, v
 int
 nfs_uaddr2sockaddr(const char *uaddr, struct sockaddr *addr)
 {
-       const char *p, *pd;     /* pointers to current character in scan */
-       const char *pnum;       /* pointer to current number to decode */
-       const char *pscope;     /* pointer to IPv6 scope ID */
-       uint8_t a[18];          /* octet array to store address bytes */
-       int i;                  /* index of next octet to decode */
-       int dci;                /* index of octet to insert double-colon zeroes */
-       int dcount, xdcount;    /* count of digits in current number */
-       int needmore;           /* set when we know we need more input (e.g. after colon, period) */
-       int dots;               /* # of dots */
-       int hex;                /* contains hex values */
-       unsigned long val;      /* decoded value */
-       int s;                  /* index used for sliding array to insert elided zeroes */
-
-#define HEXVALUE       0
-#define DECIMALVALUE   1
+       const char *p, *pd;     /* pointers to current character in scan */
+       const char *pnum;       /* pointer to current number to decode */
+       const char *pscope;     /* pointer to IPv6 scope ID */
+       uint8_t a[18];          /* octet array to store address bytes */
+       int i;                  /* index of next octet to decode */
+       int dci;                /* index of octet to insert double-colon zeroes */
+       int dcount, xdcount;    /* count of digits in current number */
+       int needmore;           /* set when we know we need more input (e.g. after colon, period) */
+       int dots;               /* # of dots */
+       int hex;                /* contains hex values */
+       unsigned long val;      /* decoded value */
+       int s;                  /* index used for sliding array to insert elided zeroes */
+
+       /* AF_LOCAL address are paths that start with '/' or are empty */
+       if (*uaddr == '/' || *uaddr == '\0') { /* AF_LOCAL address */
+               struct sockaddr_un *sun = (struct sockaddr_un *)addr;
+               sun->sun_family = AF_LOCAL;
+               sun->sun_len = sizeof(struct sockaddr_un);
+               strlcpy(sun->sun_path, uaddr, sizeof(sun->sun_path));
+
+               return 1;
+       }
+
+#define HEXVALUE        0
+#define DECIMALVALUE    1
+
 #define GET(TYPE) \
        do { \
-               if ((dcount <= 0) || (dcount > (((TYPE) == DECIMALVALUE) ? 3 : 4))) \
-                       return (0); \
-               if (((TYPE) == DECIMALVALUE) && xdcount) \
-                       return (0); \
-               val = strtoul(pnum, NULL, ((TYPE) == DECIMALVALUE) ? 10 : 16); \
-               if (((TYPE) == DECIMALVALUE) && (val >= 256)) \
-                       return (0); \
-               /* check if there is room left in the array */ \
-               if (i > (int)(sizeof(a) - (((TYPE) == HEXVALUE) ? 2 : 1) - ((dci != -1) ? 2 : 0))) \
-                       return (0); \
-               if ((TYPE) == HEXVALUE) \
-                       a[i++] = ((val >> 8) & 0xff); \
-               a[i++] = (val & 0xff); \
+               if ((dcount <= 0) || (dcount > (((TYPE) == DECIMALVALUE) ? 3 : 4))) \
+                       return (0); \
+               if (((TYPE) == DECIMALVALUE) && xdcount) \
+                       return (0); \
+               val = strtoul(pnum, NULL, ((TYPE) == DECIMALVALUE) ? 10 : 16); \
+               if (((TYPE) == DECIMALVALUE) && (val >= 256)) \
+                       return (0); \
+       /* check if there is room left in the array */ \
+               if (i > (int)(sizeof(a) - (((TYPE) == HEXVALUE) ? 2 : 1) - ((dci != -1) ? 2 : 0))) \
+                       return (0); \
+               if ((TYPE) == HEXVALUE) \
+                       a[i++] = ((val >> 8) & 0xff); \
+               a[i++] = (val & 0xff); \
        } while (0)
 
        hex = 0;
@@ -1807,14 +1997,16 @@ nfs_uaddr2sockaddr(const char *uaddr, struct sockaddr *addr)
        pnum = p = uaddr;
        pscope = NULL;
        needmore = 1;
-       if ((*p == ':') && (*++p != ':')) /* if it starts with colon, gotta be a double */
-               return (0);
+       if ((*p == ':') && (*++p != ':')) { /* if it starts with colon, gotta be a double */
+               return 0;
+       }
 
        while (*p) {
                if (IS_XDIGIT(*p)) {
                        dcount++;
-                       if (!IS_DIGIT(*p))
+                       if (!IS_DIGIT(*p)) {
                                xdcount++;
+                       }
                        needmore = 0;
                        p++;
                } else if (*p == '.') {
@@ -1823,21 +2015,25 @@ nfs_uaddr2sockaddr(const char *uaddr, struct sockaddr *addr)
                                /* this is the first, so count them */
                                for (pd = p; *pd; pd++) {
                                        if (*pd == '.') {
-                                               if (++dots > 5)
-                                                       return (0);
+                                               if (++dots > 5) {
+                                                       return 0;
+                                               }
                                        } else if (hex && (*pd == '%')) {
                                                break;
                                        } else if ((*pd < '0') || (*pd > '9')) {
-                                               return (0);
+                                               return 0;
                                        }
                                }
-                               if ((dots != 2) && (dots != 3) && (dots != 5))
-                                       return (0);
+                               if ((dots != 2) && (dots != 3) && (dots != 5)) {
+                                       return 0;
+                               }
                                if (hex && (dots == 2)) { /* hex+port */
-                                       if (!dcount && needmore)
-                                               return (0);
-                                       if (dcount) /* last hex may be elided zero */
+                                       if (!dcount && needmore) {
+                                               return 0;
+                                       }
+                                       if (dcount) { /* last hex may be elided zero */
                                                GET(HEXVALUE);
+                                       }
                                } else {
                                        GET(DECIMALVALUE);
                                }
@@ -1849,11 +2045,13 @@ nfs_uaddr2sockaddr(const char *uaddr, struct sockaddr *addr)
                        pnum = ++p;
                } else if (*p == ':') {
                        hex = 1;
-                       if (dots)
-                               return (0);
+                       if (dots) {
+                               return 0;
+                       }
                        if (!dcount) { /* missing number, probably double colon */
-                               if (dci >= 0) /* can only have one double colon */
-                                       return (0);
+                               if (dci >= 0) { /* can only have one double colon */
+                                       return 0;
+                               }
                                dci = i;
                                needmore = 0;
                        } else {
@@ -1863,99 +2061,210 @@ nfs_uaddr2sockaddr(const char *uaddr, struct sockaddr *addr)
                        }
                        pnum = ++p;
                } else if (*p == '%') { /* scope ID delimiter */
-                       if (!hex)
-                               return (0);
+                       if (!hex) {
+                               return 0;
+                       }
                        p++;
                        pscope = p;
                        break;
                } else { /* unexpected character */
-                       return (0);
+                       return 0;
                }
        }
-       if (needmore && !dcount)
-               return (0);
-       if (dcount) /* decode trailing number */
+       if (needmore && !dcount) {
+               return 0;
+       }
+       if (dcount) { /* decode trailing number */
                GET(dots ? DECIMALVALUE : HEXVALUE);
+       }
        if (dci >= 0) {  /* got a double-colon at i, need to insert a range of zeroes */
                /* if we got a port, slide to end of array */
                /* otherwise, slide to end of address (non-port) values */
                int end = ((dots == 2) || (dots == 5)) ? sizeof(a) : (sizeof(a) - 2);
-               if (i % 2) /* length of zero range must be multiple of 2 */
-                       return (0);
-               if (i >= end) /* no room? */
-                       return (0);
+               if (i % 2) { /* length of zero range must be multiple of 2 */
+                       return 0;
+               }
+               if (i >= end) { /* no room? */
+                       return 0;
+               }
                /* slide (i-dci) numbers up from index dci */
-               for (s=0; s < (i - dci); s++)
-                       a[end-1-s] = a[i-1-s];
+               for (s = 0; s < (i - dci); s++) {
+                       a[end - 1 - s] = a[i - 1 - s];
+               }
                /* zero (end-i) numbers at index dci */
-               for (s=0; s < (end - i); s++)
-                       a[dci+s] = 0;
+               for (s = 0; s < (end - i); s++) {
+                       a[dci + s] = 0;
+               }
                i = end;
        }
 
        /* copy out resulting socket address */
        if (hex) {
                struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)addr;
-               if ((((dots == 0) || (dots == 3)) && (i != (sizeof(a)-2))))
-                       return (0);
-               if ((((dots == 2) || (dots == 5)) && (i != sizeof(a))))
-                       return (0);
+               if ((((dots == 0) || (dots == 3)) && (i != (sizeof(a) - 2)))) {
+                       return 0;
+               }
+               if ((((dots == 2) || (dots == 5)) && (i != sizeof(a)))) {
+                       return 0;
+               }
                bzero(sin6, sizeof(struct sockaddr_in6));
                sin6->sin6_len = sizeof(struct sockaddr_in6);
                sin6->sin6_family = AF_INET6;
                bcopy(a, &sin6->sin6_addr.s6_addr, sizeof(struct in6_addr));
-               if ((dots == 5) || (dots == 2))
-                       sin6->sin6_port = htons((a[16] << 8) | a[17]);
+               if ((dots == 5) || (dots == 2)) {
+                       sin6->sin6_port = htons((in_port_t)((a[16] << 8) | a[17]));
+               }
                if (pscope) {
-                       for (p=pscope; IS_DIGIT(*p); p++)
+                       for (p = pscope; IS_DIGIT(*p); p++) {
                                ;
+                       }
                        if (*p && !IS_DIGIT(*p)) { /* name */
                                ifnet_t interface = NULL;
-                               if (ifnet_find_by_name(pscope, &interface) == 0)
+                               if (ifnet_find_by_name(pscope, &interface) == 0) {
                                        sin6->sin6_scope_id = ifnet_index(interface);
-                               if (interface)
+                               }
+                               if (interface) {
                                        ifnet_release(interface);
+                               }
                        } else { /* decimal number */
-                               sin6->sin6_scope_id = strtoul(pscope, NULL, 10);
+                               sin6->sin6_scope_id = (uint32_t)strtoul(pscope, NULL, 10);
                        }
                        /* XXX should we also embed scope id for linklocal? */
                }
        } else {
                struct sockaddr_in *sin = (struct sockaddr_in*)addr;
-               if ((dots != 3) && (dots != 5))
-                       return (0);
-               if ((dots == 3) && (i != 4))
-                       return (0);
-               if ((dots == 5) && (i != 6))
-                       return (0);
+               if ((dots != 3) && (dots != 5)) {
+                       return 0;
+               }
+               if ((dots == 3) && (i != 4)) {
+                       return 0;
+               }
+               if ((dots == 5) && (i != 6)) {
+                       return 0;
+               }
                bzero(sin, sizeof(struct sockaddr_in));
                sin->sin_len = sizeof(struct sockaddr_in);
                sin->sin_family = AF_INET;
                bcopy(a, &sin->sin_addr.s_addr, sizeof(struct in_addr));
-               if (dots == 5)
-                       sin->sin_port = htons((a[4] << 8) | a[5]);
+               if (dots == 5) {
+                       sin->sin_port = htons((in_port_t)((a[4] << 8) | a[5]));
+               }
+       }
+       return 1;
+}
+
+
+/* NFS Client debugging support */
+uint32_t nfs_debug_ctl;
+
+#include <libkern/libkern.h>
+#include <stdarg.h>
+
+void
+nfs_printf(unsigned int facility, unsigned int level, const char *fmt, ...)
+{
+       va_list ap;
+
+       if (NFS_IS_DBG(facility, level)) {
+               va_start(ap, fmt);
+               vprintf(fmt, ap);
+               va_end(ap);
        }
-       return (1);
 }
 
 
-#endif /* NFSCLIENT */
+#define DISPLAYLEN 16
+
+static bool
+isprint(int ch)
+{
+       return ch >= 0x20 && ch <= 0x7e;
+}
+
+static void
+hexdump(void *data, size_t len)
+{
+       size_t i, j;
+       unsigned char *d = data;
+       char *p, disbuf[3 * DISPLAYLEN + 1];
+
+       for (i = 0; i < len; i += DISPLAYLEN) {
+               for (p = disbuf, j = 0; (j + i) < len && j < DISPLAYLEN; j++, p += 3) {
+                       snprintf(p, 4, "%2.2x ", d[i + j]);
+               }
+               for (; j < DISPLAYLEN; j++, p += 3) {
+                       snprintf(p, 4, "   ");
+               }
+               printf("%s    ", disbuf);
+               for (p = disbuf, j = 0; (j + i) < len && j < DISPLAYLEN; j++, p++) {
+                       snprintf(p, 2, "%c", isprint(d[i + j]) ? d[i + j] : '.');
+               }
+               printf("%s\n", disbuf);
+       }
+}
+
+void
+nfs_dump_mbuf(const char *func, int lineno, const char *msg, mbuf_t mb)
+{
+       mbuf_t m;
+
+       printf("%s:%d %s\n", func, lineno, msg);
+       for (m = mb; m; m = mbuf_next(m)) {
+               hexdump(mbuf_data(m), mbuf_len(m));
+       }
+}
+
+/* Is a mount gone away? */
+int
+nfs_mount_gone(struct nfsmount *nmp)
+{
+       return !nmp || vfs_isforce(nmp->nm_mountp) || (nmp->nm_state & (NFSSTA_FORCE | NFSSTA_DEAD));
+}
+
+/*
+ * Return some of the more significant mount options
+ * as a string, e.g. "'ro,hard,intr,tcp,vers=3,sec=krb5,deadtimeout=0'
+ */
+int
+nfs_mountopts(struct nfsmount *nmp, char *buf, int buflen)
+{
+       int c;
+
+       c = snprintf(buf, buflen, "%s,%s,%s,%s,vers=%d,sec=%s,%sdeadtimeout=%d",
+           (vfs_flags(nmp->nm_mountp) & MNT_RDONLY) ? "ro" : "rw",
+           NMFLAG(nmp, SOFT) ? "soft" : "hard",
+           NMFLAG(nmp, INTR) ? "intr" : "nointr",
+           nmp->nm_sotype == SOCK_STREAM ? "tcp" : "udp",
+           nmp->nm_vers,
+           nmp->nm_auth == RPCAUTH_KRB5  ? "krb5" :
+           nmp->nm_auth == RPCAUTH_KRB5I ? "krb5i" :
+           nmp->nm_auth == RPCAUTH_KRB5P ? "krb5p" :
+           nmp->nm_auth == RPCAUTH_SYS   ? "sys" : "none",
+           nmp->nm_lockmode == NFS_LOCK_MODE_ENABLED ?  "locks," :
+           nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED ? "nolocks," :
+           nmp->nm_lockmode == NFS_LOCK_MODE_LOCAL ? "locallocks," : "",
+           nmp->nm_deadtimeout);
+
+       return c > buflen ? ENOMEM : 0;
+}
+
+#endif /* CONFIG_NFS_CLIENT */
 
 /*
  * Schedule a callout thread to run an NFS timer function
  * interval milliseconds in the future.
  */
 void
-nfs_interval_timer_start(thread_call_t call, int interval)
+nfs_interval_timer_start(thread_call_t call, time_t interval)
 {
        uint64_t deadline;
 
-       clock_interval_to_deadline(interval, 1000 * 1000, &deadline);
+       clock_interval_to_deadline((int)interval, 1000 * 1000, &deadline);
        thread_call_enter_delayed(call, deadline);
 }
 
 
-#if NFSSERVER
+#if CONFIG_NFS_SERVER
 
 int nfsrv_cmp_secflavs(struct nfs_sec *, struct nfs_sec *);
 int nfsrv_hang_addrlist(struct nfs_export *, struct user_nfs_export_args *);
@@ -1991,7 +2300,7 @@ nfsm_chain_add_wcc_data_f(
        }
        nfsm_chain_add_postop_attr(error, nd, nmc, postattrerr, postvap);
 
-       return (error);
+       return error;
 }
 
 /*
@@ -2008,38 +2317,40 @@ nfsm_chain_get_path_namei(
        int error = 0;
        char *cp;
 
-       if (len > (MAXPATHLEN - 1))
-               return (ENAMETOOLONG);
+       if (len > (MAXPATHLEN - 1)) {
+               return ENAMETOOLONG;
+       }
 
        /*
         * Get a buffer for the name to be translated, and copy the
         * name into the buffer.
         */
-       MALLOC_ZONE(cnp->cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
-       if (!cnp->cn_pnbuf)
-               return (ENOMEM);
+       cnp->cn_pnbuf = zalloc(ZV_NAMEI);
        cnp->cn_pnlen = MAXPATHLEN;
        cnp->cn_flags |= HASBUF;
 
        /* Copy the name from the mbuf list to the string */
        cp = cnp->cn_pnbuf;
        nfsm_chain_get_opaque(error, nmc, len, cp);
-       if (error)
+       if (error) {
                goto out;
+       }
        cnp->cn_pnbuf[len] = '\0';
 
        /* sanity check the string */
-       if ((strlen(cp) != len) || strchr(cp, '/'))
+       if ((strlen(cp) != len) || strchr(cp, '/')) {
                error = EACCES;
+       }
 out:
        if (error) {
-               if (cnp->cn_pnbuf)
-                       FREE_ZONE(cnp->cn_pnbuf, MAXPATHLEN, M_NAMEI);
+               if (cnp->cn_pnbuf) {
+                       NFS_ZFREE(ZV_NAMEI, cnp->cn_pnbuf);
+               }
                cnp->cn_flags &= ~HASBUF;
        } else {
                nip->ni_pathlen = len;
        }
-       return (error);
+       return error;
 }
 
 /*
@@ -2067,8 +2378,9 @@ nfsrv_namei(
         * Extract and set starting directory.
         */
        error = nfsrv_fhtovp(nfhp, nd, &dp, nxp, nxop);
-       if (error)
+       if (error) {
                goto out;
+       }
        error = nfsrv_credcheck(nd, ctx, *nxp, *nxop);
        if (error || (vnode_vtype(dp) != VDIR)) {
                vnode_put(dp);
@@ -2079,12 +2391,14 @@ nfsrv_namei(
 
        nip->ni_cnd.cn_context = ctx;
 
-       if (*nxop && ((*nxop)->nxo_flags & NX_READONLY))
+       if (*nxop && ((*nxop)->nxo_flags & NX_READONLY)) {
                cnp->cn_flags |= RDONLY;
+       }
 
        cnp->cn_flags |= NOCROSSMOUNT;
        cnp->cn_nameptr = cnp->cn_pnbuf;
        nip->ni_usedvp = nip->ni_startdir = dp;
+       nip->ni_rootdir = rootvnode;
 
        /*
         * And call lookup() to do the real work
@@ -2095,19 +2409,15 @@ nfsrv_namei(
                cnp->cn_nameptr = cnp->cn_pnbuf;
                nip->ni_usedvp = nip->ni_dvp = nip->ni_startdir = dp;
        }
-       if (error)
+       if (error) {
                goto out;
+       }
 
        /* Check for encountering a symbolic link */
        if (cnp->cn_flags & ISSYMLINK) {
-#if CONFIG_VFS_FUNNEL
-               if ((cnp->cn_flags & FSNODELOCKHELD)) {
-                       cnp->cn_flags &= ~FSNODELOCKHELD;
-                       unlock_fsnode(nip->ni_dvp, NULL);
-               }
-#endif /* CONFIG_VFS_FUNNEL */
-               if (cnp->cn_flags & (LOCKPARENT | WANTPARENT))
+               if (cnp->cn_flags & (LOCKPARENT | WANTPARENT)) {
                        vnode_put(nip->ni_dvp);
+               }
                if (nip->ni_vp) {
                        vnode_put(nip->ni_vp);
                        nip->ni_vp = NULL;
@@ -2119,9 +2429,9 @@ out:
                tmppn = cnp->cn_pnbuf;
                cnp->cn_pnbuf = NULL;
                cnp->cn_flags &= ~HASBUF;
-               FREE_ZONE(tmppn, cnp->cn_pnlen, M_NAMEI);
+               NFS_ZFREE(ZV_NAMEI, tmppn);
        }
-       return (error);
+       return error;
 }
 
 /*
@@ -2132,7 +2442,8 @@ void
 nfsm_adj(mbuf_t mp, int len, int nul)
 {
        mbuf_t m, mnext;
-       int count, i, mlen;
+       int count, i;
+       long mlen;
        char *cp;
 
        /*
@@ -2148,8 +2459,9 @@ nfsm_adj(mbuf_t mp, int len, int nul)
                mlen = mbuf_len(m);
                count += mlen;
                mnext = mbuf_next(m);
-               if (mnext == NULL)
+               if (mnext == NULL) {
                        break;
+               }
                m = mnext;
        }
        if (mlen > len) {
@@ -2157,14 +2469,16 @@ nfsm_adj(mbuf_t mp, int len, int nul)
                mbuf_setlen(m, mlen);
                if (nul > 0) {
                        cp = (caddr_t)mbuf_data(m) + mlen - nul;
-                       for (i = 0; i < nul; i++)
+                       for (i = 0; i < nul; i++) {
                                *cp++ = '\0';
+                       }
                }
                return;
        }
        count -= len;
-       if (count < 0)
+       if (count < 0) {
                count = 0;
+       }
        /*
         * Correct length for chain is "count".
         * Find the mbuf with last data, adjust its length,
@@ -2177,15 +2491,17 @@ nfsm_adj(mbuf_t mp, int len, int nul)
                        mbuf_setlen(m, count);
                        if (nul > 0) {
                                cp = (caddr_t)mbuf_data(m) + mlen - nul;
-                               for (i = 0; i < nul; i++)
+                               for (i = 0; i < nul; i++) {
                                        *cp++ = '\0';
+                               }
                        }
                        break;
                }
                count -= mlen;
        }
-       for (m = mbuf_next(m); m; m = mbuf_next(m))
+       for (m = mbuf_next(m); m; m = mbuf_next(m)) {
                mbuf_setlen(m, 0);
+       }
 }
 
 /*
@@ -2195,18 +2511,22 @@ nfsm_adj(mbuf_t mp, int len, int nul)
 int
 nfsm_chain_trim_data(struct nfsm_chain *nmc, int len, int *mlen)
 {
-       int cnt = 0, dlen, adjust;
+       int cnt = 0;
+       long dlen, adjust;
        caddr_t data;
        mbuf_t m;
 
-       if (mlen)
+       if (mlen) {
                *mlen = 0;
+       }
 
        /* trim header */
-       for (m = nmc->nmc_mhead; m && (m != nmc->nmc_mcur); m = mbuf_next(m))
+       for (m = nmc->nmc_mhead; m && (m != nmc->nmc_mcur); m = mbuf_next(m)) {
                mbuf_setlen(m, 0);
-       if (!m)
-               return (EIO);
+       }
+       if (!m) {
+               return EIO;
+       }
 
        /* trim current mbuf */
        data = mbuf_data(m);
@@ -2214,10 +2534,12 @@ nfsm_chain_trim_data(struct nfsm_chain *nmc, int len, int *mlen)
        adjust = nmc->nmc_ptr - data;
        dlen -= adjust;
        if ((dlen > 0) && (adjust > 0)) {
-               if (mbuf_setdata(m, nmc->nmc_ptr, dlen))
-                       return(EIO);
-       } else
+               if (mbuf_setdata(m, nmc->nmc_ptr, dlen)) {
+                       return EIO;
+               }
+       } else {
                mbuf_setlen(m, dlen);
+       }
 
        /* skip next len bytes  */
        for (; m && (cnt < len); m = mbuf_next(m)) {
@@ -2226,21 +2548,25 @@ nfsm_chain_trim_data(struct nfsm_chain *nmc, int len, int *mlen)
                if (cnt > len) {
                        /* truncate to end of data */
                        mbuf_setlen(m, dlen - (cnt - len));
-                       if (m == nmc->nmc_mcur)
+                       if (m == nmc->nmc_mcur) {
                                nmc->nmc_left -= (cnt - len);
+                       }
                        cnt = len;
                }
        }
-       if (mlen)
+       if (mlen) {
                *mlen = cnt;
+       }
 
        /* trim any trailing data */
-       if (m == nmc->nmc_mcur)
+       if (m == nmc->nmc_mcur) {
                nmc->nmc_left = 0;
-       for (; m; m = mbuf_next(m))
+       }
+       for (; m; m = mbuf_next(m)) {
                mbuf_setlen(m, 0);
+       }
 
-       return (0);
+       return 0;
 }
 
 int
@@ -2272,10 +2598,11 @@ nfsm_chain_add_fattr(
        } else {
                nfsm_chain_add_32(error, nmc, vap->va_data_size);
                nfsm_chain_add_32(error, nmc, NFS_FABLKSIZE);
-               if (vap->va_type == VFIFO)
+               if (vap->va_type == VFIFO) {
                        nfsm_chain_add_32(error, nmc, 0xffffffff);
-               else
+               } else {
                        nfsm_chain_add_32(error, nmc, vap->va_rdev);
+               }
                nfsm_chain_add_32(error, nmc, vap->va_data_alloc / NFS_FABLKSIZE);
                nfsm_chain_add_32(error, nmc, vap->va_fsid);
                nfsm_chain_add_32(error, nmc, vap->va_fileid);
@@ -2284,7 +2611,7 @@ nfsm_chain_add_fattr(
        nfsm_chain_add_time(error, nmc, nd->nd_vers, &vap->va_modify_time);
        nfsm_chain_add_time(error, nmc, nd->nd_vers, &vap->va_change_time);
 
-       return (error);
+       return error;
 }
 
 int
@@ -2295,7 +2622,7 @@ nfsm_chain_get_sattr(
 {
        int error = 0;
        uint32_t val = 0;
-       uint64_t val64;
+       uint64_t val64 = 0;
        struct timespec now;
 
        if (nd->nd_vers == NFS_VER2) {
@@ -2312,27 +2639,32 @@ nfsm_chain_get_sattr(
                        VATTR_CLEAR_ACTIVE(vap, va_type);
                }
                nfsm_chain_get_32(error, nmc, val);
-               if (val != (uint32_t)-1)
+               if (val != (uint32_t)-1) {
                        VATTR_SET(vap, va_uid, val);
+               }
                nfsm_chain_get_32(error, nmc, val);
-               if (val != (uint32_t)-1)
+               if (val != (uint32_t)-1) {
                        VATTR_SET(vap, va_gid, val);
+               }
                /* save the "size" bits for NFSv2 create (even if they appear unset) */
                nfsm_chain_get_32(error, nmc, val);
                VATTR_SET(vap, va_data_size, val);
-               if (val == (uint32_t)-1)
+               if (val == (uint32_t)-1) {
                        VATTR_CLEAR_ACTIVE(vap, va_data_size);
+               }
                nfsm_chain_get_time(error, nmc, NFS_VER2,
-                       vap->va_access_time.tv_sec,
-                       vap->va_access_time.tv_nsec);
-               if (vap->va_access_time.tv_sec != -1)
+                   vap->va_access_time.tv_sec,
+                   vap->va_access_time.tv_nsec);
+               if (vap->va_access_time.tv_sec != -1) {
                        VATTR_SET_ACTIVE(vap, va_access_time);
+               }
                nfsm_chain_get_time(error, nmc, NFS_VER2,
-                       vap->va_modify_time.tv_sec,
-                       vap->va_modify_time.tv_nsec);
-               if (vap->va_modify_time.tv_sec != -1)
+                   vap->va_modify_time.tv_sec,
+                   vap->va_modify_time.tv_nsec);
+               if (vap->va_modify_time.tv_sec != -1) {
                        VATTR_SET_ACTIVE(vap, va_modify_time);
-               return (error);
+               }
+               return error;
        }
 
        /* NFSv3 */
@@ -2361,8 +2693,8 @@ nfsm_chain_get_sattr(
        switch (val) {
        case NFS_TIME_SET_TO_CLIENT:
                nfsm_chain_get_time(error, nmc, nd->nd_vers,
-                       vap->va_access_time.tv_sec,
-                       vap->va_access_time.tv_nsec);
+                   vap->va_access_time.tv_sec,
+                   vap->va_access_time.tv_nsec);
                VATTR_SET_ACTIVE(vap, va_access_time);
                vap->va_vaflags &= ~VA_UTIMES_NULL;
                break;
@@ -2375,19 +2707,20 @@ nfsm_chain_get_sattr(
        switch (val) {
        case NFS_TIME_SET_TO_CLIENT:
                nfsm_chain_get_time(error, nmc, nd->nd_vers,
-                       vap->va_modify_time.tv_sec,
-                       vap->va_modify_time.tv_nsec);
+                   vap->va_modify_time.tv_sec,
+                   vap->va_modify_time.tv_nsec);
                VATTR_SET_ACTIVE(vap, va_modify_time);
                vap->va_vaflags &= ~VA_UTIMES_NULL;
                break;
        case NFS_TIME_SET_TO_SERVER:
                VATTR_SET(vap, va_modify_time, now);
-               if (!VATTR_IS_ACTIVE(vap, va_access_time))
+               if (!VATTR_IS_ACTIVE(vap, va_access_time)) {
                        vap->va_vaflags |= VA_UTIMES_NULL;
+               }
                break;
        }
 
-       return (error);
+       return error;
 }
 
 /*
@@ -2398,11 +2731,14 @@ nfsrv_cmp_secflavs(struct nfs_sec *sf1, struct nfs_sec *sf2)
 {
        int i;
 
-       if (sf1->count != sf2->count)
+       if (sf1->count != sf2->count) {
                return 1;
-       for (i = 0; i < sf1->count; i++)
-               if (sf1->flavors[i] != sf2->flavors[i])
+       }
+       for (i = 0; i < sf1->count; i++) {
+               if (sf1->flavors[i] != sf2->flavors[i]) {
                        return 1;
+               }
+       }
        return 0;
 }
 
@@ -2419,27 +2755,41 @@ nfsrv_hang_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa)
        struct radix_node *rn;
        struct sockaddr *saddr, *smask;
        struct domain *dom;
-       int i, error;
+       size_t i, ss_minsize;
+       int error;
        unsigned int net;
        user_addr_t uaddr;
        kauth_cred_t cred;
 
        uaddr = unxa->nxa_nets;
+       ss_minsize = sizeof(((struct sockaddr_storage *)0)->ss_len) + sizeof(((struct sockaddr_storage *)0)->ss_family);
        for (net = 0; net < unxa->nxa_netcount; net++, uaddr += sizeof(nxna)) {
                error = copyin(uaddr, &nxna, sizeof(nxna));
-               if (error)
-                       return (error);
+               if (error) {
+                       return error;
+               }
+
+               if (nxna.nxna_addr.ss_len > sizeof(struct sockaddr_storage) ||
+                   (nxna.nxna_addr.ss_len != 0 && nxna.nxna_addr.ss_len < ss_minsize) ||
+                   nxna.nxna_mask.ss_len > sizeof(struct sockaddr_storage) ||
+                   (nxna.nxna_mask.ss_len != 0 && nxna.nxna_mask.ss_len < ss_minsize) ||
+                   nxna.nxna_addr.ss_family > AF_MAX ||
+                   nxna.nxna_mask.ss_family > AF_MAX) {
+                       return EINVAL;
+               }
 
-               if (nxna.nxna_flags & (NX_MAPROOT|NX_MAPALL)) {
+               if (nxna.nxna_flags & (NX_MAPROOT | NX_MAPALL)) {
                        struct posix_cred temp_pcred;
-                       bzero(&temp_pcred, sizeof(temp_pcred));
+                       bzero(&temp_pcred, sizeof(temp_pcred));
                        temp_pcred.cr_uid = nxna.nxna_cred.cr_uid;
                        temp_pcred.cr_ngroups = nxna.nxna_cred.cr_ngroups;
-                       for (i=0; i < nxna.nxna_cred.cr_ngroups && i < NGROUPS; i++)
+                       for (i = 0; i < (size_t)nxna.nxna_cred.cr_ngroups && i < NGROUPS; i++) {
                                temp_pcred.cr_groups[i] = nxna.nxna_cred.cr_groups[i];
+                       }
                        cred = posix_cred_create(&temp_pcred);
-                       if (!IS_VALID_CRED(cred))
-                               return (ENOMEM);
+                       if (!IS_VALID_CRED(cred)) {
+                               return ENOMEM;
+                       }
                } else {
                        cred = NOCRED;
                }
@@ -2447,9 +2797,10 @@ nfsrv_hang_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa)
                if (nxna.nxna_addr.ss_len == 0) {
                        /* No address means this is a default/world export */
                        if (nx->nx_flags & NX_DEFAULTEXPORT) {
-                               if (IS_VALID_CRED(cred))
-                                       kauth_cred_unref(&cred);
-                               return (EEXIST);
+                               if (IS_VALID_CRED(cred)) {
+                                       kauth_cred_unref(&cred);
+                               }
+                               return EEXIST;
                        }
                        nx->nx_flags |= NX_DEFAULTEXPORT;
                        nx->nx_defopt.nxo_flags = nxna.nxna_flags;
@@ -2463,9 +2814,10 @@ nfsrv_hang_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa)
                i += nxna.nxna_addr.ss_len + nxna.nxna_mask.ss_len;
                MALLOC(no, struct nfs_netopt *, i, M_NETADDR, M_WAITOK);
                if (!no) {
-                       if (IS_VALID_CRED(cred))
+                       if (IS_VALID_CRED(cred)) {
                                kauth_cred_unref(&cred);
-                       return (ENOMEM);
+                       }
+                       return ENOMEM;
                }
                bzero(no, sizeof(struct nfs_netopt));
                no->no_opt.nxo_flags = nxna.nxna_flags;
@@ -2480,23 +2832,25 @@ nfsrv_hang_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa)
                } else {
                        smask = NULL;
                }
-               i = saddr->sa_family;
-               if ((rnh = nx->nx_rtable[i]) == 0) {
+               sa_family_t family = saddr->sa_family;
+               if ((rnh = nx->nx_rtable[family]) == 0) {
                        /*
                         * Seems silly to initialize every AF when most are not
                         * used, do so on demand here
                         */
-                       for (dom = domains; dom; dom = dom->dom_next)
-                               if (dom->dom_family == i && dom->dom_rtattach) {
-                                       dom->dom_rtattach((void **)&nx->nx_rtable[i],
-                                               dom->dom_rtoffset);
+                       TAILQ_FOREACH(dom, &domains, dom_entry) {
+                               if (dom->dom_family == family && dom->dom_rtattach) {
+                                       dom->dom_rtattach((void **)&nx->nx_rtable[family],
+                                           dom->dom_rtoffset);
                                        break;
                                }
-                       if ((rnh = nx->nx_rtable[i]) == 0) {
-                               if (IS_VALID_CRED(cred))
-                                       kauth_cred_unref(&cred);
+                       }
+                       if ((rnh = nx->nx_rtable[family]) == 0) {
+                               if (IS_VALID_CRED(cred)) {
+                                       kauth_cred_unref(&cred);
+                               }
                                _FREE(no, M_NETADDR);
-                               return (ENOBUFS);
+                               return ENOBUFS;
                        }
                }
                rn = (*rnh->rnh_addaddr)((caddr_t)saddr, (caddr_t)smask, rnh, no->no_rnodes);
@@ -2520,46 +2874,51 @@ nfsrv_hang_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa)
                                        /* creds are same (or both NULL) */
                                        matched = 1;
                                } else if (cred && cred2 && (kauth_cred_getuid(cred) == kauth_cred_getuid(cred2))) {
-                                   /*
-                                    * Now compare the effective and
-                                    * supplementary groups...
-                                    *
-                                    * Note: This comparison, as written,
-                                    * does not correctly indicate that
-                                    * the groups are equivalent, since
-                                    * other than the first supplementary
-                                    * group, which is also the effective
-                                    * group, order on the remaining groups
-                                    * doesn't matter, and this is an
-                                    * ordered compare.
-                                    */
-                                   gid_t groups[NGROUPS];
-                                   gid_t groups2[NGROUPS];
-                                   int groupcount = NGROUPS;
-                                   int group2count = NGROUPS;
-
-                                   if (!kauth_cred_getgroups(cred, groups, &groupcount) &&
-                                       !kauth_cred_getgroups(cred2, groups2, &group2count) &&
-                                       groupcount == group2count) {
-                                           for (i=0; i < group2count; i++)
-                                                   if (groups[i] != groups2[i])
-                                                           break;
-                                           if (i >= group2count || i >= NGROUPS)
-                                           matched = 1;
-                                   }
+                                       /*
+                                        * Now compare the effective and
+                                        * supplementary groups...
+                                        *
+                                        * Note: This comparison, as written,
+                                        * does not correctly indicate that
+                                        * the groups are equivalent, since
+                                        * other than the first supplementary
+                                        * group, which is also the effective
+                                        * group, order on the remaining groups
+                                        * doesn't matter, and this is an
+                                        * ordered compare.
+                                        */
+                                       gid_t groups[NGROUPS];
+                                       gid_t groups2[NGROUPS];
+                                       size_t groupcount = NGROUPS;
+                                       size_t group2count = NGROUPS;
+
+                                       if (!kauth_cred_getgroups(cred, groups, &groupcount) &&
+                                           !kauth_cred_getgroups(cred2, groups2, &group2count) &&
+                                           groupcount == group2count) {
+                                               for (i = 0; i < group2count; i++) {
+                                                       if (groups[i] != groups2[i]) {
+                                                               break;
+                                                       }
+                                               }
+                                               if (i >= group2count || i >= NGROUPS) {
+                                                       matched = 1;
+                                               }
+                                       }
                                }
                        }
-                       if (IS_VALID_CRED(cred))
-                               kauth_cred_unref(&cred);
+                       if (IS_VALID_CRED(cred)) {
+                               kauth_cred_unref(&cred);
+                       }
                        _FREE(no, M_NETADDR);
-                       if (matched)
+                       if (matched) {
                                continue;
-                       return (EPERM);
+                       }
+                       return EPERM;
                }
                nx->nx_expcnt++;
        }
 
-       return (0);
+       return 0;
 }
 
 /*
@@ -2581,11 +2940,12 @@ nfsrv_free_netopt(struct radix_node *rn, void *w)
        struct nfs_netopt *nno = (struct nfs_netopt *)rn;
 
        (*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh);
-       if (IS_VALID_CRED(nno->no_opt.nxo_cred))
+       if (IS_VALID_CRED(nno->no_opt.nxo_cred)) {
                kauth_cred_unref(&nno->no_opt.nxo_cred);
+       }
        _FREE((caddr_t)rn, M_NETADDR);
        *cnt -= 1;
-       return (0);
+       return 0;
 }
 
 /*
@@ -2599,29 +2959,33 @@ nfsrv_free_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa)
        struct radix_node *rn;
        struct nfsrv_free_netopt_arg fna;
        struct nfs_netopt *nno;
+       size_t ss_minsize;
        user_addr_t uaddr;
        unsigned int net;
        int i, error;
 
        if (!unxa || !unxa->nxa_netcount) {
                /* delete everything */
-               for (i = 0; i <= AF_MAX; i++)
-                       if ( (rnh = nx->nx_rtable[i]) ) {
+               for (i = 0; i <= AF_MAX; i++) {
+                       if ((rnh = nx->nx_rtable[i])) {
                                fna.rnh = rnh;
                                fna.cnt = &nx->nx_expcnt;
                                (*rnh->rnh_walktree)(rnh, nfsrv_free_netopt, (caddr_t)&fna);
                                _FREE((caddr_t)rnh, M_RTABLE);
                                nx->nx_rtable[i] = 0;
                        }
-               return (0);
+               }
+               return 0;
        }
 
        /* delete only the exports specified */
        uaddr = unxa->nxa_nets;
+       ss_minsize = sizeof(((struct sockaddr_storage *)0)->ss_len) + sizeof(((struct sockaddr_storage *)0)->ss_family);
        for (net = 0; net < unxa->nxa_netcount; net++, uaddr += sizeof(nxna)) {
                error = copyin(uaddr, &nxna, sizeof(nxna));
-               if (error)
-                       return (error);
+               if (error) {
+                       return error;
+               }
 
                if (nxna.nxna_addr.ss_len == 0) {
                        /* No address means this is a default/world export */
@@ -2635,25 +2999,42 @@ nfsrv_free_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa)
                        continue;
                }
 
+               if (nxna.nxna_addr.ss_len > sizeof(struct sockaddr_storage) ||
+                   (nxna.nxna_addr.ss_len != 0 && nxna.nxna_addr.ss_len < ss_minsize) ||
+                   nxna.nxna_addr.ss_family > AF_MAX) {
+                       printf("nfsrv_free_addrlist: invalid socket address (%u)\n", net);
+                       continue;
+               }
+
+               if (nxna.nxna_mask.ss_len > sizeof(struct sockaddr_storage) ||
+                   (nxna.nxna_mask.ss_len != 0 && nxna.nxna_mask.ss_len < ss_minsize) ||
+                   nxna.nxna_mask.ss_family > AF_MAX) {
+                       printf("nfsrv_free_addrlist: invalid socket mask (%u)\n", net);
+                       continue;
+               }
+
                if ((rnh = nx->nx_rtable[nxna.nxna_addr.ss_family]) == 0) {
                        /* AF not initialized? */
-                       if (!(unxa->nxa_flags & NXA_ADD))
+                       if (!(unxa->nxa_flags & NXA_ADD)) {
                                printf("nfsrv_free_addrlist: address not found (0)\n");
+                       }
                        continue;
                }
 
                rn = (*rnh->rnh_lookup)(&nxna.nxna_addr,
-                       nxna.nxna_mask.ss_len ? &nxna.nxna_mask : NULL, rnh);
+                   nxna.nxna_mask.ss_len ? &nxna.nxna_mask : NULL, rnh);
                if (!rn || (rn->rn_flags & RNF_ROOT)) {
-                       if (!(unxa->nxa_flags & NXA_ADD))
+                       if (!(unxa->nxa_flags & NXA_ADD)) {
                                printf("nfsrv_free_addrlist: address not found (1)\n");
+                       }
                        continue;
                }
 
                (*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh);
                nno = (struct nfs_netopt *)rn;
-               if (IS_VALID_CRED(nno->no_opt.nxo_cred))
+               if (IS_VALID_CRED(nno->no_opt.nxo_cred)) {
                        kauth_cred_unref(&nno->no_opt.nxo_cred);
+               }
                _FREE((caddr_t)rn, M_NETADDR);
 
                nx->nx_expcnt--;
@@ -2664,57 +3045,68 @@ nfsrv_free_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa)
                }
        }
 
-       return (0);
+       return 0;
 }
 
 void enablequotas(struct mount *mp, vfs_context_t ctx); // XXX
 
+#define DATA_VOLUME_MP "/System/Volumes/Data" // PLATFORM_DATA_VOLUME_MOUNT_POINT
+
 int
 nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx)
 {
        int error = 0;
-       size_t pathlen;
+       size_t pathlen, nxfs_pathlen;
        struct nfs_exportfs *nxfs, *nxfs2, *nxfs3;
        struct nfs_export *nx, *nx2, *nx3;
        struct nfs_filehandle nfh;
        struct nameidata mnd, xnd;
        vnode_t mvp = NULL, xvp = NULL;
        mount_t mp = NULL;
-       char path[MAXPATHLEN];
+       char path[MAXPATHLEN], *nxfs_path;
+       char fl_pathbuff[MAXPATHLEN];
+       int fl_pathbuff_len = MAXPATHLEN;
        int expisroot;
+       size_t datavol_len = strlen(DATA_VOLUME_MP);
 
        if (unxa->nxa_flags == NXA_CHECK) {
                /* just check if the path is an NFS-exportable file system */
                error = copyinstr(unxa->nxa_fspath, path, MAXPATHLEN, &pathlen);
-               if (error)
-                       return (error);
+               if (error) {
+                       return error;
+               }
                NDINIT(&mnd, LOOKUP, OP_LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1,
-                       UIO_SYSSPACE, CAST_USER_ADDR_T(path), ctx);
+                   UIO_SYSSPACE, CAST_USER_ADDR_T(path), ctx);
                error = namei(&mnd);
-               if (error)
-                       return (error);
+               if (error) {
+                       return error;
+               }
                mvp = mnd.ni_vp;
                mp = vnode_mount(mvp);
                /* make sure it's the root of a file system */
-               if (!vnode_isvroot(mvp))
+               if (!vnode_isvroot(mvp)) {
                        error = EINVAL;
+               }
                /* make sure the file system is NFS-exportable */
                if (!error) {
                        nfh.nfh_len = NFSV3_MAX_FID_SIZE;
                        error = VFS_VPTOFH(mvp, (int*)&nfh.nfh_len, &nfh.nfh_fid[0], NULL);
                }
-               if (!error && (nfh.nfh_len > (int)NFSV3_MAX_FID_SIZE))
+               if (!error && (nfh.nfh_len > (int)NFSV3_MAX_FID_SIZE)) {
                        error = EIO;
-               if (!error && !(mp->mnt_vtable->vfc_vfsflags & VFC_VFSREADDIR_EXTENDED))
+               }
+               if (!error && !(mp->mnt_vtable->vfc_vfsflags & VFC_VFSREADDIR_EXTENDED)) {
                        error = EISDIR;
+               }
                vnode_put(mvp);
                nameidone(&mnd);
-               return (error);
+               return error;
        }
 
        /* all other operations: must be super user */
-       if ((error = vfs_context_suser(ctx)))
-               return (error);
+       if ((error = vfs_context_suser(ctx))) {
+               return error;
+       }
 
        if (unxa->nxa_flags & NXA_DELETE_ALL) {
                /* delete all exports on all file systems */
@@ -2751,52 +3143,65 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx)
                        nfsrv_export_hashtbl = NULL;
                }
                lck_rw_done(&nfsrv_export_rwlock);
-               return (0);
+               return 0;
        }
 
        error = copyinstr(unxa->nxa_fspath, path, MAXPATHLEN, &pathlen);
-       if (error)
-               return (error);
+       if (error) {
+               return error;
+       }
 
        lck_rw_lock_exclusive(&nfsrv_export_rwlock);
 
        /* init export hash table if not already */
        if (!nfsrv_export_hashtbl) {
-               if (nfsrv_export_hash_size <= 0)
+               if (nfsrv_export_hash_size <= 0) {
                        nfsrv_export_hash_size = NFSRVEXPHASHSZ;
+               }
                nfsrv_export_hashtbl = hashinit(nfsrv_export_hash_size, M_TEMP, &nfsrv_export_hash);
        }
 
        // first check if we've already got an exportfs with the given ID
        LIST_FOREACH(nxfs, &nfsrv_exports, nxfs_next) {
-               if (nxfs->nxfs_id == unxa->nxa_fsid)
+               if (nxfs->nxfs_id == unxa->nxa_fsid) {
                        break;
+               }
        }
        if (nxfs) {
                /* verify exported FS path matches given path */
-               if (strncmp(path, nxfs->nxfs_path, MAXPATHLEN)) {
+               if (strncmp(path, nxfs->nxfs_path, MAXPATHLEN) &&
+                   (strncmp(path, DATA_VOLUME_MP, datavol_len) || strncmp(path + datavol_len, nxfs->nxfs_path, MAXPATHLEN - datavol_len))) {
                        error = EEXIST;
                        goto unlock_out;
                }
-               if ((unxa->nxa_flags & (NXA_ADD|NXA_OFFLINE)) == NXA_ADD) {
-                       /* if adding, verify that the mount is still what we expect */
-                       mp = vfs_getvfs_by_mntonname(nxfs->nxfs_path);
-                       if (mp) {
-                               mount_ref(mp, 0);
-                               mount_iterdrop(mp);
-                       }
+               if ((unxa->nxa_flags & (NXA_ADD | NXA_OFFLINE)) == NXA_ADD) {
                        /* find exported FS root vnode */
                        NDINIT(&mnd, LOOKUP, OP_LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1,
-                               UIO_SYSSPACE, CAST_USER_ADDR_T(nxfs->nxfs_path), ctx);
+                           UIO_SYSSPACE, CAST_USER_ADDR_T(nxfs->nxfs_path), ctx);
                        error = namei(&mnd);
-                       if (error)
+                       if (error) {
                                goto unlock_out;
+                       }
                        mvp = mnd.ni_vp;
                        /* make sure it's (still) the root of a file system */
                        if (!vnode_isvroot(mvp)) {
                                error = EINVAL;
                                goto out;
                        }
+                       /* if adding, verify that the mount is still what we expect */
+                       mp = vfs_getvfs_by_mntonname(nxfs->nxfs_path);
+                       if (!mp) {
+                               /* check for firmlink-free path */
+                               if (vn_getpath_no_firmlink(mvp, fl_pathbuff, &fl_pathbuff_len) == 0 &&
+                                   fl_pathbuff_len > 0 &&
+                                   !strncmp(nxfs->nxfs_path, fl_pathbuff, MAXPATHLEN)) {
+                                       mp = vfs_getvfs_by_mntonname(vnode_mount(mvp)->mnt_vfsstat.f_mntonname);
+                               }
+                       }
+                       if (mp) {
+                               mount_ref(mp, 0);
+                               mount_iterdrop(mp);
+                       }
                        /* sanity check: this should be same mount */
                        if (mp != vnode_mount(mvp)) {
                                error = EINVAL;
@@ -2812,11 +3217,12 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx)
 
                /* find exported FS root vnode */
                NDINIT(&mnd, LOOKUP, OP_LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1,
-                       UIO_SYSSPACE, CAST_USER_ADDR_T(path), ctx);
+                   UIO_SYSSPACE, CAST_USER_ADDR_T(path), ctx);
                error = namei(&mnd);
                if (error) {
-                       if (!(unxa->nxa_flags & NXA_OFFLINE))
+                       if (!(unxa->nxa_flags & NXA_OFFLINE)) {
                                goto unlock_out;
+                       }
                } else {
                        mvp = mnd.ni_vp;
                        /* make sure it's the root of a file system */
@@ -2836,12 +3242,15 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx)
                                /* make sure the file system is NFS-exportable */
                                nfh.nfh_len = NFSV3_MAX_FID_SIZE;
                                error = VFS_VPTOFH(mvp, (int*)&nfh.nfh_len, &nfh.nfh_fid[0], NULL);
-                               if (!error && (nfh.nfh_len > (int)NFSV3_MAX_FID_SIZE))
+                               if (!error && (nfh.nfh_len > (int)NFSV3_MAX_FID_SIZE)) {
                                        error = EIO;
-                               if (!error && !(mp->mnt_vtable->vfc_vfsflags & VFC_VFSREADDIR_EXTENDED))
+                               }
+                               if (!error && !(mp->mnt_vtable->vfc_vfsflags & VFC_VFSREADDIR_EXTENDED)) {
                                        error = EISDIR;
-                               if (error)
+                               }
+                               if (error) {
                                        goto out;
+                               }
                        }
                }
 
@@ -2853,39 +3262,51 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx)
                }
                bzero(nxfs, sizeof(struct nfs_exportfs));
                nxfs->nxfs_id = unxa->nxa_fsid;
-               MALLOC(nxfs->nxfs_path, char*, pathlen, M_TEMP, M_WAITOK);
+               if (mp) {
+                       nxfs_path = mp->mnt_vfsstat.f_mntonname;
+                       nxfs_pathlen = sizeof(mp->mnt_vfsstat.f_mntonname);
+               } else {
+                       nxfs_path = path;
+                       nxfs_pathlen = pathlen;
+               }
+               MALLOC(nxfs->nxfs_path, char*, nxfs_pathlen, M_TEMP, M_WAITOK);
                if (!nxfs->nxfs_path) {
                        FREE(nxfs, M_TEMP);
                        error = ENOMEM;
                        goto out;
                }
-               bcopy(path, nxfs->nxfs_path, pathlen);
+               bcopy(nxfs_path, nxfs->nxfs_path, nxfs_pathlen);
                /* insert into list in reverse-sorted order */
                nxfs3 = NULL;
                LIST_FOREACH(nxfs2, &nfsrv_exports, nxfs_next) {
-                       if (strncmp(nxfs->nxfs_path, nxfs2->nxfs_path, MAXPATHLEN) > 0)
+                       if (strncmp(nxfs->nxfs_path, nxfs2->nxfs_path, MAXPATHLEN) > 0) {
                                break;
+                       }
                        nxfs3 = nxfs2;
                }
-               if (nxfs2)
+               if (nxfs2) {
                        LIST_INSERT_BEFORE(nxfs2, nxfs, nxfs_next);
-               else if (nxfs3)
+               } else if (nxfs3) {
                        LIST_INSERT_AFTER(nxfs3, nxfs, nxfs_next);
-               else
+               } else {
                        LIST_INSERT_HEAD(&nfsrv_exports, nxfs, nxfs_next);
+               }
 
                /* make sure any quotas are enabled before we export the file system */
-               if (mp)
+               if (mp) {
                        enablequotas(mp, ctx);
+               }
        }
 
        if (unxa->nxa_exppath) {
                error = copyinstr(unxa->nxa_exppath, path, MAXPATHLEN, &pathlen);
-               if (error)
+               if (error) {
                        goto out;
+               }
                LIST_FOREACH(nx, &nxfs->nxfs_exports, nx_next) {
-                       if (nx->nx_id == unxa->nxa_expid)
+                       if (nx->nx_id == unxa->nxa_expid) {
                                break;
+                       }
                }
                if (nx) {
                        /* verify exported FS path matches given path */
@@ -2922,16 +3343,18 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx)
                        /* insert into list in reverse-sorted order */
                        nx3 = NULL;
                        LIST_FOREACH(nx2, &nxfs->nxfs_exports, nx_next) {
-                               if (strncmp(nx->nx_path, nx2->nx_path, MAXPATHLEN) > 0)
+                               if (strncmp(nx->nx_path, nx2->nx_path, MAXPATHLEN) > 0) {
                                        break;
+                               }
                                nx3 = nx2;
                        }
-                       if (nx2)
+                       if (nx2) {
                                LIST_INSERT_BEFORE(nx2, nx, nx_next);
-                       else if (nx3)
+                       } else if (nx3) {
                                LIST_INSERT_AFTER(nx3, nx, nx_next);
-                       else
+                       } else {
                                LIST_INSERT_HEAD(&nxfs->nxfs_exports, nx, nx_next);
+                       }
                        /* insert into hash */
                        LIST_INSERT_HEAD(NFSRVEXPHASH(nxfs->nxfs_id, nx->nx_id), nx, nx_hash);
 
@@ -2942,25 +3365,29 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx)
                         */
                        error = 0;
                        if ((nx3 && !strncmp(nx3->nx_path, nx->nx_path, pathlen - 1) &&
-                                   (nx3->nx_path[pathlen-1] == '/')) ||
+                           (nx3->nx_path[pathlen - 1] == '/')) ||
                            (nx2 && !strncmp(nx2->nx_path, nx->nx_path, strlen(nx2->nx_path)) &&
-                                   (nx->nx_path[strlen(nx2->nx_path)] == '/')))
+                           (nx->nx_path[strlen(nx2->nx_path)] == '/'))) {
                                error = EINVAL;
+                       }
                        if (!error) {
                                /* check export conflict with fs root export and vice versa */
                                expisroot = !nx->nx_path[0] ||
-                                           ((nx->nx_path[0] == '.') && !nx->nx_path[1]);
+                                   ((nx->nx_path[0] == '.') && !nx->nx_path[1]);
                                LIST_FOREACH(nx2, &nxfs->nxfs_exports, nx_next) {
                                        if (expisroot) {
-                                               if (nx2 != nx)
+                                               if (nx2 != nx) {
                                                        break;
-                                       } else if (!nx2->nx_path[0])
+                                               }
+                                       } else if (!nx2->nx_path[0]) {
                                                break;
-                                       else if ((nx2->nx_path[0] == '.') && !nx2->nx_path[1])
+                                       } else if ((nx2->nx_path[0] == '.') && !nx2->nx_path[1]) {
                                                break;
+                                       }
                                }
-                               if (nx2)
+                               if (nx2) {
                                        error = EINVAL;
+                               }
                        }
                        if (error) {
                                /*
@@ -2973,7 +3400,7 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx)
                                 * complexity of mountd for very little overall benefit.
                                 */
                                printf("nfsrv_export: warning: nested exports: %s/%s\n",
-                                       nxfs->nxfs_path, nx->nx_path);
+                                   nxfs->nxfs_path, nx->nx_path);
                                error = 0;
                        }
                        nx->nx_fh.nfh_xh.nxh_flags = NXHF_INVALIDFH;
@@ -3001,18 +3428,20 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx)
                                        xnd.ni_op = OP_LOOKUP;
 #endif
                                        xnd.ni_cnd.cn_flags = LOCKLEAF;
-                                       xnd.ni_pathlen = pathlen - 1;
+                                       xnd.ni_pathlen = (uint32_t)pathlen - 1; // pathlen max value is equal to MAXPATHLEN
                                        xnd.ni_cnd.cn_nameptr = xnd.ni_cnd.cn_pnbuf = path;
                                        xnd.ni_startdir = mvp;
                                        xnd.ni_usedvp   = mvp;
+                                       xnd.ni_rootdir = rootvnode;
                                        xnd.ni_cnd.cn_context = ctx;
                                        while ((error = lookup(&xnd)) == ERECYCLE) {
                                                xnd.ni_cnd.cn_flags = LOCKLEAF;
                                                xnd.ni_cnd.cn_nameptr = xnd.ni_cnd.cn_pnbuf;
                                                xnd.ni_usedvp = xnd.ni_dvp = xnd.ni_startdir = mvp;
                                        }
-                                       if (error)
+                                       if (error) {
                                                goto out1;
+                                       }
                                        xvp = xnd.ni_vp;
                                }
 
@@ -3033,8 +3462,9 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx)
                                }
 
                                vnode_put(xvp);
-                               if (error)
+                               if (error) {
                                        goto out1;
+                               }
                        } else {
                                nx->nx_fh.nfh_xh.nxh_flags = NXHF_INVALIDFH;
                                nx->nx_fh.nfh_xh.nxh_fidlen = 0;
@@ -3074,22 +3504,25 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx)
                } else {
                        /* delete only the netopts for the given addresses */
                        error = nfsrv_free_addrlist(nx, unxa);
-                       if (error)
+                       if (error) {
                                goto out1;
+                       }
                }
        }
        if (unxa->nxa_flags & NXA_ADD) {
-               /* 
+               /*
                 * If going offline set the export time so that when
                 * coming back on line we will present a new write verifier
                 * to the client.
                 */
-               if (unxa->nxa_flags & NXA_OFFLINE)
+               if (unxa->nxa_flags & NXA_OFFLINE) {
                        microtime(&nx->nx_exptime);
+               }
 
                error = nfsrv_hang_addrlist(nx, unxa);
-               if (!error && mp)
+               if (!error && mp) {
                        vfs_setflags(mp, MNT_EXPORTED);
+               }
        }
 
 out1:
@@ -3107,8 +3540,9 @@ out1:
                LIST_REMOVE(nxfs, nxfs_next);
                FREE(nxfs->nxfs_path, M_TEMP);
                FREE(nxfs, M_TEMP);
-               if (mp)
+               if (mp) {
                        vfs_clearflags(mp, MNT_EXPORTED);
+               }
        }
 
 out:
@@ -3117,10 +3551,46 @@ out:
                nameidone(&mnd);
        }
 unlock_out:
-       if (mp)
+       if (mp) {
                mount_drop(mp, 0);
+       }
+       lck_rw_done(&nfsrv_export_rwlock);
+       return error;
+}
+
+/*
+ * Check if there is a least one export that will allow this address.
+ *
+ * Return 0, if there is an export that will allow this address,
+ * else return EACCES
+ */
+int
+nfsrv_check_exports_allow_address(mbuf_t nam)
+{
+       struct nfs_exportfs             *nxfs;
+       struct nfs_export               *nx;
+       struct nfs_export_options       *nxo = NULL;
+
+       if (nam == NULL) {
+               return EACCES;
+       }
+
+       lck_rw_lock_shared(&nfsrv_export_rwlock);
+       LIST_FOREACH(nxfs, &nfsrv_exports, nxfs_next) {
+               LIST_FOREACH(nx, &nxfs->nxfs_exports, nx_next) {
+                       /* A little optimizing by checking for the default first */
+                       if (nx->nx_flags & NX_DEFAULTEXPORT) {
+                               nxo = &nx->nx_defopt;
+                       }
+                       if (nxo || (nxo = nfsrv_export_lookup(nx, nam))) {
+                               goto found;
+                       }
+               }
+       }
+found:
        lck_rw_done(&nfsrv_export_rwlock);
-       return (error);
+
+       return nxo ? 0 : EACCES;
 }
 
 struct nfs_export_options *
@@ -3134,20 +3604,27 @@ nfsrv_export_lookup(struct nfs_export *nx, mbuf_t nam)
        /* Lookup in the export list first. */
        if (nam != NULL) {
                saddr = mbuf_data(nam);
+               if (saddr->sa_family > AF_MAX) {
+                       /* Bogus sockaddr?  Don't match anything. */
+                       return NULL;
+               }
                rnh = nx->nx_rtable[saddr->sa_family];
                if (rnh != NULL) {
                        no = (struct nfs_netopt *)
-                               (*rnh->rnh_matchaddr)((caddr_t)saddr, rnh);
-                       if (no && no->no_rnodes->rn_flags & RNF_ROOT)
+                           (*rnh->rnh_matchaddr)((caddr_t)saddr, rnh);
+                       if (no && no->no_rnodes->rn_flags & RNF_ROOT) {
                                no = NULL;
-                       if (no)
+                       }
+                       if (no) {
                                nxo = &no->no_opt;
+                       }
                }
        }
        /* If no address match, use the default if it exists. */
-       if ((nxo == NULL) && (nx->nx_flags & NX_DEFAULTEXPORT))
+       if ((nxo == NULL) && (nx->nx_flags & NX_DEFAULTEXPORT)) {
                nxo = &nx->nx_defopt;
-       return (nxo);
+       }
+       return nxo;
 }
 
 /* find an export for the given handle */
@@ -3158,19 +3635,81 @@ nfsrv_fhtoexport(struct nfs_filehandle *nfhp)
        struct nfs_export *nx;
        uint32_t fsid, expid;
 
-       if (!nfsrv_export_hashtbl)
-               return (NULL);
+       if (!nfsrv_export_hashtbl) {
+               return NULL;
+       }
        fsid = ntohl(nxh->nxh_fsid);
        expid = ntohl(nxh->nxh_expid);
        nx = NFSRVEXPHASH(fsid, expid)->lh_first;
        for (; nx; nx = LIST_NEXT(nx, nx_hash)) {
-               if (nx->nx_fs->nxfs_id != fsid)
+               if (nx->nx_fs->nxfs_id != fsid) {
                        continue;
-               if (nx->nx_id != expid)
+               }
+               if (nx->nx_id != expid) {
                        continue;
+               }
                break;
        }
-       return (nx);
+       return nx;
+}
+
+struct nfsrv_getvfs_by_mntonname_callback_args {
+       const char      *path;          /* IN */
+       mount_t         mp;             /* OUT */
+};
+
+static int
+nfsrv_getvfs_by_mntonname_callback(mount_t mp, void *v)
+{
+       struct nfsrv_getvfs_by_mntonname_callback_args * const args = v;
+       char real_mntonname[MAXPATHLEN];
+       int pathbuflen = MAXPATHLEN;
+       vnode_t rvp;
+       int error;
+
+       error = VFS_ROOT(mp, &rvp, vfs_context_current());
+       if (error) {
+               goto out;
+       }
+       error = vn_getpath_ext(rvp, NULLVP, real_mntonname, &pathbuflen,
+           VN_GETPATH_FSENTER | VN_GETPATH_NO_FIRMLINK);
+       vnode_put(rvp);
+       if (error) {
+               goto out;
+       }
+       if (strcmp(args->path, real_mntonname) == 0) {
+               error = vfs_busy(mp, LK_NOWAIT);
+               if (error == 0) {
+                       args->mp = mp;
+               }
+               return VFS_RETURNED_DONE;
+       }
+out:
+       return VFS_RETURNED;
+}
+
+static mount_t
+nfsrv_getvfs_by_mntonname(char *path)
+{
+       struct nfsrv_getvfs_by_mntonname_callback_args args = {
+               .path = path,
+               .mp = NULL,
+       };
+       mount_t mp;
+       int error;
+
+       mp = vfs_getvfs_by_mntonname(path);
+       if (mp) {
+               error = vfs_busy(mp, LK_NOWAIT);
+               mount_iterdrop(mp);
+               if (error) {
+                       mp = NULL;
+               }
+       } else if (vfs_iterate(0, nfsrv_getvfs_by_mntonname_callback,
+           &args) == 0) {
+               mp = args.mp;
+       }
+       return mp;
 }
 
 /*
@@ -3197,30 +3736,36 @@ nfsrv_fhtovp(
        *nxp = NULL;
        *nxop = NULL;
 
-       if (nd != NULL)
+       if (nd != NULL) {
                nam = nd->nd_nam;
+       }
 
        v = ntohl(nxh->nxh_version);
        if (v != NFS_FH_VERSION) {
                /* file handle format not supported */
-               return (ESTALE);
+               return ESTALE;
+       }
+       if (nfhp->nfh_len > NFSV3_MAX_FH_SIZE) {
+               return EBADRPC;
+       }
+       if (nfhp->nfh_len < (int)sizeof(struct nfs_exphandle)) {
+               return ESTALE;
        }
-       if (nfhp->nfh_len > NFSV3_MAX_FH_SIZE)
-               return (EBADRPC);
-       if (nfhp->nfh_len < (int)sizeof(struct nfs_exphandle))
-               return (ESTALE);
        v = ntohs(nxh->nxh_flags);
-       if (v & NXHF_INVALIDFH)
-               return (ESTALE);
+       if (v & NXHF_INVALIDFH) {
+               return ESTALE;
+       }
 
        *nxp = nfsrv_fhtoexport(nfhp);
-       if (!*nxp)
-               return (ESTALE);
+       if (!*nxp) {
+               return ESTALE;
+       }
 
        /* Get the export option structure for this <export, client> tuple. */
        *nxop = nxo = nfsrv_export_lookup(*nxp, nam);
-       if (nam && (*nxop == NULL))
-               return (EACCES);
+       if (nam && (*nxop == NULL)) {
+               return EACCES;
+       }
 
        if (nd != NULL) {
                /* Validate the security flavor of the request */
@@ -3237,47 +3782,49 @@ nfsrv_fhtovp(
                         * This allows an unauthenticated superuser on the client
                         * to do mounts for the benefit of authenticated users.
                         */
-                       if (nd->nd_vers == NFS_VER2)
+                       if (nd->nd_vers == NFS_VER2) {
                                if (nd->nd_procnum == NFSV2PROC_GETATTR ||
-                                   nd->nd_procnum == NFSV2PROC_STATFS)
+                                   nd->nd_procnum == NFSV2PROC_STATFS) {
                                        valid = 1;
-                       if (nd->nd_vers == NFS_VER3)
-                               if (nd->nd_procnum == NFSPROC_FSINFO)
+                               }
+                       }
+                       if (nd->nd_vers == NFS_VER3) {
+                               if (nd->nd_procnum == NFSPROC_FSINFO) {
                                        valid = 1;
+                               }
+                       }
 
-                       if (!valid)
-                               return (NFSERR_AUTHERR | AUTH_REJECTCRED);
+                       if (!valid) {
+                               return NFSERR_AUTHERR | AUTH_REJECTCRED;
+                       }
                }
        }
 
-       if (nxo && (nxo->nxo_flags & NX_OFFLINE))
-               return ((nd == NULL || nd->nd_vers == NFS_VER2) ? ESTALE : NFSERR_TRYLATER);
+       if (nxo && (nxo->nxo_flags & NX_OFFLINE)) {
+               return (nd == NULL || nd->nd_vers == NFS_VER2) ? ESTALE : NFSERR_TRYLATER;
+       }
 
        /* find mount structure */
-       mp = vfs_getvfs_by_mntonname((*nxp)->nx_fs->nxfs_path);
-       if (mp) {
-               error = vfs_busy(mp, LK_NOWAIT);
-               mount_iterdrop(mp);
-               if (error)
-                       mp = NULL;
-       }
+       mp = nfsrv_getvfs_by_mntonname((*nxp)->nx_fs->nxfs_path);
        if (!mp) {
                /*
                 * We have an export, but no mount?
                 * Perhaps the export just hasn't been marked offline yet.
                 */
-               return ((nd == NULL || nd->nd_vers == NFS_VER2) ? ESTALE : NFSERR_TRYLATER);
+               return (nd == NULL || nd->nd_vers == NFS_VER2) ? ESTALE : NFSERR_TRYLATER;
        }
 
        fidp = nfhp->nfh_fhp + sizeof(*nxh);
        error = VFS_FHTOVP(mp, nxh->nxh_fidlen, fidp, vpp, NULL);
        vfs_unbusy(mp);
-       if (error)
-               return (error);
+       if (error) {
+               return error;
+       }
        /* vnode pointer should be good at this point or ... */
-       if (*vpp == NULL)
-               return (ESTALE);
-       return (0);
+       if (*vpp == NULL) {
+               return ESTALE;
+       }
+       return 0;
 }
 
 /*
@@ -3300,7 +3847,7 @@ nfsrv_credcheck(
                }
        }
        ctx->vc_ucred = nd->nd_cr;
-       return (0);
+       return 0;
 }
 
 /*
@@ -3330,37 +3877,43 @@ nfsrv_vptofh(
        nfhp->nfh_xh.nxh_flags = 0;
        nfhp->nfh_xh.nxh_reserved = 0;
 
-       if (nfsvers == NFS_VER2)
+       if (nfsvers == NFS_VER2) {
                bzero(&nfhp->nfh_fid[0], NFSV2_MAX_FID_SIZE);
+       }
 
        /* if directory FH matches export root, return invalid FH */
        if (dnfhp && nfsrv_fhmatch(dnfhp, &nx->nx_fh)) {
-               if (nfsvers == NFS_VER2)
+               if (nfsvers == NFS_VER2) {
                        nfhp->nfh_len = NFSX_V2FH;
-               else
+               } else {
                        nfhp->nfh_len = sizeof(nfhp->nfh_xh);
+               }
                nfhp->nfh_xh.nxh_fidlen = 0;
                nfhp->nfh_xh.nxh_flags = htons(NXHF_INVALIDFH);
-               return (0);
+               return 0;
        }
 
-       if (nfsvers == NFS_VER2)
+       if (nfsvers == NFS_VER2) {
                maxfidsize = NFSV2_MAX_FID_SIZE;
-       else
+       } else {
                maxfidsize = NFSV3_MAX_FID_SIZE;
+       }
        nfhp->nfh_len = maxfidsize;
 
        error = VFS_VPTOFH(vp, (int*)&nfhp->nfh_len, &nfhp->nfh_fid[0], ctx);
-       if (error)
-               return (error);
-       if (nfhp->nfh_len > maxfidsize)
-               return (EOVERFLOW);
+       if (error) {
+               return error;
+       }
+       if (nfhp->nfh_len > maxfidsize) {
+               return EOVERFLOW;
+       }
        nfhp->nfh_xh.nxh_fidlen = nfhp->nfh_len;
        nfhp->nfh_len += sizeof(nfhp->nfh_xh);
-       if ((nfsvers == NFS_VER2) && (nfhp->nfh_len < NFSX_V2FH))
+       if ((nfsvers == NFS_VER2) && (nfhp->nfh_len < NFSX_V2FH)) {
                nfhp->nfh_len = NFSX_V2FH;
+       }
 
-       return (0);
+       return 0;
 }
 
 /*
@@ -3378,11 +3931,13 @@ nfsrv_fhmatch(struct nfs_filehandle *fh1, struct nfs_filehandle *fh2)
        nxh2 = (struct nfs_exphandle *)fh2->nfh_fhp;
        len1 = sizeof(fh1->nfh_xh) + nxh1->nxh_fidlen;
        len2 = sizeof(fh2->nfh_xh) + nxh2->nxh_fidlen;
-       if (len1 != len2)
-               return (0);
-       if (bcmp(nxh1, nxh2, len1))
-               return (0);
-       return (1);
+       if (len1 != len2) {
+               return 0;
+       }
+       if (bcmp(nxh1, nxh2, len1)) {
+               return 0;
+       }
+       return 1;
 }
 
 /*
@@ -3394,16 +3949,16 @@ nfsrv_fhmatch(struct nfs_filehandle *fh1, struct nfs_filehandle *fh2)
  * If found, the node's tm_last timestamp is updated and the node is returned.
  *
  * If not found, a new node is allocated (or reclaimed via LRU), initialized, and returned.
- * Returns NULL if a new node could not be allcoated.
+ * Returns NULL if a new node could not be allocated OR saddr length exceeds sizeof(unode->sock).
  *
  * The list's user_mutex lock MUST be held.
  */
 struct nfs_user_stat_node *
 nfsrv_get_user_stat_node(struct nfs_active_user_list *list, struct sockaddr *saddr, uid_t uid)
 {
-       struct nfs_user_stat_node               *unode;
-       struct timeval                          now;
-       struct nfs_user_stat_hashtbl_head       *head;
+       struct nfs_user_stat_node               *unode;
+       struct timeval                          now;
+       struct nfs_user_stat_hashtbl_head       *head;
 
        /* seach the hash table */
        head = NFS_USER_STAT_HASH(list->user_hashtbl, uid);
@@ -3425,13 +3980,19 @@ nfsrv_get_user_stat_node(struct nfs_active_user_list *list, struct sockaddr *sad
                return unode;
        }
 
+       if (saddr->sa_len > sizeof(((struct nfs_user_stat_node *)0)->sock)) {
+               /* saddr length exceeds maximum value */
+               return NULL;
+       }
+
        if (list->node_count < nfsrv_user_stat_max_nodes) {
                /* Allocate a new node */
                MALLOC(unode, struct nfs_user_stat_node *, sizeof(struct nfs_user_stat_node),
-                       M_TEMP, M_WAITOK | M_ZERO);
+                   M_TEMP, M_WAITOK | M_ZERO);
 
-               if (!unode)
+               if (!unode) {
                        return NULL;
+               }
 
                /* increment node count */
                OSAddAtomic(1, &nfsrv_user_stat_node_count);
@@ -3440,8 +4001,9 @@ nfsrv_get_user_stat_node(struct nfs_active_user_list *list, struct sockaddr *sad
                /* reuse the oldest node in the lru list */
                unode = TAILQ_FIRST(&list->user_lru);
 
-               if (!unode)
+               if (!unode) {
                        return NULL;
+               }
 
                /* Remove the node */
                TAILQ_REMOVE(&list->user_lru, unode, lru_link);
@@ -3450,7 +4012,7 @@ nfsrv_get_user_stat_node(struct nfs_active_user_list *list, struct sockaddr *sad
 
        /* Initialize the node */
        unode->uid = uid;
-       bcopy(saddr, &unode->sock, saddr->sa_len);
+       bcopy(saddr, &unode->sock, MIN(saddr->sa_len, sizeof(unode->sock)));
        microtime(&now);
        unode->ops = 0;
        unode->bytes_read = 0;
@@ -3468,18 +4030,20 @@ nfsrv_get_user_stat_node(struct nfs_active_user_list *list, struct sockaddr *sad
 void
 nfsrv_update_user_stat(struct nfs_export *nx, struct nfsrv_descript *nd, uid_t uid, u_int ops, u_int rd_bytes, u_int wr_bytes)
 {
-       struct nfs_user_stat_node       *unode;
-       struct nfs_active_user_list     *ulist;
-       struct sockaddr                 *saddr;
+       struct nfs_user_stat_node       *unode;
+       struct nfs_active_user_list     *ulist;
+       struct sockaddr                 *saddr;
 
-       if ((!nfsrv_user_stat_enabled) || (!nx) || (!nd) || (!nd->nd_nam))
+       if ((!nfsrv_user_stat_enabled) || (!nx) || (!nd) || (!nd->nd_nam)) {
                return;
+       }
 
        saddr = (struct sockaddr *)mbuf_data(nd->nd_nam);
 
        /* check address family before going any further */
-       if ((saddr->sa_family != AF_INET) && (saddr->sa_family != AF_INET6))
+       if ((saddr->sa_family != AF_INET) && (saddr->sa_family != AF_INET6)) {
                return;
+       }
 
        ulist = &nx->nx_user_list;
 
@@ -3513,11 +4077,12 @@ nfsrv_init_user_list(struct nfs_active_user_list *ulist)
        TAILQ_INIT(&ulist->user_lru);
 
        /* initialize the hash table */
-       for(i = 0; i < NFS_USER_STAT_HASH_SIZE; i++)
+       for (i = 0; i < NFS_USER_STAT_HASH_SIZE; i++) {
                LIST_INIT(&ulist->user_hashtbl[i]);
+       }
        ulist->node_count = 0;
 
-       lck_mtx_init(&ulist->user_mutex, nfsrv_active_user_mutex_group, LCK_ATTR_NULL);
+       lck_mtx_init(&ulist->user_mutex, &nfsrv_active_user_mutex_group, LCK_ATTR_NULL);
 }
 
 /* Free all nodes in an active user list */
@@ -3526,8 +4091,9 @@ nfsrv_free_user_list(struct nfs_active_user_list *ulist)
 {
        struct nfs_user_stat_node *unode;
 
-       if (!ulist)
+       if (!ulist) {
                return;
+       }
 
        while ((unode = TAILQ_FIRST(&ulist->user_lru))) {
                /* Remove node and free */
@@ -3540,20 +4106,20 @@ nfsrv_free_user_list(struct nfs_active_user_list *ulist)
        }
        ulist->node_count = 0;
 
-       lck_mtx_destroy(&ulist->user_mutex, nfsrv_active_user_mutex_group);
+       lck_mtx_destroy(&ulist->user_mutex, &nfsrv_active_user_mutex_group);
 }
 
 /* Reclaim old expired user nodes from active user lists. */
 void
 nfsrv_active_user_list_reclaim(void)
 {
-       struct nfs_exportfs                     *nxfs;
-       struct nfs_export                       *nx;
-       struct nfs_active_user_list             *ulist;
-       struct nfs_user_stat_hashtbl_head       oldlist;
-       struct nfs_user_stat_node               *unode, *unode_next;
-       struct timeval                          now;
-       uint32_t                                tstale;
+       struct nfs_exportfs                     *nxfs;
+       struct nfs_export                       *nx;
+       struct nfs_active_user_list             *ulist;
+       struct nfs_user_stat_hashtbl_head       oldlist;
+       struct nfs_user_stat_node               *unode, *unode_next;
+       struct timeval                          now;
+       long                                    tstale;
 
        LIST_INIT(&oldlist);
 
@@ -3569,8 +4135,9 @@ nfsrv_active_user_list_reclaim(void)
                                unode_next = TAILQ_NEXT(unode, lru_link);
 
                                /* check if this node has expired */
-                               if (unode->tm_last >= tstale)
+                               if (unode->tm_last >= tstale) {
                                        break;
+                               }
 
                                /* Remove node from the active user list */
                                TAILQ_REMOVE(&ulist->user_lru, unode, lru_link);
@@ -3587,10 +4154,10 @@ nfsrv_active_user_list_reclaim(void)
                        lck_mtx_unlock(&ulist->user_mutex);
                }
        }
-        lck_rw_done(&nfsrv_export_rwlock);
+       lck_rw_done(&nfsrv_export_rwlock);
 
        /* Free expired nodes */
-        while ((unode = LIST_FIRST(&oldlist))) {
+       while ((unode = LIST_FIRST(&oldlist))) {
                LIST_REMOVE(unode, hash_link);
                FREE(unode, M_TEMP);
        }
@@ -3602,20 +4169,20 @@ nfsrv_active_user_list_reclaim(void)
  * RFC 1094.
  */
 static u_char nfsrv_v2errmap[] = {
-  NFSERR_PERM, NFSERR_NOENT,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
-  NFSERR_NXIO, NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
-  NFSERR_IO,   NFSERR_IO,      NFSERR_ACCES,   NFSERR_IO,      NFSERR_IO,
-  NFSERR_IO,   NFSERR_EXIST,   NFSERR_IO,      NFSERR_NODEV,   NFSERR_NOTDIR,
-  NFSERR_ISDIR,        NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
-  NFSERR_IO,   NFSERR_FBIG,    NFSERR_NOSPC,   NFSERR_IO,      NFSERR_ROFS,
-  NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
-  NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
-  NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
-  NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
-  NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
-  NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
-  NFSERR_IO,   NFSERR_IO,      NFSERR_NAMETOL, NFSERR_IO,      NFSERR_IO,
-  NFSERR_NOTEMPTY, NFSERR_IO,  NFSERR_IO,      NFSERR_DQUOT,   NFSERR_STALE,
+       NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+       NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+       NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
+       NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
+       NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+       NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
+       NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+       NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+       NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+       NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+       NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+       NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+       NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO,
+       NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
 };
 
 /*
@@ -3981,22 +4548,26 @@ nfsrv_errmap(struct nfsrv_descript *nd, int err)
        short *defaulterrp, *errp;
 
        if (nd->nd_vers == NFS_VER2) {
-               if (err <= (int)sizeof(nfsrv_v2errmap))
-                       return ((int)nfsrv_v2errmap[err - 1]);
-               return (NFSERR_IO);
+               if (err <= (int)sizeof(nfsrv_v2errmap)) {
+                       return (int)nfsrv_v2errmap[err - 1];
+               }
+               return NFSERR_IO;
        }
        /* NFSv3 */
-       if (nd->nd_procnum > NFSPROC_COMMIT)
-               return (err & 0xffff);
+       if (nd->nd_procnum > NFSPROC_COMMIT) {
+               return err & 0xffff;
+       }
        errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
        while (*++errp) {
-               if (*errp == err)
-                       return (err);
-               else if (*errp > err)
+               if (*errp == err) {
+                       return err;
+               } else if (*errp > err) {
                        break;
+               }
        }
-       return ((int)*defaulterrp);
+       return (int)*defaulterrp;
 }
 
-#endif /* NFSSERVER */
+#endif /* CONFIG_NFS_SERVER */
 
+#endif /* CONFIG_NFS */