The branch stable/13 has been updated by rmacklem:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=0644746d50916cd1561ccec06afaa883554b98dc

commit 0644746d50916cd1561ccec06afaa883554b98dc
Author:     Rick Macklem <rmack...@freebsd.org>
AuthorDate: 2023-03-16 22:55:36 +0000
Commit:     Rick Macklem <rmack...@freebsd.org>
CommitDate: 2023-05-25 21:16:29 +0000

    nfscl: Add a new NFSv4.1/4.2 mount option for Kerberized mounts
    
    Without this patch, a Kerberized NFSv4.1/4.2 mount must provide
    a Kerberos credential for the client at mount time.  This credential
    is typically referred to as a "machine credential".  It can be
    created one of two ways:
    - The user (usually root) has a valid TGT at the time the mount
      is done and this becomes the machine credential.
      There are two problems with this.
      1 - The user doing the mount must have a valid TGT for a user
          principal at mount time.  As such, the mount cannot be put
          in fstab(5) or similar.
      2 - When the TGT expires, the mount breaks.
    - The client machine has a service principal in its default keytab
      file and this service principal (typically called a host-based
      initiator credential) is used as the machine credential.
      There are problems with this approach as well:
      1 - There is a certain amount of administrative overhead creating
          the service principal for the NFS client, creating a keytab
          entry for this principal and then copying the keytab entry
          into the client's default keytab file via some secure means.
      2 - The NFS client must have a fixed, well known, DNS name, since
          that FQDN is in the service principal name as the instance.
    
    This patch uses a feature of NFSv4.1/4.2 called SP4_NONE, which
    allows the state maintenance operations to be performed by any
    authentication mechanism, to do these operations via AUTH_SYS
    instead of RPCSEC_GSS (Kerberos).  As such, neither of the above
    mechanisms is needed.
    
    It is hoped that this option will encourage adoption of Kerberized
    NFS mounts using TLS, to provide a more secure NFS mount.
    
    This new NFSv4.1/4.2 mount option, called "syskrb5" must be used
    with "sec=krb5[ip]" to avoid the need for either of the above
    Kerberos setups to be done by the client.
    
    Note that all file access/modification operations still require
    users on the NFS client to have a valid TGT recognized by the
    NFSv4.1/4.2 server.  As such, this option allows, at most, a
    malicious client to do some sort of DOS attack.
    
    Although not required, use of "tls" with this new option is
    encouraged, since it provides on-the-wire encryption plus,
    optionally, client identity verification via a X.509
    certificate provided to the server during TLS handshake.
    Alternately, "sec=krb5p" does provide on-the-wire
    encryption of file data.
    
    A mount_nfs(8) man page update will be done in a separate commit.
    
    (cherry picked from commit 896516e54a8c39c1c8be3ad918f38fbf196b57ed)
---
 sys/fs/nfs/nfs.h                 |   7 ++
 sys/fs/nfs/nfs_commonkrpc.c      |  86 ++++++++++++++++++++++++-
 sys/fs/nfs/nfs_commonsubs.c      |  17 +++--
 sys/fs/nfs/nfs_var.h             |   5 +-
 sys/fs/nfs/nfsport.h             |   1 +
 sys/fs/nfsclient/nfs_clnode.c    |   4 +-
 sys/fs/nfsclient/nfs_clport.c    |  26 +++++++-
 sys/fs/nfsclient/nfs_clrpcops.c  | 122 +++++++++++++++++++++++++++++------
 sys/fs/nfsclient/nfs_clvfsops.c  | 134 +++++++++++++++++++++++++++++++++++----
 sys/fs/nfsclient/nfs_clvnops.c   |   6 +-
 sys/fs/nfsclient/nfsmount.h      |   3 +
 sys/fs/nfsserver/nfs_nfsdport.c  |   3 +-
 sys/fs/nfsserver/nfs_nfsdserv.c  |  18 +++---
 sys/fs/nfsserver/nfs_nfsdstate.c |   6 +-
 14 files changed, 378 insertions(+), 60 deletions(-)

diff --git a/sys/fs/nfs/nfs.h b/sys/fs/nfs/nfs.h
index ffd612331c1f..eac318512a35 100644
--- a/sys/fs/nfs/nfs.h
+++ b/sys/fs/nfs/nfs.h
@@ -522,6 +522,13 @@ typedef struct {
        (b)->bits[2] = NFSGETATTRBIT_STATFS2;                           \
 } while (0)
 
+#define        NFSROOTFS_GETATTRBIT(b) do {                                    
\
+       (b)->bits[0] = NFSGETATTRBIT_STATFS0 | NFSATTRBIT_GETATTR0 |    \
+           NFSATTRBM_LEASETIME;                                        \
+       (b)->bits[1] = NFSGETATTRBIT_STATFS1 | NFSATTRBIT_GETATTR1;     \
+       (b)->bits[2] = NFSGETATTRBIT_STATFS2 | NFSATTRBIT_GETATTR2;     \
+} while (0)
+
 #define        NFSISSETSTATFS_ATTRBIT(b)                                       
\
                (((b)->bits[0] & NFSATTRBIT_STATFS0) ||                 \
                 ((b)->bits[1] & NFSATTRBIT_STATFS1) ||                 \
diff --git a/sys/fs/nfs/nfs_commonkrpc.c b/sys/fs/nfs/nfs_commonkrpc.c
index 9badd8be47d4..f98d9f8df99a 100644
--- a/sys/fs/nfs/nfs_commonkrpc.c
+++ b/sys/fs/nfs/nfs_commonkrpc.c
@@ -162,6 +162,87 @@ static int nfsv2_procid[NFS_V3NPROCS] = {
        NFSV2PROC_NOOP,
 };
 
+/*
+ * This static array indicates that a NFSv4 RPC should use
+ * RPCSEC_GSS, if the mount indicates that via sec=krb5[ip].
+ * System RPCs that do not use file handles will be false
+ * in this array so that they will use AUTH_SYS when the
+ * "syskrb5" mount option is specified, along with
+ * "sec=krb5[ip]".
+ */
+static bool nfscl_use_gss[NFSV42_NPROCS] = {
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       false,          /* SetClientID */
+       false,          /* SetClientIDConfirm */
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       false,          /* Renew */
+       true,
+       false,          /* ReleaseLockOwn */
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       false,          /* ExchangeID */
+       false,          /* CreateSession */
+       false,          /* DestroySession */
+       false,          /* DestroyClientID */
+       false,          /* FreeStateID */
+       true,
+       true,
+       true,
+       true,
+       false,          /* ReclaimComplete */
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       true,
+       false,          /* BindConnectionToSession */
+       true,
+       true,
+       true,
+       true,
+};
+
 /*
  * Initialize sockets and congestion for a new NFS connection.
  * We do not free the sockaddr if error.
@@ -679,7 +760,8 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount 
*nmp,
                }
                NFSUNLOCKSTATE();
        } else if (nmp != NULL && NFSHASKERB(nmp) &&
-            nd->nd_procnum != NFSPROC_NULL) {
+            nd->nd_procnum != NFSPROC_NULL && (!NFSHASSYSKRB5(nmp) ||
+            nfscl_use_gss[nd->nd_procnum])) {
                if (NFSHASALLGSSNAME(nmp) && nmp->nm_krbnamelen > 0)
                        nd->nd_flag |= ND_USEGSSNAME;
                if ((nd->nd_flag & ND_USEGSSNAME) != 0) {
@@ -720,7 +802,7 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount 
*nmp,
                else
                        secflavour = RPCSEC_GSS_KRB5;
                srv_principal = NFSMNT_SRVKRBNAME(nmp);
-       } else if (nmp != NULL && !NFSHASKERB(nmp) &&
+       } else if (nmp != NULL && (!NFSHASKERB(nmp) || NFSHASSYSKRB5(nmp)) &&
            nd->nd_procnum != NFSPROC_NULL &&
            (nd->nd_flag & ND_USEGSSNAME) != 0) {
                /*
diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index 00cc8c68e9bf..2565b4edaf23 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
 #include "opt_inet6.h"
 
 #include <fs/nfs/nfsport.h>
+#include <fs/nfsclient/nfsmount.h>
 
 #include <sys/extattr.h>
 
@@ -436,7 +437,7 @@ nfscl_reqstart(struct nfsrv_descript *nd, int procnum, 
struct nfsmount *nmp,
                if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
                        NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
                        *tl = txdr_unsigned(NFSV4OP_PUTFH);
-                       (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
+                       nfsm_fhtom(nmp, nd, nfhp, fhlen, 0);
                        if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
                            == 2 && procnum != NFSPROC_WRITEDS &&
                            procnum != NFSPROC_COMMITDS) {
@@ -466,7 +467,7 @@ nfscl_reqstart(struct nfsrv_descript *nd, int procnum, 
struct nfsmount *nmp,
                        *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
                }
        } else {
-               (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
+               nfsm_fhtom(NULL, nd, nfhp, fhlen, 0);
        }
        if (procnum < NFSV42_NPROCS)
                NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
@@ -954,12 +955,15 @@ newnfs_init(void)
  * Return the number of bytes output, including XDR overhead.
  */
 int
-nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
+nfsm_fhtom(struct nfsmount *nmp, struct nfsrv_descript *nd, u_int8_t *fhp,
+    int size, int set_true)
 {
        u_int32_t *tl;
        u_int8_t *cp;
        int fullsiz, rem, bytesize = 0;
 
+       KASSERT(nmp == NULL || nmp->nm_fhsize > 0,
+           ("nfsm_fhtom: 0 length fh"));
        if (size == 0)
                size = NFSX_MYFH;
        switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
@@ -974,6 +978,11 @@ nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int 
size, int set_true)
                break;
        case ND_NFSV3:
        case ND_NFSV4:
+               if (size == NFSX_FHMAX + 1 && nmp != NULL &&
+                   (nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0) {
+                       fhp = nmp->nm_fh;
+                       size = nmp->nm_fhsize;
+               }
                fullsiz = NFSM_RNDUP(size);
                rem = fullsiz - size;
                if (set_true) {
@@ -2741,7 +2750,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount 
*mp, vnode_t vp,
                        retnum += NFSX_UNSIGNED;
                        break;
                case NFSATTRBIT_FILEHANDLE:
-                       retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
+                       retnum += nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
                        break;
                case NFSATTRBIT_FILEID:
                        NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h
index ef7d0050e1a3..16d82053a961 100644
--- a/sys/fs/nfs/nfs_var.h
+++ b/sys/fs/nfs/nfs_var.h
@@ -325,7 +325,8 @@ int nfsaddr_match(int, union nethostaddr *, NFSSOCKADDR_T);
 int nfsaddr2_match(NFSSOCKADDR_T, NFSSOCKADDR_T);
 int nfsm_strtom(struct nfsrv_descript *, const char *, int);
 int nfsm_mbufuio(struct nfsrv_descript *, struct uio *, int);
-int nfsm_fhtom(struct nfsrv_descript *, u_int8_t *, int, int);
+int nfsm_fhtom(struct nfsmount *, struct nfsrv_descript *, u_int8_t *, int,
+    int);
 int nfsm_advance(struct nfsrv_descript *, int, int);
 void *nfsm_dissct(struct nfsrv_descript *, int, int);
 void newnfs_copycred(struct nfscred *, struct ucred *);
@@ -510,7 +511,7 @@ int nfsrpc_lockt(struct nfsrv_descript *, vnode_t,
 int nfsrpc_lock(struct nfsrv_descript *, struct nfsmount *, vnode_t,
     u_int8_t *, int, struct nfscllockowner *, int, int, u_int64_t,
     u_int64_t, short, struct ucred *, NFSPROC_T *, int);
-int nfsrpc_statfs(vnode_t, struct nfsstatfs *, struct nfsfsinfo *,
+int nfsrpc_statfs(vnode_t, struct nfsstatfs *, struct nfsfsinfo *, uint32_t *,
     struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *);
 int nfsrpc_fsinfo(vnode_t, struct nfsfsinfo *, struct ucred *,
     NFSPROC_T *, struct nfsvattr *, int *, void *);
diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h
index bcfbae857755..50071be4cc06 100644
--- a/sys/fs/nfs/nfsport.h
+++ b/sys/fs/nfs/nfsport.h
@@ -1086,6 +1086,7 @@ void ncl_copy_vattr(struct vattr *dst, struct vattr *src);
 #define        NFSHASONEOPENOWN(n)     (((n)->nm_flag & NFSMNT_ONEOPENOWN) != 
0 &&     \
                                    (n)->nm_minorvers > 0)
 #define        NFSHASTLS(n)            (((n)->nm_newflag & NFSMNT_TLS) != 0)
+#define        NFSHASSYSKRB5(n)        (((n)->nm_newflag & NFSMNT_SYSKRB5) != 
0)
 
 /*
  * Set boottime.
diff --git a/sys/fs/nfsclient/nfs_clnode.c b/sys/fs/nfsclient/nfs_clnode.c
index 9718c2c36a3c..8807cb2df712 100644
--- a/sys/fs/nfsclient/nfs_clnode.c
+++ b/sys/fs/nfsclient/nfs_clnode.c
@@ -156,8 +156,8 @@ ncl_nget(struct mount *mntp, u_int8_t *fhp, int fhsize, 
struct nfsnode **npp,
         * Are we getting the root? If so, make sure the vnode flags
         * are correct 
         */
-       if ((fhsize == nmp->nm_fhsize) &&
-           !bcmp(fhp, nmp->nm_fh, fhsize)) {
+       if (fhsize == NFSX_FHMAX + 1 || (fhsize == nmp->nm_fhsize &&
+           !bcmp(fhp, nmp->nm_fh, fhsize))) {
                if (vp->v_type == VNON)
                        vp->v_type = VDIR;
                vp->v_vflag |= VV_ROOT;
diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c
index 1d2617b2bb9b..6501827e04a8 100644
--- a/sys/fs/nfsclient/nfs_clport.c
+++ b/sys/fs/nfsclient/nfs_clport.c
@@ -140,6 +140,19 @@ nfscl_nget(struct mount *mntp, struct vnode *dvp, struct 
nfsfh *nfhp,
        dnp = VTONFS(dvp);
        *npp = NULL;
 
+       /*
+        * If this is the mount point fh and NFSMNTP_FAKEROOT is set, replace
+        * it with the fake fh.
+        */
+       if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
+           nmp->nm_fhsize > 0 && nmp->nm_fhsize == nfhp->nfh_len &&
+           !NFSBCMP(nmp->nm_fh, nfhp->nfh_fh, nmp->nm_fhsize)) {
+               free(nfhp, M_NFSFH);
+               nfhp = malloc(sizeof(struct nfsfh) + NFSX_FHMAX + 1,
+                   M_NFSFH, M_WAITOK | M_ZERO);
+               nfhp->nfh_len = NFSX_FHMAX + 1;
+       }
+
        hash = fnv_32_buf(nfhp->nfh_fh, nfhp->nfh_len, FNV1_32_INIT);
 
        error = vfs_hash_get(mntp, hash, lkflags,
@@ -241,8 +254,9 @@ nfscl_nget(struct mount *mntp, struct vnode *dvp, struct 
nfsfh *nfhp,
         * Are we getting the root? If so, make sure the vnode flags
         * are correct 
         */
-       if ((nfhp->nfh_len == nmp->nm_fhsize) &&
-           !bcmp(nfhp->nfh_fh, nmp->nm_fh, nfhp->nfh_len)) {
+       if (nfhp->nfh_len == NFSX_FHMAX + 1 ||
+           (nfhp->nfh_len == nmp->nm_fhsize &&
+            !bcmp(nfhp->nfh_fh, nmp->nm_fh, nfhp->nfh_len))) {
                if (vp->v_type == VNON)
                        vp->v_type = VDIR;
                vp->v_vflag |= VV_ROOT;
@@ -492,9 +506,15 @@ nfscl_loadattrcache(struct vnode **vpp, struct nfsvattr 
*nap, void *nvaper,
                 * this reliably with Clang and .c files during parallel build.
                 * A pcap revealed packet fragmentation and GETATTR RPC
                 * responses with wholly wrong fileids.
+                * For the case where the file handle is a fake one
+                * generated via the "syskrb5" mount option and
+                * the old fileid is 2, ignore the test, since this might
+                * be replacing the fake attributes with correct ones.
                 */
                if ((np->n_vattr.na_fileid != 0 &&
-                    np->n_vattr.na_fileid != nap->na_fileid) ||
+                    np->n_vattr.na_fileid != nap->na_fileid &&
+                    (np->n_vattr.na_fileid != 2 || !NFSHASSYSKRB5(nmp) ||
+                     np->n_fhp->nfh_len != NFSX_FHMAX + 1)) ||
                    force_fid_err) {
                        nfscl_warn_fileid(nmp, &np->n_vattr, nap);
                        error = EIDRM;
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index 51c7bb25d357..00c54ce71e28 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -227,6 +227,7 @@ static int nfsrpc_copyrpc(vnode_t, off_t, vnode_t, off_t, 
size_t *,
 static int nfsrpc_seekrpc(vnode_t, off_t *, nfsv4stateid_t *, bool *,
     int, struct nfsvattr *, int *, struct ucred *);
 static struct mbuf *nfsm_split(struct mbuf *, uint64_t);
+static void nfscl_statfs(struct vnode *, struct ucred *, NFSPROC_T *);
 
 int nfs_pnfsio(task_fn_t *, void *);
 
@@ -305,9 +306,22 @@ nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred 
*cred,
        int error;
        struct nfsrv_descript nfsd, *nd = &nfsd;
        nfsattrbit_t attrbits;
+       struct nfsmount *nmp;
+       struct nfsnode *np;
 
        *attrflagp = 0;
        supported = mode;
+       nmp = VFSTONFS(vp->v_mount);
+       np = VTONFS(vp);
+       if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
+           nmp->nm_fhsize == 0) {
+               /* Attempt to get the actual root file handle. */
+               error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), cred, p);
+               if (error != 0)
+                       return (EACCES);
+               if (np->n_fhp->nfh_len == NFSX_FHMAX + 1)
+                       nfscl_statfs(vp, cred, p);
+       }
        NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp, cred);
        NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
        *tl = txdr_unsigned(mode);
@@ -1211,7 +1225,20 @@ nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T 
*p,
        struct nfsrv_descript nfsd, *nd = &nfsd;
        int error;
        nfsattrbit_t attrbits;
+       struct nfsnode *np;
+       struct nfsmount *nmp;
 
+       nmp = VFSTONFS(vp->v_mount);
+       np = VTONFS(vp);
+       if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
+           nmp->nm_fhsize == 0) {
+               /* Attempt to get the actual root file handle. */
+               error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), cred, p);
+               if (error != 0)
+                       return (EACCES);
+               if (np->n_fhp->nfh_len == NFSX_FHMAX + 1)
+                       nfscl_statfs(vp, cred, p);
+       }
        NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred);
        if (nd->nd_flag & ND_NFSV4) {
                NFSGETATTR_ATTRBIT(&attrbits);
@@ -2316,7 +2343,7 @@ nfsrpc_createv4(vnode_t dvp, char *name, int namelen, 
struct vattr *vap,
        /* Get the directory's post-op attributes. */
        NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
        *tl = txdr_unsigned(NFSV4OP_PUTFH);
-       (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
+       nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
        NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
        *tl = txdr_unsigned(NFSV4OP_GETATTR);
        (void) nfsrv_putattrbit(nd, &attrbits);
@@ -2517,7 +2544,7 @@ tryagain:
                        *tl++ = dstateid.other[2];
                        *tl = txdr_unsigned(NFSV4OP_PUTFH);
                        np = VTONFS(dvp);
-                       (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
+                       nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh,
                            np->n_fhp->nfh_len, 0);
                        NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
                        *tl = txdr_unsigned(NFSV4OP_REMOVE);
@@ -2605,7 +2632,7 @@ tryagain:
                                NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
                                *tl = txdr_unsigned(NFSV4OP_PUTFH);
                                np = VTONFS(tvp);
-                               (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
+                               nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh,
                                    np->n_fhp->nfh_len, 0);
                                NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
                                *tl = txdr_unsigned(NFSV4OP_DELEGRETURN);
@@ -2625,7 +2652,7 @@ tryagain:
                        NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
                        *tl = txdr_unsigned(NFSV4OP_PUTFH);
                        np = VTONFS(fdvp);
-                       (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
+                       nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh,
                            np->n_fhp->nfh_len, 0);
                        NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
                        *tl = txdr_unsigned(NFSV4OP_SAVEFH);
@@ -2642,7 +2669,7 @@ tryagain:
                (void) nfsrv_putattrbit(nd, &attrbits);
                NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
                *tl = txdr_unsigned(NFSV4OP_PUTFH);
-               (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
+               nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh,
                    VTONFS(tdvp)->n_fhp->nfh_len, 0);
                NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
                *tl = txdr_unsigned(NFSV4OP_GETATTR);
@@ -2653,7 +2680,7 @@ tryagain:
        }
        (void) nfsm_strtom(nd, fnameptr, fnamelen);
        if (!(nd->nd_flag & ND_NFSV4))
-               (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
+               nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh,
                        VTONFS(tdvp)->n_fhp->nfh_len, 0);
        (void) nfsm_strtom(nd, tnameptr, tnamelen);
        error = nfscl_request(nd, fdvp, p, cred, fstuff);
@@ -2738,7 +2765,7 @@ nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int 
namelen,
                NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
                *tl = txdr_unsigned(NFSV4OP_PUTFH);
        }
-       (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh,
+       nfsm_fhtom(VFSTONFS(dvp->v_mount), nd, VTONFS(dvp)->n_fhp->nfh_fh,
                VTONFS(dvp)->n_fhp->nfh_len, 0);
        if (nd->nd_flag & ND_NFSV4) {
                NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
@@ -2878,7 +2905,7 @@ nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct 
vattr *vap,
                (void) nfsrv_putattrbit(nd, &attrbits);
                NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
                *tl = txdr_unsigned(NFSV4OP_PUTFH);
-               (void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0);
+               nfsm_fhtom(nmp, nd, fhp->nfh_fh, fhp->nfh_len, 0);
                NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
                *tl = txdr_unsigned(NFSV4OP_GETATTR);
                (void) nfsrv_putattrbit(nd, &attrbits);
@@ -4398,8 +4425,8 @@ nfsmout:
  */
 int
 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
-    struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
-    void *stuff)
+    uint32_t *leasep, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap,
+    int *attrflagp, void *stuff)
 {
        u_int32_t *tl = NULL;
        struct nfsrv_descript nfsd, *nd = &nfsd;
@@ -4414,7 +4441,10 @@ nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct 
nfsfsinfo *fsp,
                 * For V4, you actually do a getattr.
                 */
                NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred);
-               NFSSTATFS_GETATTRBIT(&attrbits);
+               if (leasep != NULL)
+                       NFSROOTFS_GETATTRBIT(&attrbits);
+               else
+                       NFSSTATFS_GETATTRBIT(&attrbits);
                (void) nfsrv_putattrbit(nd, &attrbits);
                nd->nd_flag |= ND_USEGSSNAME;
                error = nfscl_request(nd, vp, p, cred, stuff);
@@ -4422,8 +4452,8 @@ nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct 
nfsfsinfo *fsp,
                        return (error);
                if (nd->nd_repstat == 0) {
                        error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
-                           NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p,
-                           cred);
+                           NULL, NULL, sbp, fsp, NULL, 0, NULL, leasep, NULL,
+                           p, cred);
                        if (!error) {
                                nmp->nm_fsid[0] = nap->na_filesid[0];
                                nmp->nm_fsid[1] = nap->na_filesid[1];
@@ -4485,10 +4515,22 @@ nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
        u_int32_t *tl;
        nfsattrbit_t attrbits;
        int error;
+       struct nfsnode *np;
 
        *attrflagp = 0;
        nmp = VFSTONFS(vp->v_mount);
        if (NFSHASNFSV4(nmp)) {
+               np = VTONFS(vp);
+               if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
+                   nmp->nm_fhsize == 0) {
+                       /* Attempt to get the actual root file handle. */
+                       error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
+                           cred, p);
+                       if (error != 0)
+                               return (EACCES);
+                       if (np->n_fhp->nfh_len == NFSX_FHMAX + 1)
+                               nfscl_statfs(vp, cred, p);
+               }
                /*
                 * For V4, you actually do a getattr.
                 */
@@ -4675,7 +4717,7 @@ nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, 
struct ucred *cred,
        u_int32_t *tl;
        struct nfsrv_descript nfsd;
        struct nfsrv_descript *nd = &nfsd;
-       u_char *cp, *cp2;
+       u_char *cp, *cp2, *fhp;
        int error, cnt, len, setnil;
        u_int32_t *opcntp;
 
@@ -4723,9 +4765,17 @@ nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, 
struct ucred *cred,
                        len > NFSX_FHMAX) {
                        nd->nd_repstat = NFSERR_BADXDR;
                } else {
-                       nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len);
-                       if (nd->nd_repstat == 0)
-                               nmp->nm_fhsize = len;
+                       fhp = malloc(len + 1, M_TEMP, M_WAITOK);
+                       nd->nd_repstat = nfsrv_mtostr(nd, fhp, len);
+                       if (nd->nd_repstat == 0) {
+                               NFSLOCKMNT(nmp);
+                               if (nmp->nm_fhsize == 0) {
+                                       NFSBCOPY(fhp, nmp->nm_fh, len);
+                                       nmp->nm_fhsize = len;
+                               }
+                               NFSUNLOCKMNT(nmp);
+                       }
+                       free(fhp, M_TEMP);
                }
        }
        error = nd->nd_repstat;
@@ -7949,7 +7999,7 @@ nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, 
struct vattr *vap,
        /* Get the directory's post-op attributes. */
        NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
        *tl = txdr_unsigned(NFSV4OP_PUTFH);
-       nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
+       nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
        NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
        *tl = txdr_unsigned(NFSV4OP_GETATTR);
        nfsrv_putattrbit(nd, &attrbits);
@@ -8354,7 +8404,7 @@ nfsrpc_copyrpc(vnode_t invp, off_t inoff, vnode_t outvp, 
off_t outoff,
        nfsrv_putattrbit(nd, &attrbits);
        NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
        *tl = txdr_unsigned(NFSV4OP_PUTFH);
-       nfsm_fhtom(nd, VTONFS(outvp)->n_fhp->nfh_fh,
+       nfsm_fhtom(nmp, nd, VTONFS(outvp)->n_fhp->nfh_fh,
            VTONFS(outvp)->n_fhp->nfh_len, 0);
        NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
        *tl = txdr_unsigned(NFSV4OP_COPY);
@@ -8943,3 +8993,37 @@ nfsmout:
                printf("nfsrpc_bindconnsess: reply bad xdr\n");
        m_freem(nd->nd_mrep);
 }
+
+/*
+ * Do roughly what nfs_statfs() does for NFSv4, but when called with a shared
+ * locked vnode.
+ */
+static void
+nfscl_statfs(struct vnode *vp, struct ucred *cred, NFSPROC_T *td)
+{
+       struct nfsvattr nfsva;
+       struct nfsfsinfo fs;
+       struct nfsstatfs sb;
+       struct mount *mp;
+       struct nfsmount *nmp;
+       uint32_t lease;
+       int attrflag, error;
+
+       mp = vp->v_mount;
+       nmp = VFSTONFS(mp);
+       error = nfsrpc_statfs(vp, &sb, &fs, &lease, cred, td, &nfsva,
+           &attrflag, NULL);
+       if (attrflag != 0)
+               nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1);
+       if (error == 0) {
+               NFSLOCKCLSTATE();
+               if (nmp->nm_clp != NULL)
+                       nmp->nm_clp->nfsc_renew = NFSCL_RENEW(lease);
+               NFSUNLOCKCLSTATE();
+               mtx_lock(&nmp->nm_mtx);
+               nfscl_loadfsinfo(nmp, &fs);
+               nfscl_loadsbinfo(nmp, &sb, &mp->mnt_stat);
+               mp->mnt_stat.f_iosize = newnfs_iosize(nmp);
+               mtx_unlock(&nmp->nm_mtx);
+       }
+}
diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c
index be863cc9d70a..d60b8f66f8c9 100644
--- a/sys/fs/nfsclient/nfs_clvfsops.c
+++ b/sys/fs/nfsclient/nfs_clvfsops.c
@@ -291,13 +291,37 @@ nfs_statfs(struct mount *mp, struct statfs *sbp)
        struct nfsstatfs sb;
        int error = 0, attrflag, gotfsinfo = 0, ret;
        struct nfsnode *np;
+       char *fakefh;
 
        td = curthread;
 
        error = vfs_busy(mp, MBF_NOWAIT);
        if (error)
                return (error);
-       error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE);
+       if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0) {
+               if (nmp->nm_fhsize == 0) {
+                       error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
+                           td->td_ucred, td);
+                       if (error != 0) {
+                               /*
+                                * We cannot do anything yet.  Hopefully what
+                                * is in mnt_stat is sufficient.
+                                */
+                               if (sbp != &mp->mnt_stat)
+                                       *sbp = mp->mnt_stat;
+                               strncpy(&sbp->f_fstypename[0],
+                                   mp->mnt_vfc->vfc_name, MFSNAMELEN);
+                               vfs_unbusy(mp);
+                               return (0);
+                       }
+               }
+               fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK | M_ZERO);
+               error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np, LK_EXCLUSIVE);
+               free(fakefh, M_TEMP);
+       } else {
+               error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
+                   LK_EXCLUSIVE);
+       }
        if (error) {
                vfs_unbusy(mp);
                return (error);
@@ -313,8 +337,19 @@ nfs_statfs(struct mount *mp, struct statfs *sbp)
        } else
                mtx_unlock(&nmp->nm_mtx);
        if (!error)
-               error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva,
-                   &attrflag, NULL);
+               error = nfsrpc_statfs(vp, &sb, &fs, NULL, td->td_ucred, td,
+                   &nfsva, &attrflag, NULL);
+       if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
+           error == NFSERR_WRONGSEC) {
+               /* Cannot get new stats, so return what is in mnt_stat. */
+               if (sbp != &mp->mnt_stat)
+                       *sbp = mp->mnt_stat;
+               strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name,
+                   MFSNAMELEN);
+               vput(vp);
+               vfs_unbusy(mp);
+               return (0);
+       }
        if (error != 0)
                NFSCL_DEBUG(2, "statfs=%d\n", error);
        if (attrflag == 0) {
@@ -749,7 +784,7 @@ static const char *nfs_opts[] = { "from", "nfs_args",
     "nfsv3", "sec", "principal", "nfsv4", "gssname", "allgssname", "dirpath",
     "minorversion", "nametimeo", "negnametimeo", "nocto", "noncontigwr",
     "pnfs", "wcommitsize", "oneopenown", "tls", "tlscertname", "nconnect",
-    NULL };
+    "syskrb5", NULL };
 
 /*
  * Parse the "from" mountarg, passed by the generic mount(8) program
@@ -1205,6 +1240,8 @@ nfs_mount(struct mount *mp)
                 */
                aconn--;
        }
+       if (vfs_getopt(mp->mnt_optnew, "syskrb5", NULL, NULL) == 0)
+               newflag |= NFSMNT_SYSKRB5;
        if (vfs_getopt(mp->mnt_optnew, "sec",
                (void **) &secname, NULL) == 0)
                nfs_sec_name(secname, &args.flags);
@@ -1387,6 +1424,39 @@ nfs_mount(struct mount *mp)
                goto out;
        }
 
+       if ((newflag & NFSMNT_SYSKRB5) != 0 &&
+           ((args.flags & NFSMNT_NFSV4) == 0 || minvers == 0)) {
+               /*
+                * This option requires the use of SP4_NONE, which
+                * is only in NFSv4.1/4.2.
+                */
+               vfs_mount_error(mp, "syskrb5 should only be used "
+                   "for NFSv4.1/4.2 mounts");
+               error = EINVAL;
+               goto out;
+       }
+
+       if ((newflag & NFSMNT_SYSKRB5) != 0 &&
+           (args.flags & NFSMNT_KERB) == 0) {
+               /*
+                * This option modifies the behaviour of sec=krb5[ip].
+                */
+               vfs_mount_error(mp, "syskrb5 should only be used "
+                   "for sec=krb5[ip] mounts");
+               error = EINVAL;
+               goto out;
+       }
+
+       if ((newflag & NFSMNT_SYSKRB5) != 0 && krbname[0] != '\0') {
+               /*
+                * This option is used as an alternative to "gssname".
+                */
+               vfs_mount_error(mp, "syskrb5 should not be used "
+                   "with the gssname option");
+               error = EINVAL;
+               goto out;
+       }
+
        args.fh = nfh;
        error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
            dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
@@ -1448,6 +1518,7 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct 
sockaddr *nam,
        struct nfsclds *dsp, *tdsp;
        uint32_t lease;
        bool tryminvers;
+       char *fakefh;
        static u_int64_t clval = 0;
 #ifdef KERN_TLS
        u_int maxlen;
@@ -1621,6 +1692,12 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct 
sockaddr *nam,
                        error = EINVAL;
                        goto bad;
                }
+               if (NFSHASSYSKRB5(nmp) && nmp->nm_minorvers == 0) {
+                       vfs_mount_error(mp, "syskrb5 should only be used "
+                           "for NFSv4.1/4.2 mounts");
+                       error = EINVAL;
+                       goto bad;
+               }
        }
 
        if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) &&
@@ -1635,10 +1712,13 @@ mountnfs(struct nfs_args *argp, struct mount *mp, 
struct sockaddr *nam,
                        error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
                            cred, td);
                        NFSCL_DEBUG(3, "aft dirp=%d\n", error);
-                       if (error)
+                       if (error != 0 && (!NFSHASSYSKRB5(nmp) ||
+                           error != NFSERR_WRONGSEC))
                                (void) nfs_catnap(PZERO, error, "nfsgetdirp");
-               } while (error && --trycnt > 0);
-               if (error)
+               } while (error != 0 && --trycnt > 0 &&
+                   (!NFSHASSYSKRB5(nmp) || error != NFSERR_WRONGSEC));
+               if (error != 0 && (!NFSHASSYSKRB5(nmp) ||
+                   error != NFSERR_WRONGSEC))
                        goto bad;
        }
 
@@ -1649,16 +1729,27 @@ mountnfs(struct nfs_args *argp, struct mount *mp, 
struct sockaddr *nam,
         * the nfsnode gets flushed out of the cache. Ufs does not have
         * this problem, because one can identify root inodes by their
         * number == UFS_ROOTINO (2).
+        * For the "syskrb5" mount, the file handle might not have
+        * been acquired.  As such, use a "fake" file handle which
+        * can never be returned by a server for the root vnode.
         */
-       if (nmp->nm_fhsize > 0) {
+       if (nmp->nm_fhsize > 0 || NFSHASSYSKRB5(nmp)) {
                /*
                 * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set
                 * non-zero for the root vnode. f_iosize will be set correctly
                 * by nfs_statfs() before any I/O occurs.
                 */
                mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ;
-               error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
-                   LK_EXCLUSIVE);
+               if (nmp->nm_fhsize == 0) {
+                       fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK |
+                           M_ZERO);
+                       error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np,
+                           LK_EXCLUSIVE);
+                       free(fakefh, M_TEMP);
+                       nmp->nm_privflag |= NFSMNTP_FAKEROOTFH;
+               } else
+                       error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
+                           LK_EXCLUSIVE);
                if (error)
                        goto bad;
                *vpp = NFSTOV(np);
@@ -1668,8 +1759,10 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct 
sockaddr *nam,
                 * mountpoint.  This has the side effect of filling in
                 * (*vpp)->v_type with the correct value.
                 */
-               ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1,
-                   cred, td, &nfsva, NULL, &lease);
+               ret = ENXIO;
+               if (nmp->nm_fhsize > 0)
+                       ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh,
+                           nmp->nm_fhsize, 1, cred, td, &nfsva, NULL, &lease);
                if (ret) {
                        /*
                         * Just set default values to get things going.
@@ -1684,7 +1777,7 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct 
sockaddr *nam,
                        nfsva.na_vattr.va_gen = 1;
                        nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
                        nfsva.na_vattr.va_size = 512 * 1024;
-                       lease = 60;
+                       lease = 20;
                }
                (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1);
                if ((argp->flags & NFSMNT_NFSV4) != 0) {
@@ -1870,9 +1963,20 @@ nfs_root(struct mount *mp, int flags, struct vnode **vpp)
        struct nfsmount *nmp;
        struct nfsnode *np;
        int error;
+       char *fakefh;
 
        nmp = VFSTONFS(mp);
-       error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags);
+       if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0) {
+               /* Attempt to get the actual root file handle. */
+               if (nmp->nm_fhsize == 0)
+                       error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
+                           curthread->td_ucred, curthread);
+               fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK | M_ZERO);
+               error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np, flags);
+               free(fakefh, M_TEMP);
+       } else {
+               error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags);
+       }
        if (error)
                return error;
        vp = NFSTOV(np);
@@ -2113,6 +2217,8 @@ void nfscl_retopts(struct nfsmount *nmp, char *buffer, 
size_t buflen)
            &buf, &blen);
        nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_TLS) != 0, ",tls", &buf,
            &blen);
+       nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_SYSKRB5) != 0,
+           ",syskrb5", &buf, &blen);
        nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn",
            &buf, &blen);
        nfscl_printoptval(nmp, nmp->nm_aconnect + 1, ",nconnect", &buf, &blen);
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index d1d84b05bbd7..425d75c10586 100644
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -996,7 +996,9 @@ nfs_getattr(struct vop_getattr_args *ap)
        struct nfsvattr nfsva;
        struct vattr *vap = ap->a_vap;
        struct vattr vattr;
+       struct nfsmount *nmp;
 
+       nmp = VFSTONFS(vp->v_mount);
        /*
         * Update local times for special files.
         */
@@ -1006,8 +1008,10 @@ nfs_getattr(struct vop_getattr_args *ap)
        NFSUNLOCKNODE(np);
        /*
         * First look in the cache.
+        * For "syskrb5" mounts, nm_fhsize might still be zero and
+        * cached attributes should be ignored.
         */
-       if (ncl_getattrcache(vp, &vattr) == 0) {
+       if (nmp->nm_fhsize > 0 && ncl_getattrcache(vp, &vattr) == 0) {
                ncl_copy_vattr(vap, &vattr);
 
                /*
diff --git a/sys/fs/nfsclient/nfsmount.h b/sys/fs/nfsclient/nfsmount.h
index a5997e474be9..c9183ebe919f 100644
--- a/sys/fs/nfsclient/nfsmount.h
+++ b/sys/fs/nfsclient/nfsmount.h
@@ -124,9 +124,12 @@ struct     nfsmount {
 #define        NFSMNTP_NOADVISE        0x00000100
 #define        NFSMNTP_NOALLOCATE      0x00000200
 #define        NFSMNTP_DELEGISSUED     0x00000400
+#define        NFSMNTP_NODEALLOCATE    0x00000800
+#define        NFSMNTP_FAKEROOTFH      0x00001000
 
 /* New mount flags only used by the kernel via nmount(2). */
 #define        NFSMNT_TLS              0x00000001
+#define        NFSMNT_SYSKRB5          0x00000002
 
 #define        NFSMNT_DIRPATH(m)       (&((m)->nm_name[(m)->nm_krbnamelen + 
1]))
 #define        NFSMNT_SRVKRBNAME(m)                                            
\
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index 06e6a4147f30..b83e51c231b0 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -2769,7 +2769,8 @@ again:
                                NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
                                txdr_hyper(*cookiep, tl);
                                nfsrv_postopattr(nd, 0, nvap);
-                               dirlen += nfsm_fhtom(nd,(u_int8_t *)&nfh,0,1);
+                               dirlen += nfsm_fhtom(NULL, nd, (u_int8_t *)&nfh,
+                                   0, 1);
                                dirlen += (5*NFSX_UNSIGNED+NFSX_V3POSTOPATTR);
                                if (nvp != NULL)
                                        vput(nvp);
diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c
index 2d1048d26486..6238160eda13 100644
--- a/sys/fs/nfsserver/nfs_nfsdserv.c
+++ b/sys/fs/nfsserver/nfs_nfsdserv.c
@@ -674,10 +674,10 @@ nfsrvd_lookup(struct nfsrv_descript *nd, __unused int 
isdgram,
                goto out;
        }
        if (nd->nd_flag & ND_NFSV2) {
-               (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
+               nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
                nfsrv_fillattr(nd, &nva);
        } else if (nd->nd_flag & ND_NFSV3) {
-               (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
+               nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
                nfsrv_postopattr(nd, 0, &nva);
                nfsrv_postopattr(nd, dattr_ret, &dattr);
        }
@@ -1284,7 +1284,7 @@ nfsrvd_create(struct nfsrv_descript *nd, __unused int 
isdgram,
        }
        if (nd->nd_flag & ND_NFSV2) {
                if (!nd->nd_repstat) {
-                       (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
+                       nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 0);
                        nfsrv_fillattr(nd, &nva);
                }
        } else {
@@ -1294,7 +1294,7 @@ nfsrvd_create(struct nfsrv_descript *nd, __unused int 
isdgram,
                diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
                vrele(dirp);
                if (!nd->nd_repstat) {
-                       (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
+                       nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 1);
                        nfsrv_postopattr(nd, 0, &nva);
                }
                nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
*** 73 LINES SKIPPED ***

Reply via email to