Date: Fri, 1 Jun 2018 19:47:41 +0000 (UTC) From: Rick Macklem <rmacklem@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r334492 - in head/sys/fs: nfs nfsserver Message-ID: <201806011947.w51Jlf9F009761@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: rmacklem Date: Fri Jun 1 19:47:41 2018 New Revision: 334492 URL: https://svnweb.freebsd.org/changeset/base/334492 Log: 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. Reported by: andreas.nagy@frequentis.com Tested by: andreas.nagy@frequentis.com MFC after: 2 weeks Modified: head/sys/fs/nfs/nfs.h head/sys/fs/nfs/nfs_commonsubs.c head/sys/fs/nfs/nfs_var.h head/sys/fs/nfs/nfsproto.h head/sys/fs/nfsserver/nfs_nfsdserv.c head/sys/fs/nfsserver/nfs_nfsdsocket.c head/sys/fs/nfsserver/nfs_nfsdstate.c Modified: head/sys/fs/nfs/nfs.h ============================================================================== --- head/sys/fs/nfs/nfs.h Fri Jun 1 19:42:59 2018 (r334491) +++ head/sys/fs/nfs/nfs.h Fri Jun 1 19:47:41 2018 (r334492) @@ -301,6 +301,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: head/sys/fs/nfs/nfs_commonsubs.c ============================================================================== --- head/sys/fs/nfs/nfs_commonsubs.c Fri Jun 1 19:42:59 2018 (r334491) +++ head/sys/fs/nfs/nfs_commonsubs.c Fri Jun 1 19:47:41 2018 (r334492) @@ -138,7 +138,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: head/sys/fs/nfs/nfs_var.h ============================================================================== --- head/sys/fs/nfs/nfs_var.h Fri Jun 1 19:42:59 2018 (r334491) +++ head/sys/fs/nfs/nfs_var.h Fri Jun 1 19:47:41 2018 (r334492) @@ -97,6 +97,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 *); @@ -232,6 +233,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: head/sys/fs/nfs/nfsproto.h ============================================================================== --- head/sys/fs/nfs/nfsproto.h Fri Jun 1 19:42:59 2018 (r334491) +++ head/sys/fs/nfs/nfsproto.h Fri Jun 1 19:47:41 2018 (r334492) @@ -659,6 +659,15 @@ #define NFSFLEXFLAG_NO_READIO 0x00000004 #define NFSFLEXFLAG_WRITE_ONEMIRROR 0x00000008 +/* 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: head/sys/fs/nfsserver/nfs_nfsdserv.c ============================================================================== --- head/sys/fs/nfsserver/nfs_nfsdserv.c Fri Jun 1 19:42:59 2018 (r334491) +++ head/sys/fs/nfsserver/nfs_nfsdserv.c Fri Jun 1 19:47:41 2018 (r334492) @@ -4055,6 +4055,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: head/sys/fs/nfsserver/nfs_nfsdsocket.c ============================================================================== --- head/sys/fs/nfsserver/nfs_nfsdsocket.c Fri Jun 1 19:42:59 2018 (r334491) +++ head/sys/fs/nfsserver/nfs_nfsdsocket.c Fri Jun 1 19:47:41 2018 (r334492) @@ -178,7 +178,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: head/sys/fs/nfsserver/nfs_nfsdstate.c ============================================================================== --- head/sys/fs/nfsserver/nfs_nfsdstate.c Fri Jun 1 19:42:59 2018 (r334491) +++ head/sys/fs/nfsserver/nfs_nfsdstate.c Fri Jun 1 19:47:41 2018 (r334492) @@ -43,6 +43,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; @@ -630,10 +631,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 = @@ -5900,9 +5902,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 = @@ -6032,6 +6043,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); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201806011947.w51Jlf9F009761>