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