summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs
diff options
context:
space:
mode:
authorVitaliy Gusev <gusev.vitaliy@gmail.com>2020-04-12 11:28:51 +0300
committerDan McDonald <danmcd@joyent.com>2021-04-22 10:41:50 -0400
commit6f57c9527c4e1e26e4dfb190459023ee084c1f52 (patch)
tree2d0f78548f2c0de66d9e704d8c804edfc72fcd9c /usr/src/uts/common/fs
parent043819558530b9580af0efc07bc0af452bcfcef5 (diff)
downloadillumos-joyent-6f57c9527c4e1e26e4dfb190459023ee084c1f52.tar.gz
preview of upstream nfsv4.x server support
Diffstat (limited to 'usr/src/uts/common/fs')
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_attr.c3
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_dispatch.c100
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv.c422
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv_attr.c62
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_state.c170
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_xdr.c227
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4x_dispatch.c177
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4x_srv.c1250
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4x_state.c576
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4x_xdr.c2935
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_server.c5
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_stats.c21
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_subr.c10
13 files changed, 5668 insertions, 290 deletions
diff --git a/usr/src/uts/common/fs/nfs/nfs4_attr.c b/usr/src/uts/common/fs/nfs/nfs4_attr.c
index c32a9526ec..820b804312 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_attr.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_attr.c
@@ -772,6 +772,9 @@ struct nfs4_ntov_map nfs4_ntov_map[] = {
xdr_u_longlong_t,
NULL, "fattr4_mounted_on_fileid" },
+ { FATTR4_SUPPATTR_EXCLCREAT_MASK_LOCAL, 0, FALSE, FALSE,
+ FATTR4_MOUNTED_ON_FILEID + 1, 0, xdr_bitmap4,
+ NULL, "fattr4_suppattr_exclcreat" },
};
uint_t nfs4_ntov_map_size = sizeof (nfs4_ntov_map) /
diff --git a/usr/src/uts/common/fs/nfs/nfs4_dispatch.c b/usr/src/uts/common/fs/nfs/nfs4_dispatch.c
index 1fdfd0f601..0988dea0ef 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_dispatch.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_dispatch.c
@@ -26,6 +26,7 @@
/*
* Copyright 2018 Nexenta Systems, Inc.
+ * Copyright 2020 RackTop Systems, Inc.
*/
#include <sys/systm.h>
@@ -40,7 +41,7 @@
#include <nfs/nfs_dispatch.h>
#include <nfs/nfs4_drc.h>
-#define NFS4_MAX_MINOR_VERSION 0
+#define NFS4_MAX_MINOR_VERSION 2
/*
* The default size of the duplicate request cache
@@ -372,43 +373,28 @@ rfs4_find_dr(struct svc_req *req, rfs4_drc_t *drc, rfs4_dupreq_t **dup)
*
*/
int
-rfs4_dispatch(struct rpcdisp *disp, struct svc_req *req, SVCXPRT *xprt,
- char *ap)
+rfs40_dispatch(struct svc_req *req, SVCXPRT *xprt, char *ap)
{
COMPOUND4res res_buf;
COMPOUND4res *rbp;
COMPOUND4args *cap;
- cred_t *cr = NULL;
int error = 0;
int dis_flags = 0;
int dr_stat = NFS4_NOT_DUP;
rfs4_dupreq_t *drp = NULL;
int rv;
+ struct compound_state cs;
nfs4_srv_t *nsrv4 = nfs4_get_srv();
rfs4_drc_t *nfs4_drc = nsrv4->nfs4_drc;
- ASSERT(disp);
-
- /*
- * Short circuit the RPC_NULL proc.
- */
- if (disp->dis_proc == rpc_null) {
- DTRACE_NFSV4_1(null__start, struct svc_req *, req);
- if (!svc_sendreply(xprt, xdr_void, NULL)) {
- DTRACE_NFSV4_1(null__done, struct svc_req *, req);
- svcerr_systemerr(xprt);
- return (1);
- }
- DTRACE_NFSV4_1(null__done, struct svc_req *, req);
- return (0);
- }
-
/* Only NFSv4 Compounds from this point onward */
rbp = &res_buf;
cap = (COMPOUND4args *)ap;
+ rfs4_init_compound_state(&cs);
+
/*
* Figure out the disposition of the whole COMPOUND
* and record it's IDEMPOTENTCY.
@@ -445,9 +431,11 @@ rfs4_dispatch(struct rpcdisp *disp, struct svc_req *req, SVCXPRT *xprt,
case NFS4_DUP_NEW:
curthread->t_flag |= T_DONTPEND;
/* NON-IDEMPOTENT proc call */
- rfs4_compound(cap, rbp, NULL, req, cr, &rv);
+ rfs4_compound(cap, rbp, &cs, req, &rv);
curthread->t_flag &= ~T_DONTPEND;
+ rfs4_fini_compound_state(&cs);
+
if (rv) /* short ckt sendreply on error */
return (rv);
@@ -478,9 +466,11 @@ rfs4_dispatch(struct rpcdisp *disp, struct svc_req *req, SVCXPRT *xprt,
} else {
curthread->t_flag |= T_DONTPEND;
/* IDEMPOTENT proc call */
- rfs4_compound(cap, rbp, NULL, req, cr, &rv);
+ rfs4_compound(cap, rbp, &cs, req, &rv);
curthread->t_flag &= ~T_DONTPEND;
+ rfs4_fini_compound_state(&cs);
+
if (rv) /* short ckt sendreply on error */
return (rv);
@@ -528,19 +518,11 @@ rfs4_dispatch(struct rpcdisp *disp, struct svc_req *req, SVCXPRT *xprt,
return (error);
}
-bool_t
-rfs4_minorvers_mismatch(struct svc_req *req, SVCXPRT *xprt, void *args)
+static int
+rfs4_send_minor_mismatch(SVCXPRT *xprt, COMPOUND4args *argsp)
{
- COMPOUND4args *argsp;
COMPOUND4res res_buf, *resp;
-
- if (req->rq_vers != 4)
- return (FALSE);
-
- argsp = (COMPOUND4args *)args;
-
- if (argsp->minorversion <= NFS4_MAX_MINOR_VERSION)
- return (FALSE);
+ int err = 0;
resp = &res_buf;
@@ -563,8 +545,26 @@ rfs4_minorvers_mismatch(struct svc_req *req, SVCXPRT *xprt, void *args)
DTRACE_PROBE2(nfss__e__minorvers_mismatch,
SVCXPRT *, xprt, char *, resp);
svcerr_systemerr(xprt);
+ err = 1;
}
rfs4_compound_free(resp);
+ return (err);
+}
+
+bool_t
+rfs4_minorvers_mismatch(struct svc_req *req, SVCXPRT *xprt, void *args)
+{
+ COMPOUND4args *argsp;
+
+ if (req->rq_vers != 4)
+ return (FALSE);
+
+ argsp = (COMPOUND4args *)args;
+
+ if (argsp->minorversion <= NFS4_MAX_MINOR_VERSION)
+ return (FALSE);
+
+ (void) rfs4_send_minor_mismatch(xprt, argsp);
return (TRUE);
}
@@ -619,3 +619,37 @@ rfs4_resource_err(struct svc_req *req, COMPOUND4args *argsp)
UTF8STRING_FREE(rbp->tag);
kmem_free(rbp->array, rbp->array_len * sizeof (nfs_resop4));
}
+
+/* ARGSUSED */
+int
+rfs4_dispatch(struct rpcdisp *disp, struct svc_req *req,
+ SVCXPRT *xprt, char *ap)
+{
+ COMPOUND4args *cmp;
+ int error = 0;
+
+ /*
+ * Handle the NULL Proc here
+ */
+ if (req->rq_proc == RFS_NULL) {
+ return (!svc_sendreply(xprt, xdr_void, NULL));
+ }
+
+ cmp = (COMPOUND4args *)ap;
+ ASSERT(cmp != NULL);
+
+ switch (cmp->minorversion) {
+ case 1:
+ case 2:
+ error = rfs4x_dispatch(req, xprt, ap);
+ break;
+
+ case 0:
+ error = rfs40_dispatch(req, xprt, ap);
+ break;
+
+ default:
+ error = rfs4_send_minor_mismatch(xprt, cmp);
+ }
+ return (error);
+}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv.c b/usr/src/uts/common/fs/nfs/nfs4_srv.c
index 757964eb84..acaf6a8f8b 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv.c
@@ -32,6 +32,7 @@
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
* Copyright 2019 Nexenta Systems, Inc.
* Copyright 2019 Nexenta by DDN, Inc.
+ * Copyright 2020 RackTop Systems, Inc.
*/
#include <sys/param.h>
@@ -185,6 +186,8 @@ static void rfs4_op_getfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
static void rfs4_op_getfh_free(nfs_resop4 *);
static void rfs4_op_illegal(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
struct compound_state *);
+static void rfs4_op_notsup(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
+ struct compound_state *);
static void rfs4_op_link(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
struct compound_state *);
static void rfs4_op_lock(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
@@ -247,12 +250,36 @@ static void rfs4_op_secinfo(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
struct compound_state *);
static void rfs4_op_secinfo_free(nfs_resop4 *);
+void rfs4x_op_exchange_id(nfs_argop4 *argop, nfs_resop4 *resop,
+ struct svc_req *req, struct compound_state *cs);
+void rfs4x_exchange_id_free(nfs_resop4 *);
+
+void rfs4x_op_create_session(nfs_argop4 *argop, nfs_resop4 *resop,
+ struct svc_req *req, struct compound_state *cs);
+
+void rfs4x_op_destroy_session(nfs_argop4 *argop, nfs_resop4 *resop,
+ struct svc_req *req, compound_state_t *cs);
+
+void rfs4x_op_sequence(nfs_argop4 *argop, nfs_resop4 *resop,
+ struct svc_req *req, struct compound_state *cs);
+
+void rfs4x_op_reclaim_complete(nfs_argop4 *argop, nfs_resop4 *resop,
+ struct svc_req *req, compound_state_t *cs);
+
+void rfs4x_op_destroy_clientid(nfs_argop4 *argop, nfs_resop4 *resop,
+ struct svc_req *req, compound_state_t *cs);
+
+void rfs4x_op_bind_conn_to_session(nfs_argop4 *argop, nfs_resop4 *resop,
+ struct svc_req *req, compound_state_t *cs);
+
+void rfs4x_op_secinfo_noname(nfs_argop4 *argop, nfs_resop4 *resop,
+ struct svc_req *req, compound_state_t *cs);
+
static nfsstat4 check_open_access(uint32_t, struct compound_state *,
struct svc_req *);
nfsstat4 rfs4_client_sysid(rfs4_client_t *, sysid_t *);
void rfs4_ss_clid(nfs4_srv_t *, rfs4_client_t *);
-
/*
* translation table for attrs
*/
@@ -410,6 +437,67 @@ static struct rfsv4disp rfsv4disptab[] = {
/* OP_RELEASE_LOCKOWNER = 39 */
{rfs4_op_release_lockowner, nullfree, 0},
+
+ /*
+ * NFSv4.1 operations
+ */
+
+ /* OP_BACKCHANNEL_CTL = 40 */
+ {rfs4_op_notsup, nullfree, 0},
+
+ /* OP_BIND_CONN_TO_SESSION = 41 */
+ {rfs4x_op_bind_conn_to_session, nullfree, 0},
+
+ /* OP_EXCHANGE_ID = 42 */
+ {rfs4x_op_exchange_id, rfs4x_exchange_id_free, 0},
+
+ /* OP_CREATE_SESSION = 43 */
+ {rfs4x_op_create_session, nullfree, 0},
+
+ /* OP_DESTROY_SESSION = 44 */
+ {rfs4x_op_destroy_session, nullfree, 0},
+
+ /* OP_FREE_STATEID = 45 */
+ {rfs4_op_notsup, nullfree, 0},
+
+ /* OP_GET_DIR_DELEGATION = 46 */
+ {rfs4_op_notsup, nullfree, 0},
+
+ /* OP_GETDEVICEINFO = 47 */
+ {rfs4_op_notsup, nullfree, 0},
+
+ /* OP_GETDEVICELIST = 48 */
+ {rfs4_op_notsup, nullfree, 0},
+
+ /* OP_LAYOUTCOMMIT = 49 */
+ {rfs4_op_notsup, nullfree, 0},
+
+ /* OP_LAYOUTGET = 50 */
+ {rfs4_op_notsup, nullfree, 0},
+
+ /* OP_LAYOUTRETURN = 51 */
+ {rfs4_op_notsup, nullfree, 0},
+
+ /* OP_SECINFO_NO_NAME = 52 */
+ {rfs4x_op_secinfo_noname, rfs4_op_secinfo_free, 0},
+
+ /* OP_SEQUENCE = 53 */
+ {rfs4x_op_sequence, nullfree, 0},
+
+ /* OP_SET_SSV = 54 */
+ {rfs4_op_notsup, nullfree, 0},
+
+ /* OP_TEST_STATEID = 55 */
+ {rfs4_op_notsup, nullfree, 0},
+
+ /* OP_WANT_DELEGATION = 56 */
+ {rfs4_op_notsup, nullfree, 0},
+
+ /* OP_DESTROY_CLIENTID = 57 */
+ {rfs4x_op_destroy_clientid, nullfree, 0},
+
+ /* OP_RECLAIM_COMPLETE = 58 */
+ {rfs4x_op_reclaim_complete, nullfree, 0},
};
static uint_t rfsv4disp_cnt = sizeof (rfsv4disptab) / sizeof (rfsv4disptab[0]);
@@ -463,8 +551,29 @@ static char *rfs4_op_string[] = {
"rfs4_op_verify",
"rfs4_op_write",
"rfs4_op_release_lockowner",
+ /* NFSv4.1 */
+ "backchannel_ctl",
+ "bind_conn_to_session",
+ "exchange_id",
+ "create_session",
+ "destroy_session",
+ "free_stateid",
+ "get_dir_delegation",
+ "getdeviceinfo",
+ "getdevicelist",
+ "layoutcommit",
+ "layoutget",
+ "layoutreturn",
+ "secinfo_no_name",
+ "sequence",
+ "set_ssv",
+ "test_stateid",
+ "want_delegation",
+ "destroy_clientid",
+ "reclaim_complete",
"rfs4_op_illegal"
};
+
#endif
void rfs4_ss_chkclid(nfs4_srv_t *, rfs4_client_t *);
@@ -662,6 +771,31 @@ rfs4_init_compound_state(struct compound_state *cs)
cs->fh.nfs_fh4_val = cs->fhbuf;
}
+/* Do cleanup of the compound_state */
+void
+rfs4_fini_compound_state(struct compound_state *cs)
+{
+ if (cs->vp) {
+ VN_RELE(cs->vp);
+ }
+ if (cs->saved_vp) {
+ VN_RELE(cs->saved_vp);
+ }
+ if (cs->cr) {
+ crfree(cs->cr);
+ }
+ if (cs->saved_fh.nfs_fh4_val) {
+ kmem_free(cs->saved_fh.nfs_fh4_val, NFS4_FHSIZE);
+ }
+
+ if (cs->basecr) {
+ crfree(cs->basecr);
+ }
+ if (cs->sp) {
+ rfs4x_session_rele(cs->sp);
+ }
+}
+
void
rfs4_grace_start(rfs4_servinst_t *sip)
{
@@ -697,6 +831,8 @@ rfs4_servinst_in_grace(rfs4_servinst_t *sip)
rw_enter(&sip->rwlock, RW_READER);
grace_expiry = sip->start_time + sip->grace_period;
+ if (sip->nreclaim == 0)
+ grace_expiry = 0;
rw_exit(&sip->rwlock);
return (((time_t)TICK_TO_SEC(ddi_get_lbolt())) < grace_expiry);
@@ -796,6 +932,7 @@ rfs4_servinst_create(nfs4_srv_t *nsrv4, int start_grace,
sip = kmem_alloc(sizeof (rfs4_servinst_t), KM_SLEEP);
rw_init(&sip->rwlock, NULL, RW_DEFAULT, NULL);
+ sip->nreclaim = 0;
sip->start_time = (time_t)0;
sip->grace_period = (time_t)0;
sip->next = NULL;
@@ -948,7 +1085,7 @@ in_flavor_list(int nfsnum, int *flavor_list, int count)
* export structure associated with the component.
*/
/* ARGSUSED */
-static nfsstat4
+nfsstat4
do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
{
int error, different_export = 0;
@@ -1274,9 +1411,14 @@ rfs4_op_secinfo(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
goto out;
}
-
*cs->statusp = resp->status = do_rfs4_op_secinfo(cs, name, resp);
+ if (resp->status == NFS4_OK && rfs4_has_session(cs)) {
+ /* See rfc 5661 section 2.6.3.1.1.8 and 18.29.3 */
+ VN_RELE(cs->vp);
+ cs->vp = NULL;
+ }
+
if (name != nm)
kmem_free(name, MAXPATHLEN + 1);
kmem_free(nm, len);
@@ -2521,6 +2663,14 @@ rfs4_op_illegal(nfs_argop4 *argop, nfs_resop4 *resop,
*cs->statusp = resp->status = NFS4ERR_OP_ILLEGAL;
}
+/* ARGSUSED */
+static void
+rfs4_op_notsup(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
+ struct compound_state *cs)
+{
+ *cs->statusp = *((nfsstat4 *)&(resop)->nfs_resop4_u) = NFS4ERR_NOTSUPP;
+}
+
/*
* link: args: SAVED_FH: file, CURRENT_FH: target directory
* res: status. If success - CURRENT_FH unchanged, return change_info
@@ -3257,7 +3407,7 @@ rfs4_op_read(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
}
if ((stat = rfs4_check_stateid(FREAD, vp, &args->stateid, FALSE,
- deleg, TRUE, &ct)) != NFS4_OK) {
+ deleg, TRUE, &ct, cs)) != NFS4_OK) {
*cs->statusp = resp->status = stat;
goto out;
}
@@ -5198,6 +5348,7 @@ do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
*/
goto done;
}
+
if ((sarg.vap->va_mask == 0) &&
(! (fattrp->attrmask & FATTR4_ACL_MASK))) {
/*
@@ -5233,7 +5384,7 @@ do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
if (sarg.vap->va_mask & AT_SIZE) {
trunc = (sarg.vap->va_size == 0);
status = rfs4_check_stateid(FWRITE, cs->vp, stateid,
- trunc, &cs->deleg, sarg.vap->va_mask & AT_SIZE, &ct);
+ trunc, &cs->deleg, sarg.vap->va_mask & AT_SIZE, &ct, cs);
if (status != NFS4_OK)
goto done;
} else {
@@ -5622,7 +5773,7 @@ rfs4_op_write(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
cr = cs->cr;
if ((stat = rfs4_check_stateid(FWRITE, vp, &args->stateid, FALSE,
- deleg, TRUE, &ct)) != NFS4_OK) {
+ deleg, TRUE, &ct, cs)) != NFS4_OK) {
*cs->statusp = resp->status = stat;
goto out;
}
@@ -5790,18 +5941,31 @@ out:
/* XXX put in a header file */
extern int sec_svc_getcred(struct svc_req *, cred_t *, caddr_t *, int *);
+static inline int
+rfs4_opnum_in_range(const compound_state_t *cs, int opnum)
+{
+ if (opnum < FIRST_NFS4_OP || opnum > LAST_NFS4_OP)
+ return (0);
+ else if (cs->minorversion == 0 && opnum > LAST_NFS40_OP)
+ return (0);
+ else if (cs->minorversion == 1 && opnum > LAST_NFS41_OP)
+ return (0);
+ else if (cs->minorversion == 2 && opnum > LAST_NFS42_OP)
+ return (0);
+ return (1);
+}
+
void
-rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi,
- struct svc_req *req, cred_t *cr, int *rv)
+rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, compound_state_t *cs,
+ struct svc_req *req, int *rv)
{
uint_t i;
- struct compound_state cs;
+ cred_t *cr;
nfs4_srv_t *nsrv4;
nfs_export_t *ne = nfs_get_export();
if (rv != NULL)
*rv = 0;
- rfs4_init_compound_state(&cs);
/*
* Form a reply tag by copying over the request tag.
*/
@@ -5815,53 +5979,41 @@ rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi,
resp->tag.utf8string_val = NULL;
}
- cs.statusp = &resp->status;
- cs.req = req;
+ cs->statusp = &resp->status;
+ cs->req = req;
+ cs->minorversion = args->minorversion;
resp->array = NULL;
resp->array_len = 0;
- /*
- * XXX for now, minorversion should be zero
- */
- if (args->minorversion != NFS4_MINORVERSION) {
- DTRACE_NFSV4_2(compound__start, struct compound_state *,
- &cs, COMPOUND4args *, args);
- resp->status = NFS4ERR_MINOR_VERS_MISMATCH;
- DTRACE_NFSV4_2(compound__done, struct compound_state *,
- &cs, COMPOUND4res *, resp);
- return;
- }
-
if (args->array_len == 0) {
resp->status = NFS4_OK;
return;
}
- ASSERT(exi == NULL);
- ASSERT(cr == NULL);
-
cr = crget();
ASSERT(cr != NULL);
- if (sec_svc_getcred(req, cr, &cs.principal, &cs.nfsflavor) == 0) {
+ if (sec_svc_getcred(req, cr, &cs->principal, &cs->nfsflavor) == 0) {
DTRACE_NFSV4_2(compound__start, struct compound_state *,
- &cs, COMPOUND4args *, args);
+ cs, COMPOUND4args *, args);
crfree(cr);
DTRACE_NFSV4_2(compound__done, struct compound_state *,
- &cs, COMPOUND4res *, resp);
+ cs, COMPOUND4res *, resp);
svcerr_badcred(req->rq_xprt);
if (rv != NULL)
*rv = 1;
return;
}
+
resp->array_len = args->array_len;
resp->array = kmem_zalloc(args->array_len * sizeof (nfs_resop4),
KM_SLEEP);
- cs.basecr = cr;
+ cs->op_len = args->array_len;
+ cs->basecr = cr;
nsrv4 = nfs4_get_srv();
- DTRACE_NFSV4_2(compound__start, struct compound_state *, &cs,
+ DTRACE_NFSV4_2(compound__start, struct compound_state *, cs,
COMPOUND4args *, args);
/*
@@ -5890,7 +6042,7 @@ rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi,
nsrv4->seen_first_compound = 1;
}
- for (i = 0; i < args->array_len && cs.cont; i++) {
+ for (i = 0; i < args->array_len && cs->cont; i++) {
nfs_argop4 *argop;
nfs_resop4 *resop;
uint_t op;
@@ -5901,7 +6053,8 @@ rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi,
resop->resop = argop->argop;
op = (uint_t)resop->resop;
- if (op < rfsv4disp_cnt) {
+ cs->op_pos = i;
+ if (op < rfsv4disp_cnt && rfs4_opnum_in_range(cs, op)) {
/*
* Count the individual ops here; NULL and COMPOUND
* are counted in common_dispatch()
@@ -5910,11 +6063,11 @@ rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi,
NFS4_DEBUG(rfs4_debug > 1,
(CE_NOTE, "Executing %s", rfs4_op_string[op]));
- (*rfsv4disptab[op].dis_proc)(argop, resop, req, &cs);
+ (*rfsv4disptab[op].dis_proc)(argop, resop, req, cs);
NFS4_DEBUG(rfs4_debug > 1, (CE_NOTE, "%s returned %d",
- rfs4_op_string[op], *cs.statusp));
- if (*cs.statusp != NFS4_OK)
- cs.cont = FALSE;
+ rfs4_op_string[op], *cs->statusp));
+ if (*cs->statusp != NFS4_OK)
+ cs->cont = FALSE;
} else {
/*
* This is effectively dead code since XDR code
@@ -5925,15 +6078,15 @@ rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi,
op = OP_ILLEGAL;
stat[OP_ILLEGAL_IDX].value.ui64++;
- rfs4_op_illegal(argop, resop, req, &cs);
- cs.cont = FALSE;
+ rfs4_op_illegal(argop, resop, req, cs);
+ cs->cont = FALSE;
}
/*
* If not at last op, and if we are to stop, then
* compact the results array.
*/
- if ((i + 1) < args->array_len && !cs.cont) {
+ if ((i + 1) < args->array_len && !cs->cont) {
nfs_resop4 *new_res = kmem_alloc(
(i+1) * sizeof (nfs_resop4), KM_SLEEP);
bcopy(resp->array,
@@ -5948,27 +6101,9 @@ rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi,
rw_exit(&ne->exported_lock);
- /*
- * clear exportinfo and vnode fields from compound_state before dtrace
- * probe, to avoid tracing residual values for path and share path.
- */
- if (cs.vp)
- VN_RELE(cs.vp);
- if (cs.saved_vp)
- VN_RELE(cs.saved_vp);
- cs.exi = cs.saved_exi = NULL;
- cs.vp = cs.saved_vp = NULL;
-
- DTRACE_NFSV4_2(compound__done, struct compound_state *, &cs,
+ DTRACE_NFSV4_2(compound__done, struct compound_state *, cs,
COMPOUND4res *, resp);
- if (cs.saved_fh.nfs_fh4_val)
- kmem_free(cs.saved_fh.nfs_fh4_val, NFS4_FHSIZE);
-
- if (cs.basecr)
- crfree(cs.basecr);
- if (cs.cr)
- crfree(cs.cr);
/*
* done with this compound request, free the label
*/
@@ -6094,7 +6229,7 @@ static void lock_print(char *str, int operation, struct flock64 *flk)
/*ARGSUSED*/
static bool_t
-creds_ok(cred_set_t cr_set, struct svc_req *req, struct compound_state *cs)
+creds_ok(cred_set_t *cr_set, struct svc_req *req, struct compound_state *cs)
{
return (TRUE);
}
@@ -6360,6 +6495,21 @@ check_open_access(uint32_t access, struct compound_state *cs,
return (NFS4_OK);
}
+static void
+rfs4_verifier_to_mtime(verifier4 v, timestruc_t *mtime)
+{
+ timespec32_t *time = (timespec32_t *)&v;
+
+ /*
+ * Ensure no time overflows. Assumes underlying
+ * filesystem supports at least 32 bits.
+ * Truncate nsec to usec resolution to allow valid
+ * compares even if the underlying filesystem truncates.
+ */
+ mtime->tv_sec = time->tv_sec % TIME32_MAX;
+ mtime->tv_nsec = (time->tv_nsec / 1000) * 1000;
+}
+
static nfsstat4
rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
change_info4 *cinfo, bitmap4 *attrset, clientid4 clientid)
@@ -6373,7 +6523,6 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
vnode_t *vp;
vattr_t bva, ava, iva, cva, *vap;
vnode_t *dvp;
- timespec32_t *mtime;
char *nm = NULL;
uint_t buflen;
bool_t created;
@@ -6386,6 +6535,9 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
bslabel_t *clabel;
struct sockaddr *ca;
char *name = NULL;
+ fattr4 *fattr = NULL;
+
+ ASSERT(*attrset == 0);
sarg.sbp = &sb;
sarg.is_referral = B_FALSE;
@@ -6411,11 +6563,17 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
}
}
+ if ((args->mode == EXCLUSIVE4 || args->mode == EXCLUSIVE4_1) &&
+ dvp->v_flag & V_XATTRDIR) {
+ /* prohibit EXCL create of named attributes */
+ return (NFS4ERR_INVAL);
+ }
+
/*
* Get the last component of path name in nm. cs will reference
* the including directory on success.
*/
- component = &args->open_claim4_u.file;
+ component = &args->claim.open_claim4_u.file;
status = utf8_dir_verify(component);
if (status != NFS4_OK)
return (status);
@@ -6448,12 +6606,17 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
case GUARDED4:
/*FALLTHROUGH*/
case UNCHECKED4:
+ case EXCLUSIVE4_1:
nfs4_ntov_table_init(&ntov);
ntov_table_init = TRUE;
- *attrset = 0;
+ if (args->mode == EXCLUSIVE4_1)
+ fattr = &args->createhow4_u.ch_createboth.cva_attrs;
+ else
+ fattr = &args->createhow4_u.createattrs;
+
status = do_rfs4_set_attrs(attrset,
- &args->createhow4_u.createattrs,
+ fattr,
cs, &sarg, &ntov, NFS4ATTR_SETIT);
if (status == NFS4_OK && (sarg.vap->va_mask & AT_TYPE) &&
@@ -6494,28 +6657,24 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
}
setsize = TRUE;
}
+ if (args->mode == EXCLUSIVE4_1) {
+ rfs4_verifier_to_mtime(
+ args->createhow4_u.ch_createboth.cva_verf,
+ &vap->va_mtime);
+ /* attrset will be set later */
+ fattr->attrmask |= FATTR4_TIME_MODIFY_MASK;
+ vap->va_mask |= AT_MTIME;
+ }
break;
case EXCLUSIVE4:
- /* prohibit EXCL create of named attributes */
- if (dvp->v_flag & V_XATTRDIR) {
- kmem_free(nm, buflen);
- *attrset = 0;
- return (NFS4ERR_INVAL);
- }
-
cva.va_mask = AT_TYPE | AT_MTIME | AT_MODE;
cva.va_type = VREG;
- /*
- * Ensure no time overflows. Assumes underlying
- * filesystem supports at least 32 bits.
- * Truncate nsec to usec resolution to allow valid
- * compares even if the underlying filesystem truncates.
- */
- mtime = (timespec32_t *)&args->createhow4_u.createverf;
- cva.va_mtime.tv_sec = mtime->tv_sec % TIME32_MAX;
- cva.va_mtime.tv_nsec = (mtime->tv_nsec / 1000) * 1000;
cva.va_mode = (mode_t)0;
+
+ rfs4_verifier_to_mtime(args->createhow4_u.createverf,
+ &cva.va_mtime);
+
vap = &cva;
/*
@@ -6551,7 +6710,7 @@ rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
trunc = (setsize && !created);
if (args->mode != EXCLUSIVE4) {
- bitmap4 createmask = args->createhow4_u.createattrs.attrmask;
+ bitmap4 createmask = fattr->attrmask;
/*
* True verification that object was created with correct
@@ -6993,6 +7152,16 @@ rfs4_do_open(struct compound_state *cs, struct svc_req *req,
/*ARGSUSED*/
static void
+rfs4_do_openfh(struct compound_state *cs, struct svc_req *req, OPEN4args *args,
+ rfs4_openowner_t *oo, OPEN4res *resp)
+{
+ /* cs->vp and cs->fh have been updated by putfh. */
+ rfs4_do_open(cs, req, oo, DELEG_ANY,
+ (args->share_access & 0xff), args->share_deny, resp, 0);
+}
+
+/*ARGSUSED*/
+static void
rfs4_do_opennull(struct compound_state *cs, struct svc_req *req,
OPEN4args *args, rfs4_openowner_t *oo, OPEN4res *resp)
{
@@ -7000,7 +7169,7 @@ rfs4_do_opennull(struct compound_state *cs, struct svc_req *req,
bitmap4 *attrset = &resp->attrset;
if (args->opentype == OPEN4_NOCREATE)
- resp->status = rfs4_lookupfile(&args->open_claim4_u.file,
+ resp->status = rfs4_lookupfile(&args->claim.open_claim4_u.file,
req, cs, args->share_access, cinfo);
else {
/* inhibit delegation grants during exclusive create */
@@ -7087,7 +7256,7 @@ rfs4_do_openprev(struct compound_state *cs, struct svc_req *req,
cinfo->atomic = FALSE;
rfs4_do_open(cs, req, oo,
- NFS4_DELEG4TYPE2REQTYPE(args->open_claim4_u.delegate_type),
+ NFS4_DELEG4TYPE2REQTYPE(args->claim.open_claim4_u.delegate_type),
args->share_access, args->share_deny, resp, 0);
}
@@ -7098,7 +7267,7 @@ rfs4_do_opendelcur(struct compound_state *cs, struct svc_req *req,
int error;
nfsstat4 status;
stateid4 stateid =
- args->open_claim4_u.delegate_cur_info.delegate_stateid;
+ args->claim.open_claim4_u.delegate_cur_info.delegate_stateid;
rfs4_deleg_state_t *dsp;
/*
@@ -7168,7 +7337,8 @@ rfs4_do_opendelprev(struct compound_state *cs, struct svc_req *req,
nfsace4 *ace;
/* Note we ignore oflags */
- resp->status = rfs4_lookupfile(&args->open_claim4_u.file_delegate_prev,
+ resp->status = rfs4_lookupfile(
+ &args->claim.open_claim4_u.file_delegate_prev,
req, cs, args->share_access, &resp->cinfo);
if (resp->status != NFS4_OK) {
@@ -7298,10 +7468,14 @@ rfs4_check_seqid(seqid4 seqid, nfs_resop4 *lastop,
static rfs4_chkseq_t
-rfs4_check_open_seqid(seqid4 seqid, rfs4_openowner_t *op, nfs_resop4 *resop)
+rfs4_check_open_seqid(seqid4 seqid, rfs4_openowner_t *op, nfs_resop4 *resop,
+ const compound_state_t *cs)
{
rfs4_chkseq_t rc;
+ if (rfs4_has_session(cs))
+ return (NFS4_CHKSEQ_OKAY);
+
rfs4_dbe_lock(op->ro_dbe);
rc = rfs4_check_seqid(op->ro_open_seqid, &op->ro_reply, seqid, resop,
TRUE);
@@ -7347,7 +7521,7 @@ rfs4_op_open(nfs_argop4 *argop, nfs_resop4 *resop,
OPEN4args *args = &argop->nfs_argop4_u.opopen;
OPEN4res *resp = &resop->nfs_resop4_u.opopen;
open_owner4 *owner = &args->owner;
- open_claim_type4 claim = args->claim;
+ open_claim_type4 claim = args->claim.claim;
rfs4_client_t *cp;
rfs4_openowner_t *oo;
bool_t create;
@@ -7362,6 +7536,10 @@ rfs4_op_open(nfs_argop4 *argop, nfs_resop4 *resop,
goto end;
}
+ /* rfc5661 section 18.16.3 */
+ if (rfs4_has_session(cs))
+ owner->clientid = cs->client->rc_clientid;
+
/*
* Need to check clientid and lease expiration first based on
* error ordering and incrementing sequence id.
@@ -7394,6 +7572,13 @@ retry:
goto end;
}
+ /*
+ * OPEN_CONFIRM must not be implemented in v4.1
+ */
+ if (rfs4_has_session(cs)) {
+ oo->ro_need_confirm = FALSE;
+ }
+
/* Hold off access to the sequence space while the open is done */
rfs4_sw_enter(&oo->ro_sw);
@@ -7402,7 +7587,7 @@ retry:
* the sequence id.
*/
if (!create && !oo->ro_postpone_confirm) {
- switch (rfs4_check_open_seqid(args->seqid, oo, resop)) {
+ switch (rfs4_check_open_seqid(args->seqid, oo, resop, cs)) {
case NFS4_CHKSEQ_BAD:
if ((args->seqid > oo->ro_open_seqid) &&
oo->ro_need_confirm) {
@@ -7434,7 +7619,8 @@ retry:
}
/* Grace only applies to regular-type OPENs */
if (rfs4_clnt_in_grace(cp) &&
- (claim == CLAIM_NULL || claim == CLAIM_DELEGATE_CUR)) {
+ (claim == CLAIM_NULL || claim == CLAIM_DELEGATE_CUR ||
+ claim == CLAIM_FH)) {
*cs->statusp = resp->status = NFS4ERR_GRACE;
goto out;
}
@@ -7512,6 +7698,9 @@ retry:
case CLAIM_DELEGATE_PREV:
rfs4_do_opendelprev(cs, req, args, oo, resp);
break;
+ case CLAIM_FH:
+ rfs4_do_openfh(cs, req, args, oo, resp);
+ break;
default:
resp->status = NFS4ERR_INVAL;
break;
@@ -7636,6 +7825,8 @@ rfs4_op_open_confirm(nfs_argop4 *argop, nfs_resop4 *resop,
DTRACE_NFSV4_2(op__open__confirm__start, struct compound_state *, cs,
OPEN_CONFIRM4args *, args);
+ ASSERT(!rfs4_has_session(cs));
+
if (cs->vp == NULL) {
*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
goto out;
@@ -7663,10 +7854,10 @@ rfs4_op_open_confirm(nfs_argop4 *argop, nfs_resop4 *resop,
/* hold off other access to open_owner while we tinker */
rfs4_sw_enter(&sp->rs_owner->ro_sw);
- switch (rfs4_check_stateid_seqid(sp, &args->open_stateid)) {
+ switch (rfs4_check_stateid_seqid(sp, &args->open_stateid, cs)) {
case NFS4_CHECK_STATEID_OKAY:
if (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
- resop) != 0) {
+ resop, cs) != 0) {
*cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
break;
}
@@ -7692,7 +7883,7 @@ rfs4_op_open_confirm(nfs_argop4 *argop, nfs_resop4 *resop,
break;
case NFS4_CHECK_STATEID_REPLAY:
switch (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
- resop)) {
+ resop, cs)) {
case NFS4_CHKSEQ_OKAY:
/*
* This is replayed stateid; if seqid matches
@@ -7714,7 +7905,7 @@ rfs4_op_open_confirm(nfs_argop4 *argop, nfs_resop4 *resop,
break;
case NFS4_CHECK_STATEID_UNCONFIRMED:
if (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
- resop) != NFS4_CHKSEQ_OKAY) {
+ resop, cs) != NFS4_CHKSEQ_OKAY) {
*cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
break;
}
@@ -7783,10 +7974,10 @@ rfs4_op_open_downgrade(nfs_argop4 *argop, nfs_resop4 *resop,
/* hold off other access to open_owner while we tinker */
rfs4_sw_enter(&sp->rs_owner->ro_sw);
- switch (rfs4_check_stateid_seqid(sp, &args->open_stateid)) {
+ switch (rfs4_check_stateid_seqid(sp, &args->open_stateid, cs)) {
case NFS4_CHECK_STATEID_OKAY:
if (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
- resop) != NFS4_CHKSEQ_OKAY) {
+ resop, cs) != NFS4_CHKSEQ_OKAY) {
*cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
goto end;
}
@@ -7807,9 +7998,11 @@ rfs4_op_open_downgrade(nfs_argop4 *argop, nfs_resop4 *resop,
*cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
goto end;
case NFS4_CHECK_STATEID_REPLAY:
+ ASSERT(!rfs4_has_session(cs));
+
/* Check the sequence id for the open owner */
switch (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
- resop)) {
+ resop, cs)) {
case NFS4_CHKSEQ_OKAY:
/*
* This is replayed stateid; if seqid matches
@@ -8098,7 +8291,7 @@ retry:
*/
if (cp_confirmed) {
/* If creds don't match then client identifier is inuse */
- if (!creds_ok(cp_confirmed->rc_cr_set, req, cs)) {
+ if (!creds_ok(&cp_confirmed->rc_cr_set, req, cs)) {
rfs4_cbinfo_t *cbp;
/*
* Some one else has established this client
@@ -8260,7 +8453,7 @@ rfs4_op_setclientid_confirm(nfs_argop4 *argop, nfs_resop4 *resop,
goto out;
}
- if (!creds_ok(cp, req, cs)) {
+ if (!creds_ok(&cp->rc_cr_set, req, cs)) {
*cs->statusp = res->status = NFS4ERR_CLID_INUSE;
rfs4_client_rele(cp);
goto out;
@@ -8352,10 +8545,10 @@ rfs4_op_close(nfs_argop4 *argop, nfs_resop4 *resop,
/* hold off other access to open_owner while we tinker */
rfs4_sw_enter(&sp->rs_owner->ro_sw);
- switch (rfs4_check_stateid_seqid(sp, &args->open_stateid)) {
+ switch (rfs4_check_stateid_seqid(sp, &args->open_stateid, cs)) {
case NFS4_CHECK_STATEID_OKAY:
if (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
- resop) != NFS4_CHKSEQ_OKAY) {
+ resop, cs) != NFS4_CHKSEQ_OKAY) {
*cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
goto end;
}
@@ -8376,9 +8569,11 @@ rfs4_op_close(nfs_argop4 *argop, nfs_resop4 *resop,
*cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
goto end;
case NFS4_CHECK_STATEID_REPLAY:
+ ASSERT(!rfs4_has_session(cs));
+
/* Check the sequence id for the open owner */
switch (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
- resop)) {
+ resop, cs)) {
case NFS4_CHKSEQ_OKAY:
/*
* This is replayed stateid; if seqid matches
@@ -8911,7 +9106,7 @@ rfs4_op_lock(nfs_argop4 *argop, nfs_resop4 *resop,
/* hold off other access to open_owner while we tinker */
rfs4_sw_enter(&sp->rs_owner->ro_sw);
- switch (rc = rfs4_check_stateid_seqid(sp, stateid)) {
+ switch (rc = rfs4_check_stateid_seqid(sp, stateid, cs)) {
case NFS4_CHECK_STATEID_OLD:
*cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
goto end;
@@ -8928,7 +9123,12 @@ rfs4_op_lock(nfs_argop4 *argop, nfs_resop4 *resop,
*cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
goto end;
case NFS4_CHECK_STATEID_OKAY:
+ if (rfs4_has_session(cs))
+ break;
+ /* FALLTHROUGH */
case NFS4_CHECK_STATEID_REPLAY:
+ ASSERT(!rfs4_has_session(cs));
+
switch (rfs4_check_olo_seqid(olo->open_seqid,
sp->rs_owner, resop)) {
case NFS4_CHKSEQ_OKAY:
@@ -8995,7 +9195,7 @@ rfs4_op_lock(nfs_argop4 *argop, nfs_resop4 *resop,
* not appropriate. The client should be using the
* existing lock_owner branch.
*/
- if (dup_lock == FALSE && create == FALSE) {
+ if (!rfs4_has_session(cs) && !dup_lock && !create) {
if (lsp->rls_lock_completed == TRUE) {
*cs->statusp =
resp->status = NFS4ERR_BAD_SEQID;
@@ -9087,12 +9287,15 @@ rfs4_op_lock(nfs_argop4 *argop, nfs_resop4 *resop,
rfs4_sw_enter(&lsp->rls_sw);
ls_sw_held = TRUE;
- switch (rfs4_check_lo_stateid_seqid(lsp, stateid)) {
+ switch (rfs4_check_lo_stateid_seqid(lsp, stateid, cs)) {
/*
* The stateid looks like it was okay (expected to be
* the next one)
*/
case NFS4_CHECK_STATEID_OKAY:
+ if (rfs4_has_session(cs))
+ break;
+
/*
* The sequence id is now checked. Determine
* if this is a replay or if it is in the
@@ -9152,6 +9355,8 @@ rfs4_op_lock(nfs_argop4 *argop, nfs_resop4 *resop,
*cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
goto end;
case NFS4_CHECK_STATEID_REPLAY:
+ ASSERT(!rfs4_has_session(cs));
+
switch (rfs4_check_lock_seqid(
args->locker.locker4_u.lock_owner.lock_seqid,
lsp, resop)) {
@@ -9317,8 +9522,11 @@ rfs4_op_locku(nfs_argop4 *argop, nfs_resop4 *resop,
/* hold off other access to lsp while we tinker */
rfs4_sw_enter(&lsp->rls_sw);
- switch (rfs4_check_lo_stateid_seqid(lsp, stateid)) {
+ switch (rfs4_check_lo_stateid_seqid(lsp, stateid, cs)) {
case NFS4_CHECK_STATEID_OKAY:
+ if (rfs4_has_session(cs))
+ break;
+
if (rfs4_check_lock_seqid(args->seqid, lsp, resop)
!= NFS4_CHKSEQ_OKAY) {
*cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
@@ -9338,6 +9546,8 @@ rfs4_op_locku(nfs_argop4 *argop, nfs_resop4 *resop,
*cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
goto end;
case NFS4_CHECK_STATEID_REPLAY:
+ ASSERT(!rfs4_has_session(cs));
+
switch (rfs4_check_lock_seqid(args->seqid, lsp, resop)) {
case NFS4_CHKSEQ_OKAY:
/*
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c b/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
index a9ee217a8b..a558c48466 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
@@ -26,6 +26,7 @@
/*
* Copyright 2018 Nexenta Systems, Inc.
+ * Copyright 2020 RackTop Systems, Inc.
*/
#include <sys/systm.h>
@@ -126,6 +127,24 @@ static int rfs4_fattr4_time_modify_set();
/*
* Initialize the supported attributes
*/
+bitmap4 supported_attrs[3];
+
+static void
+init_supported_attrs()
+{
+ bitmap4 supported = rfs4_supported_attrs;
+
+ supported_attrs[0] = supported_attrs[1] = supported_attrs[2] =
+ rfs4_supported_attrs;
+
+ /* restrict to nfsv4.0 */
+ supported_attrs[0] &= ~(FATTR4_SUPPATTR_EXCLCREAT_MASK_LOCAL |
+ FATTR4_SEC_LABEL_MASK_LOCAL);
+
+ /* restrict to nfsv4.1 */
+ supported_attrs[1] &= ~FATTR4_SEC_LABEL_MASK_LOCAL;
+}
+
void
rfs4_attr_init()
{
@@ -143,6 +162,7 @@ rfs4_attr_init()
cs.vp = rootvp;
cs.fh.nfs_fh4_val = NULL;
cs.cr = kcred;
+ cs.minorversion = 2;
/*
* Get all the supported attributes
@@ -169,6 +189,8 @@ rfs4_attr_init()
rfs4_supported_attrs |= nfs4_ntov_map[i].fbit;
}
}
+
+ init_supported_attrs();
}
/*
@@ -219,6 +241,7 @@ rfs4_fattr4_supported_attrs(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
union nfs4_attr_u *na)
{
int error = 0;
+ bitmap4 supported = supported_attrs[sarg->cs->minorversion];
switch (cmd) {
case NFS4ATTR_SUPPORTED:
@@ -226,7 +249,7 @@ rfs4_fattr4_supported_attrs(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
error = EINVAL;
break; /* this attr is supported */
case NFS4ATTR_GETIT:
- na->supported_attrs = rfs4_supported_attrs;
+ na->supported_attrs = supported;
break;
case NFS4ATTR_SETIT:
/*
@@ -238,7 +261,7 @@ rfs4_fattr4_supported_attrs(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
/*
* Compare the input bitmap to the server's bitmap
*/
- if (na->supported_attrs != rfs4_supported_attrs) {
+ if (na->supported_attrs != supported) {
error = -1; /* no match */
}
break;
@@ -2814,6 +2837,40 @@ rfs4_fattr4_time_modify_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
return (error);
}
+/* ARGSUSED */
+static int
+rfs4_fattr4_suppattr_exclcreat(nfs4_attr_cmd_t cmd,
+ struct nfs4_svgetit_arg *sarg, union nfs4_attr_u *na)
+{
+ int error = 0;
+
+ /* Not supported for nfs4.0 */
+ if (sarg->cs->minorversion == 0)
+ return (ENOTSUP);
+
+ switch (cmd) {
+ case NFS4ATTR_SUPPORTED:
+ if (sarg->op == NFS4ATTR_SETIT)
+ error = EINVAL;
+ break; /* this attr is supported */
+ case NFS4ATTR_GETIT:
+ na->supp_exclcreat = RFS4_SUPPATTR_EXCLCREAT;
+ break;
+ case NFS4ATTR_SETIT:
+ /*
+ * read-only attr
+ */
+ error = EINVAL;
+ break;
+ case NFS4ATTR_VERIT:
+ if (na->supp_exclcreat != RFS4_SUPPATTR_EXCLCREAT)
+ error = -1; /* no match */
+ break;
+ case NFS4ATTR_FREEIT:
+ break;
+ }
+ return (error);
+}
static void
rfs4_ntov_init(void)
@@ -2875,4 +2932,5 @@ rfs4_ntov_init(void)
nfs4_ntov_map[53].sv_getit = rfs4_fattr4_time_modify;
nfs4_ntov_map[54].sv_getit = rfs4_fattr4_time_modify_set;
nfs4_ntov_map[55].sv_getit = rfs4_fattr4_mounted_on_fileid;
+ nfs4_ntov_map[56].sv_getit = rfs4_fattr4_suppattr_exclcreat;
}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_state.c b/usr/src/uts/common/fs/nfs/nfs4_state.c
index b95dd6fb02..582813bf93 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_state.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_state.c
@@ -26,6 +26,7 @@
/*
* Copyright 2018 Nexenta Systems, Inc.
* Copyright 2019 Nexenta by DDN, Inc.
+ * Copyright 2020 RackTop Systems, Inc.
*/
#include <sys/systm.h>
@@ -595,6 +596,31 @@ rfs4_ss_getstate(vnode_t *dvp, rfs4_ss_pn_t *ss_pn)
#define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
/*
+ * Check whether list @head already contains the @client
+ * This protects against counting the same client twice.
+ */
+static bool_t
+rfs4_ss_has_client(rfs4_oldstate_t *head, nfs_client_id4 *client)
+{
+ rfs4_oldstate_t *p;
+
+ for (p = head->next; p != head; p = p->next) {
+ nfs_client_id4 *m = &p->cl_id4;
+
+ if (m->id_len != client->id_len)
+ continue;
+
+ if (bcmp(m->id_val, client->id_val, client->id_len) == 0)
+ continue;
+
+ /* client ids match */
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+/*
* Add entries from statedir to supplied oldstate list.
* Optionally, move all entries from statedir -> destdir.
*/
@@ -610,6 +636,7 @@ rfs4_ss_oldstate(rfs4_oldstate_t *oldstate, char *statedir, char *destdir)
struct uio uio;
struct dirent64 *dep;
offset_t dirchunk_offset = 0;
+ unsigned int nclients = 0;
/*
* open the state directory
@@ -670,6 +697,11 @@ rfs4_ss_oldstate(rfs4_oldstate_t *oldstate, char *statedir, char *destdir)
} else {
cl_ss->ss_pn = ss_pn;
}
+
+ if (!rfs4_ss_has_client(oldstate,
+ &cl_ss->cl_id4))
+ nclients++;
+
insque(cl_ss, oldstate);
} else {
rfs4_ss_pnfree(ss_pn);
@@ -682,6 +714,12 @@ out:
VN_RELE(dvp);
if (dirt)
kmem_free((caddr_t)dirt, RFS4_SS_DIRSIZE);
+
+ if (nclients > 0) {
+ nfs4_srv_t *nsrv4 = nfs4_get_srv();
+
+ atomic_add_32(&(nsrv4->nfs4_cur_servinst->nreclaim), nclients);
+ }
}
static void
@@ -1181,6 +1219,9 @@ rfs4_state_g_init()
/* CSTYLED */
rfs4_delegstID_mem_cache = nfs4_init_mem_cache("DelegStateID_entry_cache", 2, sizeof (rfs4_deleg_state_t), 7);
+ /* CSTYLED */
+ (void) nfs4_init_mem_cache("Session_entry_cache", 1, sizeof (rfs4_session_t), 8);
+
rfs4_client_clrst = rfs4_clear_client_state;
}
@@ -1480,6 +1521,8 @@ rfs4_state_zone_init(nfs4_srv_t *nsrv4)
deleg_state_compare,
deleg_state_mkkey, FALSE);
+ rfs4x_state_init_locked(nsrv4);
+
mutex_exit(&nsrv4->state_lock);
/*
@@ -1516,6 +1559,8 @@ rfs4_state_zone_fini()
return;
}
+ rfs4x_state_fini(nsrv4);
+
/* destroy server instances and current instance ptr */
rfs4_servinst_destroy_all(nsrv4);
@@ -1720,6 +1765,8 @@ rfs4_client_destroy(rfs4_entry_t u_entry)
cv_destroy(cp->rc_cbinfo.cb_cv_nullcaller);
list_destroy(&cp->rc_openownerlist);
+ list_destroy(&cp->rc_sessions);
+
/* free callback info */
rfs4_cbinfo_free(&cp->rc_cbinfo);
@@ -1738,6 +1785,8 @@ rfs4_client_destroy(rfs4_entry_t u_entry)
if (cp->rc_sysidt != LM_NOSYSID)
lm_free_sysidt(cp->rc_sysidt);
+
+ rfs4_free_cred_set(&cp->rc_cr_set);
}
static bool_t
@@ -1786,6 +1835,7 @@ rfs4_client_create(rfs4_entry_t u_entry, void *arg)
/* We need the client to ack us */
cp->rc_need_confirm = TRUE;
cp->rc_cp_confirmed = NULL;
+ cp->rc_destroying = FALSE;
/* TRUE all the time until the callback path actually fails */
cp->rc_cbinfo.cb_notified_of_cb_path_down = TRUE;
@@ -1793,13 +1843,16 @@ rfs4_client_create(rfs4_entry_t u_entry, void *arg)
/* Initialize the access time to now */
cp->rc_last_access = gethrestime_sec();
- cp->rc_cr_set = NULL;
+ bzero(&cp->rc_cr_set, sizeof (cred_set_t));
cp->rc_sysidt = LM_NOSYSID;
list_create(&cp->rc_openownerlist, sizeof (rfs4_openowner_t),
offsetof(rfs4_openowner_t, ro_node));
+ list_create(&cp->rc_sessions, sizeof (rfs4_session_t),
+ offsetof(rfs4_session_t, sn_node));
+
/* set up the callback control structure */
cp->rc_cbinfo.cb_state = CB_UNINIT;
mutex_init(cp->rc_cbinfo.cb_lock, NULL, MUTEX_DEFAULT, NULL);
@@ -1815,6 +1868,12 @@ rfs4_client_create(rfs4_entry_t u_entry, void *arg)
rfs4_servinst_assign(nsrv4, cp, nsrv4->nfs4_cur_servinst);
rfs4_dbe_rele(cp->rc_dbe);
+ /*
+ * NFSv4.1: See rfc5661, Section 18.36.4, eir_sequenceid
+ */
+ cp->rc_contrived.xi_sid = 1;
+ cp->rc_contrived.cs_status = NFS4ERR_SEQ_MISORDERED;
+
return (TRUE);
}
@@ -2202,7 +2261,6 @@ rfs4_openowner_create(rfs4_entry_t u_entry, void *arg)
oo->ro_open_seqid = seqid;
bzero(&oo->ro_reply, sizeof (nfs_resop4));
oo->ro_client = cp;
- oo->ro_cr_set = NULL;
list_create(&oo->ro_statelist, sizeof (rfs4_state_t),
offsetof(rfs4_state_t, rs_node));
@@ -3337,6 +3395,7 @@ rfs4_client_close(rfs4_client_t *cp)
rfs4_dbe_unlock(cp->rc_dbe);
rfs4_client_state_remove(cp);
+ rfs4x_client_session_remove(cp);
/* Release the client */
rfs4_client_rele(cp);
@@ -3461,19 +3520,26 @@ rfs4_get_state(stateid4 *stateid, rfs4_state_t **spp,
}
int
-rfs4_check_stateid_seqid(rfs4_state_t *sp, stateid4 *stateid)
+rfs4_check_stateid_seqid(rfs4_state_t *sp, stateid4 *stateid,
+ const compound_state_t *cs)
{
stateid_t *id = (stateid_t *)stateid;
+ bool_t has_session = rfs4_has_session(cs);
if (rfs4_lease_expired(sp->rs_owner->ro_client))
return (NFS4_CHECK_STATEID_EXPIRED);
+ if (has_session && id->bits.chgseq == 0)
+ return (NFS4_CHECK_STATEID_OKAY);
+
/* Stateid is some time in the future - that's bad */
if (sp->rs_stateid.bits.chgseq < id->bits.chgseq)
return (NFS4_CHECK_STATEID_BAD);
- if (sp->rs_stateid.bits.chgseq == id->bits.chgseq + 1)
+ if (!has_session &&
+ sp->rs_stateid.bits.chgseq == id->bits.chgseq + 1) {
return (NFS4_CHECK_STATEID_REPLAY);
+ }
/* Stateid is some time in the past - that's old */
if (sp->rs_stateid.bits.chgseq > id->bits.chgseq)
@@ -3490,19 +3556,26 @@ rfs4_check_stateid_seqid(rfs4_state_t *sp, stateid4 *stateid)
}
int
-rfs4_check_lo_stateid_seqid(rfs4_lo_state_t *lsp, stateid4 *stateid)
+rfs4_check_lo_stateid_seqid(rfs4_lo_state_t *lsp, stateid4 *stateid,
+ const compound_state_t *cs)
{
stateid_t *id = (stateid_t *)stateid;
+ bool_t has_session = rfs4_has_session(cs);
if (rfs4_lease_expired(lsp->rls_state->rs_owner->ro_client))
return (NFS4_CHECK_STATEID_EXPIRED);
+ if (has_session && id->bits.chgseq == 0)
+ return (NFS4_CHECK_STATEID_OKAY);
+
/* Stateid is some time in the future - that's bad */
if (lsp->rls_lockid.bits.chgseq < id->bits.chgseq)
return (NFS4_CHECK_STATEID_BAD);
- if (lsp->rls_lockid.bits.chgseq == id->bits.chgseq + 1)
+ if (!has_session &&
+ lsp->rls_lockid.bits.chgseq == id->bits.chgseq + 1) {
return (NFS4_CHECK_STATEID_REPLAY);
+ }
/* Stateid is some time in the past - that's old */
if (lsp->rls_lockid.bits.chgseq > id->bits.chgseq)
@@ -3663,6 +3736,24 @@ out:
return (stat);
}
+static nfsstat4
+check_state_seqid(stateid_t *st, stateid_t *in, bool_t has_session)
+{
+ /* rfc56661, section 8.2.2, "seqid to zero" */
+ if (has_session && in->bits.chgseq == 0)
+ return (NFS4_OK);
+
+ /* Seqid in the future? - that's bad */
+ if (st->bits.chgseq < in->bits.chgseq)
+ return (NFS4ERR_BAD_STATEID);
+
+ /* Seqid in the past? - that's old */
+ if (st->bits.chgseq > in->bits.chgseq)
+ return (NFS4ERR_OLD_STATEID);
+
+ return (NFS4_OK);
+}
+
/*
* Given the I/O mode (FREAD or FWRITE), the vnode, the stateid and whether
* the file is being truncated, return NFS4_OK if allowed or appropriate
@@ -3681,7 +3772,7 @@ out:
nfsstat4
rfs4_check_stateid(int mode, vnode_t *vp,
stateid4 *stateid, bool_t trunc, bool_t *deleg,
- bool_t do_access, caller_context_t *ct)
+ bool_t do_access, caller_context_t *ct, compound_state_t *cs)
{
rfs4_file_t *fp;
bool_t create = FALSE;
@@ -3690,6 +3781,7 @@ rfs4_check_stateid(int mode, vnode_t *vp,
rfs4_lo_state_t *lsp;
stateid_t *id = (stateid_t *)stateid;
nfsstat4 stat = NFS4_OK;
+ bool_t use_ss = rfs4_has_session(cs);
if (ct != NULL) {
ct->cc_sysid = 0;
@@ -3702,6 +3794,7 @@ rfs4_check_stateid(int mode, vnode_t *vp,
fp = rfs4_findfile(vp, NULL, &create);
if (fp == NULL)
return (NFS4_OK);
+
if (fp->rf_dinfo.rd_dtype == OPEN_DELEGATE_NONE) {
rfs4_file_rele(fp);
return (NFS4_OK);
@@ -3718,6 +3811,7 @@ rfs4_check_stateid(int mode, vnode_t *vp,
stat = rfs4_get_all_state(stateid, &sp, &dsp, &lsp);
if (stat != NFS4_OK)
return (stat);
+
if (lsp != NULL) {
/* Is associated server instance in its grace period? */
if (rfs4_clnt_in_grace(lsp->rls_locker->rl_client)) {
@@ -3726,31 +3820,24 @@ rfs4_check_stateid(int mode, vnode_t *vp,
rfs4_state_rele_nounlock(sp);
return (NFS4ERR_GRACE);
}
- if (id->bits.type == LOCKID) {
- /* Seqid in the future? - that's bad */
- if (lsp->rls_lockid.bits.chgseq <
- id->bits.chgseq) {
- rfs4_lo_state_rele(lsp, FALSE);
- if (sp != NULL)
- rfs4_state_rele_nounlock(sp);
- return (NFS4ERR_BAD_STATEID);
- }
- /* Seqid in the past? - that's old */
- if (lsp->rls_lockid.bits.chgseq >
- id->bits.chgseq) {
- rfs4_lo_state_rele(lsp, FALSE);
- if (sp != NULL)
- rfs4_state_rele_nounlock(sp);
- return (NFS4ERR_OLD_STATEID);
- }
- /* Ensure specified filehandle matches */
- if (lsp->rls_state->rs_finfo->rf_vp != vp) {
- rfs4_lo_state_rele(lsp, FALSE);
- if (sp != NULL)
- rfs4_state_rele_nounlock(sp);
- return (NFS4ERR_BAD_STATEID);
- }
+
+ ASSERT(id->bits.type == LOCKID);
+ stat = check_state_seqid(&lsp->rls_lockid, id, use_ss);
+ if (stat) {
+ rfs4_lo_state_rele(lsp, FALSE);
+ if (sp)
+ rfs4_state_rele_nounlock(sp);
+ return (stat);
+ }
+
+ /* Ensure specified filehandle matches */
+ if (lsp->rls_state->rs_finfo->rf_vp != vp) {
+ rfs4_lo_state_rele(lsp, FALSE);
+ if (sp != NULL)
+ rfs4_state_rele_nounlock(sp);
+ return (NFS4ERR_BAD_STATEID);
}
+
if (ct != NULL) {
ct->cc_sysid =
lsp->rls_locker->rl_client->rc_sysidt;
@@ -3766,18 +3853,13 @@ rfs4_check_stateid(int mode, vnode_t *vp,
rfs4_state_rele_nounlock(sp);
return (NFS4ERR_GRACE);
}
+ /* Skip if is here via the LOCKID */
if (id->bits.type == OPENID) {
- /* Seqid in the future? - that's bad */
- if (sp->rs_stateid.bits.chgseq <
- id->bits.chgseq) {
+ stat = check_state_seqid(&sp->rs_stateid, id,
+ use_ss);
+ if (stat) {
rfs4_state_rele_nounlock(sp);
- return (NFS4ERR_BAD_STATEID);
- }
- /* Seqid in the past - that's old */
- if (sp->rs_stateid.bits.chgseq >
- id->bits.chgseq) {
- rfs4_state_rele_nounlock(sp);
- return (NFS4ERR_OLD_STATEID);
+ return (stat);
}
}
/* Ensure specified filehandle matches */
@@ -3842,9 +3924,11 @@ rfs4_check_stateid(int mode, vnode_t *vp,
rfs4_deleg_state_rele(dsp);
return (NFS4ERR_GRACE);
}
- if (dsp->rds_delegid.bits.chgseq != id->bits.chgseq) {
+
+ stat = check_state_seqid(&dsp->rds_delegid, id, use_ss);
+ if (stat) {
rfs4_deleg_state_rele(dsp);
- return (NFS4ERR_BAD_STATEID);
+ return (stat);
}
/* Ensure specified filehandle matches */
diff --git a/usr/src/uts/common/fs/nfs/nfs4_xdr.c b/usr/src/uts/common/fs/nfs/nfs4_xdr.c
index 36b19fe657..1879482a14 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_xdr.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_xdr.c
@@ -21,6 +21,7 @@
/*
* Copyright 2016 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2020 RackTop Systems, Inc.
*/
/*
@@ -65,6 +66,7 @@ bool_t
xdr_bitmap4(XDR *xdrs, bitmap4 *objp)
{
int32_t len, size;
+ uint32_t bmval2 = 0;
if (xdrs->x_op == XDR_FREE)
return (TRUE);
@@ -75,7 +77,15 @@ xdr_bitmap4(XDR *xdrs, bitmap4 *objp)
* uint64_t and ignore all of the rest.
*/
if (xdrs->x_op == XDR_ENCODE) {
- len = 2;
+ bitmap4 obj = *objp;
+
+ objp = &obj;
+ if (*objp & FATTR4_SUPPATTR_EXCLCREAT_MASK_LOCAL) {
+ bmval2 |= 1ULL << (FATTR4_SUPPATTR_EXCLCREAT - 64);
+ *objp &= ~FATTR4_SUPPATTR_EXCLCREAT_MASK_LOCAL;
+ }
+
+ len = bmval2 ? 3 : 2;
if (!XDR_PUTINT32(xdrs, &len))
return (FALSE);
@@ -83,15 +93,19 @@ xdr_bitmap4(XDR *xdrs, bitmap4 *objp)
#if defined(_LITTLE_ENDIAN)
if (XDR_PUTINT32(xdrs, (int32_t *)((char *)objp +
BYTES_PER_XDR_UNIT)) == TRUE) {
- return (XDR_PUTINT32(xdrs, (int32_t *)objp));
+ if (!XDR_PUTINT32(xdrs, (int32_t *)objp))
+ return (FALSE);
}
#elif defined(_BIG_ENDIAN)
if (XDR_PUTINT32(xdrs, (int32_t *)objp) == TRUE) {
- return (XDR_PUTINT32(xdrs, (int32_t *)((char *)objp +
- BYTES_PER_XDR_UNIT)));
+ if (!XDR_PUTINT32(xdrs, (int32_t *)((char *)objp +
+ BYTES_PER_XDR_UNIT)))
+ return (FALSE);
}
#endif
- return (FALSE);
+ if (len == 3 && !XDR_PUTINT32(xdrs, (int32_t *)&bmval2))
+ return (FALSE);
+ return (TRUE);
}
if (!XDR_GETINT32(xdrs, &len))
@@ -100,19 +114,28 @@ xdr_bitmap4(XDR *xdrs, bitmap4 *objp)
/*
* Common fast DECODE cases
*/
- if (len == 2) {
+ if (len == 2 || len == 3) {
#if defined(_LITTLE_ENDIAN)
if (XDR_GETINT32(xdrs, (int32_t *)((char *)objp +
BYTES_PER_XDR_UNIT)) == TRUE) {
- return (XDR_GETINT32(xdrs, (int32_t *)objp));
+ if (!XDR_GETINT32(xdrs, (int32_t *)objp))
+ return (FALSE);
}
#elif defined(_BIG_ENDIAN)
if (XDR_GETINT32(xdrs, (int32_t *)objp) == TRUE) {
- return (XDR_GETINT32(xdrs, (int32_t *)((char *)objp +
- BYTES_PER_XDR_UNIT)));
+ if (!XDR_GETINT32(xdrs, (int32_t *)((char *)objp +
+ BYTES_PER_XDR_UNIT)))
+ return (FALSE);
}
#endif
- return (FALSE);
+ if (len == 3) {
+ if (!XDR_GETINT32(xdrs, (int32_t *)&bmval2))
+ return (FALSE);
+ if (bmval2 & (1ULL << (FATTR4_SUPPATTR_EXCLCREAT - 64)))
+ *objp |= FATTR4_SUPPATTR_EXCLCREAT_MASK_LOCAL;
+ }
+
+ return (TRUE);
}
*objp = 0;
@@ -134,6 +157,12 @@ xdr_bitmap4(XDR *xdrs, bitmap4 *objp)
return (FALSE);
if (--len == 0)
return (TRUE);
+
+ if (!XDR_GETINT32(xdrs, (int32_t *)&bmval2))
+ return (FALSE);
+ if (bmval2 & (1ULL << (FATTR4_SUPPATTR_EXCLCREAT - 64)))
+ *objp |= FATTR4_SUPPATTR_EXCLCREAT_MASK_LOCAL;
+
if (!XDR_GETINT32(xdrs, (int32_t *)((char *)objp + BYTES_PER_XDR_UNIT)))
return (FALSE);
#else
@@ -661,7 +690,7 @@ xdr_fs_location4(XDR *xdrs, fs_location4 *objp)
}
/* Called by xdr_array */
-static bool_t
+bool_t
xdr_nfsace4(XDR *xdrs, nfsace4 *objp)
{
if (xdrs->x_op != XDR_FREE) {
@@ -755,6 +784,33 @@ xdr_nfstime4(XDR *xdrs, nfstime4 *objp)
return (xdr_u_int(xdrs, &objp->nseconds));
}
+bool_t
+xdr_fattr4_sec_label(XDR *xdrs, fattr4_sec_label *objp)
+{
+ uint_t dummy = 0;
+
+ if (xdrs->x_op == XDR_FREE) {
+ /*
+ * Optimized free case
+ */
+ if (objp->slai_val != NULL)
+ kmem_free(objp->slai_val, objp->slai_len);
+ return (TRUE);
+ }
+
+ /*
+ * For now use a 0 here to indicate the null translation; in
+ * the future we place a call to translation code here.
+ */
+ if (!xdr_u_int(xdrs, &dummy)) /* lfs */
+ return (FALSE);
+
+ if (!xdr_u_int(xdrs, &dummy)) /* pi */
+ return (FALSE);
+
+ return (xdr_bytes(xdrs, (char **)&objp->slai_val,
+ (uint_t *)&objp->slai_len, NFS4_OPAQUE_LIMIT));
+}
/*
* structured used for calls into xdr_ga_fattr_res() as a means
@@ -2510,7 +2566,7 @@ xdr_settime4(XDR *xdrs, settime4 *objp)
return (xdr_u_int(xdrs, &objp->time.nseconds));
}
-static bool_t
+bool_t
xdr_fattr4(XDR *xdrs, fattr4 *objp)
{
if (xdrs->x_op != XDR_FREE) {
@@ -2882,12 +2938,29 @@ xdr_LOCKU4args(XDR *xdrs, LOCKU4args *objp)
}
static bool_t
+xdr_share_access(XDR *xdrs, uint32_t *share_access, uint32_t *deleg_want)
+{
+ uint32_t w;
+
+ if (xdrs->x_op == XDR_DECODE) {
+ if (!xdr_u_int(xdrs, &w))
+ return (FALSE);
+
+ *share_access = w & OPEN4_SHARE_ACCESS_MASK;
+ *deleg_want = w & OPEN4_SHARE_WANT_MASK;
+ }
+
+ return (TRUE);
+}
+
+static bool_t
xdr_OPEN4args(XDR *xdrs, OPEN4args *objp)
{
if (xdrs->x_op != XDR_FREE) {
if (!xdr_u_int(xdrs, &objp->seqid))
return (FALSE);
- if (!xdr_u_int(xdrs, &objp->share_access))
+ if (!xdr_share_access(xdrs, &objp->share_access,
+ &objp->deleg_want))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->share_deny))
return (FALSE);
@@ -2922,47 +2995,21 @@ xdr_OPEN4args(XDR *xdrs, OPEN4args *objp)
createverf))
return (FALSE);
break;
+ case EXCLUSIVE4_1:
+ if (!xdr_creatverfattr(xdrs,
+ &objp->createhow4_u.ch_createboth))
+ return (FALSE);
+ break;
default:
return (FALSE);
}
}
/* xdr_open_claim4 */
- if (!xdr_int(xdrs, (int *)&objp->claim))
- return (FALSE);
-
- switch (objp->claim) {
- case CLAIM_NULL:
- return (xdr_bytes(xdrs, (char **)&objp->open_claim4_u.
- file.utf8string_val,
- (uint_t *)&objp->open_claim4_u.file.
- utf8string_len,
- NFS4_MAX_UTF8STRING));
- case CLAIM_PREVIOUS:
- return (xdr_int(xdrs,
- (int *)&objp->open_claim4_u.delegate_type));
- case CLAIM_DELEGATE_CUR:
- if (!xdr_u_int(xdrs, (uint_t *)&objp->open_claim4_u.
- delegate_cur_info.delegate_stateid.seqid))
- return (FALSE);
- if (!xdr_opaque(xdrs, objp->open_claim4_u.
- delegate_cur_info.delegate_stateid.other,
- NFS4_OTHER_SIZE))
- return (FALSE);
- return (xdr_bytes(xdrs, (char **)&objp->open_claim4_u.
- delegate_cur_info.file.utf8string_val,
- (uint_t *)&objp->open_claim4_u.
- delegate_cur_info.file.utf8string_len,
- NFS4_MAX_UTF8STRING));
- case CLAIM_DELEGATE_PREV:
- return (xdr_bytes(xdrs, (char **)&objp->open_claim4_u.
- file_delegate_prev.utf8string_val,
- (uint_t *)&objp->open_claim4_u.
- file_delegate_prev.utf8string_len,
- NFS4_MAX_UTF8STRING));
- default:
+ if (!xdr_open_claim4(xdrs, &objp->claim))
return (FALSE);
- }
+
+ return (TRUE);
}
/*
@@ -2984,35 +3031,8 @@ xdr_OPEN4args(XDR *xdrs, OPEN4args *objp)
}
}
- switch (objp->claim) {
- case CLAIM_NULL:
- if (objp->open_claim4_u.file.utf8string_val != NULL)
- kmem_free(objp->open_claim4_u.file.utf8string_val,
- objp->open_claim4_u.file.utf8string_len);
- return (TRUE);
- case CLAIM_PREVIOUS:
- return (TRUE);
- case CLAIM_DELEGATE_CUR:
- if (objp->open_claim4_u.delegate_cur_info.file.utf8string_val !=
- NULL) {
- kmem_free(objp->open_claim4_u.delegate_cur_info.file.
- utf8string_val,
- objp->open_claim4_u.delegate_cur_info.file.
- utf8string_len);
- }
- return (TRUE);
- case CLAIM_DELEGATE_PREV:
- if (objp->open_claim4_u.file_delegate_prev.utf8string_val !=
- NULL) {
- kmem_free(objp->open_claim4_u.file_delegate_prev.
- utf8string_val,
- objp->open_claim4_u.file_delegate_prev.
- utf8string_len);
- }
- return (TRUE);
- default:
- return (TRUE);
- }
+ (void) xdr_open_claim4(xdrs, &objp->claim);
+ return (TRUE);
}
static bool_t
@@ -3284,7 +3304,7 @@ xdr_OPEN_DOWNGRADE4args(XDR *xdrs, OPEN_DOWNGRADE4args *objp)
return (FALSE);
if (!xdr_u_int(xdrs, &objp->seqid))
return (FALSE);
- if (!xdr_u_int(xdrs, &objp->share_access))
+ if (!xdr_share_access(xdrs, &objp->share_access, &objp->deleg_want))
return (FALSE);
return (xdr_u_int(xdrs, &objp->share_deny));
}
@@ -3792,6 +3812,18 @@ xdr_secinfo4(XDR *xdrs, secinfo4 *objp)
return (TRUE);
}
+bool_t
+xdr_SECINFO4res(XDR *xdrs, SECINFO4res *objp)
+{
+ if (!xdr_int(xdrs, (int32_t *)&objp->status))
+ return (FALSE);
+ if (objp->status != NFS4_OK)
+ return (TRUE);
+ return (xdr_array(xdrs, (char **)&objp->SECINFO4resok_val,
+ (uint_t *)&objp->SECINFO4resok_len, ~0, sizeof (secinfo4),
+ (xdrproc_t)xdr_secinfo4));
+}
+
static bool_t
xdr_SETCLIENTID4args(XDR *xdrs, SETCLIENTID4args *objp)
{
@@ -3948,6 +3980,13 @@ xdr_snfs_argop4_free(XDR *xdrs, nfs_argop4 **arrayp, int len)
return (TRUE);
for (i = 0; i < len; i++) {
+ /* Freeing for nfs4.x */
+ if (array[i].argop >= OP_BACKCHANNEL_CTL &&
+ array[i].argop != OP_ILLEGAL) {
+ xdr_nfs4x_argop4(xdrs, &array[i]);
+ continue;
+ }
+
/*
* These should be ordered by frequency of use
*/
@@ -4309,6 +4348,10 @@ xdr_snfs_argop4(XDR *xdrs, nfs_argop4 *objp)
return (xdr_decode_nfs_fh4(xdrs,
&objp->nfs_argop4_u.opputfh.object));
default:
+ if (objp->argop >= OP_BACKCHANNEL_CTL &&
+ objp->argop != OP_ILLEGAL)
+ return (xdr_nfs4x_argop4(xdrs, objp));
+
return (xdr_nfs_argop4(xdrs, objp));
}
}
@@ -4775,6 +4818,10 @@ xdr_snfs_resop4(XDR *xdrs, nfs_resop4 *objp)
return (xdr_encode_nfs_fh4(xdrs,
&objp->nfs_resop4_u.opgetfh.object));
default:
+ if (objp->resop >= OP_BACKCHANNEL_CTL &&
+ objp->resop != OP_ILLEGAL)
+ return (xdr_nfs4x_resop4(xdrs, objp));
+
return (xdr_nfs_resop4(xdrs, objp));
}
}
@@ -5176,32 +5223,6 @@ xdr_cnfs_cb_argop4(XDR *xdrs, nfs_cb_argop4 *objp)
return (FALSE);
}
-static bool_t
-xdr_nfs_cb_resop4(XDR *xdrs, nfs_cb_resop4 *objp)
-{
- if (!xdr_u_int(xdrs, &objp->resop))
- return (FALSE);
- switch (objp->resop) {
- case OP_CB_GETATTR:
- if (!xdr_int(xdrs,
- (int32_t *)&objp->nfs_cb_resop4_u.opcbgetattr.
- status))
- return (FALSE);
- if (objp->nfs_cb_resop4_u.opcbgetattr.status != NFS4_OK)
- return (TRUE);
- return (xdr_fattr4(xdrs,
- &objp->nfs_cb_resop4_u.opcbgetattr.
- obj_attributes));
- case OP_CB_RECALL:
- return (xdr_int(xdrs,
- (int32_t *)&objp->nfs_cb_resop4_u.opcbrecall.status));
- case OP_CB_ILLEGAL:
- return (xdr_int(xdrs,
- (int32_t *)&objp->nfs_cb_resop4_u.opcbillegal.status));
- }
- return (FALSE);
-}
-
/*
* The NFS client side callback, RPC server
*/
diff --git a/usr/src/uts/common/fs/nfs/nfs4x_dispatch.c b/usr/src/uts/common/fs/nfs/nfs4x_dispatch.c
new file mode 100644
index 0000000000..49ae2d6ad4
--- /dev/null
+++ b/usr/src/uts/common/fs/nfs/nfs4x_dispatch.c
@@ -0,0 +1,177 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 RackTop Systems.
+ */
+
+#include <sys/systm.h>
+#include <sys/sdt.h>
+#include <rpc/types.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
+#include <rpc/auth_des.h>
+#include <rpc/svc.h>
+#include <rpc/xdr.h>
+#include <nfs/nfs4.h>
+#include <nfs/nfs_dispatch.h>
+#include <sys/cmn_err.h>
+#include <sys/modctl.h>
+
+static void
+rfs4_err_resp(COMPOUND4args *args, COMPOUND4res *resp, nfsstat4 err)
+{
+ size_t sz;
+
+ resp->array_len = 1;
+ sz = resp->array_len * sizeof (nfs_resop4);
+ resp->array = kmem_zalloc(sz, KM_SLEEP);
+
+ resp->array[0].resop = args->array[0].argop;
+ resp->status = resp->array[0].nfs_resop4_u.opillegal.status = err;
+}
+
+/*
+ * The function checks if given compound operation is allowed
+ * to be the very fist operation in compound array.
+ */
+static bool_t
+valid_first_compound_op(nfs_opnum4 op)
+{
+ if (op == OP_BIND_CONN_TO_SESSION ||
+ op == OP_SEQUENCE ||
+ op == OP_EXCHANGE_ID ||
+ op == OP_CREATE_SESSION ||
+ op == OP_DESTROY_SESSION ||
+ op == OP_DESTROY_CLIENTID ||
+ op == OP_ILLEGAL)
+ return (TRUE);
+
+ return (FALSE);
+}
+
+/*
+ * The function verifies arguments passed to mds_op_compound.
+ * If agrguments are valid, NFS4_OK is returned, otherwise
+ * function returns correspoinding NFS4 error code.
+ */
+static nfsstat4
+verify_compound_args(COMPOUND4args *args)
+{
+ if (args->array_len == 0)
+ return (NFS4_OK);
+
+ if (!valid_first_compound_op(args->array[0].argop))
+ return (NFS4ERR_OP_NOT_IN_SESSION);
+
+ if (args->array_len > 1 && args->array[0].argop != OP_SEQUENCE) {
+ /*
+ * Compound is outside the session. There must be
+ * only one operation in request.
+ */
+ return (NFS4ERR_NOT_ONLY_OP);
+ }
+
+ return (NFS4_OK);
+}
+
+static void
+rfs4x_dispatch_done(compound_state_t *cs)
+{
+ if (cs->slot)
+ rfs4x_sequence_done(cs->cmpresp, cs);
+ else {
+ rfs4_compound_free(cs->cmpresp);
+ }
+ cs->cs_flags |= RFS4_DISPATCH_DONE;
+}
+
+static bool_t
+xdr_compound_wrapper(XDR *xdrs, compound_state_t *cs)
+{
+ COMPOUND4res *resp = cs->cmpresp;
+ bool_t res = FALSE;
+ bool_t isreal = (xdrs->x_handy != 0); /* real data encoding ? */
+
+ if (!(cs->cs_flags & RFS4_DISPATCH_DONE)) {
+ res = xdr_COMPOUND4res_srv(xdrs, resp);
+ if (isreal)
+ rfs4x_dispatch_done(cs);
+ }
+
+ return (res);
+}
+
+int
+rfs4x_dispatch(struct svc_req *req, SVCXPRT *xprt, char *ap)
+{
+ struct compound_state cs;
+ COMPOUND4res res_buf;
+ COMPOUND4res *rbp;
+ COMPOUND4args *cap;
+ int rpcerr = 0;
+ nfsstat4 error;
+
+ bzero(&res_buf, sizeof (COMPOUND4res));
+ rbp = &res_buf;
+ cap = (COMPOUND4args *)ap;
+ rfs4_init_compound_state(&cs);
+
+ cs.statusp = &error;
+ cs.cmpresp = rbp;
+
+ error = verify_compound_args(cap);
+ if (error != NFS4_OK) { /* NFS4_OK is 0 */
+ rfs4_err_resp(cap, rbp, error);
+ goto out_send;
+ }
+
+ error = rfs4x_sequence_prep(cap, rbp, &cs);
+ if (error != NFS4_OK) {
+ if (error != nfserr_replay_cache)
+ rfs4_err_resp(cap, rbp, error);
+ goto out_send;
+ }
+
+ /* Regular processing */
+ curthread->t_flag |= T_DONTPEND;
+ rfs4_compound(cap, rbp, &cs, req, &rpcerr);
+ curthread->t_flag &= ~T_DONTPEND;
+
+ /*
+ * On RPC error, short sendreply
+ */
+ if (rpcerr) {
+ goto out_free;
+ }
+
+ if (curthread->t_flag & T_WOULDBLOCK) {
+ curthread->t_flag &= ~T_WOULDBLOCK;
+ error = 1;
+ goto out_free;
+ }
+
+out_send:
+ if (!svc_sendreply(xprt, xdr_compound_wrapper, (char *)&cs)) {
+ DTRACE_PROBE2(sendfail, SVCXPRT *, xprt,
+ compound_state_t *, &cs);
+ svcerr_systemerr(xprt);
+ rpcerr = 1;
+ }
+
+out_free:
+ if (!(cs.cs_flags & RFS4_DISPATCH_DONE)) {
+ rfs4x_dispatch_done(&cs);
+ }
+
+ rfs4_fini_compound_state(&cs);
+ return ((error != NFS4_OK || rpcerr) ? 1 : 0);
+}
diff --git a/usr/src/uts/common/fs/nfs/nfs4x_srv.c b/usr/src/uts/common/fs/nfs/nfs4x_srv.c
new file mode 100644
index 0000000000..854a8e1abe
--- /dev/null
+++ b/usr/src/uts/common/fs/nfs/nfs4x_srv.c
@@ -0,0 +1,1250 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 RackTop Systems.
+ */
+
+#include <rpc/types.h>
+#include <rpc/auth.h>
+#include <rpc/rpcsec_gss.h>
+#include <sys/sdt.h>
+#include <sys/disp.h>
+#include <nfs/nfs.h>
+#include <nfs/nfs4.h>
+#include <sys/systeminfo.h>
+
+/* Helpers */
+
+/* Principal handling routines */
+/* returns 0 if no match; or 1 for a match */
+int
+rfs4_cmp_cred_set(cred_set_t *p, struct compound_state *cs)
+{
+ int rc = 0;
+ rpc_gss_principal_t recp; /* cached clnt princ */
+ rpc_gss_principal_t ibrp; /* inbound req princ */
+
+
+ if (p->cp_cr == NULL)
+ return (rc); /* nothing to compare with */
+
+ if (p->cp_aflavor != cs->req->rq_cred.oa_flavor)
+ return (rc);
+
+ if (p->cp_secmod != cs->nfsflavor)
+ return (rc);
+
+ if (crcmp(p->cp_cr, cs->basecr))
+ return (rc);
+
+ switch (p->cp_aflavor) {
+ case AUTH_DES:
+ rc = (strcmp(p->cp_princ, cs->principal) == 0);
+ break;
+
+ case RPCSEC_GSS:
+ recp = (rpc_gss_principal_t)p->cp_princ;
+ ibrp = (rpc_gss_principal_t)cs->principal;
+
+ if (recp->len != ibrp->len)
+ break;
+ rc = (bcmp(recp->name, ibrp->name, ibrp->len) == 0);
+ break;
+
+ case AUTH_SYS:
+ case AUTH_NONE:
+ default:
+ rc = 1;
+ break;
+ }
+ return (rc);
+}
+
+static rpc_gss_principal_t
+rfs4_dup_princ(rpc_gss_principal_t ppl)
+{
+ rpc_gss_principal_t pdup;
+ int len;
+
+ if (ppl == NULL)
+ return (NULL);
+
+ len = sizeof (int) + ppl->len;
+ pdup = (rpc_gss_principal_t)kmem_alloc(len, KM_SLEEP);
+ bcopy(ppl, pdup, len);
+ return (pdup);
+}
+
+void
+rfs4_set_cred_set(cred_set_t *p, struct compound_state *cs)
+{
+ ASSERT(p->cp_cr == NULL);
+
+ p->cp_cr = crdup(cs->basecr);
+ p->cp_aflavor = cs->req->rq_cred.oa_flavor;
+ p->cp_secmod = cs->nfsflavor; /* secmod != flavor for RPCSEC_GSS */
+
+ /*
+ * Set principal as per security flavor
+ */
+ switch (p->cp_aflavor) {
+ case AUTH_DES:
+ p->cp_princ = strdup(cs->principal);
+ break;
+
+ case RPCSEC_GSS:
+ p->cp_princ =
+ (caddr_t)rfs4_dup_princ((rpc_gss_principal_t)cs->principal);
+ break;
+
+ case AUTH_SYS:
+ case AUTH_NONE:
+ default:
+ break;
+ }
+}
+
+void
+rfs4_free_cred_set(cred_set_t *p)
+{
+ rpc_gss_principal_t ppl;
+
+ if (p->cp_cr == NULL)
+ return;
+
+ switch (p->cp_aflavor) {
+ case AUTH_DES:
+ kmem_free(p->cp_princ, strlen(p->cp_princ) + 1);
+ break;
+
+ case RPCSEC_GSS:
+ ppl = (rpc_gss_principal_t)p->cp_princ;
+ kmem_free(ppl, ppl->len + sizeof (int));
+ break;
+ }
+
+ crfree(p->cp_cr);
+ p->cp_cr = NULL;
+}
+
+/* principal end */
+
+bool_t
+nfs_clid4_cmp(nfs_client_id4 *s1, nfs_client_id4 *s2)
+{
+ if (s1->verifier != s2->verifier)
+ return (FALSE);
+ if (s1->id_len != s2->id_len)
+ return (FALSE);
+ if (bcmp(s1->id_val, s2->id_val, s2->id_len))
+ return (FALSE);
+ return (TRUE);
+}
+
+/*
+ * Rudimentary server implementation (XXX - for now)
+ */
+void
+rfs4x_get_server_impl_id(EXCHANGE_ID4resok *resp)
+{
+ char *sol_impl = "illumos NFSv4.1 Server Implementation";
+ char *sol_idom = "nfsv41.ietf.org";
+ void *p;
+ uint_t len = 0;
+ nfs_impl_id4 *nip;
+
+ resp->eir_server_impl_id.eir_server_impl_id_len = 1;
+ nip = kmem_zalloc(sizeof (nfs_impl_id4), KM_SLEEP);
+ resp->eir_server_impl_id.eir_server_impl_id_val = nip;
+
+ /* Domain */
+ nip->nii_domain.utf8string_len = len = strlen(sol_idom);
+ p = kmem_zalloc(len * sizeof (char), KM_SLEEP);
+ nip->nii_domain.utf8string_val = p;
+ bcopy(sol_idom, p, len);
+
+ /* Implementation */
+ nip->nii_name.utf8string_len = len = strlen(sol_impl);
+ p = kmem_zalloc(len * sizeof (char), KM_SLEEP);
+ nip->nii_name.utf8string_val = p;
+ bcopy(sol_impl, p, len);
+
+ /* Time is zero for now */
+}
+
+/*
+ * Compute the "use bits", i.e. the flags specifying the permissible
+ * regular, MDS, and data server ops for the returned clientid.
+ *
+ * The minorversion1 specification allows a server implementor two
+ * alternatives: allow PNFS_MDS and PNFS_DS on the same clientid, or
+ * force the client to create separate clientids to distinguish
+ * MDS versus DS operations.
+ *
+ * Our design distinguishes operations based upon filehandle, and thus
+ * there is no reason to force the client to create separate clientids.
+ * Thus, we give the client as much as possible, while keeping the result
+ * within the allowed combinations as specified in the specification.
+ *
+ * Our constraints are: use a subset of the client's request, unless
+ * the client requested nothing, in which case we may return any
+ * legal combination; and, the combination of NON_PNFS and PNFS_MDS
+ * may not both be set in the results. These constraints are reflected
+ * in the ASSERT()s at the end.
+ */
+
+static uint32_t
+compute_use_pnfs_flags(uint32_t request)
+{
+ uint32_t rc;
+
+ /* Start with the client's initial request */
+ rc = request & EXCHGID4_FLAG_MASK_PNFS;
+
+ /* If the client requested nothing, return the most permissive. */
+ if (rc == 0) {
+ rc = EXCHGID4_FLAG_USE_NON_PNFS;
+ goto done;
+ }
+
+ /* Don't permit the illegal combination of MDS and NON_PNFS */
+ if ((rc &
+ (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS)) ==
+ (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS))
+ rc &= ~EXCHGID4_FLAG_USE_PNFS_MDS;
+done:
+ ASSERT(((request & EXCHGID4_FLAG_MASK_PNFS) == 0) ||
+ ((rc & ~(request & EXCHGID4_FLAG_MASK_PNFS)) == 0));
+ ASSERT((rc & (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS))
+ != (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS));
+ ASSERT(rc != 0);
+
+ return (rc);
+}
+
+static void
+rfs4x_set_trunkinfo(EXCHANGE_ID4resok *rok)
+{
+ const char *nodename = uts_nodename();
+ unsigned int nd_len = strlen(nodename);
+ unsigned int hw_len = strlen(hw_serial);
+ unsigned id_len = nd_len + 1 + hw_len;
+ char *s = kmem_alloc(id_len, KM_SLEEP);
+ server_owner4 *so = &rok->eir_server_owner;
+ struct eir_server_scope *ss = &rok->eir_server_scope;
+
+ (void) memcpy(s, nodename, nd_len);
+ s[nd_len] = ' ';
+ (void) memcpy(s + nd_len + 1, hw_serial, hw_len);
+
+ so->so_major_id.so_major_id_len = id_len;
+ so->so_major_id.so_major_id_val = s;
+
+ ss->eir_server_scope_len = id_len;
+ ss->eir_server_scope_val = kmem_alloc(id_len, KM_SLEEP);
+ (void) memcpy(ss->eir_server_scope_val, s, id_len);
+
+ rok->eir_server_owner.so_minor_id = 0;
+}
+
+static bool_t
+client_has_state_locked(rfs4_client_t *cp)
+{
+ if (list_head(&cp->rc_sessions) != NULL ||
+ list_head(&cp->rc_openownerlist) != NULL)
+ return (TRUE);
+ else
+ return (FALSE);
+}
+
+/* OPERATIONS */
+
+/* EXCHANGE_ID */
+void
+rfs4x_op_exchange_id(nfs_argop4 *argop, nfs_resop4 *resop,
+ struct svc_req *req, compound_state_t *cs)
+{
+ EXCHANGE_ID4args *args = &argop->nfs_argop4_u.opexchange_id;
+ EXCHANGE_ID4res *resp = &resop->nfs_resop4_u.opexchange_id;
+ EXCHANGE_ID4resok *rok = &resp->EXCHANGE_ID4res_u.eir_resok4;
+ rfs4_client_t *cp, *conf;
+ bool_t update, create;
+ client_owner4 *cop;
+ nfs_client_id4 cid; /* cip */
+ nfsstat4 status = NFS4_OK;
+ nfs4_srv_t *nsrv4;
+
+ DTRACE_NFSV4_2(op__exchange__id__start,
+ struct compound_state *, cs,
+ EXCHANGE_ID4args *, args);
+
+ /*
+ * EXCHANGE_ID's may be preceded by SEQUENCE
+ *
+ * Check that eia_flags only has "valid" spec bits
+ * and that no 'eir_flag' ONLY bits are specified.
+ */
+ if (args->eia_flags & ~EXID4_FLAG_MASK) {
+ status = NFS4ERR_INVAL;
+ goto err;
+ }
+
+ update = (args->eia_flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A);
+ cop = &args->eia_clientowner;
+ conf = NULL;
+
+ cid.verifier = cop->co_verifier;
+ cid.id_len = cop->co_ownerid.co_ownerid_len;
+ cid.id_val = cop->co_ownerid.co_ownerid_val;
+ cid.cl_addr = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+
+ /*
+ * Refer to Section 18.35.4
+ */
+again:
+ create = TRUE;
+ cp = rfs4_findclient(&cid, &create, conf);
+ ASSERT(cp != NULL);
+
+ if (conf) {
+ rfs4_dbe_lock(cp->rc_dbe);
+ if (cp->rc_cp_confirmed == NULL)
+ cp->rc_cp_confirmed = conf;
+ else
+ rfs4_client_rele(conf);
+ rfs4_dbe_unlock(cp->rc_dbe);
+ conf = NULL;
+ }
+
+ if (create) {
+ /* Record just created */
+ if (!update) {
+ /* case 1 - utok */
+ rfs4_set_cred_set(&cp->rc_cr_set, cs);
+
+ rok->eir_clientid = cp->rc_clientid;
+ rok->eir_sequenceid = cp->rc_contrived.xi_sid;
+ goto out;
+ } else {
+ /* no record and trying to update */
+ status = NFS4ERR_NOENT;
+ goto err_out;
+ }
+ }
+
+ /* Record exists */
+
+ /* expired clients should be ignored and released */
+ if (rfs4_lease_expired(cp)) {
+ rfs4_client_close(cp);
+ update = FALSE;
+ goto again;
+ }
+
+ if (cp->rc_need_confirm) {
+ /* UNCONFIRMED */
+ if (!update) {
+ /* case 4 - utok */
+ rfs4_client_close(cp);
+
+ ASSERT(!update);
+ goto again;
+ } else {
+ /* case 7 - utok */
+ status = NFS4ERR_NOENT;
+ goto err_out;
+ }
+ }
+
+ /* record exists and confirmed */
+ if (!update) {
+ if (!rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) {
+ /* case 3 */
+ /* lease is checked above */
+ rfs4_dbe_lock(cp->rc_dbe);
+ if (!client_has_state_locked(cp)) {
+ rfs4_dbe_unlock(cp->rc_dbe);
+
+ rfs4_client_close(cp);
+ ASSERT(!update);
+ goto again;
+ }
+ rfs4_dbe_unlock(cp->rc_dbe);
+
+ /*
+ * clid_in_use. old_client_ret has unexpired
+ * lease with state.
+ */
+ status = NFS4ERR_CLID_INUSE;
+ goto err_out;
+ } else if (cp->rc_nfs_client.verifier != cid.verifier) {
+ /* case 5: Client Restart */
+ /*
+ * Skip confirmed client record to allow confirmed
+ * and unconfirmed state at the same time. The number
+ * of states can collapse to one once the server
+ * receives an applicable CREATE_SESSION or EXCHANGE_ID.
+ */
+ ASSERT(conf == NULL);
+ conf = cp;
+ ASSERT(!update);
+ goto again;
+
+ } else if (nfs_clid4_cmp(&cp->rc_nfs_client, &cid)) {
+ /* case 2 - utok */
+ rok->eir_clientid = cp->rc_clientid;
+ rok->eir_sequenceid = cp->rc_contrived.xi_sid;
+ /* trickle down to "out" */
+
+ } else {
+ /* something is really wacky in srv state */
+ status = NFS4ERR_SERVERFAULT;
+ goto err_out;
+ }
+
+ } else { /* UPDATE */
+ if (cp->rc_nfs_client.verifier != cid.verifier) {
+ /* 18.35.4 case 8 */
+ status = NFS4ERR_NOT_SAME;
+ goto err_out;
+ }
+ if (!rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) {
+ /* 18.35.4 case 9 */
+ status = NFS4ERR_PERM;
+ goto err_out;
+ }
+
+ /* case 6 - utok */
+ rok->eir_clientid = cp->rc_clientid;
+ rok->eir_sequenceid = cp->rc_contrived.xi_sid;
+ /* trickle down to "out" */
+ }
+out:
+ rok->eir_flags = 0;
+ if (resp->eir_status == NFS4_OK && !cp->rc_need_confirm)
+ rok->eir_flags |= EXCHGID4_FLAG_CONFIRMED_R;
+
+ /*
+ * State Protection Mojo
+ */
+ cp->rc_state_prot.sp_type = args->eia_state_protect.spa_how;
+ switch (cp->rc_state_prot.sp_type) {
+ case SP4_NONE:
+ break;
+
+ case SP4_MACH_CRED:
+ /* XXX - Some of Karen's secret sauce here... */
+ break;
+
+ case SP4_SSV:
+ /* XXX - ... and here */
+#define ssv_args eia_state_protect.state_protect4_a_u.spa_ssv_parms
+ if (args->ssv_args.ssp_ops.spo_must_allow & OP_EXCHANGE_ID) {
+ /*
+ * if the client ID was created specifying SP4_SSV
+ * state protection and EXCHANGE_ID as the one of
+ * the operations in spo_must_allow, then server MUST
+ * authorize EXCHANGE_IDs with the SSV principal in
+ * addition to the principal that created the client
+ * ID.
+ */
+ /* EMPTY */;
+ }
+ break;
+ }
+
+ /*
+ * Referrals supports
+ */
+ if (args->eia_flags & EXCHGID4_FLAG_SUPP_MOVED_REFER) {
+ rok->eir_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER;
+ }
+
+ /*
+ * Migration/Replication not (yet) supported
+ */
+ if (args->eia_flags & EXCHGID4_FLAG_SUPP_MOVED_MIGR)
+ rok->eir_flags &= ~EXCHGID4_FLAG_SUPP_MOVED_MIGR;
+
+ /*
+ * TODO: Add the appropriate "use_pnfs" flags.
+ */
+ rok->eir_flags |= compute_use_pnfs_flags(args->eia_flags);
+
+ /* force no state protection for now */
+ rok->eir_state_protect.spr_how = SP4_NONE;
+
+ /* Implementation specific mojo */
+ if (args->eia_client_impl_id.eia_client_impl_id_len != 0) {
+ /* EMPTY */;
+ }
+
+ nsrv4 = nfs4_get_srv();
+
+ /* XXX - jw - best guess */
+ rfs4_ss_clid(nsrv4, cp);
+
+ /* Server's implementation */
+ rfs4x_get_server_impl_id(rok);
+
+ /* compute trunking capabilities */
+ bzero(&rok->eir_server_scope, sizeof (rok->eir_server_scope));
+ bzero(&rok->eir_server_owner, sizeof (server_owner4));
+
+ /* Add trunk handling */
+ rfs4x_set_trunkinfo(rok);
+
+ /*
+ * XXX - jw - best guess
+ * Check to see if client can perform reclaims
+ */
+ rfs4_ss_chkclid(nsrv4, cp);
+
+err_out:
+ rfs4_client_rele(cp);
+err:
+ *cs->statusp = resp->eir_status = status;
+
+ DTRACE_NFSV4_2(op__exchange__id__done,
+ struct compound_state *, cs,
+ EXCHANGE_ID4res *, resp);
+}
+
+void
+rfs4x_exchange_id_free(nfs_resop4 *resop)
+{
+ EXCHANGE_ID4res *resp = &resop->nfs_resop4_u.opexchange_id;
+ EXCHANGE_ID4resok *rok = &resp->EXCHANGE_ID4res_u.eir_resok4;
+ struct server_owner4 *sop = &rok->eir_server_owner;
+ nfs_impl_id4 *nip;
+ int len = 0;
+
+ /* Server Owner: major */
+ if ((len = sop->so_major_id.so_major_id_len) != 0)
+ kmem_free(sop->so_major_id.so_major_id_val, len);
+
+ if ((nip = rok->eir_server_impl_id.eir_server_impl_id_val) != NULL) {
+ /* Immplementation */
+ len = nip->nii_name.utf8string_len;
+ kmem_free(nip->nii_name.utf8string_val, len * sizeof (char));
+
+ /* Domain */
+ len = nip->nii_domain.utf8string_len;
+ kmem_free(nip->nii_domain.utf8string_val, len * sizeof (char));
+
+ /* Server Impl */
+ kmem_free(nip, sizeof (nfs_impl_id4));
+ }
+}
+
+void
+rfs4x_op_create_session(nfs_argop4 *argop, nfs_resop4 *resop,
+ struct svc_req *req, compound_state_t *cs)
+{
+ CREATE_SESSION4args *args = &argop->nfs_argop4_u.opcreate_session;
+ CREATE_SESSION4res *resp = &resop->nfs_resop4_u.opcreate_session;
+ CREATE_SESSION4resok *rok = &resp->CREATE_SESSION4res_u.csr_resok4;
+ CREATE_SESSION4resok *crp;
+ rfs4_client_t *cp;
+ rfs4_session_t *sp;
+ session41_create_t sca;
+ sequenceid4 stseq;
+ sequenceid4 agseq;
+ nfsstat4 status = NFS4_OK;
+
+ DTRACE_NFSV4_2(op__create__session__start,
+ struct compound_state *, cs,
+ CREATE_SESSION4args*, args);
+
+ /*
+ * A CREATE_SESSION request can be prefixed by OP_SEQUENCE.
+ * In this case, the newly created session has no relation
+ * to the sessid used for the OP_SEQUENCE.
+ */
+
+ /*
+ * Find the clientid
+ */
+ cp = rfs4_findclient_by_id(args->csa_clientid, TRUE);
+ if (cp == NULL) {
+ status = NFS4ERR_STALE_CLIENTID;
+ goto out;
+ }
+
+ /*
+ * Make sure the lease is still valid.
+ */
+ if (rfs4_lease_expired(cp)) {
+ rfs4_client_close(cp);
+ status = NFS4ERR_STALE_CLIENTID;
+ goto out;
+ }
+
+ /*
+ * Sequenceid processing (handling replay's, etc)
+ */
+ agseq = args->csa_sequence;
+ stseq = cp->rc_contrived.xi_sid;
+ if (stseq == agseq + 1) {
+ /*
+ * If the previous sequenceid, then must be a replay of a
+ * previous CREATE_SESSION; return the cached result.
+ */
+ crp = (CREATE_SESSION4resok *)&cp->rc_contrived.cs_res;
+ status = cp->rc_contrived.cs_status;
+ rok->csr_sequence = agseq;
+ bcopy(crp->csr_sessionid, rok->csr_sessionid,
+ sizeof (sessionid4));
+ rok->csr_flags = crp->csr_flags;
+ rok->csr_fore_chan_attrs = crp->csr_fore_chan_attrs;
+ rok->csr_back_chan_attrs = crp->csr_back_chan_attrs;
+
+ rfs4_update_lease(cp);
+ rfs4_client_rele(cp);
+ goto out;
+ }
+
+ if (stseq != agseq) {
+ /*
+ * No way to differentiate MISORD_NEWREQ vs. MISORD_REPLAY,
+ * so anything else, we simply treat as SEQ_MISORDERED.
+ */
+ status = NFS4ERR_SEQ_MISORDERED;
+ rfs4_client_rele(cp);
+ goto out;
+ }
+
+ /*
+ * Clientid confirmation
+ */
+ if (cp->rc_need_confirm) {
+ if (rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) {
+ cp->rc_need_confirm = FALSE;
+ if (cp->rc_cp_confirmed != NULL) {
+ rfs4_client_close(cp->rc_cp_confirmed);
+ cp->rc_cp_confirmed = NULL;
+ }
+ } else {
+ status = NFS4ERR_CLID_INUSE;
+ rfs4_client_rele(cp);
+ goto out;
+ }
+ }
+
+ /*
+ * Session creation
+ */
+ sca.cs_error = 0;
+ sca.cs_req = req;
+ sca.cs_client = cp;
+ sca.cs_aotw = *args;
+ sp = rfs4x_createsession(&sca);
+
+ if (sca.cs_error) {
+ status = sca.cs_error;
+ rfs4_client_rele(cp);
+ if (sp != NULL)
+ rfs4x_session_rele(sp);
+ goto out;
+ }
+
+ if (sp == NULL) {
+ status = NFS4ERR_SERVERFAULT;
+ rfs4_client_rele(cp);
+ goto out;
+ }
+
+ /*
+ * Need to store the result in the rfs4_client_t's contrived
+ * result slot and then respond from there. This way, when the
+ * csa_sequence == contrived.cc_sid, we can return the latest
+ * cached result. (see replay: above)
+ */
+ crp = (CREATE_SESSION4resok *)&cp->rc_contrived.cs_res;
+ cp->rc_contrived.cs_status = NFS4_OK;
+ rok->csr_sequence = crp->csr_sequence = cp->rc_contrived.xi_sid;
+ bcopy(sp->sn_sessid, rok->csr_sessionid, sizeof (sessionid4));
+ bcopy(sp->sn_sessid, crp->csr_sessionid, sizeof (sessionid4));
+ rok->csr_flags = crp->csr_flags = sp->sn_csflags;
+
+ cp->rc_contrived.xi_sid++;
+
+ /*
+ * XXX: struct assignment of channel4_attrs is broken because
+ * ca_rdma_ird is specified as a single element array. A struct
+ * assignment will copy the ca_rdma_ird array ptr to multiple args/
+ * res structs, and the ptr will be free'd multiple times.
+ * Without RDMA, ca_rdma_ird is a zero element array so its ptr
+ * is NULL (which is why this doesn't cause problems right now).
+ *
+ * Struct assignment is convenient, and it would be best to enable
+ * it by creating an in-kernel channel4_attrs struct which didn't
+ * contain the single element array, but just contained the inbound
+ * receive queue depth. Let the XDR encode/decode funcs convert
+ * from the in-kernel form to the OTW form.
+ */
+ rok->csr_fore_chan_attrs =
+ crp->csr_fore_chan_attrs = sp->sn_fore->cn_attrs;
+ rok->csr_back_chan_attrs = crp->csr_back_chan_attrs =
+ args->csa_back_chan_attrs;
+
+ rfs4_update_lease(cp);
+
+ /*
+ * References from the session to the client are
+ * accounted for while session is being created.
+ */
+ rfs4_client_rele(cp);
+ rfs4x_session_rele(sp);
+out:
+ *cs->statusp = resp->csr_status = status;
+
+ DTRACE_NFSV4_2(op__create__session__done,
+ struct compound_state *, cs,
+ CREATE_SESSION4res *, resp);
+}
+
+/* ARGSUSED */
+void
+rfs4x_op_destroy_session(nfs_argop4 *argop, nfs_resop4 *resop,
+ struct svc_req *req, compound_state_t *cs)
+{
+ DESTROY_SESSION4args *args = &argop->nfs_argop4_u.opdestroy_session;
+ DESTROY_SESSION4res *resp = &resop->nfs_resop4_u.opdestroy_session;
+ rfs4_session_t *sp;
+ rfs4_client_t *cp;
+ nfsstat4 status = NFS4_OK;
+ int addref = 0; /* additional reference */
+
+ DTRACE_NFSV4_2(op__destroy__session__start,
+ struct compound_state *, cs,
+ DESTROY_SESSION4args *, args);
+
+ /* section 18.37.3 rfc5661 */
+ if (rfs4_has_session(cs)) {
+ /* compound with a sequence */
+ if (bcmp(args->dsa_sessionid, cs->sp->sn_sessid,
+ sizeof (sessionid4)) == 0) {
+ /*
+ * Same session.
+ * must be the final operation in the COMPOUND request
+ */
+ if ((cs->op_pos + 1) != cs->op_len) {
+ status = NFS4ERR_NOT_ONLY_OP;
+ goto out;
+ }
+ addref++;
+ } else {
+ /* Not the same session */
+ /*
+ * TODO: need to verify that both sessions share
+ * the connection
+ */
+ DTRACE_PROBE(nfss41__i__destroy_encap_session);
+
+ }
+ }
+
+ sp = rfs4x_findsession_by_id(args->dsa_sessionid);
+ if (sp == NULL) {
+ status = NFS4ERR_BADSESSION;
+ goto out;
+ }
+ /*
+ * verify cred that was used to create the session matches and is in
+ * concordance w/the state protection type used.
+ */
+ cp = sp->sn_clnt;
+ switch (cp->rc_state_prot.sp_type) {
+ case SP4_MACH_CRED:
+ cmn_err(CE_NOTE, "op_destroy_session: SP4_MACH_CRED");
+ if (!rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) {
+ status = NFS4ERR_PERM;
+ rfs4x_session_rele(sp);
+ goto out;
+ }
+ break;
+
+ case SP4_SSV:
+ /*
+ * XXX - Need some of Karen's secret ssv sauce
+ * here. For now, just allow the destroy.
+ */
+ cmn_err(CE_NOTE, "op_destroy_session: SP4_SSV");
+ break;
+
+ case SP4_NONE:
+ break;
+
+ default:
+ break;
+ }
+
+ status = rfs4x_destroysession(sp, 2 + addref);
+ rfs4x_session_rele(sp);
+out:
+ *cs->statusp = resp->dsr_status = status;
+
+ DTRACE_NFSV4_2(op__destroy__session__done,
+ struct compound_state *, cs,
+ DESTROY_SESSION4res *, resp);
+}
+
+/*
+ * The thread will traverse the entire list pinging the connections
+ * that need it and refreshing any stale/dead connections.
+ */
+static void
+ping_cb_null_thr(rfs4_session_t *sp)
+{
+ /* TODO: Need implementation */
+ cmn_err(CE_NOTE, "nfs4x: ping_cb_null thread");
+ rfs4x_session_rele(sp);
+ thread_exit();
+}
+
+/*
+ * Find session and validate sequence args.
+ * If this function successfully completes the compound state
+ * will contain a session pointer.
+ */
+static nfsstat4
+rfs4x_find_session(SEQUENCE4args *sargs, struct compound_state *cs)
+{
+ rfs4_session_t *sp;
+ slotid4 slot;
+
+ ASSERT(sargs != NULL);
+
+ if ((sp = rfs4x_findsession_by_id(sargs->sa_sessionid)) == NULL)
+ return (NFS4ERR_BADSESSION);
+
+ slot = sargs->sa_slotid;
+ if (slot < 0 || slot >= sp->sn_fore->cn_attrs.ca_maxrequests) {
+ rfs4x_session_rele(sp);
+ return (NFS4ERR_BADSLOT);
+ }
+ cs->sp = sp;
+ cs->cachethis = sargs->sa_cachethis;
+
+ return (NFS4_OK);
+}
+
+/* called under held lock */
+static nfsstat4
+check_slot_seqid(rfs4_slot_t *slot, sequenceid4 seqid)
+{
+ nfsstat4 status = NFS4ERR_SEQ_MISORDERED;
+
+ if (slot->se_flags & RFS4_SLOT_INUSE) {
+ /*
+ * There are three cases:
+ * 1. Duplicated requests for currently performing
+ * duplicated request.
+ * 2. New request for currently performing duplicated
+ * request.
+ * 3. Request with bad seqid for non finished performing
+ * request (due to a little window between 'prep'
+ * stage and actual renew se_seqid).
+ * In all cases tell a client to retry request later.
+ */
+ if (slot->se_seqid == seqid || slot->se_seqid + 1 == seqid) {
+ status = NFS4ERR_DELAY;
+ }
+ } else {
+ if (seqid == slot->se_seqid + 1)
+ status = NFS4_OK;
+ else if (seqid == slot->se_seqid)
+ status = nfserr_replay_cache;
+ }
+ return (status);
+}
+
+/*
+ * Prep stage for SEQUENCE operation.
+ *
+ * Main purpose to call this:
+ * - check on cached replay
+ * - Set cs.sp and cs.slot
+ */
+int
+rfs4x_sequence_prep(COMPOUND4args *args, COMPOUND4res *resp,
+ compound_state_t *cs)
+{
+ SEQUENCE4args *sargs;
+ nfsstat4 status;
+ rfs4_slot_t *slot;
+
+ if (args->array_len == 0 || args->array[0].argop != OP_SEQUENCE)
+ return (NFS4_OK);
+
+ sargs = &args->array[0].nfs_argop4_u.opsequence;
+
+ status = rfs4x_find_session(sargs, cs);
+ if (status != NFS4_OK)
+ return (status);
+
+ /* have reference to session */
+ slot = &cs->sp->sn_slots[sargs->sa_slotid];
+
+ mutex_enter(&slot->se_lock);
+ status = check_slot_seqid(slot, sargs->sa_sequenceid);
+ if (status == nfserr_replay_cache) {
+ if (slot->se_flags & RFS4_SLOT_CACHED) {
+ slot->se_flags |= RFS4_SLOT_INUSE;
+ cs->slot = slot;
+ *resp = slot->se_buf;
+ } else {
+ status = NFS4ERR_SEQ_MISORDERED;
+ }
+ } else if (status == NFS4_OK) {
+ slot->se_flags |= RFS4_SLOT_INUSE;
+ cs->slot = slot;
+ }
+ mutex_exit(&slot->se_lock);
+
+ return (status);
+}
+
+/*
+ * Do cleanup things
+ * 1. cache reply
+ * 2. release slot
+ */
+void
+rfs4x_sequence_done(COMPOUND4res *resp, compound_state_t *cs)
+{
+ rfs4_slot_t *slot = cs->slot;
+ rfs4_session_t *sp = cs->sp;
+ int add = 0;
+
+ ASSERT(slot != NULL);
+ ASSERT(sp != NULL);
+
+ mutex_enter(&slot->se_lock);
+ slot->se_flags &= ~RFS4_SLOT_INUSE;
+
+ if (*cs->statusp != nfserr_replay_cache) {
+ if (slot->se_flags & RFS4_SLOT_CACHED) {
+ rfs4_compound_free(&slot->se_buf);
+ slot->se_flags &= ~RFS4_SLOT_CACHED;
+ add = -1;
+ }
+
+ if (*cs->statusp == NFS4_OK && cs->cachethis) {
+ slot->se_flags |= RFS4_SLOT_CACHED;
+ slot->se_buf = *resp; /* cache a reply */
+ add += 1;
+ } else {
+ rfs4_compound_free(resp);
+ }
+ }
+ mutex_exit(&slot->se_lock);
+
+ if (add != 0)
+ atomic_add_32(&sp->sn_rcached, add);
+}
+
+/*
+ * Process the SEQUENCE operation. The session pointer has already been
+ * cached in the compound state, so we just dereference
+ */
+/*ARGSUSED*/
+void
+rfs4x_op_sequence(nfs_argop4 *argop, nfs_resop4 *resop,
+ struct svc_req *req, compound_state_t *cs)
+{
+ SEQUENCE4args *args = &argop->nfs_argop4_u.opsequence;
+ SEQUENCE4res *resp = &resop->nfs_resop4_u.opsequence;
+ SEQUENCE4resok *rok = &resp->SEQUENCE4res_u.sr_resok4;
+ rfs4_session_t *sp = cs->sp;
+ rfs4_slot_t *slot = cs->slot;
+ nfsstat4 status = NFS4_OK;
+ uint32_t cbstat = 0x0;
+
+ DTRACE_NFSV4_2(op__sequence__start,
+ struct compound_state *, cs,
+ SEQUENCE4args *, args);
+
+ ASSERT(sp != NULL && slot != NULL);
+
+ if (cs->op_pos != 0) {
+ status = NFS4ERR_SEQUENCE_POS;
+ goto out;
+ }
+
+ if (rfs4_lease_expired(sp->sn_clnt)) {
+ status = NFS4ERR_BADSESSION;
+ goto out;
+ }
+
+ /*
+ * If the back channel has been established...
+ * . if the channel has _not_ been marked as failed _AND_
+ * there are connections that have pings outstanding,
+ * we go ahead and fire the thread to traverse all of
+ * the session's conns, issuing CB_NULL's to those that
+ * need a ping.
+ * . if the channel is _not_ OK (ie. failed), then notify
+ * client that there is currently a problem with the CB
+ * path.
+ */
+ rfs4_dbe_lock(sp->sn_dbe);
+ if (SN_CB_CHAN_EST(sp)) {
+ if (SN_CB_CHAN_OK(sp)) {
+ if (sp->sn_bc.pngcnt > 0 && !sp->sn_bc.pnginprog) {
+ kthread_t *t;
+
+ rfs4x_session_hold(sp);
+ t = thread_create(NULL, 0, ping_cb_null_thr,
+ sp, 0, &p0, TS_RUN, minclsyspri);
+ if (!t)
+ rfs4x_session_rele(sp);
+ }
+ } else {
+ cbstat |= SEQ4_STATUS_CB_PATH_DOWN;
+ }
+ }
+ cs->client = sp->sn_clnt;
+
+ DTRACE_PROBE1(compound_clid, clientid4, cs->client->rc_clientid);
+
+ ASSERT(args->sa_sequenceid == slot->se_seqid + 1);
+
+ /*
+ * New request.
+ */
+ mutex_enter(&slot->se_lock);
+ slot->se_seqid = args->sa_sequenceid;
+ mutex_exit(&slot->se_lock);
+
+ /*
+ * Update access time and lease
+ */
+ cs->slotno = args->sa_slotid;
+ sp->sn_laccess = nfs_sys_uptime();
+ rfs4_update_lease(cs->client);
+
+ /*
+ * Let's keep it simple for now
+ */
+ bcopy(sp->sn_sessid, rok->sr_sessionid, sizeof (sessionid4));
+ rok->sr_sequenceid = slot->se_seqid;
+ rok->sr_slotid = args->sa_slotid;
+ rok->sr_highest_slotid =
+ sp->sn_fore->cn_attrs.ca_maxrequests - 1;
+ rok->sr_target_highest_slotid =
+ sp->sn_fore->cn_attrs.ca_maxrequests - 1;
+ rok->sr_status_flags |= cbstat;
+ rfs4_dbe_unlock(sp->sn_dbe);
+out:
+ *cs->statusp = resp->sr_status = status;
+ DTRACE_NFSV4_2(op__sequence__done,
+ struct compound_state *, cs,
+ SEQUENCE4res *, resp);
+}
+
+/* ARGSUSED */
+void
+rfs4x_op_reclaim_complete(nfs_argop4 *argop, nfs_resop4 *resop,
+ struct svc_req *req, compound_state_t *cs)
+{
+ RECLAIM_COMPLETE4args *args = &argop->nfs_argop4_u.opreclaim_complete;
+ RECLAIM_COMPLETE4res *resp = &resop->nfs_resop4_u.opreclaim_complete;
+ rfs4_client_t *cp;
+ nfsstat4 status = NFS4_OK;
+
+ DTRACE_NFSV4_2(op__reclaim__complete__start,
+ struct compound_state *, cs,
+ RECLAIM_COMPLETE4args *, args);
+
+ cp = cs->client;
+ rfs4_dbe_lock(cp->rc_dbe);
+ if (args->rca_one_fs) {
+ /* do what? we don't track this */
+ goto out;
+ }
+
+ if (cp->rc_reclaim_completed) {
+ status = NFS4ERR_COMPLETE_ALREADY;
+ goto out;
+ }
+
+ if (cp->rc_can_reclaim) {
+ ASSERT(rfs4_servinst(cp)->nreclaim > 0);
+ atomic_add_32(&(rfs4_servinst(cp))->nreclaim, -1);
+ }
+
+ cp->rc_reclaim_completed = 1;
+out:
+ rfs4_dbe_unlock(cp->rc_dbe);
+
+ *cs->statusp = resp->rcr_status = status;
+ DTRACE_NFSV4_2(op__reclaim__complete__done,
+ struct compound_state *, cs,
+ RECLAIM_COMPLETE4res *, resp);
+}
+
+/* ARGSUSED */
+void
+rfs4x_op_destroy_clientid(nfs_argop4 *argop, nfs_resop4 *resop,
+ struct svc_req *req, compound_state_t *cs)
+{
+ DESTROY_CLIENTID4args *args = &argop->nfs_argop4_u.opdestroy_clientid;
+ DESTROY_CLIENTID4res *resp = &resop->nfs_resop4_u.opdestroy_clientid;
+ rfs4_client_t *cp;
+ nfsstat4 status = NFS4_OK;
+
+ DTRACE_NFSV4_2(op__destroy__clientid__start,
+ struct compound_state *, cs,
+ DESTROY_CLIENTID4args *, args);
+
+ cp = rfs4_findclient_by_id(args->dca_clientid, TRUE);
+ if (cp == NULL) {
+ status = NFS4ERR_STALE_CLIENTID;
+ goto end;
+ }
+
+ rfs4_dbe_lock(cp->rc_dbe);
+ if (client_has_state_locked(cp))
+ status = NFS4ERR_CLIENTID_BUSY;
+ else
+ cp->rc_destroying = TRUE;
+ rfs4_dbe_unlock(cp->rc_dbe);
+
+ if (status == NFS4_OK)
+ rfs4_client_close(cp);
+ else
+ rfs4_client_rele(cp);
+end:
+ *cs->statusp = resp->dcr_status = status;
+
+ DTRACE_NFSV4_2(op__destroy__clientid__done,
+ struct compound_state *, cs,
+ DESTROY_CLIENTID4res *, resp);
+}
+
+/*ARGSUSED*/
+void
+rfs4x_op_bind_conn_to_session(nfs_argop4 *argop, nfs_resop4 *resop,
+ struct svc_req *req, compound_state_t *cs)
+{
+ BIND_CONN_TO_SESSION4args *args =
+ &argop->nfs_argop4_u.opbind_conn_to_session;
+ BIND_CONN_TO_SESSION4res *resp =
+ &resop->nfs_resop4_u.opbind_conn_to_session;
+ BIND_CONN_TO_SESSION4resok *rok =
+ &resp->BIND_CONN_TO_SESSION4res_u.bctsr_resok4;
+ rfs4_session_t *sp;
+ nfsstat4 status = NFS4_OK;
+
+ DTRACE_NFSV4_2(op__bind__conn__to__session__start,
+ struct compound_state *, cs,
+ BIND_CONN_TO_SESSION4args *, args);
+
+ if (cs->op_pos != 0) {
+ status = NFS4ERR_NOT_ONLY_OP;
+ goto end;
+ }
+
+ sp = rfs4x_findsession_by_id(args->bctsa_sessid);
+ if (sp == NULL) {
+ status = NFS4ERR_BADSESSION;
+ goto end;
+ }
+
+ rfs4_update_lease(sp->sn_clnt); /* no need lock protection */
+
+ rfs4_dbe_lock(sp->sn_dbe);
+ sp->sn_laccess = nfs_sys_uptime();
+ rfs4_dbe_unlock(sp->sn_dbe);
+
+ rok->bctsr_use_conn_in_rdma_mode = FALSE;
+
+ switch (args->bctsa_dir) {
+ case CDFC4_FORE:
+ case CDFC4_FORE_OR_BOTH:
+ /* always map to Fore */
+ rok->bctsr_dir = CDFS4_FORE;
+ break;
+
+ case CDFC4_BACK:
+ case CDFC4_BACK_OR_BOTH:
+ /* TODO: always map to Back */
+ rok->bctsr_dir = CDFS4_FORE;
+ break;
+ default:
+ break;
+ }
+
+ bcopy(sp->sn_sessid, rok->bctsr_sessid, sizeof (sessionid4));
+ rfs4x_session_rele(sp);
+end:
+ *cs->statusp = resp->bctsr_status = status;
+
+ DTRACE_NFSV4_2(op__bind__conn__to__session__done,
+ struct compound_state *, cs,
+ BIND_CONN_TO_SESSION4res *, resp);
+}
+
+/* ARGSUSED */
+void
+rfs4x_op_secinfo_noname(nfs_argop4 *argop, nfs_resop4 *resop,
+ struct svc_req *req, compound_state_t *cs)
+{
+ SECINFO_NO_NAME4res *resp = &resop->nfs_resop4_u.opsecinfo_no_name;
+ nfsstat4 status;
+ bool_t dotdot;
+
+ DTRACE_NFSV4_1(op__secinfo__no__name__start,
+ struct compound_state *, cs);
+
+ if (cs->vp == NULL) {
+ status = NFS4ERR_NOFILEHANDLE;
+ goto out;
+ }
+
+ if (cs->vp->v_type != VDIR) {
+ status = NFS4ERR_NOTDIR;
+ goto out;
+ }
+
+ dotdot =
+ (argop->nfs_argop4_u.opsecinfo_no_name == SECINFO_STYLE4_PARENT);
+
+ status = do_rfs4_op_secinfo(cs, dotdot ? ".." : ".", resp);
+
+ /* Cleanup FH as described at 18.45.3 and 2.6.3.1.1.8 */
+ if (status == NFS4_OK) {
+ VN_RELE(cs->vp);
+ cs->vp = NULL;
+ }
+out:
+ *cs->statusp = resp->status = status;
+
+ DTRACE_NFSV4_2(op__secinfo__no__name__done,
+ struct compound_state *, cs,
+ SECINFO_NO_NAME4res *, resp);
+}
diff --git a/usr/src/uts/common/fs/nfs/nfs4x_state.c b/usr/src/uts/common/fs/nfs/nfs4x_state.c
new file mode 100644
index 0000000000..aba02734fc
--- /dev/null
+++ b/usr/src/uts/common/fs/nfs/nfs4x_state.c
@@ -0,0 +1,576 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2017 RackTop Systems.
+ */
+
+#include <sys/sdt.h>
+#include <sys/atomic.h>
+#include <nfs/nfs4.h>
+
+#ifdef DEBUG
+#define RFS4_TABSIZE 17
+#else
+#define RFS4_TABSIZE 2047
+#endif
+
+#define RFS4_MAXTABSZ 1024*1024
+
+slotid4 rfs4_max_slots = MAXSLOTS; /* fore channel */
+slotid4 rfs4_back_max_slots = MAXSLOTS_BACK; /* back channel */
+
+typedef union {
+ /* Both members have the same size */
+ struct {
+ uint32_t pad0;
+ uint32_t pad1;
+ uint32_t start_time; /* NFS server start time */
+ uint32_t s_id; /* unique session index */
+ } impl_id;
+ sessionid4 id4;
+} rfs4_sid;
+
+/*
+ * --------------------------------------------------------
+ * MDS - NFSv4.1 Sessions
+ * --------------------------------------------------------
+ */
+static uint32_t
+sessid_hash(void *key)
+{
+ rfs4_sid *idp = key;
+
+ return (idp->impl_id.s_id);
+}
+
+static bool_t
+sessid_compare(rfs4_entry_t entry, void *key)
+{
+ rfs4_session_t *sp = (rfs4_session_t *)entry;
+ sessionid4 *idp = (sessionid4 *)key;
+
+ return (bcmp(idp, &sp->sn_sessid, sizeof (sessionid4)) == 0);
+}
+
+static void *
+sessid_mkkey(rfs4_entry_t entry)
+{
+ rfs4_session_t *sp = (rfs4_session_t *)entry;
+
+ return (&sp->sn_sessid);
+}
+
+/* ARGSUSED */
+static bool_t
+cmp_false(rfs4_entry_t entry, void *key)
+{
+ return (FALSE);
+}
+
+/* ARGSUSED */
+static void *
+mkkey_null(rfs4_entry_t entry)
+{
+ return (NULL);
+}
+
+void
+rfs4x_session_rele(rfs4_session_t *sp)
+{
+ rfs4_dbe_rele(sp->sn_dbe);
+}
+
+void
+rfs4x_session_hold(rfs4_session_t *sp)
+{
+ rfs4_dbe_hold(sp->sn_dbe);
+}
+
+rfs4_session_t *
+rfs4x_findsession_by_id(sessionid4 sessid)
+{
+ rfs4_session_t *sp;
+ bool_t create = FALSE;
+ nfs4_srv_t *nsrv4 = nfs4_get_srv();
+
+ rw_enter(&nsrv4->findsession_lock, RW_READER);
+ sp = (rfs4_session_t *)rfs4_dbsearch(nsrv4->rfs4_session_idx,
+ sessid, &create, NULL, RFS4_DBS_VALID);
+ rw_exit(&nsrv4->findsession_lock);
+
+ return (sp);
+}
+
+/*
+ * A clientid can have multiple sessions associated with it. Hence,
+ * performing a raw 'mds_findsession' (even for a create) might
+ * yield a list of sessions associated with the clientid in question.
+ * Call rfs4_dbseach() function with key that cannot be found
+ * and create an association between the session table and both
+ * primary (sessionid) index and secondary (clientid) index for the
+ * newly created session.
+ */
+
+rfs4_session_t *
+rfs4x_createsession(session41_create_t *ap)
+{
+ static volatile uint32_t session_id_counter;
+
+ rfs4_session_t *sp = NULL;
+ bool_t create = TRUE;
+ rfs4_sid key = {0, 0, 0, 0};
+ nfs4_srv_t *nsrv4 = nfs4_get_srv();
+
+ /*
+ * Use unique counter for s_id and s_id to ensure that
+ * created entry will have the same index in dbi_buckets[]
+ */
+ ap->cs_id = key.impl_id.s_id = atomic_inc_32_nv(&session_id_counter);
+
+ rw_enter(&nsrv4->findsession_lock, RW_WRITER);
+ if ((sp = (rfs4_session_t *)rfs4_dbsearch(nsrv4->rfs4_session_idx,
+ &key, &create, (void *)ap, RFS4_DBS_VALID)) == NULL) {
+ DTRACE_PROBE1(mds__srv__createsession__fail,
+ session41_create_t *, ap);
+ }
+ rw_exit(&nsrv4->findsession_lock);
+ return (sp);
+}
+
+/* return success of operation */
+static bool_t
+client_insert_session(rfs4_client_t *cp, rfs4_session_t *sp)
+{
+ bool_t res = TRUE;
+
+ rfs4_dbe_lock(cp->rc_dbe);
+ if (cp->rc_destroying)
+ res = FALSE;
+ else
+ list_insert_tail(&cp->rc_sessions, sp);
+ rfs4_dbe_unlock(cp->rc_dbe);
+
+ return (res);
+}
+
+static void
+client_remove_session(rfs4_client_t *cp, rfs4_session_t *sp)
+{
+ rfs4_dbe_lock(cp->rc_dbe);
+ if (list_link_active(&sp->sn_node))
+ list_remove(&cp->rc_sessions, sp);
+ rfs4_dbe_unlock(cp->rc_dbe);
+}
+
+/*
+ * Invalidate the session in the DB (so it can't be found anymore)
+ */
+nfsstat4
+rfs4x_destroysession(rfs4_session_t *sp, unsigned useref)
+{
+ nfsstat4 status = NFS4_OK;
+
+ /*
+ * RFC 7862 Section 14.1.3:
+ * In hindsight, the NFSv4.1 specification should have
+ * mandated that DESTROY_SESSION either abort or complete
+ * all outstanding operations.
+ */
+ rfs4_dbe_lock(sp->sn_dbe);
+ if (rfs4_dbe_refcnt(sp->sn_dbe) > useref)
+ status = NFS4ERR_DELAY;
+ else
+ rfs4_dbe_invalidate(sp->sn_dbe);
+ rfs4_dbe_unlock(sp->sn_dbe);
+
+ if (status == NFS4_OK)
+ client_remove_session(sp->sn_clnt, sp);
+
+ return (status);
+}
+
+/* Invalidate all client's sessions */
+void
+rfs4x_client_session_remove(rfs4_client_t *cp)
+{
+ rfs4_session_t *sp;
+
+ /*
+ * Client is forcibly closing so invalidate all sessions
+ * without checking the refcount.
+ */
+ rfs4_dbe_lock(cp->rc_dbe);
+ while ((sp = list_head(&cp->rc_sessions)) != NULL) {
+ list_remove(&cp->rc_sessions, sp);
+
+ rfs4_dbe_lock(sp->sn_dbe);
+ rfs4_dbe_invalidate(sp->sn_dbe);
+ rfs4_dbe_unlock(sp->sn_dbe);
+
+ }
+ rfs4_dbe_unlock(cp->rc_dbe);
+}
+
+nfsstat4
+sess_chan_limits(sess_channel_t *scp)
+{
+ if (scp->cn_attrs.ca_maxrequests > rfs4_max_slots) {
+ scp->cn_attrs.ca_maxrequests = rfs4_max_slots;
+ }
+
+ if (scp->cn_back_attrs.ca_maxrequests > rfs4_back_max_slots)
+ scp->cn_back_attrs.ca_maxrequests = rfs4_back_max_slots;
+
+
+ if (scp->cn_attrs.ca_maxoperations > NFS4_COMPOUND_LIMIT)
+ scp->cn_attrs.ca_maxoperations = NFS4_COMPOUND_LIMIT;
+
+ /*
+ * Lower limit should be set to smallest sane COMPOUND. Even
+ * though a singleton SEQUENCE op is the very smallest COMPOUND,
+ * it's also quite boring. For all practical purposes, the lower
+ * limit for creating a sess is limited to:
+ *
+ * [SEQUENCE + PUTROOTFH + GETFH]
+ *
+ * XXX - can't limit READ's to a specific threshold, otherwise
+ * we artificially limit the clients to perform reads of
+ * AT LEAST that granularity, which is WRONG !!! Same goes
+ * for READDIR's and GETATTR's.
+ */
+ if (scp->cn_attrs.ca_maxresponsesize < (sizeof (SEQUENCE4res) +
+ sizeof (PUTROOTFH4res) + sizeof (GETFH4res)))
+ return (NFS4ERR_TOOSMALL);
+ return (NFS4_OK);
+}
+
+/*
+ * NFSv4.1 Slot replay cache
+ */
+static void
+rfs41_cleanup_slot(rfs4_slot_t *se)
+{
+ rfs4_compound_free((COMPOUND4res *)&se->se_buf);
+}
+
+static rfs4_slot_t *
+slots_alloc(size_t n)
+{
+ rfs4_slot_t *p;
+ int i;
+
+ p = kmem_zalloc(sizeof (rfs4_slot_t) * n, KM_SLEEP);
+ for (i = 0; i < n; i++) {
+ mutex_init(&p[i].se_lock, NULL, MUTEX_DEFAULT, NULL);
+ }
+
+ return (p);
+}
+
+static void
+slots_free(rfs4_slot_t *slots, size_t n)
+{
+ int i;
+
+ for (i = 0; i < n; i++) {
+ rfs4_slot_t *slot = &slots[i];
+
+ mutex_destroy(&slot->se_lock);
+
+ if (slot->se_flags & RFS4_SLOT_CACHED) {
+ rfs41_cleanup_slot(slot);
+ }
+ }
+ kmem_free(slots, sizeof (rfs4_slot_t) * n);
+}
+
+/* Additional functions */
+
+/* check csa_flags for OP_CREATE_SESSION */
+bool_t
+nfs4x_csa_flags_valid(uint32_t flags)
+{
+ if (flags & ~CREATE_SESSION4_FLAG_MASK)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+sess_channel_t *
+rfs41_create_session_channel(channel_dir_from_server4 dir)
+{
+ sess_channel_t *cp;
+ sess_bcsd_t *bp;
+
+ cp = (sess_channel_t *)kmem_zalloc(sizeof (sess_channel_t), KM_SLEEP);
+ rw_init(&cp->cn_lock, NULL, RW_DEFAULT, NULL);
+
+ switch (dir) {
+ case CDFS4_FORE:
+ break;
+
+ case CDFS4_BOTH:
+ case CDFS4_BACK:
+ /* BackChan Specific Data */
+ bp = (sess_bcsd_t *)kmem_zalloc(sizeof (sess_bcsd_t), KM_SLEEP);
+ rw_init(&bp->bsd_rwlock, NULL, RW_DEFAULT, NULL);
+ cp->cn_csd = (sess_bcsd_t *)bp;
+ break;
+ }
+ return (cp);
+}
+
+void
+rfs41_destroy_session_channel(rfs4_session_t *sp)
+{
+ sess_channel_t *cp;
+ sess_bcsd_t *bp;
+
+ if (sp->sn_back != NULL) {
+ /* only one channel for both direction for now */
+ ASSERT(sp->sn_fore == sp->sn_back);
+
+ cp = sp->sn_back;
+ bp = (sess_bcsd_t *)cp->cn_csd;
+ rw_destroy(&bp->bsd_rwlock);
+ kmem_free(bp, sizeof (sess_bcsd_t));
+ } else {
+ cp = sp->sn_fore;
+ }
+
+ rw_destroy(&cp->cn_lock);
+ kmem_free(cp, sizeof (sess_channel_t));
+
+ sp->sn_back = NULL;
+ sp->sn_fore = NULL;
+}
+
+static bool_t
+rfs4_session_create(rfs4_entry_t u_entry, void *arg)
+{
+ rfs4_session_t *sp = (rfs4_session_t *)u_entry;
+ session41_create_t *ap = (session41_create_t *)arg;
+ sess_channel_t *ocp = NULL;
+ rfs4_sid *sidp;
+ bool_t bdrpc = FALSE;
+ channel_dir_from_server4 dir;
+ nfsstat4 sle;
+ nfs4_srv_t *nsrv4 = nfs4_get_srv();
+
+ ASSERT(sp != NULL);
+ if (sp == NULL)
+ return (FALSE);
+
+ /*
+ * Back pointer/ref to parent data struct (rfs4_client_t)
+ */
+ sp->sn_clnt = (rfs4_client_t *)ap->cs_client;
+ rfs4_dbe_hold(sp->sn_clnt->rc_dbe);
+
+ /*
+ * Handcrafting the session id
+ */
+ sidp = (rfs4_sid *)&sp->sn_sessid;
+ sidp->impl_id.pad0 = 0x00000000;
+ sidp->impl_id.pad1 = 0xFFFFFFFF;
+ sidp->impl_id.start_time = nsrv4->rfs4_start_time;
+ sidp->impl_id.s_id = ap->cs_id;
+
+ /*
+ * Process csa_flags; note that CREATE_SESSION4_FLAG_CONN_BACK_CHAN
+ * is processed below since it affects direction and setup of the
+ * backchannel accordingly.
+ */
+ if (!nfs4x_csa_flags_valid(ap->cs_aotw.csa_flags)) {
+ ap->cs_error = NFS4ERR_INVAL;
+ goto err;
+ }
+
+ sp->sn_csflags = 0;
+ if (ap->cs_aotw.csa_flags & CREATE_SESSION4_FLAG_PERSIST)
+ /* XXX - Worry about persistence later */
+ sp->sn_csflags &= ~CREATE_SESSION4_FLAG_PERSIST;
+
+ if (ap->cs_aotw.csa_flags & CREATE_SESSION4_FLAG_CONN_RDMA)
+ /* XXX - No RDMA for now */
+ sp->sn_csflags &= ~CREATE_SESSION4_FLAG_CONN_RDMA;
+
+ /*
+ * Initialize some overall sessions values
+ */
+ sp->sn_bc.progno = ap->cs_aotw.csa_cb_program;
+ sp->sn_laccess = nfs_sys_uptime();
+ sp->sn_flags = 0;
+ sp->sn_rcached = 0;
+
+ /*
+ * Check if client has specified that the FORE channel should
+ * also be used for call back traffic (ie. bidir RPC). If so,
+ * let's try to accomodate the request.
+ */
+ DTRACE_PROBE1(csa__flags, uint32_t, ap->cs_aotw.csa_flags);
+
+ /*
+ * Session's channel flags depending on bdrpc
+ * TODO: Add backchannel handling, i.e. when bdrpc is TRUE
+ */
+ dir = bdrpc ? (CDFS4_FORE | CDFS4_BACK) : CDFS4_FORE;
+ ocp = rfs41_create_session_channel(dir);
+ ocp->cn_dir = dir;
+ sp->sn_fore = ocp;
+
+ /*
+ * Check if channel attrs will be flexible enough for future
+ * purposes. Channel attribute enforcement is done as part of
+ * COMPOUND processing.
+ */
+ ocp->cn_attrs = ap->cs_aotw.csa_fore_chan_attrs;
+ ocp->cn_back_attrs = ap->cs_aotw.csa_back_chan_attrs;
+ if (sle = sess_chan_limits(ocp)) {
+ ap->cs_error = sle;
+ goto err_free_chan;
+ }
+
+ /* will fail if client is going to destroy */
+ if (!client_insert_session(sp->sn_clnt, sp)) {
+ ap->cs_error = NFS4ERR_DELAY;
+ goto err_free_chan;
+ }
+
+ /*
+ * No need for locks/synchronization at this time,
+ * since we're barely creating the session.
+ */
+ if (bdrpc) {
+ /* Need to be implemented */
+ VERIFY(0);
+ } else {
+ /*
+ * If not doing bdrpc, then we expect the client to perform
+ * an explicit BIND_CONN_TO_SESSION if it wants callback
+ * traffic. Subsequently, the cb channel should be set up
+ * at that point along with its corresponding slot (see
+ * rfs41_bc_setup).
+ */
+ sp->sn_csflags &= ~CREATE_SESSION4_FLAG_CONN_BACK_CHAN;
+ sp->sn_back = NULL;
+
+ /*
+ * XXX 08/15/2008 (rick) - if the channel is not bidir when
+ * created in CREATE_SESSION, then we should save off
+ * the ap->cs_aotw.csa_back_chan_attrs in case later
+ * a bc2s is called to create the back channel.
+ */
+ }
+
+ /*
+ * Now we allocate space for the slrc, initializing each slot's
+ * sequenceid and slotid to zero and a (pre)cached result of
+ * NFS4ERR_SEQ_MISORDERED. Note that we zero out the entries
+ * by virtue of the z-alloc.
+ */
+ sp->sn_slots = slots_alloc(ocp->cn_attrs.ca_maxrequests);
+
+ return (TRUE);
+
+err_free_chan:
+ rfs41_destroy_session_channel(sp);
+err:
+ rfs4_dbe_rele(sp->sn_clnt->rc_dbe);
+ return (FALSE);
+}
+
+static void
+rfs4_session_destroy(rfs4_entry_t u_entry)
+{
+ rfs4_session_t *sp = (rfs4_session_t *)u_entry;
+ sess_bcsd_t *bsdp;
+
+ if (SN_CB_CHAN_EST(sp) && (bsdp = sp->sn_back->cn_csd) != NULL) {
+ slots_free(bsdp->bsd_slots,
+ sp->sn_back->cn_back_attrs.ca_maxrequests);
+ bsdp->bsd_slots = NULL;
+ }
+
+ /*
+ * Nuke slot replay cache for this session
+ */
+ if (sp->sn_slots) {
+ slots_free(sp->sn_slots, sp->sn_fore->cn_attrs.ca_maxrequests);
+ sp->sn_slots = NULL;
+ }
+
+ /*
+ * XXX - A session can have multiple BC clnt handles that need
+ * to be discarded. rfs4_session_inval calls CLNT_DESTROY
+ * which will remove the CB client handle from the global
+ * list (cb_clnt_list) now. This will have to change once
+ * we manage the BC clnt handles per session.
+ */
+
+ /*
+ * Remove the fore and back channels.
+ */
+ rfs41_destroy_session_channel(sp);
+
+ client_remove_session(sp->sn_clnt, sp);
+
+ rfs4_client_rele(sp->sn_clnt);
+}
+
+static bool_t
+rfs4_session_expiry(rfs4_entry_t u_entry)
+{
+ rfs4_session_t *sp = (rfs4_session_t *)u_entry;
+
+ if (sp == NULL || rfs4_dbe_is_invalid(sp->sn_dbe))
+ return (TRUE);
+
+ if (rfs4_lease_expired(sp->sn_clnt))
+ return (TRUE);
+
+ return (FALSE);
+}
+
+void
+rfs4x_state_init_locked(nfs4_srv_t *nsrv4)
+{
+ rw_init(&nsrv4->findsession_lock, NULL, RW_DEFAULT, NULL);
+
+ nsrv4->rfs4_session_tab = rfs4_table_create(nsrv4->nfs4_server_state,
+ "Session", 5 * rfs4_lease_time, 1, rfs4_session_create,
+ rfs4_session_destroy, rfs4_session_expiry, sizeof (rfs4_session_t),
+ RFS4_TABSIZE, RFS4_MAXTABSZ/8, 100);
+
+ nsrv4->rfs4_session_idx = rfs4_index_create(nsrv4->rfs4_session_tab,
+ "session_idx", sessid_hash, sessid_compare, sessid_mkkey, TRUE);
+}
+
+void
+rfs4x_state_fini(nfs4_srv_t *nsrv4)
+{
+ /* All tables will be destroyed by caller */
+ rw_destroy(&nsrv4->findsession_lock);
+}
diff --git a/usr/src/uts/common/fs/nfs/nfs4x_xdr.c b/usr/src/uts/common/fs/nfs/nfs4x_xdr.c
new file mode 100644
index 0000000000..7b4bce31f8
--- /dev/null
+++ b/usr/src/uts/common/fs/nfs/nfs4x_xdr.c
@@ -0,0 +1,2935 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2017 RackTop Systems.
+ */
+
+/*
+ * This file contains the xdr for datatypes and operations that are
+ * specific to NFSv4 minor version 1 (i.e., datatypes that
+ * were either introduced or changed by the NFSv4.1 specification).
+ */
+
+/*
+ * INSTRUCTIONS for updating to a new NFSv4.1:
+ *
+ * **DO NOT** simply replace this file with code rpcgen creates
+ * and then remove non-NFS41 code. The file now contains the hand
+ * coded xdr for the NFS4.1 attributes. If you run rpcgen,
+ * manually integrate parts related to the draft diffs.
+ */
+#include <sys/statvfs.h>
+#include <sys/sysmacros.h>
+#include <sys/sdt.h>
+#include <nfs/nfs4.h>
+#include <nfs/nfs4_attr.h>
+
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif /* !_KERNEL */
+
+/* modified version */
+bool_t
+xdr_verifier4(XDR *xdrs, verifier4 *objp)
+{
+ if (!xdr_u_longlong_t(xdrs, (u_longlong_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_sequenceid4(XDR *xdrs, sequenceid4 *objp)
+{
+ if (!xdr_uint32_t(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_sessionid4(XDR *xdrs, sessionid4 objp)
+{
+ if (!xdr_opaque(xdrs, objp, NFS4_SESSIONID_SIZE))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_slotid4(XDR *xdrs, slotid4 *objp)
+{
+
+ if (!xdr_uint32_t(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_change_policy4(XDR *xdrs, change_policy4 *objp)
+{
+ if (!xdr_uint64_t(xdrs, &objp->cp_major))
+ return (FALSE);
+ if (!xdr_uint64_t(xdrs, &objp->cp_minor))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_aclflag4(XDR *xdrs, aclflag4 *objp)
+{
+ if (!xdr_uint32_t(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_nfsacl41(XDR *xdrs, nfsacl41 *objp)
+{
+ if (!xdr_aclflag4(xdrs, &objp->na41_flag))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->na41_aces.na41_aces_val,
+ (uint_t *)&objp->na41_aces.na41_aces_len, ~0, sizeof (nfsace4),
+ (xdrproc_t)xdr_nfsace4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_mode_masked4(XDR *xdrs, mode_masked4 *objp)
+{
+ if (!xdr_mode4(xdrs, &objp->mm_value_to_set))
+ return (FALSE);
+ if (!xdr_mode4(xdrs, &objp->mm_mask_bits))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_nfs_impl_id4(XDR *xdrs, nfs_impl_id4 *objp)
+{
+ if (!xdr_utf8str_cis(xdrs, &objp->nii_domain))
+ return (FALSE);
+ if (!xdr_utf8str_cs(xdrs, &objp->nii_name))
+ return (FALSE);
+ if (!xdr_nfstime4(xdrs, &objp->nii_date))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_layouttype4(XDR *xdrs, layouttype4 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_layout_content4(XDR *xdrs, layout_content4 *objp)
+{
+ if (!xdr_layouttype4(xdrs, &objp->loc_type))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->loc_body.loc_body_val,
+ (uint_t *)&objp->loc_body.loc_body_len, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_layoutiomode4(XDR *xdrs, layoutiomode4 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+
+bool_t
+xdr_layout4(XDR *xdrs, layout4 *objp)
+{
+ if (!xdr_offset4(xdrs, &objp->lo_offset))
+ return (FALSE);
+ if (!xdr_length4(xdrs, &objp->lo_length))
+ return (FALSE);
+ if (!xdr_layoutiomode4(xdrs, &objp->lo_iomode))
+ return (FALSE);
+ if (!xdr_layout_content4(xdrs, &objp->lo_content))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_deviceid4(XDR *xdrs, deviceid4 objp)
+{
+ if (!xdr_opaque(xdrs, objp, NFS4_DEVICEID4_SIZE))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_device_addr4(XDR *xdrs, device_addr4 *objp)
+{
+ if (!xdr_layouttype4(xdrs, &objp->da_layout_type))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->da_addr_body.da_addr_body_val,
+ (uint_t *)&objp->da_addr_body.da_addr_body_len, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_layoutupdate4(XDR *xdrs, layoutupdate4 *objp)
+{
+ if (!xdr_layouttype4(xdrs, &objp->lou_type))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->lou_body.lou_body_val,
+ (uint_t *)&objp->lou_body.lou_body_len, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_layoutreturn_type4(XDR *xdrs, layoutreturn_type4 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+/* layouttype4 specific data */
+
+bool_t
+xdr_layoutreturn_file4(XDR *xdrs, layoutreturn_file4 *objp)
+{
+ if (!xdr_offset4(xdrs, &objp->lrf_offset))
+ return (FALSE);
+ if (!xdr_length4(xdrs, &objp->lrf_length))
+ return (FALSE);
+ if (!xdr_stateid4(xdrs, &objp->lrf_stateid))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->lrf_body.lrf_body_val,
+ (uint_t *)&objp->lrf_body.lrf_body_len, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_layoutreturn4(XDR *xdrs, layoutreturn4 *objp)
+{
+ if (!xdr_layoutreturn_type4(xdrs, &objp->lr_returntype))
+ return (FALSE);
+ switch (objp->lr_returntype) {
+ case LAYOUTRETURN4_FILE:
+ if (!xdr_layoutreturn_file4(xdrs,
+ &objp->layoutreturn4_u.lr_layout))
+ return (FALSE);
+ break;
+ }
+ return (TRUE);
+}
+
+
+bool_t
+xdr_fs4_status_type(XDR *xdrs, fs4_status_type *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fs4_status(XDR *xdrs, fs4_status *objp)
+{
+ if (!xdr_bool(xdrs, &objp->fss_absent))
+ return (FALSE);
+ if (!xdr_fs4_status_type(xdrs, &objp->fss_type))
+ return (FALSE);
+ if (!xdr_utf8str_cs(xdrs, &objp->fss_source))
+ return (FALSE);
+ if (!xdr_utf8str_cs(xdrs, &objp->fss_current))
+ return (FALSE);
+ if (!xdr_int32_t(xdrs, &objp->fss_age))
+ return (FALSE);
+ if (!xdr_nfstime4(xdrs, &objp->fss_version))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_threshold4_read_size(XDR *xdrs, threshold4_read_size *objp)
+{
+
+ if (!xdr_length4(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_threshold4_write_size(XDR *xdrs, threshold4_write_size *objp)
+{
+ if (!xdr_length4(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_threshold4_read_iosize(XDR *xdrs, threshold4_read_iosize *objp)
+{
+ if (!xdr_length4(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_threshold4_write_iosize(XDR *xdrs, threshold4_write_iosize *objp)
+{
+ if (!xdr_length4(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_threshold_item4(XDR *xdrs, threshold_item4 *objp)
+{
+ if (!xdr_layouttype4(xdrs, &objp->thi_layout_type))
+ return (FALSE);
+ if (!xdr_bitmap4(xdrs, &objp->thi_hintset))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->thi_hintlist.thi_hintlist_val,
+ (uint_t *)&objp->thi_hintlist.thi_hintlist_len, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_mdsthreshold4(XDR *xdrs, mdsthreshold4 *objp)
+{
+ if (!xdr_array(xdrs, (char **)&objp->mth_hints.mth_hints_val,
+ (uint_t *)&objp->mth_hints.mth_hints_len, ~0,
+ sizeof (threshold_item4), (xdrproc_t)xdr_threshold_item4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_retention_get4(XDR *xdrs, retention_get4 *objp)
+{
+ if (!xdr_uint64_t(xdrs, &objp->rg_duration))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->rg_begin_time.rg_begin_time_val,
+ (uint_t *)&objp->rg_begin_time.rg_begin_time_len, 1,
+ sizeof (nfstime4), (xdrproc_t)xdr_nfstime4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_retention_set4(XDR *xdrs, retention_set4 *objp)
+{
+ if (!xdr_bool(xdrs, &objp->rs_enable))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->rs_duration.rs_duration_val,
+ (uint_t *)&objp->rs_duration.rs_duration_len, 1, sizeof (uint64_t),
+ (xdrproc_t)xdr_uint64_t))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fs_charset_cap4(XDR *xdrs, fs_charset_cap4 *objp)
+{
+
+ if (!xdr_uint32_t(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fattr4_mode_set_masked(XDR *xdrs, fattr4_mode_set_masked *objp)
+{
+ if (!xdr_mode_masked4(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fattr4_dir_notif_delay(XDR *xdrs, fattr4_dir_notif_delay *objp)
+{
+
+ if (!xdr_nfstime4(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fattr4_dirent_notif_delay(XDR *xdrs, fattr4_dirent_notif_delay *objp)
+{
+ if (!xdr_nfstime4(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fattr4_fs_layout_types(XDR *xdrs, fattr4_fs_layout_types *objp)
+{
+ if (!xdr_array(xdrs, (char **)&objp->fattr4_fs_layout_types_val,
+ (uint_t *)&objp->fattr4_fs_layout_types_len, ~0,
+ sizeof (layouttype4), (xdrproc_t)xdr_layouttype4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fattr4_fs_status(XDR *xdrs, fattr4_fs_status *objp)
+{
+ if (!xdr_fs4_status(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fattr4_fs_charset_cap4(XDR *xdrs, fattr4_fs_charset_cap *objp)
+{
+ if (!xdr_fs_charset_cap4(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fattr4_retention_get(XDR *xdrs, fattr4_retention_get *objp)
+{
+ if (!xdr_retention_get4(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fattr4_retention_set(XDR *xdrs, fattr4_retention_set *objp)
+{
+ if (!xdr_retention_set4(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fattr4_retentevt_get(XDR *xdrs, fattr4_retentevt_get *objp)
+{
+ if (!xdr_retention_get4(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fattr4_retentevt_set(XDR *xdrs, fattr4_retentevt_set *objp)
+{
+ if (!xdr_retention_set4(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fattr4_retention_hold(XDR *xdrs, fattr4_retention_hold *objp)
+{
+ if (!xdr_uint64_t(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fattr4_dacl(XDR *xdrs, fattr4_dacl *objp)
+{
+ if (!xdr_nfsacl41(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fattr4_sacl(XDR *xdrs, fattr4_sacl *objp)
+{
+ if (!xdr_nfsacl41(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_client_owner4(XDR *xdrs, client_owner4 *objp)
+{
+ if (!xdr_verifier4(xdrs, (verifier4 *)&objp->co_verifier))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->co_ownerid.co_ownerid_val,
+ (uint_t *)&objp->co_ownerid.co_ownerid_len, NFS4_OPAQUE_LIMIT))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_server_owner4(XDR *xdrs, server_owner4 *objp)
+{
+ if (!xdr_uint64_t(xdrs, &objp->so_minor_id))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->so_major_id.so_major_id_val,
+ (uint_t *)&objp->so_major_id.so_major_id_len, NFS4_OPAQUE_LIMIT))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_state_owner4(XDR *xdrs, state_owner4 *objp)
+{
+ if (!xdr_clientid4(xdrs, &objp->clientid))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->owner.owner_val,
+ (uint_t *)&objp->owner.owner_len, NFS4_OPAQUE_LIMIT))
+ return (FALSE);
+ return (TRUE);
+}
+
+/* Input for computing subkeys */
+
+bool_t
+xdr_ssv_subkey4(XDR *xdrs, ssv_subkey4 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+
+/* Input for computing smt_hmac */
+
+bool_t
+xdr_ssv_mic_plain_tkn4(XDR *xdrs, ssv_mic_plain_tkn4 *objp)
+{
+ if (!xdr_uint32_t(xdrs, &objp->smpt_ssv_seq))
+ return (FALSE);
+ if (!xdr_bytes(xdrs,
+ (char **)&objp->smpt_orig_plain.smpt_orig_plain_val,
+ (uint_t *)&objp->smpt_orig_plain.smpt_orig_plain_len, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+
+/* SSV GSS PerMsgToken token */
+
+bool_t
+xdr_ssv_mic_tkn4(XDR *xdrs, ssv_mic_tkn4 *objp)
+{
+ if (!xdr_uint32_t(xdrs, &objp->smt_ssv_seq))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->smt_hmac.smt_hmac_val,
+ (uint_t *)&objp->smt_hmac.smt_hmac_len, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+
+/* Input for computing ssct_encr_data and ssct_hmac */
+
+bool_t
+xdr_ssv_seal_plain_tkn4(XDR *xdrs, ssv_seal_plain_tkn4 *objp)
+{
+ if (!xdr_bytes(xdrs,
+ (char **)&objp->sspt_confounder.sspt_confounder_val,
+ (uint_t *)&objp->sspt_confounder.sspt_confounder_len, ~0))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->sspt_ssv_seq))
+ return (FALSE);
+ if (!xdr_bytes(xdrs,
+ (char **)&objp->sspt_orig_plain.sspt_orig_plain_val,
+ (uint_t *)&objp->sspt_orig_plain.sspt_orig_plain_len, ~0))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->sspt_pad.sspt_pad_val,
+ (uint_t *)&objp->sspt_pad.sspt_pad_len, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+
+/* SSV GSS SealedMessage token */
+
+bool_t
+xdr_ssv_seal_cipher_tkn4(XDR *xdrs, ssv_seal_cipher_tkn4 *objp)
+{
+ if (!xdr_uint32_t(xdrs, &objp->ssct_ssv_seq))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->ssct_iv.ssct_iv_val,
+ (uint_t *)&objp->ssct_iv.ssct_iv_len, ~0))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->ssct_encr_data.ssct_encr_data_val,
+ (uint_t *)&objp->ssct_encr_data.ssct_encr_data_len, ~0))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->ssct_hmac.ssct_hmac_val,
+ (uint_t *)&objp->ssct_hmac.ssct_hmac_len, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+
+bool_t
+xdr_fs_locations_server4(XDR *xdrs, fs_locations_server4 *objp)
+{
+ if (!xdr_int32_t(xdrs, &objp->fls_currency))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->fls_info.fls_info_val,
+ (uint_t *)&objp->fls_info.fls_info_len, ~0))
+ return (FALSE);
+ if (!xdr_utf8str_cis(xdrs, &objp->fls_server))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fs_locations_item4(XDR *xdrs, fs_locations_item4 *objp)
+{
+ if (!xdr_array(xdrs, (char **)&objp->fli_entries.fli_entries_val,
+ (uint_t *)&objp->fli_entries.fli_entries_len, ~0,
+ sizeof (fs_locations_server4), (xdrproc_t)xdr_fs_locations_server4))
+ return (FALSE);
+ if (!xdr_pathname4(xdrs, &objp->fli_rootpath))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fs_locations_info4(XDR *xdrs, fs_locations_info4 *objp)
+{
+ if (!xdr_uint32_t(xdrs, &objp->fli_flags))
+ return (FALSE);
+ if (!xdr_int32_t(xdrs, &objp->fli_valid_for))
+ return (FALSE);
+ if (!xdr_pathname4(xdrs, &objp->fli_fs_root))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->fli_items.fli_items_val,
+ (uint_t *)&objp->fli_items.fli_items_len, ~0,
+ sizeof (fs_locations_item4), (xdrproc_t)xdr_fs_locations_item4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fattr4_fs_locations_info(XDR *xdrs, fattr4_fs_locations_info *objp)
+{
+ if (!xdr_fs_locations_info4(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_nfl_util4(XDR *xdrs, nfl_util4 *objp)
+{
+ if (!xdr_uint32_t(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_filelayout_hint_care4(XDR *xdrs, filelayout_hint_care4 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+
+bool_t
+xdr_multipath_list4(XDR *xdrs, multipath_list4 *objp)
+{
+ if (!xdr_array(xdrs, (char **)&objp->multipath_list4_val,
+ (uint_t *)&objp->multipath_list4_len, ~0,
+ sizeof (netaddr4), (xdrproc_t)xdr_netaddr4))
+ return (FALSE);
+ return (TRUE);
+}
+
+/* Encoded in the da_addr_body field of type device_addr4: */
+
+bool_t
+xdr_nfsv4_1_file_layout_ds_addr4(XDR *xdrs, nfsv4_1_file_layout_ds_addr4 *objp)
+{
+ if (!xdr_array(xdrs,
+ (char **)&objp->nflda_stripe_indices.nflda_stripe_indices_val,
+ (uint_t *)&objp->nflda_stripe_indices.nflda_stripe_indices_len, ~0,
+ sizeof (uint32_t), (xdrproc_t)xdr_uint32_t))
+ return (FALSE);
+ if (!xdr_array(xdrs,
+ (char **)&objp->nflda_multipath_ds_list.nflda_multipath_ds_list_val,
+ (uint_t *)&objp->nflda_multipath_ds_list.
+ nflda_multipath_ds_list_len, ~0, sizeof (multipath_list4),
+ (xdrproc_t)xdr_multipath_list4))
+ return (FALSE);
+ return (TRUE);
+}
+
+
+/* Encoded in the loc_body field of type layout_content4: */
+
+bool_t
+xdr_nfsv4_1_file_layout4(XDR *xdrs, nfsv4_1_file_layout4 *objp)
+{
+ if (!xdr_deviceid4(xdrs, objp->nfl_deviceid))
+ return (FALSE);
+ if (!xdr_nfl_util4(xdrs, &objp->nfl_util))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->nfl_first_stripe_index))
+ return (FALSE);
+ if (!xdr_offset4(xdrs, &objp->nfl_pattern_offset))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->nfl_fh_list.nfl_fh_list_val,
+ (uint_t *)&objp->nfl_fh_list.nfl_fh_list_len, ~0,
+ sizeof (nfs_fh4), (xdrproc_t)xdr_nfs_fh4))
+ return (FALSE);
+ return (TRUE);
+}
+
+/*
+ * Encoded in the lou_body field of type layoutupdate4:
+ * Nothing. lou_body is a zero length array of octets.
+ */
+
+
+bool_t
+xdr_creatverfattr(XDR *xdrs, creatverfattr *objp)
+{
+ if (!xdr_verifier4(xdrs, (verifier4 *)&objp->cva_verf))
+ return (FALSE);
+ if (!xdr_fattr4(xdrs, &objp->cva_attrs))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_open_claim_delegate_cur4(XDR *xdrs, open_claim_delegate_cur4 *objp)
+{
+ if (!xdr_stateid4(xdrs, &objp->delegate_stateid))
+ return (FALSE);
+ if (!xdr_component4(xdrs, &objp->file))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_open_claim4(XDR *xdrs, open_claim4 *objp)
+{
+ if (!xdr_open_claim_type4(xdrs, &objp->claim))
+ return (FALSE);
+ switch (objp->claim) {
+ case CLAIM_NULL:
+ if (!xdr_component4(xdrs, &objp->open_claim4_u.file))
+ return (FALSE);
+ break;
+ case CLAIM_PREVIOUS:
+ if (!xdr_open_delegation_type4(xdrs,
+ &objp->open_claim4_u.delegate_type))
+ return (FALSE);
+ break;
+ case CLAIM_DELEGATE_CUR:
+ if (!xdr_open_claim_delegate_cur4(xdrs,
+ &objp->open_claim4_u.delegate_cur_info))
+ return (FALSE);
+ break;
+ case CLAIM_DELEGATE_PREV:
+ if (!xdr_component4(xdrs,
+ &objp->open_claim4_u.file_delegate_prev))
+ return (FALSE);
+ break;
+ case CLAIM_FH:
+ break;
+ case CLAIM_DELEG_PREV_FH:
+ break;
+ case CLAIM_DELEG_CUR_FH:
+ if (!xdr_stateid4(xdrs,
+ &objp->open_claim4_u.oc_delegate_stateid))
+ return (FALSE);
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_why_no_delegation4(XDR *xdrs, why_no_delegation4 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_open_none_delegation4(XDR *xdrs, open_none_delegation4 *objp)
+{
+ if (!xdr_why_no_delegation4(xdrs, &objp->ond_why))
+ return (FALSE);
+ switch (objp->ond_why) {
+ case WND4_CONTENTION:
+ if (!xdr_bool(xdrs,
+ &objp->open_none_delegation4_u.ond_server_will_push_deleg))
+ return (FALSE);
+ break;
+ case WND4_RESOURCE:
+ if (!xdr_bool(xdrs, &objp->open_none_delegation4_u.
+ ond_server_will_signal_avail))
+ return (FALSE);
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_open_delegation4(XDR *xdrs, open_delegation4 *objp)
+{
+ if (!xdr_open_delegation_type4(xdrs, &objp->delegation_type))
+ return (FALSE);
+ switch (objp->delegation_type) {
+ case OPEN_DELEGATE_NONE:
+ break;
+ case OPEN_DELEGATE_READ:
+ if (!xdr_open_read_delegation4(xdrs,
+ &objp->open_delegation4_u.read))
+ return (FALSE);
+ break;
+ case OPEN_DELEGATE_WRITE:
+ if (!xdr_open_write_delegation4(xdrs,
+ &objp->open_delegation4_u.write))
+ return (FALSE);
+ break;
+ case OPEN_DELEGATE_NONE_EXT:
+ if (!xdr_open_none_delegation4(xdrs,
+ &objp->open_delegation4_u.od_whynone))
+ return (FALSE);
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_gsshandle4_t(XDR *xdrs, gsshandle4_t *objp)
+{
+ if (!xdr_bytes(xdrs, (char **)&objp->gsshandle4_t_val,
+ (uint_t *)&objp->gsshandle4_t_len, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_gss_cb_handles4(XDR *xdrs, gss_cb_handles4 *objp)
+{
+ if (!xdr_rpc_gss_svc_t(xdrs, &objp->gcbp_service))
+ return (FALSE);
+ if (!xdr_gsshandle4_t(xdrs, &objp->gcbp_handle_from_server))
+ return (FALSE);
+ if (!xdr_gsshandle4_t(xdrs, &objp->gcbp_handle_from_client))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_callback_sec_parms4(XDR *xdrs, callback_sec_parms4 *objp)
+{
+ if (!xdr_uint32_t(xdrs, &objp->cb_secflavor))
+ return (FALSE);
+ switch (objp->cb_secflavor) {
+ case AUTH_NONE:
+ break;
+ case AUTH_SYS:
+ if (!xdr_authsys_parms(xdrs,
+ &objp->callback_sec_parms4_u.cbsp_sys_cred))
+ return (FALSE);
+ break;
+ case RPCSEC_GSS:
+ if (!xdr_gss_cb_handles4(xdrs,
+ &objp->callback_sec_parms4_u.cbsp_gss_handles))
+ return (FALSE);
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_BACKCHANNEL_CTL4args(XDR *xdrs, BACKCHANNEL_CTL4args *objp)
+{
+ if (!xdr_uint32_t(xdrs, &objp->bca_cb_program))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->bca_sec_parms.bca_sec_parms_val,
+ (uint_t *)&objp->bca_sec_parms.bca_sec_parms_len, ~0,
+ sizeof (callback_sec_parms4), (xdrproc_t)xdr_callback_sec_parms4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_BACKCHANNEL_CTL4res(XDR *xdrs, BACKCHANNEL_CTL4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->bcr_status))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_channel_dir_from_client4(XDR *xdrs, channel_dir_from_client4 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_BIND_CONN_TO_SESSION4args(XDR *xdrs, BIND_CONN_TO_SESSION4args *objp)
+{
+ if (!xdr_sessionid4(xdrs, objp->bctsa_sessid))
+ return (FALSE);
+ if (!xdr_channel_dir_from_client4(xdrs, &objp->bctsa_dir))
+ return (FALSE);
+ if (!xdr_bool(xdrs, &objp->bctsa_use_conn_in_rdma_mode))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_channel_dir_from_server4(XDR *xdrs, channel_dir_from_server4 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_BIND_CONN_TO_SESSION4resok(XDR *xdrs, BIND_CONN_TO_SESSION4resok *objp)
+{
+ if (!xdr_sessionid4(xdrs, objp->bctsr_sessid))
+ return (FALSE);
+ if (!xdr_channel_dir_from_server4(xdrs, &objp->bctsr_dir))
+ return (FALSE);
+ if (!xdr_bool(xdrs, &objp->bctsr_use_conn_in_rdma_mode))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_BIND_CONN_TO_SESSION4res(XDR *xdrs, BIND_CONN_TO_SESSION4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->bctsr_status))
+ return (FALSE);
+ switch (objp->bctsr_status) {
+ case NFS4_OK:
+ if (!xdr_BIND_CONN_TO_SESSION4resok(xdrs,
+ &objp->BIND_CONN_TO_SESSION4res_u.bctsr_resok4))
+ return (FALSE);
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_state_protect_ops4(XDR *xdrs, state_protect_ops4 *objp)
+{
+ if (!xdr_bitmap4(xdrs, &objp->spo_must_enforce))
+ return (FALSE);
+ if (!xdr_bitmap4(xdrs, &objp->spo_must_allow))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_ssv_sp_parms4(XDR *xdrs, ssv_sp_parms4 *objp)
+{
+ if (!xdr_state_protect_ops4(xdrs, &objp->ssp_ops))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->ssp_hash_algs.ssp_hash_algs_val,
+ (uint_t *)&objp->ssp_hash_algs.ssp_hash_algs_len, ~0,
+ sizeof (sec_oid4), (xdrproc_t)xdr_sec_oid4))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->ssp_encr_algs.ssp_encr_algs_val,
+ (uint_t *)&objp->ssp_encr_algs.ssp_encr_algs_len, ~0,
+ sizeof (sec_oid4), (xdrproc_t)xdr_sec_oid4))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->ssp_window))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->ssp_num_gss_handles))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_state_protect_how4(XDR *xdrs, state_protect_how4 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_state_protect4_a(XDR *xdrs, state_protect4_a *objp)
+{
+ if (!xdr_state_protect_how4(xdrs, &objp->spa_how))
+ return (FALSE);
+ switch (objp->spa_how) {
+ case SP4_NONE:
+ break;
+ case SP4_MACH_CRED:
+ if (!xdr_state_protect_ops4(xdrs,
+ &objp->state_protect4_a_u.spa_mach_ops))
+ return (FALSE);
+ break;
+ case SP4_SSV:
+ if (!xdr_ssv_sp_parms4(xdrs,
+ &objp->state_protect4_a_u.spa_ssv_parms))
+ return (FALSE);
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_EXCHANGE_ID4args(XDR *xdrs, EXCHANGE_ID4args *objp)
+{
+ if (!xdr_client_owner4(xdrs, &objp->eia_clientowner))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->eia_flags))
+ return (FALSE);
+ if (!xdr_state_protect4_a(xdrs, &objp->eia_state_protect))
+ return (FALSE);
+ if (!xdr_array(xdrs,
+ (char **)&objp->eia_client_impl_id.eia_client_impl_id_val,
+ (uint_t *)&objp->eia_client_impl_id.eia_client_impl_id_len, 1,
+ sizeof (nfs_impl_id4), (xdrproc_t)xdr_nfs_impl_id4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_ssv_prot_info4(XDR *xdrs, ssv_prot_info4 *objp)
+{
+ if (!xdr_state_protect_ops4(xdrs, &objp->spi_ops))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->spi_hash_alg))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->spi_encr_alg))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->spi_ssv_len))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->spi_window))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->spi_handles.spi_handles_val,
+ (uint_t *)&objp->spi_handles.spi_handles_len, ~0,
+ sizeof (gsshandle4_t), (xdrproc_t)xdr_gsshandle4_t))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_state_protect4_r(XDR *xdrs, state_protect4_r *objp)
+{
+ if (!xdr_state_protect_how4(xdrs, &objp->spr_how))
+ return (FALSE);
+ switch (objp->spr_how) {
+ case SP4_NONE:
+ break;
+ case SP4_MACH_CRED:
+ if (!xdr_state_protect_ops4(xdrs,
+ &objp->state_protect4_r_u.spr_mach_ops))
+ return (FALSE);
+ break;
+ case SP4_SSV:
+ if (!xdr_ssv_prot_info4(xdrs,
+ &objp->state_protect4_r_u.spr_ssv_info))
+ return (FALSE);
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_EXCHANGE_ID4resok(XDR *xdrs, EXCHANGE_ID4resok *objp)
+{
+ if (!xdr_clientid4(xdrs, &objp->eir_clientid))
+ return (FALSE);
+ if (!xdr_sequenceid4(xdrs, &objp->eir_sequenceid))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->eir_flags))
+ return (FALSE);
+ if (!xdr_state_protect4_r(xdrs, &objp->eir_state_protect))
+ return (FALSE);
+ if (!xdr_server_owner4(xdrs, &objp->eir_server_owner))
+ return (FALSE);
+ if (!xdr_bytes(xdrs,
+ (char **)&objp->eir_server_scope.eir_server_scope_val,
+ (uint_t *)&objp->eir_server_scope.eir_server_scope_len,
+ NFS4_OPAQUE_LIMIT))
+ return (FALSE);
+ if (!xdr_array(xdrs,
+ (char **)&objp->eir_server_impl_id.eir_server_impl_id_val,
+ (uint_t *)&objp->eir_server_impl_id.eir_server_impl_id_len, 1,
+ sizeof (nfs_impl_id4), (xdrproc_t)xdr_nfs_impl_id4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_EXCHANGE_ID4res(XDR *xdrs, EXCHANGE_ID4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->eir_status))
+ return (FALSE);
+ switch (objp->eir_status) {
+ case NFS4_OK:
+ if (!xdr_EXCHANGE_ID4resok(xdrs,
+ &objp->EXCHANGE_ID4res_u.eir_resok4))
+ return (FALSE);
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_channel_attrs4(XDR *xdrs, channel_attrs4 *objp)
+{
+ if (!xdr_count4(xdrs, &objp->ca_headerpadsize))
+ return (FALSE);
+ if (!xdr_count4(xdrs, &objp->ca_maxrequestsize))
+ return (FALSE);
+ if (!xdr_count4(xdrs, &objp->ca_maxresponsesize))
+ return (FALSE);
+ if (!xdr_count4(xdrs, &objp->ca_maxresponsesize_cached))
+ return (FALSE);
+ if (!xdr_count4(xdrs, &objp->ca_maxoperations))
+ return (FALSE);
+ if (!xdr_count4(xdrs, &objp->ca_maxrequests))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->ca_rdma_ird.ca_rdma_ird_val,
+ (uint_t *)&objp->ca_rdma_ird.ca_rdma_ird_len, 1,
+ sizeof (uint32_t), (xdrproc_t)xdr_uint32_t))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CREATE_SESSION4args(XDR *xdrs, CREATE_SESSION4args *objp)
+{
+
+ if (!xdr_clientid4(xdrs, &objp->csa_clientid))
+ return (FALSE);
+ if (!xdr_sequenceid4(xdrs, &objp->csa_sequence))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->csa_flags))
+ return (FALSE);
+ if (!xdr_channel_attrs4(xdrs, &objp->csa_fore_chan_attrs))
+ return (FALSE);
+ if (!xdr_channel_attrs4(xdrs, &objp->csa_back_chan_attrs))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->csa_cb_program))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->csa_sec_parms.csa_sec_parms_val,
+ (uint_t *)&objp->csa_sec_parms.csa_sec_parms_len, ~0,
+ sizeof (callback_sec_parms4), (xdrproc_t)xdr_callback_sec_parms4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CREATE_SESSION4resok(XDR *xdrs, CREATE_SESSION4resok *objp)
+{
+ if (!xdr_sessionid4(xdrs, objp->csr_sessionid))
+ return (FALSE);
+ if (!xdr_sequenceid4(xdrs, &objp->csr_sequence))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->csr_flags))
+ return (FALSE);
+ if (!xdr_channel_attrs4(xdrs, &objp->csr_fore_chan_attrs))
+ return (FALSE);
+ if (!xdr_channel_attrs4(xdrs, &objp->csr_back_chan_attrs))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CREATE_SESSION4res(XDR *xdrs, CREATE_SESSION4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->csr_status))
+ return (FALSE);
+ switch (objp->csr_status) {
+ case NFS4_OK:
+ if (!xdr_CREATE_SESSION4resok(xdrs,
+ &objp->CREATE_SESSION4res_u.csr_resok4))
+ return (FALSE);
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_DESTROY_SESSION4args(XDR *xdrs, DESTROY_SESSION4args *objp)
+{
+ if (!xdr_sessionid4(xdrs, objp->dsa_sessionid))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_DESTROY_SESSION4res(XDR *xdrs, DESTROY_SESSION4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->dsr_status))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_FREE_STATEID4args(XDR *xdrs, FREE_STATEID4args *objp)
+{
+ if (!xdr_stateid4(xdrs, &objp->fsa_stateid))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_FREE_STATEID4res(XDR *xdrs, FREE_STATEID4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->fsr_status))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_attr_notice4(XDR *xdrs, attr_notice4 *objp)
+{
+ if (!xdr_nfstime4(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_GET_DIR_DELEGATION4args(XDR *xdrs, GET_DIR_DELEGATION4args *objp)
+{
+ if (!xdr_bool(xdrs, &objp->gdda_signal_deleg_avail))
+ return (FALSE);
+ if (!xdr_bitmap4(xdrs, &objp->gdda_notification_types))
+ return (FALSE);
+ if (!xdr_attr_notice4(xdrs, &objp->gdda_child_attr_delay))
+ return (FALSE);
+ if (!xdr_attr_notice4(xdrs, &objp->gdda_dir_attr_delay))
+ return (FALSE);
+ if (!xdr_bitmap4(xdrs, &objp->gdda_child_attributes))
+ return (FALSE);
+ if (!xdr_bitmap4(xdrs, &objp->gdda_dir_attributes))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_GET_DIR_DELEGATION4resok(XDR *xdrs, GET_DIR_DELEGATION4resok *objp)
+{
+ if (!xdr_verifier4(xdrs, (verifier4 *)&objp->gddr_cookieverf))
+ return (FALSE);
+ if (!xdr_stateid4(xdrs, &objp->gddr_stateid))
+ return (FALSE);
+ if (!xdr_bitmap4(xdrs, &objp->gddr_notification))
+ return (FALSE);
+ if (!xdr_bitmap4(xdrs, &objp->gddr_child_attributes))
+ return (FALSE);
+ if (!xdr_bitmap4(xdrs, &objp->gddr_dir_attributes))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_gddrnf4_status(XDR *xdrs, gddrnf4_status *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_GET_DIR_DELEGATION4res_non_fatal(XDR *xdrs,
+ GET_DIR_DELEGATION4res_non_fatal *objp)
+{
+ if (!xdr_gddrnf4_status(xdrs, &objp->gddrnf_status))
+ return (FALSE);
+ switch (objp->gddrnf_status) {
+ case GDD4_OK:
+ if (!xdr_GET_DIR_DELEGATION4resok(xdrs,
+ &objp->GET_DIR_DELEGATION4res_non_fatal_u.gddrnf_resok4))
+ return (FALSE);
+ break;
+ case GDD4_UNAVAIL:
+ if (!xdr_bool(xdrs, &objp->GET_DIR_DELEGATION4res_non_fatal_u.
+ gddrnf_will_signal_deleg_avail))
+ return (FALSE);
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_GET_DIR_DELEGATION4res(XDR *xdrs, GET_DIR_DELEGATION4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->gddr_status))
+ return (FALSE);
+ switch (objp->gddr_status) {
+ case NFS4_OK:
+ if (!xdr_GET_DIR_DELEGATION4res_non_fatal(xdrs,
+ &objp->GET_DIR_DELEGATION4res_u.gddr_res_non_fatal4))
+ return (FALSE);
+ break;
+ }
+ return (TRUE);
+}
+
+/*
+ * Special xdr function to encode single word bitmaps for
+ * notification bitmaps which only need a single word.
+ */
+bool_t
+xdr_bitmap4_notify(XDR *xdrs, bitmap4 *objp)
+{
+ int32_t len = 1;
+
+ ASSERT(xdrs->x_op == XDR_ENCODE);
+ if (!XDR_PUTINT32(xdrs, &len))
+ return (FALSE);
+#if defined(_BIG_ENDIAN)
+ return (XDR_PUTINT32(xdrs, (int32_t *)objp));
+#elif defined(_LITTLE_ENDIAN)
+ return (XDR_PUTINT32(xdrs, (int32_t *)objp+1));
+#endif
+}
+
+bool_t
+xdr_GETDEVICEINFO4args(XDR *xdrs, GETDEVICEINFO4args *objp)
+{
+ if (!xdr_deviceid4(xdrs, objp->gdia_device_id))
+ return (FALSE);
+ if (!xdr_layouttype4(xdrs, &objp->gdia_layout_type))
+ return (FALSE);
+ if (!xdr_count4(xdrs, &objp->gdia_maxcount))
+ return (FALSE);
+ if (xdrs->x_op == XDR_ENCODE) {
+ if (!xdr_bitmap4_notify(xdrs, &objp->gdia_notify_types))
+ return (FALSE);
+ } else
+ if (!xdr_bitmap4(xdrs, &objp->gdia_notify_types))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_GETDEVICEINFO4resok(XDR *xdrs, GETDEVICEINFO4resok *objp)
+{
+ if (!xdr_device_addr4(xdrs, &objp->gdir_device_addr))
+ return (FALSE);
+ if (xdrs->x_op == XDR_ENCODE) {
+ if (!xdr_bitmap4_notify(xdrs, &objp->gdir_notification))
+ return (FALSE);
+ } else
+ if (!xdr_bitmap4(xdrs, &objp->gdir_notification))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_GETDEVICEINFO4res(XDR *xdrs, GETDEVICEINFO4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->gdir_status))
+ return (FALSE);
+ switch (objp->gdir_status) {
+ case NFS4_OK:
+ if (!xdr_GETDEVICEINFO4resok(xdrs,
+ &objp->GETDEVICEINFO4res_u.gdir_resok4))
+ return (FALSE);
+ break;
+ case NFS4ERR_TOOSMALL:
+ if (!xdr_count4(xdrs, &objp->GETDEVICEINFO4res_u.gdir_mincount))
+ return (FALSE);
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_GETDEVICELIST4args(XDR *xdrs, GETDEVICELIST4args *objp)
+{
+ if (!xdr_layouttype4(xdrs, &objp->gdla_layout_type))
+ return (FALSE);
+ if (!xdr_count4(xdrs, &objp->gdla_maxdevices))
+ return (FALSE);
+ if (!xdr_nfs_cookie4(xdrs, &objp->gdla_cookie))
+ return (FALSE);
+ if (!xdr_verifier4(xdrs, (verifier4 *)&objp->gdla_cookieverf))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_GETDEVICELIST4resok(XDR *xdrs, GETDEVICELIST4resok *objp)
+{
+ if (!xdr_nfs_cookie4(xdrs, &objp->gdlr_cookie))
+ return (FALSE);
+ if (!xdr_verifier4(xdrs, (verifier4 *)&objp->gdlr_cookieverf))
+ return (FALSE);
+ if (!xdr_array(xdrs,
+ (char **)&objp->gdlr_deviceid_list.gdlr_deviceid_list_val,
+ (uint_t *)&objp->gdlr_deviceid_list.gdlr_deviceid_list_len,
+ ~0, sizeof (deviceid4), (xdrproc_t)xdr_deviceid4))
+ return (FALSE);
+ if (!xdr_bool(xdrs, &objp->gdlr_eof))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_GETDEVICELIST4res(XDR *xdrs, GETDEVICELIST4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->gdlr_status))
+ return (FALSE);
+ switch (objp->gdlr_status) {
+ case NFS4_OK:
+ if (!xdr_GETDEVICELIST4resok(xdrs,
+ &objp->GETDEVICELIST4res_u.gdlr_resok4))
+ return (FALSE);
+ break;
+ default:
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_newtime4(XDR *xdrs, newtime4 *objp)
+{
+ if (!xdr_bool(xdrs, &objp->nt_timechanged))
+ return (FALSE);
+ switch (objp->nt_timechanged) {
+ case TRUE:
+ if (!xdr_nfstime4(xdrs, &objp->newtime4_u.nt_time))
+ return (FALSE);
+ break;
+ case FALSE:
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_newoffset4(XDR *xdrs, newoffset4 *objp)
+{
+ if (!xdr_bool(xdrs, &objp->no_newoffset))
+ return (FALSE);
+ switch (objp->no_newoffset) {
+ case TRUE:
+ if (!xdr_offset4(xdrs, &objp->newoffset4_u.no_offset))
+ return (FALSE);
+ break;
+ case FALSE:
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_LAYOUTCOMMIT4args(XDR *xdrs, LAYOUTCOMMIT4args *objp)
+{
+ if (!xdr_offset4(xdrs, &objp->loca_offset))
+ return (FALSE);
+ if (!xdr_length4(xdrs, &objp->loca_length))
+ return (FALSE);
+ if (!xdr_bool(xdrs, &objp->loca_reclaim))
+ return (FALSE);
+ if (!xdr_stateid4(xdrs, &objp->loca_stateid))
+ return (FALSE);
+ if (!xdr_newoffset4(xdrs, &objp->loca_last_write_offset))
+ return (FALSE);
+ if (!xdr_newtime4(xdrs, &objp->loca_time_modify))
+ return (FALSE);
+ if (!xdr_layoutupdate4(xdrs, &objp->loca_layoutupdate))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_newsize4(XDR *xdrs, newsize4 *objp)
+{
+ if (!xdr_bool(xdrs, &objp->ns_sizechanged))
+ return (FALSE);
+ switch (objp->ns_sizechanged) {
+ case TRUE:
+ if (!xdr_length4(xdrs, &objp->newsize4_u.ns_size))
+ return (FALSE);
+ break;
+ case FALSE:
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_LAYOUTCOMMIT4resok(XDR *xdrs, LAYOUTCOMMIT4resok *objp)
+{
+ if (!xdr_newsize4(xdrs, &objp->locr_newsize))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_LAYOUTCOMMIT4res(XDR *xdrs, LAYOUTCOMMIT4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->locr_status))
+ return (FALSE);
+ switch (objp->locr_status) {
+ case NFS4_OK:
+ if (!xdr_LAYOUTCOMMIT4resok(xdrs,
+ &objp->LAYOUTCOMMIT4res_u.locr_resok4))
+ return (FALSE);
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_LAYOUTGET4args(XDR *xdrs, LAYOUTGET4args *objp)
+{
+ if (!xdr_bool(xdrs, &objp->loga_signal_layout_avail))
+ return (FALSE);
+ if (!xdr_layouttype4(xdrs, &objp->loga_layout_type))
+ return (FALSE);
+ if (!xdr_layoutiomode4(xdrs, &objp->loga_iomode))
+ return (FALSE);
+ if (!xdr_offset4(xdrs, &objp->loga_offset))
+ return (FALSE);
+ if (!xdr_length4(xdrs, &objp->loga_length))
+ return (FALSE);
+ if (!xdr_length4(xdrs, &objp->loga_minlength))
+ return (FALSE);
+ if (!xdr_stateid4(xdrs, &objp->loga_stateid))
+ return (FALSE);
+ if (!xdr_count4(xdrs, &objp->loga_maxcount))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_LAYOUTGET4resok(XDR *xdrs, LAYOUTGET4resok *objp)
+{
+ if (!xdr_bool(xdrs, &objp->logr_return_on_close))
+ return (FALSE);
+ if (!xdr_stateid4(xdrs, &objp->logr_stateid))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->logr_layout.logr_layout_val,
+ (uint_t *)&objp->logr_layout.logr_layout_len, ~0,
+ sizeof (layout4), (xdrproc_t)xdr_layout4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_LAYOUTGET4res(XDR *xdrs, LAYOUTGET4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->logr_status))
+ return (FALSE);
+ switch (objp->logr_status) {
+ case NFS4_OK:
+ if (!xdr_LAYOUTGET4resok(xdrs,
+ &objp->LAYOUTGET4res_u.logr_resok4))
+ return (FALSE);
+ break;
+ case NFS4ERR_LAYOUTTRYLATER:
+ if (!xdr_bool(xdrs,
+ &objp->LAYOUTGET4res_u.logr_will_signal_layout_avail))
+ return (FALSE);
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_LAYOUTRETURN4args(XDR *xdrs, LAYOUTRETURN4args *objp)
+{
+ if (!xdr_bool(xdrs, &objp->lora_reclaim))
+ return (FALSE);
+ if (!xdr_layouttype4(xdrs, &objp->lora_layout_type))
+ return (FALSE);
+ if (!xdr_layoutiomode4(xdrs, &objp->lora_iomode))
+ return (FALSE);
+ if (!xdr_layoutreturn4(xdrs, &objp->lora_layoutreturn))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_layoutreturn_stateid(XDR *xdrs, layoutreturn_stateid *objp)
+{
+ if (!xdr_bool(xdrs, &objp->lrs_present))
+ return (FALSE);
+ switch (objp->lrs_present) {
+ case TRUE:
+ if (!xdr_stateid4(xdrs,
+ &objp->layoutreturn_stateid_u.lrs_stateid))
+ return (FALSE);
+ break;
+ case FALSE:
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_LAYOUTRETURN4res(XDR *xdrs, LAYOUTRETURN4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->lorr_status))
+ return (FALSE);
+ switch (objp->lorr_status) {
+ case NFS4_OK:
+ if (!xdr_layoutreturn_stateid(xdrs,
+ &objp->LAYOUTRETURN4res_u.lorr_stateid))
+ return (FALSE);
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_secinfo_style4(XDR *xdrs, secinfo_style4 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_SECINFO_NO_NAME4args(XDR *xdrs, SECINFO_NO_NAME4args *objp)
+{
+ if (!xdr_secinfo_style4(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_SECINFO_NO_NAME4res(XDR *xdrs, SECINFO_NO_NAME4res *objp)
+{
+ if (!xdr_SECINFO4res(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_SEQUENCE4args(XDR *xdrs, SEQUENCE4args *objp)
+{
+ if (!xdr_sessionid4(xdrs, objp->sa_sessionid))
+ return (FALSE);
+ if (!xdr_sequenceid4(xdrs, &objp->sa_sequenceid))
+ return (FALSE);
+ if (!xdr_slotid4(xdrs, &objp->sa_slotid))
+ return (FALSE);
+ if (!xdr_slotid4(xdrs, &objp->sa_highest_slotid))
+ return (FALSE);
+ if (!xdr_bool(xdrs, &objp->sa_cachethis))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_SEQUENCE4resok(XDR *xdrs, SEQUENCE4resok *objp)
+{
+ if (!xdr_sessionid4(xdrs, objp->sr_sessionid))
+ return (FALSE);
+ if (!xdr_sequenceid4(xdrs, &objp->sr_sequenceid))
+ return (FALSE);
+ if (!xdr_slotid4(xdrs, &objp->sr_slotid))
+ return (FALSE);
+ if (!xdr_slotid4(xdrs, &objp->sr_highest_slotid))
+ return (FALSE);
+ if (!xdr_slotid4(xdrs, &objp->sr_target_highest_slotid))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->sr_status_flags))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_SEQUENCE4res(XDR *xdrs, SEQUENCE4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->sr_status))
+ return (FALSE);
+ switch (objp->sr_status) {
+ case NFS4_OK:
+ if (!xdr_SEQUENCE4resok(xdrs, &objp->SEQUENCE4res_u.sr_resok4))
+ return (FALSE);
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_ssa_digest_input4(XDR *xdrs, ssa_digest_input4 *objp)
+{
+ if (!xdr_SEQUENCE4args(xdrs, &objp->sdi_seqargs))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_SET_SSV4args(XDR *xdrs, SET_SSV4args *objp)
+{
+ if (!xdr_bytes(xdrs, (char **)&objp->ssa_ssv.ssa_ssv_val,
+ (uint_t *)&objp->ssa_ssv.ssa_ssv_len, ~0))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->ssa_digest.ssa_digest_val,
+ (uint_t *)&objp->ssa_digest.ssa_digest_len, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_ssr_digest_input4(XDR *xdrs, ssr_digest_input4 *objp)
+{
+ if (!xdr_SEQUENCE4res(xdrs, &objp->sdi_seqres))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_SET_SSV4resok(XDR *xdrs, SET_SSV4resok *objp)
+{
+ if (!xdr_bytes(xdrs, (char **)&objp->ssr_digest.ssr_digest_val,
+ (uint_t *)&objp->ssr_digest.ssr_digest_len, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_SET_SSV4res(XDR *xdrs, SET_SSV4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->ssr_status))
+ return (FALSE);
+ switch (objp->ssr_status) {
+ case NFS4_OK:
+ if (!xdr_SET_SSV4resok(xdrs, &objp->SET_SSV4res_u.ssr_resok4))
+ return (FALSE);
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_TEST_STATEID4args(XDR *xdrs, TEST_STATEID4args *objp)
+{
+ if (!xdr_array(xdrs, (char **)&objp->ts_stateids.ts_stateids_val,
+ (uint_t *)&objp->ts_stateids.ts_stateids_len, ~0,
+ sizeof (stateid4), (xdrproc_t)xdr_stateid4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_TEST_STATEID4resok(XDR *xdrs, TEST_STATEID4resok *objp)
+{
+ if (!xdr_array(xdrs,
+ (char **)&objp->tsr_status_codes.tsr_status_codes_val,
+ (uint_t *)&objp->tsr_status_codes.tsr_status_codes_len, ~0,
+ sizeof (nfsstat4), (xdrproc_t)xdr_nfsstat4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_TEST_STATEID4res(XDR *xdrs, TEST_STATEID4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->tsr_status))
+ return (FALSE);
+ switch (objp->tsr_status) {
+ case NFS4_OK:
+ if (!xdr_TEST_STATEID4resok(xdrs,
+ &objp->TEST_STATEID4res_u.tsr_resok4))
+ return (FALSE);
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_deleg_claim4(XDR *xdrs, deleg_claim4 *objp)
+{
+ if (!xdr_open_claim_type4(xdrs, &objp->dc_claim))
+ return (FALSE);
+ switch (objp->dc_claim) {
+ case CLAIM_FH:
+ break;
+ case CLAIM_DELEG_PREV_FH:
+ break;
+ case CLAIM_PREVIOUS:
+ if (!xdr_open_delegation_type4(xdrs,
+ &objp->deleg_claim4_u.dc_delegate_type))
+ return (FALSE);
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_WANT_DELEGATION4args(XDR *xdrs, WANT_DELEGATION4args *objp)
+{
+ if (!xdr_uint32_t(xdrs, &objp->wda_want))
+ return (FALSE);
+ if (!xdr_deleg_claim4(xdrs, &objp->wda_claim))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_WANT_DELEGATION4res(XDR *xdrs, WANT_DELEGATION4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->wdr_status))
+ return (FALSE);
+ switch (objp->wdr_status) {
+ case NFS4_OK:
+ if (!xdr_open_delegation4(xdrs,
+ &objp->WANT_DELEGATION4res_u.wdr_resok4))
+ return (FALSE);
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_DESTROY_CLIENTID4args(XDR *xdrs, DESTROY_CLIENTID4args *objp)
+{
+ if (!xdr_clientid4(xdrs, &objp->dca_clientid))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_DESTROY_CLIENTID4res(XDR *xdrs, DESTROY_CLIENTID4res *objp)
+{
+
+ if (!xdr_nfsstat4(xdrs, &objp->dcr_status))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_RECLAIM_COMPLETE4args(XDR *xdrs, RECLAIM_COMPLETE4args *objp)
+{
+ if (!xdr_bool(xdrs, &objp->rca_one_fs))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_RECLAIM_COMPLETE4res(XDR *xdrs, RECLAIM_COMPLETE4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->rcr_status))
+ return (FALSE);
+ return (TRUE);
+}
+
+/* new operations for NFSv4.1 */
+
+bool_t
+xdr_nfs4x_argop4(XDR *xdrs, nfs_argop4 *objp)
+{
+ /* nfs_opnum4 has already been xdr'd */
+ switch (objp->argop) {
+ case OP_BACKCHANNEL_CTL:
+ if (!xdr_BACKCHANNEL_CTL4args(xdrs,
+ &objp->nfs_argop4_u.opbackchannel_ctl))
+ return (FALSE);
+ break;
+ case OP_BIND_CONN_TO_SESSION:
+ if (!xdr_BIND_CONN_TO_SESSION4args(xdrs,
+ &objp->nfs_argop4_u.opbind_conn_to_session))
+ return (FALSE);
+ break;
+ case OP_EXCHANGE_ID:
+ if (!xdr_EXCHANGE_ID4args(xdrs,
+ &objp->nfs_argop4_u.opexchange_id))
+ return (FALSE);
+ break;
+ case OP_CREATE_SESSION:
+ if (!xdr_CREATE_SESSION4args(xdrs,
+ &objp->nfs_argop4_u.opcreate_session))
+ return (FALSE);
+ break;
+ case OP_DESTROY_SESSION:
+ if (!xdr_DESTROY_SESSION4args(xdrs,
+ &objp->nfs_argop4_u.opdestroy_session))
+ return (FALSE);
+ break;
+ case OP_FREE_STATEID:
+ if (!xdr_FREE_STATEID4args(xdrs,
+ &objp->nfs_argop4_u.opfree_stateid))
+ return (FALSE);
+ break;
+ case OP_GET_DIR_DELEGATION:
+ if (!xdr_GET_DIR_DELEGATION4args(xdrs,
+ &objp->nfs_argop4_u.opget_dir_delegation))
+ return (FALSE);
+ break;
+ case OP_GETDEVICEINFO:
+ if (!xdr_GETDEVICEINFO4args(xdrs,
+ &objp->nfs_argop4_u.opgetdeviceinfo))
+ return (FALSE);
+ break;
+ case OP_GETDEVICELIST:
+ if (!xdr_GETDEVICELIST4args(xdrs,
+ &objp->nfs_argop4_u.opgetdevicelist))
+ return (FALSE);
+ break;
+ case OP_LAYOUTCOMMIT:
+ if (!xdr_LAYOUTCOMMIT4args(xdrs,
+ &objp->nfs_argop4_u.oplayoutcommit))
+ return (FALSE);
+ break;
+ case OP_LAYOUTGET:
+ if (!xdr_LAYOUTGET4args(xdrs,
+ &objp->nfs_argop4_u.oplayoutget))
+ return (FALSE);
+ break;
+ case OP_LAYOUTRETURN:
+ if (!xdr_LAYOUTRETURN4args(xdrs,
+ &objp->nfs_argop4_u.oplayoutreturn))
+ return (FALSE);
+ break;
+ case OP_SECINFO_NO_NAME:
+ if (!xdr_SECINFO_NO_NAME4args(xdrs,
+ &objp->nfs_argop4_u.opsecinfo_no_name))
+ return (FALSE);
+ break;
+ case OP_SEQUENCE:
+ if (!xdr_SEQUENCE4args(xdrs,
+ &objp->nfs_argop4_u.opsequence))
+ return (FALSE);
+ break;
+ case OP_SET_SSV:
+ if (!xdr_SET_SSV4args(xdrs,
+ &objp->nfs_argop4_u.opset_ssv))
+ return (FALSE);
+ break;
+ case OP_TEST_STATEID:
+ if (!xdr_TEST_STATEID4args(xdrs,
+ &objp->nfs_argop4_u.optest_stateid))
+ return (FALSE);
+ break;
+ case OP_WANT_DELEGATION:
+ if (!xdr_WANT_DELEGATION4args(xdrs,
+ &objp->nfs_argop4_u.opwant_delegation))
+ return (FALSE);
+ break;
+ case OP_DESTROY_CLIENTID:
+ if (!xdr_DESTROY_CLIENTID4args(xdrs,
+ &objp->nfs_argop4_u.opdestroy_clientid))
+ return (FALSE);
+ break;
+ case OP_RECLAIM_COMPLETE:
+ if (!xdr_RECLAIM_COMPLETE4args(xdrs,
+ &objp->nfs_argop4_u.opreclaim_complete))
+ return (FALSE);
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_nfs4x_resop4(XDR *xdrs, nfs_resop4 *objp)
+{
+ /* nfs_opnum4 has already been xdr's */
+ switch (objp->resop) {
+ case OP_BACKCHANNEL_CTL:
+ if (!xdr_BACKCHANNEL_CTL4res(xdrs,
+ &objp->nfs_resop4_u.opbackchannel_ctl))
+ return (FALSE);
+ break;
+ case OP_BIND_CONN_TO_SESSION:
+ if (!xdr_BIND_CONN_TO_SESSION4res(xdrs,
+ &objp->nfs_resop4_u.opbind_conn_to_session))
+ return (FALSE);
+ break;
+ case OP_EXCHANGE_ID:
+ if (!xdr_EXCHANGE_ID4res(xdrs,
+ &objp->nfs_resop4_u.opexchange_id))
+ return (FALSE);
+ break;
+ case OP_CREATE_SESSION:
+ if (!xdr_CREATE_SESSION4res(xdrs,
+ &objp->nfs_resop4_u.opcreate_session))
+ return (FALSE);
+ break;
+ case OP_DESTROY_SESSION:
+ if (!xdr_DESTROY_SESSION4res(xdrs,
+ &objp->nfs_resop4_u.opdestroy_session))
+ return (FALSE);
+ break;
+ case OP_FREE_STATEID:
+ if (!xdr_FREE_STATEID4res(xdrs,
+ &objp->nfs_resop4_u.opfree_stateid))
+ return (FALSE);
+ break;
+ case OP_GET_DIR_DELEGATION:
+ if (!xdr_GET_DIR_DELEGATION4res(xdrs,
+ &objp->nfs_resop4_u.opget_dir_delegation))
+ return (FALSE);
+ break;
+ case OP_GETDEVICEINFO:
+ if (!xdr_GETDEVICEINFO4res(xdrs,
+ &objp->nfs_resop4_u.opgetdeviceinfo))
+ return (FALSE);
+ break;
+ case OP_GETDEVICELIST:
+ if (!xdr_GETDEVICELIST4res(xdrs,
+ &objp->nfs_resop4_u.opgetdevicelist))
+ return (FALSE);
+ break;
+ case OP_LAYOUTCOMMIT:
+ if (!xdr_LAYOUTCOMMIT4res(xdrs,
+ &objp->nfs_resop4_u.oplayoutcommit))
+ return (FALSE);
+ break;
+ case OP_LAYOUTGET:
+ if (!xdr_LAYOUTGET4res(xdrs,
+ &objp->nfs_resop4_u.oplayoutget))
+ return (FALSE);
+ break;
+ case OP_LAYOUTRETURN:
+ if (!xdr_LAYOUTRETURN4res(xdrs,
+ &objp->nfs_resop4_u.oplayoutreturn))
+ return (FALSE);
+ break;
+ case OP_SECINFO_NO_NAME:
+ if (!xdr_SECINFO_NO_NAME4res(xdrs,
+ &objp->nfs_resop4_u.opsecinfo_no_name))
+ return (FALSE);
+ break;
+ case OP_SEQUENCE:
+ if (!xdr_SEQUENCE4res(xdrs,
+ &objp->nfs_resop4_u.opsequence))
+ return (FALSE);
+ break;
+ case OP_SET_SSV:
+ if (!xdr_SET_SSV4res(xdrs,
+ &objp->nfs_resop4_u.opset_ssv))
+ return (FALSE);
+ break;
+ case OP_TEST_STATEID:
+ if (!xdr_TEST_STATEID4res(xdrs,
+ &objp->nfs_resop4_u.optest_stateid))
+ return (FALSE);
+ break;
+ case OP_WANT_DELEGATION:
+ if (!xdr_WANT_DELEGATION4res(xdrs,
+ &objp->nfs_resop4_u.opwant_delegation))
+ return (FALSE);
+ break;
+ case OP_DESTROY_CLIENTID:
+ if (!xdr_DESTROY_CLIENTID4res(xdrs,
+ &objp->nfs_resop4_u.opdestroy_clientid))
+ return (FALSE);
+ break;
+ case OP_RECLAIM_COMPLETE:
+ if (!xdr_RECLAIM_COMPLETE4res(xdrs,
+ &objp->nfs_resop4_u.opreclaim_complete))
+ return (FALSE);
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_layoutrecall_type4(XDR *xdrs, layoutrecall_type4 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_layoutrecall_file4(XDR *xdrs, layoutrecall_file4 *objp)
+{
+ switch (xdrs->x_op) {
+ case XDR_ENCODE:
+ /* TODO: encode nfs4x_fh */
+ return (FALSE);
+
+ case XDR_DECODE:
+ if (!xdr_bytes(xdrs, (char **)&objp->lor_fh.nfs_fh4_val,
+ (uint_t *)&objp->lor_fh.nfs_fh4_len, NFS4_FHSIZE))
+ return (FALSE);
+ break;
+
+ case XDR_FREE:
+ if (objp->lor_fh.nfs_fh4_val != NULL) {
+ if (!xdr_bytes(xdrs,
+ (char **)&objp->lor_fh.nfs_fh4_val,
+ (uint_t *)&objp->lor_fh.nfs_fh4_len,
+ NFS4_FHSIZE))
+ return (FALSE);
+ }
+ break;
+ }
+
+ if (!xdr_offset4(xdrs, &objp->lor_offset))
+ return (FALSE);
+ if (!xdr_length4(xdrs, &objp->lor_length))
+ return (FALSE);
+ if (!xdr_stateid4(xdrs, &objp->lor_stateid))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_layoutrecall4(XDR *xdrs, layoutrecall4 *objp)
+{
+ if (!xdr_layoutrecall_type4(xdrs, &objp->lor_recalltype))
+ return (FALSE);
+ switch (objp->lor_recalltype) {
+ case LAYOUTRECALL4_FILE:
+ if (!xdr_layoutrecall_file4(xdrs,
+ &objp->layoutrecall4_u.lor_layout))
+ return (FALSE);
+ break;
+ case LAYOUTRECALL4_FSID:
+ if (!xdr_fsid4(xdrs, &objp->layoutrecall4_u.lor_fsid))
+ return (FALSE);
+ break;
+ case LAYOUTRECALL4_ALL:
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_LAYOUTRECALL4args(XDR *xdrs, CB_LAYOUTRECALL4args *objp)
+{
+ if (!xdr_layouttype4(xdrs, &objp->clora_type))
+ return (FALSE);
+ if (!xdr_layoutiomode4(xdrs, &objp->clora_iomode))
+ return (FALSE);
+ if (!xdr_bool(xdrs, &objp->clora_changed))
+ return (FALSE);
+ if (!xdr_layoutrecall4(xdrs, &objp->clora_recall))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_LAYOUTRECALL4res(XDR *xdrs, CB_LAYOUTRECALL4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->clorr_status))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_notify_type4(XDR *xdrs, notify_type4 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_notify_entry4(XDR *xdrs, notify_entry4 *objp)
+{
+ if (!xdr_component4(xdrs, &objp->ne_file))
+ return (FALSE);
+ if (!xdr_fattr4(xdrs, &objp->ne_attrs))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_prev_entry4(XDR *xdrs, prev_entry4 *objp)
+{
+ if (!xdr_notify_entry4(xdrs, &objp->pe_prev_entry))
+ return (FALSE);
+ if (!xdr_nfs_cookie4(xdrs, &objp->pe_prev_entry_cookie))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_notify_remove4(XDR *xdrs, notify_remove4 *objp)
+{
+
+ if (!xdr_notify_entry4(xdrs, &objp->nrm_old_entry))
+ return (FALSE);
+ if (!xdr_nfs_cookie4(xdrs, &objp->nrm_old_entry_cookie))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_notify_add4(XDR *xdrs, notify_add4 *objp)
+{
+ if (!xdr_array(xdrs, (char **)&objp->nad_old_entry.nad_old_entry_val,
+ (uint_t *)&objp->nad_old_entry.nad_old_entry_len, 1,
+ sizeof (notify_remove4), (xdrproc_t)xdr_notify_remove4))
+ return (FALSE);
+ if (!xdr_notify_entry4(xdrs, &objp->nad_new_entry))
+ return (FALSE);
+ if (!xdr_array(xdrs,
+ (char **)&objp->nad_new_entry_cookie.nad_new_entry_cookie_val,
+ (uint_t *)&objp->nad_new_entry_cookie.nad_new_entry_cookie_len, 1,
+ sizeof (nfs_cookie4), (xdrproc_t)xdr_nfs_cookie4))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->nad_prev_entry.nad_prev_entry_val,
+ (uint_t *)&objp->nad_prev_entry.nad_prev_entry_len, 1,
+ sizeof (prev_entry4), (xdrproc_t)xdr_prev_entry4))
+ return (FALSE);
+ if (!xdr_bool(xdrs, &objp->nad_last_entry))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_notify_attr4(XDR *xdrs, notify_attr4 *objp)
+{
+ if (!xdr_notify_entry4(xdrs, &objp->na_changed_entry))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_notify_rename4(XDR *xdrs, notify_rename4 *objp)
+{
+ if (!xdr_notify_remove4(xdrs, &objp->nrn_old_entry))
+ return (FALSE);
+ if (!xdr_notify_add4(xdrs, &objp->nrn_new_entry))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_notify_verifier4(XDR *xdrs, notify_verifier4 *objp)
+{
+ if (!xdr_verifier4(xdrs, (verifier4 *)&objp->nv_old_cookieverf))
+ return (FALSE);
+ if (!xdr_verifier4(xdrs, (verifier4 *)&objp->nv_new_cookieverf))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_notifylist4(XDR *xdrs, notifylist4 *objp)
+{
+ if (!xdr_bytes(xdrs, (char **)&objp->notifylist4_val,
+ (uint_t *)&objp->notifylist4_len, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_notify4(XDR *xdrs, notify4 *objp)
+{
+ if (xdrs->x_op == XDR_ENCODE) {
+ if (!xdr_bitmap4_notify(xdrs, &objp->notify_mask))
+ return (FALSE);
+ } else
+ if (!xdr_bitmap4(xdrs, &objp->notify_mask))
+ return (FALSE);
+ if (!xdr_notifylist4(xdrs, &objp->notify_vals))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_NOTIFY4args(XDR *xdrs, CB_NOTIFY4args *objp)
+{
+ if (!xdr_stateid4(xdrs, &objp->cna_stateid))
+ return (FALSE);
+ if (!xdr_nfs_fh4(xdrs, &objp->cna_fh))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->cna_changes.cna_changes_val,
+ (uint_t *)&objp->cna_changes.cna_changes_len, ~0,
+ sizeof (notify4), (xdrproc_t)xdr_notify4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_NOTIFY4res(XDR *xdrs, CB_NOTIFY4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->cnr_status))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_PUSH_DELEG4args(XDR *xdrs, CB_PUSH_DELEG4args *objp)
+{
+ if (!xdr_nfs_fh4(xdrs, &objp->cpda_fh))
+ return (FALSE);
+ if (!xdr_open_delegation4(xdrs, &objp->cpda_delegation))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_PUSH_DELEG4res(XDR *xdrs, CB_PUSH_DELEG4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->cpdr_status))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_RECALL_ANY4args(XDR *xdrs, CB_RECALL_ANY4args *objp)
+{
+ if (!xdr_uint32_t(xdrs, &objp->craa_objects_to_keep))
+ return (FALSE);
+ if (!xdr_bitmap4(xdrs, &objp->craa_type_mask))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_RECALL_ANY4res(XDR *xdrs, CB_RECALL_ANY4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->crar_status))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_RECALLABLE_OBJ_AVAIL4args(XDR *xdrs, CB_RECALLABLE_OBJ_AVAIL4args *objp)
+{
+ if (!xdr_CB_RECALL_ANY4args(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_RECALLABLE_OBJ_AVAIL4res(XDR *xdrs, CB_RECALLABLE_OBJ_AVAIL4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->croa_status))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_RECALL_SLOT4args(XDR *xdrs, CB_RECALL_SLOT4args *objp)
+{
+ if (!xdr_slotid4(xdrs, &objp->rsa_target_highest_slotid))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_RECALL_SLOT4res(XDR *xdrs, CB_RECALL_SLOT4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->rsr_status))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_referring_call4(XDR *xdrs, referring_call4 *objp)
+{
+ if (!xdr_sequenceid4(xdrs, &objp->rc_sequenceid))
+ return (FALSE);
+ if (!xdr_slotid4(xdrs, &objp->rc_slotid))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_referring_call_list4(XDR *xdrs, referring_call_list4 *objp)
+{
+ if (!xdr_sessionid4(xdrs, objp->rcl_sessionid))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->rcl_referring_calls.
+ rcl_referring_calls_val,
+ (uint_t *)&objp->rcl_referring_calls.rcl_referring_calls_len, ~0,
+ sizeof (referring_call4), (xdrproc_t)xdr_referring_call4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_SEQUENCE4args(XDR *xdrs, CB_SEQUENCE4args *objp)
+{
+ if (!xdr_sessionid4(xdrs, objp->csa_sessionid))
+ return (FALSE);
+ if (!xdr_sequenceid4(xdrs, &objp->csa_sequenceid))
+ return (FALSE);
+ if (!xdr_slotid4(xdrs, &objp->csa_slotid))
+ return (FALSE);
+ if (!xdr_slotid4(xdrs, &objp->csa_highest_slotid))
+ return (FALSE);
+ if (!xdr_bool(xdrs, &objp->csa_cachethis))
+ return (FALSE);
+ if (!xdr_array(xdrs, (char **)&objp->csa_referring_call_lists.
+ csa_referring_call_lists_val,
+ (uint_t *)&objp->csa_referring_call_lists.
+ csa_referring_call_lists_len, ~0, sizeof (referring_call_list4),
+ (xdrproc_t)xdr_referring_call_list4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_SEQUENCE4resok(XDR *xdrs, CB_SEQUENCE4resok *objp)
+{
+ if (!xdr_sessionid4(xdrs, objp->csr_sessionid))
+ return (FALSE);
+ if (!xdr_sequenceid4(xdrs, &objp->csr_sequenceid))
+ return (FALSE);
+ if (!xdr_slotid4(xdrs, &objp->csr_slotid))
+ return (FALSE);
+ if (!xdr_slotid4(xdrs, &objp->csr_highest_slotid))
+ return (FALSE);
+ if (!xdr_slotid4(xdrs, &objp->csr_target_highest_slotid))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_SEQUENCE4res(XDR *xdrs, CB_SEQUENCE4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->csr_status))
+ return (FALSE);
+ switch (objp->csr_status) {
+ case NFS4_OK:
+ if (!xdr_CB_SEQUENCE4resok(xdrs,
+ &objp->CB_SEQUENCE4res_u.csr_resok4))
+ return (FALSE);
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_WANTS_CANCELLED4args(XDR *xdrs, CB_WANTS_CANCELLED4args *objp)
+{
+ if (!xdr_bool(xdrs, &objp->cwca_contended_wants_cancelled))
+ return (FALSE);
+ if (!xdr_bool(xdrs, &objp->cwca_resourced_wants_cancelled))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_WANTS_CANCELLED4res(XDR *xdrs, CB_WANTS_CANCELLED4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->cwcr_status))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_NOTIFY_LOCK4args(XDR *xdrs, CB_NOTIFY_LOCK4args *objp)
+{
+ if (!xdr_nfs_fh4(xdrs, &objp->cnla_fh))
+ return (FALSE);
+ if (!xdr_lock_owner4(xdrs, &objp->cnla_lock_owner))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_NOTIFY_LOCK4res(XDR *xdrs, CB_NOTIFY_LOCK4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->cnlr_status))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_notify_deviceid_type4(XDR *xdrs, notify_deviceid_type4 *objp)
+{
+
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_notify_deviceid_delete4(XDR *xdrs, notify_deviceid_delete4 *objp)
+{
+ if (!xdr_layouttype4(xdrs, &objp->ndd_layouttype))
+ return (FALSE);
+ if (!xdr_deviceid4(xdrs, objp->ndd_deviceid))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_notify_deviceid_change4(XDR *xdrs, notify_deviceid_change4 *objp)
+{
+
+ if (!xdr_layouttype4(xdrs, &objp->ndc_layouttype))
+ return (FALSE);
+ if (!xdr_deviceid4(xdrs, objp->ndc_deviceid))
+ return (FALSE);
+ if (!xdr_bool(xdrs, &objp->ndc_immediate))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_NOTIFY_DEVICEID4args(XDR *xdrs, CB_NOTIFY_DEVICEID4args *objp)
+{
+ if (!xdr_array(xdrs, (char **)&objp->cnda_changes.cnda_changes_val,
+ (uint_t *)&objp->cnda_changes.cnda_changes_len, ~0,
+ sizeof (notify4), (xdrproc_t)xdr_notify4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_NOTIFY_DEVICEID4res(XDR *xdrs, CB_NOTIFY_DEVICEID4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->cndr_status))
+ return (FALSE);
+ return (TRUE);
+}
+
+/* Callback operations new to NFSv4.1 */
+
+bool_t
+xdr_nfs_cb_argop4(XDR *xdrs, nfs_cb_argop4 *objp)
+{
+ /* argop has already been xdr'd */
+ switch (objp->argop) {
+ case OP_CB_LAYOUTRECALL:
+ if (!xdr_CB_LAYOUTRECALL4args(xdrs,
+ &objp->nfs_cb_argop4_u.opcblayoutrecall))
+ return (FALSE);
+ break;
+ case OP_CB_NOTIFY:
+ if (!xdr_CB_NOTIFY4args(xdrs,
+ &objp->nfs_cb_argop4_u.opcbnotify))
+ return (FALSE);
+ break;
+ case OP_CB_PUSH_DELEG:
+ if (!xdr_CB_PUSH_DELEG4args(xdrs,
+ &objp->nfs_cb_argop4_u.opcbpush_deleg))
+ return (FALSE);
+ break;
+ case OP_CB_RECALL_ANY:
+ if (!xdr_CB_RECALL_ANY4args(xdrs,
+ &objp->nfs_cb_argop4_u.opcbrecall_any))
+ return (FALSE);
+ break;
+ case OP_CB_RECALLABLE_OBJ_AVAIL:
+ if (!xdr_CB_RECALLABLE_OBJ_AVAIL4args(xdrs,
+ &objp->nfs_cb_argop4_u.opcbrecallable_obj_avail))
+ return (FALSE);
+ break;
+ case OP_CB_RECALL_SLOT:
+ if (!xdr_CB_RECALL_SLOT4args(xdrs,
+ &objp->nfs_cb_argop4_u.opcbrecall_slot))
+ return (FALSE);
+ break;
+ case OP_CB_SEQUENCE:
+ if (!xdr_CB_SEQUENCE4args(xdrs,
+ &objp->nfs_cb_argop4_u.opcbsequence))
+ return (FALSE);
+ break;
+ case OP_CB_WANTS_CANCELLED:
+ if (!xdr_CB_WANTS_CANCELLED4args(xdrs,
+ &objp->nfs_cb_argop4_u.opcbwants_cancelled))
+ return (FALSE);
+ break;
+ case OP_CB_NOTIFY_LOCK:
+ if (!xdr_CB_NOTIFY_LOCK4args(xdrs,
+ &objp->nfs_cb_argop4_u.opcbnotify_lock))
+ return (FALSE);
+ break;
+ case OP_CB_NOTIFY_DEVICEID:
+ if (!xdr_CB_NOTIFY_DEVICEID4args(xdrs,
+ &objp->nfs_cb_argop4_u.opcbnotify_deviceid))
+ return (FALSE);
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_GETATTR4res(XDR *xdrs, CB_GETATTR4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->status))
+ return (FALSE);
+
+ switch (objp->status) {
+ case NFS4_OK:
+ if (!xdr_fattr4(xdrs, &objp->obj_attributes))
+ return (FALSE);
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_RECALL4res(XDR *xdrs, CB_RECALL4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->status))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_CB_ILLEGAL4res(XDR *xdrs, CB_ILLEGAL4res *objp)
+{
+ if (!xdr_nfsstat4(xdrs, &objp->status))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_nfs_cb_resop4(XDR *xdrs, nfs_cb_resop4 *objp)
+{
+ if (!xdr_u_int(xdrs, &objp->resop))
+ return (FALSE);
+
+ switch (objp->resop) {
+ case OP_CB_GETATTR:
+ if (!xdr_CB_GETATTR4res(xdrs,
+ &objp->nfs_cb_resop4_u.opcbgetattr))
+ return (FALSE);
+ break;
+ case OP_CB_RECALL:
+ if (!xdr_CB_RECALL4res(xdrs,
+ &objp->nfs_cb_resop4_u.opcbrecall))
+ return (FALSE);
+ break;
+ case OP_CB_LAYOUTRECALL:
+ if (!xdr_CB_LAYOUTRECALL4res(xdrs,
+ &objp->nfs_cb_resop4_u.opcblayoutrecall))
+ return (FALSE);
+ break;
+ case OP_CB_NOTIFY:
+ if (!xdr_CB_NOTIFY4res(xdrs,
+ &objp->nfs_cb_resop4_u.opcbnotify))
+ return (FALSE);
+ break;
+ case OP_CB_PUSH_DELEG:
+ if (!xdr_CB_PUSH_DELEG4res(xdrs,
+ &objp->nfs_cb_resop4_u.opcbpush_deleg))
+ return (FALSE);
+ break;
+ case OP_CB_RECALL_ANY:
+ if (!xdr_CB_RECALL_ANY4res(xdrs,
+ &objp->nfs_cb_resop4_u.opcbrecall_any))
+ return (FALSE);
+ break;
+ case OP_CB_RECALLABLE_OBJ_AVAIL:
+ if (!xdr_CB_RECALLABLE_OBJ_AVAIL4res(xdrs,
+ &objp->nfs_cb_resop4_u.opcbrecallable_obj_avail))
+ return (FALSE);
+ break;
+ case OP_CB_RECALL_SLOT:
+ if (!xdr_CB_RECALL_SLOT4res(xdrs,
+ &objp->nfs_cb_resop4_u.opcbrecall_slot))
+ return (FALSE);
+ break;
+ case OP_CB_SEQUENCE:
+ if (!xdr_CB_SEQUENCE4res(xdrs,
+ &objp->nfs_cb_resop4_u.opcbsequence))
+ return (FALSE);
+ break;
+ case OP_CB_WANTS_CANCELLED:
+ if (!xdr_CB_WANTS_CANCELLED4res(xdrs,
+ &objp->nfs_cb_resop4_u.opcbwants_cancelled))
+ return (FALSE);
+ break;
+ case OP_CB_NOTIFY_LOCK:
+ if (!xdr_CB_NOTIFY_LOCK4res(xdrs,
+ &objp->nfs_cb_resop4_u.opcbnotify_lock))
+ return (FALSE);
+ break;
+ case OP_CB_NOTIFY_DEVICEID:
+ if (!xdr_CB_NOTIFY_DEVICEID4res(xdrs,
+ &objp->nfs_cb_resop4_u.opcbnotify_deviceid))
+ return (FALSE);
+ break;
+ case OP_CB_ILLEGAL:
+ if (!xdr_CB_ILLEGAL4res(xdrs,
+ &objp->nfs_cb_resop4_u.opcbillegal))
+ return (FALSE);
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/*
+ * Additional common NFSv4 XDR
+ */
+
+bool_t
+xdr_clientid4(XDR *xdrs, clientid4 *objp)
+{
+ if (!xdr_uint64_t(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_component4(XDR *xdrs, component4 *objp)
+{
+ if (!xdr_utf8string(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_count4(XDR *xdrs, count4 *objp)
+{
+ if (!xdr_uint32_t(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_fsid4(XDR *xdrs, fsid4 *objp)
+{
+ if (!xdr_uint64_t(xdrs, &objp->major))
+ return (FALSE);
+ if (!xdr_uint64_t(xdrs, &objp->minor))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_length4(XDR *xdrs, length4 *objp)
+{
+ if (!xdr_uint64_t(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_limit_by4(XDR *xdrs, limit_by4 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_lock_owner4(XDR *xdrs, lock_owner4 *objp)
+{
+ if (!xdr_clientid4(xdrs, &objp->clientid))
+ return (FALSE);
+ if (!xdr_bytes(xdrs, (char **)&objp->owner_val,
+ (uint_t *)&objp->owner_len, NFS4_OPAQUE_LIMIT))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_mode4(XDR *xdrs, mode4 *objp)
+{
+ if (!xdr_uint32_t(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_netaddr4(XDR *xdrs, netaddr4 *objp)
+{
+ if (!xdr_string(xdrs, &objp->na_r_netid, ~0))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->na_r_addr, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_nfs_cookie4(XDR *xdrs, nfs_cookie4 *objp)
+{
+ if (!xdr_uint64_t(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+
+bool_t
+xdr_nfs_modified_limit4(XDR *xdrs, nfs_modified_limit4 *objp)
+{
+ if (!xdr_uint32_t(xdrs, &objp->num_blocks))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->bytes_per_block))
+ return (FALSE);
+ return (TRUE);
+}
+
+
+bool_t
+xdr_nfs_space_limit4(XDR *xdrs, nfs_space_limit4 *objp)
+{
+ if (!xdr_limit_by4(xdrs, &objp->limitby))
+ return (FALSE);
+ switch (objp->limitby) {
+ case NFS_LIMIT_SIZE:
+ if (!xdr_uint64_t(xdrs, &objp->nfs_space_limit4_u.filesize))
+ return (FALSE);
+ break;
+ case NFS_LIMIT_BLOCKS:
+ if (!xdr_nfs_modified_limit4(xdrs,
+ &objp->nfs_space_limit4_u.mod_blocks))
+ return (FALSE);
+ break;
+ default:
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_nfsstat4(XDR *xdrs, nfsstat4 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_offset4(XDR *xdrs, offset4 *objp)
+{
+ if (!xdr_uint64_t(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_open_claim_type4(XDR *xdrs, open_claim_type4 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_open_delegation_type4(XDR *xdrs, open_delegation_type4 *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_open_read_delegation4(XDR *xdrs, open_read_delegation4 *objp)
+{
+ if (!xdr_stateid4(xdrs, &objp->stateid))
+ return (FALSE);
+ if (!xdr_bool(xdrs, &objp->recall))
+ return (FALSE);
+ if (!xdr_nfsace4(xdrs, &objp->permissions))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_open_write_delegation4(XDR *xdrs, open_write_delegation4 *objp)
+{
+ if (!xdr_stateid4(xdrs, &objp->stateid))
+ return (FALSE);
+ if (!xdr_bool(xdrs, &objp->recall))
+ return (FALSE);
+ if (!xdr_nfs_space_limit4(xdrs, &objp->space_limit))
+ return (FALSE);
+ if (!xdr_nfsace4(xdrs, &objp->permissions))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_pathname4(XDR *xdrs, pathname4 *objp)
+{
+ if (!xdr_array(xdrs, (char **)&objp->pathname4_val,
+ (uint_t *)&objp->pathname4_len, ~0, sizeof (component4),
+ (xdrproc_t)xdr_component4))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_sec_oid4(XDR *xdrs, sec_oid4 *objp)
+{
+ if (!xdr_bytes(xdrs, (char **)&objp->sec_oid4_val,
+ (uint_t *)&objp->sec_oid4_len, ~0))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_rpc_gss_svc_t(XDR *xdrs, rpc_gss_svc_t *objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *)objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_stateid4(XDR *xdrs, stateid4 *objp)
+{
+ if (!xdr_uint32_t(xdrs, &objp->seqid))
+ return (FALSE);
+ if (!xdr_opaque(xdrs, objp->other, 12))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_utf8str_cis(XDR *xdrs, utf8str_cis *objp)
+{
+ if (!xdr_utf8string(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+bool_t
+xdr_utf8str_cs(XDR *xdrs, utf8str_cs *objp)
+{
+ if (!xdr_utf8string(xdrs, objp))
+ return (FALSE);
+ return (TRUE);
+}
+
+/* End of additional common NFSv4 XDR */
diff --git a/usr/src/uts/common/fs/nfs/nfs_server.c b/usr/src/uts/common/fs/nfs/nfs_server.c
index b916f727d9..0071fe50c8 100644
--- a/usr/src/uts/common/fs/nfs/nfs_server.c
+++ b/usr/src/uts/common/fs/nfs/nfs_server.c
@@ -261,7 +261,6 @@ static SVC_CALLOUT_TABLE nfs_sct_rdma = {
*/
nvlist_t *rfs4_dss_paths, *rfs4_dss_oldpaths;
-int rfs4_dispatch(struct rpcdisp *, struct svc_req *, SVCXPRT *, char *);
bool_t rfs4_minorvers_mismatch(struct svc_req *, SVCXPRT *, void *);
/*
@@ -1056,13 +1055,13 @@ static struct rpcdisp rfsdisptab_v4[] = {
*/
/* RFS_NULL = 0 */
- {rpc_null,
+ {NULL,
xdr_void, NULL_xdrproc_t, 0,
xdr_void, NULL_xdrproc_t, 0,
nullfree, RPC_IDEMPOTENT, 0},
/* RFS4_compound = 1 */
- {rfs4_compound,
+ {NULL,
xdr_COMPOUND4args_srv, NULL_xdrproc_t, sizeof (COMPOUND4args),
xdr_COMPOUND4res_srv, NULL_xdrproc_t, sizeof (COMPOUND4res),
rfs4_compound_free, 0, 0},
diff --git a/usr/src/uts/common/fs/nfs/nfs_stats.c b/usr/src/uts/common/fs/nfs/nfs_stats.c
index 97f820d756..6dc19f67d3 100644
--- a/usr/src/uts/common/fs/nfs/nfs_stats.c
+++ b/usr/src/uts/common/fs/nfs/nfs_stats.c
@@ -21,6 +21,8 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2020 RackTop Systems, Inc.
*/
#include <sys/types.h>
@@ -417,6 +419,25 @@ static const kstat_named_t rfsproccnt_v4_tmpl[] = {
{ "verify", KSTAT_DATA_UINT64 },
{ "write", KSTAT_DATA_UINT64 },
{ "release_lockowner", KSTAT_DATA_UINT64 },
+ { "backchannel_ctl", KSTAT_DATA_UINT64 },
+ { "bind_conn_to_session", KSTAT_DATA_UINT64 },
+ { "exchange_id", KSTAT_DATA_UINT64 },
+ { "create_session", KSTAT_DATA_UINT64 },
+ { "destroy_session", KSTAT_DATA_UINT64 },
+ { "free_stateid", KSTAT_DATA_UINT64 },
+ { "get_dir_delegation", KSTAT_DATA_UINT64 },
+ { "getdeviceinfo", KSTAT_DATA_UINT64 },
+ { "getdevicelist", KSTAT_DATA_UINT64 },
+ { "layoutcommit", KSTAT_DATA_UINT64 },
+ { "layoutget", KSTAT_DATA_UINT64 },
+ { "layoutreturn", KSTAT_DATA_UINT64 },
+ { "secinfo_no_name", KSTAT_DATA_UINT64 },
+ { "sequence", KSTAT_DATA_UINT64 },
+ { "set_ssv", KSTAT_DATA_UINT64 },
+ { "test_stateid", KSTAT_DATA_UINT64 },
+ { "want_delegation", KSTAT_DATA_UINT64 },
+ { "destroy_clientid", KSTAT_DATA_UINT64 },
+ { "reclaim_complete", KSTAT_DATA_UINT64 },
{ "illegal", KSTAT_DATA_UINT64 },
};
diff --git a/usr/src/uts/common/fs/nfs/nfs_subr.c b/usr/src/uts/common/fs/nfs/nfs_subr.c
index 68cd0df081..ee622988ab 100644
--- a/usr/src/uts/common/fs/nfs/nfs_subr.c
+++ b/usr/src/uts/common/fs/nfs/nfs_subr.c
@@ -5277,3 +5277,13 @@ do_xattr_exists_check(vnode_t *vp, ulong_t *valp, cred_t *cr)
kmem_free(dbuf, dlen);
return (0);
}
+
+/*
+ * NFS specific function that returns time since
+ * system boot in seconds.
+ */
+time_t
+nfs_sys_uptime(void)
+{
+ return (TICK_TO_SEC(ddi_get_lbolt()));
+}