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 pn_free(&lookpn); 1107 exi_rele(ex1); 1108 return (EEXIST); 1109 } 1110 if (ex1) 1111 exi_rele(ex1); 1112 1113 /* 1114 * Get the vfs id 1115 */ 1116 bzero(&fid, sizeof (fid)); 1117 fid.fid_len = MAXFIDSZ; 1118 error = VOP_FID(vp, &fid, NULL); 1119 fsid = vp->v_vfsp->vfs_fsid; 1120 1121 if (error) { 1122 VN_RELE(vp); 1123 if (dvp != NULL) 1124 VN_RELE(dvp); 1125 /* 1126 * If VOP_FID returns ENOSPC then the fid supplied 1127 * is too small. For now we simply return EREMOTE. 1128 */ 1129 if (error == ENOSPC) 1130 error = EREMOTE; 1131 pn_free(&lookpn); 1132 return (error); 1133 } 1134 1135 /* 1136 * Do not allow re-sharing a shared vnode under a different path 1137 * PSEUDO export has ex_path fabricated, e.g. "/tmp (pseudo)", skip it. 1138 */ 1139 rw_enter(&exported_lock, RW_READER); 1140 DTRACE_PROBE(nfss__i__exported_lock2_start); 1141 for (ex2 = exptable[exptablehash(&fsid, &fid)]; ex2; 1142 ex2 = ex2->fid_hash.next) { 1143 if (ex2 != exi_root && !PSEUDO(ex2) && 1144 VN_CMP(ex2->exi_vp, vp) && 1145 strcmp(ex2->exi_export.ex_path, lookpn.pn_path) != 0) { 1146 DTRACE_PROBE(nfss__i__exported_lock2_stop); 1147 rw_exit(&exported_lock); 1148 pn_free(&lookpn); 1149 return (EEXIST); 1150 } 1151 } 1152 DTRACE_PROBE(nfss__i__exported_lock2_stop); 1153 rw_exit(&exported_lock); 1154 pn_free(&lookpn); 1155 1156 exi = kmem_zalloc(sizeof (*exi), KM_SLEEP); 1157 exi->exi_fsid = fsid; 1158 exi->exi_fid = fid; 1159 exi->exi_vp = vp; 1160 exi->exi_count = 1; 1161 exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag & 1162 VSW_VOLATILEDEV) ? 1 : 0; 1163 mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL); 1164 exi->exi_dvp = dvp; 1165 1166 /* 1167 * Initialize auth cache lock 1168 */ 1169 rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL); 1170 1171 /* 1172 * Build up the template fhandle 1173 */ 1174 exi->exi_fh.fh_fsid = fsid; 1175 if (exi->exi_fid.fid_len > sizeof (exi->exi_fh.fh_xdata)) { 1176 error = EREMOTE; 1177 goto out1; 1178 } 1179 exi->exi_fh.fh_xlen = exi->exi_fid.fid_len; 1180 bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata, 1181 exi->exi_fid.fid_len); 1182 1183 exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data); 1184 1185 kex = &exi->exi_export; 1186 1187 /* 1188 * Load in everything, and do sanity checking 1189 */ 1190 STRUCT_INIT(uexi, model); 1191 if (copyin(STRUCT_FGETP(uap, uex), STRUCT_BUF(uexi), 1192 STRUCT_SIZE(uexi))) { 1193 error = EFAULT; 1194 goto out1; 1195 } 1196 1197 kex->ex_version = STRUCT_FGET(uexi, ex_version); 1198 if (kex->ex_version != EX_CURRENT_VERSION) { 1199 error = EINVAL; 1200 cmn_err(CE_WARN, 1201 "NFS: exportfs requires export struct version 2 - got %d\n", 1202 kex->ex_version); 1203 goto out1; 1204 } 1205 1206 /* 1207 * Must have at least one security entry 1208 */ 1209 kex->ex_seccnt = STRUCT_FGET(uexi, ex_seccnt); 1210 if (kex->ex_seccnt < 1) { 1211 error = EINVAL; 1212 goto out1; 1213 } 1214 1215 kex->ex_path = STRUCT_FGETP(uexi, ex_path); 1216 kex->ex_pathlen = STRUCT_FGET(uexi, ex_pathlen); 1217 kex->ex_flags = STRUCT_FGET(uexi, ex_flags); 1218 kex->ex_anon = STRUCT_FGET(uexi, ex_anon); 1219 kex->ex_secinfo = STRUCT_FGETP(uexi, ex_secinfo); 1220 kex->ex_index = STRUCT_FGETP(uexi, ex_index); 1221 kex->ex_log_buffer = STRUCT_FGETP(uexi, ex_log_buffer); 1222 kex->ex_log_bufferlen = STRUCT_FGET(uexi, ex_log_bufferlen); 1223 kex->ex_tag = STRUCT_FGETP(uexi, ex_tag); 1224 kex->ex_taglen = STRUCT_FGET(uexi, ex_taglen); 1225 1226 /* 1227 * Copy the exported pathname into 1228 * an appropriately sized buffer. 1229 */ 1230 pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1231 if (copyinstr(kex->ex_path, pathbuf, MAXPATHLEN, &kex->ex_pathlen)) { 1232 kmem_free(pathbuf, MAXPATHLEN); 1233 error = EFAULT; 1234 goto out1; 1235 } 1236 kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP); 1237 bcopy(pathbuf, kex->ex_path, kex->ex_pathlen); 1238 kex->ex_path[kex->ex_pathlen] = '\0'; 1239 kmem_free(pathbuf, MAXPATHLEN); 1240 1241 /* 1242 * Get the path to the logging buffer and the tag 1243 */ 1244 if (kex->ex_flags & EX_LOG) { 1245 log_buffer = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1246 if (copyinstr(kex->ex_log_buffer, log_buffer, MAXPATHLEN, 1247 &kex->ex_log_bufferlen)) { 1248 kmem_free(log_buffer, MAXPATHLEN); 1249 error = EFAULT; 1250 goto out2; 1251 } 1252 kex->ex_log_buffer = 1253 kmem_alloc(kex->ex_log_bufferlen + 1, KM_SLEEP); 1254 bcopy(log_buffer, kex->ex_log_buffer, kex->ex_log_bufferlen); 1255 kex->ex_log_buffer[kex->ex_log_bufferlen] = '\0'; 1256 kmem_free(log_buffer, MAXPATHLEN); 1257 1258 tagbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1259 if (copyinstr(kex->ex_tag, tagbuf, MAXPATHLEN, 1260 &kex->ex_taglen)) { 1261 kmem_free(tagbuf, MAXPATHLEN); 1262 error = EFAULT; 1263 goto out3; 1264 } 1265 kex->ex_tag = kmem_alloc(kex->ex_taglen + 1, KM_SLEEP); 1266 bcopy(tagbuf, kex->ex_tag, kex->ex_taglen); 1267 kex->ex_tag[kex->ex_taglen] = '\0'; 1268 kmem_free(tagbuf, MAXPATHLEN); 1269 } 1270 1271 /* 1272 * Load the security information for each flavor 1273 */ 1274 allocsize = kex->ex_seccnt * SIZEOF_STRUCT(secinfo, model); 1275 sp = kmem_zalloc(allocsize, KM_SLEEP); 1276 if (copyin(kex->ex_secinfo, sp, allocsize)) { 1277 kmem_free(sp, allocsize); 1278 error = EFAULT; 1279 goto out4; 1280 } 1281 1282 /* 1283 * All of these nested structures need to be converted to 1284 * the kernel native format. 1285 */ 1286 if (model != DATAMODEL_NATIVE) { 1287 size_t allocsize2; 1288 struct secinfo *sp2; 1289 1290 allocsize2 = kex->ex_seccnt * sizeof (struct secinfo); 1291 sp2 = kmem_zalloc(allocsize2, KM_SLEEP); 1292 1293 for (i = 0; i < kex->ex_seccnt; i++) { 1294 STRUCT_HANDLE(secinfo, usi); 1295 1296 STRUCT_SET_HANDLE(usi, model, 1297 (struct secinfo *)((caddr_t)sp + 1298 (i * SIZEOF_STRUCT(secinfo, model)))); 1299 bcopy(STRUCT_FGET(usi, s_secinfo.sc_name), 1300 sp2[i].s_secinfo.sc_name, MAX_NAME_LEN); 1301 sp2[i].s_secinfo.sc_nfsnum = 1302 STRUCT_FGET(usi, s_secinfo.sc_nfsnum); 1303 sp2[i].s_secinfo.sc_rpcnum = 1304 STRUCT_FGET(usi, s_secinfo.sc_rpcnum); 1305 bcopy(STRUCT_FGET(usi, s_secinfo.sc_gss_mech), 1306 sp2[i].s_secinfo.sc_gss_mech, MAX_NAME_LEN); 1307 sp2[i].s_secinfo.sc_gss_mech_type = 1308 STRUCT_FGETP(usi, s_secinfo.sc_gss_mech_type); 1309 sp2[i].s_secinfo.sc_qop = 1310 STRUCT_FGET(usi, s_secinfo.sc_qop); 1311 sp2[i].s_secinfo.sc_service = 1312 STRUCT_FGET(usi, s_secinfo.sc_service); 1313 1314 sp2[i].s_flags = STRUCT_FGET(usi, s_flags); 1315 sp2[i].s_window = STRUCT_FGET(usi, s_window); 1316 sp2[i].s_rootid = STRUCT_FGET(usi, s_rootid); 1317 sp2[i].s_rootcnt = STRUCT_FGET(usi, s_rootcnt); 1318 sp2[i].s_rootnames = STRUCT_FGETP(usi, s_rootnames); 1319 } 1320 kmem_free(sp, allocsize); 1321 sp = sp2; 1322 allocsize = allocsize2; 1323 } 1324 1325 kex->ex_secinfo = sp; 1326 1327 /* 1328 * And now copy rootnames for each individual secinfo. 1329 */ 1330 callback = 0; 1331 allocd_seccnt = 0; 1332 while (allocd_seccnt < kex->ex_seccnt) { 1333 1334 exs = &sp[allocd_seccnt]; 1335 if (exs->s_rootcnt > 0) { 1336 if (!sec_svc_loadrootnames(exs->s_secinfo.sc_rpcnum, 1337 exs->s_rootcnt, &exs->s_rootnames, model)) { 1338 error = EFAULT; 1339 goto out5; 1340 } 1341 } 1342 1343 if (exs->s_secinfo.sc_rpcnum == RPCSEC_GSS) { 1344 rpc_gss_OID mech_tmp; 1345 STRUCT_DECL(rpc_gss_OID_s, umech_tmp); 1346 caddr_t elements_tmp; 1347 1348 /* Copyin mechanism type */ 1349 STRUCT_INIT(umech_tmp, model); 1350 mech_tmp = kmem_alloc(sizeof (*mech_tmp), KM_SLEEP); 1351 if (copyin(exs->s_secinfo.sc_gss_mech_type, 1352 STRUCT_BUF(umech_tmp), STRUCT_SIZE(umech_tmp))) { 1353 kmem_free(mech_tmp, sizeof (*mech_tmp)); 1354 error = EFAULT; 1355 goto out5; 1356 } 1357 mech_tmp->length = STRUCT_FGET(umech_tmp, length); 1358 mech_tmp->elements = STRUCT_FGETP(umech_tmp, elements); 1359 1360 elements_tmp = kmem_alloc(mech_tmp->length, KM_SLEEP); 1361 if (copyin(mech_tmp->elements, elements_tmp, 1362 mech_tmp->length)) { 1363 kmem_free(elements_tmp, mech_tmp->length); 1364 kmem_free(mech_tmp, sizeof (*mech_tmp)); 1365 error = EFAULT; 1366 goto out5; 1367 } 1368 mech_tmp->elements = elements_tmp; 1369 exs->s_secinfo.sc_gss_mech_type = mech_tmp; 1370 allocd_seccnt++; 1371 1372 callback = 1; 1373 } else 1374 allocd_seccnt++; 1375 } 1376 1377 /* 1378 * Init the secinfo reference count and mark these flavors 1379 * explicitly exported flavors. 1380 */ 1381 for (i = 0; i < kex->ex_seccnt; i++) { 1382 kex->ex_secinfo[i].s_flags |= M_4SEC_EXPORTED; 1383 kex->ex_secinfo[i].s_refcnt = 1; 1384 } 1385 1386 /* 1387 * Set up rpcsec_gss callback routine entry if any. 1388 */ 1389 if (callback) { 1390 cb.callback = rfs_gsscallback; 1391 cb.program = NFS_ACL_PROGRAM; 1392 for (cb.version = NFS_ACL_VERSMIN; 1393 cb.version <= NFS_ACL_VERSMAX; cb.version++) { 1394 (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK, 1395 (void *)&cb); 1396 } 1397 1398 cb.program = NFS_PROGRAM; 1399 for (cb.version = NFS_VERSMIN; 1400 cb.version <= NFS_VERSMAX; cb.version++) { 1401 (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK, 1402 (void *)&cb); 1403 } 1404 } 1405 1406 /* 1407 * Check the index flag. Do this here to avoid holding the 1408 * lock while dealing with the index option (as we do with 1409 * the public option). 1410 */ 1411 if (kex->ex_flags & EX_INDEX) { 1412 if (!kex->ex_index) { /* sanity check */ 1413 error = EINVAL; 1414 goto out5; 1415 } 1416 if (error = loadindex(kex)) 1417 goto out5; 1418 } 1419 1420 if (kex->ex_flags & EX_LOG) { 1421 if (error = nfslog_setup(exi)) 1422 goto out6; 1423 } 1424 1425 /* 1426 * Insert the new entry at the front of the export list 1427 */ 1428 rw_enter(&exported_lock, RW_WRITER); 1429 DTRACE_PROBE(nfss__i__exported_lock3_start); 1430 1431 export_link(exi); 1432 1433 /* 1434 * Check the rest of the list for an old entry for the fs. 1435 * If one is found then unlink it, wait until this is the 1436 * only reference and then free it. 1437 */ 1438 for (ex = exi->fid_hash.next; ex != NULL; ex = ex->fid_hash.next) { 1439 if (ex != exi_root && VN_CMP(ex->exi_vp, vp)) { 1440 export_unlink(ex); 1441 break; 1442 } 1443 } 1444 1445 /* 1446 * If the public filehandle is pointing at the 1447 * old entry, then point it back at the root. 1448 */ 1449 if (ex != NULL && ex == exi_public) 1450 exi_public = exi_root; 1451 1452 /* 1453 * If the public flag is on, make the global exi_public 1454 * point to this entry and turn off the public bit so that 1455 * we can distinguish it from the place holder export. 1456 */ 1457 if (kex->ex_flags & EX_PUBLIC) { 1458 exi_public = exi; 1459 kex->ex_flags &= ~EX_PUBLIC; 1460 } 1461 1462 #ifdef VOLATILE_FH_TEST 1463 /* 1464 * Set up the volatile_id value if volatile on share. 1465 * The list of volatile renamed filehandles is always destroyed, 1466 * if the fs was reshared. 1467 */ 1468 if (kex->ex_flags & EX_VOLFH) 1469 exi->exi_volatile_id = gethrestime_sec(); 1470 1471 mutex_init(&exi->exi_vol_rename_lock, NULL, MUTEX_DEFAULT, NULL); 1472 #endif /* VOLATILE_FH_TEST */ 1473 1474 /* 1475 * If this is a new export, then climb up 1476 * the tree and check if any pseudo exports 1477 * need to be created to provide a path for 1478 * NFS v4 clients. 1479 */ 1480 if (ex == NULL) { 1481 error = treeclimb_export(exi); 1482 if (error) 1483 goto out7; 1484 } else { 1485 /* If it's a re-export update namespace tree */ 1486 exi->exi_tree = ex->exi_tree; 1487 exi->exi_tree->tree_exi = exi; 1488 } 1489 1490 /* 1491 * build a unique flavor list from the flavors specified 1492 * in the share cmd. unique means that each flavor only 1493 * appears once in the secinfo list -- no duplicates allowed. 1494 */ 1495 newcnt = build_seclist_nodups(&exi->exi_export, newsec, FALSE); 1496 1497 srv_secinfo_treeclimb(exi, newsec, newcnt, TRUE); 1498 1499 /* 1500 * If re-sharing an old export entry, update the secinfo data 1501 * depending on if the old entry is a pseudo node or not. 1502 */ 1503 if (ex != NULL) { 1504 oldcnt = build_seclist_nodups(&ex->exi_export, oldsec, FALSE); 1505 if (PSEUDO(ex)) { 1506 /* 1507 * The dir being shared is a pseudo export root (which 1508 * will be transformed into a real export root). The 1509 * flavor(s) of the new share were propagated to the 1510 * ancestors by srv_secinfo_treeclimb() above. Now 1511 * transfer the implicit flavor refs from the old 1512 * pseudo exprot root to the new (real) export root. 1513 */ 1514 srv_secinfo_add(&exi->exi_export.ex_secinfo, 1515 &exi->exi_export.ex_seccnt, oldsec, oldcnt, TRUE); 1516 } else { 1517 /* 1518 * First transfer implicit flavor refs to new export. 1519 * Remove old flavor refs last. 1520 */ 1521 srv_secinfo_exp2exp(&exi->exi_export, oldsec, oldcnt); 1522 srv_secinfo_treeclimb(ex, oldsec, oldcnt, FALSE); 1523 } 1524 } 1525 1526 /* 1527 * If it's a re-export and the old entry has a pseudonode list, 1528 * transfer it to the new export. 1529 */ 1530 if (ex != NULL && (ex->exi_visible != NULL)) { 1531 exi->exi_visible = ex->exi_visible; 1532 ex->exi_visible = NULL; 1533 } 1534 1535 DTRACE_PROBE(nfss__i__exported_lock3_stop); 1536 rw_exit(&exported_lock); 1537 1538 if (exi_public == exi || kex->ex_flags & EX_LOG) { 1539 /* 1540 * Log share operation to this buffer only. 1541 */ 1542 nfslog_share_record(exi, cr); 1543 } 1544 1545 if (ex != NULL) 1546 exi_rele(ex); 1547 1548 return (0); 1549 1550 out7: 1551 /* Unlink the new export in exptable. */ 1552 export_unlink(exi); 1553 DTRACE_PROBE(nfss__i__exported_lock3_stop); 1554 rw_exit(&exported_lock); 1555 out6: 1556 if (kex->ex_flags & EX_INDEX) 1557 kmem_free(kex->ex_index, strlen(kex->ex_index) + 1); 1558 out5: 1559 /* free partially completed allocation */ 1560 while (--allocd_seccnt >= 0) { 1561 exs = &kex->ex_secinfo[allocd_seccnt]; 1562 srv_secinfo_entry_free(exs); 1563 } 1564 1565 if (kex->ex_secinfo) { 1566 kmem_free(kex->ex_secinfo, 1567 kex->ex_seccnt * sizeof (struct secinfo)); 1568 } 1569 1570 out4: 1571 if ((kex->ex_flags & EX_LOG) && kex->ex_tag != NULL) 1572 kmem_free(kex->ex_tag, kex->ex_taglen + 1); 1573 out3: 1574 if ((kex->ex_flags & EX_LOG) && kex->ex_log_buffer != NULL) 1575 kmem_free(kex->ex_log_buffer, kex->ex_log_bufferlen + 1); 1576 out2: 1577 kmem_free(kex->ex_path, kex->ex_pathlen + 1); 1578 out1: 1579 VN_RELE(vp); 1580 if (dvp != NULL) 1581 VN_RELE(dvp); 1582 mutex_destroy(&exi->exi_lock); 1583 rw_destroy(&exi->exi_cache_lock); 1584 kmem_free(exi, sizeof (*exi)); 1585 return (error); 1586 } 1587 1588 /* 1589 * Remove the exportinfo from the export list 1590 */ 1591 void 1592 export_unlink(struct exportinfo *exi) 1593 { 1594 ASSERT(RW_WRITE_HELD(&exported_lock)); 1595 1596 exp_hash_unlink(exi, fid_hash); 1597 exp_hash_unlink(exi, path_hash); 1598 } 1599 1600 /* 1601 * Unexport an exported filesystem 1602 */ 1603 static int 1604 unexport(struct exportinfo *exi) 1605 { 1606 struct secinfo cursec[MAX_FLAVORS]; 1607 int curcnt; 1608 1609 rw_enter(&exported_lock, RW_WRITER); 1610 1611 /* Check if exi is still linked in the export table */ 1612 if (!EXP_LINKED(exi) || PSEUDO(exi)) { 1613 rw_exit(&exported_lock); 1614 return (EINVAL); 1615 } 1616 1617 export_unlink(exi); 1618 1619 /* 1620 * Remove security flavors before treeclimb_unexport() is called 1621 * because srv_secinfo_treeclimb needs the namespace tree 1622 */ 1623 curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE); 1624 1625 srv_secinfo_treeclimb(exi, cursec, curcnt, FALSE); 1626 1627 /* 1628 * If there's a visible list, then need to leave 1629 * a pseudo export here to retain the visible list 1630 * for paths to exports below. 1631 */ 1632 if (exi->exi_visible) { 1633 struct exportinfo *newexi; 1634 1635 newexi = pseudo_exportfs(exi->exi_vp, &exi->exi_fid, 1636 exi->exi_visible, &exi->exi_export); 1637 exi->exi_visible = NULL; 1638 1639 /* interconnect the existing treenode with the new exportinfo */ 1640 newexi->exi_tree = exi->exi_tree; 1641 newexi->exi_tree->tree_exi = newexi; 1642 } else { 1643 treeclimb_unexport(exi); 1644 } 1645 1646 rw_exit(&exported_lock); 1647 1648 /* 1649 * Need to call into the NFSv4 server and release all data 1650 * held on this particular export. This is important since 1651 * the v4 server may be holding file locks or vnodes under 1652 * this export. 1653 */ 1654 rfs4_clean_state_exi(exi); 1655 1656 /* 1657 * Notify the lock manager that the filesystem is being 1658 * unexported. 1659 */ 1660 lm_unexport(exi); 1661 1662 /* 1663 * If this was a public export, restore 1664 * the public filehandle to the root. 1665 */ 1666 if (exi == exi_public) { 1667 exi_public = exi_root; 1668 1669 nfslog_share_record(exi_public, CRED()); 1670 } 1671 1672 if (exi->exi_export.ex_flags & EX_LOG) { 1673 nfslog_unshare_record(exi, CRED()); 1674 } 1675 1676 exi_rele(exi); 1677 return (0); 1678 } 1679 1680 /* 1681 * Get file handle system call. 1682 * Takes file name and returns a file handle for it. 1683 * Credentials must be verified before calling. 1684 */ 1685 int 1686 nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr) 1687 { 1688 nfs_fh3 fh; 1689 char buf[NFS3_MAXFHSIZE]; 1690 char *logptr, logbuf[NFS3_MAXFHSIZE]; 1691 int l = NFS3_MAXFHSIZE; 1692 vnode_t *vp; 1693 vnode_t *dvp; 1694 struct exportinfo *exi; 1695 int error; 1696 int vers; 1697 STRUCT_HANDLE(nfs_getfh_args, uap); 1698 1699 #ifdef lint 1700 model = model; /* STRUCT macros don't always use it */ 1701 #endif 1702 1703 STRUCT_SET_HANDLE(uap, model, args); 1704 1705 error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE, 1706 FOLLOW, &dvp, &vp); 1707 if (error == EINVAL) { 1708 /* 1709 * if fname resolves to / we get EINVAL error 1710 * since we wanted the parent vnode. Try again 1711 * with NULL dvp. 1712 */ 1713 error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE, 1714 FOLLOW, NULL, &vp); 1715 dvp = NULL; 1716 } 1717 if (!error && vp == NULL) { 1718 /* 1719 * Last component of fname not found 1720 */ 1721 if (dvp != NULL) { 1722 VN_RELE(dvp); 1723 } 1724 error = ENOENT; 1725 } 1726 if (error) 1727 return (error); 1728 1729 /* 1730 * 'vp' may be an AUTOFS node, so we perform a 1731 * VOP_ACCESS() to trigger the mount of the 1732 * intended filesystem, so we can share the intended 1733 * filesystem instead of the AUTOFS filesystem. 1734 */ 1735 (void) VOP_ACCESS(vp, 0, 0, cr, NULL); 1736 1737 /* 1738 * We're interested in the top most filesystem. 1739 * This is specially important when uap->dname is a trigger 1740 * AUTOFS node, since we're really interested in sharing the 1741 * filesystem AUTOFS mounted as result of the VOP_ACCESS() 1742 * call not the AUTOFS node itself. 1743 */ 1744 if (vn_mountedvfs(vp) != NULL) { 1745 if (error = traverse(&vp)) { 1746 VN_RELE(vp); 1747 if (dvp != NULL) 1748 VN_RELE(dvp); 1749 return (error); 1750 } 1751 } 1752 1753 vers = STRUCT_FGET(uap, vers); 1754 exi = nfs_vptoexi(dvp, vp, cr, NULL, &error, FALSE); 1755 if (!error) { 1756 if (vers == NFS_VERSION) { 1757 error = makefh((fhandle_t *)buf, vp, exi); 1758 l = NFS_FHSIZE; 1759 logptr = buf; 1760 } else if (vers == NFS_V3) { 1761 int i, sz, pad; 1762 1763 error = makefh3(&fh, vp, exi); 1764 l = RNDUP(fh.fh3_length); 1765 if (!error && (l > sizeof (fhandle3_t))) 1766 error = EREMOTE; 1767 logptr = logbuf; 1768 if (!error) { 1769 i = 0; 1770 sz = sizeof (fsid_t); 1771 bcopy(&fh.fh3_fsid, &buf[i], sz); 1772 i += sz; 1773 1774 /* 1775 * For backwards compatibility, the 1776 * fid length may be less than 1777 * NFS_FHMAXDATA, but it was always 1778 * encoded as NFS_FHMAXDATA bytes. 1779 */ 1780 1781 sz = sizeof (ushort_t); 1782 bcopy(&fh.fh3_len, &buf[i], sz); 1783 i += sz; 1784 bcopy(fh.fh3_data, &buf[i], fh.fh3_len); 1785 i += fh.fh3_len; 1786 pad = (NFS_FHMAXDATA - fh.fh3_len); 1787 if (pad > 0) { 1788 bzero(&buf[i], pad); 1789 i += pad; 1790 l += pad; 1791 } 1792 1793 sz = sizeof (ushort_t); 1794 bcopy(&fh.fh3_xlen, &buf[i], sz); 1795 i += sz; 1796 bcopy(fh.fh3_xdata, &buf[i], fh.fh3_xlen); 1797 i += fh.fh3_xlen; 1798 pad = (NFS_FHMAXDATA - fh.fh3_xlen); 1799 if (pad > 0) { 1800 bzero(&buf[i], pad); 1801 i += pad; 1802 l += pad; 1803 } 1804 } 1805 /* 1806 * If we need to do NFS logging, the filehandle 1807 * must be downsized to 32 bytes. 1808 */ 1809 if (!error && exi->exi_export.ex_flags & EX_LOG) { 1810 i = 0; 1811 sz = sizeof (fsid_t); 1812 bcopy(&fh.fh3_fsid, &logbuf[i], sz); 1813 i += sz; 1814 sz = sizeof (ushort_t); 1815 bcopy(&fh.fh3_len, &logbuf[i], sz); 1816 i += sz; 1817 sz = NFS_FHMAXDATA; 1818 bcopy(fh.fh3_data, &logbuf[i], sz); 1819 i += sz; 1820 sz = sizeof (ushort_t); 1821 bcopy(&fh.fh3_xlen, &logbuf[i], sz); 1822 i += sz; 1823 sz = NFS_FHMAXDATA; 1824 bcopy(fh.fh3_xdata, &logbuf[i], sz); 1825 i += sz; 1826 } 1827 } 1828 if (!error && exi->exi_export.ex_flags & EX_LOG) { 1829 nfslog_getfh(exi, (fhandle_t *)logptr, 1830 STRUCT_FGETP(uap, fname), UIO_USERSPACE, cr); 1831 } 1832 exi_rele(exi); 1833 if (!error) { 1834 if (copyout(&l, STRUCT_FGETP(uap, lenp), sizeof (int))) 1835 error = EFAULT; 1836 if (copyout(buf, STRUCT_FGETP(uap, fhp), l)) 1837 error = EFAULT; 1838 } 1839 } 1840 VN_RELE(vp); 1841 if (dvp != NULL) { 1842 VN_RELE(dvp); 1843 } 1844 return (error); 1845 } 1846 1847 /* 1848 * Strategy: if vp is in the export list, then 1849 * return the associated file handle. Otherwise, ".." 1850 * once up the vp and try again, until the root of the 1851 * filesystem is reached. 1852 */ 1853 struct exportinfo * 1854 nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk, 1855 int *err, bool_t v4srv) 1856 { 1857 fid_t fid; 1858 int error; 1859 struct exportinfo *exi; 1860 1861 ASSERT(vp); 1862 VN_HOLD(vp); 1863 if (dvp != NULL) { 1864 VN_HOLD(dvp); 1865 } 1866 if (walk != NULL) 1867 *walk = 0; 1868 1869 for (;;) { 1870 bzero(&fid, sizeof (fid)); 1871 fid.fid_len = MAXFIDSZ; 1872 error = vop_fid_pseudo(vp, &fid); 1873 if (error) { 1874 /* 1875 * If vop_fid_pseudo returns ENOSPC then the fid 1876 * supplied is too small. For now we simply 1877 * return EREMOTE. 1878 */ 1879 if (error == ENOSPC) 1880 error = EREMOTE; 1881 break; 1882 } 1883 1884 if (v4srv) 1885 exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); 1886 else 1887 exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid); 1888 1889 if (exi != NULL) { 1890 /* 1891 * Found the export info 1892 */ 1893 break; 1894 } 1895 1896 /* 1897 * We have just failed finding a matching export. 1898 * If we're at the root of this filesystem, then 1899 * it's time to stop (with failure). 1900 */ 1901 if (vp->v_flag & VROOT) { 1902 error = EINVAL; 1903 break; 1904 } 1905 1906 if (walk != NULL) 1907 (*walk)++; 1908 1909 /* 1910 * Now, do a ".." up vp. If dvp is supplied, use it, 1911 * otherwise, look it up. 1912 */ 1913 if (dvp == NULL) { 1914 error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr, 1915 NULL, NULL, NULL); 1916 if (error) 1917 break; 1918 } 1919 VN_RELE(vp); 1920 vp = dvp; 1921 dvp = NULL; 1922 } 1923 VN_RELE(vp); 1924 if (dvp != NULL) { 1925 VN_RELE(dvp); 1926 } 1927 if (error != 0) { 1928 if (err != NULL) 1929 *err = error; 1930 return (NULL); 1931 } 1932 return (exi); 1933 } 1934 1935 int 1936 chk_clnt_sec(exportinfo_t *exi, struct svc_req *req) 1937 { 1938 int i, nfsflavor; 1939 struct secinfo *sp; 1940 1941 /* 1942 * Get the nfs flavor number from xprt. 1943 */ 1944 nfsflavor = (int)(uintptr_t)req->rq_xprt->xp_cookie; 1945 1946 sp = exi->exi_export.ex_secinfo; 1947 for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 1948 if ((nfsflavor == sp[i].s_secinfo.sc_nfsnum) && 1949 SEC_REF_EXPORTED(sp + i)) 1950 return (TRUE); 1951 } 1952 return (FALSE); 1953 } 1954 1955 /* 1956 * Make an fhandle from a vnode 1957 */ 1958 int 1959 makefh(fhandle_t *fh, vnode_t *vp, exportinfo_t *exi) 1960 { 1961 int error; 1962 1963 *fh = exi->exi_fh; /* struct copy */ 1964 1965 error = VOP_FID(vp, (fid_t *)&fh->fh_len, NULL); 1966 if (error) { 1967 /* 1968 * Should be something other than EREMOTE 1969 */ 1970 return (EREMOTE); 1971 } 1972 return (0); 1973 } 1974 1975 /* 1976 * This routine makes an overloaded V2 fhandle which contains 1977 * sec modes. 1978 * 1979 * Note that the first four octets contain the length octet, 1980 * the status octet, and two padded octets to make them XDR 1981 * four-octet aligned. 1982 * 1983 * 1 2 3 4 32 1984 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+ 1985 * | l | s | | | sec_1 |...| sec_n |...| | 1986 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+ 1987 * 1988 * where 1989 * 1990 * the status octet s indicates whether there are more security 1991 * flavors (1 means yes, 0 means no) that require the client to 1992 * perform another 0x81 LOOKUP to get them, 1993 * 1994 * the length octet l is the length describing the number of 1995 * valid octets that follow. (l = 4 * n, where n is the number 1996 * of security flavors sent in the current overloaded filehandle.) 1997 * 1998 * sec_index should always be in the inclusive range: [1 - ex_seccnt], 1999 * and it tells server where to start within the secinfo array. 2000 * Usually it will always be 1; however, if more flavors are used 2001 * for the public export than can be encoded in the overloaded FH 2002 * (7 for NFS2), subsequent SNEGO MCLs will have a larger index 2003 * so the server will pick up where it left off from the previous 2004 * MCL reply. 2005 * 2006 * With NFS4 support, implicitly allowed flavors are also in 2007 * the secinfo array; however, they should not be returned in 2008 * SNEGO MCL replies. 2009 */ 2010 int 2011 makefh_ol(fhandle_t *fh, exportinfo_t *exi, uint_t sec_index) 2012 { 2013 secinfo_t sec[MAX_FLAVORS]; 2014 int totalcnt, i, *ipt, cnt, seccnt, secidx, fh_max_cnt; 2015 char *c; 2016 2017 if (fh == NULL || exi == NULL || sec_index < 1) 2018 return (EREMOTE); 2019 2020 /* 2021 * WebNFS clients need to know the unique set of explicitly 2022 * shared flavors in used for the public export. When 2023 * "TRUE" is passed to build_seclist_nodups(), only explicitly 2024 * shared flavors are included in the list. 2025 */ 2026 seccnt = build_seclist_nodups(&exi->exi_export, sec, TRUE); 2027 if (sec_index > seccnt) 2028 return (EREMOTE); 2029 2030 fh_max_cnt = (NFS_FHSIZE / sizeof (int)) - 1; 2031 totalcnt = seccnt - sec_index + 1; 2032 cnt = totalcnt > fh_max_cnt ? fh_max_cnt : totalcnt; 2033 2034 c = (char *)fh; 2035 /* 2036 * Encode the length octet representing the number of 2037 * security flavors (in bytes) in this overloaded fh. 2038 */ 2039 *c = cnt * sizeof (int); 2040 2041 /* 2042 * Encode the status octet that indicates whether there 2043 * are more security flavors the client needs to get. 2044 */ 2045 *(c + 1) = totalcnt > fh_max_cnt; 2046 2047 /* 2048 * put security flavors in the overloaded fh 2049 */ 2050 ipt = (int *)(c + sizeof (int32_t)); 2051 secidx = sec_index - 1; 2052 for (i = 0; i < cnt; i++) { 2053 ipt[i] = htonl(sec[i + secidx].s_secinfo.sc_nfsnum); 2054 } 2055 return (0); 2056 } 2057 2058 /* 2059 * Make an nfs_fh3 from a vnode 2060 */ 2061 int 2062 makefh3(nfs_fh3 *fh, vnode_t *vp, struct exportinfo *exi) 2063 { 2064 int error; 2065 fid_t fid; 2066 2067 bzero(&fid, sizeof (fid)); 2068 fid.fid_len = MAXFIDSZ; 2069 error = VOP_FID(vp, &fid, NULL); 2070 if (error) 2071 return (EREMOTE); 2072 2073 bzero(fh, sizeof (nfs_fh3)); 2074 fh->fh3_fsid = exi->exi_fsid; 2075 fh->fh3_len = fid.fid_len; 2076 bcopy(fid.fid_data, fh->fh3_data, fh->fh3_len); 2077 fh->fh3_xlen = exi->exi_fid.fid_len; 2078 bcopy(exi->exi_fid.fid_data, fh->fh3_xdata, fh->fh3_xlen); 2079 fh->fh3_length = sizeof (fsid_t) 2080 + sizeof (ushort_t) + fh->fh3_len 2081 + sizeof (ushort_t) + fh->fh3_xlen; 2082 fh->fh3_flags = 0; 2083 return (0); 2084 } 2085 2086 /* 2087 * This routine makes an overloaded V3 fhandle which contains 2088 * sec modes. 2089 * 2090 * 1 4 2091 * +--+--+--+--+ 2092 * | len | 2093 * +--+--+--+--+ 2094 * up to 64 2095 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+ 2096 * |s | | | | sec_1 | sec_2 | ... | sec_n | 2097 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+ 2098 * 2099 * len = 4 * (n+1), where n is the number of security flavors 2100 * sent in the current overloaded filehandle. 2101 * 2102 * the status octet s indicates whether there are more security 2103 * mechanisms (1 means yes, 0 means no) that require the client 2104 * to perform another 0x81 LOOKUP to get them. 2105 * 2106 * Three octets are padded after the status octet. 2107 */ 2108 int 2109 makefh3_ol(nfs_fh3 *fh, struct exportinfo *exi, uint_t sec_index) 2110 { 2111 secinfo_t sec[MAX_FLAVORS]; 2112 int totalcnt, cnt, *ipt, i, seccnt, fh_max_cnt, secidx; 2113 char *c; 2114 2115 if (fh == NULL || exi == NULL || sec_index < 1) 2116 return (EREMOTE); 2117 2118 /* 2119 * WebNFS clients need to know the unique set of explicitly 2120 * shared flavors in used for the public export. When 2121 * "TRUE" is passed to build_seclist_nodups(), only explicitly 2122 * shared flavors are included in the list. 2123 */ 2124 seccnt = build_seclist_nodups(&exi->exi_export, sec, TRUE); 2125 2126 if (sec_index > seccnt) 2127 return (EREMOTE); 2128 2129 fh_max_cnt = (NFS3_FHSIZE / sizeof (int)) - 1; 2130 totalcnt = seccnt - sec_index + 1; 2131 cnt = totalcnt > fh_max_cnt ? fh_max_cnt : totalcnt; 2132 2133 /* 2134 * Place the length in fh3_length representing the number 2135 * of security flavors (in bytes) in this overloaded fh. 2136 */ 2137 fh->fh3_flags = FH_WEBNFS; 2138 fh->fh3_length = (cnt+1) * sizeof (int32_t); 2139 2140 c = (char *)&fh->fh3_u.nfs_fh3_i.fh3_i; 2141 /* 2142 * Encode the status octet that indicates whether there 2143 * are more security flavors the client needs to get. 2144 */ 2145 *c = totalcnt > fh_max_cnt; 2146 2147 /* 2148 * put security flavors in the overloaded fh 2149 */ 2150 secidx = sec_index - 1; 2151 ipt = (int *)(c + sizeof (int32_t)); 2152 for (i = 0; i < cnt; i++) { 2153 ipt[i] = htonl(sec[i + secidx].s_secinfo.sc_nfsnum); 2154 } 2155 return (0); 2156 } 2157 2158 /* 2159 * Make an nfs_fh4 from a vnode 2160 */ 2161 int 2162 makefh4(nfs_fh4 *fh, vnode_t *vp, struct exportinfo *exi) 2163 { 2164 int error; 2165 nfs_fh4_fmt_t *fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val; 2166 fid_t fid; 2167 2168 bzero(&fid, sizeof (fid)); 2169 fid.fid_len = MAXFIDSZ; 2170 /* 2171 * vop_fid_pseudo() is used to set up NFSv4 namespace, so 2172 * use vop_fid_pseudo() here to get the fid instead of VOP_FID. 2173 */ 2174 error = vop_fid_pseudo(vp, &fid); 2175 if (error) 2176 return (error); 2177 2178 fh->nfs_fh4_len = NFS_FH4_LEN; 2179 2180 fh_fmtp->fh4_i.fhx_fsid = exi->exi_fh.fh_fsid; 2181 fh_fmtp->fh4_i.fhx_xlen = exi->exi_fh.fh_xlen; 2182 2183 bzero(fh_fmtp->fh4_i.fhx_data, sizeof (fh_fmtp->fh4_i.fhx_data)); 2184 bzero(fh_fmtp->fh4_i.fhx_xdata, sizeof (fh_fmtp->fh4_i.fhx_xdata)); 2185 bcopy(exi->exi_fh.fh_xdata, fh_fmtp->fh4_i.fhx_xdata, 2186 exi->exi_fh.fh_xlen); 2187 2188 fh_fmtp->fh4_len = fid.fid_len; 2189 ASSERT(fid.fid_len <= sizeof (fh_fmtp->fh4_data)); 2190 bcopy(fid.fid_data, fh_fmtp->fh4_data, fid.fid_len); 2191 fh_fmtp->fh4_flag = 0; 2192 2193 #ifdef VOLATILE_FH_TEST 2194 /* 2195 * XXX (temporary?) 2196 * Use the rnode volatile_id value to add volatility to the fh. 2197 * 2198 * For testing purposes there are currently two scenarios, based 2199 * on whether the filesystem was shared with "volatile_fh" 2200 * or "expire_on_rename". In the first case, use the value of 2201 * export struct share_time as the volatile_id. In the second 2202 * case use the vnode volatile_id value (which is set to the 2203 * time in which the file was renamed). 2204 * 2205 * Note that the above are temporary constructs for testing only 2206 * XXX 2207 */ 2208 if (exi->exi_export.ex_flags & EX_VOLRNM) { 2209 fh_fmtp->fh4_volatile_id = find_volrnm_fh_id(exi, fh); 2210 } else if (exi->exi_export.ex_flags & EX_VOLFH) { 2211 fh_fmtp->fh4_volatile_id = exi->exi_volatile_id; 2212 } else { 2213 fh_fmtp->fh4_volatile_id = 0; 2214 } 2215 #endif /* VOLATILE_FH_TEST */ 2216 2217 return (0); 2218 } 2219 2220 /* 2221 * Convert an fhandle into a vnode. 2222 * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode. 2223 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2224 * are done with it. 2225 */ 2226 vnode_t * 2227 nfs_fhtovp(fhandle_t *fh, struct exportinfo *exi) 2228 { 2229 vfs_t *vfsp; 2230 vnode_t *vp; 2231 int error; 2232 fid_t *fidp; 2233 2234 TRACE_0(TR_FAC_NFS, TR_FHTOVP_START, 2235 "fhtovp_start"); 2236 2237 if (exi == NULL) { 2238 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, 2239 "fhtovp_end:(%S)", "exi NULL"); 2240 return (NULL); /* not exported */ 2241 } 2242 2243 ASSERT(exi->exi_vp != NULL); 2244 2245 if (PUBLIC_FH2(fh)) { 2246 if (exi->exi_export.ex_flags & EX_PUBLIC) { 2247 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, 2248 "fhtovp_end:(%S)", "root not exported"); 2249 return (NULL); 2250 } 2251 vp = exi->exi_vp; 2252 VN_HOLD(vp); 2253 return (vp); 2254 } 2255 2256 vfsp = exi->exi_vp->v_vfsp; 2257 ASSERT(vfsp != NULL); 2258 fidp = (fid_t *)&fh->fh_len; 2259 2260 error = VFS_VGET(vfsp, &vp, fidp); 2261 if (error || vp == NULL) { 2262 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, 2263 "fhtovp_end:(%S)", "VFS_GET failed or vp NULL"); 2264 return (NULL); 2265 } 2266 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, 2267 "fhtovp_end:(%S)", "end"); 2268 return (vp); 2269 } 2270 2271 /* 2272 * Convert an fhandle into a vnode. 2273 * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode. 2274 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2275 * are done with it. 2276 * This is just like nfs_fhtovp() but without the exportinfo argument. 2277 */ 2278 2279 vnode_t * 2280 lm_fhtovp(fhandle_t *fh) 2281 { 2282 register vfs_t *vfsp; 2283 vnode_t *vp; 2284 int error; 2285 2286 vfsp = getvfs(&fh->fh_fsid); 2287 if (vfsp == NULL) 2288 return (NULL); 2289 2290 error = VFS_VGET(vfsp, &vp, (fid_t *)&(fh->fh_len)); 2291 VFS_RELE(vfsp); 2292 if (error || vp == NULL) 2293 return (NULL); 2294 2295 return (vp); 2296 } 2297 2298 /* 2299 * Convert an nfs_fh3 into a vnode. 2300 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode. 2301 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2302 * are done with it. 2303 */ 2304 vnode_t * 2305 nfs3_fhtovp(nfs_fh3 *fh, struct exportinfo *exi) 2306 { 2307 vfs_t *vfsp; 2308 vnode_t *vp; 2309 int error; 2310 fid_t *fidp; 2311 2312 if (exi == NULL) 2313 return (NULL); /* not exported */ 2314 2315 ASSERT(exi->exi_vp != NULL); 2316 2317 if (PUBLIC_FH3(fh)) { 2318 if (exi->exi_export.ex_flags & EX_PUBLIC) 2319 return (NULL); 2320 vp = exi->exi_vp; 2321 VN_HOLD(vp); 2322 return (vp); 2323 } 2324 2325 if (fh->fh3_length < NFS3_OLDFHSIZE || 2326 fh->fh3_length > NFS3_MAXFHSIZE) 2327 return (NULL); 2328 2329 vfsp = exi->exi_vp->v_vfsp; 2330 ASSERT(vfsp != NULL); 2331 fidp = FH3TOFIDP(fh); 2332 2333 error = VFS_VGET(vfsp, &vp, fidp); 2334 if (error || vp == NULL) 2335 return (NULL); 2336 2337 return (vp); 2338 } 2339 2340 /* 2341 * Convert an nfs_fh3 into a vnode. 2342 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode. 2343 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2344 * are done with it. 2345 * BTW: This is just like nfs3_fhtovp() but without the exportinfo arg. 2346 * Also, vfsp is accessed through getvfs() rather using exportinfo !! 2347 */ 2348 2349 vnode_t * 2350 lm_nfs3_fhtovp(nfs_fh3 *fh) 2351 { 2352 vfs_t *vfsp; 2353 vnode_t *vp; 2354 int error; 2355 fid_t *fidp; 2356 2357 if (fh->fh3_length < NFS3_OLDFHSIZE || 2358 fh->fh3_length > NFS3_MAXFHSIZE) 2359 return (NULL); 2360 2361 vfsp = getvfs(&fh->fh3_fsid); 2362 if (vfsp == NULL) 2363 return (NULL); 2364 fidp = FH3TOFIDP(fh); 2365 2366 error = VFS_VGET(vfsp, &vp, fidp); 2367 VFS_RELE(vfsp); 2368 if (error || vp == NULL) 2369 return (NULL); 2370 2371 return (vp); 2372 } 2373 2374 /* 2375 * Convert an nfs_fh4 into a vnode. 2376 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode. 2377 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2378 * are done with it. 2379 */ 2380 vnode_t * 2381 nfs4_fhtovp(nfs_fh4 *fh, struct exportinfo *exi, nfsstat4 *statp) 2382 { 2383 vfs_t *vfsp; 2384 vnode_t *vp = NULL; 2385 int error; 2386 fid_t *fidp; 2387 nfs_fh4_fmt_t *fh_fmtp; 2388 #ifdef VOLATILE_FH_TEST 2389 uint32_t volatile_id = 0; 2390 #endif /* VOLATILE_FH_TEST */ 2391 2392 if (exi == NULL) { 2393 *statp = NFS4ERR_STALE; 2394 return (NULL); /* not exported */ 2395 } 2396 ASSERT(exi->exi_vp != NULL); 2397 2398 /* caller should have checked this */ 2399 ASSERT(fh->nfs_fh4_len >= NFS_FH4_LEN); 2400 2401 fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val; 2402 vfsp = exi->exi_vp->v_vfsp; 2403 ASSERT(vfsp != NULL); 2404 fidp = (fid_t *)&fh_fmtp->fh4_len; 2405 2406 #ifdef VOLATILE_FH_TEST 2407 /* XXX check if volatile - should be changed later */ 2408 if (exi->exi_export.ex_flags & (EX_VOLRNM | EX_VOLFH)) { 2409 /* 2410 * Filesystem is shared with volatile filehandles 2411 */ 2412 if (exi->exi_export.ex_flags & EX_VOLRNM) 2413 volatile_id = find_volrnm_fh_id(exi, fh); 2414 else 2415 volatile_id = exi->exi_volatile_id; 2416 2417 if (fh_fmtp->fh4_volatile_id != volatile_id) { 2418 *statp = NFS4ERR_FHEXPIRED; 2419 return (NULL); 2420 } 2421 } 2422 /* 2423 * XXX even if test_volatile_fh false, the fh may contain a 2424 * volatile id if obtained when the test was set. 2425 */ 2426 fh_fmtp->fh4_volatile_id = (uchar_t)0; 2427 #endif /* VOLATILE_FH_TEST */ 2428 2429 error = VFS_VGET(vfsp, &vp, fidp); 2430 /* 2431 * If we can not get vp from VFS_VGET, perhaps this is 2432 * an nfs v2/v3/v4 node in an nfsv4 pseudo filesystem. 2433 * Check it out. 2434 */ 2435 if (error && PSEUDO(exi)) 2436 error = nfs4_vget_pseudo(exi, &vp, fidp); 2437 2438 if (error || vp == NULL) { 2439 *statp = NFS4ERR_STALE; 2440 return (NULL); 2441 } 2442 /* XXX - disgusting hack */ 2443 if (vp->v_type == VNON && vp->v_flag & V_XATTRDIR) 2444 vp->v_type = VDIR; 2445 *statp = NFS4_OK; 2446 return (vp); 2447 } 2448 2449 /* 2450 * Find the export structure associated with the given filesystem. 2451 * If found, then increment the ref count (exi_count). 2452 */ 2453 struct exportinfo * 2454 checkexport(fsid_t *fsid, fid_t *fid) 2455 { 2456 struct exportinfo *exi; 2457 2458 rw_enter(&exported_lock, RW_READER); 2459 for (exi = exptable[exptablehash(fsid, fid)]; 2460 exi != NULL; 2461 exi = exi->fid_hash.next) { 2462 if (exportmatch(exi, fsid, fid)) { 2463 /* 2464 * If this is the place holder for the 2465 * public file handle, then return the 2466 * real export entry for the public file 2467 * handle. 2468 */ 2469 if (exi->exi_export.ex_flags & EX_PUBLIC) { 2470 exi = exi_public; 2471 } 2472 2473 exi_hold(exi); 2474 rw_exit(&exported_lock); 2475 return (exi); 2476 } 2477 } 2478 rw_exit(&exported_lock); 2479 return (NULL); 2480 } 2481 2482 2483 /* 2484 * "old school" version of checkexport() for NFS4. NFS4 2485 * rfs4_compound holds exported_lock for duration of compound 2486 * processing. This version doesn't manipulate exi_count 2487 * since NFS4 breaks fundamental assumptions in the exi_count 2488 * design. 2489 */ 2490 struct exportinfo * 2491 checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp) 2492 { 2493 struct exportinfo *exi; 2494 2495 ASSERT(RW_LOCK_HELD(&exported_lock)); 2496 2497 for (exi = exptable[exptablehash(fsid, fid)]; 2498 exi != NULL; 2499 exi = exi->fid_hash.next) { 2500 if (exportmatch(exi, fsid, fid)) { 2501 /* 2502 * If this is the place holder for the 2503 * public file handle, then return the 2504 * real export entry for the public file 2505 * handle. 2506 */ 2507 if (exi->exi_export.ex_flags & EX_PUBLIC) { 2508 exi = exi_public; 2509 } 2510 2511 /* 2512 * If vp is given, check if vp is the 2513 * same vnode as the exported node. 2514 * 2515 * Since VOP_FID of a lofs node returns the 2516 * fid of its real node (ufs), the exported 2517 * node for lofs and (pseudo) ufs may have 2518 * the same fsid and fid. 2519 */ 2520 if (vp == NULL || vp == exi->exi_vp) 2521 return (exi); 2522 } 2523 } 2524 2525 return (NULL); 2526 } 2527 2528 /* 2529 * Free an entire export list node 2530 */ 2531 void 2532 exportfree(struct exportinfo *exi) 2533 { 2534 struct exportdata *ex; 2535 struct charset_cache *cache; 2536 2537 ex = &exi->exi_export; 2538 2539 ASSERT(exi->exi_vp != NULL && !(exi->exi_export.ex_flags & EX_PUBLIC)); 2540 VN_RELE(exi->exi_vp); 2541 if (exi->exi_dvp != NULL) 2542 VN_RELE(exi->exi_dvp); 2543 2544 if (ex->ex_flags & EX_INDEX) 2545 kmem_free(ex->ex_index, strlen(ex->ex_index) + 1); 2546 2547 kmem_free(ex->ex_path, ex->ex_pathlen + 1); 2548 nfsauth_cache_free(exi); 2549 2550 /* 2551 * if there is a character set mapping cached, clean it up. 2552 */ 2553 for (cache = exi->exi_charset; cache != NULL; 2554 cache = exi->exi_charset) { 2555 if (cache->inbound != (kiconv_t)-1) 2556 (void) kiconv_close(cache->inbound); 2557 if (cache->outbound != (kiconv_t)-1) 2558 (void) kiconv_close(cache->outbound); 2559 exi->exi_charset = cache->next; 2560 kmem_free(cache, sizeof (struct charset_cache)); 2561 } 2562 2563 if (exi->exi_logbuffer != NULL) 2564 nfslog_disable(exi); 2565 2566 if (ex->ex_flags & EX_LOG) { 2567 kmem_free(ex->ex_log_buffer, ex->ex_log_bufferlen + 1); 2568 kmem_free(ex->ex_tag, ex->ex_taglen + 1); 2569 } 2570 2571 if (exi->exi_visible) 2572 free_visible(exi->exi_visible); 2573 2574 srv_secinfo_list_free(ex->ex_secinfo, ex->ex_seccnt); 2575 2576 #ifdef VOLATILE_FH_TEST 2577 free_volrnm_list(exi); 2578 mutex_destroy(&exi->exi_vol_rename_lock); 2579 #endif /* VOLATILE_FH_TEST */ 2580 2581 mutex_destroy(&exi->exi_lock); 2582 rw_destroy(&exi->exi_cache_lock); 2583 2584 kmem_free(exi, sizeof (*exi)); 2585 } 2586 2587 /* 2588 * load the index file from user space into kernel space. 2589 */ 2590 static int 2591 loadindex(struct exportdata *kex) 2592 { 2593 int error; 2594 char index[MAXNAMELEN+1]; 2595 size_t len; 2596 2597 /* 2598 * copyinstr copies the complete string including the NULL and 2599 * returns the len with the NULL byte included in the calculation 2600 * as long as the max length is not exceeded. 2601 */ 2602 if (error = copyinstr(kex->ex_index, index, sizeof (index), &len)) 2603 return (error); 2604 2605 kex->ex_index = kmem_alloc(len, KM_SLEEP); 2606 bcopy(index, kex->ex_index, len); 2607 2608 return (0); 2609 } 2610 2611 void 2612 exi_hold(struct exportinfo *exi) 2613 { 2614 mutex_enter(&exi->exi_lock); 2615 exi->exi_count++; 2616 mutex_exit(&exi->exi_lock); 2617 } 2618 2619 /* 2620 * When a thread completes using exi, it should call exi_rele(). 2621 * exi_rele() decrements exi_count. It releases exi if exi_count == 0, i.e. 2622 * if this is the last user of exi and exi is not on exportinfo list anymore 2623 */ 2624 void 2625 exi_rele(struct exportinfo *exi) 2626 { 2627 mutex_enter(&exi->exi_lock); 2628 exi->exi_count--; 2629 if (exi->exi_count == 0) { 2630 mutex_exit(&exi->exi_lock); 2631 exportfree(exi); 2632 } else 2633 mutex_exit(&exi->exi_lock); 2634 } 2635 2636 #ifdef VOLATILE_FH_TEST 2637 /* 2638 * Test for volatile fh's - add file handle to list and set its volatile id 2639 * to time it was renamed. If EX_VOLFH is also on and the fs is reshared, 2640 * the vol_rename queue is purged. 2641 * 2642 * XXX This code is for unit testing purposes only... To correctly use it, it 2643 * needs to tie a rename list to the export struct and (more 2644 * important), protect access to the exi rename list using a write lock. 2645 */ 2646 2647 /* 2648 * get the fh vol record if it's in the volatile on rename list. Don't check 2649 * volatile_id in the file handle - compare only the file handles. 2650 */ 2651 static struct ex_vol_rename * 2652 find_volrnm_fh(struct exportinfo *exi, nfs_fh4 *fh4p) 2653 { 2654 struct ex_vol_rename *p = NULL; 2655 fhandle4_t *fhp; 2656 2657 /* XXX shouldn't we assert &exported_lock held? */ 2658 ASSERT(MUTEX_HELD(&exi->exi_vol_rename_lock)); 2659 2660 if (fh4p->nfs_fh4_len != NFS_FH4_LEN) { 2661 return (NULL); 2662 } 2663 fhp = &((nfs_fh4_fmt_t *)fh4p->nfs_fh4_val)->fh4_i; 2664 for (p = exi->exi_vol_rename; p != NULL; p = p->vrn_next) { 2665 if (bcmp(fhp, &p->vrn_fh_fmt.fh4_i, 2666 sizeof (fhandle4_t)) == 0) 2667 break; 2668 } 2669 return (p); 2670 } 2671 2672 /* 2673 * get the volatile id for the fh (if there is - else return 0). Ignore the 2674 * volatile_id in the file handle - compare only the file handles. 2675 */ 2676 static uint32_t 2677 find_volrnm_fh_id(struct exportinfo *exi, nfs_fh4 *fh4p) 2678 { 2679 struct ex_vol_rename *p; 2680 uint32_t volatile_id; 2681 2682 mutex_enter(&exi->exi_vol_rename_lock); 2683 p = find_volrnm_fh(exi, fh4p); 2684 volatile_id = (p ? p->vrn_fh_fmt.fh4_volatile_id : 2685 exi->exi_volatile_id); 2686 mutex_exit(&exi->exi_vol_rename_lock); 2687 return (volatile_id); 2688 } 2689 2690 /* 2691 * Free the volatile on rename list - will be called if a filesystem is 2692 * unshared or reshared without EX_VOLRNM 2693 */ 2694 static void 2695 free_volrnm_list(struct exportinfo *exi) 2696 { 2697 struct ex_vol_rename *p, *pnext; 2698 2699 /* no need to hold mutex lock - this one is called from exportfree */ 2700 for (p = exi->exi_vol_rename; p != NULL; p = pnext) { 2701 pnext = p->vrn_next; 2702 kmem_free(p, sizeof (*p)); 2703 } 2704 exi->exi_vol_rename = NULL; 2705 } 2706 2707 /* 2708 * Add a file handle to the volatile on rename list. 2709 */ 2710 void 2711 add_volrnm_fh(struct exportinfo *exi, vnode_t *vp) 2712 { 2713 struct ex_vol_rename *p; 2714 char fhbuf[NFS4_FHSIZE]; 2715 nfs_fh4 fh4; 2716 int error; 2717 2718 fh4.nfs_fh4_val = fhbuf; 2719 error = makefh4(&fh4, vp, exi); 2720 if ((error) || (fh4.nfs_fh4_len != sizeof (p->vrn_fh_fmt))) { 2721 return; 2722 } 2723 2724 mutex_enter(&exi->exi_vol_rename_lock); 2725 2726 p = find_volrnm_fh(exi, &fh4); 2727 2728 if (p == NULL) { 2729 p = kmem_alloc(sizeof (*p), KM_SLEEP); 2730 bcopy(fh4.nfs_fh4_val, &p->vrn_fh_fmt, sizeof (p->vrn_fh_fmt)); 2731 p->vrn_next = exi->exi_vol_rename; 2732 exi->exi_vol_rename = p; 2733 } 2734 2735 p->vrn_fh_fmt.fh4_volatile_id = gethrestime_sec(); 2736 mutex_exit(&exi->exi_vol_rename_lock); 2737 } 2738 2739 #endif /* VOLATILE_FH_TEST */ 2740