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