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 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 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 * 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 86 rfs4x_session_rele(rfs4_session_t *sp) 87 { 88 rfs4_dbe_rele(sp->sn_dbe); 89 } 90 91 void 92 rfs4x_session_hold(rfs4_session_t *sp) 93 { 94 rfs4_dbe_hold(sp->sn_dbe); 95 } 96 97 rfs4_session_t * 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 * 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 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 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 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 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 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 287 rfs41_cleanup_slot(rfs4_slot_t *se) 288 { 289 rfs4_compound_free((COMPOUND4res *)&se->se_buf); 290 } 291 292 static rfs4_slot_t * 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 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 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 * 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 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 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 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 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 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 563 rfs4x_state_fini(nfs4_srv_t *nsrv4) 564 { 565 /* All tables will be destroyed by caller */ 566 } 567