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:
parent
4fc0f18c20
commit
c59e4cc34d
@ -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
|
||||
|
144
sys/fs/nfs/nfs.h
144
sys/fs/nfs/nfs.h
@ -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.
|
||||
|
@ -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++);
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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) || \
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
593
sys/rpc/clnt_bck.c
Normal 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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user