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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 * 22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/systm.h> 29 30 #include <nfs/nfs.h> 31 #include <nfs/export.h> 32 #include <sys/cmn_err.h> 33 34 /* 35 * A version of VOP_FID that deals with a remote VOP_FID for nfs. 36 * If vp is an nfs node, nfs4_fid() returns EREMOTE, nfs3_fid() and nfs_fid() 37 * returns the filehandle of vp as its fid. When nfs uses fid to set the 38 * exportinfo filehandle template, a remote nfs filehandle would be too big for 39 * the fid of the exported directory. This routine remaps the value of the 40 * attribute va_nodeid of vp to be the fid of vp, so that the fid can fit. 41 * 42 * We need this fid mainly for setting up NFSv4 server namespace where an 43 * nfs filesystem is also part of it. Thus, need to be able to setup a pseudo 44 * exportinfo for an nfs node. 45 * 46 * e.g. mount an ufs filesystem on an nfs filesystem, then share the ufs 47 * filesystem. (like exporting a local disk from a "diskless" client) 48 */ 49 int 50 vop_fid_pseudo(vnode_t *vp, fid_t *fidp) 51 { 52 struct vattr va; 53 int error; 54 55 error = VOP_FID(vp, fidp); 56 57 /* 58 * XXX nfs4_fid() does nothing and returns EREMOTE. 59 * XXX nfs3_fid()/nfs_fid() returns nfs filehandle as its fid 60 * which has a bigger length than local fid. 61 * NFS_FHMAXDATA_EXT is the size of 62 * fhandle_ext_t.fh_xdata[NFS_FHMAXDATA_EXT]. 63 * 64 * Note: nfs[2,3,4]_fid() only gets called for diskless clients. 65 */ 66 if (error == EREMOTE || 67 (error == 0 && fidp->fid_len > NFS_FHMAXDATA_EXT)) { 68 69 va.va_mask = AT_NODEID; 70 error = VOP_GETATTR(vp, &va, 0, CRED()); 71 if (error) 72 return (error); 73 74 fidp->fid_len = sizeof (va.va_nodeid); 75 bcopy(&va.va_nodeid, fidp->fid_data, fidp->fid_len); 76 return (0); 77 } 78 79 return (error); 80 } 81 82 /* 83 * Get an nfsv4 vnode of the given fid from the visible list of an 84 * nfs filesystem or get the exi_vp if it is the root node. 85 */ 86 int 87 nfs4_vget_pseudo(struct exportinfo *exi, vnode_t **vpp, fid_t *fidp) 88 { 89 fid_t exp_fid; 90 struct exp_visible *visp; 91 int error; 92 93 /* check if the given fid is in the visible list */ 94 95 for (visp = exi->exi_visible; visp; visp = visp->vis_next) { 96 if (EQFID(fidp, &visp->vis_fid)) { 97 VN_HOLD(visp->vis_vp); 98 *vpp = visp->vis_vp; 99 return (0); 100 } 101 } 102 103 /* check if the given fid is the same as the exported node */ 104 105 bzero(&exp_fid, sizeof (exp_fid)); 106 exp_fid.fid_len = MAXFIDSZ; 107 error = vop_fid_pseudo(exi->exi_vp, &exp_fid); 108 if (error) 109 return (error); 110 111 if (EQFID(fidp, &exp_fid)) { 112 VN_HOLD(exi->exi_vp); 113 *vpp = exi->exi_vp; 114 return (0); 115 } 116 117 return (ENOENT); 118 } 119 120 /* 121 * Create a pseudo export entry 122 * 123 * This is an export entry that's created as the 124 * side-effect of a "real" export. As a part of 125 * a real export, the pathname to the export is 126 * checked to see if all the directory components 127 * are accessible via an NFSv4 client, i.e. are 128 * exported. If tree_climb() finds an unexported 129 * mountpoint along the path, then it calls this 130 * function to export it. 131 * 132 * This pseudo export differs from a real export 133 * in restriction on simple. read-only access, 134 * and the addition of a "visible" list of directories. 135 * A real export may have a visible list if it is a root of 136 * a file system and at least one of its subtree resides in 137 * a different file system is shared. 138 * 139 * A visible list is per file system. It resides in the exportinfo 140 * for the pseudo node (VROOT) and it could reside in a real export 141 * of a VROOT node. 142 */ 143 int 144 pseudo_exportfs(vnode_t *vp, struct exp_visible *vis_head, 145 struct exportdata *exdata) 146 { 147 struct exportinfo *exi; 148 struct exportdata *kex; 149 fid_t fid; 150 fsid_t fsid; 151 int error; 152 char *pseudo; 153 154 ASSERT(RW_WRITE_HELD(&exported_lock)); 155 156 /* 157 * Get the vfs id 158 */ 159 bzero(&fid, sizeof (fid)); 160 fid.fid_len = MAXFIDSZ; 161 error = vop_fid_pseudo(vp, &fid); 162 if (error) { 163 /* 164 * If VOP_FID returns ENOSPC then the fid supplied 165 * is too small. For now we simply return EREMOTE. 166 */ 167 if (error == ENOSPC) 168 error = EREMOTE; 169 return (error); 170 } 171 172 fsid = vp->v_vfsp->vfs_fsid; 173 exi = kmem_zalloc(sizeof (*exi), KM_SLEEP); 174 exi->exi_fsid = fsid; 175 exi->exi_fid = fid; 176 exi->exi_vp = vp; 177 VN_HOLD(exi->exi_vp); 178 exi->exi_visible = vis_head; 179 exi->exi_count = 1; 180 exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag & 181 VSW_VOLATILEDEV) ? 1 : 0; 182 mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL); 183 184 /* 185 * Build up the template fhandle 186 */ 187 exi->exi_fh.fh_fsid = fsid; 188 ASSERT(exi->exi_fid.fid_len <= sizeof (exi->exi_fh.fh_xdata)); 189 exi->exi_fh.fh_xlen = exi->exi_fid.fid_len; 190 bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata, 191 exi->exi_fid.fid_len); 192 exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data); 193 194 kex = &exi->exi_export; 195 kex->ex_flags = EX_PSEUDO; 196 197 /* Set up a generic pathname */ 198 199 pseudo = "(pseudo)"; 200 kex->ex_pathlen = strlen(pseudo); 201 kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP); 202 (void) strcpy(kex->ex_path, pseudo); 203 204 /* Transfer the secinfo data from exdata to this new pseudo node */ 205 if (exdata) 206 srv_secinfo_exp2pseu(&exi->exi_export, exdata); 207 208 /* 209 * Initialize auth cache lock 210 */ 211 rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL); 212 213 /* 214 * Insert the new entry at the front of the export list 215 */ 216 export_link(exi); 217 218 return (0); 219 } 220 221 /* 222 * Free a list of visible directories 223 */ 224 void 225 free_visible(struct exp_visible *head) 226 { 227 struct exp_visible *visp, *next; 228 229 for (visp = head; visp; visp = next) { 230 if (visp->vis_vp != NULL) 231 VN_RELE(visp->vis_vp); 232 next = visp->vis_next; 233 kmem_free(visp, sizeof (*visp)); 234 } 235 } 236 237 /* 238 * Add a list of visible directories to a pseudo exportfs. 239 * 240 * When we export a new directory we need to add a new 241 * path segment through the pseudofs to reach the new 242 * directory. This new path is reflected in a list of 243 * directories added to the "visible" list. 244 * 245 * Here there are two lists of visible fids: one hanging off the 246 * pseudo exportinfo, and the one we want to add. It's possible 247 * that the two lists share a common path segment 248 * and have some common directories. We need to combine 249 * the lists so there's no duplicate entries. Where a common 250 * path component is found, the vis_count field is bumped. 251 * 252 * When the addition is complete, the supplied list is freed. 253 */ 254 255 static void 256 more_visible(struct exportinfo *exi, struct exp_visible *vis_head) 257 { 258 struct exp_visible *vp1, *vp2; 259 struct exp_visible *tail, *new; 260 int found; 261 262 /* 263 * If exportinfo doesn't already have a visible 264 * list just assign the entire supplied list. 265 */ 266 if (exi->exi_visible == NULL) { 267 exi->exi_visible = vis_head; 268 return; 269 } 270 271 /* 272 * The outer loop traverses the supplied list. 273 */ 274 for (vp1 = vis_head; vp1; vp1 = vp1->vis_next) { 275 276 /* 277 * Given an element from the list to be added, 278 * search the exportinfo visible list looking for a match. 279 * If a match is found, increment the reference count. 280 */ 281 found = 0; 282 283 for (vp2 = exi->exi_visible; vp2; vp2 = vp2->vis_next) { 284 285 tail = vp2; 286 287 if (EQFID(&vp1->vis_fid, &vp2->vis_fid)) { 288 found = 1; 289 vp2->vis_count++; 290 VN_RELE(vp1->vis_vp); 291 vp1->vis_vp = NULL; 292 293 /* 294 * If the visible struct we want to add 295 * (vp1) has vis_exported set to 1, then 296 * the matching visible struct we just found 297 * must also have it's vis_exported field 298 * set to 1. 299 * 300 * For example, if /export/home was shared 301 * (and a UFS mountpoint), then "export" and 302 * "home" would each have visible structs in 303 * the root pseudo exportinfo. The vis_exported 304 * for home would be 1, and vis_exported for 305 * export would be 0. Now, if /export was 306 * also shared, more_visible would find the 307 * existing visible struct for export, and 308 * see that vis_exported was 0. The code 309 * below will set it to 1. 310 * 311 * vp1 is from vis list passed in (vis_head) 312 * vp2 is from vis list on pseudo exportinfo 313 */ 314 if (vp1->vis_exported && !vp2->vis_exported) 315 vp2->vis_exported = 1; 316 break; 317 } 318 } 319 320 /* If not found - add to the end of the list */ 321 if (! found) { 322 new = kmem_zalloc(sizeof (*new), KM_SLEEP); 323 *new = *vp1; 324 tail->vis_next = new; 325 new->vis_next = NULL; 326 vp1->vis_vp = NULL; 327 } 328 } 329 330 /* 331 * Throw away the path list. vis_vp pointers in vis_head list 332 * are either VN_RELEed or reassigned, and are set to NULL. 333 * There is no need to VN_RELE in free_visible for this vis_head. 334 */ 335 free_visible(vis_head); 336 } 337 338 /* 339 * Remove a list of visible directories from the pseudo exportfs. 340 * 341 * When we unexport a directory, we have to remove path 342 * components from the visible list in the pseudo exportfs 343 * entry. The supplied visible list contains the fids of the path 344 * to the unexported directory. The visible list of the export 345 * is checked against this list any matching fids have their 346 * reference count decremented. If a reference count drops to 347 * zero, then it means no paths now use this directory, so its 348 * fid can be removed from the visible list. 349 * 350 * When the last path is removed, the visible list will be null. 351 */ 352 static void 353 less_visible(struct exportinfo *exi, struct exp_visible *vis_head) 354 { 355 struct exp_visible *vp1, *vp2; 356 struct exp_visible *prev, *next; 357 358 /* 359 * The outer loop traverses the supplied list. 360 */ 361 for (vp1 = vis_head; vp1; vp1 = vp1->vis_next) { 362 363 /* 364 * Given an element from the list to be removed, 365 * search the exportinfo list looking for a match. 366 * If a match is found, decrement the reference 367 * count and drop the element if the count drops 368 * to zero. 369 */ 370 for (vp2 = exi->exi_visible, prev = NULL; vp2; vp2 = next) { 371 372 next = vp2->vis_next; 373 374 if (EQFID(&vp1->vis_fid, &vp2->vis_fid)) { 375 376 /* 377 * Decrement the ref count. 378 * Remove the entry if it's zero. 379 */ 380 if (--vp2->vis_count <= 0) { 381 if (prev == NULL) 382 exi->exi_visible = next; 383 else 384 prev->vis_next = next; 385 386 VN_RELE(vp2->vis_vp); 387 kmem_free(vp2, sizeof (*vp1)); 388 } else { 389 /* 390 * If we're here, then the vp2 will 391 * remain in the vis list. If the 392 * vis entry corresponds to the object 393 * being unshared, then vis_exported 394 * needs to be set to 0. 395 * 396 * vp1 is a node from caller's list 397 * vp2 is node from exportinfo's list 398 * 399 * Only 1 node in the caller's list 400 * will have vis_exported set to 1, 401 * and it corresponds to the obj being 402 * unshared. It should always be the 403 * last element of the caller's list. 404 */ 405 if (vp1->vis_exported && 406 vp2->vis_exported) { 407 vp2->vis_exported = 0; 408 } 409 } 410 411 break; 412 } 413 414 prev = vp2; 415 } 416 } 417 418 free_visible(vis_head); 419 } 420 421 /* 422 * This function checks the path to a new export to 423 * check whether all the pathname components are 424 * exported. It works by climbing the file tree one 425 * component at a time via "..", crossing mountpoints 426 * if necessary until an export entry is found, or the 427 * system root is reached. 428 * 429 * If an unexported mountpoint is found, then 430 * a new pseudo export is added and the pathname from 431 * the mountpoint down to the export is added to the 432 * visible list for the new pseudo export. If an existing 433 * pseudo export is found, then the pathname is added 434 * to its visible list. 435 * 436 * Note that there's some tests for exportdir. 437 * The exportinfo entry that's passed as a parameter 438 * is that of the real export and exportdir is set 439 * for this case. 440 * 441 * Here is an example of a possible setup: 442 * 443 * () - a new fs; fs mount point 444 * EXPORT - a real exported node 445 * PSEUDO - a pseudo node 446 * vis - visible list 447 * f# - security flavor# 448 * (f#) - security flavor# propagated from its decendents 449 * "" - covered vnode 450 * 451 * 452 * / 453 * | 454 * (a) PSEUDO (f1,f2) 455 * | vis: b,b,"c","n" 456 * | 457 * b 458 * ---------|------------------ 459 * | | 460 * (c) EXPORT,f1(f2) (n) PSEUDO (f1,f2) 461 * | vis: "e","d" | vis: m,m,,p,q,"o" 462 * | | 463 * ------------------ ------------------- 464 * | | | | | 465 * (d) (e) f m EXPORT,f1(f2) p 466 * EXPORT EXPORT | | 467 * f1 f2 | | 468 * | | | 469 * j (o) EXPORT,f2 q EXPORT f2 470 * 471 */ 472 int 473 treeclimb_export(struct exportinfo *exip) 474 { 475 vnode_t *dvp, *vp; 476 fid_t fid; 477 int error; 478 int exportdir; 479 struct exportinfo *exi = NULL; 480 struct exp_visible *visp; 481 struct exp_visible *vis_head = NULL; 482 struct vattr va; 483 484 ASSERT(RW_WRITE_HELD(&exported_lock)); 485 486 vp = exip->exi_vp; 487 VN_HOLD(vp); 488 exportdir = 1; 489 490 for (;;) { 491 492 bzero(&fid, sizeof (fid)); 493 fid.fid_len = MAXFIDSZ; 494 error = vop_fid_pseudo(vp, &fid); 495 if (error) 496 break; 497 498 if (! exportdir) { 499 /* 500 * Check if this exportroot is a VROOT dir. If so, 501 * then attach the pseudonodes. If not, then 502 * continue .. traversal until we hit a VROOT 503 * export (pseudo or real). 504 */ 505 exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); 506 if (exi != NULL && vp->v_flag & VROOT) { 507 /* 508 * Found an export info 509 * 510 * Extend the list of visible 511 * directories whether it's a pseudo 512 * or a real export. 513 */ 514 more_visible(exi, vis_head); 515 vis_head = NULL; 516 break; /* and climb no further */ 517 } 518 } 519 520 /* 521 * If at the root of the filesystem, need 522 * to traverse across the mountpoint 523 * and continue the climb on the mounted-on 524 * filesystem. 525 */ 526 if (vp->v_flag & VROOT) { 527 528 if (! exportdir) { 529 /* 530 * Found the root directory of a filesystem 531 * that isn't exported. Need to export 532 * this as a pseudo export so that an NFS v4 533 * client can do lookups in it. 534 */ 535 error = pseudo_exportfs(vp, vis_head, NULL); 536 if (error) 537 break; 538 vis_head = NULL; 539 } 540 541 if (VN_CMP(vp, rootdir)) { 542 /* at system root */ 543 break; 544 } 545 546 vp = untraverse(vp); 547 exportdir = 0; 548 continue; 549 } 550 551 /* 552 * Do a getattr to obtain the nodeid (inode num) 553 * for this vnode. 554 */ 555 va.va_mask = AT_NODEID; 556 error = VOP_GETATTR(vp, &va, 0, CRED()); 557 if (error) 558 break; 559 560 /* 561 * Add this directory fid to visible list 562 */ 563 visp = kmem_alloc(sizeof (*visp), KM_SLEEP); 564 VN_HOLD(vp); 565 visp->vis_vp = vp; 566 visp->vis_fid = fid; /* structure copy */ 567 visp->vis_ino = va.va_nodeid; 568 visp->vis_count = 1; 569 visp->vis_exported = exportdir; 570 visp->vis_next = vis_head; 571 vis_head = visp; 572 573 /* 574 * Now, do a ".." to find parent dir of vp. 575 */ 576 error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED()); 577 578 if (error == ENOTDIR && exportdir) { 579 dvp = exip->exi_dvp; 580 ASSERT(dvp != NULL); 581 VN_HOLD(dvp); 582 error = 0; 583 } 584 585 if (error) 586 break; 587 588 exportdir = 0; 589 VN_RELE(vp); 590 vp = dvp; 591 } 592 593 VN_RELE(vp); 594 return (error); 595 } 596 597 /* 598 * Walk up the tree looking for pseudo export entries. 599 * 600 * If a pseudo export is found, remove the path we've 601 * climbed from its visible list. If the visible list 602 * still has entries after the removal, then we can stop. 603 * If it becomes null, then remove the pseudo export entry 604 * and carry on up the tree to see if there's any more. 605 */ 606 int 607 treeclimb_unexport(struct exportinfo *exip) 608 { 609 vnode_t *dvp, *vp; 610 fid_t fid; 611 int error = 0; 612 int exportdir; 613 struct exportinfo *exi = NULL; 614 struct exp_visible *vis_head = NULL, *visp; 615 616 ASSERT(RW_WRITE_HELD(&exported_lock)); 617 618 exportdir = 1; 619 vp = exip->exi_vp; 620 VN_HOLD(vp); 621 622 for (;;) { 623 624 bzero(&fid, sizeof (fid)); 625 fid.fid_len = MAXFIDSZ; 626 error = vop_fid_pseudo(vp, &fid); 627 if (error) 628 break; 629 630 if (! exportdir) { 631 632 /* 633 * We need to use checkexport4() here because it 634 * doesn't acquire exported_lock and it doesn't 635 * manipulate exi_count. 636 * 637 * Remove directories from the visible 638 * list that are unique to the path 639 * for this export. (Only VROOT exportinfos 640 * have can have visible entries). 641 */ 642 exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); 643 if (exi != NULL && (vp->v_flag & VROOT)) { 644 645 less_visible(exi, vis_head); 646 vis_head = NULL; 647 648 /* 649 * If the visible list has entries 650 * or if it's a real export, then 651 * there's no need to keep climbing. 652 */ 653 if (exi->exi_visible || ! PSEUDO(exi)) 654 break; 655 656 /* 657 * Otherwise, we have a pseudo export 658 * with an empty list (no exports below 659 * it) so we must remove and continue 660 * the climb to remove its name from 661 * the parent export. 662 */ 663 error = export_unlink(&vp->v_vfsp->vfs_fsid, 664 &fid, vp, NULL); 665 if (error) 666 break; 667 668 exi_rele(exi); 669 } 670 } 671 672 /* 673 * If at the root of the filesystem, need 674 * to traverse across the mountpoint 675 * and continue the climb on the mounted-on 676 * filesystem. 677 */ 678 if (vp->v_flag & VROOT) { 679 if (VN_CMP(vp, rootdir)) { 680 /* at system root */ 681 break; 682 } 683 vp = untraverse(vp); 684 exportdir = 0; 685 continue; 686 } 687 688 /* 689 * Add this directory fid to path list 690 */ 691 visp = kmem_alloc(sizeof (*visp), KM_SLEEP); 692 VN_HOLD(vp); 693 visp->vis_vp = vp; 694 visp->vis_fid = fid; /* structure copy */ 695 visp->vis_ino = 0; 696 visp->vis_count = 1; 697 visp->vis_exported = exportdir; 698 visp->vis_next = vis_head; 699 vis_head = visp; 700 701 /* 702 * Do a ".." to find parent dir of vp. 703 */ 704 error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED()); 705 706 if (error == ENOTDIR && exportdir) { 707 dvp = exip->exi_dvp; 708 ASSERT(dvp != NULL); 709 VN_HOLD(dvp); 710 error = 0; 711 } 712 if (error) 713 break; 714 715 exportdir = 0; 716 VN_RELE(vp); 717 vp = dvp; 718 } 719 720 VN_RELE(vp); 721 return (error); 722 } 723 724 725 /* 726 * Traverse backward across mountpoint from the 727 * root vnode of a filesystem to its mounted-on 728 * vnode. 729 */ 730 vnode_t * 731 untraverse(vnode_t *vp) 732 { 733 vnode_t *tvp, *nextvp; 734 735 tvp = vp; 736 for (;;) { 737 if (! (tvp->v_flag & VROOT)) 738 break; 739 740 /* lock vfs to prevent unmount of this vfs */ 741 vfs_lock_wait(tvp->v_vfsp); 742 743 if ((nextvp = tvp->v_vfsp->vfs_vnodecovered) == NULL) { 744 vfs_unlock(tvp->v_vfsp); 745 break; 746 } 747 748 /* 749 * Hold nextvp to prevent unmount. After unlock vfs and 750 * rele tvp, any number of overlays could be unmounted. 751 * Putting a hold on vfs_vnodecovered will only allow 752 * tvp's vfs to be unmounted. Of course if caller placed 753 * extra hold on vp before calling untraverse, the following 754 * hold would not be needed. Since prev actions of caller 755 * are unknown, we need to hold here just to be safe. 756 */ 757 VN_HOLD(nextvp); 758 vfs_unlock(tvp->v_vfsp); 759 VN_RELE(tvp); 760 tvp = nextvp; 761 } 762 763 return (tvp); 764 } 765 766 /* 767 * Given an exportinfo, climb up to find the exportinfo for the VROOT 768 * of the filesystem. 769 * 770 * e.g. / 771 * | 772 * a (VROOT) pseudo-exportinfo 773 * | 774 * b 775 * | 776 * c #share /a/b/c 777 * | 778 * d 779 * 780 * where c is in the same filesystem as a. 781 * So, get_root_export(*exportinfo_for_c) returns exportinfo_for_a 782 * 783 * If d is shared, then c will be put into a's visible list. 784 * Note: visible list is per filesystem and is attached to the 785 * VROOT exportinfo. 786 */ 787 struct exportinfo * 788 get_root_export(struct exportinfo *exip) 789 { 790 vnode_t *dvp, *vp; 791 fid_t fid; 792 struct exportinfo *exi = exip; 793 int error; 794 795 vp = exi->exi_vp; 796 VN_HOLD(vp); 797 798 for (;;) { 799 800 if (vp->v_flag & VROOT) { 801 ASSERT(exi != NULL); 802 break; 803 } 804 805 /* 806 * Now, do a ".." to find parent dir of vp. 807 */ 808 error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED()); 809 810 if (error) { 811 exi = NULL; 812 break; 813 } 814 815 VN_RELE(vp); 816 vp = dvp; 817 818 bzero(&fid, sizeof (fid)); 819 fid.fid_len = MAXFIDSZ; 820 error = vop_fid_pseudo(vp, &fid); 821 if (error) { 822 exi = NULL; 823 break; 824 } 825 826 exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); 827 } 828 829 VN_RELE(vp); 830 return (exi); 831 } 832 833 /* 834 * Return true if the supplied vnode has a sub-directory exported. 835 */ 836 int 837 has_visible(struct exportinfo *exi, vnode_t *vp) 838 { 839 struct exp_visible *visp; 840 fid_t fid; 841 bool_t vp_is_exported; 842 843 vp_is_exported = VN_CMP(vp, exi->exi_vp); 844 845 /* 846 * An exported root vnode has a sub-dir shared if it has a visible list. 847 * i.e. if it does not have a visible list, then there is no node in 848 * this filesystem leads to any other shared node. 849 */ 850 if (vp_is_exported && (vp->v_flag & VROOT)) 851 return (exi->exi_visible ? 1 : 0); 852 853 /* 854 * Only the exportinfo of a fs root node may have a visible list. 855 * Either it is a pseudo root node, or a real exported root node. 856 */ 857 if ((exi = get_root_export(exi)) == NULL) { 858 return (0); 859 } 860 861 if (!exi->exi_visible) 862 return (0); 863 864 /* Get the fid of the vnode */ 865 bzero(&fid, sizeof (fid)); 866 fid.fid_len = MAXFIDSZ; 867 if (vop_fid_pseudo(vp, &fid) != 0) { 868 return (0); 869 } 870 871 /* 872 * See if vp is in the visible list of the root node exportinfo. 873 */ 874 for (visp = exi->exi_visible; visp; visp = visp->vis_next) { 875 if (EQFID(&fid, &visp->vis_fid)) { 876 /* 877 * If vp is an exported non-root node with only 1 path 878 * count (for itself), it indicates no sub-dir shared 879 * using this vp as a path. 880 */ 881 if (vp_is_exported && visp->vis_count < 2) 882 break; 883 884 return (1); 885 } 886 } 887 888 return (0); 889 } 890 891 /* 892 * Returns true if the supplied vnode is visible 893 * in this export. If vnode is visible, return 894 * vis_exported in expseudo. 895 */ 896 int 897 nfs_visible(struct exportinfo *exi, vnode_t *vp, int *expseudo) 898 { 899 struct exp_visible *visp; 900 fid_t fid; 901 902 /* 903 * First check to see if vp is export root. 904 * 905 * A pseudo export root can never be exported 906 * (it would be a real export then); however, 907 * it is always visible. If a pseudo root object 908 * was exported by server admin, then the entire 909 * pseudo exportinfo (and all visible entries) would 910 * be destroyed. A pseudo exportinfo only exists 911 * to provide access to real (descendant) export(s). 912 * 913 * Previously, rootdir was special cased here; however, 914 * the export root special case handles the rootdir 915 * case also. 916 */ 917 if (VN_CMP(vp, exi->exi_vp)) { 918 *expseudo = 0; 919 return (1); 920 } 921 922 /* 923 * Only a PSEUDO node has a visible list or an exported VROOT 924 * node may have a visible list. 925 */ 926 if (! PSEUDO(exi) && (exi = get_root_export(exi)) == NULL) { 927 *expseudo = 0; 928 return (0); 929 } 930 931 /* Get the fid of the vnode */ 932 933 bzero(&fid, sizeof (fid)); 934 fid.fid_len = MAXFIDSZ; 935 if (vop_fid_pseudo(vp, &fid) != 0) { 936 *expseudo = 0; 937 return (0); 938 } 939 940 /* 941 * We can't trust VN_CMP() above because of LOFS. 942 * Even though VOP_CMP will do the right thing for LOFS 943 * objects, VN_CMP will short circuit out early when the 944 * vnode ops ptrs are different. Just in case we're dealing 945 * with LOFS, compare exi_fid/fsid here. 946 * 947 * expseudo is not set because this is not an export 948 */ 949 if (EQFID(&exi->exi_fid, &fid) && 950 EQFSID(&exi->exi_fsid, &vp->v_vfsp->vfs_fsid)) { 951 *expseudo = 0; 952 return (1); 953 } 954 955 956 /* See if it matches any fid in the visible list */ 957 958 for (visp = exi->exi_visible; visp; visp = visp->vis_next) { 959 if (EQFID(&fid, &visp->vis_fid)) { 960 *expseudo = visp->vis_exported; 961 return (1); 962 } 963 } 964 965 *expseudo = 0; 966 967 return (0); 968 } 969 970 /* 971 * Returns true if the supplied vnode is the 972 * directory of an export point. 973 */ 974 int 975 nfs_exported(struct exportinfo *exi, vnode_t *vp) 976 { 977 struct exp_visible *visp; 978 fid_t fid; 979 980 /* 981 * First check to see if vp is the export root 982 * This check required for the case of lookup .. 983 * where .. is a V_ROOT vnode and a pseudo exportroot. 984 * Pseudo export root objects do not have an entry 985 * in the visible list even though every V_ROOT 986 * pseudonode is visible. It is safe to compare 987 * vp here because pseudo_exportfs put a hold on 988 * it when exi_vp was initialized. 989 * 990 * Note: VN_CMP() won't match for LOFS shares, but they're 991 * handled below w/EQFID/EQFSID. 992 */ 993 if (VN_CMP(vp, exi->exi_vp)) 994 return (1); 995 996 /* Get the fid of the vnode */ 997 998 bzero(&fid, sizeof (fid)); 999 fid.fid_len = MAXFIDSZ; 1000 if (vop_fid_pseudo(vp, &fid) != 0) 1001 return (0); 1002 1003 if (EQFID(&fid, &exi->exi_fid) && 1004 EQFSID(&vp->v_vfsp->vfs_fsid, &exi->exi_fsid)) { 1005 return (1); 1006 } 1007 1008 /* See if it matches any fid in the visible list */ 1009 1010 for (visp = exi->exi_visible; visp; visp = visp->vis_next) { 1011 if (EQFID(&fid, &visp->vis_fid)) 1012 return (visp->vis_exported); 1013 } 1014 1015 return (0); 1016 } 1017 1018 /* 1019 * Returns true if the supplied inode is visible 1020 * in this export. This function is used by 1021 * readdir which uses inode numbers from the 1022 * directory. 1023 * 1024 * NOTE: this code does not match inode number for ".", 1025 * but it isn't required because NFS4 server rddir 1026 * skips . and .. entries. 1027 */ 1028 int 1029 nfs_visible_inode(struct exportinfo *exi, ino64_t ino, int *expseudo) 1030 { 1031 struct exp_visible *visp; 1032 1033 /* 1034 * Only a PSEUDO node has a visible list or an exported VROOT 1035 * node may have a visible list. 1036 */ 1037 if (! PSEUDO(exi) && (exi = get_root_export(exi)) == NULL) { 1038 *expseudo = 0; 1039 return (0); 1040 } 1041 1042 for (visp = exi->exi_visible; visp; visp = visp->vis_next) 1043 if ((u_longlong_t)ino == visp->vis_ino) { 1044 *expseudo = visp->vis_exported; 1045 return (1); 1046 } 1047 1048 *expseudo = 0; 1049 return (0); 1050 } 1051