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