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 (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T. 27 * All rights reserved. 28 */ 29 30 31 #include <sys/types.h> 32 #include <sys/param.h> 33 #include <sys/time.h> 34 #include <sys/vfs.h> 35 #include <sys/vnode.h> 36 #include <sys/socket.h> 37 #include <sys/errno.h> 38 #include <sys/uio.h> 39 #include <sys/proc.h> 40 #include <sys/user.h> 41 #include <sys/file.h> 42 #include <sys/tiuser.h> 43 #include <sys/kmem.h> 44 #include <sys/pathname.h> 45 #include <sys/debug.h> 46 #include <sys/vtrace.h> 47 #include <sys/cmn_err.h> 48 #include <sys/acl.h> 49 #include <sys/utsname.h> 50 #include <sys/sdt.h> 51 #include <netinet/in.h> 52 53 #include <rpc/types.h> 54 #include <rpc/auth.h> 55 #include <rpc/svc.h> 56 57 #include <nfs/nfs.h> 58 #include <nfs/export.h> 59 #include <nfs/nfssys.h> 60 #include <nfs/nfs_clnt.h> 61 #include <nfs/nfs_acl.h> 62 #include <nfs/nfs_log.h> 63 #include <nfs/lm.h> 64 #include <sys/sunddi.h> 65 #include <sys/pkp_hash.h> 66 67 treenode_t *ns_root; 68 69 struct exportinfo *exptable_path_hash[PKP_HASH_SIZE]; 70 struct exportinfo *exptable[EXPTABLESIZE]; 71 72 static int unexport(exportinfo_t *); 73 static void exportfree(exportinfo_t *); 74 static int loadindex(exportdata_t *); 75 76 extern void nfsauth_cache_free(exportinfo_t *); 77 extern int sec_svc_loadrootnames(int, int, caddr_t **, model_t); 78 extern void sec_svc_freerootnames(int, int, caddr_t *); 79 80 static int build_seclist_nodups(exportdata_t *, secinfo_t *, int); 81 static void srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int); 82 static void srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int); 83 static void srv_secinfo_treeclimb(exportinfo_t *, secinfo_t *, int, int); 84 85 #ifdef VOLATILE_FH_TEST 86 static struct ex_vol_rename *find_volrnm_fh(exportinfo_t *, nfs_fh4 *); 87 static uint32_t find_volrnm_fh_id(exportinfo_t *, nfs_fh4 *); 88 static void free_volrnm_list(exportinfo_t *); 89 #endif /* VOLATILE_FH_TEST */ 90 91 /* 92 * exported_lock Read/Write lock that protects the exportinfo list. 93 * This lock must be held when searching or modifiying 94 * the exportinfo list. 95 */ 96 krwlock_t exported_lock; 97 98 /* 99 * "public" and default (root) location for public filehandle 100 */ 101 struct exportinfo *exi_public, *exi_root; 102 103 fid_t exi_rootfid; /* for checking the default public file handle */ 104 105 fhandle_t nullfh2; /* for comparing V2 filehandles */ 106 107 /* 108 * macro for static dtrace probes to trace server namespace ref count mods. 109 */ 110 #define SECREF_TRACE(seclist, tag, flav, aftcnt) \ 111 DTRACE_PROBE4(nfss__i__nmspc__secref, struct secinfo *, (seclist), \ 112 char *, (tag), int, (int)(flav), int, (int)(aftcnt)) 113 114 115 #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1)) 116 117 static uint8_t 118 xor_hash(uint8_t *data, int len) 119 { 120 uint8_t h = 0; 121 122 while (len--) 123 h ^= *data++; 124 125 return (h); 126 } 127 128 /* 129 * File handle hash function, XOR over all bytes in fsid and fid. 130 */ 131 static unsigned 132 nfs_fhhash(fsid_t *fsid, fid_t *fid) 133 { 134 int len; 135 uint8_t h; 136 137 h = xor_hash((uint8_t *)fsid, sizeof (fsid_t)); 138 139 /* 140 * Sanity check the length before using it 141 * blindly in case the client trashed it. 142 */ 143 len = fid->fid_len > NFS_FH4MAXDATA ? 0 : fid->fid_len; 144 h ^= xor_hash((uint8_t *)fid->fid_data, len); 145 146 return ((unsigned)h); 147 } 148 149 /* 150 * Free the memory allocated within a secinfo entry. 151 */ 152 void 153 srv_secinfo_entry_free(struct secinfo *secp) 154 { 155 if (secp->s_rootcnt > 0 && secp->s_rootnames != NULL) { 156 sec_svc_freerootnames(secp->s_secinfo.sc_rpcnum, 157 secp->s_rootcnt, secp->s_rootnames); 158 secp->s_rootcnt = 0; 159 } 160 161 if ((secp->s_secinfo.sc_rpcnum == RPCSEC_GSS) && 162 (secp->s_secinfo.sc_gss_mech_type)) { 163 kmem_free(secp->s_secinfo.sc_gss_mech_type->elements, 164 secp->s_secinfo.sc_gss_mech_type->length); 165 kmem_free(secp->s_secinfo.sc_gss_mech_type, 166 sizeof (rpc_gss_OID_desc)); 167 secp->s_secinfo.sc_gss_mech_type = NULL; 168 } 169 } 170 171 /* 172 * Free a list of secinfo allocated in the exportdata structure. 173 */ 174 void 175 srv_secinfo_list_free(struct secinfo *secinfo, int cnt) 176 { 177 int i; 178 179 if (cnt == 0) 180 return; 181 182 for (i = 0; i < cnt; i++) 183 srv_secinfo_entry_free(&secinfo[i]); 184 185 kmem_free(secinfo, cnt * sizeof (struct secinfo)); 186 } 187 188 /* 189 * Allocate and copy a secinfo data from "from" to "to". 190 * 191 * This routine is used by srv_secinfo_add() to add a new flavor to an 192 * ancestor's export node. The rootnames are not copied because the 193 * allowable rootname access only applies to the explicit exported node, 194 * not its ancestor's. 195 * 196 * "to" should have already been allocated and zeroed before calling 197 * this routine. 198 * 199 * This routine is used under the protection of exported_lock (RW_WRITER). 200 */ 201 void 202 srv_secinfo_copy(struct secinfo *from, struct secinfo *to) 203 { 204 to->s_secinfo.sc_nfsnum = from->s_secinfo.sc_nfsnum; 205 to->s_secinfo.sc_rpcnum = from->s_secinfo.sc_rpcnum; 206 207 if (from->s_secinfo.sc_rpcnum == RPCSEC_GSS) { 208 to->s_secinfo.sc_service = from->s_secinfo.sc_service; 209 bcopy(from->s_secinfo.sc_name, to->s_secinfo.sc_name, 210 strlen(from->s_secinfo.sc_name)); 211 bcopy(from->s_secinfo.sc_gss_mech, to->s_secinfo.sc_gss_mech, 212 strlen(from->s_secinfo.sc_gss_mech)); 213 214 /* copy mechanism oid */ 215 to->s_secinfo.sc_gss_mech_type = 216 kmem_alloc(sizeof (rpc_gss_OID_desc), KM_SLEEP); 217 to->s_secinfo.sc_gss_mech_type->length = 218 from->s_secinfo.sc_gss_mech_type->length; 219 to->s_secinfo.sc_gss_mech_type->elements = 220 kmem_alloc(from->s_secinfo.sc_gss_mech_type->length, 221 KM_SLEEP); 222 bcopy(from->s_secinfo.sc_gss_mech_type->elements, 223 to->s_secinfo.sc_gss_mech_type->elements, 224 from->s_secinfo.sc_gss_mech_type->length); 225 } 226 227 to->s_refcnt = from->s_refcnt; 228 to->s_window = from->s_window; 229 /* no need to copy the mode bits - s_flags */ 230 } 231 232 /* 233 * Create a secinfo array without duplicates. The condensed 234 * flavor list is used to propagate flavor ref counts to an 235 * export's ancestor pseudonodes. 236 */ 237 static int 238 build_seclist_nodups(exportdata_t *exd, secinfo_t *nodups, int exponly) 239 { 240 int ccnt, c; 241 int ncnt, n; 242 struct secinfo *cursec; 243 244 ncnt = 0; 245 ccnt = exd->ex_seccnt; 246 cursec = exd->ex_secinfo; 247 248 for (c = 0; c < ccnt; c++) { 249 250 if (exponly && ! SEC_REF_EXPORTED(&cursec[c])) 251 continue; 252 253 for (n = 0; n < ncnt; n++) { 254 if (nodups[n].s_secinfo.sc_nfsnum == 255 cursec[c].s_secinfo.sc_nfsnum) 256 break; 257 } 258 259 /* 260 * The structure copy below also copys ptrs embedded 261 * within struct secinfo. The ptrs are copied but 262 * they are never freed from the nodups array. If 263 * an ancestor's secinfo array doesn't contain one 264 * of the nodups flavors, then the entry is properly 265 * copied into the ancestor's secinfo array. 266 * (see srv_secinfo_copy) 267 */ 268 if (n == ncnt) { 269 nodups[n] = cursec[c]; 270 ncnt++; 271 } 272 } 273 return (ncnt); 274 } 275 276 /* 277 * Add the new security flavors from newdata to the current list, pcursec. 278 * Upon return, *pcursec has the newly merged secinfo list. 279 * 280 * There should be at least 1 secinfo entry in newsec. 281 * 282 * This routine is used under the protection of exported_lock (RW_WRITER). 283 */ 284 static void 285 srv_secinfo_add(secinfo_t **pcursec, int *pcurcnt, secinfo_t *newsec, 286 int newcnt, int is_pseudo) 287 { 288 int ccnt, c; /* sec count in current data - curdata */ 289 int n; /* index for newsec - newsecinfo */ 290 int tcnt; /* total sec count after merge */ 291 int mcnt; /* total sec count after merge */ 292 struct secinfo *msec; /* merged secinfo list */ 293 struct secinfo *cursec; 294 295 cursec = *pcursec; 296 ccnt = *pcurcnt; 297 298 ASSERT(newcnt > 0); 299 tcnt = ccnt + newcnt; 300 301 for (n = 0; n < newcnt; n++) { 302 for (c = 0; c < ccnt; c++) { 303 if (newsec[n].s_secinfo.sc_nfsnum == 304 cursec[c].s_secinfo.sc_nfsnum) { 305 cursec[c].s_refcnt += newsec[n].s_refcnt; 306 SECREF_TRACE(cursec, "add_ref", 307 cursec[c].s_secinfo.sc_nfsnum, 308 cursec[c].s_refcnt); 309 tcnt--; 310 break; 311 } 312 } 313 } 314 315 if (tcnt == ccnt) 316 return; /* no change; no new flavors */ 317 318 msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP); 319 320 /* move current secinfo list data to the new list */ 321 for (c = 0; c < ccnt; c++) 322 msec[c] = cursec[c]; 323 324 /* Add the flavor that's not in the current data */ 325 mcnt = ccnt; 326 for (n = 0; n < newcnt; n++) { 327 for (c = 0; c < ccnt; c++) { 328 if (newsec[n].s_secinfo.sc_nfsnum == 329 cursec[c].s_secinfo.sc_nfsnum) 330 break; 331 } 332 333 /* This is the one. Add it. */ 334 if (c == ccnt) { 335 srv_secinfo_copy(&newsec[n], &msec[mcnt]); 336 337 if (is_pseudo) 338 msec[mcnt].s_flags = M_RO; 339 340 SECREF_TRACE(msec, "new_ref", 341 msec[mcnt].s_secinfo.sc_nfsnum, 342 msec[mcnt].s_refcnt); 343 mcnt++; 344 } 345 } 346 347 ASSERT(mcnt == tcnt); 348 349 /* 350 * Done. Update curdata. Free the old secinfo list in 351 * curdata and return the new sec array info 352 */ 353 if (ccnt > 0) 354 kmem_free(cursec, ccnt * sizeof (struct secinfo)); 355 *pcurcnt = tcnt; 356 *pcursec = msec; 357 } 358 359 /* 360 * For NFS V4. 361 * Remove the security data of the unexported node from its ancestors. 362 * Assume there is at least one flavor entry in the current sec list 363 * (pcursec). 364 * 365 * This routine is used under the protection of exported_lock (RW_WRITER). 366 * 367 * Every element of remsec is an explicitly exported flavor. If 368 * srv_secinfo_remove() is called fom an exportfs error path, then 369 * the flavor list was derived from the user's share cmdline, 370 * and all flavors are explicit. If it was called from the unshare path, 371 * build_seclist_nodups() was called with the exponly flag. 372 */ 373 static void 374 srv_secinfo_remove(secinfo_t **pcursec, int *pcurcnt, secinfo_t *remsec, 375 int remcnt) 376 { 377 int ccnt, c; /* sec count in current data - cursec */ 378 int r; /* sec count in removal data - remsec */ 379 int tcnt, mcnt; /* total sec count after removing */ 380 struct secinfo *msec; /* final secinfo list after removing */ 381 struct secinfo *cursec; 382 383 cursec = *pcursec; 384 ccnt = *pcurcnt; 385 tcnt = ccnt; 386 387 for (r = 0; r < remcnt; r++) { 388 /* 389 * At unshare/reshare time, only explicitly shared flavor ref 390 * counts are decremented and propagated to ancestors. 391 * Implicit flavor refs came from shared descendants, and 392 * they must be kept. 393 */ 394 if (! SEC_REF_EXPORTED(&remsec[r])) 395 continue; 396 397 for (c = 0; c < ccnt; c++) { 398 if (remsec[r].s_secinfo.sc_nfsnum == 399 cursec[c].s_secinfo.sc_nfsnum) { 400 401 /* 402 * Decrement secinfo reference count by 1. 403 * If this entry is invalid after decrementing 404 * the count (i.e. count < 1), this entry will 405 * be removed. 406 */ 407 cursec[c].s_refcnt--; 408 409 SECREF_TRACE(cursec, "del_ref", 410 cursec[c].s_secinfo.sc_nfsnum, 411 cursec[c].s_refcnt); 412 413 ASSERT(cursec[c].s_refcnt >= 0); 414 415 if (SEC_REF_INVALID(&cursec[c])) 416 tcnt--; 417 break; 418 } 419 } 420 } 421 422 ASSERT(tcnt >= 0); 423 if (tcnt == ccnt) 424 return; /* no change; no flavors to remove */ 425 426 if (tcnt == 0) { 427 srv_secinfo_list_free(cursec, ccnt); 428 *pcurcnt = 0; 429 *pcursec = NULL; 430 return; 431 } 432 433 msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP); 434 435 /* walk thru the given secinfo list to remove the flavors */ 436 mcnt = 0; 437 for (c = 0; c < ccnt; c++) { 438 if (SEC_REF_INVALID(&cursec[c])) { 439 srv_secinfo_entry_free(&cursec[c]); 440 } else { 441 msec[mcnt] = cursec[c]; 442 mcnt++; 443 } 444 } 445 446 ASSERT(mcnt == tcnt); 447 /* 448 * Done. Update curdata. 449 * Free the existing secinfo list in curdata. All pointers 450 * within the list have either been moved to msec or freed 451 * if it's invalid. 452 */ 453 kmem_free(*pcursec, ccnt * sizeof (struct secinfo)); 454 *pcursec = msec; 455 *pcurcnt = tcnt; 456 } 457 458 459 /* 460 * For the reshare case, sec flavor accounting happens in 3 steps: 461 * 1) propagate addition of new flavor refs up the ancestor tree 462 * 2) transfer flavor refs of descendants to new/reshared exportdata 463 * 3) propagate removal of old flavor refs up the ancestor tree 464 * 465 * srv_secinfo_exp2exp() implements step 2 of a reshare. At this point, 466 * the new flavor list has already been propagated up through the 467 * ancestor tree via srv_secinfo_treeclimb(). 468 * 469 * If there is more than 1 export reference to an old flavor (i.e. some 470 * of its children shared with this flavor), this flavor information 471 * needs to be transferred to the new exportdata struct. A flavor in 472 * the old exportdata has descendant refs when its s_refcnt > 1 or it 473 * is implicitly shared (M_SEC4_EXPORTED not set in s_flags). 474 * 475 * SEC_REF_EXPORTED() is only true when M_SEC4_EXPORTED is set 476 * SEC_REF_SELF() is only true when both M_SEC4_EXPORTED is set and s_refcnt==1 477 * 478 * Transferring descendant flavor refcnts happens in 2 passes: 479 * a) flavors used before (oldsecinfo) and after (curdata->ex_secinfo) reshare 480 * b) flavors used before but not after reshare 481 * 482 * This routine is used under the protection of exported_lock (RW_WRITER). 483 */ 484 void 485 srv_secinfo_exp2exp(exportdata_t *curdata, secinfo_t *oldsecinfo, int ocnt) 486 { 487 int ccnt, c; /* sec count in current data - curdata */ 488 int o; /* sec count in old data - oldsecinfo */ 489 int tcnt, mcnt; /* total sec count after the transfer */ 490 struct secinfo *msec; /* merged secinfo list */ 491 492 ccnt = curdata->ex_seccnt; 493 494 ASSERT(ocnt > 0); 495 ASSERT(!(curdata->ex_flags & EX_PSEUDO)); 496 497 /* 498 * If the oldsecinfo has flavors with more than 1 reference count 499 * and the flavor is specified in the reshare, transfer the flavor 500 * refs to the new seclist (curdata.ex_secinfo). 501 */ 502 tcnt = ccnt + ocnt; 503 504 for (o = 0; o < ocnt; o++) { 505 506 if (SEC_REF_SELF(&oldsecinfo[o])) { 507 tcnt--; 508 continue; 509 } 510 511 for (c = 0; c < ccnt; c++) { 512 if (oldsecinfo[o].s_secinfo.sc_nfsnum == 513 curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) { 514 515 /* 516 * add old reference to the current 517 * secinfo count 518 */ 519 curdata->ex_secinfo[c].s_refcnt += 520 oldsecinfo[o].s_refcnt; 521 522 /* 523 * Delete the old export flavor 524 * reference. The initial reference 525 * was created during srv_secinfo_add, 526 * and the count is decremented below 527 * to account for the initial reference. 528 */ 529 if (SEC_REF_EXPORTED(&oldsecinfo[o])) 530 curdata->ex_secinfo[c].s_refcnt--; 531 532 SECREF_TRACE(curdata->ex_path, 533 "reshare_xfer_common_child_refs", 534 curdata->ex_secinfo[c].s_secinfo.sc_nfsnum, 535 curdata->ex_secinfo[c].s_refcnt); 536 537 ASSERT(curdata->ex_secinfo[c].s_refcnt >= 0); 538 539 tcnt--; 540 break; 541 } 542 } 543 } 544 545 if (tcnt == ccnt) 546 return; /* no more transfer to do */ 547 548 /* 549 * oldsecinfo has flavors referenced by its children that are not 550 * in the current (new) export flavor list. Add these flavors. 551 */ 552 msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP); 553 554 /* move current secinfo list data to the new list */ 555 for (c = 0; c < ccnt; c++) 556 msec[c] = curdata->ex_secinfo[c]; 557 558 /* 559 * Add the flavor that's not in the new export, but still 560 * referenced by its children. 561 */ 562 mcnt = ccnt; 563 for (o = 0; o < ocnt; o++) { 564 if (! SEC_REF_SELF(&oldsecinfo[o])) { 565 for (c = 0; c < ccnt; c++) { 566 if (oldsecinfo[o].s_secinfo.sc_nfsnum == 567 curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) 568 break; 569 } 570 571 /* 572 * This is the one. Add it. Decrement the ref count 573 * by 1 if the flavor is an explicitly shared flavor 574 * for the oldsecinfo export node. 575 */ 576 if (c == ccnt) { 577 srv_secinfo_copy(&oldsecinfo[o], &msec[mcnt]); 578 if (SEC_REF_EXPORTED(&oldsecinfo[o])) 579 msec[mcnt].s_refcnt--; 580 581 SECREF_TRACE(curdata, 582 "reshare_xfer_implicit_child_refs", 583 msec[mcnt].s_secinfo.sc_nfsnum, 584 msec[mcnt].s_refcnt); 585 586 ASSERT(msec[mcnt].s_refcnt >= 0); 587 mcnt++; 588 } 589 } 590 } 591 592 ASSERT(mcnt == tcnt); 593 /* 594 * Done. Update curdata, free the existing secinfo list in 595 * curdata and set the new value. 596 */ 597 if (ccnt > 0) 598 kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo)); 599 curdata->ex_seccnt = tcnt; 600 curdata->ex_secinfo = msec; 601 } 602 603 /* 604 * When unsharing an old export node and the old node becomes a pseudo node, 605 * if there is more than 1 export reference to an old flavor (i.e. some of 606 * its children shared with this flavor), this flavor information needs to 607 * be transferred to the new shared node. 608 * 609 * This routine is used under the protection of exported_lock (RW_WRITER). 610 */ 611 void 612 srv_secinfo_exp2pseu(exportdata_t *curdata, exportdata_t *olddata) 613 { 614 int ocnt, o; /* sec count in transfer data - trandata */ 615 int tcnt, mcnt; /* total sec count after transfer */ 616 struct secinfo *msec; /* merged secinfo list */ 617 618 ASSERT(curdata->ex_flags & EX_PSEUDO); 619 ASSERT(curdata->ex_seccnt == 0); 620 621 ocnt = olddata->ex_seccnt; 622 623 /* 624 * If the olddata has flavors with more than 1 reference count, 625 * transfer the information to the curdata. 626 */ 627 tcnt = ocnt; 628 629 for (o = 0; o < ocnt; o++) { 630 if (SEC_REF_SELF(&olddata->ex_secinfo[o])) 631 tcnt--; 632 } 633 634 if (tcnt == 0) 635 return; /* no transfer to do */ 636 637 msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP); 638 639 mcnt = 0; 640 for (o = 0; o < ocnt; o++) { 641 if (! SEC_REF_SELF(&olddata->ex_secinfo[o])) { 642 643 /* 644 * Decrement the reference count by 1 if the flavor is 645 * an explicitly shared flavor for the olddata export 646 * node. 647 */ 648 srv_secinfo_copy(&olddata->ex_secinfo[o], &msec[mcnt]); 649 msec[mcnt].s_flags = M_RO; 650 if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o])) 651 msec[mcnt].s_refcnt--; 652 653 SECREF_TRACE(curdata, "unshare_morph_pseudo", 654 msec[mcnt].s_secinfo.sc_nfsnum, 655 msec[mcnt].s_refcnt); 656 657 ASSERT(msec[mcnt].s_refcnt >= 0); 658 mcnt++; 659 } 660 } 661 662 ASSERT(mcnt == tcnt); 663 /* 664 * Done. Update curdata. 665 * Free up the existing secinfo list in curdata and 666 * set the new value. 667 */ 668 curdata->ex_seccnt = tcnt; 669 curdata->ex_secinfo = msec; 670 } 671 672 /* 673 * Find for given treenode the exportinfo which has its 674 * exp_visible linked on its exi_visible list. 675 * 676 * Note: We could add new pointer either to treenode or 677 * to exp_visible, which will point there directly. 678 * This would buy some speed for some memory. 679 */ 680 exportinfo_t * 681 vis2exi(treenode_t *tnode) 682 { 683 exportinfo_t *exi_ret = NULL; 684 685 for (;;) { 686 tnode = tnode->tree_parent; 687 if (TREE_ROOT(tnode)) { 688 exi_ret = tnode->tree_exi; 689 break; 690 } 691 } 692 693 ASSERT(exi_ret); /* Every visible should have its home exportinfo */ 694 return (exi_ret); 695 } 696 697 /* 698 * For NFS V4. 699 * Add or remove the newly exported or unexported security flavors of the 700 * given exportinfo from its ancestors upto the system root. 701 */ 702 void 703 srv_secinfo_treeclimb(exportinfo_t *exip, secinfo_t *sec, int seccnt, int isadd) 704 { 705 treenode_t *tnode = exip->exi_tree; 706 707 ASSERT(RW_WRITE_HELD(&exported_lock)); 708 ASSERT(tnode); 709 710 if (seccnt == 0) 711 return; 712 713 /* 714 * If flavors are being added and the new export root isn't 715 * also VROOT, its implicitly allowed flavors are inherited from 716 * from its pseudonode. 717 * Note - for VROOT exports the implicitly allowed flavors were 718 * transferred from the PSEUDO export in exportfs() 719 */ 720 if (isadd && !(exip->exi_vp->v_flag & VROOT) && 721 tnode->tree_vis->vis_seccnt > 0) { 722 srv_secinfo_add(&exip->exi_export.ex_secinfo, 723 &exip->exi_export.ex_seccnt, tnode->tree_vis->vis_secinfo, 724 tnode->tree_vis->vis_seccnt, FALSE); 725 } 726 727 /* 728 * Move to parent node and propagate sec flavor 729 * to exportinfo and to visible structures. 730 */ 731 tnode = tnode->tree_parent; 732 733 while (tnode) { 734 735 /* If there is exportinfo, update it */ 736 if (tnode->tree_exi) { 737 secinfo_t **pxsec = 738 &tnode->tree_exi->exi_export.ex_secinfo; 739 int *pxcnt = &tnode->tree_exi->exi_export.ex_seccnt; 740 int is_pseudo = PSEUDO(tnode->tree_exi); 741 if (isadd) 742 srv_secinfo_add(pxsec, pxcnt, sec, seccnt, 743 is_pseudo); 744 else 745 srv_secinfo_remove(pxsec, pxcnt, sec, seccnt); 746 } 747 748 /* Update every visible - only root node has no visible */ 749 if (tnode->tree_vis) { 750 secinfo_t **pxsec = &tnode->tree_vis->vis_secinfo; 751 int *pxcnt = &tnode->tree_vis->vis_seccnt; 752 if (isadd) 753 srv_secinfo_add(pxsec, pxcnt, sec, seccnt, 754 FALSE); 755 else 756 srv_secinfo_remove(pxsec, pxcnt, sec, seccnt); 757 } 758 tnode = tnode->tree_parent; 759 } 760 } 761 762 /* hash_name is a text substitution for either fid_hash or path_hash */ 763 #define exp_hash_unlink(exi, hash_name) \ 764 if (*(exi)->hash_name.bckt == (exi)) \ 765 *(exi)->hash_name.bckt = (exi)->hash_name.next; \ 766 if ((exi)->hash_name.prev) \ 767 (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \ 768 if ((exi)->hash_name.next) \ 769 (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \ 770 (exi)->hash_name.bckt = NULL; 771 772 #define exp_hash_link(exi, hash_name, bucket) \ 773 (exi)->hash_name.bckt = (bucket); \ 774 (exi)->hash_name.prev = NULL; \ 775 (exi)->hash_name.next = *(bucket); \ 776 if ((exi)->hash_name.next) \ 777 (exi)->hash_name.next->hash_name.prev = (exi); \ 778 *(bucket) = (exi); 779 780 void 781 export_link(exportinfo_t *exi) 782 { 783 exportinfo_t **bckt; 784 785 bckt = &exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)]; 786 exp_hash_link(exi, fid_hash, bckt); 787 788 bckt = &exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path, 789 strlen(exi->exi_export.ex_path))]; 790 exp_hash_link(exi, path_hash, bckt); 791 } 792 793 /* 794 * Initialization routine for export routines. Should only be called once. 795 */ 796 int 797 nfs_exportinit(void) 798 { 799 int error; 800 801 rw_init(&exported_lock, NULL, RW_DEFAULT, NULL); 802 803 /* 804 * Allocate the place holder for the public file handle, which 805 * is all zeroes. It is initially set to the root filesystem. 806 */ 807 exi_root = kmem_zalloc(sizeof (*exi_root), KM_SLEEP); 808 exi_public = exi_root; 809 810 exi_root->exi_export.ex_flags = EX_PUBLIC; 811 exi_root->exi_export.ex_pathlen = 1; /* length of "/" */ 812 exi_root->exi_export.ex_path = 813 kmem_alloc(exi_root->exi_export.ex_pathlen + 1, KM_SLEEP); 814 exi_root->exi_export.ex_path[0] = '/'; 815 exi_root->exi_export.ex_path[1] = '\0'; 816 817 exi_root->exi_count = 1; 818 mutex_init(&exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL); 819 820 exi_root->exi_vp = rootdir; 821 exi_rootfid.fid_len = MAXFIDSZ; 822 error = vop_fid_pseudo(exi_root->exi_vp, &exi_rootfid); 823 if (error) { 824 mutex_destroy(&exi_root->exi_lock); 825 kmem_free(exi_root, sizeof (*exi_root)); 826 return (error); 827 } 828 829 /* setup the fhandle template */ 830 exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid; 831 exi_root->exi_fh.fh_xlen = exi_rootfid.fid_len; 832 bcopy(exi_rootfid.fid_data, exi_root->exi_fh.fh_xdata, 833 exi_rootfid.fid_len); 834 exi_root->exi_fh.fh_len = sizeof (exi_root->exi_fh.fh_data); 835 836 /* 837 * Publish the exportinfo in the hash table 838 */ 839 export_link(exi_root); 840 841 nfslog_init(); 842 ns_root = NULL; 843 844 return (0); 845 } 846 847 /* 848 * Finalization routine for export routines. Called to cleanup previously 849 * initialization work when the NFS server module could not be loaded correctly. 850 */ 851 void 852 nfs_exportfini(void) 853 { 854 /* 855 * Deallocate the place holder for the public file handle. 856 */ 857 srv_secinfo_list_free(exi_root->exi_export.ex_secinfo, 858 exi_root->exi_export.ex_seccnt); 859 mutex_destroy(&exi_root->exi_lock); 860 kmem_free(exi_root, sizeof (*exi_root)); 861 862 rw_destroy(&exported_lock); 863 } 864 865 /* 866 * Check if 2 gss mechanism identifiers are the same. 867 * 868 * return FALSE if not the same. 869 * return TRUE if the same. 870 */ 871 static bool_t 872 nfs_mech_equal(rpc_gss_OID mech1, rpc_gss_OID mech2) 873 { 874 if ((mech1->length == 0) && (mech2->length == 0)) 875 return (TRUE); 876 877 if (mech1->length != mech2->length) 878 return (FALSE); 879 880 return (bcmp(mech1->elements, mech2->elements, mech1->length) == 0); 881 } 882 883 /* 884 * This routine is used by rpc to map rpc security number 885 * to nfs specific security flavor number. 886 * 887 * The gss callback prototype is 888 * callback(struct svc_req *, gss_cred_id_t *, gss_ctx_id_t *, 889 * rpc_gss_lock_t *, void **), 890 * since nfs does not use the gss_cred_id_t/gss_ctx_id_t arguments 891 * we cast them to void. 892 */ 893 /*ARGSUSED*/ 894 bool_t 895 rfs_gsscallback(struct svc_req *req, gss_cred_id_t deleg, void *gss_context, 896 rpc_gss_lock_t *lock, void **cookie) 897 { 898 int i, j; 899 rpc_gss_rawcred_t *raw_cred; 900 struct exportinfo *exi; 901 902 /* 903 * We don't deal with delegated credentials. 904 */ 905 if (deleg != GSS_C_NO_CREDENTIAL) 906 return (FALSE); 907 908 raw_cred = lock->raw_cred; 909 *cookie = NULL; 910 911 rw_enter(&exported_lock, RW_READER); 912 for (i = 0; i < EXPTABLESIZE; i++) { 913 exi = exptable[i]; 914 while (exi) { 915 if (exi->exi_export.ex_seccnt > 0) { 916 struct secinfo *secp; 917 seconfig_t *se; 918 int seccnt; 919 920 secp = exi->exi_export.ex_secinfo; 921 seccnt = exi->exi_export.ex_seccnt; 922 for (j = 0; j < seccnt; j++) { 923 /* 924 * If there is a map of the triplet 925 * (mechanism, service, qop) between 926 * raw_cred and the exported flavor, 927 * get the psudo flavor number. 928 * Also qop should not be NULL, it 929 * should be "default" or something 930 * else. 931 */ 932 se = &secp[j].s_secinfo; 933 if ((se->sc_rpcnum == RPCSEC_GSS) && 934 935 (nfs_mech_equal( 936 se->sc_gss_mech_type, 937 raw_cred->mechanism)) && 938 939 (se->sc_service == 940 raw_cred->service) && 941 (raw_cred->qop == se->sc_qop)) { 942 943 *cookie = (void *)(uintptr_t) 944 se->sc_nfsnum; 945 goto done; 946 } 947 } 948 } 949 exi = exi->fid_hash.next; 950 } 951 } 952 done: 953 rw_exit(&exported_lock); 954 955 /* 956 * If no nfs pseudo number mapping can be found in the export 957 * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may 958 * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC). 959 * 960 * For example: 961 * server first shares with krb5i; 962 * client mounts with krb5i; 963 * server re-shares with krb5p; 964 * client tries with krb5i, but no mapping can be found; 965 * rpcsec_gss module calls this routine to do the mapping, 966 * if this routine fails, request is rejected from 967 * the rpc layer. 968 * What we need is to let the nfs layer rejects the request. 969 * For V4, we can reject with NFS4ERR_WRONGSEC and the client 970 * may recover from it by getting the new flavor via SECINFO. 971 * 972 * nfs pseudo number for RPCSEC_GSS mapping (see nfssec.conf) 973 * is owned by IANA (see RFC 2623). 974 * 975 * XXX NFS_FLAVOR_NOMAP is defined in Solaris to work around 976 * the implementation issue. This number should not overlap with 977 * any new IANA defined pseudo flavor numbers. 978 */ 979 if (*cookie == NULL) 980 *cookie = (void *)NFS_FLAVOR_NOMAP; 981 982 lock->locked = TRUE; 983 984 return (TRUE); 985 } 986 987 988 /* 989 * Exportfs system call; credentials should be checked before 990 * calling this function. 991 */ 992 int 993 exportfs(struct exportfs_args *args, model_t model, cred_t *cr) 994 { 995 vnode_t *vp; 996 vnode_t *dvp; 997 struct exportdata *kex; 998 struct exportinfo *exi = NULL; 999 struct exportinfo *ex, *ex1, *ex2; 1000 fid_t fid; 1001 fsid_t fsid; 1002 int error; 1003 size_t allocsize; 1004 struct secinfo *sp; 1005 struct secinfo *exs; 1006 rpc_gss_callback_t cb; 1007 char *pathbuf; 1008 char *log_buffer; 1009 char *tagbuf; 1010 int callback; 1011 int allocd_seccnt; 1012 STRUCT_HANDLE(exportfs_args, uap); 1013 STRUCT_DECL(exportdata, uexi); 1014 struct secinfo newsec[MAX_FLAVORS]; 1015 int newcnt; 1016 struct secinfo oldsec[MAX_FLAVORS]; 1017 int oldcnt; 1018 int i; 1019 struct pathname lookpn; 1020 1021 STRUCT_SET_HANDLE(uap, model, args); 1022 1023 /* Read in pathname from userspace */ 1024 if (error = pn_get(STRUCT_FGETP(uap, dname), UIO_USERSPACE, &lookpn)) 1025 return (error); 1026 1027 /* Walk the export list looking for that pathname */ 1028 rw_enter(&exported_lock, RW_READER); 1029 DTRACE_PROBE(nfss__i__exported_lock1_start); 1030 for (ex1 = exptable_path_hash[pkp_tab_hash(lookpn.pn_path, 1031 strlen(lookpn.pn_path))]; ex1; ex1 = ex1->path_hash.next) { 1032 if (ex1 != exi_root && 0 == 1033 strcmp(ex1->exi_export.ex_path, lookpn.pn_path)) { 1034 exi_hold(ex1); 1035 break; 1036 } 1037 } 1038 DTRACE_PROBE(nfss__i__exported_lock1_stop); 1039 rw_exit(&exported_lock); 1040 1041 /* Is this an unshare? */ 1042 if (STRUCT_FGETP(uap, uex) == NULL) { 1043 pn_free(&lookpn); 1044 if (ex1 == NULL) 1045 return (EINVAL); 1046 error = unexport(ex1); 1047 exi_rele(ex1); 1048 return (error); 1049 } 1050 1051 /* It is a share or a re-share */ 1052 error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE, 1053 FOLLOW, &dvp, &vp); 1054 if (error == EINVAL) { 1055 /* 1056 * if fname resolves to / we get EINVAL error 1057 * since we wanted the parent vnode. Try again 1058 * with NULL dvp. 1059 */ 1060 error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE, 1061 FOLLOW, NULL, &vp); 1062 dvp = NULL; 1063 } 1064 if (!error && vp == NULL) { 1065 /* Last component of fname not found */ 1066 if (dvp != NULL) 1067 VN_RELE(dvp); 1068 error = ENOENT; 1069 } 1070 if (error) { 1071 pn_free(&lookpn); 1072 if (ex1) 1073 exi_rele(ex1); 1074 return (error); 1075 } 1076 1077 /* 1078 * 'vp' may be an AUTOFS node, so we perform a 1079 * VOP_ACCESS() to trigger the mount of the 1080 * intended filesystem, so we can share the intended 1081 * filesystem instead of the AUTOFS filesystem. 1082 */ 1083 (void) VOP_ACCESS(vp, 0, 0, cr, NULL); 1084 1085 /* 1086 * We're interested in the top most filesystem. 1087 * This is specially important when uap->dname is a trigger 1088 * AUTOFS node, since we're really interested in sharing the 1089 * filesystem AUTOFS mounted as result of the VOP_ACCESS() 1090 * call not the AUTOFS node itself. 1091 */ 1092 if (vn_mountedvfs(vp) != NULL) { 1093 if (error = traverse(&vp)) { 1094 VN_RELE(vp); 1095 if (dvp != NULL) 1096 VN_RELE(dvp); 1097 pn_free(&lookpn); 1098 if (ex1) 1099 exi_rele(ex1); 1100 return (error); 1101 } 1102 } 1103 1104 /* Do not allow sharing another vnode for already shared path */ 1105 if (ex1 && !PSEUDO(ex1) && !VN_CMP(ex1->exi_vp, vp)) { 1106 VN_RELE(vp); 1107 if (dvp != NULL) 1108 VN_RELE(dvp); 1109 pn_free(&lookpn); 1110 exi_rele(ex1); 1111 return (EEXIST); 1112 } 1113 if (ex1) 1114 exi_rele(ex1); 1115 1116 /* 1117 * Get the vfs id 1118 */ 1119 bzero(&fid, sizeof (fid)); 1120 fid.fid_len = MAXFIDSZ; 1121 error = VOP_FID(vp, &fid, NULL); 1122 fsid = vp->v_vfsp->vfs_fsid; 1123 1124 if (error) { 1125 VN_RELE(vp); 1126 if (dvp != NULL) 1127 VN_RELE(dvp); 1128 /* 1129 * If VOP_FID returns ENOSPC then the fid supplied 1130 * is too small. For now we simply return EREMOTE. 1131 */ 1132 if (error == ENOSPC) 1133 error = EREMOTE; 1134 pn_free(&lookpn); 1135 return (error); 1136 } 1137 1138 /* 1139 * Do not allow re-sharing a shared vnode under a different path 1140 * PSEUDO export has ex_path fabricated, e.g. "/tmp (pseudo)", skip it. 1141 */ 1142 rw_enter(&exported_lock, RW_READER); 1143 DTRACE_PROBE(nfss__i__exported_lock2_start); 1144 for (ex2 = exptable[exptablehash(&fsid, &fid)]; ex2; 1145 ex2 = ex2->fid_hash.next) { 1146 if (ex2 != exi_root && !PSEUDO(ex2) && 1147 VN_CMP(ex2->exi_vp, vp) && 1148 strcmp(ex2->exi_export.ex_path, lookpn.pn_path) != 0) { 1149 DTRACE_PROBE(nfss__i__exported_lock2_stop); 1150 rw_exit(&exported_lock); 1151 VN_RELE(vp); 1152 if (dvp != NULL) 1153 VN_RELE(dvp); 1154 pn_free(&lookpn); 1155 return (EEXIST); 1156 } 1157 } 1158 DTRACE_PROBE(nfss__i__exported_lock2_stop); 1159 rw_exit(&exported_lock); 1160 pn_free(&lookpn); 1161 1162 exi = kmem_zalloc(sizeof (*exi), KM_SLEEP); 1163 exi->exi_fsid = fsid; 1164 exi->exi_fid = fid; 1165 exi->exi_vp = vp; 1166 exi->exi_count = 1; 1167 exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag & 1168 VSW_VOLATILEDEV) ? 1 : 0; 1169 mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL); 1170 exi->exi_dvp = dvp; 1171 1172 /* 1173 * Initialize auth cache lock 1174 */ 1175 rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL); 1176 1177 /* 1178 * Build up the template fhandle 1179 */ 1180 exi->exi_fh.fh_fsid = fsid; 1181 if (exi->exi_fid.fid_len > sizeof (exi->exi_fh.fh_xdata)) { 1182 error = EREMOTE; 1183 goto out1; 1184 } 1185 exi->exi_fh.fh_xlen = exi->exi_fid.fid_len; 1186 bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata, 1187 exi->exi_fid.fid_len); 1188 1189 exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data); 1190 1191 kex = &exi->exi_export; 1192 1193 /* 1194 * Load in everything, and do sanity checking 1195 */ 1196 STRUCT_INIT(uexi, model); 1197 if (copyin(STRUCT_FGETP(uap, uex), STRUCT_BUF(uexi), 1198 STRUCT_SIZE(uexi))) { 1199 error = EFAULT; 1200 goto out1; 1201 } 1202 1203 kex->ex_version = STRUCT_FGET(uexi, ex_version); 1204 if (kex->ex_version != EX_CURRENT_VERSION) { 1205 error = EINVAL; 1206 cmn_err(CE_WARN, 1207 "NFS: exportfs requires export struct version 2 - got %d\n", 1208 kex->ex_version); 1209 goto out1; 1210 } 1211 1212 /* 1213 * Must have at least one security entry 1214 */ 1215 kex->ex_seccnt = STRUCT_FGET(uexi, ex_seccnt); 1216 if (kex->ex_seccnt < 1) { 1217 error = EINVAL; 1218 goto out1; 1219 } 1220 1221 kex->ex_path = STRUCT_FGETP(uexi, ex_path); 1222 kex->ex_pathlen = STRUCT_FGET(uexi, ex_pathlen); 1223 kex->ex_flags = STRUCT_FGET(uexi, ex_flags); 1224 kex->ex_anon = STRUCT_FGET(uexi, ex_anon); 1225 kex->ex_secinfo = STRUCT_FGETP(uexi, ex_secinfo); 1226 kex->ex_index = STRUCT_FGETP(uexi, ex_index); 1227 kex->ex_log_buffer = STRUCT_FGETP(uexi, ex_log_buffer); 1228 kex->ex_log_bufferlen = STRUCT_FGET(uexi, ex_log_bufferlen); 1229 kex->ex_tag = STRUCT_FGETP(uexi, ex_tag); 1230 kex->ex_taglen = STRUCT_FGET(uexi, ex_taglen); 1231 1232 /* 1233 * Copy the exported pathname into 1234 * an appropriately sized buffer. 1235 */ 1236 pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1237 if (copyinstr(kex->ex_path, pathbuf, MAXPATHLEN, &kex->ex_pathlen)) { 1238 kmem_free(pathbuf, MAXPATHLEN); 1239 error = EFAULT; 1240 goto out1; 1241 } 1242 kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP); 1243 bcopy(pathbuf, kex->ex_path, kex->ex_pathlen); 1244 kex->ex_path[kex->ex_pathlen] = '\0'; 1245 kmem_free(pathbuf, MAXPATHLEN); 1246 1247 /* 1248 * Get the path to the logging buffer and the tag 1249 */ 1250 if (kex->ex_flags & EX_LOG) { 1251 log_buffer = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1252 if (copyinstr(kex->ex_log_buffer, log_buffer, MAXPATHLEN, 1253 &kex->ex_log_bufferlen)) { 1254 kmem_free(log_buffer, MAXPATHLEN); 1255 error = EFAULT; 1256 goto out2; 1257 } 1258 kex->ex_log_buffer = 1259 kmem_alloc(kex->ex_log_bufferlen + 1, KM_SLEEP); 1260 bcopy(log_buffer, kex->ex_log_buffer, kex->ex_log_bufferlen); 1261 kex->ex_log_buffer[kex->ex_log_bufferlen] = '\0'; 1262 kmem_free(log_buffer, MAXPATHLEN); 1263 1264 tagbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1265 if (copyinstr(kex->ex_tag, tagbuf, MAXPATHLEN, 1266 &kex->ex_taglen)) { 1267 kmem_free(tagbuf, MAXPATHLEN); 1268 error = EFAULT; 1269 goto out3; 1270 } 1271 kex->ex_tag = kmem_alloc(kex->ex_taglen + 1, KM_SLEEP); 1272 bcopy(tagbuf, kex->ex_tag, kex->ex_taglen); 1273 kex->ex_tag[kex->ex_taglen] = '\0'; 1274 kmem_free(tagbuf, MAXPATHLEN); 1275 } 1276 1277 /* 1278 * Load the security information for each flavor 1279 */ 1280 allocsize = kex->ex_seccnt * SIZEOF_STRUCT(secinfo, model); 1281 sp = kmem_zalloc(allocsize, KM_SLEEP); 1282 if (copyin(kex->ex_secinfo, sp, allocsize)) { 1283 kmem_free(sp, allocsize); 1284 error = EFAULT; 1285 goto out4; 1286 } 1287 1288 /* 1289 * All of these nested structures need to be converted to 1290 * the kernel native format. 1291 */ 1292 if (model != DATAMODEL_NATIVE) { 1293 size_t allocsize2; 1294 struct secinfo *sp2; 1295 1296 allocsize2 = kex->ex_seccnt * sizeof (struct secinfo); 1297 sp2 = kmem_zalloc(allocsize2, KM_SLEEP); 1298 1299 for (i = 0; i < kex->ex_seccnt; i++) { 1300 STRUCT_HANDLE(secinfo, usi); 1301 1302 STRUCT_SET_HANDLE(usi, model, 1303 (struct secinfo *)((caddr_t)sp + 1304 (i * SIZEOF_STRUCT(secinfo, model)))); 1305 bcopy(STRUCT_FGET(usi, s_secinfo.sc_name), 1306 sp2[i].s_secinfo.sc_name, MAX_NAME_LEN); 1307 sp2[i].s_secinfo.sc_nfsnum = 1308 STRUCT_FGET(usi, s_secinfo.sc_nfsnum); 1309 sp2[i].s_secinfo.sc_rpcnum = 1310 STRUCT_FGET(usi, s_secinfo.sc_rpcnum); 1311 bcopy(STRUCT_FGET(usi, s_secinfo.sc_gss_mech), 1312 sp2[i].s_secinfo.sc_gss_mech, MAX_NAME_LEN); 1313 sp2[i].s_secinfo.sc_gss_mech_type = 1314 STRUCT_FGETP(usi, s_secinfo.sc_gss_mech_type); 1315 sp2[i].s_secinfo.sc_qop = 1316 STRUCT_FGET(usi, s_secinfo.sc_qop); 1317 sp2[i].s_secinfo.sc_service = 1318 STRUCT_FGET(usi, s_secinfo.sc_service); 1319 1320 sp2[i].s_flags = STRUCT_FGET(usi, s_flags); 1321 sp2[i].s_window = STRUCT_FGET(usi, s_window); 1322 sp2[i].s_rootid = STRUCT_FGET(usi, s_rootid); 1323 sp2[i].s_rootcnt = STRUCT_FGET(usi, s_rootcnt); 1324 sp2[i].s_rootnames = STRUCT_FGETP(usi, s_rootnames); 1325 } 1326 kmem_free(sp, allocsize); 1327 sp = sp2; 1328 allocsize = allocsize2; 1329 } 1330 1331 kex->ex_secinfo = sp; 1332 1333 /* 1334 * And now copy rootnames for each individual secinfo. 1335 */ 1336 callback = 0; 1337 allocd_seccnt = 0; 1338 while (allocd_seccnt < kex->ex_seccnt) { 1339 1340 exs = &sp[allocd_seccnt]; 1341 if (exs->s_rootcnt > 0) { 1342 if (!sec_svc_loadrootnames(exs->s_secinfo.sc_rpcnum, 1343 exs->s_rootcnt, &exs->s_rootnames, model)) { 1344 error = EFAULT; 1345 goto out5; 1346 } 1347 } 1348 1349 if (exs->s_secinfo.sc_rpcnum == RPCSEC_GSS) { 1350 rpc_gss_OID mech_tmp; 1351 STRUCT_DECL(rpc_gss_OID_s, umech_tmp); 1352 caddr_t elements_tmp; 1353 1354 /* Copyin mechanism type */ 1355 STRUCT_INIT(umech_tmp, model); 1356 mech_tmp = kmem_alloc(sizeof (*mech_tmp), KM_SLEEP); 1357 if (copyin(exs->s_secinfo.sc_gss_mech_type, 1358 STRUCT_BUF(umech_tmp), STRUCT_SIZE(umech_tmp))) { 1359 kmem_free(mech_tmp, sizeof (*mech_tmp)); 1360 error = EFAULT; 1361 goto out5; 1362 } 1363 mech_tmp->length = STRUCT_FGET(umech_tmp, length); 1364 mech_tmp->elements = STRUCT_FGETP(umech_tmp, elements); 1365 1366 elements_tmp = kmem_alloc(mech_tmp->length, KM_SLEEP); 1367 if (copyin(mech_tmp->elements, elements_tmp, 1368 mech_tmp->length)) { 1369 kmem_free(elements_tmp, mech_tmp->length); 1370 kmem_free(mech_tmp, sizeof (*mech_tmp)); 1371 error = EFAULT; 1372 goto out5; 1373 } 1374 mech_tmp->elements = elements_tmp; 1375 exs->s_secinfo.sc_gss_mech_type = mech_tmp; 1376 allocd_seccnt++; 1377 1378 callback = 1; 1379 } else 1380 allocd_seccnt++; 1381 } 1382 1383 /* 1384 * Init the secinfo reference count and mark these flavors 1385 * explicitly exported flavors. 1386 */ 1387 for (i = 0; i < kex->ex_seccnt; i++) { 1388 kex->ex_secinfo[i].s_flags |= M_4SEC_EXPORTED; 1389 kex->ex_secinfo[i].s_refcnt = 1; 1390 } 1391 1392 /* 1393 * Set up rpcsec_gss callback routine entry if any. 1394 */ 1395 if (callback) { 1396 cb.callback = rfs_gsscallback; 1397 cb.program = NFS_ACL_PROGRAM; 1398 for (cb.version = NFS_ACL_VERSMIN; 1399 cb.version <= NFS_ACL_VERSMAX; cb.version++) { 1400 (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK, 1401 (void *)&cb); 1402 } 1403 1404 cb.program = NFS_PROGRAM; 1405 for (cb.version = NFS_VERSMIN; 1406 cb.version <= NFS_VERSMAX; cb.version++) { 1407 (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK, 1408 (void *)&cb); 1409 } 1410 } 1411 1412 /* 1413 * Check the index flag. Do this here to avoid holding the 1414 * lock while dealing with the index option (as we do with 1415 * the public option). 1416 */ 1417 if (kex->ex_flags & EX_INDEX) { 1418 if (!kex->ex_index) { /* sanity check */ 1419 error = EINVAL; 1420 goto out5; 1421 } 1422 if (error = loadindex(kex)) 1423 goto out5; 1424 } 1425 1426 if (kex->ex_flags & EX_LOG) { 1427 if (error = nfslog_setup(exi)) 1428 goto out6; 1429 } 1430 1431 /* 1432 * Insert the new entry at the front of the export list 1433 */ 1434 rw_enter(&exported_lock, RW_WRITER); 1435 DTRACE_PROBE(nfss__i__exported_lock3_start); 1436 1437 export_link(exi); 1438 1439 /* 1440 * Check the rest of the list for an old entry for the fs. 1441 * If one is found then unlink it, wait until this is the 1442 * only reference and then free it. 1443 */ 1444 for (ex = exi->fid_hash.next; ex != NULL; ex = ex->fid_hash.next) { 1445 if (ex != exi_root && VN_CMP(ex->exi_vp, vp)) { 1446 export_unlink(ex); 1447 break; 1448 } 1449 } 1450 1451 /* 1452 * If the public filehandle is pointing at the 1453 * old entry, then point it back at the root. 1454 */ 1455 if (ex != NULL && ex == exi_public) 1456 exi_public = exi_root; 1457 1458 /* 1459 * If the public flag is on, make the global exi_public 1460 * point to this entry and turn off the public bit so that 1461 * we can distinguish it from the place holder export. 1462 */ 1463 if (kex->ex_flags & EX_PUBLIC) { 1464 exi_public = exi; 1465 kex->ex_flags &= ~EX_PUBLIC; 1466 } 1467 1468 #ifdef VOLATILE_FH_TEST 1469 /* 1470 * Set up the volatile_id value if volatile on share. 1471 * The list of volatile renamed filehandles is always destroyed, 1472 * if the fs was reshared. 1473 */ 1474 if (kex->ex_flags & EX_VOLFH) 1475 exi->exi_volatile_id = gethrestime_sec(); 1476 1477 mutex_init(&exi->exi_vol_rename_lock, NULL, MUTEX_DEFAULT, NULL); 1478 #endif /* VOLATILE_FH_TEST */ 1479 1480 /* 1481 * If this is a new export, then climb up 1482 * the tree and check if any pseudo exports 1483 * need to be created to provide a path for 1484 * NFS v4 clients. 1485 */ 1486 if (ex == NULL) { 1487 error = treeclimb_export(exi); 1488 if (error) 1489 goto out7; 1490 } else { 1491 /* If it's a re-export update namespace tree */ 1492 exi->exi_tree = ex->exi_tree; 1493 exi->exi_tree->tree_exi = exi; 1494 } 1495 1496 /* 1497 * build a unique flavor list from the flavors specified 1498 * in the share cmd. unique means that each flavor only 1499 * appears once in the secinfo list -- no duplicates allowed. 1500 */ 1501 newcnt = build_seclist_nodups(&exi->exi_export, newsec, FALSE); 1502 1503 srv_secinfo_treeclimb(exi, newsec, newcnt, TRUE); 1504 1505 /* 1506 * If re-sharing an old export entry, update the secinfo data 1507 * depending on if the old entry is a pseudo node or not. 1508 */ 1509 if (ex != NULL) { 1510 oldcnt = build_seclist_nodups(&ex->exi_export, oldsec, FALSE); 1511 if (PSEUDO(ex)) { 1512 /* 1513 * The dir being shared is a pseudo export root (which 1514 * will be transformed into a real export root). The 1515 * flavor(s) of the new share were propagated to the 1516 * ancestors by srv_secinfo_treeclimb() above. Now 1517 * transfer the implicit flavor refs from the old 1518 * pseudo exprot root to the new (real) export root. 1519 */ 1520 srv_secinfo_add(&exi->exi_export.ex_secinfo, 1521 &exi->exi_export.ex_seccnt, oldsec, oldcnt, TRUE); 1522 } else { 1523 /* 1524 * First transfer implicit flavor refs to new export. 1525 * Remove old flavor refs last. 1526 */ 1527 srv_secinfo_exp2exp(&exi->exi_export, oldsec, oldcnt); 1528 srv_secinfo_treeclimb(ex, oldsec, oldcnt, FALSE); 1529 } 1530 } 1531 1532 /* 1533 * If it's a re-export and the old entry has a pseudonode list, 1534 * transfer it to the new export. 1535 */ 1536 if (ex != NULL && (ex->exi_visible != NULL)) { 1537 exi->exi_visible = ex->exi_visible; 1538 ex->exi_visible = NULL; 1539 } 1540 1541 DTRACE_PROBE(nfss__i__exported_lock3_stop); 1542 rw_exit(&exported_lock); 1543 1544 if (exi_public == exi || kex->ex_flags & EX_LOG) { 1545 /* 1546 * Log share operation to this buffer only. 1547 */ 1548 nfslog_share_record(exi, cr); 1549 } 1550 1551 if (ex != NULL) 1552 exi_rele(ex); 1553 1554 return (0); 1555 1556 out7: 1557 /* Unlink the new export in exptable. */ 1558 export_unlink(exi); 1559 DTRACE_PROBE(nfss__i__exported_lock3_stop); 1560 rw_exit(&exported_lock); 1561 out6: 1562 if (kex->ex_flags & EX_INDEX) 1563 kmem_free(kex->ex_index, strlen(kex->ex_index) + 1); 1564 out5: 1565 /* free partially completed allocation */ 1566 while (--allocd_seccnt >= 0) { 1567 exs = &kex->ex_secinfo[allocd_seccnt]; 1568 srv_secinfo_entry_free(exs); 1569 } 1570 1571 if (kex->ex_secinfo) { 1572 kmem_free(kex->ex_secinfo, 1573 kex->ex_seccnt * sizeof (struct secinfo)); 1574 } 1575 1576 out4: 1577 if ((kex->ex_flags & EX_LOG) && kex->ex_tag != NULL) 1578 kmem_free(kex->ex_tag, kex->ex_taglen + 1); 1579 out3: 1580 if ((kex->ex_flags & EX_LOG) && kex->ex_log_buffer != NULL) 1581 kmem_free(kex->ex_log_buffer, kex->ex_log_bufferlen + 1); 1582 out2: 1583 kmem_free(kex->ex_path, kex->ex_pathlen + 1); 1584 out1: 1585 VN_RELE(vp); 1586 if (dvp != NULL) 1587 VN_RELE(dvp); 1588 mutex_destroy(&exi->exi_lock); 1589 rw_destroy(&exi->exi_cache_lock); 1590 kmem_free(exi, sizeof (*exi)); 1591 return (error); 1592 } 1593 1594 /* 1595 * Remove the exportinfo from the export list 1596 */ 1597 void 1598 export_unlink(struct exportinfo *exi) 1599 { 1600 ASSERT(RW_WRITE_HELD(&exported_lock)); 1601 1602 exp_hash_unlink(exi, fid_hash); 1603 exp_hash_unlink(exi, path_hash); 1604 } 1605 1606 /* 1607 * Unexport an exported filesystem 1608 */ 1609 static int 1610 unexport(struct exportinfo *exi) 1611 { 1612 struct secinfo cursec[MAX_FLAVORS]; 1613 int curcnt; 1614 1615 rw_enter(&exported_lock, RW_WRITER); 1616 1617 /* Check if exi is still linked in the export table */ 1618 if (!EXP_LINKED(exi) || PSEUDO(exi)) { 1619 rw_exit(&exported_lock); 1620 return (EINVAL); 1621 } 1622 1623 export_unlink(exi); 1624 1625 /* 1626 * Remove security flavors before treeclimb_unexport() is called 1627 * because srv_secinfo_treeclimb needs the namespace tree 1628 */ 1629 curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE); 1630 1631 srv_secinfo_treeclimb(exi, cursec, curcnt, FALSE); 1632 1633 /* 1634 * If there's a visible list, then need to leave 1635 * a pseudo export here to retain the visible list 1636 * for paths to exports below. 1637 */ 1638 if (exi->exi_visible) { 1639 struct exportinfo *newexi; 1640 1641 newexi = pseudo_exportfs(exi->exi_vp, &exi->exi_fid, 1642 exi->exi_visible, &exi->exi_export); 1643 exi->exi_visible = NULL; 1644 1645 /* interconnect the existing treenode with the new exportinfo */ 1646 newexi->exi_tree = exi->exi_tree; 1647 newexi->exi_tree->tree_exi = newexi; 1648 } else { 1649 treeclimb_unexport(exi); 1650 } 1651 1652 rw_exit(&exported_lock); 1653 1654 /* 1655 * Need to call into the NFSv4 server and release all data 1656 * held on this particular export. This is important since 1657 * the v4 server may be holding file locks or vnodes under 1658 * this export. 1659 */ 1660 rfs4_clean_state_exi(exi); 1661 1662 /* 1663 * Notify the lock manager that the filesystem is being 1664 * unexported. 1665 */ 1666 lm_unexport(exi); 1667 1668 /* 1669 * If this was a public export, restore 1670 * the public filehandle to the root. 1671 */ 1672 if (exi == exi_public) { 1673 exi_public = exi_root; 1674 1675 nfslog_share_record(exi_public, CRED()); 1676 } 1677 1678 if (exi->exi_export.ex_flags & EX_LOG) { 1679 nfslog_unshare_record(exi, CRED()); 1680 } 1681 1682 exi_rele(exi); 1683 return (0); 1684 } 1685 1686 /* 1687 * Get file handle system call. 1688 * Takes file name and returns a file handle for it. 1689 * Credentials must be verified before calling. 1690 */ 1691 int 1692 nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr) 1693 { 1694 nfs_fh3 fh; 1695 char buf[NFS3_MAXFHSIZE]; 1696 char *logptr, logbuf[NFS3_MAXFHSIZE]; 1697 int l = NFS3_MAXFHSIZE; 1698 vnode_t *vp; 1699 vnode_t *dvp; 1700 struct exportinfo *exi; 1701 int error; 1702 int vers; 1703 STRUCT_HANDLE(nfs_getfh_args, uap); 1704 1705 #ifdef lint 1706 model = model; /* STRUCT macros don't always use it */ 1707 #endif 1708 1709 STRUCT_SET_HANDLE(uap, model, args); 1710 1711 error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE, 1712 FOLLOW, &dvp, &vp); 1713 if (error == EINVAL) { 1714 /* 1715 * if fname resolves to / we get EINVAL error 1716 * since we wanted the parent vnode. Try again 1717 * with NULL dvp. 1718 */ 1719 error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE, 1720 FOLLOW, NULL, &vp); 1721 dvp = NULL; 1722 } 1723 if (!error && vp == NULL) { 1724 /* 1725 * Last component of fname not found 1726 */ 1727 if (dvp != NULL) { 1728 VN_RELE(dvp); 1729 } 1730 error = ENOENT; 1731 } 1732 if (error) 1733 return (error); 1734 1735 /* 1736 * 'vp' may be an AUTOFS node, so we perform a 1737 * VOP_ACCESS() to trigger the mount of the 1738 * intended filesystem, so we can share the intended 1739 * filesystem instead of the AUTOFS filesystem. 1740 */ 1741 (void) VOP_ACCESS(vp, 0, 0, cr, NULL); 1742 1743 /* 1744 * We're interested in the top most filesystem. 1745 * This is specially important when uap->dname is a trigger 1746 * AUTOFS node, since we're really interested in sharing the 1747 * filesystem AUTOFS mounted as result of the VOP_ACCESS() 1748 * call not the AUTOFS node itself. 1749 */ 1750 if (vn_mountedvfs(vp) != NULL) { 1751 if (error = traverse(&vp)) { 1752 VN_RELE(vp); 1753 if (dvp != NULL) 1754 VN_RELE(dvp); 1755 return (error); 1756 } 1757 } 1758 1759 vers = STRUCT_FGET(uap, vers); 1760 exi = nfs_vptoexi(dvp, vp, cr, NULL, &error, FALSE); 1761 if (!error) { 1762 if (vers == NFS_VERSION) { 1763 error = makefh((fhandle_t *)buf, vp, exi); 1764 l = NFS_FHSIZE; 1765 logptr = buf; 1766 } else if (vers == NFS_V3) { 1767 int i, sz, pad; 1768 1769 error = makefh3(&fh, vp, exi); 1770 l = RNDUP(fh.fh3_length); 1771 if (!error && (l > sizeof (fhandle3_t))) 1772 error = EREMOTE; 1773 logptr = logbuf; 1774 if (!error) { 1775 i = 0; 1776 sz = sizeof (fsid_t); 1777 bcopy(&fh.fh3_fsid, &buf[i], sz); 1778 i += sz; 1779 1780 /* 1781 * For backwards compatibility, the 1782 * fid length may be less than 1783 * NFS_FHMAXDATA, but it was always 1784 * encoded as NFS_FHMAXDATA bytes. 1785 */ 1786 1787 sz = sizeof (ushort_t); 1788 bcopy(&fh.fh3_len, &buf[i], sz); 1789 i += sz; 1790 bcopy(fh.fh3_data, &buf[i], fh.fh3_len); 1791 i += fh.fh3_len; 1792 pad = (NFS_FHMAXDATA - fh.fh3_len); 1793 if (pad > 0) { 1794 bzero(&buf[i], pad); 1795 i += pad; 1796 l += pad; 1797 } 1798 1799 sz = sizeof (ushort_t); 1800 bcopy(&fh.fh3_xlen, &buf[i], sz); 1801 i += sz; 1802 bcopy(fh.fh3_xdata, &buf[i], fh.fh3_xlen); 1803 i += fh.fh3_xlen; 1804 pad = (NFS_FHMAXDATA - fh.fh3_xlen); 1805 if (pad > 0) { 1806 bzero(&buf[i], pad); 1807 i += pad; 1808 l += pad; 1809 } 1810 } 1811 /* 1812 * If we need to do NFS logging, the filehandle 1813 * must be downsized to 32 bytes. 1814 */ 1815 if (!error && exi->exi_export.ex_flags & EX_LOG) { 1816 i = 0; 1817 sz = sizeof (fsid_t); 1818 bcopy(&fh.fh3_fsid, &logbuf[i], sz); 1819 i += sz; 1820 sz = sizeof (ushort_t); 1821 bcopy(&fh.fh3_len, &logbuf[i], sz); 1822 i += sz; 1823 sz = NFS_FHMAXDATA; 1824 bcopy(fh.fh3_data, &logbuf[i], sz); 1825 i += sz; 1826 sz = sizeof (ushort_t); 1827 bcopy(&fh.fh3_xlen, &logbuf[i], sz); 1828 i += sz; 1829 sz = NFS_FHMAXDATA; 1830 bcopy(fh.fh3_xdata, &logbuf[i], sz); 1831 i += sz; 1832 } 1833 } 1834 if (!error && exi->exi_export.ex_flags & EX_LOG) { 1835 nfslog_getfh(exi, (fhandle_t *)logptr, 1836 STRUCT_FGETP(uap, fname), UIO_USERSPACE, cr); 1837 } 1838 exi_rele(exi); 1839 if (!error) { 1840 if (copyout(&l, STRUCT_FGETP(uap, lenp), sizeof (int))) 1841 error = EFAULT; 1842 if (copyout(buf, STRUCT_FGETP(uap, fhp), l)) 1843 error = EFAULT; 1844 } 1845 } 1846 VN_RELE(vp); 1847 if (dvp != NULL) { 1848 VN_RELE(dvp); 1849 } 1850 return (error); 1851 } 1852 1853 /* 1854 * Strategy: if vp is in the export list, then 1855 * return the associated file handle. Otherwise, ".." 1856 * once up the vp and try again, until the root of the 1857 * filesystem is reached. 1858 */ 1859 struct exportinfo * 1860 nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk, 1861 int *err, bool_t v4srv) 1862 { 1863 fid_t fid; 1864 int error; 1865 struct exportinfo *exi; 1866 1867 ASSERT(vp); 1868 VN_HOLD(vp); 1869 if (dvp != NULL) { 1870 VN_HOLD(dvp); 1871 } 1872 if (walk != NULL) 1873 *walk = 0; 1874 1875 for (;;) { 1876 bzero(&fid, sizeof (fid)); 1877 fid.fid_len = MAXFIDSZ; 1878 error = vop_fid_pseudo(vp, &fid); 1879 if (error) { 1880 /* 1881 * If vop_fid_pseudo returns ENOSPC then the fid 1882 * supplied is too small. For now we simply 1883 * return EREMOTE. 1884 */ 1885 if (error == ENOSPC) 1886 error = EREMOTE; 1887 break; 1888 } 1889 1890 if (v4srv) 1891 exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); 1892 else 1893 exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid); 1894 1895 if (exi != NULL) { 1896 /* 1897 * Found the export info 1898 */ 1899 break; 1900 } 1901 1902 /* 1903 * We have just failed finding a matching export. 1904 * If we're at the root of this filesystem, then 1905 * it's time to stop (with failure). 1906 */ 1907 if (vp->v_flag & VROOT) { 1908 error = EINVAL; 1909 break; 1910 } 1911 1912 if (walk != NULL) 1913 (*walk)++; 1914 1915 /* 1916 * Now, do a ".." up vp. If dvp is supplied, use it, 1917 * otherwise, look it up. 1918 */ 1919 if (dvp == NULL) { 1920 error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr, 1921 NULL, NULL, NULL); 1922 if (error) 1923 break; 1924 } 1925 VN_RELE(vp); 1926 vp = dvp; 1927 dvp = NULL; 1928 } 1929 VN_RELE(vp); 1930 if (dvp != NULL) { 1931 VN_RELE(dvp); 1932 } 1933 if (error != 0) { 1934 if (err != NULL) 1935 *err = error; 1936 return (NULL); 1937 } 1938 return (exi); 1939 } 1940 1941 int 1942 chk_clnt_sec(exportinfo_t *exi, struct svc_req *req) 1943 { 1944 int i, nfsflavor; 1945 struct secinfo *sp; 1946 1947 /* 1948 * Get the nfs flavor number from xprt. 1949 */ 1950 nfsflavor = (int)(uintptr_t)req->rq_xprt->xp_cookie; 1951 1952 sp = exi->exi_export.ex_secinfo; 1953 for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 1954 if ((nfsflavor == sp[i].s_secinfo.sc_nfsnum) && 1955 SEC_REF_EXPORTED(sp + i)) 1956 return (TRUE); 1957 } 1958 return (FALSE); 1959 } 1960 1961 /* 1962 * Make an fhandle from a vnode 1963 */ 1964 int 1965 makefh(fhandle_t *fh, vnode_t *vp, exportinfo_t *exi) 1966 { 1967 int error; 1968 1969 *fh = exi->exi_fh; /* struct copy */ 1970 1971 error = VOP_FID(vp, (fid_t *)&fh->fh_len, NULL); 1972 if (error) { 1973 /* 1974 * Should be something other than EREMOTE 1975 */ 1976 return (EREMOTE); 1977 } 1978 return (0); 1979 } 1980 1981 /* 1982 * This routine makes an overloaded V2 fhandle which contains 1983 * sec modes. 1984 * 1985 * Note that the first four octets contain the length octet, 1986 * the status octet, and two padded octets to make them XDR 1987 * four-octet aligned. 1988 * 1989 * 1 2 3 4 32 1990 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+ 1991 * | l | s | | | sec_1 |...| sec_n |...| | 1992 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+ 1993 * 1994 * where 1995 * 1996 * the status octet s indicates whether there are more security 1997 * flavors (1 means yes, 0 means no) that require the client to 1998 * perform another 0x81 LOOKUP to get them, 1999 * 2000 * the length octet l is the length describing the number of 2001 * valid octets that follow. (l = 4 * n, where n is the number 2002 * of security flavors sent in the current overloaded filehandle.) 2003 * 2004 * sec_index should always be in the inclusive range: [1 - ex_seccnt], 2005 * and it tells server where to start within the secinfo array. 2006 * Usually it will always be 1; however, if more flavors are used 2007 * for the public export than can be encoded in the overloaded FH 2008 * (7 for NFS2), subsequent SNEGO MCLs will have a larger index 2009 * so the server will pick up where it left off from the previous 2010 * MCL reply. 2011 * 2012 * With NFS4 support, implicitly allowed flavors are also in 2013 * the secinfo array; however, they should not be returned in 2014 * SNEGO MCL replies. 2015 */ 2016 int 2017 makefh_ol(fhandle_t *fh, exportinfo_t *exi, uint_t sec_index) 2018 { 2019 secinfo_t sec[MAX_FLAVORS]; 2020 int totalcnt, i, *ipt, cnt, seccnt, secidx, fh_max_cnt; 2021 char *c; 2022 2023 if (fh == NULL || exi == NULL || sec_index < 1) 2024 return (EREMOTE); 2025 2026 /* 2027 * WebNFS clients need to know the unique set of explicitly 2028 * shared flavors in used for the public export. When 2029 * "TRUE" is passed to build_seclist_nodups(), only explicitly 2030 * shared flavors are included in the list. 2031 */ 2032 seccnt = build_seclist_nodups(&exi->exi_export, sec, TRUE); 2033 if (sec_index > seccnt) 2034 return (EREMOTE); 2035 2036 fh_max_cnt = (NFS_FHSIZE / sizeof (int)) - 1; 2037 totalcnt = seccnt - sec_index + 1; 2038 cnt = totalcnt > fh_max_cnt ? fh_max_cnt : totalcnt; 2039 2040 c = (char *)fh; 2041 /* 2042 * Encode the length octet representing the number of 2043 * security flavors (in bytes) in this overloaded fh. 2044 */ 2045 *c = cnt * sizeof (int); 2046 2047 /* 2048 * Encode the status octet that indicates whether there 2049 * are more security flavors the client needs to get. 2050 */ 2051 *(c + 1) = totalcnt > fh_max_cnt; 2052 2053 /* 2054 * put security flavors in the overloaded fh 2055 */ 2056 ipt = (int *)(c + sizeof (int32_t)); 2057 secidx = sec_index - 1; 2058 for (i = 0; i < cnt; i++) { 2059 ipt[i] = htonl(sec[i + secidx].s_secinfo.sc_nfsnum); 2060 } 2061 return (0); 2062 } 2063 2064 /* 2065 * Make an nfs_fh3 from a vnode 2066 */ 2067 int 2068 makefh3(nfs_fh3 *fh, vnode_t *vp, struct exportinfo *exi) 2069 { 2070 int error; 2071 fid_t fid; 2072 2073 bzero(&fid, sizeof (fid)); 2074 fid.fid_len = MAXFIDSZ; 2075 error = VOP_FID(vp, &fid, NULL); 2076 if (error) 2077 return (EREMOTE); 2078 2079 bzero(fh, sizeof (nfs_fh3)); 2080 fh->fh3_fsid = exi->exi_fsid; 2081 fh->fh3_len = fid.fid_len; 2082 bcopy(fid.fid_data, fh->fh3_data, fh->fh3_len); 2083 fh->fh3_xlen = exi->exi_fid.fid_len; 2084 bcopy(exi->exi_fid.fid_data, fh->fh3_xdata, fh->fh3_xlen); 2085 fh->fh3_length = sizeof (fsid_t) 2086 + sizeof (ushort_t) + fh->fh3_len 2087 + sizeof (ushort_t) + fh->fh3_xlen; 2088 fh->fh3_flags = 0; 2089 return (0); 2090 } 2091 2092 /* 2093 * This routine makes an overloaded V3 fhandle which contains 2094 * sec modes. 2095 * 2096 * 1 4 2097 * +--+--+--+--+ 2098 * | len | 2099 * +--+--+--+--+ 2100 * up to 64 2101 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+ 2102 * |s | | | | sec_1 | sec_2 | ... | sec_n | 2103 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+ 2104 * 2105 * len = 4 * (n+1), where n is the number of security flavors 2106 * sent in the current overloaded filehandle. 2107 * 2108 * the status octet s indicates whether there are more security 2109 * mechanisms (1 means yes, 0 means no) that require the client 2110 * to perform another 0x81 LOOKUP to get them. 2111 * 2112 * Three octets are padded after the status octet. 2113 */ 2114 int 2115 makefh3_ol(nfs_fh3 *fh, struct exportinfo *exi, uint_t sec_index) 2116 { 2117 secinfo_t sec[MAX_FLAVORS]; 2118 int totalcnt, cnt, *ipt, i, seccnt, fh_max_cnt, secidx; 2119 char *c; 2120 2121 if (fh == NULL || exi == NULL || sec_index < 1) 2122 return (EREMOTE); 2123 2124 /* 2125 * WebNFS clients need to know the unique set of explicitly 2126 * shared flavors in used for the public export. When 2127 * "TRUE" is passed to build_seclist_nodups(), only explicitly 2128 * shared flavors are included in the list. 2129 */ 2130 seccnt = build_seclist_nodups(&exi->exi_export, sec, TRUE); 2131 2132 if (sec_index > seccnt) 2133 return (EREMOTE); 2134 2135 fh_max_cnt = (NFS3_FHSIZE / sizeof (int)) - 1; 2136 totalcnt = seccnt - sec_index + 1; 2137 cnt = totalcnt > fh_max_cnt ? fh_max_cnt : totalcnt; 2138 2139 /* 2140 * Place the length in fh3_length representing the number 2141 * of security flavors (in bytes) in this overloaded fh. 2142 */ 2143 fh->fh3_flags = FH_WEBNFS; 2144 fh->fh3_length = (cnt+1) * sizeof (int32_t); 2145 2146 c = (char *)&fh->fh3_u.nfs_fh3_i.fh3_i; 2147 /* 2148 * Encode the status octet that indicates whether there 2149 * are more security flavors the client needs to get. 2150 */ 2151 *c = totalcnt > fh_max_cnt; 2152 2153 /* 2154 * put security flavors in the overloaded fh 2155 */ 2156 secidx = sec_index - 1; 2157 ipt = (int *)(c + sizeof (int32_t)); 2158 for (i = 0; i < cnt; i++) { 2159 ipt[i] = htonl(sec[i + secidx].s_secinfo.sc_nfsnum); 2160 } 2161 return (0); 2162 } 2163 2164 /* 2165 * Make an nfs_fh4 from a vnode 2166 */ 2167 int 2168 makefh4(nfs_fh4 *fh, vnode_t *vp, struct exportinfo *exi) 2169 { 2170 int error; 2171 nfs_fh4_fmt_t *fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val; 2172 fid_t fid; 2173 2174 bzero(&fid, sizeof (fid)); 2175 fid.fid_len = MAXFIDSZ; 2176 /* 2177 * vop_fid_pseudo() is used to set up NFSv4 namespace, so 2178 * use vop_fid_pseudo() here to get the fid instead of VOP_FID. 2179 */ 2180 error = vop_fid_pseudo(vp, &fid); 2181 if (error) 2182 return (error); 2183 2184 fh->nfs_fh4_len = NFS_FH4_LEN; 2185 2186 fh_fmtp->fh4_i.fhx_fsid = exi->exi_fh.fh_fsid; 2187 fh_fmtp->fh4_i.fhx_xlen = exi->exi_fh.fh_xlen; 2188 2189 bzero(fh_fmtp->fh4_i.fhx_data, sizeof (fh_fmtp->fh4_i.fhx_data)); 2190 bzero(fh_fmtp->fh4_i.fhx_xdata, sizeof (fh_fmtp->fh4_i.fhx_xdata)); 2191 bcopy(exi->exi_fh.fh_xdata, fh_fmtp->fh4_i.fhx_xdata, 2192 exi->exi_fh.fh_xlen); 2193 2194 fh_fmtp->fh4_len = fid.fid_len; 2195 ASSERT(fid.fid_len <= sizeof (fh_fmtp->fh4_data)); 2196 bcopy(fid.fid_data, fh_fmtp->fh4_data, fid.fid_len); 2197 fh_fmtp->fh4_flag = 0; 2198 2199 #ifdef VOLATILE_FH_TEST 2200 /* 2201 * XXX (temporary?) 2202 * Use the rnode volatile_id value to add volatility to the fh. 2203 * 2204 * For testing purposes there are currently two scenarios, based 2205 * on whether the filesystem was shared with "volatile_fh" 2206 * or "expire_on_rename". In the first case, use the value of 2207 * export struct share_time as the volatile_id. In the second 2208 * case use the vnode volatile_id value (which is set to the 2209 * time in which the file was renamed). 2210 * 2211 * Note that the above are temporary constructs for testing only 2212 * XXX 2213 */ 2214 if (exi->exi_export.ex_flags & EX_VOLRNM) { 2215 fh_fmtp->fh4_volatile_id = find_volrnm_fh_id(exi, fh); 2216 } else if (exi->exi_export.ex_flags & EX_VOLFH) { 2217 fh_fmtp->fh4_volatile_id = exi->exi_volatile_id; 2218 } else { 2219 fh_fmtp->fh4_volatile_id = 0; 2220 } 2221 #endif /* VOLATILE_FH_TEST */ 2222 2223 return (0); 2224 } 2225 2226 /* 2227 * Convert an fhandle into a vnode. 2228 * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode. 2229 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2230 * are done with it. 2231 */ 2232 vnode_t * 2233 nfs_fhtovp(fhandle_t *fh, struct exportinfo *exi) 2234 { 2235 vfs_t *vfsp; 2236 vnode_t *vp; 2237 int error; 2238 fid_t *fidp; 2239 2240 TRACE_0(TR_FAC_NFS, TR_FHTOVP_START, 2241 "fhtovp_start"); 2242 2243 if (exi == NULL) { 2244 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, 2245 "fhtovp_end:(%S)", "exi NULL"); 2246 return (NULL); /* not exported */ 2247 } 2248 2249 ASSERT(exi->exi_vp != NULL); 2250 2251 if (PUBLIC_FH2(fh)) { 2252 if (exi->exi_export.ex_flags & EX_PUBLIC) { 2253 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, 2254 "fhtovp_end:(%S)", "root not exported"); 2255 return (NULL); 2256 } 2257 vp = exi->exi_vp; 2258 VN_HOLD(vp); 2259 return (vp); 2260 } 2261 2262 vfsp = exi->exi_vp->v_vfsp; 2263 ASSERT(vfsp != NULL); 2264 fidp = (fid_t *)&fh->fh_len; 2265 2266 error = VFS_VGET(vfsp, &vp, fidp); 2267 if (error || vp == NULL) { 2268 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, 2269 "fhtovp_end:(%S)", "VFS_GET failed or vp NULL"); 2270 return (NULL); 2271 } 2272 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, 2273 "fhtovp_end:(%S)", "end"); 2274 return (vp); 2275 } 2276 2277 /* 2278 * Convert an fhandle into a vnode. 2279 * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode. 2280 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2281 * are done with it. 2282 * This is just like nfs_fhtovp() but without the exportinfo argument. 2283 */ 2284 2285 vnode_t * 2286 lm_fhtovp(fhandle_t *fh) 2287 { 2288 register vfs_t *vfsp; 2289 vnode_t *vp; 2290 int error; 2291 2292 vfsp = getvfs(&fh->fh_fsid); 2293 if (vfsp == NULL) 2294 return (NULL); 2295 2296 error = VFS_VGET(vfsp, &vp, (fid_t *)&(fh->fh_len)); 2297 VFS_RELE(vfsp); 2298 if (error || vp == NULL) 2299 return (NULL); 2300 2301 return (vp); 2302 } 2303 2304 /* 2305 * Convert an nfs_fh3 into a vnode. 2306 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode. 2307 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2308 * are done with it. 2309 */ 2310 vnode_t * 2311 nfs3_fhtovp(nfs_fh3 *fh, struct exportinfo *exi) 2312 { 2313 vfs_t *vfsp; 2314 vnode_t *vp; 2315 int error; 2316 fid_t *fidp; 2317 2318 if (exi == NULL) 2319 return (NULL); /* not exported */ 2320 2321 ASSERT(exi->exi_vp != NULL); 2322 2323 if (PUBLIC_FH3(fh)) { 2324 if (exi->exi_export.ex_flags & EX_PUBLIC) 2325 return (NULL); 2326 vp = exi->exi_vp; 2327 VN_HOLD(vp); 2328 return (vp); 2329 } 2330 2331 if (fh->fh3_length < NFS3_OLDFHSIZE || 2332 fh->fh3_length > NFS3_MAXFHSIZE) 2333 return (NULL); 2334 2335 vfsp = exi->exi_vp->v_vfsp; 2336 ASSERT(vfsp != NULL); 2337 fidp = FH3TOFIDP(fh); 2338 2339 error = VFS_VGET(vfsp, &vp, fidp); 2340 if (error || vp == NULL) 2341 return (NULL); 2342 2343 return (vp); 2344 } 2345 2346 /* 2347 * Convert an nfs_fh3 into a vnode. 2348 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode. 2349 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2350 * are done with it. 2351 * BTW: This is just like nfs3_fhtovp() but without the exportinfo arg. 2352 * Also, vfsp is accessed through getvfs() rather using exportinfo !! 2353 */ 2354 2355 vnode_t * 2356 lm_nfs3_fhtovp(nfs_fh3 *fh) 2357 { 2358 vfs_t *vfsp; 2359 vnode_t *vp; 2360 int error; 2361 fid_t *fidp; 2362 2363 if (fh->fh3_length < NFS3_OLDFHSIZE || 2364 fh->fh3_length > NFS3_MAXFHSIZE) 2365 return (NULL); 2366 2367 vfsp = getvfs(&fh->fh3_fsid); 2368 if (vfsp == NULL) 2369 return (NULL); 2370 fidp = FH3TOFIDP(fh); 2371 2372 error = VFS_VGET(vfsp, &vp, fidp); 2373 VFS_RELE(vfsp); 2374 if (error || vp == NULL) 2375 return (NULL); 2376 2377 return (vp); 2378 } 2379 2380 /* 2381 * Convert an nfs_fh4 into a vnode. 2382 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode. 2383 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2384 * are done with it. 2385 */ 2386 vnode_t * 2387 nfs4_fhtovp(nfs_fh4 *fh, struct exportinfo *exi, nfsstat4 *statp) 2388 { 2389 vfs_t *vfsp; 2390 vnode_t *vp = NULL; 2391 int error; 2392 fid_t *fidp; 2393 nfs_fh4_fmt_t *fh_fmtp; 2394 #ifdef VOLATILE_FH_TEST 2395 uint32_t volatile_id = 0; 2396 #endif /* VOLATILE_FH_TEST */ 2397 2398 if (exi == NULL) { 2399 *statp = NFS4ERR_STALE; 2400 return (NULL); /* not exported */ 2401 } 2402 ASSERT(exi->exi_vp != NULL); 2403 2404 /* caller should have checked this */ 2405 ASSERT(fh->nfs_fh4_len >= NFS_FH4_LEN); 2406 2407 fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val; 2408 vfsp = exi->exi_vp->v_vfsp; 2409 ASSERT(vfsp != NULL); 2410 fidp = (fid_t *)&fh_fmtp->fh4_len; 2411 2412 #ifdef VOLATILE_FH_TEST 2413 /* XXX check if volatile - should be changed later */ 2414 if (exi->exi_export.ex_flags & (EX_VOLRNM | EX_VOLFH)) { 2415 /* 2416 * Filesystem is shared with volatile filehandles 2417 */ 2418 if (exi->exi_export.ex_flags & EX_VOLRNM) 2419 volatile_id = find_volrnm_fh_id(exi, fh); 2420 else 2421 volatile_id = exi->exi_volatile_id; 2422 2423 if (fh_fmtp->fh4_volatile_id != volatile_id) { 2424 *statp = NFS4ERR_FHEXPIRED; 2425 return (NULL); 2426 } 2427 } 2428 /* 2429 * XXX even if test_volatile_fh false, the fh may contain a 2430 * volatile id if obtained when the test was set. 2431 */ 2432 fh_fmtp->fh4_volatile_id = (uchar_t)0; 2433 #endif /* VOLATILE_FH_TEST */ 2434 2435 error = VFS_VGET(vfsp, &vp, fidp); 2436 /* 2437 * If we can not get vp from VFS_VGET, perhaps this is 2438 * an nfs v2/v3/v4 node in an nfsv4 pseudo filesystem. 2439 * Check it out. 2440 */ 2441 if (error && PSEUDO(exi)) 2442 error = nfs4_vget_pseudo(exi, &vp, fidp); 2443 2444 if (error || vp == NULL) { 2445 *statp = NFS4ERR_STALE; 2446 return (NULL); 2447 } 2448 /* XXX - disgusting hack */ 2449 if (vp->v_type == VNON && vp->v_flag & V_XATTRDIR) 2450 vp->v_type = VDIR; 2451 *statp = NFS4_OK; 2452 return (vp); 2453 } 2454 2455 /* 2456 * Find the export structure associated with the given filesystem. 2457 * If found, then increment the ref count (exi_count). 2458 */ 2459 struct exportinfo * 2460 checkexport(fsid_t *fsid, fid_t *fid) 2461 { 2462 struct exportinfo *exi; 2463 2464 rw_enter(&exported_lock, RW_READER); 2465 for (exi = exptable[exptablehash(fsid, fid)]; 2466 exi != NULL; 2467 exi = exi->fid_hash.next) { 2468 if (exportmatch(exi, fsid, fid)) { 2469 /* 2470 * If this is the place holder for the 2471 * public file handle, then return the 2472 * real export entry for the public file 2473 * handle. 2474 */ 2475 if (exi->exi_export.ex_flags & EX_PUBLIC) { 2476 exi = exi_public; 2477 } 2478 2479 exi_hold(exi); 2480 rw_exit(&exported_lock); 2481 return (exi); 2482 } 2483 } 2484 rw_exit(&exported_lock); 2485 return (NULL); 2486 } 2487 2488 2489 /* 2490 * "old school" version of checkexport() for NFS4. NFS4 2491 * rfs4_compound holds exported_lock for duration of compound 2492 * processing. This version doesn't manipulate exi_count 2493 * since NFS4 breaks fundamental assumptions in the exi_count 2494 * design. 2495 */ 2496 struct exportinfo * 2497 checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp) 2498 { 2499 struct exportinfo *exi; 2500 2501 ASSERT(RW_LOCK_HELD(&exported_lock)); 2502 2503 for (exi = exptable[exptablehash(fsid, fid)]; 2504 exi != NULL; 2505 exi = exi->fid_hash.next) { 2506 if (exportmatch(exi, fsid, fid)) { 2507 /* 2508 * If this is the place holder for the 2509 * public file handle, then return the 2510 * real export entry for the public file 2511 * handle. 2512 */ 2513 if (exi->exi_export.ex_flags & EX_PUBLIC) { 2514 exi = exi_public; 2515 } 2516 2517 /* 2518 * If vp is given, check if vp is the 2519 * same vnode as the exported node. 2520 * 2521 * Since VOP_FID of a lofs node returns the 2522 * fid of its real node (ufs), the exported 2523 * node for lofs and (pseudo) ufs may have 2524 * the same fsid and fid. 2525 */ 2526 if (vp == NULL || vp == exi->exi_vp) 2527 return (exi); 2528 } 2529 } 2530 2531 return (NULL); 2532 } 2533 2534 /* 2535 * Free an entire export list node 2536 */ 2537 void 2538 exportfree(struct exportinfo *exi) 2539 { 2540 struct exportdata *ex; 2541 struct charset_cache *cache; 2542 2543 ex = &exi->exi_export; 2544 2545 ASSERT(exi->exi_vp != NULL && !(exi->exi_export.ex_flags & EX_PUBLIC)); 2546 VN_RELE(exi->exi_vp); 2547 if (exi->exi_dvp != NULL) 2548 VN_RELE(exi->exi_dvp); 2549 2550 if (ex->ex_flags & EX_INDEX) 2551 kmem_free(ex->ex_index, strlen(ex->ex_index) + 1); 2552 2553 kmem_free(ex->ex_path, ex->ex_pathlen + 1); 2554 nfsauth_cache_free(exi); 2555 2556 /* 2557 * if there is a character set mapping cached, clean it up. 2558 */ 2559 for (cache = exi->exi_charset; cache != NULL; 2560 cache = exi->exi_charset) { 2561 if (cache->inbound != (kiconv_t)-1) 2562 (void) kiconv_close(cache->inbound); 2563 if (cache->outbound != (kiconv_t)-1) 2564 (void) kiconv_close(cache->outbound); 2565 exi->exi_charset = cache->next; 2566 kmem_free(cache, sizeof (struct charset_cache)); 2567 } 2568 2569 if (exi->exi_logbuffer != NULL) 2570 nfslog_disable(exi); 2571 2572 if (ex->ex_flags & EX_LOG) { 2573 kmem_free(ex->ex_log_buffer, ex->ex_log_bufferlen + 1); 2574 kmem_free(ex->ex_tag, ex->ex_taglen + 1); 2575 } 2576 2577 if (exi->exi_visible) 2578 free_visible(exi->exi_visible); 2579 2580 srv_secinfo_list_free(ex->ex_secinfo, ex->ex_seccnt); 2581 2582 #ifdef VOLATILE_FH_TEST 2583 free_volrnm_list(exi); 2584 mutex_destroy(&exi->exi_vol_rename_lock); 2585 #endif /* VOLATILE_FH_TEST */ 2586 2587 mutex_destroy(&exi->exi_lock); 2588 rw_destroy(&exi->exi_cache_lock); 2589 2590 kmem_free(exi, sizeof (*exi)); 2591 } 2592 2593 /* 2594 * load the index file from user space into kernel space. 2595 */ 2596 static int 2597 loadindex(struct exportdata *kex) 2598 { 2599 int error; 2600 char index[MAXNAMELEN+1]; 2601 size_t len; 2602 2603 /* 2604 * copyinstr copies the complete string including the NULL and 2605 * returns the len with the NULL byte included in the calculation 2606 * as long as the max length is not exceeded. 2607 */ 2608 if (error = copyinstr(kex->ex_index, index, sizeof (index), &len)) 2609 return (error); 2610 2611 kex->ex_index = kmem_alloc(len, KM_SLEEP); 2612 bcopy(index, kex->ex_index, len); 2613 2614 return (0); 2615 } 2616 2617 void 2618 exi_hold(struct exportinfo *exi) 2619 { 2620 mutex_enter(&exi->exi_lock); 2621 exi->exi_count++; 2622 mutex_exit(&exi->exi_lock); 2623 } 2624 2625 /* 2626 * When a thread completes using exi, it should call exi_rele(). 2627 * exi_rele() decrements exi_count. It releases exi if exi_count == 0, i.e. 2628 * if this is the last user of exi and exi is not on exportinfo list anymore 2629 */ 2630 void 2631 exi_rele(struct exportinfo *exi) 2632 { 2633 mutex_enter(&exi->exi_lock); 2634 exi->exi_count--; 2635 if (exi->exi_count == 0) { 2636 mutex_exit(&exi->exi_lock); 2637 exportfree(exi); 2638 } else 2639 mutex_exit(&exi->exi_lock); 2640 } 2641 2642 #ifdef VOLATILE_FH_TEST 2643 /* 2644 * Test for volatile fh's - add file handle to list and set its volatile id 2645 * to time it was renamed. If EX_VOLFH is also on and the fs is reshared, 2646 * the vol_rename queue is purged. 2647 * 2648 * XXX This code is for unit testing purposes only... To correctly use it, it 2649 * needs to tie a rename list to the export struct and (more 2650 * important), protect access to the exi rename list using a write lock. 2651 */ 2652 2653 /* 2654 * get the fh vol record if it's in the volatile on rename list. Don't check 2655 * volatile_id in the file handle - compare only the file handles. 2656 */ 2657 static struct ex_vol_rename * 2658 find_volrnm_fh(struct exportinfo *exi, nfs_fh4 *fh4p) 2659 { 2660 struct ex_vol_rename *p = NULL; 2661 fhandle4_t *fhp; 2662 2663 /* XXX shouldn't we assert &exported_lock held? */ 2664 ASSERT(MUTEX_HELD(&exi->exi_vol_rename_lock)); 2665 2666 if (fh4p->nfs_fh4_len != NFS_FH4_LEN) { 2667 return (NULL); 2668 } 2669 fhp = &((nfs_fh4_fmt_t *)fh4p->nfs_fh4_val)->fh4_i; 2670 for (p = exi->exi_vol_rename; p != NULL; p = p->vrn_next) { 2671 if (bcmp(fhp, &p->vrn_fh_fmt.fh4_i, 2672 sizeof (fhandle4_t)) == 0) 2673 break; 2674 } 2675 return (p); 2676 } 2677 2678 /* 2679 * get the volatile id for the fh (if there is - else return 0). Ignore the 2680 * volatile_id in the file handle - compare only the file handles. 2681 */ 2682 static uint32_t 2683 find_volrnm_fh_id(struct exportinfo *exi, nfs_fh4 *fh4p) 2684 { 2685 struct ex_vol_rename *p; 2686 uint32_t volatile_id; 2687 2688 mutex_enter(&exi->exi_vol_rename_lock); 2689 p = find_volrnm_fh(exi, fh4p); 2690 volatile_id = (p ? p->vrn_fh_fmt.fh4_volatile_id : 2691 exi->exi_volatile_id); 2692 mutex_exit(&exi->exi_vol_rename_lock); 2693 return (volatile_id); 2694 } 2695 2696 /* 2697 * Free the volatile on rename list - will be called if a filesystem is 2698 * unshared or reshared without EX_VOLRNM 2699 */ 2700 static void 2701 free_volrnm_list(struct exportinfo *exi) 2702 { 2703 struct ex_vol_rename *p, *pnext; 2704 2705 /* no need to hold mutex lock - this one is called from exportfree */ 2706 for (p = exi->exi_vol_rename; p != NULL; p = pnext) { 2707 pnext = p->vrn_next; 2708 kmem_free(p, sizeof (*p)); 2709 } 2710 exi->exi_vol_rename = NULL; 2711 } 2712 2713 /* 2714 * Add a file handle to the volatile on rename list. 2715 */ 2716 void 2717 add_volrnm_fh(struct exportinfo *exi, vnode_t *vp) 2718 { 2719 struct ex_vol_rename *p; 2720 char fhbuf[NFS4_FHSIZE]; 2721 nfs_fh4 fh4; 2722 int error; 2723 2724 fh4.nfs_fh4_val = fhbuf; 2725 error = makefh4(&fh4, vp, exi); 2726 if ((error) || (fh4.nfs_fh4_len != sizeof (p->vrn_fh_fmt))) { 2727 return; 2728 } 2729 2730 mutex_enter(&exi->exi_vol_rename_lock); 2731 2732 p = find_volrnm_fh(exi, &fh4); 2733 2734 if (p == NULL) { 2735 p = kmem_alloc(sizeof (*p), KM_SLEEP); 2736 bcopy(fh4.nfs_fh4_val, &p->vrn_fh_fmt, sizeof (p->vrn_fh_fmt)); 2737 p->vrn_next = exi->exi_vol_rename; 2738 exi->exi_vol_rename = p; 2739 } 2740 2741 p->vrn_fh_fmt.fh4_volatile_id = gethrestime_sec(); 2742 mutex_exit(&exi->exi_vol_rename_lock); 2743 } 2744 2745 #endif /* VOLATILE_FH_TEST */ 2746