svn commit: r336842 - in stable/11/sys/fs: nfs nfsserver
Rick Macklem
rmacklem at FreeBSD.org
Sat Jul 28 20:29:07 UTC 2018
Author: rmacklem
Date: Sat Jul 28 20:29:05 2018
New Revision: 336842
URL: https://svnweb.freebsd.org/changeset/base/336842
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/11/sys/fs/nfs/nfs.h
stable/11/sys/fs/nfs/nfs_commonsubs.c
stable/11/sys/fs/nfs/nfs_var.h
stable/11/sys/fs/nfs/nfsproto.h
stable/11/sys/fs/nfsserver/nfs_nfsdserv.c
stable/11/sys/fs/nfsserver/nfs_nfsdsocket.c
stable/11/sys/fs/nfsserver/nfs_nfsdstate.c
Directory Properties:
stable/11/ (props changed)
Modified: stable/11/sys/fs/nfs/nfs.h
==============================================================================
--- stable/11/sys/fs/nfs/nfs.h Sat Jul 28 20:26:25 2018 (r336841)
+++ stable/11/sys/fs/nfs/nfs.h Sat Jul 28 20:29:05 2018 (r336842)
@@ -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/11/sys/fs/nfs/nfs_commonsubs.c
==============================================================================
--- stable/11/sys/fs/nfs/nfs_commonsubs.c Sat Jul 28 20:26:25 2018 (r336841)
+++ stable/11/sys/fs/nfs/nfs_commonsubs.c Sat Jul 28 20:29:05 2018 (r336842)
@@ -139,7 +139,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/11/sys/fs/nfs/nfs_var.h
==============================================================================
--- stable/11/sys/fs/nfs/nfs_var.h Sat Jul 28 20:26:25 2018 (r336841)
+++ stable/11/sys/fs/nfs/nfs_var.h Sat Jul 28 20:29:05 2018 (r336842)
@@ -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/11/sys/fs/nfs/nfsproto.h
==============================================================================
--- stable/11/sys/fs/nfs/nfsproto.h Sat Jul 28 20:26:25 2018 (r336841)
+++ stable/11/sys/fs/nfs/nfsproto.h Sat Jul 28 20:29:05 2018 (r336842)
@@ -650,6 +650,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/11/sys/fs/nfsserver/nfs_nfsdserv.c
==============================================================================
--- stable/11/sys/fs/nfsserver/nfs_nfsdserv.c Sat Jul 28 20:26:25 2018 (r336841)
+++ stable/11/sys/fs/nfsserver/nfs_nfsdserv.c Sat Jul 28 20:29:05 2018 (r336842)
@@ -4051,6 +4051,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/11/sys/fs/nfsserver/nfs_nfsdsocket.c
==============================================================================
--- stable/11/sys/fs/nfsserver/nfs_nfsdsocket.c Sat Jul 28 20:26:25 2018 (r336841)
+++ stable/11/sys/fs/nfsserver/nfs_nfsdsocket.c Sat Jul 28 20:29:05 2018 (r336842)
@@ -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/11/sys/fs/nfsserver/nfs_nfsdstate.c
==============================================================================
--- stable/11/sys/fs/nfsserver/nfs_nfsdstate.c Sat Jul 28 20:26:25 2018 (r336841)
+++ stable/11/sys/fs/nfsserver/nfs_nfsdstate.c Sat Jul 28 20:29:05 2018 (r336842)
@@ -41,6 +41,7 @@ extern struct nfsstatsv1 nfsstatsv1;
extern int nfsrv_lease;
extern struct timeval nfsboottime;
extern u_int32_t newnfs_true, newnfs_false;
+extern int nfsd_debuglevel;
NFSV4ROOTLOCKMUTEX;
NFSSTATESPINLOCK;
@@ -628,10 +629,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 =
@@ -5901,9 +5903,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 =
@@ -6033,6 +6044,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);
}
More information about the svn-src-all
mailing list