Modify the NFSv4.1 server so that it allows ReclaimComplete as done by ESXi 6.7.
I believe that a ReclaimComplete with rca_one_fs == TRUE is only to be used after a file system has been transferred to a different file server. However, RFC5661 is somewhat vague w.r.t. this and the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs == TRUE and one with ReclaimComplete with rca_one_fs == FALSE. Therefore, just ignore the rca_one_fs == TRUE operation and return NFS_OK without doing anything instead of replying NFS4ERR_NOTSUPP. This allows the ESXi 6.7 NFSv4.1 client to do a mount. After discussion on the NFSv4 IETF working group mailing list, doing this along with setting a flag to note that a ReclaimComplete with rca_one_fs TRUE was an appropriate way to handle this. The flag that indicates that a ReclaimComplete with rca_one_fs == TRUE was done may be used to disable replies of NFS4ERR_GRACE for non-reclaim state operations in a future commit. This patch along with r332790, r334492 and r336357 allow ESXi 6.7 NFSv4.1 mounts work ok. ESX 6.5 NFSv4.1 mounts do not work well, due to what I believe are violations of RFC-5661 and should not be used. Reported by: andreas.nagy@frequentis.com Tested by: andreas.nagy@frequentis.com, daniel@ftml.net (earlier version) MFC after: 2 weeks Relnotes: yes
This commit is contained in:
parent
80d3469a3f
commit
a3e709cd33
@ -329,6 +329,7 @@ struct nfsreferral {
|
||||
#define LCL_RECLAIMCOMPLETE 0x00010000
|
||||
#define LCL_NFSV41 0x00020000
|
||||
#define LCL_DONEBINDCONN 0x00040000
|
||||
#define LCL_RECLAIMONEFS 0x00080000
|
||||
|
||||
#define LCL_GSS LCL_KERBV /* Or of all mechs */
|
||||
|
||||
|
@ -141,7 +141,7 @@ void nfsrv_nfsuserddelport(void);
|
||||
void nfsrv_throwawayallstate(NFSPROC_T *);
|
||||
int nfsrv_checksequence(struct nfsrv_descript *, uint32_t, uint32_t *,
|
||||
uint32_t *, int, uint32_t *, NFSPROC_T *);
|
||||
int nfsrv_checkreclaimcomplete(struct nfsrv_descript *);
|
||||
int nfsrv_checkreclaimcomplete(struct nfsrv_descript *, int);
|
||||
void nfsrv_cache_session(uint8_t *, uint32_t, int, struct mbuf **);
|
||||
void nfsrv_freeallbackchannel_xprts(void);
|
||||
int nfsrv_layoutcommit(struct nfsrv_descript *, vnode_t, int, int, uint64_t,
|
||||
|
@ -4229,17 +4229,26 @@ nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
|
||||
__unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
|
||||
{
|
||||
uint32_t *tl;
|
||||
int error = 0;
|
||||
int error = 0, onefs;
|
||||
|
||||
if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
|
||||
nd->nd_repstat = NFSERR_WRONGSEC;
|
||||
goto nfsmout;
|
||||
}
|
||||
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
|
||||
/*
|
||||
* I believe that a ReclaimComplete with rca_one_fs == TRUE is only
|
||||
* to be used after a file system has been transferred to a different
|
||||
* file server. However, RFC5661 is somewhat vague w.r.t. this and
|
||||
* the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
|
||||
* == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
|
||||
* Therefore, just ignore the rca_one_fs == TRUE operation and return
|
||||
* NFS_OK without doing anything.
|
||||
*/
|
||||
onefs = 0;
|
||||
if (*tl == newnfs_true)
|
||||
nd->nd_repstat = NFSERR_NOTSUPP;
|
||||
else
|
||||
nd->nd_repstat = nfsrv_checkreclaimcomplete(nd);
|
||||
onefs = 1;
|
||||
nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
|
||||
nfsmout:
|
||||
NFSEXITCODE2(error, nd);
|
||||
return (error);
|
||||
|
@ -6064,7 +6064,7 @@ nfsrv_checksequence(struct nfsrv_descript *nd, uint32_t sequenceid,
|
||||
* Check/set reclaim complete for this session/clientid.
|
||||
*/
|
||||
int
|
||||
nfsrv_checkreclaimcomplete(struct nfsrv_descript *nd)
|
||||
nfsrv_checkreclaimcomplete(struct nfsrv_descript *nd, int onefs)
|
||||
{
|
||||
struct nfsdsession *sep;
|
||||
struct nfssessionhash *shp;
|
||||
@ -6080,8 +6080,10 @@ nfsrv_checkreclaimcomplete(struct nfsrv_descript *nd)
|
||||
return (NFSERR_BADSESSION);
|
||||
}
|
||||
|
||||
/* Check to see if reclaim complete has already happened. */
|
||||
if ((sep->sess_clp->lc_flags & LCL_RECLAIMCOMPLETE) != 0)
|
||||
if (onefs != 0)
|
||||
sep->sess_clp->lc_flags |= LCL_RECLAIMONEFS;
|
||||
/* Check to see if reclaim complete has already happened. */
|
||||
else if ((sep->sess_clp->lc_flags & LCL_RECLAIMCOMPLETE) != 0)
|
||||
error = NFSERR_COMPLETEALREADY;
|
||||
else {
|
||||
sep->sess_clp->lc_flags |= LCL_RECLAIMCOMPLETE;
|
||||
|
Loading…
Reference in New Issue
Block a user