xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs4x_state.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 <sys/sdt.h>
30 #include <sys/atomic.h>
31 #include <nfs/nfs4.h>
32 
33 #ifdef DEBUG
34 #define	RFS4_TABSIZE 17
35 #else
36 #define	RFS4_TABSIZE 2047
37 #endif
38 
39 #define	RFS4_MAXTABSZ 1024*1024
40 
41 slotid4 rfs4_max_slots		= MAXSLOTS;		/* fore channel */
42 slotid4 rfs4_back_max_slots	= MAXSLOTS_BACK;	/* back channel */
43 
44 typedef union {
45 	/* Both members have the same size */
46 	struct {
47 		uint32_t pad0;
48 		uint32_t pad1;
49 		uint32_t start_time;	/* NFS server start time */
50 		uint32_t s_id;		/* unique session index */
51 	} impl_id;
52 	sessionid4 id4;
53 } rfs4_sid;
54 
55 /*
56  * --------------------------------------------------------
57  * MDS - NFSv4.1  Sessions
58  * --------------------------------------------------------
59  */
60 static uint32_t
sessid_hash(void * key)61 sessid_hash(void *key)
62 {
63 	rfs4_sid *idp = key;
64 
65 	return (idp->impl_id.s_id);
66 }
67 
68 static bool_t
sessid_compare(rfs4_entry_t entry,void * key)69 sessid_compare(rfs4_entry_t entry, void *key)
70 {
71 	rfs4_session_t	*sp = (rfs4_session_t *)entry;
72 	sessionid4	*idp = (sessionid4 *)key;
73 
74 	return (bcmp(idp, &sp->sn_sessid, sizeof (sessionid4)) == 0);
75 }
76 
77 static void *
sessid_mkkey(rfs4_entry_t entry)78 sessid_mkkey(rfs4_entry_t entry)
79 {
80 	rfs4_session_t *sp = (rfs4_session_t *)entry;
81 
82 	return (&sp->sn_sessid);
83 }
84 
85 void
rfs4x_session_rele(rfs4_session_t * sp)86 rfs4x_session_rele(rfs4_session_t *sp)
87 {
88 	rfs4_dbe_rele(sp->sn_dbe);
89 }
90 
91 void
rfs4x_session_hold(rfs4_session_t * sp)92 rfs4x_session_hold(rfs4_session_t *sp)
93 {
94 	rfs4_dbe_hold(sp->sn_dbe);
95 }
96 
97 rfs4_session_t *
rfs4x_findsession_by_id(sessionid4 sessid)98 rfs4x_findsession_by_id(sessionid4 sessid)
99 {
100 	rfs4_session_t	*sp;
101 	bool_t		 create = FALSE;
102 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
103 
104 	sp = (rfs4_session_t *)rfs4_dbsearch(nsrv4->rfs4_session_idx,
105 	    sessid, &create, NULL, RFS4_DBS_VALID);
106 
107 	return (sp);
108 }
109 
110 /*
111  * A clientid can have multiple sessions associated with it. Hence,
112  * performing a raw 'mds_findsession' (even for a create) might
113  * yield a list of sessions associated with the clientid in question.
114  * Call rfs4_dbseach() function with key that cannot be found
115  * and create an association between the session table and both
116  * primary (sessionid) index and secondary (clientid) index for the
117  * newly created session.
118  */
119 
120 rfs4_session_t	*
rfs4x_createsession(session41_create_t * ap)121 rfs4x_createsession(session41_create_t *ap)
122 {
123 	static uint32_t session_id_counter;
124 
125 	rfs4_session_t	*sp = NULL;
126 	bool_t create = TRUE;
127 	rfs4_sid key = {0, 0, 0, 0};
128 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
129 
130 	/*
131 	 * Use unique counter for s_id and s_id to ensure that
132 	 * created entry will have the same index in dbi_buckets[]
133 	 */
134 	ap->cs_id = key.impl_id.s_id = atomic_inc_32_nv(&session_id_counter);
135 
136 	if ((sp = (rfs4_session_t *)rfs4_dbsearch(nsrv4->rfs4_session_idx,
137 	    &key, &create, (void *)ap, RFS4_DBS_VALID)) == NULL) {
138 		DTRACE_PROBE1(mds__srv__createsession__fail,
139 		    session41_create_t *, ap);
140 	}
141 	return (sp);
142 }
143 
144 /* return success of operation */
145 static bool_t
client_insert_session(rfs4_client_t * cp,rfs4_session_t * sp)146 client_insert_session(rfs4_client_t *cp, rfs4_session_t *sp)
147 {
148 	bool_t res = TRUE;
149 
150 	rfs4_dbe_lock(cp->rc_dbe);
151 	if (cp->rc_destroying)
152 		res = FALSE;
153 	else
154 		list_insert_tail(&cp->rc_sessions, sp);
155 	rfs4_dbe_unlock(cp->rc_dbe);
156 
157 	return (res);
158 }
159 
160 static void
client_remove_session(rfs4_client_t * cp,rfs4_session_t * sp)161 client_remove_session(rfs4_client_t *cp, rfs4_session_t *sp)
162 {
163 	rfs4_dbe_lock(cp->rc_dbe);
164 	if (list_link_active(&sp->sn_node))
165 		list_remove(&cp->rc_sessions, sp);
166 	rfs4_dbe_unlock(cp->rc_dbe);
167 }
168 
169 /*
170  * Invalidate the session in the DB (so it can't be found anymore)
171  */
172 nfsstat4
rfs4x_destroysession(rfs4_session_t * sp,unsigned useref)173 rfs4x_destroysession(rfs4_session_t *sp, unsigned useref)
174 {
175 	nfsstat4 status = NFS4_OK;
176 
177 	/*
178 	 * RFC 7862 Section 14.1.3:
179 	 * In hindsight, the  NFSv4.1 specification should have
180 	 * mandated that DESTROY_SESSION either abort or complete
181 	 * all outstanding operations.
182 	 */
183 	rfs4_dbe_lock(sp->sn_dbe);
184 	if (rfs4_dbe_refcnt(sp->sn_dbe) > useref)
185 		status = NFS4ERR_DELAY;
186 	else
187 		rfs4_dbe_invalidate(sp->sn_dbe);
188 	rfs4_dbe_unlock(sp->sn_dbe);
189 
190 	if (status == NFS4_OK)
191 		client_remove_session(sp->sn_clnt, sp);
192 
193 	return (status);
194 }
195 
196 /* Invalidate all client's sessions */
197 void
rfs4x_client_session_remove(rfs4_client_t * cp)198 rfs4x_client_session_remove(rfs4_client_t *cp)
199 {
200 	rfs4_session_t *sp;
201 
202 	/*
203 	 * Client is forcibly closing so invalidate all sessions
204 	 * without checking the refcount.
205 	 */
206 	rfs4_dbe_lock(cp->rc_dbe);
207 	while ((sp = list_head(&cp->rc_sessions)) != NULL) {
208 		list_remove(&cp->rc_sessions, sp);
209 
210 		rfs4_dbe_invalidate(sp->sn_dbe);
211 	}
212 	rfs4_dbe_unlock(cp->rc_dbe);
213 }
214 
215 /*
216  * RFC5661 Section 18.36.3
217  * Definitions for ca_maxrequestsize:
218  *   The maximum size of a COMPOUND or CB_COMPOUND request that will be sent.
219  */
220 #define	NFS4_MIN_COMPOUND_REQSZ (( \
221 	2 + 2 +	/* credential, verifier: AUTH_NULL, Length 0 */ \
222 	1 +	/* zero length tag */ \
223 	3 +	/* minorversion, opcount, opcode */ \
224 	(RNDUP(NFS4_SESSIONID_SIZE) / BYTES_PER_XDR_UNIT) + \
225 	4) *	/* seqid, slotid, high-slotid, cachethis */ \
226 	BYTES_PER_XDR_UNIT)
227 /*
228  * ca_maxresponsesize:
229  *   The maximum size of a COMPOUND or CB_COMPOUND reply that the
230  *   requester will accept from the replier including RPC headers
231  *   (see the ca_maxrequestsize definition).
232  */
233 #define	NFS4_MIN_COMPOUND_RESPSZ ((					\
234 	2 +	/* verifier: AUTH_NULL, Length 0 */ \
235 	1 +	/* status */ \
236 	1 +	/* zero length tag */ \
237 	3 +	/* opcount, opcode, status */ \
238 	(RNDUP(NFS4_SESSIONID_SIZE) / BYTES_PER_XDR_UNIT) + \
239 	4) *	/* seqid, slotid, high-slotid, target-slotid, status */ \
240 	BYTES_PER_XDR_UNIT)
241 
242 #define	NFS4_MIN_CB_COMPOUND_REQSZ	NFS4_MIN_COMPOUND_REQSZ
243 #define	NFS4_MIN_CB_COMPOUND_RESPSZ	NFS4_MIN_COMPOUND_RESPSZ
244 
245 #define	NFS4_SLOT_CACHED_SIZE	2048
246 
247 nfsstat4
sess_chan_limits(sess_channel_t * scp)248 sess_chan_limits(sess_channel_t *scp)
249 {
250 	if (scp->cn_attrs.ca_maxrequests > rfs4_max_slots) {
251 		scp->cn_attrs.ca_maxrequests = rfs4_max_slots;
252 	}
253 
254 	if (scp->cn_back_attrs.ca_maxrequests > rfs4_back_max_slots)
255 		scp->cn_back_attrs.ca_maxrequests = rfs4_back_max_slots;
256 
257 	if (scp->cn_attrs.ca_maxoperations > NFS4_COMPOUND_LIMIT)
258 		scp->cn_attrs.ca_maxoperations = NFS4_COMPOUND_LIMIT;
259 
260 	/* maxreqsize, maxrespsize */
261 	if (scp->cn_attrs.ca_maxrequestsize < NFS4_MIN_COMPOUND_REQSZ)
262 		return (NFS4ERR_TOOSMALL);
263 
264 	if (scp->cn_attrs.ca_maxresponsesize < NFS4_MIN_COMPOUND_RESPSZ)
265 		return (NFS4ERR_TOOSMALL);
266 
267 	if (scp->cn_back_attrs.ca_maxrequestsize < NFS4_MIN_CB_COMPOUND_REQSZ)
268 		return (NFS4ERR_TOOSMALL);
269 
270 	if (scp->cn_back_attrs.ca_maxresponsesize < NFS4_MIN_CB_COMPOUND_RESPSZ)
271 		return (NFS4ERR_TOOSMALL);
272 
273 	/* maxresp_cached */
274 	scp->cn_attrs.ca_maxresponsesize_cached =
275 	    MIN(scp->cn_attrs.ca_maxresponsesize_cached,
276 	    NFS4_SLOT_CACHED_SIZE + NFS4_MIN_HDR_SEQSZ);
277 
278 	scp->cn_back_attrs.ca_maxresponsesize_cached = 0;
279 
280 	return (NFS4_OK);
281 }
282 
283 /*
284  * NFSv4.1 Slot replay cache
285  */
286 static void
rfs41_cleanup_slot(rfs4_slot_t * se)287 rfs41_cleanup_slot(rfs4_slot_t *se)
288 {
289 	rfs4_compound_free((COMPOUND4res *)&se->se_buf);
290 }
291 
292 static rfs4_slot_t *
slots_alloc(size_t n)293 slots_alloc(size_t n)
294 {
295 	rfs4_slot_t *p;
296 	int i;
297 
298 	p = kmem_zalloc(sizeof (rfs4_slot_t) * n, KM_SLEEP);
299 	for (i = 0; i < n; i++) {
300 		mutex_init(&p[i].se_lock, NULL, MUTEX_DEFAULT, NULL);
301 	}
302 
303 	return (p);
304 }
305 
306 static void
slots_free(rfs4_slot_t * slots,size_t n)307 slots_free(rfs4_slot_t *slots, size_t n)
308 {
309 	int i;
310 
311 	for (i = 0; i < n; i++) {
312 		rfs4_slot_t *slot = &slots[i];
313 
314 		mutex_destroy(&slot->se_lock);
315 
316 		if (slot->se_flags & RFS4_SLOT_CACHED) {
317 			rfs41_cleanup_slot(slot);
318 		}
319 	}
320 	kmem_free(slots, sizeof (rfs4_slot_t) * n);
321 }
322 
323 /* Additional functions */
324 
325 /* check csa_flags for OP_CREATE_SESSION */
326 bool_t
nfs4x_csa_flags_valid(uint32_t flags)327 nfs4x_csa_flags_valid(uint32_t flags)
328 {
329 	if (flags & ~CREATE_SESSION4_FLAG_MASK)
330 		return (FALSE);
331 
332 	return (TRUE);
333 }
334 
335 sess_channel_t *
rfs41_create_session_channel(channel_dir_from_server4 dir)336 rfs41_create_session_channel(channel_dir_from_server4 dir)
337 {
338 	sess_channel_t   *cp;
339 	sess_bcsd_t	 *bp;
340 
341 	cp = (sess_channel_t *)kmem_zalloc(sizeof (sess_channel_t), KM_SLEEP);
342 	rw_init(&cp->cn_lock, NULL, RW_DEFAULT, NULL);
343 
344 	switch (dir) {
345 	case CDFS4_FORE:
346 		break;
347 
348 	case CDFS4_BOTH:
349 	case CDFS4_BACK:
350 		/* BackChan Specific Data */
351 		bp = (sess_bcsd_t *)kmem_zalloc(sizeof (sess_bcsd_t), KM_SLEEP);
352 		rw_init(&bp->bsd_rwlock, NULL, RW_DEFAULT, NULL);
353 		cp->cn_csd = (sess_bcsd_t *)bp;
354 		break;
355 	}
356 	return (cp);
357 }
358 
359 void
rfs41_destroy_session_channel(rfs4_session_t * sp)360 rfs41_destroy_session_channel(rfs4_session_t *sp)
361 {
362 	sess_channel_t	*cp;
363 	sess_bcsd_t	*bp;
364 
365 	if (sp->sn_back != NULL) {
366 		/* only one channel for both direction for now */
367 		ASSERT(sp->sn_fore == sp->sn_back);
368 
369 		cp = sp->sn_back;
370 		bp = (sess_bcsd_t *)cp->cn_csd;
371 		rw_destroy(&bp->bsd_rwlock);
372 		kmem_free(bp, sizeof (sess_bcsd_t));
373 	} else {
374 		cp = sp->sn_fore;
375 	}
376 
377 	rw_destroy(&cp->cn_lock);
378 	kmem_free(cp, sizeof (sess_channel_t));
379 
380 	sp->sn_back = NULL;
381 	sp->sn_fore = NULL;
382 }
383 
384 static bool_t
rfs4_session_create(rfs4_entry_t u_entry,void * arg)385 rfs4_session_create(rfs4_entry_t u_entry, void *arg)
386 {
387 	rfs4_session_t		*sp = (rfs4_session_t *)u_entry;
388 	session41_create_t	*ap = (session41_create_t *)arg;
389 	sess_channel_t		*ocp = NULL;
390 	rfs4_sid		*sidp;
391 	bool_t			 bdrpc = FALSE;
392 	channel_dir_from_server4 dir;
393 	nfsstat4		 sle;
394 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
395 
396 	ASSERT(sp != NULL);
397 	if (sp == NULL)
398 		return (FALSE);
399 
400 	/*
401 	 * Back pointer/ref to parent data struct (rfs4_client_t)
402 	 */
403 	sp->sn_clnt = (rfs4_client_t *)ap->cs_client;
404 	rfs4_dbe_hold(sp->sn_clnt->rc_dbe);
405 
406 	/*
407 	 * Handcrafting the session id
408 	 */
409 	sidp = (rfs4_sid *)&sp->sn_sessid;
410 	sidp->impl_id.pad0 = 0x00000000;
411 	sidp->impl_id.pad1 = 0xFFFFFFFF;
412 	sidp->impl_id.start_time = nsrv4->rfs4_start_time;
413 	sidp->impl_id.s_id = ap->cs_id;
414 
415 	/*
416 	 * Process csa_flags; note that CREATE_SESSION4_FLAG_CONN_BACK_CHAN
417 	 * is processed below since it affects direction and setup of the
418 	 * backchannel accordingly.
419 	 */
420 	if (!nfs4x_csa_flags_valid(ap->cs_aotw.csa_flags)) {
421 		ap->cs_error = NFS4ERR_INVAL;
422 		goto err;
423 	}
424 
425 	sp->sn_csflags = ap->cs_aotw.csa_flags;
426 	if (ap->cs_aotw.csa_flags & CREATE_SESSION4_FLAG_PERSIST)
427 		/* Do not support persistent reply cache (yet). */
428 		sp->sn_csflags &= ~CREATE_SESSION4_FLAG_PERSIST;
429 
430 	if (ap->cs_aotw.csa_flags & CREATE_SESSION4_FLAG_CONN_RDMA)
431 		/* No RDMA for now */
432 		sp->sn_csflags &= ~CREATE_SESSION4_FLAG_CONN_RDMA;
433 
434 	/*
435 	 * Initialize some overall sessions values
436 	 */
437 	sp->sn_bc.progno = ap->cs_aotw.csa_cb_program;
438 	sp->sn_laccess = nfs_sys_uptime();
439 	sp->sn_flags = 0;
440 	sp->sn_rcached = 0;
441 
442 	/*
443 	 * Check if client has specified that the FORE channel should
444 	 * also be used for call back traffic (ie. bidir RPC). If so,
445 	 * let's try to accomodate the request.
446 	 */
447 	DTRACE_PROBE1(csa__flags, uint32_t, ap->cs_aotw.csa_flags);
448 
449 	/*
450 	 * Session's channel flags depending on bdrpc
451 	 * TODO: Add backchannel handling, i.e. when bdrpc is TRUE
452 	 */
453 	dir = bdrpc ? (CDFS4_FORE | CDFS4_BACK) : CDFS4_FORE;
454 	ocp = rfs41_create_session_channel(dir);
455 	ocp->cn_dir = dir;
456 	sp->sn_fore = ocp;
457 
458 	/*
459 	 * Check if channel attrs will be flexible enough for future
460 	 * purposes. Channel attribute enforcement is done as part of
461 	 * COMPOUND processing.
462 	 */
463 	ocp->cn_attrs = ap->cs_aotw.csa_fore_chan_attrs;
464 	ocp->cn_back_attrs = ap->cs_aotw.csa_back_chan_attrs;
465 	sle = sess_chan_limits(ocp);
466 	if (sle != NFS4_OK) {
467 		ap->cs_error = sle;
468 		goto err_free_chan;
469 	}
470 
471 	/* will fail if client is going to destroy */
472 	if (!client_insert_session(sp->sn_clnt, sp)) {
473 		ap->cs_error = NFS4ERR_DELAY;
474 		goto err_free_chan;
475 	}
476 
477 	/*
478 	 * No need for locks/synchronization at this time,
479 	 * since we're barely creating the session.
480 	 */
481 	if (bdrpc) {
482 		/* Need to be implemented */
483 		VERIFY(0);
484 	} else {
485 		sp->sn_csflags &= ~CREATE_SESSION4_FLAG_CONN_BACK_CHAN;
486 		sp->sn_back = NULL;
487 	}
488 
489 	/*
490 	 * Now we allocate space for the slrc, initializing each slot's
491 	 * sequenceid and slotid to zero and a (pre)cached result of
492 	 * NFS4ERR_SEQ_MISORDERED. Note that we zero out the entries
493 	 * by virtue of the z-alloc.
494 	 */
495 	sp->sn_slots = slots_alloc(ocp->cn_attrs.ca_maxrequests);
496 
497 	return (TRUE);
498 
499 err_free_chan:
500 	rfs41_destroy_session_channel(sp);
501 err:
502 	rfs4_dbe_rele(sp->sn_clnt->rc_dbe);
503 	return (FALSE);
504 }
505 
506 static void
rfs4_session_destroy(rfs4_entry_t u_entry)507 rfs4_session_destroy(rfs4_entry_t u_entry)
508 {
509 	rfs4_session_t	*sp = (rfs4_session_t *)u_entry;
510 	sess_bcsd_t	*bsdp;
511 
512 	if (SN_CB_CHAN_EST(sp) && (bsdp = sp->sn_back->cn_csd) != NULL) {
513 		slots_free(bsdp->bsd_slots,
514 		    sp->sn_back->cn_back_attrs.ca_maxrequests);
515 		bsdp->bsd_slots = NULL;
516 	}
517 
518 	/*
519 	 * Nuke slot replay cache for this session
520 	 */
521 	if (sp->sn_slots) {
522 		slots_free(sp->sn_slots, sp->sn_fore->cn_attrs.ca_maxrequests);
523 		sp->sn_slots = NULL;
524 	}
525 
526 	/*
527 	 * Remove the fore and back channels.
528 	 */
529 	rfs41_destroy_session_channel(sp);
530 
531 	client_remove_session(sp->sn_clnt, sp);
532 
533 	rfs4_client_rele(sp->sn_clnt);
534 }
535 
536 static bool_t
rfs4_session_expiry(rfs4_entry_t u_entry)537 rfs4_session_expiry(rfs4_entry_t u_entry)
538 {
539 	rfs4_session_t *sp = (rfs4_session_t *)u_entry;
540 
541 	if (sp == NULL || rfs4_dbe_is_invalid(sp->sn_dbe))
542 		return (TRUE);
543 
544 	if (rfs4_lease_expired(sp->sn_clnt))
545 		return (TRUE);
546 
547 	return (FALSE);
548 }
549 
550 void
rfs4x_state_init_locked(nfs4_srv_t * nsrv4)551 rfs4x_state_init_locked(nfs4_srv_t *nsrv4)
552 {
553 	nsrv4->rfs4_session_tab = rfs4_table_create(nsrv4->nfs4_server_state,
554 	    "Session", 5 * rfs4_lease_time, 1, rfs4_session_create,
555 	    rfs4_session_destroy, rfs4_session_expiry, sizeof (rfs4_session_t),
556 	    RFS4_TABSIZE, RFS4_MAXTABSZ/8, -1);
557 
558 	nsrv4->rfs4_session_idx = rfs4_index_create(nsrv4->rfs4_session_tab,
559 	    "session_idx", sessid_hash, sessid_compare, sessid_mkkey, TRUE);
560 }
561 
562 void
rfs4x_state_fini(nfs4_srv_t * nsrv4)563 rfs4x_state_fini(nfs4_srv_t *nsrv4)
564 {
565 	/* All tables will be destroyed by caller */
566 }
567