xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs4x_srv.c (revision b45434de)
1f44e1126SVitaliy Gusev /*
2f44e1126SVitaliy Gusev  * CDDL HEADER START
3f44e1126SVitaliy Gusev  *
4f44e1126SVitaliy Gusev  * The contents of this file are subject to the terms of the
5f44e1126SVitaliy Gusev  * Common Development and Distribution License (the "License").
6f44e1126SVitaliy Gusev  * You may not use this file except in compliance with the License.
7f44e1126SVitaliy Gusev  *
8f44e1126SVitaliy Gusev  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f44e1126SVitaliy Gusev  * or http://www.opensolaris.org/os/licensing.
10f44e1126SVitaliy Gusev  * See the License for the specific language governing permissions
11f44e1126SVitaliy Gusev  * and limitations under the License.
12f44e1126SVitaliy Gusev  *
13f44e1126SVitaliy Gusev  * When distributing Covered Code, include this CDDL HEADER in each
14f44e1126SVitaliy Gusev  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f44e1126SVitaliy Gusev  * If applicable, add the following below this CDDL HEADER, with the
16f44e1126SVitaliy Gusev  * fields enclosed by brackets "[]" replaced with your own identifying
17f44e1126SVitaliy Gusev  * information: Portions Copyright [yyyy] [name of copyright owner]
18f44e1126SVitaliy Gusev  *
19f44e1126SVitaliy Gusev  * CDDL HEADER END
20f44e1126SVitaliy Gusev  */
21f44e1126SVitaliy Gusev /*
22f44e1126SVitaliy Gusev  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23f44e1126SVitaliy Gusev  * Use is subject to license terms.
24f44e1126SVitaliy Gusev  *
25f44e1126SVitaliy Gusev  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
26f44e1126SVitaliy Gusev  * Copyright 2017 RackTop Systems.
27f44e1126SVitaliy Gusev  */
28f44e1126SVitaliy Gusev 
29f44e1126SVitaliy Gusev #include <rpc/types.h>
30f44e1126SVitaliy Gusev #include <rpc/auth.h>
31f44e1126SVitaliy Gusev #include <rpc/rpcsec_gss.h>
32f44e1126SVitaliy Gusev #include <sys/sdt.h>
33f44e1126SVitaliy Gusev #include <sys/disp.h>
34f44e1126SVitaliy Gusev #include <nfs/nfs.h>
35f44e1126SVitaliy Gusev #include <nfs/nfs4.h>
36f44e1126SVitaliy Gusev #include <sys/systeminfo.h>
37f44e1126SVitaliy Gusev 
38f44e1126SVitaliy Gusev /* Helpers */
39f44e1126SVitaliy Gusev 
40f44e1126SVitaliy Gusev /* Principal handling routines */
41f44e1126SVitaliy Gusev /* returns 0 if no match; or 1 for a match */
42f44e1126SVitaliy Gusev int
rfs4_cmp_cred_set(cred_set_t * p,struct compound_state * cs)43f44e1126SVitaliy Gusev rfs4_cmp_cred_set(cred_set_t *p, struct compound_state *cs)
44f44e1126SVitaliy Gusev {
45f44e1126SVitaliy Gusev 	int			 rc = 0;
46f44e1126SVitaliy Gusev 	rpc_gss_principal_t	 recp;		/* cached clnt princ */
47f44e1126SVitaliy Gusev 	rpc_gss_principal_t	 ibrp;		/* inbound req princ */
48f44e1126SVitaliy Gusev 
49f44e1126SVitaliy Gusev 
50f44e1126SVitaliy Gusev 	if (p->cp_cr == NULL)
51f44e1126SVitaliy Gusev 		return (rc);	/* nothing to compare with */
52f44e1126SVitaliy Gusev 
53f44e1126SVitaliy Gusev 	if (p->cp_aflavor != cs->req->rq_cred.oa_flavor)
54f44e1126SVitaliy Gusev 		return (rc);
55f44e1126SVitaliy Gusev 
56f44e1126SVitaliy Gusev 	if (p->cp_secmod != cs->nfsflavor)
57f44e1126SVitaliy Gusev 		return (rc);
58f44e1126SVitaliy Gusev 
59f44e1126SVitaliy Gusev 	if (crcmp(p->cp_cr, cs->basecr))
60f44e1126SVitaliy Gusev 		return (rc);
61f44e1126SVitaliy Gusev 
62f44e1126SVitaliy Gusev 	switch (p->cp_aflavor) {
63f44e1126SVitaliy Gusev 	case AUTH_DES:
64f44e1126SVitaliy Gusev 		rc = (strcmp(p->cp_princ, cs->principal) == 0);
65f44e1126SVitaliy Gusev 		break;
66f44e1126SVitaliy Gusev 
67f44e1126SVitaliy Gusev 	case RPCSEC_GSS:
68f44e1126SVitaliy Gusev 		recp = (rpc_gss_principal_t)p->cp_princ;
69f44e1126SVitaliy Gusev 		ibrp = (rpc_gss_principal_t)cs->principal;
70f44e1126SVitaliy Gusev 
71f44e1126SVitaliy Gusev 		if (recp->len != ibrp->len)
72f44e1126SVitaliy Gusev 			break;
73f44e1126SVitaliy Gusev 		rc = (bcmp(recp->name, ibrp->name, ibrp->len) == 0);
74f44e1126SVitaliy Gusev 		break;
75f44e1126SVitaliy Gusev 
76f44e1126SVitaliy Gusev 	case AUTH_SYS:
77f44e1126SVitaliy Gusev 	case AUTH_NONE:
78f44e1126SVitaliy Gusev 	default:
79f44e1126SVitaliy Gusev 		rc = 1;
80f44e1126SVitaliy Gusev 		break;
81f44e1126SVitaliy Gusev 	}
82f44e1126SVitaliy Gusev 	return (rc);
83f44e1126SVitaliy Gusev }
84f44e1126SVitaliy Gusev 
85f44e1126SVitaliy Gusev static rpc_gss_principal_t
rfs4_dup_princ(rpc_gss_principal_t ppl)86f44e1126SVitaliy Gusev rfs4_dup_princ(rpc_gss_principal_t ppl)
87f44e1126SVitaliy Gusev {
88f44e1126SVitaliy Gusev 	rpc_gss_principal_t	pdup;
89f44e1126SVitaliy Gusev 	size_t			len;
90f44e1126SVitaliy Gusev 
91f44e1126SVitaliy Gusev 	if (ppl == NULL)
92f44e1126SVitaliy Gusev 		return (NULL);
93f44e1126SVitaliy Gusev 
94f44e1126SVitaliy Gusev 	len = sizeof (int) + ppl->len;
95f44e1126SVitaliy Gusev 	pdup = (rpc_gss_principal_t)kmem_alloc(len, KM_SLEEP);
96f44e1126SVitaliy Gusev 	bcopy(ppl, pdup, len);
97f44e1126SVitaliy Gusev 	return (pdup);
98f44e1126SVitaliy Gusev }
99f44e1126SVitaliy Gusev 
100f44e1126SVitaliy Gusev void
rfs4_set_cred_set(cred_set_t * p,struct compound_state * cs)101f44e1126SVitaliy Gusev rfs4_set_cred_set(cred_set_t *p, struct compound_state *cs)
102f44e1126SVitaliy Gusev {
103f44e1126SVitaliy Gusev 	ASSERT(p->cp_cr == NULL);
104f44e1126SVitaliy Gusev 
105f44e1126SVitaliy Gusev 	p->cp_cr = crdup(cs->basecr);
106f44e1126SVitaliy Gusev 	p->cp_aflavor = cs->req->rq_cred.oa_flavor;
107f44e1126SVitaliy Gusev 	p->cp_secmod = cs->nfsflavor;	/* secmod != flavor for RPCSEC_GSS */
108f44e1126SVitaliy Gusev 
109f44e1126SVitaliy Gusev 	/*
110f44e1126SVitaliy Gusev 	 * Set principal as per security flavor
111f44e1126SVitaliy Gusev 	 */
112f44e1126SVitaliy Gusev 	switch (p->cp_aflavor) {
113f44e1126SVitaliy Gusev 	case AUTH_DES:
114f44e1126SVitaliy Gusev 		p->cp_princ = strdup(cs->principal);
115f44e1126SVitaliy Gusev 		break;
116f44e1126SVitaliy Gusev 
117f44e1126SVitaliy Gusev 	case RPCSEC_GSS:
118f44e1126SVitaliy Gusev 		p->cp_princ =
119f44e1126SVitaliy Gusev 		    (caddr_t)rfs4_dup_princ((rpc_gss_principal_t)cs->principal);
120f44e1126SVitaliy Gusev 		break;
121f44e1126SVitaliy Gusev 
122f44e1126SVitaliy Gusev 	case AUTH_SYS:
123f44e1126SVitaliy Gusev 	case AUTH_NONE:
124f44e1126SVitaliy Gusev 	default:
125f44e1126SVitaliy Gusev 		break;
126f44e1126SVitaliy Gusev 	}
127f44e1126SVitaliy Gusev }
128f44e1126SVitaliy Gusev 
129f44e1126SVitaliy Gusev void
rfs4_free_cred_set(cred_set_t * p)130f44e1126SVitaliy Gusev rfs4_free_cred_set(cred_set_t *p)
131f44e1126SVitaliy Gusev {
132f44e1126SVitaliy Gusev 	rpc_gss_principal_t ppl;
133f44e1126SVitaliy Gusev 
134f44e1126SVitaliy Gusev 	if (p->cp_cr == NULL)
135f44e1126SVitaliy Gusev 		return;
136f44e1126SVitaliy Gusev 
137f44e1126SVitaliy Gusev 	switch (p->cp_aflavor) {
138f44e1126SVitaliy Gusev 	case AUTH_DES:
139f44e1126SVitaliy Gusev 		kmem_free(p->cp_princ, strlen(p->cp_princ) + 1);
140f44e1126SVitaliy Gusev 		break;
141f44e1126SVitaliy Gusev 
142f44e1126SVitaliy Gusev 	case RPCSEC_GSS:
143f44e1126SVitaliy Gusev 		ppl = (rpc_gss_principal_t)p->cp_princ;
144f44e1126SVitaliy Gusev 		kmem_free(ppl, ppl->len + sizeof (int));
145f44e1126SVitaliy Gusev 		break;
146f44e1126SVitaliy Gusev 	}
147f44e1126SVitaliy Gusev 
148f44e1126SVitaliy Gusev 	crfree(p->cp_cr);
149f44e1126SVitaliy Gusev 	p->cp_cr = NULL;
150f44e1126SVitaliy Gusev }
151f44e1126SVitaliy Gusev 
152f44e1126SVitaliy Gusev /* principal end */
153f44e1126SVitaliy Gusev 
154f44e1126SVitaliy Gusev bool_t
nfs_clid4_cmp(nfs_client_id4 * s1,nfs_client_id4 * s2)155f44e1126SVitaliy Gusev nfs_clid4_cmp(nfs_client_id4 *s1, nfs_client_id4 *s2)
156f44e1126SVitaliy Gusev {
157f44e1126SVitaliy Gusev 	if (s1->verifier != s2->verifier)
158f44e1126SVitaliy Gusev 		return (FALSE);
159f44e1126SVitaliy Gusev 	if (s1->id_len != s2->id_len)
160f44e1126SVitaliy Gusev 		return (FALSE);
161f44e1126SVitaliy Gusev 	if (bcmp(s1->id_val, s2->id_val, s2->id_len))
162f44e1126SVitaliy Gusev 		return (FALSE);
163f44e1126SVitaliy Gusev 	return (TRUE);
164f44e1126SVitaliy Gusev }
165f44e1126SVitaliy Gusev 
166f44e1126SVitaliy Gusev /*
167f44e1126SVitaliy Gusev  * Rudimentary server implementation (XXX - for now)
168f44e1126SVitaliy Gusev  */
169f44e1126SVitaliy Gusev void
rfs4x_get_server_impl_id(EXCHANGE_ID4resok * resp)170f44e1126SVitaliy Gusev rfs4x_get_server_impl_id(EXCHANGE_ID4resok *resp)
171f44e1126SVitaliy Gusev {
172f44e1126SVitaliy Gusev 	char		*sol_impl = "illumos NFSv4.1 Server Implementation";
173f44e1126SVitaliy Gusev 	char		*sol_idom = "nfsv41.ietf.org";
174f44e1126SVitaliy Gusev 	void		*p;
175f44e1126SVitaliy Gusev 	uint_t		 len = 0;
176f44e1126SVitaliy Gusev 	nfs_impl_id4	*nip;
177f44e1126SVitaliy Gusev 
178f44e1126SVitaliy Gusev 	resp->eir_server_impl_id.eir_server_impl_id_len = 1;
179f44e1126SVitaliy Gusev 	nip = kmem_zalloc(sizeof (nfs_impl_id4), KM_SLEEP);
180f44e1126SVitaliy Gusev 	resp->eir_server_impl_id.eir_server_impl_id_val = nip;
181f44e1126SVitaliy Gusev 
182f44e1126SVitaliy Gusev 	/* Domain */
183f44e1126SVitaliy Gusev 	nip->nii_domain.utf8string_len = len = strlen(sol_idom);
184f44e1126SVitaliy Gusev 	p = kmem_zalloc(len * sizeof (char), KM_SLEEP);
185f44e1126SVitaliy Gusev 	nip->nii_domain.utf8string_val = p;
186f44e1126SVitaliy Gusev 	bcopy(sol_idom, p, len);
187f44e1126SVitaliy Gusev 
188f44e1126SVitaliy Gusev 	/* Implementation */
189f44e1126SVitaliy Gusev 	nip->nii_name.utf8string_len = len = strlen(sol_impl);
190f44e1126SVitaliy Gusev 	p = kmem_zalloc(len * sizeof (char), KM_SLEEP);
191f44e1126SVitaliy Gusev 	nip->nii_name.utf8string_val = p;
192f44e1126SVitaliy Gusev 	bcopy(sol_impl, p, len);
193f44e1126SVitaliy Gusev 
194f44e1126SVitaliy Gusev 	/* Time is zero for now */
195f44e1126SVitaliy Gusev }
196f44e1126SVitaliy Gusev 
197f44e1126SVitaliy Gusev static void
rfs4x_set_trunkinfo(EXCHANGE_ID4resok * rok)198f44e1126SVitaliy Gusev rfs4x_set_trunkinfo(EXCHANGE_ID4resok *rok)
199f44e1126SVitaliy Gusev {
200f44e1126SVitaliy Gusev 	const char *nodename = uts_nodename();
201f44e1126SVitaliy Gusev 	size_t nd_len = strlen(nodename);
202f44e1126SVitaliy Gusev 	size_t hw_len = strlen(hw_serial);
203f44e1126SVitaliy Gusev 	size_t id_len = nd_len + 1 + hw_len;
204f44e1126SVitaliy Gusev 	char *s = kmem_alloc(id_len, KM_SLEEP);
205f44e1126SVitaliy Gusev 	server_owner4 *so = &rok->eir_server_owner;
206f44e1126SVitaliy Gusev 	struct eir_server_scope *ss = &rok->eir_server_scope;
207f44e1126SVitaliy Gusev 
208f44e1126SVitaliy Gusev 	(void) memcpy(s, nodename, nd_len);
209f44e1126SVitaliy Gusev 	s[nd_len] = ' ';
210f44e1126SVitaliy Gusev 	(void) memcpy(s + nd_len + 1, hw_serial, hw_len);
211f44e1126SVitaliy Gusev 
212f44e1126SVitaliy Gusev 	so->so_major_id.so_major_id_len = id_len;
213f44e1126SVitaliy Gusev 	so->so_major_id.so_major_id_val = s;
214f44e1126SVitaliy Gusev 
215f44e1126SVitaliy Gusev 	ss->eir_server_scope_len = id_len;
216f44e1126SVitaliy Gusev 	ss->eir_server_scope_val = kmem_alloc(id_len, KM_SLEEP);
217f44e1126SVitaliy Gusev 	(void) memcpy(ss->eir_server_scope_val, s, id_len);
218f44e1126SVitaliy Gusev 
219f44e1126SVitaliy Gusev 	rok->eir_server_owner.so_minor_id = 0;
220f44e1126SVitaliy Gusev }
221f44e1126SVitaliy Gusev 
222f44e1126SVitaliy Gusev static bool_t
client_has_state_locked(rfs4_client_t * cp)223f44e1126SVitaliy Gusev client_has_state_locked(rfs4_client_t *cp)
224f44e1126SVitaliy Gusev {
225f44e1126SVitaliy Gusev 	if (list_head(&cp->rc_sessions) != NULL ||
226f44e1126SVitaliy Gusev 	    list_head(&cp->rc_openownerlist) != NULL)
227f44e1126SVitaliy Gusev 		return (TRUE);
228f44e1126SVitaliy Gusev 	else
229f44e1126SVitaliy Gusev 		return (FALSE);
230f44e1126SVitaliy Gusev }
231f44e1126SVitaliy Gusev 
232f44e1126SVitaliy Gusev /* OPERATIONS */
233f44e1126SVitaliy Gusev 
234f44e1126SVitaliy Gusev /*
235f44e1126SVitaliy Gusev  * EXCHANGE_ID
236f44e1126SVitaliy Gusev  * RFC5661 sec. 18.35
237f44e1126SVitaliy Gusev  */
238f44e1126SVitaliy Gusev void
rfs4x_op_exchange_id(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)239f44e1126SVitaliy Gusev rfs4x_op_exchange_id(nfs_argop4 *argop, nfs_resop4 *resop,
240f44e1126SVitaliy Gusev     struct svc_req *req, compound_state_t *cs)
241f44e1126SVitaliy Gusev {
242f44e1126SVitaliy Gusev 	EXCHANGE_ID4args	*args = &argop->nfs_argop4_u.opexchange_id;
243f44e1126SVitaliy Gusev 	EXCHANGE_ID4res		*resp = &resop->nfs_resop4_u.opexchange_id;
244f44e1126SVitaliy Gusev 	EXCHANGE_ID4resok	*rok = &resp->EXCHANGE_ID4res_u.eir_resok4;
245f44e1126SVitaliy Gusev 	rfs4_client_t		*cp, *conf;
246f44e1126SVitaliy Gusev 	bool_t			 update, create;
247f44e1126SVitaliy Gusev 	client_owner4		*cop;
248f44e1126SVitaliy Gusev 	nfs_client_id4		 cid; /* cip */
249f44e1126SVitaliy Gusev 	nfsstat4		status = NFS4_OK;
250f44e1126SVitaliy Gusev 	nfs4_srv_t		*nsrv4;
251f44e1126SVitaliy Gusev 
252f44e1126SVitaliy Gusev 	DTRACE_NFSV4_2(op__exchange__id__start,
253f44e1126SVitaliy Gusev 	    struct compound_state *, cs,
254f44e1126SVitaliy Gusev 	    EXCHANGE_ID4args *, args);
255f44e1126SVitaliy Gusev 
256f44e1126SVitaliy Gusev 	/*
257f44e1126SVitaliy Gusev 	 * EXCHANGE_ID's may be preceded by SEQUENCE
258f44e1126SVitaliy Gusev 	 *
259f44e1126SVitaliy Gusev 	 * Check that eia_flags only has "valid" spec bits
260f44e1126SVitaliy Gusev 	 * and that no 'eir_flag' ONLY bits are specified.
261f44e1126SVitaliy Gusev 	 */
262f44e1126SVitaliy Gusev 	if (args->eia_flags & ~EXID4_FLAG_MASK) {
263f44e1126SVitaliy Gusev 		status = NFS4ERR_INVAL;
264f44e1126SVitaliy Gusev 		goto err;
265f44e1126SVitaliy Gusev 	}
266f44e1126SVitaliy Gusev 
267f44e1126SVitaliy Gusev 	update = (args->eia_flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A);
268f44e1126SVitaliy Gusev 	cop = &args->eia_clientowner;
269f44e1126SVitaliy Gusev 	conf = NULL;
270f44e1126SVitaliy Gusev 
271f44e1126SVitaliy Gusev 	cid.verifier = cop->co_verifier;
272f44e1126SVitaliy Gusev 	cid.id_len = cop->co_ownerid.co_ownerid_len;
273f44e1126SVitaliy Gusev 	cid.id_val = cop->co_ownerid.co_ownerid_val;
274f44e1126SVitaliy Gusev 	cid.cl_addr = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
275f44e1126SVitaliy Gusev 
276f44e1126SVitaliy Gusev 	/*
277f44e1126SVitaliy Gusev 	 * Refer to Section 18.35.4
278f44e1126SVitaliy Gusev 	 */
279f44e1126SVitaliy Gusev again:
280f44e1126SVitaliy Gusev 	create = TRUE;
281f44e1126SVitaliy Gusev 	cp = rfs4_findclient(&cid, &create, conf);
282f44e1126SVitaliy Gusev 
283f44e1126SVitaliy Gusev 	if (cp == NULL) {
284f44e1126SVitaliy Gusev 		status = NFS4ERR_RESOURCE;
285f44e1126SVitaliy Gusev 		if (conf)
286f44e1126SVitaliy Gusev 			rfs4_client_rele(conf);
287f44e1126SVitaliy Gusev 		goto err;
288f44e1126SVitaliy Gusev 	}
289f44e1126SVitaliy Gusev 
290f44e1126SVitaliy Gusev 	if (conf) {
291f44e1126SVitaliy Gusev 		rfs4_dbe_lock(cp->rc_dbe);
292f44e1126SVitaliy Gusev 		if (cp->rc_cp_confirmed == NULL)
293f44e1126SVitaliy Gusev 			cp->rc_cp_confirmed = conf;
294f44e1126SVitaliy Gusev 		else
295f44e1126SVitaliy Gusev 			rfs4_client_rele(conf);
296f44e1126SVitaliy Gusev 		rfs4_dbe_unlock(cp->rc_dbe);
297f44e1126SVitaliy Gusev 		conf = NULL;
298f44e1126SVitaliy Gusev 	}
299f44e1126SVitaliy Gusev 
300f44e1126SVitaliy Gusev 	if (create) {
301f44e1126SVitaliy Gusev 		/* Record just created */
302f44e1126SVitaliy Gusev 		if (!update) {
303f44e1126SVitaliy Gusev 			/* case 1 - utok */
304f44e1126SVitaliy Gusev 			rfs4_set_cred_set(&cp->rc_cr_set, cs);
305f44e1126SVitaliy Gusev 
306f44e1126SVitaliy Gusev 			rok->eir_clientid = cp->rc_clientid;
307f44e1126SVitaliy Gusev 			rok->eir_sequenceid = cp->rc_contrived.xi_sid;
308f44e1126SVitaliy Gusev 			goto out;
309f44e1126SVitaliy Gusev 		} else {
310f44e1126SVitaliy Gusev 			/* no record and trying to update */
311f44e1126SVitaliy Gusev 			status = NFS4ERR_NOENT;
312f44e1126SVitaliy Gusev 			goto err_out;
313f44e1126SVitaliy Gusev 		}
314f44e1126SVitaliy Gusev 	}
315f44e1126SVitaliy Gusev 
316f44e1126SVitaliy Gusev 	/* Record exists */
317f44e1126SVitaliy Gusev 
318f44e1126SVitaliy Gusev 	/* expired clients should be ignored and released */
319f44e1126SVitaliy Gusev 	if (rfs4_lease_expired(cp)) {
320f44e1126SVitaliy Gusev 		rfs4_client_close(cp);
321f44e1126SVitaliy Gusev 		update = FALSE;
322f44e1126SVitaliy Gusev 		goto again;
323f44e1126SVitaliy Gusev 	}
324f44e1126SVitaliy Gusev 
325f44e1126SVitaliy Gusev 	if (cp->rc_need_confirm) {
326f44e1126SVitaliy Gusev 		/* UNCONFIRMED */
327f44e1126SVitaliy Gusev 		if (!update) {
328f44e1126SVitaliy Gusev 			/* case 4 - utok */
329f44e1126SVitaliy Gusev 			rfs4_client_close(cp);
330f44e1126SVitaliy Gusev 
331f44e1126SVitaliy Gusev 			ASSERT(!update);
332f44e1126SVitaliy Gusev 			goto again;
333f44e1126SVitaliy Gusev 		} else {
334f44e1126SVitaliy Gusev 			/* case 7 - utok */
335f44e1126SVitaliy Gusev 			status = NFS4ERR_NOENT;
336f44e1126SVitaliy Gusev 			goto err_out;
337f44e1126SVitaliy Gusev 		}
338f44e1126SVitaliy Gusev 	}
339f44e1126SVitaliy Gusev 
340f44e1126SVitaliy Gusev 	/* record exists and confirmed */
341f44e1126SVitaliy Gusev 	if (!update) {
342f44e1126SVitaliy Gusev 		if (!rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) {
343f44e1126SVitaliy Gusev 			/* case 3 */
344f44e1126SVitaliy Gusev 			/* lease is checked above */
345f44e1126SVitaliy Gusev 			rfs4_dbe_lock(cp->rc_dbe);
346f44e1126SVitaliy Gusev 			if (!client_has_state_locked(cp)) {
347f44e1126SVitaliy Gusev 				rfs4_dbe_unlock(cp->rc_dbe);
348f44e1126SVitaliy Gusev 
349f44e1126SVitaliy Gusev 				rfs4_client_close(cp);
350f44e1126SVitaliy Gusev 				ASSERT(!update);
351f44e1126SVitaliy Gusev 				goto again;
352f44e1126SVitaliy Gusev 			}
353f44e1126SVitaliy Gusev 			rfs4_dbe_unlock(cp->rc_dbe);
354f44e1126SVitaliy Gusev 
355f44e1126SVitaliy Gusev 			/*
356f44e1126SVitaliy Gusev 			 * clid_in_use. old_client_ret has unexpired
357f44e1126SVitaliy Gusev 			 * lease with state.
358f44e1126SVitaliy Gusev 			 */
359f44e1126SVitaliy Gusev 			status = NFS4ERR_CLID_INUSE;
360f44e1126SVitaliy Gusev 			goto err_out;
361f44e1126SVitaliy Gusev 		} else if (cp->rc_nfs_client.verifier != cid.verifier) {
362f44e1126SVitaliy Gusev 			/* case 5: Client Restart */
363f44e1126SVitaliy Gusev 			/*
364f44e1126SVitaliy Gusev 			 * Skip confirmed client record to allow confirmed
365f44e1126SVitaliy Gusev 			 * and unconfirmed state at the same time. The number
366f44e1126SVitaliy Gusev 			 * of states can collapse to one once the server
367f44e1126SVitaliy Gusev 			 * receives an applicable CREATE_SESSION or EXCHANGE_ID.
368f44e1126SVitaliy Gusev 			 */
369f44e1126SVitaliy Gusev 			ASSERT(conf == NULL);
370f44e1126SVitaliy Gusev 			conf = cp;
371f44e1126SVitaliy Gusev 			ASSERT(!update);
372f44e1126SVitaliy Gusev 			goto again;
373f44e1126SVitaliy Gusev 
374f44e1126SVitaliy Gusev 		} else if (nfs_clid4_cmp(&cp->rc_nfs_client, &cid)) {
375f44e1126SVitaliy Gusev 			/* case 2 - utok */
376f44e1126SVitaliy Gusev 			rok->eir_clientid = cp->rc_clientid;
377f44e1126SVitaliy Gusev 			rok->eir_sequenceid = cp->rc_contrived.xi_sid;
378f44e1126SVitaliy Gusev 			/* trickle down to "out" */
379f44e1126SVitaliy Gusev 
380f44e1126SVitaliy Gusev 		} else {
381f44e1126SVitaliy Gusev 			/* something is really wacky in srv state */
382f44e1126SVitaliy Gusev 			status = NFS4ERR_SERVERFAULT;
383f44e1126SVitaliy Gusev 			goto err_out;
384f44e1126SVitaliy Gusev 		}
385f44e1126SVitaliy Gusev 
386f44e1126SVitaliy Gusev 	} else { /* UPDATE */
387f44e1126SVitaliy Gusev 		if (cp->rc_nfs_client.verifier != cid.verifier) {
388f44e1126SVitaliy Gusev 			/* 18.35.4 case 8 */
389f44e1126SVitaliy Gusev 			status = NFS4ERR_NOT_SAME;
390f44e1126SVitaliy Gusev 			goto err_out;
391f44e1126SVitaliy Gusev 		}
392f44e1126SVitaliy Gusev 		if (!rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) {
393f44e1126SVitaliy Gusev 			/* 18.35.4 case 9 */
394f44e1126SVitaliy Gusev 			status = NFS4ERR_PERM;
395f44e1126SVitaliy Gusev 			goto err_out;
396f44e1126SVitaliy Gusev 		}
397f44e1126SVitaliy Gusev 
398f44e1126SVitaliy Gusev 		/* case 6 - utok */
399f44e1126SVitaliy Gusev 		rok->eir_clientid = cp->rc_clientid;
400f44e1126SVitaliy Gusev 		rok->eir_sequenceid = cp->rc_contrived.xi_sid;
401f44e1126SVitaliy Gusev 		/* trickle down to "out" */
402f44e1126SVitaliy Gusev 	}
403f44e1126SVitaliy Gusev out:
404f44e1126SVitaliy Gusev 	rok->eir_flags = 0;
405f44e1126SVitaliy Gusev 	if (resp->eir_status == NFS4_OK && !cp->rc_need_confirm)
406f44e1126SVitaliy Gusev 		rok->eir_flags |= EXCHGID4_FLAG_CONFIRMED_R;
407f44e1126SVitaliy Gusev 
408f44e1126SVitaliy Gusev 	/*
409f44e1126SVitaliy Gusev 	 * State Protection (See sec. 2.10.8.3)
410f44e1126SVitaliy Gusev 	 */
411f44e1126SVitaliy Gusev 	cp->rc_state_prot.sp_type = args->eia_state_protect.spa_how;
412f44e1126SVitaliy Gusev 	switch (cp->rc_state_prot.sp_type) {
413f44e1126SVitaliy Gusev 	case SP4_NONE:
414f44e1126SVitaliy Gusev 		break;
415f44e1126SVitaliy Gusev 
416f44e1126SVitaliy Gusev 	case SP4_MACH_CRED:
417f44e1126SVitaliy Gusev 		break;
418f44e1126SVitaliy Gusev 
419f44e1126SVitaliy Gusev 	case SP4_SSV:
420f44e1126SVitaliy Gusev 		/*
421f44e1126SVitaliy Gusev 		 * SSV state protection is not implemented.
422f44e1126SVitaliy Gusev 		 */
423f44e1126SVitaliy Gusev 		status = NFS4ERR_ENCR_ALG_UNSUPP;
424f44e1126SVitaliy Gusev 		goto err_out;
425f44e1126SVitaliy Gusev 	default:
426f44e1126SVitaliy Gusev 		status = NFS4ERR_INVAL;
427f44e1126SVitaliy Gusev 		goto err_out;
428f44e1126SVitaliy Gusev 
429f44e1126SVitaliy Gusev 	}
430f44e1126SVitaliy Gusev 
431f44e1126SVitaliy Gusev 	/*
432f44e1126SVitaliy Gusev 	 * Referrals supports
433f44e1126SVitaliy Gusev 	 */
434f44e1126SVitaliy Gusev 	if (args->eia_flags & EXCHGID4_FLAG_SUPP_MOVED_REFER) {
435f44e1126SVitaliy Gusev 		rok->eir_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER;
436f44e1126SVitaliy Gusev 	}
437f44e1126SVitaliy Gusev 
438f44e1126SVitaliy Gusev 	/*
439f44e1126SVitaliy Gusev 	 * Migration/Replication not (yet) supported
440f44e1126SVitaliy Gusev 	 */
441f44e1126SVitaliy Gusev 	if (args->eia_flags & EXCHGID4_FLAG_SUPP_MOVED_MIGR)
442f44e1126SVitaliy Gusev 		rok->eir_flags &= ~EXCHGID4_FLAG_SUPP_MOVED_MIGR;
443f44e1126SVitaliy Gusev 
444f44e1126SVitaliy Gusev 	/*
445f44e1126SVitaliy Gusev 	 * RFC8881 Section 13.1 Client ID and Session Considerations
446f44e1126SVitaliy Gusev 	 * Non-metadata server, do not support pNFS (yet).
447f44e1126SVitaliy Gusev 	 */
448f44e1126SVitaliy Gusev 	rok->eir_flags |= EXCHGID4_FLAG_USE_NON_PNFS;
449f44e1126SVitaliy Gusev 
450f44e1126SVitaliy Gusev 	/* force no state protection for now */
451f44e1126SVitaliy Gusev 	rok->eir_state_protect.spr_how = SP4_NONE;
452f44e1126SVitaliy Gusev 
453f44e1126SVitaliy Gusev 	/* Implementation specific mojo */
454f44e1126SVitaliy Gusev 	if (args->eia_client_impl_id.eia_client_impl_id_len != 0) {
455f44e1126SVitaliy Gusev 		/* EMPTY */;
456f44e1126SVitaliy Gusev 	}
457f44e1126SVitaliy Gusev 
458f44e1126SVitaliy Gusev 	nsrv4 = nfs4_get_srv();
459f44e1126SVitaliy Gusev 
460f44e1126SVitaliy Gusev 	/* Record clientid in stable storage */
461f44e1126SVitaliy Gusev 	rfs4_ss_clid(nsrv4, cp);
462f44e1126SVitaliy Gusev 
463f44e1126SVitaliy Gusev 	/* Server's implementation */
464f44e1126SVitaliy Gusev 	rfs4x_get_server_impl_id(rok);
465f44e1126SVitaliy Gusev 
466f44e1126SVitaliy Gusev 	/* compute trunking capabilities */
467f44e1126SVitaliy Gusev 	bzero(&rok->eir_server_scope, sizeof (rok->eir_server_scope));
468f44e1126SVitaliy Gusev 	bzero(&rok->eir_server_owner, sizeof (server_owner4));
469f44e1126SVitaliy Gusev 
470f44e1126SVitaliy Gusev 	/* Add trunk handling */
471f44e1126SVitaliy Gusev 	rfs4x_set_trunkinfo(rok);
472f44e1126SVitaliy Gusev 
473f44e1126SVitaliy Gusev 	/*
474f44e1126SVitaliy Gusev 	 * Check to see if client can perform reclaims
475f44e1126SVitaliy Gusev 	 */
476f44e1126SVitaliy Gusev 	rfs4_ss_chkclid(nsrv4, cp);
477f44e1126SVitaliy Gusev 
478f44e1126SVitaliy Gusev err_out:
479f44e1126SVitaliy Gusev 	rfs4_client_rele(cp);
480f44e1126SVitaliy Gusev err:
481f44e1126SVitaliy Gusev 	*cs->statusp = resp->eir_status = status;
482f44e1126SVitaliy Gusev 
483f44e1126SVitaliy Gusev 	DTRACE_NFSV4_2(op__exchange__id__done,
484f44e1126SVitaliy Gusev 	    struct compound_state *, cs,
485f44e1126SVitaliy Gusev 	    EXCHANGE_ID4res *, resp);
486f44e1126SVitaliy Gusev }
487f44e1126SVitaliy Gusev 
488f44e1126SVitaliy Gusev void
rfs4x_exchange_id_free(nfs_resop4 * resop)489f44e1126SVitaliy Gusev rfs4x_exchange_id_free(nfs_resop4 *resop)
490f44e1126SVitaliy Gusev {
491f44e1126SVitaliy Gusev 	EXCHANGE_ID4res		*resp = &resop->nfs_resop4_u.opexchange_id;
492f44e1126SVitaliy Gusev 	EXCHANGE_ID4resok	*rok = &resp->EXCHANGE_ID4res_u.eir_resok4;
493f44e1126SVitaliy Gusev 	struct server_owner4	*sop = &rok->eir_server_owner;
494f44e1126SVitaliy Gusev 	nfs_impl_id4		*nip;
495f44e1126SVitaliy Gusev 	int			 len = 0;
496f44e1126SVitaliy Gusev 
497f44e1126SVitaliy Gusev 	/* Server Owner: major */
498f44e1126SVitaliy Gusev 	if ((len = sop->so_major_id.so_major_id_len) != 0)
499f44e1126SVitaliy Gusev 		kmem_free(sop->so_major_id.so_major_id_val, len);
500f44e1126SVitaliy Gusev 
501f44e1126SVitaliy Gusev 	if ((nip = rok->eir_server_impl_id.eir_server_impl_id_val) != NULL) {
502f44e1126SVitaliy Gusev 		/* Immplementation */
503f44e1126SVitaliy Gusev 		len = nip->nii_name.utf8string_len;
504f44e1126SVitaliy Gusev 		kmem_free(nip->nii_name.utf8string_val, len * sizeof (char));
505f44e1126SVitaliy Gusev 
506f44e1126SVitaliy Gusev 		/* Domain */
507f44e1126SVitaliy Gusev 		len = nip->nii_domain.utf8string_len;
508f44e1126SVitaliy Gusev 		kmem_free(nip->nii_domain.utf8string_val, len * sizeof (char));
509f44e1126SVitaliy Gusev 
510f44e1126SVitaliy Gusev 		/* Server Impl */
511f44e1126SVitaliy Gusev 		kmem_free(nip, sizeof (nfs_impl_id4));
512f44e1126SVitaliy Gusev 	}
513f44e1126SVitaliy Gusev }
514f44e1126SVitaliy Gusev 
515f44e1126SVitaliy Gusev void
rfs4x_op_create_session(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)516f44e1126SVitaliy Gusev rfs4x_op_create_session(nfs_argop4 *argop, nfs_resop4 *resop,
517f44e1126SVitaliy Gusev     struct svc_req *req, compound_state_t *cs)
518f44e1126SVitaliy Gusev {
519f44e1126SVitaliy Gusev 	CREATE_SESSION4args	*args = &argop->nfs_argop4_u.opcreate_session;
520f44e1126SVitaliy Gusev 	CREATE_SESSION4res	*resp = &resop->nfs_resop4_u.opcreate_session;
521f44e1126SVitaliy Gusev 	CREATE_SESSION4resok	*rok = &resp->CREATE_SESSION4res_u.csr_resok4;
522f44e1126SVitaliy Gusev 	CREATE_SESSION4resok	*crp;
523f44e1126SVitaliy Gusev 	rfs4_client_t		*cp;
524f44e1126SVitaliy Gusev 	rfs4_session_t		*sp;
525f44e1126SVitaliy Gusev 	session41_create_t	 sca;
526f44e1126SVitaliy Gusev 	sequenceid4		 stseq;
527f44e1126SVitaliy Gusev 	sequenceid4		 agseq;
528f44e1126SVitaliy Gusev 	nfsstat4		 status = NFS4_OK;
529f44e1126SVitaliy Gusev 
530f44e1126SVitaliy Gusev 	DTRACE_NFSV4_2(op__create__session__start,
531f44e1126SVitaliy Gusev 	    struct compound_state *, cs,
532f44e1126SVitaliy Gusev 	    CREATE_SESSION4args*, args);
533f44e1126SVitaliy Gusev 
534f44e1126SVitaliy Gusev 	/*
535f44e1126SVitaliy Gusev 	 * A CREATE_SESSION request can be prefixed by OP_SEQUENCE.
536f44e1126SVitaliy Gusev 	 * In this case, the newly created session has no relation
537f44e1126SVitaliy Gusev 	 * to the sessid used for the OP_SEQUENCE.
538f44e1126SVitaliy Gusev 	 */
539f44e1126SVitaliy Gusev 
540f44e1126SVitaliy Gusev 	/*
541f44e1126SVitaliy Gusev 	 * Find the clientid
542f44e1126SVitaliy Gusev 	 */
543f44e1126SVitaliy Gusev 	cp = rfs4_findclient_by_id(args->csa_clientid, TRUE);
544f44e1126SVitaliy Gusev 	if (cp == NULL) {
545f44e1126SVitaliy Gusev 		status = NFS4ERR_STALE_CLIENTID;
546f44e1126SVitaliy Gusev 		goto out;
547f44e1126SVitaliy Gusev 	}
548f44e1126SVitaliy Gusev 
549f44e1126SVitaliy Gusev 	/*
550f44e1126SVitaliy Gusev 	 * Make sure the lease is still valid.
551f44e1126SVitaliy Gusev 	 */
552f44e1126SVitaliy Gusev 	if (rfs4_lease_expired(cp)) {
553f44e1126SVitaliy Gusev 		rfs4_client_close(cp);
554f44e1126SVitaliy Gusev 		status = NFS4ERR_STALE_CLIENTID;
555f44e1126SVitaliy Gusev 		goto out;
556f44e1126SVitaliy Gusev 	}
557f44e1126SVitaliy Gusev 
558f44e1126SVitaliy Gusev 	/*
559f44e1126SVitaliy Gusev 	 * Sequenceid processing (handling replay's, etc)
560f44e1126SVitaliy Gusev 	 */
561f44e1126SVitaliy Gusev 	agseq = args->csa_sequence;
562f44e1126SVitaliy Gusev 	stseq = cp->rc_contrived.xi_sid;
563f44e1126SVitaliy Gusev 	if (stseq == agseq + 1) {
564f44e1126SVitaliy Gusev 		/*
565f44e1126SVitaliy Gusev 		 * If the previous sequenceid, then must be a replay of a
566f44e1126SVitaliy Gusev 		 * previous CREATE_SESSION; return the cached result.
567f44e1126SVitaliy Gusev 		 */
568f44e1126SVitaliy Gusev 		crp = (CREATE_SESSION4resok *)&cp->rc_contrived.cs_res;
569f44e1126SVitaliy Gusev 		status = cp->rc_contrived.cs_status;
570f44e1126SVitaliy Gusev 		rok->csr_sequence = agseq;
571f44e1126SVitaliy Gusev 		bcopy(crp->csr_sessionid, rok->csr_sessionid,
572f44e1126SVitaliy Gusev 		    sizeof (sessionid4));
573f44e1126SVitaliy Gusev 		rok->csr_flags = crp->csr_flags;
574f44e1126SVitaliy Gusev 		rok->csr_fore_chan_attrs = crp->csr_fore_chan_attrs;
575f44e1126SVitaliy Gusev 		rok->csr_back_chan_attrs = crp->csr_back_chan_attrs;
576f44e1126SVitaliy Gusev 
577f44e1126SVitaliy Gusev 		rfs4_update_lease(cp);
578f44e1126SVitaliy Gusev 		rfs4_client_rele(cp);
579f44e1126SVitaliy Gusev 		goto out;
580f44e1126SVitaliy Gusev 	}
581f44e1126SVitaliy Gusev 
582f44e1126SVitaliy Gusev 	if (stseq != agseq) {
583f44e1126SVitaliy Gusev 		/*
584f44e1126SVitaliy Gusev 		 * No way to differentiate MISORD_NEWREQ vs. MISORD_REPLAY,
585f44e1126SVitaliy Gusev 		 * so anything else, we simply treat as SEQ_MISORDERED.
586f44e1126SVitaliy Gusev 		 */
587f44e1126SVitaliy Gusev 		status = NFS4ERR_SEQ_MISORDERED;
588f44e1126SVitaliy Gusev 		rfs4_client_rele(cp);
589f44e1126SVitaliy Gusev 		goto out;
590f44e1126SVitaliy Gusev 	}
591f44e1126SVitaliy Gusev 
592f44e1126SVitaliy Gusev 	/*
593f44e1126SVitaliy Gusev 	 * Clientid confirmation
594f44e1126SVitaliy Gusev 	 */
595f44e1126SVitaliy Gusev 	if (cp->rc_need_confirm) {
596f44e1126SVitaliy Gusev 		if (rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) {
597f44e1126SVitaliy Gusev 			cp->rc_need_confirm = FALSE;
598f44e1126SVitaliy Gusev 			if (cp->rc_cp_confirmed != NULL) {
599f44e1126SVitaliy Gusev 				rfs4_client_close(cp->rc_cp_confirmed);
600f44e1126SVitaliy Gusev 				cp->rc_cp_confirmed = NULL;
601f44e1126SVitaliy Gusev 			}
602f44e1126SVitaliy Gusev 		} else {
603f44e1126SVitaliy Gusev 			status = NFS4ERR_CLID_INUSE;
604f44e1126SVitaliy Gusev 			rfs4_client_rele(cp);
605f44e1126SVitaliy Gusev 			goto out;
606f44e1126SVitaliy Gusev 		}
607f44e1126SVitaliy Gusev 	}
608f44e1126SVitaliy Gusev 
609f44e1126SVitaliy Gusev 	/*
610f44e1126SVitaliy Gusev 	 * Session creation
611f44e1126SVitaliy Gusev 	 */
612f44e1126SVitaliy Gusev 	sca.cs_error = 0;
613f44e1126SVitaliy Gusev 	sca.cs_req = req;
614f44e1126SVitaliy Gusev 	sca.cs_client = cp;
615f44e1126SVitaliy Gusev 	sca.cs_aotw = *args;
616f44e1126SVitaliy Gusev 	sp = rfs4x_createsession(&sca);
617f44e1126SVitaliy Gusev 
618f44e1126SVitaliy Gusev 	if (sca.cs_error) {
619f44e1126SVitaliy Gusev 		status = sca.cs_error;
620f44e1126SVitaliy Gusev 		rfs4_client_rele(cp);
621f44e1126SVitaliy Gusev 		if (sp != NULL)
622f44e1126SVitaliy Gusev 			rfs4x_session_rele(sp);
623f44e1126SVitaliy Gusev 		goto out;
624f44e1126SVitaliy Gusev 	}
625f44e1126SVitaliy Gusev 
626f44e1126SVitaliy Gusev 	if (sp == NULL) {
627f44e1126SVitaliy Gusev 		status = NFS4ERR_SERVERFAULT;
628f44e1126SVitaliy Gusev 		rfs4_client_rele(cp);
629f44e1126SVitaliy Gusev 		goto out;
630f44e1126SVitaliy Gusev 	}
631f44e1126SVitaliy Gusev 
632f44e1126SVitaliy Gusev 	/*
633f44e1126SVitaliy Gusev 	 * Need to store the result in the rfs4_client_t's contrived
634f44e1126SVitaliy Gusev 	 * result slot and then respond from there. This way, when the
635f44e1126SVitaliy Gusev 	 * csa_sequence == contrived.cc_sid, we can return the latest
636f44e1126SVitaliy Gusev 	 * cached result. (see replay: above)
637f44e1126SVitaliy Gusev 	 */
638f44e1126SVitaliy Gusev 	crp = (CREATE_SESSION4resok *)&cp->rc_contrived.cs_res;
639f44e1126SVitaliy Gusev 	cp->rc_contrived.cs_status = NFS4_OK;
640f44e1126SVitaliy Gusev 	rok->csr_sequence = crp->csr_sequence = cp->rc_contrived.xi_sid;
641f44e1126SVitaliy Gusev 	bcopy(sp->sn_sessid, rok->csr_sessionid, sizeof (sessionid4));
642f44e1126SVitaliy Gusev 	bcopy(sp->sn_sessid, crp->csr_sessionid, sizeof (sessionid4));
643f44e1126SVitaliy Gusev 	rok->csr_flags = crp->csr_flags = sp->sn_csflags;
644f44e1126SVitaliy Gusev 
645f44e1126SVitaliy Gusev 	cp->rc_contrived.xi_sid++;
646f44e1126SVitaliy Gusev 
647f44e1126SVitaliy Gusev 	rok->csr_fore_chan_attrs =
648f44e1126SVitaliy Gusev 	    crp->csr_fore_chan_attrs = sp->sn_fore->cn_attrs;
649f44e1126SVitaliy Gusev 	rok->csr_back_chan_attrs = crp->csr_back_chan_attrs =
650f44e1126SVitaliy Gusev 	    args->csa_back_chan_attrs;
651f44e1126SVitaliy Gusev 
652f44e1126SVitaliy Gusev 	rfs4_update_lease(cp);
653f44e1126SVitaliy Gusev 
654f44e1126SVitaliy Gusev 	/*
655f44e1126SVitaliy Gusev 	 * References from the session to the client are
656f44e1126SVitaliy Gusev 	 * accounted for while session is being created.
657f44e1126SVitaliy Gusev 	 */
658f44e1126SVitaliy Gusev 	rfs4_client_rele(cp);
659f44e1126SVitaliy Gusev 	rfs4x_session_rele(sp);
660f44e1126SVitaliy Gusev out:
661f44e1126SVitaliy Gusev 	*cs->statusp = resp->csr_status = status;
662f44e1126SVitaliy Gusev 
663f44e1126SVitaliy Gusev 	DTRACE_NFSV4_2(op__create__session__done,
664f44e1126SVitaliy Gusev 	    struct compound_state *, cs,
665f44e1126SVitaliy Gusev 	    CREATE_SESSION4res *, resp);
666f44e1126SVitaliy Gusev }
667f44e1126SVitaliy Gusev 
668f44e1126SVitaliy Gusev /* ARGSUSED */
669f44e1126SVitaliy Gusev void
rfs4x_op_destroy_session(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)670f44e1126SVitaliy Gusev rfs4x_op_destroy_session(nfs_argop4 *argop, nfs_resop4 *resop,
671f44e1126SVitaliy Gusev     struct svc_req *req, compound_state_t *cs)
672f44e1126SVitaliy Gusev {
673f44e1126SVitaliy Gusev 	DESTROY_SESSION4args	*args = &argop->nfs_argop4_u.opdestroy_session;
674f44e1126SVitaliy Gusev 	DESTROY_SESSION4res	*resp = &resop->nfs_resop4_u.opdestroy_session;
675f44e1126SVitaliy Gusev 	rfs4_session_t		*sp;
676f44e1126SVitaliy Gusev 	rfs4_client_t		*cp;
677f44e1126SVitaliy Gusev 	nfsstat4 status = NFS4_OK;
678f44e1126SVitaliy Gusev 	int addref = 0;		/* additional reference */
679f44e1126SVitaliy Gusev 
680f44e1126SVitaliy Gusev 	DTRACE_NFSV4_2(op__destroy__session__start,
681f44e1126SVitaliy Gusev 	    struct compound_state *, cs,
682f44e1126SVitaliy Gusev 	    DESTROY_SESSION4args *, args);
683f44e1126SVitaliy Gusev 
684f44e1126SVitaliy Gusev 	/* section 18.37.3 rfc5661 */
685f44e1126SVitaliy Gusev 	if (rfs4_has_session(cs)) {
686f44e1126SVitaliy Gusev 		/* compound with a sequence */
687f44e1126SVitaliy Gusev 		if (bcmp(args->dsa_sessionid, cs->sp->sn_sessid,
688f44e1126SVitaliy Gusev 		    sizeof (sessionid4)) == 0) {
689f44e1126SVitaliy Gusev 			/*
690f44e1126SVitaliy Gusev 			 * Same session.
691f44e1126SVitaliy Gusev 			 * must be the final operation in the COMPOUND request
692f44e1126SVitaliy Gusev 			 */
693f44e1126SVitaliy Gusev 			if ((cs->op_pos + 1) != cs->op_len) {
694f44e1126SVitaliy Gusev 				status = NFS4ERR_NOT_ONLY_OP;
695f44e1126SVitaliy Gusev 				goto out;
696f44e1126SVitaliy Gusev 			}
697f44e1126SVitaliy Gusev 			addref++;
698f44e1126SVitaliy Gusev 		} else {
699f44e1126SVitaliy Gusev 			/* Not the same session */
700f44e1126SVitaliy Gusev 			DTRACE_PROBE(nfss41__i__destroy_encap_session);
701f44e1126SVitaliy Gusev 
702f44e1126SVitaliy Gusev 		}
703f44e1126SVitaliy Gusev 	}
704f44e1126SVitaliy Gusev 
705f44e1126SVitaliy Gusev 	sp = rfs4x_findsession_by_id(args->dsa_sessionid);
706f44e1126SVitaliy Gusev 	if (sp == NULL) {
707f44e1126SVitaliy Gusev 		status = NFS4ERR_BADSESSION;
708f44e1126SVitaliy Gusev 		goto out;
709f44e1126SVitaliy Gusev 	}
710f44e1126SVitaliy Gusev 
711f44e1126SVitaliy Gusev 	/*
712f44e1126SVitaliy Gusev 	 * State Protection (See sec. 2.10.8.3)
713f44e1126SVitaliy Gusev 	 *
714f44e1126SVitaliy Gusev 	 * verify cred that was used to create the session matches and is in
715f44e1126SVitaliy Gusev 	 * concordance w/the state protection type used.
716f44e1126SVitaliy Gusev 	 */
717f44e1126SVitaliy Gusev 	cp = sp->sn_clnt;
718f44e1126SVitaliy Gusev 	switch (cp->rc_state_prot.sp_type) {
719f44e1126SVitaliy Gusev 	case SP4_MACH_CRED:
720f44e1126SVitaliy Gusev 		if (!rfs4_cmp_cred_set(&cp->rc_cr_set, cs)) {
721f44e1126SVitaliy Gusev 			status = NFS4ERR_PERM;
722f44e1126SVitaliy Gusev 			goto err_out;
723f44e1126SVitaliy Gusev 		}
724f44e1126SVitaliy Gusev 		break;
725f44e1126SVitaliy Gusev 
726f44e1126SVitaliy Gusev 	case SP4_SSV:
727f44e1126SVitaliy Gusev 		/*
728f44e1126SVitaliy Gusev 		 * Todo -- Missing SSV validation here, if/when
729f44e1126SVitaliy Gusev 		 * SSV state protection is implemented.
730f44e1126SVitaliy Gusev 		 * Should not get this after check in EXCHANGE_ID
731f44e1126SVitaliy Gusev 		 */
732f44e1126SVitaliy Gusev 		status = NFS4ERR_PERM;
733f44e1126SVitaliy Gusev 		goto err_out;
734f44e1126SVitaliy Gusev 
735f44e1126SVitaliy Gusev 	case SP4_NONE:
736f44e1126SVitaliy Gusev 		break;
737f44e1126SVitaliy Gusev 
738f44e1126SVitaliy Gusev 	default:
739f44e1126SVitaliy Gusev 		break;
740f44e1126SVitaliy Gusev 	}
741f44e1126SVitaliy Gusev 
742f44e1126SVitaliy Gusev 	status = rfs4x_destroysession(sp, 2 + addref);
743f44e1126SVitaliy Gusev err_out:
744f44e1126SVitaliy Gusev 	rfs4x_session_rele(sp);
745f44e1126SVitaliy Gusev out:
746f44e1126SVitaliy Gusev 	*cs->statusp = resp->dsr_status = status;
747f44e1126SVitaliy Gusev 
748f44e1126SVitaliy Gusev 	DTRACE_NFSV4_2(op__destroy__session__done,
749f44e1126SVitaliy Gusev 	    struct compound_state *, cs,
750f44e1126SVitaliy Gusev 	    DESTROY_SESSION4res *, resp);
751f44e1126SVitaliy Gusev }
752f44e1126SVitaliy Gusev 
753f44e1126SVitaliy Gusev /*
754f44e1126SVitaliy Gusev  * Find session and validate sequence args.
755f44e1126SVitaliy Gusev  * If this function successfully completes the compound state
756f44e1126SVitaliy Gusev  * will contain a session pointer.
757f44e1126SVitaliy Gusev  */
758f44e1126SVitaliy Gusev static nfsstat4
rfs4x_find_session(SEQUENCE4args * sargs,struct compound_state * cs)759f44e1126SVitaliy Gusev rfs4x_find_session(SEQUENCE4args *sargs, struct compound_state *cs)
760f44e1126SVitaliy Gusev {
761f44e1126SVitaliy Gusev 	rfs4_session_t	*sp;
762f44e1126SVitaliy Gusev 	slotid4		 slot;
763f44e1126SVitaliy Gusev 
764f44e1126SVitaliy Gusev 	ASSERT(sargs != NULL);
765f44e1126SVitaliy Gusev 
766f44e1126SVitaliy Gusev 	if ((sp = rfs4x_findsession_by_id(sargs->sa_sessionid)) == NULL)
767f44e1126SVitaliy Gusev 		return (NFS4ERR_BADSESSION);
768f44e1126SVitaliy Gusev 
769f44e1126SVitaliy Gusev 	slot = sargs->sa_slotid;
770f44e1126SVitaliy Gusev 	if (slot >= sp->sn_fore->cn_attrs.ca_maxrequests) {
771f44e1126SVitaliy Gusev 		rfs4x_session_rele(sp);
772f44e1126SVitaliy Gusev 		return (NFS4ERR_BADSLOT);
773f44e1126SVitaliy Gusev 	}
774f44e1126SVitaliy Gusev 	cs->sp = sp;
775f44e1126SVitaliy Gusev 	cs->cachethis = sargs->sa_cachethis;
776f44e1126SVitaliy Gusev 
777f44e1126SVitaliy Gusev 	return (NFS4_OK);
778f44e1126SVitaliy Gusev }
779f44e1126SVitaliy Gusev 
780f44e1126SVitaliy Gusev /* called under held lock */
781f44e1126SVitaliy Gusev static nfsstat4
check_slot_seqid(rfs4_slot_t * slot,sequenceid4 seqid)782f44e1126SVitaliy Gusev check_slot_seqid(rfs4_slot_t *slot, sequenceid4 seqid)
783f44e1126SVitaliy Gusev {
784f44e1126SVitaliy Gusev 	nfsstat4 status = NFS4ERR_SEQ_MISORDERED;
785f44e1126SVitaliy Gusev 
786f44e1126SVitaliy Gusev 	if (slot->se_flags & RFS4_SLOT_INUSE) {
787f44e1126SVitaliy Gusev 		/*
788f44e1126SVitaliy Gusev 		 * There are three cases:
789f44e1126SVitaliy Gusev 		 * 1. Duplicated requests for currently performing
790f44e1126SVitaliy Gusev 		 *    duplicated request.
791f44e1126SVitaliy Gusev 		 * 2. New request for currently performing duplicated
792f44e1126SVitaliy Gusev 		 *    request.
793f44e1126SVitaliy Gusev 		 * 3. Request with bad seqid for non finished performing
794f44e1126SVitaliy Gusev 		 *    request (due to a little window between 'prep'
795f44e1126SVitaliy Gusev 		 *    stage and actual renew se_seqid).
796f44e1126SVitaliy Gusev 		 * In all cases tell a client to retry request later.
797f44e1126SVitaliy Gusev 		 */
798f44e1126SVitaliy Gusev 		if (slot->se_seqid == seqid || slot->se_seqid + 1 == seqid) {
799f44e1126SVitaliy Gusev 			status = NFS4ERR_DELAY;
800f44e1126SVitaliy Gusev 		}
801f44e1126SVitaliy Gusev 	} else {
802f44e1126SVitaliy Gusev 		if (seqid == slot->se_seqid + 1)
803f44e1126SVitaliy Gusev 			status = NFS4_OK;
804f44e1126SVitaliy Gusev 		else if (seqid == slot->se_seqid)
805f44e1126SVitaliy Gusev 			status = nfserr_replay_cache;
806f44e1126SVitaliy Gusev 	}
807f44e1126SVitaliy Gusev 	return (status);
808f44e1126SVitaliy Gusev }
809f44e1126SVitaliy Gusev 
810f44e1126SVitaliy Gusev /*
811f44e1126SVitaliy Gusev  * Prep stage for SEQUENCE operation.
812f44e1126SVitaliy Gusev  *
813f44e1126SVitaliy Gusev  * Main purpose to call this:
814f44e1126SVitaliy Gusev  *     - check on cached replay
815f44e1126SVitaliy Gusev  *     - Set cs.sp and cs.slot
816f44e1126SVitaliy Gusev  */
817f44e1126SVitaliy Gusev int
rfs4x_sequence_prep(COMPOUND4args * args,COMPOUND4res * resp,compound_state_t * cs)818f44e1126SVitaliy Gusev rfs4x_sequence_prep(COMPOUND4args *args, COMPOUND4res *resp,
819f44e1126SVitaliy Gusev     compound_state_t *cs)
820f44e1126SVitaliy Gusev {
821f44e1126SVitaliy Gusev 	SEQUENCE4args	*sargs;
822f44e1126SVitaliy Gusev 	nfsstat4	status;
823f44e1126SVitaliy Gusev 	rfs4_slot_t	*slot;
824f44e1126SVitaliy Gusev 
825f44e1126SVitaliy Gusev 	if (args->array_len == 0 || args->array[0].argop != OP_SEQUENCE)
826f44e1126SVitaliy Gusev 		return (NFS4_OK);
827f44e1126SVitaliy Gusev 
828f44e1126SVitaliy Gusev 	sargs = &args->array[0].nfs_argop4_u.opsequence;
829f44e1126SVitaliy Gusev 
830f44e1126SVitaliy Gusev 	status = rfs4x_find_session(sargs, cs);
831f44e1126SVitaliy Gusev 	if (status != NFS4_OK)
832f44e1126SVitaliy Gusev 		return (status);
833f44e1126SVitaliy Gusev 
834*b45434deSVitaliy Gusev 	if (args->array_len > cs->sp->sn_fore->cn_attrs.ca_maxoperations)
835*b45434deSVitaliy Gusev 		return (NFS4ERR_TOO_MANY_OPS);
836*b45434deSVitaliy Gusev 
837f44e1126SVitaliy Gusev 	/*  have reference to session */
838f44e1126SVitaliy Gusev 	slot = &cs->sp->sn_slots[sargs->sa_slotid];
839f44e1126SVitaliy Gusev 
840f44e1126SVitaliy Gusev 	mutex_enter(&slot->se_lock);
841f44e1126SVitaliy Gusev 	status = check_slot_seqid(slot, sargs->sa_sequenceid);
842f44e1126SVitaliy Gusev 	if (status == nfserr_replay_cache) {
843f44e1126SVitaliy Gusev 		if (slot->se_flags & RFS4_SLOT_CACHED) {
844f44e1126SVitaliy Gusev 			slot->se_flags |= RFS4_SLOT_INUSE;
845f44e1126SVitaliy Gusev 			cs->slot = slot;
846f44e1126SVitaliy Gusev 			*resp = slot->se_buf;
847f44e1126SVitaliy Gusev 		} else {
848f44e1126SVitaliy Gusev 			status =  NFS4ERR_SEQ_MISORDERED;
849f44e1126SVitaliy Gusev 		}
850f44e1126SVitaliy Gusev 	} else if (status == NFS4_OK) {
851f44e1126SVitaliy Gusev 		slot->se_flags |= RFS4_SLOT_INUSE;
852f44e1126SVitaliy Gusev 		cs->slot = slot;
853f44e1126SVitaliy Gusev 	}
854f44e1126SVitaliy Gusev 	mutex_exit(&slot->se_lock);
855f44e1126SVitaliy Gusev 
856f44e1126SVitaliy Gusev 	return (status);
857f44e1126SVitaliy Gusev }
858f44e1126SVitaliy Gusev 
859f44e1126SVitaliy Gusev /*
860f44e1126SVitaliy Gusev  * Do cleanup things
861f44e1126SVitaliy Gusev  *   1. cache reply
862f44e1126SVitaliy Gusev  *   2. release slot
863f44e1126SVitaliy Gusev  */
864f44e1126SVitaliy Gusev void
rfs4x_sequence_done(COMPOUND4res * resp,compound_state_t * cs)865f44e1126SVitaliy Gusev rfs4x_sequence_done(COMPOUND4res *resp, compound_state_t *cs)
866f44e1126SVitaliy Gusev {
867f44e1126SVitaliy Gusev 	rfs4_slot_t *slot = cs->slot;
868f44e1126SVitaliy Gusev 	rfs4_session_t *sp = cs->sp;
869f44e1126SVitaliy Gusev 	int add = 0;
870f44e1126SVitaliy Gusev 
871f44e1126SVitaliy Gusev 	ASSERT(slot != NULL);
872f44e1126SVitaliy Gusev 	ASSERT(sp != NULL);
873f44e1126SVitaliy Gusev 
874f44e1126SVitaliy Gusev 	mutex_enter(&slot->se_lock);
875f44e1126SVitaliy Gusev 	slot->se_flags &= ~RFS4_SLOT_INUSE;
876f44e1126SVitaliy Gusev 
877f44e1126SVitaliy Gusev 	if (*cs->statusp != nfserr_replay_cache) {
878f44e1126SVitaliy Gusev 		if (slot->se_flags & RFS4_SLOT_CACHED) {
879f44e1126SVitaliy Gusev 			rfs4_compound_free(&slot->se_buf);
880f44e1126SVitaliy Gusev 			slot->se_flags &= ~RFS4_SLOT_CACHED;
881f44e1126SVitaliy Gusev 			add = -1;
882f44e1126SVitaliy Gusev 		}
883f44e1126SVitaliy Gusev 
884f44e1126SVitaliy Gusev 		if (*cs->statusp == NFS4_OK && cs->cachethis) {
885f44e1126SVitaliy Gusev 			slot->se_flags |= RFS4_SLOT_CACHED;
886f44e1126SVitaliy Gusev 			slot->se_buf = *resp;	/* cache a reply */
887f44e1126SVitaliy Gusev 			add += 1;
888f44e1126SVitaliy Gusev 		} else {
889f44e1126SVitaliy Gusev 			rfs4_compound_free(resp);
890f44e1126SVitaliy Gusev 		}
891f44e1126SVitaliy Gusev 	}
892f44e1126SVitaliy Gusev 	mutex_exit(&slot->se_lock);
893f44e1126SVitaliy Gusev 
894f44e1126SVitaliy Gusev 	if (add != 0)
895f44e1126SVitaliy Gusev 		atomic_add_32(&sp->sn_rcached, add);
896f44e1126SVitaliy Gusev }
897f44e1126SVitaliy Gusev 
898f44e1126SVitaliy Gusev /*
899f44e1126SVitaliy Gusev  * Process the SEQUENCE operation. The session pointer has already been
900f44e1126SVitaliy Gusev  * cached in the compound state, so we just dereference
901f44e1126SVitaliy Gusev  */
902f44e1126SVitaliy Gusev /*ARGSUSED*/
903f44e1126SVitaliy Gusev void
rfs4x_op_sequence(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)904f44e1126SVitaliy Gusev rfs4x_op_sequence(nfs_argop4 *argop, nfs_resop4 *resop,
905f44e1126SVitaliy Gusev     struct svc_req *req, compound_state_t *cs)
906f44e1126SVitaliy Gusev {
907f44e1126SVitaliy Gusev 	SEQUENCE4args	*args = &argop->nfs_argop4_u.opsequence;
908f44e1126SVitaliy Gusev 	SEQUENCE4res	*resp = &resop->nfs_resop4_u.opsequence;
909f44e1126SVitaliy Gusev 	SEQUENCE4resok	*rok  = &resp->SEQUENCE4res_u.sr_resok4;
910f44e1126SVitaliy Gusev 	rfs4_session_t	*sp = cs->sp;
911f44e1126SVitaliy Gusev 	rfs4_slot_t	*slot = cs->slot;
912f44e1126SVitaliy Gusev 	nfsstat4	 status = NFS4_OK;
913f44e1126SVitaliy Gusev 	uint32_t	 cbstat = 0;
914f44e1126SVitaliy Gusev 
915f44e1126SVitaliy Gusev 	DTRACE_NFSV4_2(op__sequence__start,
916f44e1126SVitaliy Gusev 	    struct compound_state *, cs,
917f44e1126SVitaliy Gusev 	    SEQUENCE4args *, args);
918f44e1126SVitaliy Gusev 
919f44e1126SVitaliy Gusev 	ASSERT(sp != NULL && slot != NULL);
920f44e1126SVitaliy Gusev 
921f44e1126SVitaliy Gusev 	if (cs->op_pos != 0) {
922f44e1126SVitaliy Gusev 		status = NFS4ERR_SEQUENCE_POS;
923f44e1126SVitaliy Gusev 		goto out;
924f44e1126SVitaliy Gusev 	}
925f44e1126SVitaliy Gusev 
926f44e1126SVitaliy Gusev 	if (rfs4_lease_expired(sp->sn_clnt)) {
927f44e1126SVitaliy Gusev 		status = NFS4ERR_BADSESSION;
928f44e1126SVitaliy Gusev 		goto out;
929f44e1126SVitaliy Gusev 	}
930f44e1126SVitaliy Gusev 
931f44e1126SVitaliy Gusev 	rfs4_dbe_lock(sp->sn_dbe);
932f44e1126SVitaliy Gusev 	cs->client = sp->sn_clnt;
933f44e1126SVitaliy Gusev 
934f44e1126SVitaliy Gusev 	DTRACE_PROBE1(compound_clid, clientid4, cs->client->rc_clientid);
935f44e1126SVitaliy Gusev 
936f44e1126SVitaliy Gusev 	ASSERT(args->sa_sequenceid == slot->se_seqid + 1);
937f44e1126SVitaliy Gusev 
938f44e1126SVitaliy Gusev 	/*
939f44e1126SVitaliy Gusev 	 * New request.
940f44e1126SVitaliy Gusev 	 */
941f44e1126SVitaliy Gusev 	mutex_enter(&slot->se_lock);
942f44e1126SVitaliy Gusev 	slot->se_seqid = args->sa_sequenceid;
943f44e1126SVitaliy Gusev 	mutex_exit(&slot->se_lock);
944f44e1126SVitaliy Gusev 
945f44e1126SVitaliy Gusev 	cs->slotno = args->sa_slotid;
946f44e1126SVitaliy Gusev 
947f44e1126SVitaliy Gusev 	/* Update access time */
948f44e1126SVitaliy Gusev 	sp->sn_laccess = nfs_sys_uptime();
949f44e1126SVitaliy Gusev 
950f44e1126SVitaliy Gusev 	/* Prepare result */
951f44e1126SVitaliy Gusev 	bcopy(sp->sn_sessid, rok->sr_sessionid, sizeof (sessionid4));
952f44e1126SVitaliy Gusev 	rok->sr_sequenceid = slot->se_seqid;
953f44e1126SVitaliy Gusev 	rok->sr_slotid = args->sa_slotid;
954f44e1126SVitaliy Gusev 	rok->sr_highest_slotid =
955f44e1126SVitaliy Gusev 	    sp->sn_fore->cn_attrs.ca_maxrequests - 1;
956f44e1126SVitaliy Gusev 	rok->sr_target_highest_slotid =
957f44e1126SVitaliy Gusev 	    sp->sn_fore->cn_attrs.ca_maxrequests - 1;
958f44e1126SVitaliy Gusev 	rok->sr_status_flags |= cbstat;
959f44e1126SVitaliy Gusev 	rfs4_dbe_unlock(sp->sn_dbe);
960f44e1126SVitaliy Gusev 
961f44e1126SVitaliy Gusev 	/* Update lease (out of session lock) */
962f44e1126SVitaliy Gusev 	rfs4_update_lease(cs->client);
963f44e1126SVitaliy Gusev 
964f44e1126SVitaliy Gusev out:
965f44e1126SVitaliy Gusev 	*cs->statusp = resp->sr_status = status;
966f44e1126SVitaliy Gusev 	DTRACE_NFSV4_2(op__sequence__done,
967f44e1126SVitaliy Gusev 	    struct compound_state *, cs,
968f44e1126SVitaliy Gusev 	    SEQUENCE4res *, resp);
969f44e1126SVitaliy Gusev }
970f44e1126SVitaliy Gusev 
971f44e1126SVitaliy Gusev /* ARGSUSED */
972f44e1126SVitaliy Gusev void
rfs4x_op_reclaim_complete(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)973f44e1126SVitaliy Gusev rfs4x_op_reclaim_complete(nfs_argop4 *argop, nfs_resop4 *resop,
974f44e1126SVitaliy Gusev     struct svc_req *req, compound_state_t *cs)
975f44e1126SVitaliy Gusev {
976f44e1126SVitaliy Gusev 	RECLAIM_COMPLETE4args *args = &argop->nfs_argop4_u.opreclaim_complete;
977f44e1126SVitaliy Gusev 	RECLAIM_COMPLETE4res *resp = &resop->nfs_resop4_u.opreclaim_complete;
978f44e1126SVitaliy Gusev 	rfs4_client_t *cp;
979f44e1126SVitaliy Gusev 	nfsstat4 status = NFS4_OK;
980f44e1126SVitaliy Gusev 
981f44e1126SVitaliy Gusev 	DTRACE_NFSV4_2(op__reclaim__complete__start,
982f44e1126SVitaliy Gusev 	    struct compound_state *, cs,
983f44e1126SVitaliy Gusev 	    RECLAIM_COMPLETE4args *, args);
984f44e1126SVitaliy Gusev 
985f44e1126SVitaliy Gusev 	cp = cs->client;
986f44e1126SVitaliy Gusev 	rfs4_dbe_lock(cp->rc_dbe);
987f44e1126SVitaliy Gusev 	if (args->rca_one_fs) {
988f44e1126SVitaliy Gusev 		/* do what?  we don't track this */
989f44e1126SVitaliy Gusev 		goto out;
990f44e1126SVitaliy Gusev 	}
991f44e1126SVitaliy Gusev 
992f44e1126SVitaliy Gusev 	if (cp->rc_reclaim_completed) {
993f44e1126SVitaliy Gusev 		status = NFS4ERR_COMPLETE_ALREADY;
994f44e1126SVitaliy Gusev 		goto out;
995f44e1126SVitaliy Gusev 	}
996f44e1126SVitaliy Gusev 
997f44e1126SVitaliy Gusev 	if (cp->rc_can_reclaim) {
998f44e1126SVitaliy Gusev 		ASSERT(rfs4_servinst(cp)->nreclaim > 0);
999f44e1126SVitaliy Gusev 		atomic_add_32(&(rfs4_servinst(cp))->nreclaim, -1);
1000f44e1126SVitaliy Gusev 	}
1001f44e1126SVitaliy Gusev 
1002f44e1126SVitaliy Gusev 	cp->rc_reclaim_completed = 1;
1003f44e1126SVitaliy Gusev out:
1004f44e1126SVitaliy Gusev 	rfs4_dbe_unlock(cp->rc_dbe);
1005f44e1126SVitaliy Gusev 
1006f44e1126SVitaliy Gusev 	*cs->statusp = resp->rcr_status = status;
1007f44e1126SVitaliy Gusev 	DTRACE_NFSV4_2(op__reclaim__complete__done,
1008f44e1126SVitaliy Gusev 	    struct compound_state *, cs,
1009f44e1126SVitaliy Gusev 	    RECLAIM_COMPLETE4res *, resp);
1010f44e1126SVitaliy Gusev }
1011f44e1126SVitaliy Gusev 
1012f44e1126SVitaliy Gusev /* ARGSUSED */
1013f44e1126SVitaliy Gusev void
rfs4x_op_destroy_clientid(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)1014f44e1126SVitaliy Gusev rfs4x_op_destroy_clientid(nfs_argop4 *argop, nfs_resop4 *resop,
1015f44e1126SVitaliy Gusev     struct svc_req *req, compound_state_t *cs)
1016f44e1126SVitaliy Gusev {
1017f44e1126SVitaliy Gusev 	DESTROY_CLIENTID4args *args = &argop->nfs_argop4_u.opdestroy_clientid;
1018f44e1126SVitaliy Gusev 	DESTROY_CLIENTID4res *resp = &resop->nfs_resop4_u.opdestroy_clientid;
1019f44e1126SVitaliy Gusev 	rfs4_client_t *cp;
1020f44e1126SVitaliy Gusev 	nfsstat4 status = NFS4_OK;
1021f44e1126SVitaliy Gusev 
1022f44e1126SVitaliy Gusev 	DTRACE_NFSV4_2(op__destroy__clientid__start,
1023f44e1126SVitaliy Gusev 	    struct compound_state *, cs,
1024f44e1126SVitaliy Gusev 	    DESTROY_CLIENTID4args *, args);
1025f44e1126SVitaliy Gusev 
1026f44e1126SVitaliy Gusev 	cp = rfs4_findclient_by_id(args->dca_clientid, TRUE);
1027f44e1126SVitaliy Gusev 	if (cp == NULL) {
1028f44e1126SVitaliy Gusev 		status = NFS4ERR_STALE_CLIENTID;
1029f44e1126SVitaliy Gusev 		goto end;
1030f44e1126SVitaliy Gusev 	}
1031f44e1126SVitaliy Gusev 
1032f44e1126SVitaliy Gusev 	rfs4_dbe_lock(cp->rc_dbe);
1033f44e1126SVitaliy Gusev 	if (client_has_state_locked(cp))
1034f44e1126SVitaliy Gusev 		status = NFS4ERR_CLIENTID_BUSY;
1035f44e1126SVitaliy Gusev 	else
1036f44e1126SVitaliy Gusev 		cp->rc_destroying = TRUE;
1037f44e1126SVitaliy Gusev 	rfs4_dbe_unlock(cp->rc_dbe);
1038f44e1126SVitaliy Gusev 
1039f44e1126SVitaliy Gusev 	if (status == NFS4_OK)
1040f44e1126SVitaliy Gusev 		rfs4_client_close(cp);
1041f44e1126SVitaliy Gusev 	else
1042f44e1126SVitaliy Gusev 		rfs4_client_rele(cp);
1043f44e1126SVitaliy Gusev end:
1044f44e1126SVitaliy Gusev 	*cs->statusp = resp->dcr_status = status;
1045f44e1126SVitaliy Gusev 
1046f44e1126SVitaliy Gusev 	DTRACE_NFSV4_2(op__destroy__clientid__done,
1047f44e1126SVitaliy Gusev 	    struct compound_state *, cs,
1048f44e1126SVitaliy Gusev 	    DESTROY_CLIENTID4res *, resp);
1049f44e1126SVitaliy Gusev }
1050f44e1126SVitaliy Gusev 
1051f44e1126SVitaliy Gusev /*ARGSUSED*/
1052f44e1126SVitaliy Gusev void
rfs4x_op_bind_conn_to_session(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)1053f44e1126SVitaliy Gusev rfs4x_op_bind_conn_to_session(nfs_argop4 *argop, nfs_resop4 *resop,
1054f44e1126SVitaliy Gusev     struct svc_req *req, compound_state_t *cs)
1055f44e1126SVitaliy Gusev {
1056f44e1126SVitaliy Gusev 	BIND_CONN_TO_SESSION4args  *args =
1057f44e1126SVitaliy Gusev 	    &argop->nfs_argop4_u.opbind_conn_to_session;
1058f44e1126SVitaliy Gusev 	BIND_CONN_TO_SESSION4res   *resp =
1059f44e1126SVitaliy Gusev 	    &resop->nfs_resop4_u.opbind_conn_to_session;
1060f44e1126SVitaliy Gusev 	BIND_CONN_TO_SESSION4resok *rok =
1061f44e1126SVitaliy Gusev 	    &resp->BIND_CONN_TO_SESSION4res_u.bctsr_resok4;
1062f44e1126SVitaliy Gusev 	rfs4_session_t	*sp;
1063f44e1126SVitaliy Gusev 	nfsstat4 status = NFS4_OK;
1064f44e1126SVitaliy Gusev 
1065f44e1126SVitaliy Gusev 	DTRACE_NFSV4_2(op__bind__conn__to__session__start,
1066f44e1126SVitaliy Gusev 	    struct compound_state *, cs,
1067f44e1126SVitaliy Gusev 	    BIND_CONN_TO_SESSION4args *, args);
1068f44e1126SVitaliy Gusev 
1069f44e1126SVitaliy Gusev 	if (cs->op_pos != 0) {
1070f44e1126SVitaliy Gusev 		status = NFS4ERR_NOT_ONLY_OP;
1071f44e1126SVitaliy Gusev 		goto end;
1072f44e1126SVitaliy Gusev 	}
1073f44e1126SVitaliy Gusev 
1074f44e1126SVitaliy Gusev 	sp = rfs4x_findsession_by_id(args->bctsa_sessid);
1075f44e1126SVitaliy Gusev 	if (sp == NULL) {
1076f44e1126SVitaliy Gusev 		status = NFS4ERR_BADSESSION;
1077f44e1126SVitaliy Gusev 		goto end;
1078f44e1126SVitaliy Gusev 	}
1079f44e1126SVitaliy Gusev 
1080f44e1126SVitaliy Gusev 	rfs4_update_lease(sp->sn_clnt); /* no need lock protection */
1081f44e1126SVitaliy Gusev 
1082f44e1126SVitaliy Gusev 	rfs4_dbe_lock(sp->sn_dbe);
1083f44e1126SVitaliy Gusev 	sp->sn_laccess = nfs_sys_uptime();
1084f44e1126SVitaliy Gusev 	rfs4_dbe_unlock(sp->sn_dbe);
1085f44e1126SVitaliy Gusev 
1086f44e1126SVitaliy Gusev 	rok->bctsr_use_conn_in_rdma_mode = FALSE;
1087f44e1126SVitaliy Gusev 
1088f44e1126SVitaliy Gusev 	switch (args->bctsa_dir) {
1089f44e1126SVitaliy Gusev 	case CDFC4_FORE:
1090f44e1126SVitaliy Gusev 	case CDFC4_FORE_OR_BOTH:
1091f44e1126SVitaliy Gusev 		/* always map to Fore */
1092f44e1126SVitaliy Gusev 		rok->bctsr_dir = CDFS4_FORE;
1093f44e1126SVitaliy Gusev 		break;
1094f44e1126SVitaliy Gusev 
1095f44e1126SVitaliy Gusev 	case CDFC4_BACK:
1096f44e1126SVitaliy Gusev 	case CDFC4_BACK_OR_BOTH:
1097f44e1126SVitaliy Gusev 		/* TODO: always map to Back */
1098f44e1126SVitaliy Gusev 		rok->bctsr_dir = CDFS4_FORE;
1099f44e1126SVitaliy Gusev 		break;
1100f44e1126SVitaliy Gusev 	default:
1101f44e1126SVitaliy Gusev 		break;
1102f44e1126SVitaliy Gusev 	}
1103f44e1126SVitaliy Gusev 
1104f44e1126SVitaliy Gusev 	bcopy(sp->sn_sessid, rok->bctsr_sessid, sizeof (sessionid4));
1105f44e1126SVitaliy Gusev 	rfs4x_session_rele(sp);
1106f44e1126SVitaliy Gusev end:
1107f44e1126SVitaliy Gusev 	*cs->statusp = resp->bctsr_status = status;
1108f44e1126SVitaliy Gusev 
1109f44e1126SVitaliy Gusev 	DTRACE_NFSV4_2(op__bind__conn__to__session__done,
1110f44e1126SVitaliy Gusev 	    struct compound_state *, cs,
1111f44e1126SVitaliy Gusev 	    BIND_CONN_TO_SESSION4res *, resp);
1112f44e1126SVitaliy Gusev }
1113f44e1126SVitaliy Gusev 
1114f44e1126SVitaliy Gusev /* ARGSUSED */
1115f44e1126SVitaliy Gusev void
rfs4x_op_secinfo_noname(nfs_argop4 * argop,nfs_resop4 * resop,struct svc_req * req,compound_state_t * cs)1116f44e1126SVitaliy Gusev rfs4x_op_secinfo_noname(nfs_argop4 *argop, nfs_resop4 *resop,
1117f44e1126SVitaliy Gusev     struct svc_req *req, compound_state_t *cs)
1118f44e1126SVitaliy Gusev {
1119f44e1126SVitaliy Gusev 	SECINFO_NO_NAME4res *resp = &resop->nfs_resop4_u.opsecinfo_no_name;
1120f44e1126SVitaliy Gusev 	nfsstat4 status;
1121f44e1126SVitaliy Gusev 	bool_t dotdot;
1122f44e1126SVitaliy Gusev 
1123f44e1126SVitaliy Gusev 	DTRACE_NFSV4_1(op__secinfo__no__name__start,
1124f44e1126SVitaliy Gusev 	    struct compound_state *, cs);
1125f44e1126SVitaliy Gusev 
1126f44e1126SVitaliy Gusev 	if (cs->vp == NULL) {
1127f44e1126SVitaliy Gusev 		status = NFS4ERR_NOFILEHANDLE;
1128f44e1126SVitaliy Gusev 		goto out;
1129f44e1126SVitaliy Gusev 	}
1130f44e1126SVitaliy Gusev 
1131f44e1126SVitaliy Gusev 	if (cs->vp->v_type != VDIR) {
1132f44e1126SVitaliy Gusev 		status = NFS4ERR_NOTDIR;
1133f44e1126SVitaliy Gusev 		goto out;
1134f44e1126SVitaliy Gusev 	}
1135f44e1126SVitaliy Gusev 
1136f44e1126SVitaliy Gusev 	dotdot =
1137f44e1126SVitaliy Gusev 	    (argop->nfs_argop4_u.opsecinfo_no_name == SECINFO_STYLE4_PARENT);
1138f44e1126SVitaliy Gusev 
1139f44e1126SVitaliy Gusev 	status = do_rfs4_op_secinfo(cs, dotdot ? ".." : ".", resp);
1140f44e1126SVitaliy Gusev 
1141f44e1126SVitaliy Gusev 	/* Cleanup FH as described at 18.45.3 and 2.6.3.1.1.8 */
1142f44e1126SVitaliy Gusev 	if (status == NFS4_OK) {
1143f44e1126SVitaliy Gusev 		VN_RELE(cs->vp);
1144f44e1126SVitaliy Gusev 		cs->vp = NULL;
1145f44e1126SVitaliy Gusev 	}
1146f44e1126SVitaliy Gusev out:
1147f44e1126SVitaliy Gusev 	*cs->statusp = resp->status = status;
1148f44e1126SVitaliy Gusev 
1149f44e1126SVitaliy Gusev 	DTRACE_NFSV4_2(op__secinfo__no__name__done,
1150f44e1126SVitaliy Gusev 	    struct compound_state *, cs,
1151f44e1126SVitaliy Gusev 	    SECINFO_NO_NAME4res *, resp);
1152f44e1126SVitaliy Gusev }
1153