Merge the NFSv4.1 server code in projects/nfsv4.1-server over

into head. The code is not believed to have any effect
on the semantics of non-NFSv4.1 server behaviour.
It is a rather large merge, but I am hoping that there will
not be any regressions for the NFS server.

MFC after:	1 month
This commit is contained in:
Rick Macklem 2014-07-01 20:47:16 +00:00
parent 4fc0f18c20
commit c59e4cc34d
24 changed files with 2717 additions and 356 deletions

View File

@ -3810,6 +3810,7 @@ pci/viapm.c optional viapm pci
rpc/auth_none.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
rpc/auth_unix.c optional krpc | nfslockd | nfsclient | nfscl | nfsd
rpc/authunix_prot.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd
rpc/clnt_bck.c optional krpc | nfslockd | nfsserver | nfscl | nfsd
rpc/clnt_dg.c optional krpc | nfslockd | nfsclient | nfscl | nfsd
rpc/clnt_rc.c optional krpc | nfslockd | nfsclient | nfscl | nfsd
rpc/clnt_vc.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd

View File

@ -50,7 +50,8 @@
#define NFS_MAXREXMIT 100 /* Stop counting after this many */
#define NFSV4_CALLBACKTIMEO (2 * NFS_HZ) /* Timeout in ticks */
#define NFSV4_CALLBACKRETRY 5 /* Number of retries before failure */
#define NFSV4_CBSLOTS 8 /* Number of slots for session */
#define NFSV4_SLOTS 64 /* Number of slots, fore channel */
#define NFSV4_CBSLOTS 8 /* Number of slots, back channel */
#define NFSV4_CBRETRYCNT 4 /* # of CBRecall retries upon err */
#define NFSV4_UPCALLTIMEO (15 * NFS_HZ) /* Timeout in ticks for upcalls */
/* to gssd or nfsuserd */
@ -91,6 +92,9 @@
#ifndef NFSLOCKHASHSIZE
#define NFSLOCKHASHSIZE 20 /* Size of server nfslock hash table */
#endif
#ifndef NFSSESSIONHASHSIZE
#define NFSSESSIONHASHSIZE 20 /* Size of server session hash table */
#endif
#define NFSSTATEHASHSIZE 10 /* Size of server stateid hash table */
#ifndef NFSUSERHASHSIZE
#define NFSUSERHASHSIZE 30 /* Size of user id hash table */
@ -276,6 +280,8 @@ struct nfsreferral {
#define LCL_GSSINTEGRITY 0x00002000
#define LCL_GSSPRIVACY 0x00004000
#define LCL_ADMINREVOKED 0x00008000
#define LCL_RECLAIMCOMPLETE 0x00010000
#define LCL_NFSV41 0x00020000
#define LCL_GSS LCL_KERBV /* Or of all mechs */
@ -318,6 +324,11 @@ struct nfsreferral {
#define NFSLCK_SETATTR 0x02000000
#define NFSLCK_DELEGPURGE 0x04000000
#define NFSLCK_DELEGRETURN 0x08000000
#define NFSLCK_WANTWDELEG 0x10000000
#define NFSLCK_WANTRDELEG 0x20000000
#define NFSLCK_WANTNODELEG 0x40000000
#define NFSLCK_WANTBITS \
(NFSLCK_WANTWDELEG | NFSLCK_WANTRDELEG | NFSLCK_WANTNODELEG)
/* And bits for nid_flag */
#define NFSID_INITIALIZE 0x0001
@ -341,68 +352,120 @@ struct nfsreferral {
* THE MACROS MUST BE MANUALLY MODIFIED IF NFSATTRBIT_MAXWORDS CHANGES!!
* It is (NFSATTRBIT_MAX + 31) / 32.
*/
#define NFSATTRBIT_MAXWORDS 2
#define NFSATTRBIT_MAXWORDS 3
typedef struct {
u_int32_t bits[NFSATTRBIT_MAXWORDS];
} nfsattrbit_t;
#define NFSZERO_ATTRBIT(b) do { (b)->bits[0] = 0; (b)->bits[1] = 0; } while (0)
#define NFSSET_ATTRBIT(t, f) do { (t)->bits[0] = (f)->bits[0]; \
(t)->bits[1] = (f)->bits[1]; } while (0)
#define NFSZERO_ATTRBIT(b) do { \
(b)->bits[0] = 0; \
(b)->bits[1] = 0; \
(b)->bits[2] = 0; \
} while (0)
#define NFSSET_ATTRBIT(t, f) do { \
(t)->bits[0] = (f)->bits[0]; \
(t)->bits[1] = (f)->bits[1]; \
(t)->bits[2] = (f)->bits[2]; \
} while (0)
#define NFSSETSUPP_ATTRBIT(b) do { \
(b)->bits[0] = NFSATTRBIT_SUPP0; \
(b)->bits[1] = (NFSATTRBIT_SUPP1 | NFSATTRBIT_SUPPSETONLY); } while (0)
(b)->bits[1] = (NFSATTRBIT_SUPP1 | NFSATTRBIT_SUPPSETONLY); \
(b)->bits[2] = NFSATTRBIT_SUPP2; \
} while (0)
#define NFSISSET_ATTRBIT(b, p) ((b)->bits[(p) / 32] & (1 << ((p) % 32)))
#define NFSSETBIT_ATTRBIT(b, p) ((b)->bits[(p) / 32] |= (1 << ((p) % 32)))
#define NFSCLRBIT_ATTRBIT(b, p) ((b)->bits[(p) / 32] &= ~(1 << ((p) % 32)))
#define NFSCLRALL_ATTRBIT(b, a) do { \
(b)->bits[0] &= ~((a)->bits[0]); \
(b)->bits[1] &= ~((a)->bits[1]); \
} while (0)
(b)->bits[0] &= ~((a)->bits[0]); \
(b)->bits[1] &= ~((a)->bits[1]); \
(b)->bits[2] &= ~((a)->bits[2]); \
} while (0)
#define NFSCLRNOT_ATTRBIT(b, a) do { \
(b)->bits[0] &= ((a)->bits[0]); \
(b)->bits[1] &= ((a)->bits[1]); \
} while (0)
(b)->bits[0] &= ((a)->bits[0]); \
(b)->bits[1] &= ((a)->bits[1]); \
(b)->bits[2] &= ((a)->bits[2]); \
} while (0)
#define NFSCLRNOTFILLABLE_ATTRBIT(b) do { \
(b)->bits[0] &= NFSATTRBIT_SUPP0; \
(b)->bits[1] &= NFSATTRBIT_SUPP1; } while (0)
(b)->bits[0] &= NFSATTRBIT_SUPP0; \
(b)->bits[1] &= NFSATTRBIT_SUPP1; \
(b)->bits[2] &= NFSATTRBIT_SUPP2; \
} while (0)
#define NFSCLRNOTSETABLE_ATTRBIT(b) do { \
(b)->bits[0] &= NFSATTRBIT_SETABLE0; \
(b)->bits[1] &= NFSATTRBIT_SETABLE1; } while (0)
#define NFSNONZERO_ATTRBIT(b) ((b)->bits[0] || (b)->bits[1])
#define NFSEQUAL_ATTRBIT(b, p) \
((b)->bits[0] == (p)->bits[0] && (b)->bits[1] == (p)->bits[1])
(b)->bits[0] &= NFSATTRBIT_SETABLE0; \
(b)->bits[1] &= NFSATTRBIT_SETABLE1; \
(b)->bits[2] &= NFSATTRBIT_SETABLE2; \
} while (0)
#define NFSNONZERO_ATTRBIT(b) ((b)->bits[0] || (b)->bits[1] || (b)->bits[2])
#define NFSEQUAL_ATTRBIT(b, p) ((b)->bits[0] == (p)->bits[0] && \
(b)->bits[1] == (p)->bits[1] && (b)->bits[2] == (p)->bits[2])
#define NFSGETATTR_ATTRBIT(b) do { \
(b)->bits[0] = NFSATTRBIT_GETATTR0; \
(b)->bits[1] = NFSATTRBIT_GETATTR1; } while (0)
(b)->bits[0] = NFSATTRBIT_GETATTR0; \
(b)->bits[1] = NFSATTRBIT_GETATTR1; \
(b)->bits[2] = NFSATTRBIT_GETATTR2; \
} while (0)
#define NFSWCCATTR_ATTRBIT(b) do { \
(b)->bits[0] = NFSATTRBIT_WCCATTR0; \
(b)->bits[1] = NFSATTRBIT_WCCATTR1; } while (0)
(b)->bits[0] = NFSATTRBIT_WCCATTR0; \
(b)->bits[1] = NFSATTRBIT_WCCATTR1; \
(b)->bits[2] = NFSATTRBIT_WCCATTR2; \
} while (0)
#define NFSWRITEGETATTR_ATTRBIT(b) do { \
(b)->bits[0] = NFSATTRBIT_WRITEGETATTR0; \
(b)->bits[1] = NFSATTRBIT_WRITEGETATTR1; } while (0)
(b)->bits[0] = NFSATTRBIT_WRITEGETATTR0; \
(b)->bits[1] = NFSATTRBIT_WRITEGETATTR1; \
(b)->bits[2] = NFSATTRBIT_WRITEGETATTR2; \
} while (0)
#define NFSCBGETATTR_ATTRBIT(b, c) do { \
(c)->bits[0] = ((b)->bits[0] & NFSATTRBIT_CBGETATTR0); \
(c)->bits[1] = ((b)->bits[1] & NFSATTRBIT_CBGETATTR1); } while (0)
(c)->bits[0] = ((b)->bits[0] & NFSATTRBIT_CBGETATTR0); \
(c)->bits[1] = ((b)->bits[1] & NFSATTRBIT_CBGETATTR1); \
(c)->bits[2] = ((b)->bits[2] & NFSATTRBIT_CBGETATTR2); \
} while (0)
#define NFSPATHCONF_GETATTRBIT(b) do { \
(b)->bits[0] = NFSGETATTRBIT_PATHCONF0; \
(b)->bits[1] = NFSGETATTRBIT_PATHCONF1; } while (0)
(b)->bits[0] = NFSGETATTRBIT_PATHCONF0; \
(b)->bits[1] = NFSGETATTRBIT_PATHCONF1; \
(b)->bits[2] = NFSGETATTRBIT_PATHCONF2; \
} while (0)
#define NFSSTATFS_GETATTRBIT(b) do { \
(b)->bits[0] = NFSGETATTRBIT_STATFS0; \
(b)->bits[1] = NFSGETATTRBIT_STATFS1; } while (0)
(b)->bits[0] = NFSGETATTRBIT_STATFS0; \
(b)->bits[1] = NFSGETATTRBIT_STATFS1; \
(b)->bits[2] = NFSGETATTRBIT_STATFS2; \
} while (0)
#define NFSISSETSTATFS_ATTRBIT(b) \
(((b)->bits[0] & NFSATTRBIT_STATFS0) || \
((b)->bits[1] & NFSATTRBIT_STATFS1))
((b)->bits[1] & NFSATTRBIT_STATFS1) || \
((b)->bits[2] & NFSATTRBIT_STATFS2))
#define NFSCLRSTATFS_ATTRBIT(b) do { \
(b)->bits[0] &= ~NFSATTRBIT_STATFS0; \
(b)->bits[1] &= ~NFSATTRBIT_STATFS1; } while (0)
(b)->bits[0] &= ~NFSATTRBIT_STATFS0; \
(b)->bits[1] &= ~NFSATTRBIT_STATFS1; \
(b)->bits[2] &= ~NFSATTRBIT_STATFS2; \
} while (0)
#define NFSREADDIRPLUS_ATTRBIT(b) do { \
(b)->bits[0] = NFSATTRBIT_READDIRPLUS0; \
(b)->bits[1] = NFSATTRBIT_READDIRPLUS1; } while (0)
(b)->bits[0] = NFSATTRBIT_READDIRPLUS0; \
(b)->bits[1] = NFSATTRBIT_READDIRPLUS1; \
(b)->bits[2] = NFSATTRBIT_READDIRPLUS2; \
} while (0)
#define NFSREFERRAL_ATTRBIT(b) do { \
(b)->bits[0] = NFSATTRBIT_REFERRAL0; \
(b)->bits[1] = NFSATTRBIT_REFERRAL1; } while (0)
(b)->bits[0] = NFSATTRBIT_REFERRAL0; \
(b)->bits[1] = NFSATTRBIT_REFERRAL1; \
(b)->bits[2] = NFSATTRBIT_REFERRAL2; \
} while (0)
/*
* Store uid, gid creds that were used when the stateid was acquired.
@ -529,6 +592,9 @@ struct nfsrv_descript {
int nd_gssnamelen; /* principal name length */
char *nd_gssname; /* principal name */
uint32_t *nd_slotseq; /* ptr to slot seq# in req */
uint8_t nd_sessionid[NFSX_V4SESSIONID]; /* Session id */
uint32_t nd_slotid; /* Slotid for this RPC */
SVCXPRT *nd_xprt; /* Server RPC handle */
};
#define nd_princlen nd_gssnamelen
@ -562,6 +628,8 @@ struct nfsrv_descript {
#define ND_NFSCL 0x01000000
#define ND_NFSV41 0x02000000
#define ND_HASSEQUENCE 0x04000000
#define ND_CACHETHIS 0x08000000
#define ND_LASTOP 0x10000000
/*
* ND_GSS should be the "or" of all GSS type authentications.

View File

@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
#include <sys/vnode.h>
#include <rpc/rpc.h>
#include <rpc/krpc.h>
#include <kgssapi/krb5/kcrypto.h>
@ -738,8 +739,12 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp,
}
nd->nd_mrep = NULL;
stat = CLNT_CALL_MBUF(nrp->nr_client, &ext, procnum, nd->nd_mreq,
&nd->nd_mrep, timo);
if (clp != NULL && sep != NULL)
stat = clnt_bck_call(nrp->nr_client, &ext, procnum,
nd->nd_mreq, &nd->nd_mrep, timo, sep->nfsess_xprt);
else
stat = CLNT_CALL_MBUF(nrp->nr_client, &ext, procnum,
nd->nd_mreq, &nd->nd_mrep, timo);
if (rep != NULL) {
/*
@ -794,7 +799,8 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp,
nd->nd_md = nd->nd_mrep;
nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
nd->nd_repstat = 0;
if (nd->nd_procnum != NFSPROC_NULL) {
if (nd->nd_procnum != NFSPROC_NULL &&
nd->nd_procnum != NFSV4PROC_CBNULL) {
/* If sep == NULL, set it to the default in nmp. */
if (sep == NULL && nmp != NULL)
sep = NFSMNT_MDSSESSION(nmp);
@ -826,11 +832,20 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp,
/*
* If the first op is Sequence, free up the slot.
*/
if (nmp != NULL && i == NFSV4OP_SEQUENCE && j != 0)
if ((nmp != NULL && i == NFSV4OP_SEQUENCE && j != 0) ||
(clp != NULL && i == NFSV4OP_CBSEQUENCE && j != 0))
NFSCL_DEBUG(1, "failed seq=%d\n", j);
if (nmp != NULL && i == NFSV4OP_SEQUENCE && j == 0) {
NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
5 * NFSX_UNSIGNED);
if ((nmp != NULL && i == NFSV4OP_SEQUENCE && j == 0) ||
(clp != NULL && i == NFSV4OP_CBSEQUENCE && j == 0)
) {
if (i == NFSV4OP_SEQUENCE)
NFSM_DISSECT(tl, uint32_t *,
NFSX_V4SESSIONID +
5 * NFSX_UNSIGNED);
else
NFSM_DISSECT(tl, uint32_t *,
NFSX_V4SESSIONID +
4 * NFSX_UNSIGNED);
mtx_lock(&sep->nfsess_mtx);
tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
retseq = fxdr_unsigned(uint32_t, *tl++);

View File

@ -112,6 +112,7 @@ MALLOC_DEFINE(M_NEWNFSDEVINFO, "NFSCL devinfo", "NFSv4.1 Device Info");
MALLOC_DEFINE(M_NEWNFSSOCKREQ, "NFSCL sockreq", "NFS Sock Req");
MALLOC_DEFINE(M_NEWNFSCLDS, "NFSCL session", "NFSv4.1 Session");
MALLOC_DEFINE(M_NEWNFSLAYRECALL, "NFSCL layrecall", "NFSv4.1 Layout Recall");
MALLOC_DEFINE(M_NEWNFSDSESSION, "NFSD session", "NFSD Session for a client");
/*
* Definition of mutex locks.

View File

@ -1733,6 +1733,23 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
}
attrsum += NFSX_HYPER;
break;
case NFSATTRBIT_SUPPATTREXCLCREAT:
retnotsup = 0;
error = nfsrv_getattrbits(nd, &retattrbits,
&cnt, &retnotsup);
if (error)
goto nfsmout;
if (compare && !(*retcmpp)) {
NFSSETSUPP_ATTRBIT(&checkattrbits);
NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
NFSCLRBIT_ATTRBIT(&checkattrbits,
NFSATTRBIT_TIMEACCESSSET);
if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
|| retnotsup)
*retcmpp = NFSERR_NOTSAME;
}
attrsum += cnt;
break;
default:
printf("EEK! nfsv4_loadattr unknown attr=%d\n",
bitpos);
@ -2469,6 +2486,12 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
txdr_hyper(uquad, tl);
retnum += NFSX_HYPER;
break;
case NFSATTRBIT_SUPPATTREXCLCREAT:
NFSSETSUPP_ATTRBIT(&attrbits);
NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
retnum += nfsrv_putattrbit(nd, &attrbits);
break;
default:
printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
};
@ -3663,6 +3686,9 @@ nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
/*
* Handle an NFSv4.1 Sequence request for the session.
* If reply != NULL, use it to return the cached reply, as required.
* The client gets a cached reply via this call for callbacks, however the
* server gets a cached reply via the nfsv4_seqsess_cachereply() call.
*/
int
nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
@ -3671,7 +3697,8 @@ nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
int error;
error = 0;
*reply = NULL;
if (reply != NULL)
*reply = NULL;
if (slotid > maxslot)
return (NFSERR_BADSLOT);
if (seqid == slots[slotid].nfssl_seq) {
@ -3679,13 +3706,18 @@ nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
if (slots[slotid].nfssl_inprog != 0)
error = NFSERR_DELAY;
else if (slots[slotid].nfssl_reply != NULL) {
*reply = slots[slotid].nfssl_reply;
slots[slotid].nfssl_reply = NULL;
if (reply != NULL) {
*reply = slots[slotid].nfssl_reply;
slots[slotid].nfssl_reply = NULL;
}
slots[slotid].nfssl_inprog = 1;
error = NFSERR_REPLYFROMCACHE;
} else
error = NFSERR_SEQMISORDERED;
/* No reply cached, so just do it. */
slots[slotid].nfssl_inprog = 1;
} else if ((slots[slotid].nfssl_seq + 1) == seqid) {
m_freem(slots[slotid].nfssl_reply);
if (slots[slotid].nfssl_reply != NULL)
m_freem(slots[slotid].nfssl_reply);
slots[slotid].nfssl_reply = NULL;
slots[slotid].nfssl_inprog = 1;
slots[slotid].nfssl_seq++;
@ -3696,12 +3728,22 @@ nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
/*
* Cache this reply for the slot.
* Use the "rep" argument to return the cached reply if repstat is set to
* NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
*/
void
nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, struct mbuf *rep)
nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
struct mbuf **rep)
{
slots[slotid].nfssl_reply = rep;
if (repstat == NFSERR_REPLYFROMCACHE) {
*rep = slots[slotid].nfssl_reply;
slots[slotid].nfssl_reply = NULL;
} else {
if (slots[slotid].nfssl_reply != NULL)
m_freem(slots[slotid].nfssl_reply);
slots[slotid].nfssl_reply = *rep;
}
slots[slotid].nfssl_inprog = 0;
}
@ -3713,51 +3755,13 @@ nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
struct nfsclsession *sep, int dont_replycache)
{
uint32_t *tl, slotseq = 0;
int i, maxslot, slotpos;
uint64_t bitval;
int error, maxslot, slotpos;
uint8_t sessionid[NFSX_V4SESSIONID];
/* Find an unused slot. */
slotpos = -1;
maxslot = -1;
mtx_lock(&sep->nfsess_mtx);
do {
bitval = 1;
for (i = 0; i < sep->nfsess_foreslots; i++) {
if ((bitval & sep->nfsess_slots) == 0) {
slotpos = i;
sep->nfsess_slots |= bitval;
sep->nfsess_slotseq[i]++;
slotseq = sep->nfsess_slotseq[i];
break;
}
bitval <<= 1;
}
if (slotpos == -1) {
/*
* If a forced dismount is in progress, just return.
* This RPC attempt will fail when it calls
* newnfs_request().
*/
if ((nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
!= 0) {
mtx_unlock(&sep->nfsess_mtx);
return;
}
/* Wake up once/sec, to check for a forced dismount. */
(void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
PZERO, "nfsclseq", hz);
}
} while (slotpos == -1);
/* Now, find the highest slot in use. (nfsc_slots is 64bits) */
bitval = 1;
for (i = 0; i < 64; i++) {
if ((bitval & sep->nfsess_slots) != 0)
maxslot = i;
bitval <<= 1;
}
bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
mtx_unlock(&sep->nfsess_mtx);
error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
sessionid);
if (error != 0)
return;
KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
/* Build the Sequence arguments. */
@ -3775,6 +3779,60 @@ nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
nd->nd_flag |= ND_HASSEQUENCE;
}
int
nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
{
int i, maxslot, slotpos;
uint64_t bitval;
/* Find an unused slot. */
slotpos = -1;
maxslot = -1;
mtx_lock(&sep->nfsess_mtx);
do {
bitval = 1;
for (i = 0; i < sep->nfsess_foreslots; i++) {
if ((bitval & sep->nfsess_slots) == 0) {
slotpos = i;
sep->nfsess_slots |= bitval;
sep->nfsess_slotseq[i]++;
*slotseqp = sep->nfsess_slotseq[i];
break;
}
bitval <<= 1;
}
if (slotpos == -1) {
/*
* If a forced dismount is in progress, just return.
* This RPC attempt will fail when it calls
* newnfs_request().
*/
if (nmp != NULL &&
(nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
!= 0) {
mtx_unlock(&sep->nfsess_mtx);
return (ESTALE);
}
/* Wake up once/sec, to check for a forced dismount. */
(void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
PZERO, "nfsclseq", hz);
}
} while (slotpos == -1);
/* Now, find the highest slot in use. (nfsc_slots is 64bits) */
bitval = 1;
for (i = 0; i < 64; i++) {
if ((bitval & sep->nfsess_slots) != 0)
maxslot = i;
bitval <<= 1;
}
bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
mtx_unlock(&sep->nfsess_mtx);
*slotposp = slotpos;
*maxslotp = maxslot;
return (0);
}
/*
* Free a session slot.
*/

View File

@ -61,6 +61,7 @@ union nethostaddr;
struct nfsstate;
struct nfslock;
struct nfsclient;
struct nfsdsession;
struct nfslockconflict;
struct nfsd_idargs;
struct nfsd_clid;
@ -90,8 +91,11 @@ NFS_READDIR_ARGS;
/* nfs_nfsdstate.c */
int nfsrv_setclient(struct nfsrv_descript *, struct nfsclient **,
nfsquad_t *, nfsquad_t *, NFSPROC_T *);
int nfsrv_getclient(nfsquad_t, int, struct nfsclient **, nfsquad_t,
struct nfsrv_descript *, NFSPROC_T *);
int nfsrv_getclient(nfsquad_t, int, struct nfsclient **, struct nfsdsession *,
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_freestateid(struct nfsrv_descript *, nfsv4stateid_t *, NFSPROC_T *);
int nfsrv_adminrevoke(struct nfsd_clid *, NFSPROC_T *);
void nfsrv_dumpclients(struct nfsd_dumpclients *, int);
void nfsrv_dumplocks(vnode_t, struct nfsd_dumplocks *, int, NFSPROC_T *);
@ -105,8 +109,8 @@ int nfsrv_opencheck(nfsquad_t, nfsv4stateid_t *, struct nfsstate *,
vnode_t, struct nfsrv_descript *, NFSPROC_T *, int);
int nfsrv_openupdate(vnode_t, struct nfsstate *, nfsquad_t,
nfsv4stateid_t *, struct nfsrv_descript *, NFSPROC_T *);
int nfsrv_delegupdate(nfsquad_t, nfsv4stateid_t *, vnode_t, int,
struct ucred *, NFSPROC_T *);
int nfsrv_delegupdate(struct nfsrv_descript *, nfsquad_t, nfsv4stateid_t *,
vnode_t, int, struct ucred *, NFSPROC_T *);
int nfsrv_releaselckown(struct nfsstate *, nfsquad_t, NFSPROC_T *);
void nfsrv_zapclient(struct nfsclient *, NFSPROC_T *);
int nfssvc_idname(struct nfsd_idargs *);
@ -127,6 +131,10 @@ int nfsrv_checkgetattr(struct nfsrv_descript *, vnode_t,
int nfsrv_nfsuserdport(u_short, NFSPROC_T *);
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 *);
void nfsrv_cache_session(uint8_t *, uint32_t, int, struct mbuf **);
/* nfs_nfsdserv.c */
int nfsrvd_access(struct nfsrv_descript *, int,
@ -211,10 +219,27 @@ int nfsrvd_releaselckown(struct nfsrv_descript *, int,
vnode_t, NFSPROC_T *, struct nfsexstuff *);
int nfsrvd_pathconf(struct nfsrv_descript *, int,
vnode_t, NFSPROC_T *, struct nfsexstuff *);
int nfsrvd_exchangeid(struct nfsrv_descript *, int,
vnode_t, NFSPROC_T *, struct nfsexstuff *);
int nfsrvd_createsession(struct nfsrv_descript *, int,
vnode_t, NFSPROC_T *, struct nfsexstuff *);
int nfsrvd_sequence(struct nfsrv_descript *, int,
vnode_t, NFSPROC_T *, struct nfsexstuff *);
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_destroysession(struct nfsrv_descript *, int,
vnode_t, NFSPROC_T *, struct nfsexstuff *);
int nfsrvd_freestateid(struct nfsrv_descript *, int,
vnode_t, NFSPROC_T *, struct nfsexstuff *);
int nfsrvd_notsupp(struct nfsrv_descript *, int,
vnode_t, NFSPROC_T *, struct nfsexstuff *);
/* nfs_nfsdsocket.c */
void nfsrvd_rephead(struct nfsrv_descript *);
void nfsrvd_dorpc(struct nfsrv_descript *, int, NFSPROC_T *);
void nfsrvd_dorpc(struct nfsrv_descript *, int, u_char *, int, u_int32_t,
NFSPROC_T *);
/* nfs_nfsdcache.c */
void nfsrvd_initcache(void);
@ -264,9 +289,11 @@ int nfsv4_getipaddr(struct nfsrv_descript *, struct sockaddr_storage *,
int *);
int nfsv4_seqsession(uint32_t, uint32_t, uint32_t, struct nfsslot *,
struct mbuf **, uint16_t);
void nfsv4_seqsess_cacherep(uint32_t, struct nfsslot *, struct mbuf *);
void nfsv4_seqsess_cacherep(uint32_t, struct nfsslot *, int, struct mbuf **);
void nfsv4_setsequence(struct nfsmount *, struct nfsrv_descript *,
struct nfsclsession *, int);
int nfsv4_sequencelookup(struct nfsmount *, struct nfsclsession *, int *,
int *, uint32_t *, uint8_t *);
void nfsv4_freeslot(struct nfsclsession *, int);
/* nfs_clcomsubs.c */
@ -322,6 +349,8 @@ int nfsrv_parsename(struct nfsrv_descript *, char *, u_long *,
NFSPATHLEN_T *);
void nfsd_init(void);
int nfsd_checkrootexp(struct nfsrv_descript *);
void nfsd_getminorvers(struct nfsrv_descript *, u_char *, u_char **, int *,
u_int32_t *);
/* nfs_clvfsops.c */
void nfscl_retopts(struct nfsmount *, char *, size_t);
@ -628,6 +657,7 @@ int nfsvno_advlock(vnode_t, int, u_int64_t, u_int64_t, NFSPROC_T *);
int nfsrv_v4rootexport(void *, struct ucred *, NFSPROC_T *);
int nfsvno_testexp(struct nfsrv_descript *, struct nfsexstuff *);
uint32_t nfsrv_hashfh(fhandle_t *);
uint32_t nfsrv_hashsessionid(uint8_t *);
void nfsrv_backupstable(void);
/* nfs_commonkrpc.c */

View File

@ -57,6 +57,7 @@ struct nfsclsession {
struct mtx nfsess_mtx;
struct nfsslot nfsess_cbslots[NFSV4_CBSLOTS];
nfsquad_t nfsess_clientid;
SVCXPRT *nfsess_xprt; /* For backchannel callback */
uint32_t nfsess_slotseq[64]; /* Max for 64bit nm_slots */
uint64_t nfsess_slots;
uint32_t nfsess_sequenceid;

View File

@ -115,3 +115,9 @@ struct nfsexstuff {
#define NFSRV_MINFH (sizeof (fhandle_t))
#define NFSRV_MAXFH (sizeof (fhandle_t))
/* Use this macro for debug printfs. */
#define NFSD_DEBUG(level, ...) do { \
if (nfsd_debuglevel >= (level)) \
printf(__VA_ARGS__); \
} while (0)

View File

@ -638,6 +638,9 @@ void nfsrvd_rcv(struct socket *, void *, int);
#define NFSUNLOCKSOCKREQ(r) mtx_unlock(&((r)->nr_mtx))
#define NFSLOCKDS(d) mtx_lock(&((d)->nfsclds_mtx))
#define NFSUNLOCKDS(d) mtx_unlock(&((d)->nfsclds_mtx))
#define NFSSESSIONMUTEXPTR(s) (&((s)->mtx))
#define NFSLOCKSESSION(s) mtx_lock(&((s)->mtx))
#define NFSUNLOCKSESSION(s) mtx_unlock(&((s)->mtx))
/*
* Use these macros to initialize/free a mutex.
@ -733,6 +736,7 @@ MALLOC_DECLARE(M_NEWNFSDEVINFO);
MALLOC_DECLARE(M_NEWNFSSOCKREQ);
MALLOC_DECLARE(M_NEWNFSCLDS);
MALLOC_DECLARE(M_NEWNFSLAYRECALL);
MALLOC_DECLARE(M_NEWNFSDSESSION);
#define M_NFSRVCACHE M_NEWNFSRVCACHE
#define M_NFSDCLIENT M_NEWNFSDCLIENT
#define M_NFSDSTATE M_NEWNFSDSTATE
@ -758,6 +762,7 @@ MALLOC_DECLARE(M_NEWNFSLAYRECALL);
#define M_NFSSOCKREQ M_NEWNFSSOCKREQ
#define M_NFSCLDS M_NEWNFSCLDS
#define M_NFSLAYRECALL M_NEWNFSLAYRECALL
#define M_NFSDSESSION M_NEWNFSDSESSION
#define NFSINT_SIGMASK(set) \
(SIGISMEMBER(set, SIGINT) || SIGISMEMBER(set, SIGTERM) || \

View File

@ -389,9 +389,13 @@
#define NFSV4OPEN_CLAIMPREVIOUS 1
#define NFSV4OPEN_CLAIMDELEGATECUR 2
#define NFSV4OPEN_CLAIMDELEGATEPREV 3
#define NFSV4OPEN_CLAIMFH 4
#define NFSV4OPEN_CLAIMDELEGATECURFH 5
#define NFSV4OPEN_CLAIMDELEGATEPREVFH 6
#define NFSV4OPEN_DELEGATENONE 0
#define NFSV4OPEN_DELEGATEREAD 1
#define NFSV4OPEN_DELEGATEWRITE 2
#define NFSV4OPEN_DELEGATENONEEXT 3
#define NFSV4OPEN_LIMITSIZE 1
#define NFSV4OPEN_LIMITBLOCKS 2
@ -479,23 +483,50 @@
#define NFSV4OPEN_ACCESSREAD 0x00000001
#define NFSV4OPEN_ACCESSWRITE 0x00000002
#define NFSV4OPEN_ACCESSBOTH 0x00000003
#define NFSV4OPEN_WANTDELEGMASK 0x0000ff00
#define NFSV4OPEN_WANTREADDELEG 0x00000100
#define NFSV4OPEN_WANTWRITEDELEG 0x00000200
#define NFSV4OPEN_WANTANYDELEG 0x00000300
#define NFSV4OPEN_WANTNODELEG 0x00000400
#define NFSV4OPEN_WANTCANCEL 0x00000500
#define NFSV4OPEN_WANTSIGNALDELEG 0x00010000
#define NFSV4OPEN_WANTPUSHDELEG 0x00020000
#define NFSV4OPEN_DENYNONE 0x00000000
#define NFSV4OPEN_DENYREAD 0x00000001
#define NFSV4OPEN_DENYWRITE 0x00000002
#define NFSV4OPEN_DENYBOTH 0x00000003
/*
* Delegate_none_ext reply values.
*/
#define NFSV4OPEN_NOTWANTED 0
#define NFSV4OPEN_CONTENTION 1
#define NFSV4OPEN_RESOURCE 2
#define NFSV4OPEN_NOTSUPPFTYPE 3
#define NFSV4OPEN_NOTSUPPWRITEFTYPE 4
#define NFSV4OPEN_NOTSUPPUPGRADE 5
#define NFSV4OPEN_NOTSUPPDOWNGRADE 6
#define NFSV4OPEN_CANCELLED 7
#define NFSV4OPEN_ISDIR 8
/*
* Open result flags
* (The first two are in the spec. The rest are used internally.)
* (The first four are in the spec. The rest are used internally.)
*/
#define NFSV4OPEN_RESULTCONFIRM 0x00000002
#define NFSV4OPEN_LOCKTYPEPOSIX 0x00000004
#define NFSV4OPEN_PRESERVEUNLINKED 0x00000008
#define NFSV4OPEN_MAYNOTIFYLOCK 0x00000020
#define NFSV4OPEN_RFLAGS \
(NFSV4OPEN_RESULTCONFIRM | NFSV4OPEN_LOCKTYPEPOSIX)
(NFSV4OPEN_RESULTCONFIRM | NFSV4OPEN_LOCKTYPEPOSIX | \
NFSV4OPEN_PRESERVEUNLINKED | NFSV4OPEN_MAYNOTIFYLOCK)
#define NFSV4OPEN_RECALL 0x00010000
#define NFSV4OPEN_READDELEGATE 0x00020000
#define NFSV4OPEN_WRITEDELEGATE 0x00040000
#define NFSV4OPEN_WDRESOURCE 0x00080000
#define NFSV4OPEN_WDCONTENTION 0x00100000
#define NFSV4OPEN_WDNOTWANTED 0x00200000
/*
* NFS V4 File Handle types
@ -805,6 +836,27 @@ struct nfsv3_sattr {
#define NFSATTRBIT_TIMEMODIFY 53
#define NFSATTRBIT_TIMEMODIFYSET 54
#define NFSATTRBIT_MOUNTEDONFILEID 55
#define NFSATTRBIT_DIRNOTIFDELAY 56
#define NFSATTRBIT_DIRENTNOTIFDELAY 57
#define NFSATTRBIT_DACL 58
#define NFSATTRBIT_SACL 59
#define NFSATTRBIT_CHANGEPOLICY 60
#define NFSATTRBIT_FSSTATUS 61
#define NFSATTRBIT_FSLAYOUTTYPE 62
#define NFSATTRBIT_LAYOUTHINT 63
#define NFSATTRBIT_LAYOUTTYPE 64
#define NFSATTRBIT_LAYOUTBLKSIZE 65
#define NFSATTRBIT_LAYOUTALIGNMENT 66
#define NFSATTRBIT_FSLOCATIONSINFO 67
#define NFSATTRBIT_MDSTHRESHOLD 68
#define NFSATTRBIT_RETENTIONGET 69
#define NFSATTRBIT_RETENTIONSET 70
#define NFSATTRBIT_RETENTEVTGET 71
#define NFSATTRBIT_RETENTEVTSET 72
#define NFSATTRBIT_RETENTIONHOLD 73
#define NFSATTRBIT_MODESETMASKED 74
#define NFSATTRBIT_SUPPATTREXCLCREAT 75
#define NFSATTRBIT_FSCHARSETCAP 76
#define NFSATTRBM_SUPPORTEDATTRS 0x00000001
#define NFSATTRBM_TYPE 0x00000002
@ -862,8 +914,29 @@ struct nfsv3_sattr {
#define NFSATTRBM_TIMEMODIFY 0x00200000
#define NFSATTRBM_TIMEMODIFYSET 0x00400000
#define NFSATTRBM_MOUNTEDONFILEID 0x00800000
#define NFSATTRBM_DIRNOTIFDELAY 0x01000000
#define NFSATTRBM_DIRENTNOTIFDELAY 0x02000000
#define NFSATTRBM_DACL 0x04000000
#define NFSATTRBM_SACL 0x08000000
#define NFSATTRBM_CHANGEPOLICY 0x10000000
#define NFSATTRBM_FSSTATUS 0x20000000
#define NFSATTRBM_FSLAYOUTTYPE 0x40000000
#define NFSATTRBM_LAYOUTHINT 0x80000000
#define NFSATTRBM_LAYOUTTYPE 0x00000001
#define NFSATTRBM_LAYOUTBLKSIZE 0x00000002
#define NFSATTRBM_LAYOUTALIGNMENT 0x00000004
#define NFSATTRBM_FSLOCATIONSINFO 0x00000008
#define NFSATTRBM_MDSTHRESHOLD 0x00000010
#define NFSATTRBM_RETENTIONGET 0x00000020
#define NFSATTRBM_RETENTIONSET 0x00000040
#define NFSATTRBM_RETENTEVTGET 0x00000080
#define NFSATTRBM_RETENTEVTSET 0x00000100
#define NFSATTRBM_RETENTIONHOLD 0x00000200
#define NFSATTRBM_MODESETMASKED 0x00000400
#define NFSATTRBM_SUPPATTREXCLCREAT 0x00000800
#define NFSATTRBM_FSCHARSETCAP 0x00001000
#define NFSATTRBIT_MAX 56
#define NFSATTRBIT_MAX 77
/*
* Sets of attributes that are supported, by words in the bitmap.
@ -871,6 +944,7 @@ struct nfsv3_sattr {
/*
* NFSATTRBIT_SUPPORTED - SUPP0 - bits 0<->31
* SUPP1 - bits 32<->63
* SUPP2 - bits 64<->95
*/
#define NFSATTRBIT_SUPP0 \
(NFSATTRBM_SUPPORTEDATTRS | \
@ -937,6 +1011,8 @@ struct nfsv3_sattr {
#define NFSATTRBIT_SUPP1 NFSATTRBIT_S1
#endif
#define NFSATTRBIT_SUPP2 NFSATTRBM_SUPPATTREXCLCREAT
/*
* NFSATTRBIT_SUPPSETONLY is the OR of NFSATTRBIT_TIMEACCESSSET and
* NFSATTRBIT_TIMEMODIFYSET.
@ -947,6 +1023,7 @@ struct nfsv3_sattr {
/*
* NFSATTRBIT_SETABLE - SETABLE0 - bits 0<->31
* SETABLE1 - bits 32<->63
* SETABLE2 - bits 64<->95
*/
#define NFSATTRBIT_SETABLE0 \
(NFSATTRBM_SIZE | \
@ -957,6 +1034,7 @@ struct nfsv3_sattr {
NFSATTRBM_OWNERGROUP | \
NFSATTRBM_TIMEACCESSSET | \
NFSATTRBM_TIMEMODIFYSET)
#define NFSATTRBIT_SETABLE2 0
/*
* Set of attributes that the getattr vnode op needs.
@ -986,6 +1064,11 @@ struct nfsv3_sattr {
NFSATTRBM_TIMEMETADATA | \
NFSATTRBM_TIMEMODIFY)
/*
* NFSATTRBIT_GETATTR2 - bits 64<->95
*/
#define NFSATTRBIT_GETATTR2 0
/*
* Subset of the above that the Write RPC gets.
* OR of the following bits.
@ -1012,6 +1095,11 @@ struct nfsv3_sattr {
NFSATTRBM_TIMEMETADATA | \
NFSATTRBM_TIMEMODIFY)
/*
* NFSATTRBIT_WRITEGETATTR2 - bits 64<->95
*/
#define NFSATTRBIT_WRITEGETATTR2 0
/*
* Set of attributes that the wccattr operation op needs.
* OR of the following bits.
@ -1025,6 +1113,11 @@ struct nfsv3_sattr {
#define NFSATTRBIT_WCCATTR1 \
(NFSATTRBM_TIMEMODIFY)
/*
* NFSATTRBIT_WCCATTR2 - bits 64<->95
*/
#define NFSATTRBIT_WCCATTR2 0
/*
* NFSATTRBIT_CBGETATTR0 - bits 0<->31
*/
@ -1035,6 +1128,11 @@ struct nfsv3_sattr {
*/
#define NFSATTRBIT_CBGETATTR1 0x0
/*
* NFSATTRBIT_CBGETATTR2 - bits 64<->95
*/
#define NFSATTRBIT_CBGETATTR2 0x0
/*
* Sets of attributes that require a VFS_STATFS() call to get the
* values of.
@ -1066,6 +1164,11 @@ struct nfsv3_sattr {
NFSATTRBM_SPACEUSED | \
NFSATTRBM_TIMEDELTA)
/*
* NFSATTRBIT_STATFS2 - bits 64<->95
*/
#define NFSATTRBIT_STATFS2 0
/*
* These are the bits that are needed by the nfs_statfs() call.
* (The regular getattr bits are or'd in so the vnode gets the correct
@ -1093,6 +1196,11 @@ struct nfsv3_sattr {
NFSATTRBM_SPACETOTAL | \
NFSATTRBM_TIMEDELTA)
/*
* NFSGETATTRBIT_STATFS2 - bits 64<->95
*/
#define NFSGETATTRBIT_STATFS2 0
/*
* Set of attributes for the equivalent of an nfsv3 pathconf rpc.
* NFSGETATTRBIT_PATHCONF0 - bits 0<->31
@ -1110,6 +1218,11 @@ struct nfsv3_sattr {
#define NFSGETATTRBIT_PATHCONF1 (NFSATTRBIT_GETATTR1 | \
NFSATTRBM_NOTRUNC)
/*
* NFSGETATTRBIT_PATHCONF2 - bits 64<->95
*/
#define NFSGETATTRBIT_PATHCONF2 0
/*
* Sets of attributes required by readdir and readdirplus.
* NFSATTRBIT_READDIRPLUS0 (NFSATTRBIT_GETATTR0 | NFSATTRBIT_FILEHANDLE |
@ -1118,6 +1231,7 @@ struct nfsv3_sattr {
#define NFSATTRBIT_READDIRPLUS0 (NFSATTRBIT_GETATTR0 | NFSATTRBM_FILEHANDLE | \
NFSATTRBM_RDATTRERROR)
#define NFSATTRBIT_READDIRPLUS1 NFSATTRBIT_GETATTR1
#define NFSATTRBIT_READDIRPLUS2 0
/*
* Set of attributes supported by Referral vnodes.
@ -1125,6 +1239,7 @@ struct nfsv3_sattr {
#define NFSATTRBIT_REFERRAL0 (NFSATTRBM_TYPE | NFSATTRBM_FSID | \
NFSATTRBM_RDATTRERROR | NFSATTRBM_FSLOCATIONS)
#define NFSATTRBIT_REFERRAL1 NFSATTRBM_MOUNTEDONFILEID
#define NFSATTRBIT_REFERRAL2 0
/*
* Structure for data handled by the statfs rpc. Since some fields are

View File

@ -42,6 +42,8 @@ LIST_HEAD(nfsclienthashhead, nfsclient);
LIST_HEAD(nfsstatehead, nfsstate);
LIST_HEAD(nfslockhead, nfslock);
LIST_HEAD(nfslockhashhead, nfslockfile);
LIST_HEAD(nfssessionhead, nfsdsession);
LIST_HEAD(nfssessionhashhead, nfsdsession);
/*
* List head for nfsusrgrp.
@ -64,6 +66,13 @@ TAILQ_HEAD(nfsuserlruhead, nfsusrgrp);
(&nfsgroupnamehash[((l)>=4?(*(p)+*((p)+1)+*((p)+2)+*((p)+3)):*(p)) \
% NFSGROUPHASHSIZE])
struct nfssessionhash {
struct mtx mtx;
struct nfssessionhashhead list;
};
#define NFSSESSIONHASH(f) \
(&nfssessionhash[nfsrv_hashsessionid(f) % NFSSESSIONHASHSIZE])
/*
* Client server structure for V4. It is doubly linked into two lists.
* The first is a hash table based on the clientid and the second is a
@ -76,6 +85,7 @@ struct nfsclient {
struct nfsstatehead lc_open; /* Open owner list */
struct nfsstatehead lc_deleg; /* Delegations */
struct nfsstatehead lc_olddeleg; /* and old delegations */
struct nfssessionhead lc_session; /* List of NFSv4.1 sessions */
time_t lc_expiry; /* Expiry time (sec) */
time_t lc_delegtime; /* Old deleg expiry (sec) */
nfsquad_t lc_clientid; /* 64 bit clientid */
@ -100,6 +110,43 @@ struct nfsclient {
#define CLOPS_RENEW 0x0002
#define CLOPS_RENEWOP 0x0004
/*
* Structure for an NFSv4.1 session.
* Locking rules for this structure.
* To add/delete one of these structures from the lists, you must lock
* both: NFSLOCKSESSION(session hashhead) and NFSLOCKSTATE() in that order.
* To traverse the lists looking for one of these, you must hold one
* of these two locks.
* The exception is if the thread holds the exclusive root sleep lock.
* In this case, all other nfsd threads are blocked, so locking the
* mutexes isn't required.
* When manipulating sess_refcnt, NFSLOCKSTATE() must be locked.
* When manipulating the fields withinsess_cbsess except nfsess_xprt,
* sess_cbsess.nfsess_mtx must be locked.
* When manipulating sess_slots and sess_cbsess.nfsess_xprt,
* NFSLOCKSESSION(session hashhead) must be locked.
*/
struct nfsdsession {
uint64_t sess_refcnt; /* Reference count. */
LIST_ENTRY(nfsdsession) sess_hash; /* Hash list of sessions. */
LIST_ENTRY(nfsdsession) sess_list; /* List of client sessions. */
struct nfsslot sess_slots[NFSV4_SLOTS];
struct nfsclient *sess_clp; /* Associated clientid. */
uint32_t sess_crflags;
uint32_t sess_cbprogram;
uint32_t sess_maxreq;
uint32_t sess_maxresp;
uint32_t sess_maxrespcached;
uint32_t sess_maxops;
uint32_t sess_maxslots;
uint32_t sess_cbmaxreq;
uint32_t sess_cbmaxresp;
uint32_t sess_cbmaxrespcached;
uint32_t sess_cbmaxops;
uint8_t sess_sessionid[NFSX_V4SESSIONID];
struct nfsclsession sess_cbsess; /* Callback session. */
};
/*
* Nfs state structure. I couldn't resist overloading this one, since
* it makes cleanup, etc. simpler. These structures are used in four ways:

View File

@ -3548,7 +3548,7 @@ nfscl_docb(struct nfsrv_descript *nd, NFSPROC_T *p)
if (clp != NULL) {
nfsv4_seqsess_cacherep(slotid,
NFSMNT_MDSSESSION(clp->nfsc_nmp)->nfsess_cbslots,
rep);
NFSERR_OK, &rep);
NFSUNLOCKCLSTATE();
} else {
NFSUNLOCKCLSTATE();

View File

@ -977,6 +977,9 @@ nfsrvd_refcache(struct nfsrvcache *rp)
{
struct mtx *mutex;
if (rp == NULL)
/* For NFSv4.1, there is no cache entry. */
return;
mutex = nfsrc_cachemutex(rp);
mtx_lock(mutex);
if (rp->rc_refcnt < 0)

View File

@ -305,7 +305,10 @@ nfs_proc(struct nfsrv_descript *nd, u_int32_t xid, SVCXPRT *xprt,
struct nfsrvcache **rpp)
{
struct thread *td = curthread;
int cacherep = RC_DOIT, isdgram;
int cacherep = RC_DOIT, isdgram, taglen = -1;
struct mbuf *m;
u_char tag[NFSV4_SMALLSTR + 1], *tagstr = NULL;
u_int32_t minorvers = 0;
uint32_t ack;
*rpp = NULL;
@ -339,10 +342,18 @@ nfs_proc(struct nfsrv_descript *nd, u_int32_t xid, SVCXPRT *xprt,
nd->nd_retxid = xid;
nd->nd_tcpconntime = NFSD_MONOSEC;
nd->nd_sockref = xprt->xp_sockref;
cacherep = nfsrvd_getcache(nd);
ack = 0;
SVC_ACK(xprt, &ack);
nfsrc_trimcache(xprt->xp_sockref, ack, 0);
if ((nd->nd_flag & ND_NFSV4) != 0)
nfsd_getminorvers(nd, tag, &tagstr, &taglen,
&minorvers);
if ((nd->nd_flag & ND_NFSV41) != 0)
/* NFSv4.1 caches replies in the session slots. */
cacherep = RC_DOIT;
else {
cacherep = nfsrvd_getcache(nd);
ack = 0;
SVC_ACK(xprt, &ack);
nfsrc_trimcache(xprt->xp_sockref, ack, 0);
}
}
/*
@ -352,13 +363,33 @@ nfs_proc(struct nfsrv_descript *nd, u_int32_t xid, SVCXPRT *xprt,
* RC_DROPIT - just throw the request away
*/
if (cacherep == RC_DOIT) {
nfsrvd_dorpc(nd, isdgram, td);
if (nd->nd_repstat == NFSERR_DONTREPLY)
cacherep = RC_DROPIT;
else
if ((nd->nd_flag & ND_NFSV41) != 0)
nd->nd_xprt = xprt;
nfsrvd_dorpc(nd, isdgram, tagstr, taglen, minorvers, td);
if ((nd->nd_flag & ND_NFSV41) != 0) {
if (nd->nd_repstat != NFSERR_REPLYFROMCACHE &&
(nd->nd_flag & ND_SAVEREPLY) != 0) {
/* Cache a copy of the reply. */
m = m_copym(nd->nd_mreq, 0, M_COPYALL,
M_WAITOK);
} else
m = NULL;
if ((nd->nd_flag & ND_HASSEQUENCE) != 0)
nfsrv_cache_session(nd->nd_sessionid,
nd->nd_slotid, nd->nd_repstat, &m);
if (nd->nd_repstat == NFSERR_REPLYFROMCACHE)
nd->nd_repstat = 0;
cacherep = RC_REPLY;
*rpp = nfsrvd_updatecache(nd);
} else {
if (nd->nd_repstat == NFSERR_DONTREPLY)
cacherep = RC_DROPIT;
else
cacherep = RC_REPLY;
*rpp = nfsrvd_updatecache(nd);
}
}
if (tagstr != NULL && taglen > NFSV4_SMALLSTR)
free(tagstr, M_TEMP);
NFSEXITCODE2(0, nd);
return (cacherep);

View File

@ -58,6 +58,7 @@ extern struct nfsrv_stablefirst nfsrv_stablefirst;
extern void (*nfsd_call_servertimer)(void);
extern SVCPOOL *nfsrvd_pool;
extern struct nfsv4lock nfsd_suspend_lock;
extern struct nfssessionhash nfssessionhash[NFSSESSIONHASHSIZE];
struct vfsoptlist nfsv4root_opt, nfsv4root_newopt;
NFSDLOCKMUTEX;
struct nfsrchash_bucket nfsrchash_table[NFSRVCACHE_HASHSIZE];
@ -67,6 +68,7 @@ struct mtx nfs_v4root_mutex;
struct nfsrvfh nfs_rootfh, nfs_pubfh;
int nfs_pubfhset = 0, nfs_rootfhset = 0;
struct proc *nfsd_master_proc = NULL;
int nfsd_debuglevel = 0;
static pid_t nfsd_master_pid = (pid_t)-1;
static char nfsd_master_comm[MAXCOMLEN + 1];
static struct timeval nfsd_master_start;
@ -93,6 +95,8 @@ SYSCTL_INT(_vfs_nfsd, OID_AUTO, issue_delegations, CTLFLAG_RW,
&nfsrv_issuedelegs, 0, "Enable nfsd to issue delegations");
SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_locallocks, CTLFLAG_RW,
&nfsrv_dolocallocks, 0, "Enable nfsd to acquire local locks on files");
SYSCTL_INT(_vfs_nfsd, OID_AUTO, debuglevel, CTLFLAG_RW, &nfsd_debuglevel,
0, "Debug level for new nfs server");
SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_stringtouid, CTLFLAG_RW,
&nfsd_enable_stringtouid, 0, "Enable nfsd to accept numeric owner_names");
@ -3260,6 +3264,18 @@ nfsrv_hashfh(fhandle_t *fhp)
return (hashval);
}
/*
* Calculate a hash value for the sessionid.
*/
uint32_t
nfsrv_hashsessionid(uint8_t *sessionid)
{
uint32_t hashval;
hashval = hash32_buf(sessionid, NFSX_V4SESSIONID, 0);
return (hashval);
}
/*
* Signal the userland master nfsd to backup the stable restart file.
*/
@ -3318,6 +3334,9 @@ nfsd_modevent(module_t mod, int type, void *data)
mtx_init(&nfs_v4root_mutex, "nfs_v4root_mutex", NULL, MTX_DEF);
mtx_init(&nfsv4root_mnt.mnt_mtx, "struct mount mtx", NULL,
MTX_DEF);
for (i = 0; i < NFSSESSIONHASHSIZE; i++)
mtx_init(&nfssessionhash[i].mtx, "nfs_session_mutex",
NULL, MTX_DEF);
lockinit(&nfsv4root_mnt.mnt_explock, PVFS, "explock", 0, 0);
nfsrvd_initcache();
nfsd_init();
@ -3365,6 +3384,8 @@ nfsd_modevent(module_t mod, int type, void *data)
mtx_destroy(&nfsrc_udpmtx);
mtx_destroy(&nfs_v4root_mutex);
mtx_destroy(&nfsv4root_mnt.mnt_mtx);
for (i = 0; i < NFSSESSIONHASHSIZE; i++)
mtx_destroy(&nfssessionhash[i].mtx);
lockdestroy(&nfsv4root_mnt.mnt_explock);
loaded = 0;
break;

View File

@ -666,10 +666,14 @@ nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
if (nd->nd_flag & ND_IMPLIEDCLID) {
if (nd->nd_clientid.qval != clientid.qval)
printf("EEK! multiple clids\n");
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
if ((nd->nd_flag & ND_NFSV41) != 0)
clientid.qval = nd->nd_clientid.qval;
else if (nd->nd_clientid.qval != clientid.qval)
printf("EEK1 multiple clids\n");
} else {
if ((nd->nd_flag & ND_NFSV41) != 0)
printf("EEK! no clientid from session\n");
nd->nd_flag |= ND_IMPLIEDCLID;
nd->nd_clientid.qval = clientid.qval;
}
@ -818,10 +822,14 @@ nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
if (nd->nd_flag & ND_IMPLIEDCLID) {
if (nd->nd_clientid.qval != clientid.qval)
printf("EEK! multiple clids\n");
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
if ((nd->nd_flag & ND_NFSV41) != 0)
clientid.qval = nd->nd_clientid.qval;
else if (nd->nd_clientid.qval != clientid.qval)
printf("EEK2 multiple clids\n");
} else {
if ((nd->nd_flag & ND_NFSV41) != 0)
printf("EEK! no clientid from session\n");
nd->nd_flag |= ND_IMPLIEDCLID;
nd->nd_clientid.qval = clientid.qval;
}
@ -2204,10 +2212,14 @@ nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
clientid.lval[0] = *tl++;
clientid.lval[1] = *tl++;
if (nd->nd_flag & ND_IMPLIEDCLID) {
if (nd->nd_clientid.qval != clientid.qval)
printf("EEK! multiple clids\n");
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
if ((nd->nd_flag & ND_NFSV41) != 0)
clientid.qval = nd->nd_clientid.qval;
else if (nd->nd_clientid.qval != clientid.qval)
printf("EEK3 multiple clids\n");
} else {
if ((nd->nd_flag & ND_NFSV41) != 0)
printf("EEK! no clientid from session\n");
nd->nd_flag |= ND_IMPLIEDCLID;
nd->nd_clientid.qval = clientid.qval;
}
@ -2227,10 +2239,14 @@ nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
stp->ls_seq = fxdr_unsigned(int, *tl);
clientid.lval[0] = stp->ls_stateid.other[0];
clientid.lval[1] = stp->ls_stateid.other[1];
if (nd->nd_flag & ND_IMPLIEDCLID) {
if (nd->nd_clientid.qval != clientid.qval)
printf("EEK! multiple clids\n");
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
if ((nd->nd_flag & ND_NFSV41) != 0)
clientid.qval = nd->nd_clientid.qval;
else if (nd->nd_clientid.qval != clientid.qval)
printf("EEK4 multiple clids\n");
} else {
if ((nd->nd_flag & ND_NFSV41) != 0)
printf("EEK! no clientid from session\n");
nd->nd_flag |= ND_IMPLIEDCLID;
nd->nd_clientid.qval = clientid.qval;
}
@ -2376,10 +2392,14 @@ nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
tl += 2;
clientid.lval[0] = *tl++;
clientid.lval[1] = *tl;
if (nd->nd_flag & ND_IMPLIEDCLID) {
if (nd->nd_clientid.qval != clientid.qval)
printf("EEK! multiple clids\n");
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
if ((nd->nd_flag & ND_NFSV41) != 0)
clientid.qval = nd->nd_clientid.qval;
else if (nd->nd_clientid.qval != clientid.qval)
printf("EEK5 multiple clids\n");
} else {
if ((nd->nd_flag & ND_NFSV41) != 0)
printf("EEK! no clientid from session\n");
nd->nd_flag |= ND_IMPLIEDCLID;
nd->nd_clientid.qval = clientid.qval;
}
@ -2487,10 +2507,14 @@ nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
}
clientid.lval[0] = stp->ls_stateid.other[0];
clientid.lval[1] = stp->ls_stateid.other[1];
if (nd->nd_flag & ND_IMPLIEDCLID) {
if (nd->nd_clientid.qval != clientid.qval)
printf("EEK! multiple clids\n");
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
if ((nd->nd_flag & ND_NFSV41) != 0)
clientid.qval = nd->nd_clientid.qval;
else if (nd->nd_clientid.qval != clientid.qval)
printf("EEK6 multiple clids\n");
} else {
if ((nd->nd_flag & ND_NFSV41) != 0)
printf("EEK! no clientid from session\n");
nd->nd_flag |= ND_IMPLIEDCLID;
nd->nd_clientid.qval = clientid.qval;
}
@ -2531,7 +2555,7 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
struct nfsexstuff *exp)
{
u_int32_t *tl;
int i;
int i, retext;
struct nfsstate *stp = NULL;
int error = 0, create, claim, exclusive_flag = 0;
u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
@ -2568,6 +2592,39 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
stp->ls_uid = nd->nd_cred->cr_uid;
stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
i = fxdr_unsigned(int, *tl++);
retext = 0;
if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
retext = 1;
/* For now, ignore these. */
i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
switch (i & NFSV4OPEN_WANTDELEGMASK) {
case NFSV4OPEN_WANTANYDELEG:
stp->ls_flags |= (NFSLCK_WANTRDELEG |
NFSLCK_WANTWDELEG);
i &= ~NFSV4OPEN_WANTDELEGMASK;
break;
case NFSV4OPEN_WANTREADDELEG:
stp->ls_flags |= NFSLCK_WANTRDELEG;
i &= ~NFSV4OPEN_WANTDELEGMASK;
break;
case NFSV4OPEN_WANTWRITEDELEG:
stp->ls_flags |= NFSLCK_WANTWDELEG;
i &= ~NFSV4OPEN_WANTDELEGMASK;
break;
case NFSV4OPEN_WANTNODELEG:
stp->ls_flags |= NFSLCK_WANTNODELEG;
i &= ~NFSV4OPEN_WANTDELEGMASK;
break;
case NFSV4OPEN_WANTCANCEL:
printf("NFSv4: ignore Open WantCancel\n");
i &= ~NFSV4OPEN_WANTDELEGMASK;
break;
default:
/* nd_repstat will be set to NFSERR_INVAL below. */
break;
};
}
switch (i) {
case NFSV4OPEN_ACCESSREAD:
stp->ls_flags |= NFSLCK_READACCESS;
@ -2599,10 +2656,14 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
};
clientid.lval[0] = *tl++;
clientid.lval[1] = *tl;
if (nd->nd_flag & ND_IMPLIEDCLID) {
if (nd->nd_clientid.qval != clientid.qval)
printf("EEK! multiple clids\n");
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
if ((nd->nd_flag & ND_NFSV41) != 0)
clientid.qval = nd->nd_clientid.qval;
else if (nd->nd_clientid.qval != clientid.qval)
printf("EEK7 multiple clids\n");
} else {
if ((nd->nd_flag & ND_NFSV41) != 0)
printf("EEK! no clientid from session\n");
nd->nd_flag |= ND_IMPLIEDCLID;
nd->nd_clientid.qval = clientid.qval;
}
@ -2642,6 +2703,28 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
cverf[0] = *tl++;
cverf[1] = *tl;
break;
case NFSCREATE_EXCLUSIVE41:
NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
cverf[0] = *tl++;
cverf[1] = *tl;
error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
if (error != 0)
goto nfsmout;
if (NFSISSET_ATTRBIT(&attrbits,
NFSATTRBIT_TIMEACCESSSET))
nd->nd_repstat = NFSERR_INVAL;
/*
* If the na_gid being set is the same as that of
* the directory it is going in, clear it, since
* that is what will be set by default. This allows
* a user that isn't in that group to do the create.
*/
if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
nva.na_gid == dirfor.na_gid)
NFSVNO_UNSET(&nva, gid);
if (nd->nd_repstat == 0)
nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
break;
default:
nd->nd_repstat = NFSERR_BADXDR;
goto nfsmout;
@ -2723,27 +2806,38 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
exclusive_flag = 1;
if (!named.ni_vp)
nva.na_mode = 0;
break;
case NFSCREATE_EXCLUSIVE41:
exclusive_flag = 1;
break;
};
}
nfsvno_open(nd, &named, clientid, &stateid, stp,
&exclusive_flag, &nva, cverf, create, aclp, &attrbits,
nd->nd_cred, p, exp, &vp);
} else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
i = fxdr_unsigned(int, *tl);
switch (i) {
case NFSV4OPEN_DELEGATEREAD:
stp->ls_flags |= NFSLCK_DELEGREAD;
break;
case NFSV4OPEN_DELEGATEWRITE:
stp->ls_flags |= NFSLCK_DELEGWRITE;
case NFSV4OPEN_DELEGATENONE:
break;
default:
nd->nd_repstat = NFSERR_BADXDR;
goto nfsmout;
};
stp->ls_flags |= NFSLCK_RECLAIM;
} else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
NFSV4OPEN_CLAIMFH) {
if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
i = fxdr_unsigned(int, *tl);
switch (i) {
case NFSV4OPEN_DELEGATEREAD:
stp->ls_flags |= NFSLCK_DELEGREAD;
break;
case NFSV4OPEN_DELEGATEWRITE:
stp->ls_flags |= NFSLCK_DELEGWRITE;
case NFSV4OPEN_DELEGATENONE:
break;
default:
nd->nd_repstat = NFSERR_BADXDR;
goto nfsmout;
};
stp->ls_flags |= NFSLCK_RECLAIM;
} else {
/* CLAIM_NULL_FH */
if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
nd->nd_repstat = NFSERR_INVAL;
}
vp = dp;
NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
if ((vp->v_iflag & VI_DOOMED) == 0)
@ -2832,7 +2926,21 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
*tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
else if (rflags & NFSV4OPEN_WRITEDELEGATE)
*tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
else
else if (retext != 0) {
*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
*tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
*tl = newnfs_false;
} else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
*tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
*tl = newnfs_false;
} else {
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
}
} else
*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
@ -2908,10 +3016,14 @@ nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
stp->ls_flags = NFSLCK_CLOSE;
clientid.lval[0] = stp->ls_stateid.other[0];
clientid.lval[1] = stp->ls_stateid.other[1];
if (nd->nd_flag & ND_IMPLIEDCLID) {
if (nd->nd_clientid.qval != clientid.qval)
printf("EEK! multiple clids\n");
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
if ((nd->nd_flag & ND_NFSV41) != 0)
clientid.qval = nd->nd_clientid.qval;
else if (nd->nd_clientid.qval != clientid.qval)
printf("EEK8 multiple clids\n");
} else {
if ((nd->nd_flag & ND_NFSV41) != 0)
printf("EEK! no clientid from session\n");
nd->nd_flag |= ND_IMPLIEDCLID;
nd->nd_clientid.qval = clientid.qval;
}
@ -2948,14 +3060,18 @@ nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
clientid.lval[0] = *tl++;
clientid.lval[1] = *tl;
if (nd->nd_flag & ND_IMPLIEDCLID) {
if (nd->nd_clientid.qval != clientid.qval)
printf("EEK! multiple clids\n");
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
if ((nd->nd_flag & ND_NFSV41) != 0)
clientid.qval = nd->nd_clientid.qval;
else if (nd->nd_clientid.qval != clientid.qval)
printf("EEK9 multiple clids\n");
} else {
if ((nd->nd_flag & ND_NFSV41) != 0)
printf("EEK! no clientid from session\n");
nd->nd_flag |= ND_IMPLIEDCLID;
nd->nd_clientid.qval = clientid.qval;
}
nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
NFSV4OP_DELEGPURGE, nd->nd_cred, p);
nfsmout:
NFSEXITCODE2(error, nd);
@ -2979,14 +3095,18 @@ nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
clientid.lval[0] = stateid.other[0];
clientid.lval[1] = stateid.other[1];
if (nd->nd_flag & ND_IMPLIEDCLID) {
if (nd->nd_clientid.qval != clientid.qval)
printf("EEK! multiple clids\n");
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
if ((nd->nd_flag & ND_NFSV41) != 0)
clientid.qval = nd->nd_clientid.qval;
else if (nd->nd_clientid.qval != clientid.qval)
printf("EEK10 multiple clids\n");
} else {
if ((nd->nd_flag & ND_NFSV41) != 0)
printf("EEK! no clientid from session\n");
nd->nd_flag |= ND_IMPLIEDCLID;
nd->nd_clientid.qval = clientid.qval;
}
nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
NFSV4OP_DELEGRETURN, nd->nd_cred, p);
nfsmout:
vput(vp);
@ -3024,6 +3144,10 @@ nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
nfsv4stateid_t stateid;
nfsquad_t clientid;
if ((nd->nd_flag & ND_NFSV41) != 0) {
nd->nd_repstat = NFSERR_NOTSUPP;
goto nfsmout;
}
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
stp->ls_ownerlen = 0;
stp->ls_op = nd->nd_rp;
@ -3036,10 +3160,14 @@ nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
stp->ls_flags = NFSLCK_CONFIRM;
clientid.lval[0] = stp->ls_stateid.other[0];
clientid.lval[1] = stp->ls_stateid.other[1];
if (nd->nd_flag & ND_IMPLIEDCLID) {
if (nd->nd_clientid.qval != clientid.qval)
printf("EEK! multiple clids\n");
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
if ((nd->nd_flag & ND_NFSV41) != 0)
clientid.qval = nd->nd_clientid.qval;
else if (nd->nd_clientid.qval != clientid.qval)
printf("EEK11 multiple clids\n");
} else {
if ((nd->nd_flag & ND_NFSV41) != 0)
printf("EEK! no clientid from session\n");
nd->nd_flag |= ND_IMPLIEDCLID;
nd->nd_clientid.qval = clientid.qval;
}
@ -3112,10 +3240,14 @@ nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
clientid.lval[0] = stp->ls_stateid.other[0];
clientid.lval[1] = stp->ls_stateid.other[1];
if (nd->nd_flag & ND_IMPLIEDCLID) {
if (nd->nd_clientid.qval != clientid.qval)
printf("EEK! multiple clids\n");
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
if ((nd->nd_flag & ND_NFSV41) != 0)
clientid.qval = nd->nd_clientid.qval;
else if (nd->nd_clientid.qval != clientid.qval)
printf("EEK12 multiple clids\n");
} else {
if ((nd->nd_flag & ND_NFSV41) != 0)
printf("EEK! no clientid from session\n");
nd->nd_flag |= ND_IMPLIEDCLID;
nd->nd_clientid.qval = clientid.qval;
}
@ -3144,6 +3276,10 @@ nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
int error = 0;
nfsquad_t clientid;
if ((nd->nd_flag & ND_NFSV41) != 0) {
nd->nd_repstat = NFSERR_NOTSUPP;
goto nfsmout;
}
if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
nd->nd_repstat = NFSERR_WRONGSEC;
goto nfsmout;
@ -3151,15 +3287,19 @@ nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
clientid.lval[0] = *tl++;
clientid.lval[1] = *tl;
if (nd->nd_flag & ND_IMPLIEDCLID) {
if (nd->nd_clientid.qval != clientid.qval)
printf("EEK! multiple clids\n");
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
if ((nd->nd_flag & ND_NFSV41) != 0)
clientid.qval = nd->nd_clientid.qval;
else if (nd->nd_clientid.qval != clientid.qval)
printf("EEK13 multiple clids\n");
} else {
if ((nd->nd_flag & ND_NFSV41) != 0)
printf("EEK! no clientid from session\n");
nd->nd_flag |= ND_IMPLIEDCLID;
nd->nd_clientid.qval = clientid.qval;
}
nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
NULL, (nfsquad_t)((u_quad_t)0), nd, p);
NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
nfsmout:
NFSEXITCODE2(error, nd);
return (error);
@ -3283,6 +3423,10 @@ nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
u_char *verf, *ucp, *ucp2, addrbuf[24];
nfsquad_t clientid, confirm;
if ((nd->nd_flag & ND_NFSV41) != 0) {
nd->nd_repstat = NFSERR_NOTSUPP;
goto nfsmout;
}
if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
nd->nd_repstat = NFSERR_WRONGSEC;
goto out;
@ -3395,6 +3539,10 @@ nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
int error = 0;
nfsquad_t clientid, confirm;
if ((nd->nd_flag & ND_NFSV41) != 0) {
nd->nd_repstat = NFSERR_NOTSUPP;
goto nfsmout;
}
if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
nd->nd_repstat = NFSERR_WRONGSEC;
goto nfsmout;
@ -3410,7 +3558,7 @@ nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
* returns the appropriate NFSERR status.
*/
nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
NULL, confirm, nd, p);
NULL, NULL, confirm, 0, nd, p);
nfsmout:
NFSEXITCODE2(error, nd);
return (error);
@ -3485,6 +3633,10 @@ nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
int error = 0, len;
nfsquad_t clientid;
if ((nd->nd_flag & ND_NFSV41) != 0) {
nd->nd_repstat = NFSERR_NOTSUPP;
goto nfsmout;
}
if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
nd->nd_repstat = NFSERR_WRONGSEC;
goto nfsmout;
@ -3503,10 +3655,14 @@ nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
stp->ls_uid = nd->nd_cred->cr_uid;
clientid.lval[0] = *tl++;
clientid.lval[1] = *tl;
if (nd->nd_flag & ND_IMPLIEDCLID) {
if (nd->nd_clientid.qval != clientid.qval)
printf("EEK! multiple clids\n");
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
if ((nd->nd_flag & ND_NFSV41) != 0)
clientid.qval = nd->nd_clientid.qval;
else if (nd->nd_clientid.qval != clientid.qval)
printf("EEK14 multiple clids\n");
} else {
if ((nd->nd_flag & ND_NFSV41) != 0)
printf("EEK! no clientid from session\n");
nd->nd_flag |= ND_IMPLIEDCLID;
nd->nd_clientid.qval = clientid.qval;
}
@ -3524,3 +3680,385 @@ nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
NFSEXITCODE2(error, nd);
return (error);
}
/*
* nfsv4 exchange_id service
*/
APPLESTATIC int
nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
__unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
{
uint32_t *tl;
int error = 0, i, idlen;
struct nfsclient *clp = NULL;
nfsquad_t clientid, confirm;
uint8_t *verf;
uint32_t sp4type, v41flags;
uint64_t owner_minor;
struct timespec verstime;
if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
nd->nd_repstat = NFSERR_WRONGSEC;
goto nfsmout;
}
NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
verf = (uint8_t *)tl;
tl += (NFSX_VERF / NFSX_UNSIGNED);
i = fxdr_unsigned(int, *tl);
if (i > NFSV4_OPAQUELIMIT || i <= 0) {
nd->nd_repstat = NFSERR_BADXDR;
goto nfsmout;
}
idlen = i;
if (nd->nd_flag & ND_GSS)
i += nd->nd_princlen;
clp = (struct nfsclient *)malloc(sizeof(struct nfsclient) + i,
M_NFSDCLIENT, M_WAITOK | M_ZERO);
NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
clp->lc_req.nr_cred = NULL;
NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
clp->lc_idlen = idlen;
error = nfsrv_mtostr(nd, clp->lc_id, idlen);
if (error != 0)
goto nfsmout;
if ((nd->nd_flag & ND_GSS) != 0) {
clp->lc_flags = LCL_GSS | LCL_NFSV41;
if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
clp->lc_flags |= LCL_GSSINTEGRITY;
else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
clp->lc_flags |= LCL_GSSPRIVACY;
} else
clp->lc_flags = LCL_NFSV41;
if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
clp->lc_flags |= LCL_NAME;
clp->lc_namelen = nd->nd_princlen;
clp->lc_name = &clp->lc_id[idlen];
NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
} else {
clp->lc_uid = nd->nd_cred->cr_uid;
clp->lc_gid = nd->nd_cred->cr_gid;
}
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
v41flags = fxdr_unsigned(uint32_t, *tl++);
if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
nd->nd_repstat = NFSERR_INVAL;
goto nfsmout;
}
if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
confirm.lval[1] = 1;
else
confirm.lval[1] = 0;
v41flags = NFSV4EXCH_USENONPNFS;
sp4type = fxdr_unsigned(uint32_t, *tl);
if (sp4type != NFSV4EXCH_SP4NONE) {
nd->nd_repstat = NFSERR_NOTSUPP;
goto nfsmout;
}
/*
* nfsrv_setclient() does the actual work of adding it to the
* client list. If there is no error, the structure has been
* linked into the client list and clp should no longer be used
* here. When an error is returned, it has not been linked in,
* so it should be free'd.
*/
nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
if (clp != NULL) {
NFSSOCKADDRFREE(clp->lc_req.nr_nam);
NFSFREEMUTEX(&clp->lc_req.nr_mtx);
free(clp, M_NFSDCLIENT);
}
if (nd->nd_repstat == 0) {
if (confirm.lval[1] != 0)
v41flags |= NFSV4EXCH_CONFIRMEDR;
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
*tl++ = clientid.lval[0]; /* ClientID */
*tl++ = clientid.lval[1];
*tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
*tl++ = txdr_unsigned(v41flags); /* Exch flags */
*tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */
owner_minor = 0; /* Owner */
txdr_hyper(owner_minor, tl); /* Minor */
(void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
*tl++ = txdr_unsigned(NFSX_UNSIGNED);
*tl++ = time_uptime; /* Make scope a unique value. */
*tl = txdr_unsigned(1);
(void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
(void)nfsm_strtom(nd, version, strlen(version));
NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
verstime.tv_nsec = 0;
txdr_nfsv4time(&verstime, tl);
}
NFSEXITCODE2(0, nd);
return (0);
nfsmout:
if (clp != NULL) {
NFSSOCKADDRFREE(clp->lc_req.nr_nam);
NFSFREEMUTEX(&clp->lc_req.nr_mtx);
free(clp, M_NFSDCLIENT);
}
NFSEXITCODE2(error, nd);
return (error);
}
/*
* nfsv4 create session service
*/
APPLESTATIC int
nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
__unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
{
uint32_t *tl;
int error = 0;
nfsquad_t clientid, confirm;
struct nfsdsession *sep = NULL;
uint32_t rdmacnt;
if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
nd->nd_repstat = NFSERR_WRONGSEC;
goto nfsmout;
}
sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
M_NFSDSESSION, M_WAITOK | M_ZERO);
sep->sess_refcnt = 1;
mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
clientid.lval[0] = *tl++;
clientid.lval[1] = *tl++;
confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
/* Persistent sessions and RDMA are not supported. */
sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
/* Fore channel attributes. */
NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
tl++; /* Header pad always 0. */
sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
if (sep->sess_maxslots > NFSV4_SLOTS)
sep->sess_maxslots = NFSV4_SLOTS;
rdmacnt = fxdr_unsigned(uint32_t, *tl);
if (rdmacnt > 1) {
nd->nd_repstat = NFSERR_BADXDR;
goto nfsmout;
} else if (rdmacnt == 1)
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
/* Back channel attributes. */
NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
tl++; /* Header pad always 0. */
sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
rdmacnt = fxdr_unsigned(uint32_t, *tl);
if (rdmacnt > 1) {
nd->nd_repstat = NFSERR_BADXDR;
goto nfsmout;
} else if (rdmacnt == 1)
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
/*
* nfsrv_getclient() searches the client list for a match and
* returns the appropriate NFSERR status.
*/
nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
NULL, sep, confirm, sep->sess_cbprogram, nd, p);
if (nd->nd_repstat == 0) {
NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
*tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
*tl++ = txdr_unsigned(sep->sess_crflags);
/* Fore channel attributes. */
*tl++ = 0;
*tl++ = txdr_unsigned(sep->sess_maxreq);
*tl++ = txdr_unsigned(sep->sess_maxresp);
*tl++ = txdr_unsigned(sep->sess_maxrespcached);
*tl++ = txdr_unsigned(sep->sess_maxops);
*tl++ = txdr_unsigned(sep->sess_maxslots);
*tl++ = txdr_unsigned(1);
*tl++ = txdr_unsigned(0); /* No RDMA. */
/* Back channel attributes. */
*tl++ = 0;
*tl++ = txdr_unsigned(sep->sess_cbmaxreq);
*tl++ = txdr_unsigned(sep->sess_cbmaxresp);
*tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
*tl++ = txdr_unsigned(sep->sess_cbmaxops);
*tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
*tl++ = txdr_unsigned(1);
*tl = txdr_unsigned(0); /* No RDMA. */
}
nfsmout:
if (nd->nd_repstat != 0 && sep != NULL)
free(sep, M_NFSDSESSION);
NFSEXITCODE2(error, nd);
return (error);
}
/*
* nfsv4 sequence service
*/
APPLESTATIC int
nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
__unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
{
uint32_t *tl;
uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
int cache_this, error = 0;
if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
nd->nd_repstat = NFSERR_WRONGSEC;
goto nfsmout;
}
NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
sequenceid = fxdr_unsigned(uint32_t, *tl++);
nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
highest_slotid = fxdr_unsigned(uint32_t, *tl++);
if (*tl == newnfs_true)
cache_this = 1;
else
cache_this = 0;
nd->nd_flag |= ND_HASSEQUENCE;
nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
&target_highest_slotid, cache_this, &sflags, p);
if (nd->nd_repstat == 0) {
NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
*tl++ = txdr_unsigned(sequenceid);
*tl++ = txdr_unsigned(nd->nd_slotid);
*tl++ = txdr_unsigned(highest_slotid);
*tl++ = txdr_unsigned(target_highest_slotid);
*tl = txdr_unsigned(sflags);
}
nfsmout:
NFSEXITCODE2(error, nd);
return (error);
}
/*
* nfsv4 reclaim complete service
*/
APPLESTATIC int
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;
if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
nd->nd_repstat = NFSERR_WRONGSEC;
goto nfsmout;
}
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
if (*tl == newnfs_true)
nd->nd_repstat = NFSERR_NOTSUPP;
else
nd->nd_repstat = nfsrv_checkreclaimcomplete(nd);
nfsmout:
NFSEXITCODE2(error, nd);
return (error);
}
/*
* nfsv4 destroy clientid service
*/
APPLESTATIC int
nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
__unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
{
uint32_t *tl;
nfsquad_t clientid;
int error = 0;
if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
nd->nd_repstat = NFSERR_WRONGSEC;
goto nfsmout;
}
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
clientid.lval[0] = *tl++;
clientid.lval[1] = *tl;
nd->nd_repstat = nfsrv_destroyclient(clientid, p);
nfsmout:
NFSEXITCODE2(error, nd);
return (error);
}
/*
* nfsv4 destroy session service
*/
APPLESTATIC int
nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
__unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
{
uint8_t *cp, sessid[NFSX_V4SESSIONID];
int error = 0;
if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
nd->nd_repstat = NFSERR_WRONGSEC;
goto nfsmout;
}
NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
nd->nd_repstat = nfsrv_destroysession(nd, sessid);
nfsmout:
NFSEXITCODE2(error, nd);
return (error);
}
/*
* nfsv4 free stateid service
*/
APPLESTATIC int
nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
__unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
{
uint32_t *tl;
nfsv4stateid_t stateid;
int error = 0;
if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
nd->nd_repstat = NFSERR_WRONGSEC;
goto nfsmout;
}
NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
nfsmout:
NFSEXITCODE2(error, nd);
return (error);
}
/*
* nfsv4 service not supported
*/
APPLESTATIC int
nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
__unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
{
nd->nd_repstat = NFSERR_NOTSUPP;
NFSEXITCODE2(0, nd);
return (0);
}

View File

@ -48,6 +48,7 @@ extern struct nfsv4lock nfsv4rootfs_lock;
extern struct nfsrv_stablefirst nfsrv_stablefirst;
extern struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE];
extern int nfsrc_floodlevel, nfsrc_tcpsavedreplies;
extern int nfsd_debuglevel;
NFSV4ROOTLOCKMUTEX;
NFSSTATESPINLOCK;
@ -131,7 +132,7 @@ int (*nfsrv3_procs2[NFS_V3NPROCS])(struct nfsrv_descript *,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
};
int (*nfsrv4_ops0[NFSV4OP_NOPS])(struct nfsrv_descript *,
int (*nfsrv4_ops0[NFSV41_NOPS])(struct nfsrv_descript *,
int, vnode_t , NFSPROC_T *, struct nfsexstuff *) = {
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , NFSPROC_T *, struct nfsexstuff *))0,
@ -173,9 +174,28 @@ int (*nfsrv4_ops0[NFSV4OP_NOPS])(struct nfsrv_descript *,
nfsrvd_verify,
nfsrvd_write,
nfsrvd_releaselckown,
nfsrvd_notsupp,
nfsrvd_notsupp,
nfsrvd_exchangeid,
nfsrvd_createsession,
nfsrvd_destroysession,
nfsrvd_freestateid,
nfsrvd_notsupp,
nfsrvd_notsupp,
nfsrvd_notsupp,
nfsrvd_notsupp,
nfsrvd_notsupp,
nfsrvd_notsupp,
nfsrvd_notsupp,
nfsrvd_sequence,
nfsrvd_notsupp,
nfsrvd_notsupp,
nfsrvd_notsupp,
nfsrvd_destroyclientid,
nfsrvd_reclaimcomplete,
};
int (*nfsrv4_ops1[NFSV4OP_NOPS])(struct nfsrv_descript *,
int (*nfsrv4_ops1[NFSV41_NOPS])(struct nfsrv_descript *,
int, vnode_t , vnode_t *, fhandle_t *,
NFSPROC_T *, struct nfsexstuff *) = {
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
@ -218,9 +238,28 @@ int (*nfsrv4_ops1[NFSV4OP_NOPS])(struct nfsrv_descript *,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t *, fhandle_t *, NFSPROC_T *, struct nfsexstuff *))0,
};
int (*nfsrv4_ops2[NFSV4OP_NOPS])(struct nfsrv_descript *,
int (*nfsrv4_ops2[NFSV41_NOPS])(struct nfsrv_descript *,
int, vnode_t , vnode_t , NFSPROC_T *,
struct nfsexstuff *, struct nfsexstuff *) = {
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
@ -263,6 +302,25 @@ int (*nfsrv4_ops2[NFSV4OP_NOPS])(struct nfsrv_descript *,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
(int (*)(struct nfsrv_descript *, int, vnode_t , vnode_t , NFSPROC_T *, struct nfsexstuff *, struct nfsexstuff *))0,
};
#endif /* !APPLEKEXT */
@ -304,7 +362,7 @@ static int nfs_writerpc[NFS_NPROCS] = { 0, 0, 1, 0, 0, 0, 0,
/* local functions */
static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
NFSPROC_T *p);
u_char *tag, int taglen, u_int32_t minorvers, NFSPROC_T *p);
/*
@ -314,7 +372,7 @@ static void nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
static int nfs_retfh[NFS_V3NPROCS] = { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
1, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 };
extern struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS];
extern struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS];
static int nfsv3to4op[NFS_V3NPROCS] = {
NFSPROC_NULL,
@ -349,8 +407,8 @@ static int nfsv3to4op[NFS_V3NPROCS] = {
* The NFS V4 Compound RPC is performed separately by nfsrvd_compound().
*/
APPLESTATIC void
nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram,
NFSPROC_T *p)
nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen,
u_int32_t minorvers, NFSPROC_T *p)
{
int error = 0, lktype;
vnode_t vp;
@ -427,7 +485,7 @@ nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram,
* The group is indicated by the value in nfs_retfh[].
*/
if (nd->nd_flag & ND_NFSV4) {
nfsrvd_compound(nd, isdgram, p);
nfsrvd_compound(nd, isdgram, tag, taglen, minorvers, p);
} else {
if (nfs_retfh[nd->nd_procnum] == 1) {
if (vp)
@ -482,15 +540,14 @@ nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram,
* vnode pointer handling.
*/
static void
nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
NFSPROC_T *p)
nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
int taglen, u_int32_t minorvers, NFSPROC_T *p)
{
int i, op;
int i, op, op0 = 0;
u_int32_t *tl;
struct nfsclient *clp, *nclp;
int numops, taglen = -1, error = 0, igotlock;
u_int32_t minorvers, retops = 0, *retopsp = NULL, *repp;
u_char tag[NFSV4_SMALLSTR + 1], *tagstr;
int numops, error = 0, igotlock;
u_int32_t retops = 0, *retopsp = NULL, *repp;
vnode_t vp, nvp, savevp;
struct nfsrvfh fh;
mount_t new_mp, temp_mp = NULL;
@ -595,31 +652,17 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
savevp = vp = NULL;
save_fsid.val[0] = save_fsid.val[1] = 0;
cur_fsid.val[0] = cur_fsid.val[1] = 0;
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
taglen = fxdr_unsigned(int, *tl);
/* If taglen < 0, there was a parsing error in nfsd_getminorvers(). */
if (taglen < 0) {
error = EBADRPC;
goto nfsmout;
}
if (taglen <= NFSV4_SMALLSTR)
tagstr = tag;
else
tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK);
error = nfsrv_mtostr(nd, tagstr, taglen);
if (error) {
if (taglen > NFSV4_SMALLSTR)
free(tagstr, M_TEMP);
taglen = -1;
goto nfsmout;
}
(void) nfsm_strtom(nd, tag, taglen);
if (taglen > NFSV4_SMALLSTR) {
free(tagstr, M_TEMP);
}
NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
minorvers = fxdr_unsigned(u_int32_t, *tl++);
if (minorvers != NFSV4_MINORVERSION)
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
if (minorvers != NFSV4_MINORVERSION && minorvers != NFSV41_MINORVERSION)
nd->nd_repstat = NFSERR_MINORVERMISMATCH;
if (nd->nd_repstat)
numops = 0;
@ -638,7 +681,10 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
*repp = *tl;
op = fxdr_unsigned(int, *tl);
if (op < NFSV4OP_ACCESS || op >= NFSV4OP_NOPS) {
NFSD_DEBUG(4, "op=%d\n", op);
if (op < NFSV4OP_ACCESS ||
(op >= NFSV4OP_NOPS && (nd->nd_flag & ND_NFSV41) == 0) ||
(op >= NFSV41_NOPS && (nd->nd_flag & ND_NFSV41) != 0)) {
nd->nd_repstat = NFSERR_OPILLEGAL;
*repp++ = txdr_unsigned(NFSV4OP_OPILLEGAL);
*repp = nfsd_errmap(nd);
@ -647,6 +693,10 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
} else {
repp++;
}
if (i == 0)
op0 = op;
if (i == numops - 1)
nd->nd_flag |= ND_LASTOP;
/*
* Check for a referral on the current FH and, if so, return
@ -661,6 +711,29 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
break;
}
/*
* For NFSv4.1, check for a Sequence Operation being first
* or one of the other allowed operations by itself.
*/
if ((nd->nd_flag & ND_NFSV41) != 0) {
if (i != 0 && op == NFSV4OP_SEQUENCE)
nd->nd_repstat = NFSERR_SEQUENCEPOS;
else if (i == 0 && op != NFSV4OP_SEQUENCE &&
op != NFSV4OP_EXCHANGEID &&
op != NFSV4OP_CREATESESSION &&
op != NFSV4OP_BINDCONNTOSESS &&
op != NFSV4OP_DESTROYCLIENTID &&
op != NFSV4OP_DESTROYSESSION)
nd->nd_repstat = NFSERR_OPNOTINSESS;
else if (i != 0 && op0 != NFSV4OP_SEQUENCE)
nd->nd_repstat = NFSERR_NOTONLYOP;
if (nd->nd_repstat != 0) {
*repp = nfsd_errmap(nd);
retops++;
break;
}
}
nd->nd_procnum = op;
/*
* If over flood level, reply NFSERR_RESOURCE, if at the first
@ -672,7 +745,8 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram,
* If nfsrv_mallocmget_limit() returns True, the system is near
* to its limit for memory that malloc()/mget() can allocate.
*/
if (i == 0 && nd->nd_rp->rc_refcnt == 0 &&
if (i == 0 && (nd->nd_rp == NULL ||
nd->nd_rp->rc_refcnt == 0) &&
(nfsrv_mallocmget_limit() ||
nfsrc_tcpsavedreplies > nfsrc_floodlevel)) {
if (nfsrc_tcpsavedreplies > nfsrc_floodlevel) {

File diff suppressed because it is too large Load Diff

View File

@ -46,6 +46,7 @@ extern u_int32_t newnfs_true, newnfs_false;
extern int nfs_pubfhset;
extern struct nfsclienthashhead nfsclienthash[NFSCLIENTHASHSIZE];
extern struct nfslockhashhead nfslockhash[NFSLOCKHASHSIZE];
extern struct nfssessionhash nfssessionhash[NFSSESSIONHASHSIZE];
extern int nfsrv_useacl;
extern uid_t nfsrv_defaultuid;
extern gid_t nfsrv_defaultgid;
@ -56,6 +57,8 @@ static nfstype newnfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK,
extern nfstype nfsv34_type[9];
#endif /* !APPLEKEXT */
static u_int32_t nfsrv_isannfserr(u_int32_t);
SYSCTL_DECL(_vfs_nfsd);
static int disable_checkutf8 = 0;
@ -68,16 +71,16 @@ static char nfsrv_hexdigit(char, int *);
/*
* Maps errno values to nfs error numbers.
* Use NFSERR_IO as the catch all for ones not specifically defined in
* RFC 1094.
* RFC 1094. (It now includes the errors added for NFSv3.)
*/
static u_char nfsrv_v2errmap[ELAST] = {
static u_char nfsrv_v2errmap[NFSERR_REMOTE] = {
NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
NFSERR_IO, NFSERR_EXIST, NFSERR_XDEV, NFSERR_NODEV, NFSERR_NOTDIR,
NFSERR_ISDIR, NFSERR_INVAL, NFSERR_IO, NFSERR_IO, NFSERR_IO,
NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
NFSERR_MLINK, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
@ -85,9 +88,7 @@ static u_char nfsrv_v2errmap[ELAST] = {
NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO,
NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
NFSERR_IO,
NFSERR_REMOTE,
};
/*
@ -1493,18 +1494,40 @@ nfsd_errmap(struct nfsrv_descript *nd)
else if (nd->nd_repstat == NFSERR_MINORVERMISMATCH ||
nd->nd_repstat == NFSERR_OPILLEGAL)
return (txdr_unsigned(nd->nd_repstat));
else
else if ((nd->nd_flag & ND_NFSV41) != 0) {
if (nd->nd_repstat == EOPNOTSUPP)
nd->nd_repstat = NFSERR_NOTSUPP;
nd->nd_repstat = nfsrv_isannfserr(nd->nd_repstat);
return (txdr_unsigned(nd->nd_repstat));
} else
errp = defaulterrp = nfsrv_v4errmap[nd->nd_procnum];
while (*++errp)
if (*errp == nd->nd_repstat)
return (txdr_unsigned(nd->nd_repstat));
return (txdr_unsigned(*defaulterrp));
}
if (nd->nd_repstat <= ELAST)
if (nd->nd_repstat <= NFSERR_REMOTE)
return (txdr_unsigned(nfsrv_v2errmap[nd->nd_repstat - 1]));
return (txdr_unsigned(NFSERR_IO));
}
/*
* Check to see if the error is a valid NFS one. If not, replace it with
* NFSERR_IO.
*/
static u_int32_t
nfsrv_isannfserr(u_int32_t errval)
{
if (errval == NFSERR_OK)
return (errval);
if (errval >= NFSERR_BADHANDLE && errval <= NFSERR_DELEGREVOKED)
return (errval);
if (errval > 0 && errval <= NFSERR_REMOTE)
return (nfsrv_v2errmap[errval - 1]);
return (NFSERR_IO);
}
/*
* Check to see if setting a uid/gid is permitted when creating a new
* file object. (Called when uid and/or gid is specified in the
@ -2005,6 +2028,8 @@ nfsd_init(void)
LIST_INIT(&nfsclienthash[i]);
for (i = 0; i < NFSLOCKHASHSIZE; i++)
LIST_INIT(&nfslockhash[i]);
for (i = 0; i < NFSSESSIONHASHSIZE; i++)
LIST_INIT(&nfssessionhash[i].list);
/* and the v2 pubfh should be all zeros */
NFSBZERO(nfs_v2pubfh, NFSX_V2FH);
@ -2032,3 +2057,42 @@ nfsd_checkrootexp(struct nfsrv_descript *nd)
return (1);
}
/*
* Parse the first part of an NFSv4 compound to find out what the minor
* version# is.
*/
void
nfsd_getminorvers(struct nfsrv_descript *nd, u_char *tag, u_char **tagstrp,
int *taglenp, u_int32_t *minversp)
{
uint32_t *tl;
int error = 0, taglen = -1;
u_char *tagstr = NULL;
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
taglen = fxdr_unsigned(int, *tl);
if (taglen < 0 || taglen > NFSV4_OPAQUELIMIT) {
error = EBADRPC;
goto nfsmout;
}
if (taglen <= NFSV4_SMALLSTR)
tagstr = tag;
else
tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK);
error = nfsrv_mtostr(nd, tagstr, taglen);
if (error != 0)
goto nfsmout;
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
*minversp = fxdr_unsigned(u_int32_t, *tl);
*tagstrp = tagstr;
if (*minversp == NFSV41_MINORVERSION)
nd->nd_flag |= ND_NFSV41;
nfsmout:
if (error != 0) {
if (tagstr != NULL && taglen > NFSV4_SMALLSTR)
free(tagstr, M_TEMP);
taglen = -1;
}
*taglenp = taglen;
}

View File

@ -5,6 +5,7 @@ KMOD= krpc
SRCS= auth_none.c \
auth_unix.c \
authunix_prot.c \
clnt_bck.c \
clnt_dg.c \
clnt_rc.c \
clnt_vc.c \

593
sys/rpc/clnt_bck.c Normal file
View File

@ -0,0 +1,593 @@
/* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */
/*-
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC";
static char sccsid3[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* clnt_tcp.c, Implements a TCP/IP based, client side RPC.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*
* TCP based RPC supports 'batched calls'.
* A sequence of calls may be batched-up in a send buffer. The rpc call
* return immediately to the client even though the call was not necessarily
* sent. The batching occurs if the results' xdr routine is NULL (0) AND
* the rpc timeout value is zero (see clnt.h, rpc).
*
* Clients should NOT casually batch calls that in fact return results; that is,
* the server side should be aware that a call is batched and not produce any
* return message. Batched calls that produce many result messages can
* deadlock (netlock) the client and the server....
*
* Now go hang yourself.
*/
/*
* This code handles the special case of a NFSv4.n backchannel for
* callback RPCs. It is similar to clnt_vc.c, but uses the TCP
* connection provided by the client to the server.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/mutex.h>
#include <sys/pcpu.h>
#include <sys/proc.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sx.h>
#include <sys/syslog.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <net/vnet.h>
#include <netinet/tcp.h>
#include <rpc/rpc.h>
#include <rpc/rpc_com.h>
#include <rpc/krpc.h>
struct cmessage {
struct cmsghdr cmsg;
struct cmsgcred cmcred;
};
static void clnt_bck_geterr(CLIENT *, struct rpc_err *);
static bool_t clnt_bck_freeres(CLIENT *, xdrproc_t, void *);
static void clnt_bck_abort(CLIENT *);
static bool_t clnt_bck_control(CLIENT *, u_int, void *);
static void clnt_bck_close(CLIENT *);
static void clnt_bck_destroy(CLIENT *);
static struct clnt_ops clnt_bck_ops = {
.cl_abort = clnt_bck_abort,
.cl_geterr = clnt_bck_geterr,
.cl_freeres = clnt_bck_freeres,
.cl_close = clnt_bck_close,
.cl_destroy = clnt_bck_destroy,
.cl_control = clnt_bck_control
};
/*
* Create a client handle for a connection.
* Default options are set, which the user can change using clnt_control()'s.
* This code handles the special case of an NFSv4.1 session backchannel
* call, which is sent on a TCP connection created against the server
* by a client.
*/
void *
clnt_bck_create(
struct socket *so, /* Server transport socket. */
const rpcprog_t prog, /* program number */
const rpcvers_t vers) /* version number */
{
CLIENT *cl; /* client handle */
struct ct_data *ct = NULL; /* client handle */
struct timeval now;
struct rpc_msg call_msg;
static uint32_t disrupt;
XDR xdrs;
if (disrupt == 0)
disrupt = (uint32_t)(long)so;
cl = (CLIENT *)mem_alloc(sizeof (*cl));
ct = (struct ct_data *)mem_alloc(sizeof (*ct));
mtx_init(&ct->ct_lock, "ct->ct_lock", NULL, MTX_DEF);
ct->ct_threads = 0;
ct->ct_closing = FALSE;
ct->ct_closed = FALSE;
ct->ct_upcallrefs = 0;
ct->ct_closeit = FALSE;
/*
* Set up private data struct
*/
ct->ct_wait.tv_sec = -1;
ct->ct_wait.tv_usec = -1;
/*
* Initialize call message
*/
getmicrotime(&now);
ct->ct_xid = ((uint32_t)++disrupt) ^ __RPC_GETXID(&now);
call_msg.rm_xid = ct->ct_xid;
call_msg.rm_direction = CALL;
call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
call_msg.rm_call.cb_prog = (uint32_t)prog;
call_msg.rm_call.cb_vers = (uint32_t)vers;
/*
* pre-serialize the static part of the call msg and stash it away
*/
xdrmem_create(&xdrs, ct->ct_mcallc, MCALL_MSG_SIZE,
XDR_ENCODE);
if (!xdr_callhdr(&xdrs, &call_msg))
goto err;
ct->ct_mpos = XDR_GETPOS(&xdrs);
XDR_DESTROY(&xdrs);
ct->ct_waitchan = "rpcbck";
ct->ct_waitflag = 0;
cl->cl_refs = 1;
cl->cl_ops = &clnt_bck_ops;
cl->cl_private = ct;
cl->cl_auth = authnone_create();
TAILQ_INIT(&ct->ct_pending);
return (cl);
err:
if (cl) {
if (ct) {
mtx_destroy(&ct->ct_lock);
mem_free(ct, sizeof (struct ct_data));
}
if (cl)
mem_free(cl, sizeof (CLIENT));
}
return (NULL);
}
enum clnt_stat
clnt_bck_call(
CLIENT *cl, /* client handle */
struct rpc_callextra *ext, /* call metadata */
rpcproc_t proc, /* procedure number */
struct mbuf *args, /* pointer to args */
struct mbuf **resultsp, /* pointer to results */
struct timeval utimeout,
SVCXPRT *xprt)
{
struct ct_data *ct = (struct ct_data *) cl->cl_private;
AUTH *auth;
struct rpc_err *errp;
enum clnt_stat stat;
XDR xdrs;
struct rpc_msg reply_msg;
bool_t ok;
int nrefreshes = 2; /* number of times to refresh cred */
struct timeval timeout;
uint32_t xid;
struct mbuf *mreq = NULL, *results;
struct ct_request *cr;
int error;
cr = malloc(sizeof(struct ct_request), M_RPC, M_WAITOK);
mtx_lock(&ct->ct_lock);
if (ct->ct_closing || ct->ct_closed) {
mtx_unlock(&ct->ct_lock);
free(cr, M_RPC);
return (RPC_CANTSEND);
}
ct->ct_threads++;
if (ext) {
auth = ext->rc_auth;
errp = &ext->rc_err;
} else {
auth = cl->cl_auth;
errp = &ct->ct_error;
}
cr->cr_mrep = NULL;
cr->cr_error = 0;
if (ct->ct_wait.tv_usec == -1)
timeout = utimeout; /* use supplied timeout */
else
timeout = ct->ct_wait; /* use default timeout */
call_again:
mtx_assert(&ct->ct_lock, MA_OWNED);
ct->ct_xid++;
xid = ct->ct_xid;
mtx_unlock(&ct->ct_lock);
/*
* Leave space to pre-pend the record mark.
*/
mreq = m_gethdr(M_WAITOK, MT_DATA);
mreq->m_data += sizeof(uint32_t);
KASSERT(ct->ct_mpos + sizeof(uint32_t) <= MHLEN,
("RPC header too big"));
bcopy(ct->ct_mcallc, mreq->m_data, ct->ct_mpos);
mreq->m_len = ct->ct_mpos;
/*
* The XID is the first thing in the request.
*/
*mtod(mreq, uint32_t *) = htonl(xid);
xdrmbuf_create(&xdrs, mreq, XDR_ENCODE);
errp->re_status = stat = RPC_SUCCESS;
if ((!XDR_PUTINT32(&xdrs, &proc)) ||
(!AUTH_MARSHALL(auth, xid, &xdrs,
m_copym(args, 0, M_COPYALL, M_WAITOK)))) {
errp->re_status = stat = RPC_CANTENCODEARGS;
mtx_lock(&ct->ct_lock);
goto out;
}
mreq->m_pkthdr.len = m_length(mreq, NULL);
/*
* Prepend a record marker containing the packet length.
*/
M_PREPEND(mreq, sizeof(uint32_t), M_WAITOK);
*mtod(mreq, uint32_t *) =
htonl(0x80000000 | (mreq->m_pkthdr.len - sizeof(uint32_t)));
cr->cr_xid = xid;
mtx_lock(&ct->ct_lock);
/*
* Check to see if the client end has already started to close down
* the connection. The svc code will have set ct_error.re_status
* to RPC_CANTRECV if this is the case.
* If the client starts to close down the connection after this
* point, it will be detected later when cr_error is checked,
* since the request is in the ct_pending queue.
*/
if (ct->ct_error.re_status == RPC_CANTRECV) {
if (errp != &ct->ct_error) {
errp->re_errno = ct->ct_error.re_errno;
errp->re_status = RPC_CANTRECV;
}
stat = RPC_CANTRECV;
goto out;
}
TAILQ_INSERT_TAIL(&ct->ct_pending, cr, cr_link);
mtx_unlock(&ct->ct_lock);
/*
* sosend consumes mreq.
*/
sx_xlock(&xprt->xp_lock);
error = sosend(xprt->xp_socket, NULL, NULL, mreq, NULL, 0, curthread);
if (error != 0) printf("sosend=%d\n", error);
mreq = NULL;
if (error == EMSGSIZE) {
printf("emsgsize\n");
SOCKBUF_LOCK(&xprt->xp_socket->so_snd);
sbwait(&xprt->xp_socket->so_snd);
SOCKBUF_UNLOCK(&xprt->xp_socket->so_snd);
sx_xunlock(&xprt->xp_lock);
AUTH_VALIDATE(auth, xid, NULL, NULL);
mtx_lock(&ct->ct_lock);
TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
goto call_again;
}
sx_xunlock(&xprt->xp_lock);
reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL;
reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf;
reply_msg.acpted_rply.ar_verf.oa_length = 0;
reply_msg.acpted_rply.ar_results.where = NULL;
reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
mtx_lock(&ct->ct_lock);
if (error) {
TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
errp->re_errno = error;
errp->re_status = stat = RPC_CANTSEND;
goto out;
}
/*
* Check to see if we got an upcall while waiting for the
* lock. In both these cases, the request has been removed
* from ct->ct_pending.
*/
if (cr->cr_error) {
TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
errp->re_errno = cr->cr_error;
errp->re_status = stat = RPC_CANTRECV;
goto out;
}
if (cr->cr_mrep) {
TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
goto got_reply;
}
/*
* Hack to provide rpc-based message passing
*/
if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
errp->re_status = stat = RPC_TIMEDOUT;
goto out;
}
error = msleep(cr, &ct->ct_lock, ct->ct_waitflag, ct->ct_waitchan,
tvtohz(&timeout));
TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
if (error) {
/*
* The sleep returned an error so our request is still
* on the list. Turn the error code into an
* appropriate client status.
*/
errp->re_errno = error;
switch (error) {
case EINTR:
stat = RPC_INTR;
break;
case EWOULDBLOCK:
stat = RPC_TIMEDOUT;
break;
default:
stat = RPC_CANTRECV;
};
errp->re_status = stat;
goto out;
} else {
/*
* We were woken up by the svc thread. If the
* upcall had a receive error, report that,
* otherwise we have a reply.
*/
if (cr->cr_error) {
errp->re_errno = cr->cr_error;
errp->re_status = stat = RPC_CANTRECV;
goto out;
}
}
got_reply:
/*
* Now decode and validate the response. We need to drop the
* lock since xdr_replymsg may end up sleeping in malloc.
*/
mtx_unlock(&ct->ct_lock);
if (ext && ext->rc_feedback)
ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg);
xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE);
ok = xdr_replymsg(&xdrs, &reply_msg);
cr->cr_mrep = NULL;
if (ok) {
if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
(reply_msg.acpted_rply.ar_stat == SUCCESS))
errp->re_status = stat = RPC_SUCCESS;
else
stat = _seterr_reply(&reply_msg, errp);
if (stat == RPC_SUCCESS) {
results = xdrmbuf_getall(&xdrs);
if (!AUTH_VALIDATE(auth, xid,
&reply_msg.acpted_rply.ar_verf, &results)) {
errp->re_status = stat = RPC_AUTHERROR;
errp->re_why = AUTH_INVALIDRESP;
} else {
KASSERT(results,
("auth validated but no result"));
*resultsp = results;
}
} /* end successful completion */
/*
* If unsuccesful AND error is an authentication error
* then refresh credentials and try again, else break
*/
else if (stat == RPC_AUTHERROR)
/* maybe our credentials need to be refreshed ... */
if (nrefreshes > 0 && AUTH_REFRESH(auth, &reply_msg)) {
nrefreshes--;
XDR_DESTROY(&xdrs);
mtx_lock(&ct->ct_lock);
goto call_again;
}
/* end of unsuccessful completion */
/* end of valid reply message */
} else
errp->re_status = stat = RPC_CANTDECODERES;
XDR_DESTROY(&xdrs);
mtx_lock(&ct->ct_lock);
out:
mtx_assert(&ct->ct_lock, MA_OWNED);
KASSERT(stat != RPC_SUCCESS || *resultsp,
("RPC_SUCCESS without reply"));
if (mreq != NULL)
m_freem(mreq);
if (cr->cr_mrep != NULL)
m_freem(cr->cr_mrep);
ct->ct_threads--;
if (ct->ct_closing)
wakeup(ct);
mtx_unlock(&ct->ct_lock);
if (auth && stat != RPC_SUCCESS)
AUTH_VALIDATE(auth, xid, NULL, NULL);
free(cr, M_RPC);
return (stat);
}
static void
clnt_bck_geterr(CLIENT *cl, struct rpc_err *errp)
{
struct ct_data *ct = (struct ct_data *) cl->cl_private;
*errp = ct->ct_error;
}
static bool_t
clnt_bck_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
{
XDR xdrs;
bool_t dummy;
xdrs.x_op = XDR_FREE;
dummy = (*xdr_res)(&xdrs, res_ptr);
return (dummy);
}
/*ARGSUSED*/
static void
clnt_bck_abort(CLIENT *cl)
{
}
static bool_t
clnt_bck_control(CLIENT *cl, u_int request, void *info)
{
return (TRUE);
}
static void
clnt_bck_close(CLIENT *cl)
{
struct ct_data *ct = (struct ct_data *) cl->cl_private;
mtx_lock(&ct->ct_lock);
if (ct->ct_closed) {
mtx_unlock(&ct->ct_lock);
return;
}
if (ct->ct_closing) {
while (ct->ct_closing)
msleep(ct, &ct->ct_lock, 0, "rpcclose", 0);
KASSERT(ct->ct_closed, ("client should be closed"));
mtx_unlock(&ct->ct_lock);
return;
}
ct->ct_closing = FALSE;
ct->ct_closed = TRUE;
mtx_unlock(&ct->ct_lock);
wakeup(ct);
}
static void
clnt_bck_destroy(CLIENT *cl)
{
struct ct_data *ct = (struct ct_data *) cl->cl_private;
clnt_bck_close(cl);
mtx_destroy(&ct->ct_lock);
mem_free(ct, sizeof(struct ct_data));
if (cl->cl_netid && cl->cl_netid[0])
mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
if (cl->cl_tp && cl->cl_tp[0])
mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
mem_free(cl, sizeof(CLIENT));
}
/*
* This call is done by the svc code when a backchannel RPC reply is
* received.
*/
void
clnt_bck_svccall(void *arg, struct mbuf *mrep, uint32_t xid)
{
struct ct_data *ct = (struct ct_data *)arg;
struct ct_request *cr;
int foundreq;
mtx_lock(&ct->ct_lock);
ct->ct_upcallrefs++;
/*
* See if we can match this reply to a request.
*/
foundreq = 0;
TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) {
if (cr->cr_xid == xid) {
/*
* This one matches. We leave the reply mbuf list in
* cr->cr_mrep. Set the XID to zero so that we will
* ignore any duplicated replies.
*/
cr->cr_xid = 0;
cr->cr_mrep = mrep;
cr->cr_error = 0;
foundreq = 1;
wakeup(cr);
break;
}
}
ct->ct_upcallrefs--;
if (ct->ct_upcallrefs < 0)
panic("rpcvc svccall refcnt");
if (ct->ct_upcallrefs == 0)
wakeup(&ct->ct_upcallrefs);
mtx_unlock(&ct->ct_lock);
if (foundreq == 0)
m_freem(mrep);
}

View File

@ -37,6 +37,10 @@
*/
#define MCALL_MSG_SIZE 24
void clnt_bck_svccall(void *, struct mbuf *, uint32_t);
enum clnt_stat clnt_bck_call(CLIENT *, struct rpc_callextra *, rpcproc_t,
struct mbuf *, struct mbuf **, struct timeval, SVCXPRT *);
/*
* A pending RPC request which awaits a reply. Requests which have
* received their reply will have cr_xid set to zero and cr_mrep to

View File

@ -145,6 +145,7 @@ struct __rpc_svcthread;
* Server side transport handle. In the kernel, transports have a
* reference count which tracks the number of currently assigned
* worker threads plus one for the service pool's reference.
* For NFSv4.1 sessions, a reference is also held for a backchannel.
*/
typedef struct __rpc_svcxprt {
#ifdef _KERNEL
@ -774,6 +775,13 @@ extern SVCXPRT *svc_vc_create(SVCPOOL *, struct socket *,
extern SVCXPRT *svc_vc_create_backchannel(SVCPOOL *);
extern void *clnt_bck_create(struct socket *, const rpcprog_t, const rpcvers_t);
/*
* struct socket *; -- server transport socket
* const rpcprog_t prog; -- RPC program number
* const rpcvers_t vers; -- RPC program version
*/
/*
* Generic TLI create routine
*/

View File

@ -654,6 +654,7 @@ svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
struct socket* so = xprt->xp_socket;
XDR xdrs;
int error, rcvflag;
uint32_t xid_plus_direction[2];
/*
* Serialise access to the socket and our own record parsing
@ -672,6 +673,32 @@ svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
/* Process and return complete request in cd->mreq. */
if (cd->mreq != NULL && cd->resid == 0 && cd->eor) {
/*
* Now, check for a backchannel reply.
* The XID is in the first uint32_t of the reply
* and the message direction is the second one.
*/
if ((cd->mreq->m_len >= sizeof(xid_plus_direction) ||
m_length(cd->mreq, NULL) >=
sizeof(xid_plus_direction)) &&
xprt->xp_p2 != NULL) {
m_copydata(cd->mreq, 0,
sizeof(xid_plus_direction),
(char *)xid_plus_direction);
xid_plus_direction[0] =
ntohl(xid_plus_direction[0]);
xid_plus_direction[1] =
ntohl(xid_plus_direction[1]);
/* Check message direction. */
if (xid_plus_direction[1] == REPLY) {
clnt_bck_svccall(xprt->xp_p2,
cd->mreq,
xid_plus_direction[0]);
cd->mreq = NULL;
continue;
}
}
xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE);
cd->mreq = NULL;
@ -848,7 +875,6 @@ svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg,
}
XDR_DESTROY(&xdrs);
xprt->xp_p2 = NULL;
return (stat);
}