Author: rmacklem
Date: Sat Jul 28 20:38:08 2018
New Revision: 336846
URL: https://svnweb.freebsd.org/changeset/base/336846

Log:
  MFC: r334492
  Add the BindConnectiontoSession operation to the NFSv4.1 server.
  
  Under some fairly unusual circumstances, the Linux NFSv4.1 client is
  doing a BindConnectiontoSession operation for TCP connections.
  It is also used by the ESXi6.5 NFSv4.1 client.
  This patch adds this operation to the NFSv4.1 server.
  
  PR:           226493

Modified:
  stable/10/sys/fs/nfs/nfs.h
  stable/10/sys/fs/nfs/nfs_commonsubs.c
  stable/10/sys/fs/nfs/nfs_var.h
  stable/10/sys/fs/nfs/nfsproto.h
  stable/10/sys/fs/nfsserver/nfs_nfsdserv.c
  stable/10/sys/fs/nfsserver/nfs_nfsdsocket.c
  stable/10/sys/fs/nfsserver/nfs_nfsdstate.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/fs/nfs/nfs.h
==============================================================================
--- stable/10/sys/fs/nfs/nfs.h  Sat Jul 28 20:36:23 2018        (r336845)
+++ stable/10/sys/fs/nfs/nfs.h  Sat Jul 28 20:38:08 2018        (r336846)
@@ -288,6 +288,7 @@ struct nfsreferral {
 #define        LCL_ADMINREVOKED        0x00008000
 #define        LCL_RECLAIMCOMPLETE     0x00010000
 #define        LCL_NFSV41              0x00020000
+#define        LCL_DONEBINDCONN        0x00040000
 
 #define        LCL_GSS         LCL_KERBV       /* Or of all mechs */
 

Modified: stable/10/sys/fs/nfs/nfs_commonsubs.c
==============================================================================
--- stable/10/sys/fs/nfs/nfs_commonsubs.c       Sat Jul 28 20:36:23 2018        
(r336845)
+++ stable/10/sys/fs/nfs/nfs_commonsubs.c       Sat Jul 28 20:38:08 2018        
(r336846)
@@ -136,7 +136,7 @@ struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
        { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 },             /* Write */
        { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* ReleaseLockOwner */
        { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Backchannel Ctrl */
-       { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Bind Conn to Sess */
+       { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },             /* Bind Conn to Sess */
        { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },             /* Exchange ID */
        { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },             /* Create Session */
        { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },             /* Destroy Session */

Modified: stable/10/sys/fs/nfs/nfs_var.h
==============================================================================
--- stable/10/sys/fs/nfs/nfs_var.h      Sat Jul 28 20:36:23 2018        
(r336845)
+++ stable/10/sys/fs/nfs/nfs_var.h      Sat Jul 28 20:38:08 2018        
(r336846)
@@ -95,6 +95,7 @@ int nfsrv_getclient(nfsquad_t, int, struct nfsclient *
     nfsquad_t, uint32_t, struct nfsrv_descript *, NFSPROC_T *);
 int nfsrv_destroyclient(nfsquad_t, NFSPROC_T *);
 int nfsrv_destroysession(struct nfsrv_descript *, uint8_t *);
+int nfsrv_bindconnsess(struct nfsrv_descript *, uint8_t *, int *);
 int nfsrv_freestateid(struct nfsrv_descript *, nfsv4stateid_t *, NFSPROC_T *);
 int nfsrv_teststateid(struct nfsrv_descript *, nfsv4stateid_t *, NFSPROC_T *);
 int nfsrv_adminrevoke(struct nfsd_clid *, NFSPROC_T *);
@@ -230,6 +231,8 @@ int nfsrvd_sequence(struct nfsrv_descript *, int,
 int nfsrvd_reclaimcomplete(struct nfsrv_descript *, int,
     vnode_t, NFSPROC_T *, struct nfsexstuff *);
 int nfsrvd_destroyclientid(struct nfsrv_descript *, int,
+    vnode_t, NFSPROC_T *, struct nfsexstuff *);
+int nfsrvd_bindconnsess(struct nfsrv_descript *, int,
     vnode_t, NFSPROC_T *, struct nfsexstuff *);
 int nfsrvd_destroysession(struct nfsrv_descript *, int,
     vnode_t, NFSPROC_T *, struct nfsexstuff *);

Modified: stable/10/sys/fs/nfs/nfsproto.h
==============================================================================
--- stable/10/sys/fs/nfs/nfsproto.h     Sat Jul 28 20:36:23 2018        
(r336845)
+++ stable/10/sys/fs/nfs/nfsproto.h     Sat Jul 28 20:38:08 2018        
(r336846)
@@ -648,6 +648,15 @@
 #define        NFSFLAYUTIL_DENSE               0x1
 #define        NFSFLAYUTIL_COMMIT_THRU_MDS     0x2
 
+/* Enum values for Bind Connection to Session. */
+#define        NFSCDFC4_FORE           0x1
+#define        NFSCDFC4_BACK           0x2
+#define        NFSCDFC4_FORE_OR_BOTH   0x3
+#define        NFSCDFC4_BACK_OR_BOTH   0x7
+#define        NFSCDFS4_FORE           0x1
+#define        NFSCDFS4_BACK           0x2
+#define        NFSCDFS4_BOTH           0x3
+
 /* Conversion macros */
 #define        vtonfsv2_mode(t,m)                                              
\
                txdr_unsigned(((t) == VFIFO) ? MAKEIMODE(VCHR, (m)) :   \

Modified: stable/10/sys/fs/nfsserver/nfs_nfsdserv.c
==============================================================================
--- stable/10/sys/fs/nfsserver/nfs_nfsdserv.c   Sat Jul 28 20:36:23 2018        
(r336845)
+++ stable/10/sys/fs/nfsserver/nfs_nfsdserv.c   Sat Jul 28 20:38:08 2018        
(r336846)
@@ -4020,6 +4020,45 @@ nfsmout:
 }
 
 /*
+ * nfsv4 bind connection to session service
+ */
+APPLESTATIC int
+nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
+    __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
+{
+       uint32_t *tl;
+       uint8_t sessid[NFSX_V4SESSIONID];
+       int error = 0, foreaft;
+
+       if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
+               nd->nd_repstat = NFSERR_WRONGSEC;
+               goto nfsmout;
+       }
+       NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
+       NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
+       tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
+       foreaft = fxdr_unsigned(int, *tl++);
+       if (*tl == newnfs_true) {
+               /* RDMA is not supported. */
+               nd->nd_repstat = NFSERR_NOTSUPP;
+               goto nfsmout;
+       }
+
+       nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
+       if (nd->nd_repstat == 0) {
+               NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
+                   NFSX_UNSIGNED);
+               NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
+               tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
+               *tl++ = txdr_unsigned(foreaft);
+               *tl = newnfs_false;
+       }
+nfsmout:
+       NFSEXITCODE2(error, nd);
+       return (error);
+}
+
+/*
  * nfsv4 destroy session service
  */
 APPLESTATIC int

Modified: stable/10/sys/fs/nfsserver/nfs_nfsdsocket.c
==============================================================================
--- stable/10/sys/fs/nfsserver/nfs_nfsdsocket.c Sat Jul 28 20:36:23 2018        
(r336845)
+++ stable/10/sys/fs/nfsserver/nfs_nfsdsocket.c Sat Jul 28 20:38:08 2018        
(r336846)
@@ -176,7 +176,7 @@ int (*nfsrv4_ops0[NFSV41_NOPS])(struct nfsrv_descript 
        nfsrvd_write,
        nfsrvd_releaselckown,
        nfsrvd_notsupp,
-       nfsrvd_notsupp,
+       nfsrvd_bindconnsess,
        nfsrvd_exchangeid,
        nfsrvd_createsession,
        nfsrvd_destroysession,

Modified: stable/10/sys/fs/nfsserver/nfs_nfsdstate.c
==============================================================================
--- stable/10/sys/fs/nfsserver/nfs_nfsdstate.c  Sat Jul 28 20:36:23 2018        
(r336845)
+++ stable/10/sys/fs/nfsserver/nfs_nfsdstate.c  Sat Jul 28 20:38:08 2018        
(r336846)
@@ -41,6 +41,7 @@ extern struct nfsstats newnfsstats;
 extern int nfsrv_lease;
 extern struct timeval nfsboottime;
 extern u_int32_t newnfs_true, newnfs_false;
+extern int nfsd_debuglevel;
 NFSV4ROOTLOCKMUTEX;
 NFSSTATESPINLOCK;
 
@@ -633,10 +634,11 @@ nfsrv_getclient(nfsquad_t clientid, int opflags, struc
                    if (nsep != NULL) {
                        /* Hold a reference on the xprt for a backchannel. */
                        if ((nsep->sess_crflags & NFSV4CRSESS_CONNBACKCHAN)
-                           != 0 && clp->lc_req.nr_client == NULL) {
-                           clp->lc_req.nr_client = (struct __rpc_client *)
-                               clnt_bck_create(nd->nd_xprt->xp_socket,
-                               cbprogram, NFSV4_CBVERS);
+                           != 0) {
+                           if (clp->lc_req.nr_client == NULL)
+                               clp->lc_req.nr_client = (struct __rpc_client *)
+                                   clnt_bck_create(nd->nd_xprt->xp_socket,
+                                   cbprogram, NFSV4_CBVERS);
                            if (clp->lc_req.nr_client != NULL) {
                                SVC_ACQUIRE(nd->nd_xprt);
                                nd->nd_xprt->xp_p2 =
@@ -5893,9 +5895,18 @@ nfsrv_checksequence(struct nfsrv_descript *nd, uint32_
        /*
         * If this session handles the backchannel, save the nd_xprt for this
         * RPC, since this is the one being used.
+        * RFC-5661 specifies that the fore channel will be implicitly
+        * bound by a Sequence operation.  However, since some NFSv4.1 clients
+        * erroneously assumed that the back channel would be implicitly
+        * bound as well, do the implicit binding unless a
+        * BindConnectiontoSession has already been done on the session.
         */
        if (sep->sess_clp->lc_req.nr_client != NULL &&
-           (sep->sess_crflags & NFSV4CRSESS_CONNBACKCHAN) != 0) {
+           sep->sess_cbsess.nfsess_xprt != nd->nd_xprt &&
+           (sep->sess_crflags & NFSV4CRSESS_CONNBACKCHAN) != 0 &&
+           (sep->sess_clp->lc_flags & LCL_DONEBINDCONN) == 0) {
+               NFSD_DEBUG(2,
+                   "nfsrv_checksequence: implicit back channel bind\n");
                savxprt = sep->sess_cbsess.nfsess_xprt;
                SVC_ACQUIRE(nd->nd_xprt);
                nd->nd_xprt->xp_p2 =
@@ -6025,6 +6036,80 @@ nfsrv_destroysession(struct nfsrv_descript *nd, uint8_
        NFSLOCKV4ROOTMUTEX();
        nfsv4_unlock(&nfsv4rootfs_lock, 1);
        NFSUNLOCKV4ROOTMUTEX();
+       return (error);
+}
+
+/*
+ * Bind a connection to a session.
+ * For now, only certain variants are supported, since the current session
+ * structure can only handle a single backchannel entry, which will be
+ * applied to all connections if it is set.
+ */
+int
+nfsrv_bindconnsess(struct nfsrv_descript *nd, uint8_t *sessionid, int 
*foreaftp)
+{
+       struct nfssessionhash *shp;
+       struct nfsdsession *sep;
+       struct nfsclient *clp;
+       SVCXPRT *savxprt;
+       int error;
+
+       error = 0;
+       shp = NFSSESSIONHASH(sessionid);
+       NFSLOCKSTATE();
+       NFSLOCKSESSION(shp);
+       sep = nfsrv_findsession(sessionid);
+       if (sep != NULL) {
+               clp = sep->sess_clp;
+               if (*foreaftp == NFSCDFC4_BACK ||
+                   *foreaftp == NFSCDFC4_BACK_OR_BOTH ||
+                   *foreaftp == NFSCDFC4_FORE_OR_BOTH) {
+                       /* Try to set up a backchannel. */
+                       if (clp->lc_req.nr_client == NULL) {
+                               NFSD_DEBUG(2, "nfsrv_bindconnsess: acquire "
+                                   "backchannel\n");
+                               clp->lc_req.nr_client = (struct __rpc_client *)
+                                   clnt_bck_create(nd->nd_xprt->xp_socket,
+                                   sep->sess_cbprogram, NFSV4_CBVERS);
+                       }
+                       if (clp->lc_req.nr_client != NULL) {
+                               NFSD_DEBUG(2, "nfsrv_bindconnsess: set up "
+                                   "backchannel\n");
+                               savxprt = sep->sess_cbsess.nfsess_xprt;
+                               SVC_ACQUIRE(nd->nd_xprt);
+                               nd->nd_xprt->xp_p2 =
+                                   clp->lc_req.nr_client->cl_private;
+                               /* Disable idle timeout. */
+                               nd->nd_xprt->xp_idletimeout = 0;
+                               sep->sess_cbsess.nfsess_xprt = nd->nd_xprt;
+                               if (savxprt != NULL)
+                                       SVC_RELEASE(savxprt);
+                               sep->sess_crflags |= NFSV4CRSESS_CONNBACKCHAN;
+                               clp->lc_flags |= LCL_DONEBINDCONN;
+                               if (*foreaftp == NFSCDFS4_BACK)
+                                       *foreaftp = NFSCDFS4_BACK;
+                               else
+                                       *foreaftp = NFSCDFS4_BOTH;
+                       } else if (*foreaftp != NFSCDFC4_BACK) {
+                               NFSD_DEBUG(2, "nfsrv_bindconnsess: can't set "
+                                   "up backchannel\n");
+                               sep->sess_crflags &= ~NFSV4CRSESS_CONNBACKCHAN;
+                               clp->lc_flags |= LCL_DONEBINDCONN;
+                               *foreaftp = NFSCDFS4_FORE;
+                       } else {
+                               error = NFSERR_NOTSUPP;
+                               printf("nfsrv_bindconnsess: Can't add "
+                                   "backchannel\n");
+                       }
+               } else {
+                       NFSD_DEBUG(2, "nfsrv_bindconnsess: Set forechannel\n");
+                       clp->lc_flags |= LCL_DONEBINDCONN;
+                       *foreaftp = NFSCDFS4_FORE;
+               }
+       } else
+               error = NFSERR_BADSESSION;
+       NFSUNLOCKSESSION(shp);
+       NFSUNLOCKSTATE();
        return (error);
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to