801         sip->next = NULL;
 802         sip->prev = NULL;
 803 
 804         rw_init(&sip->oldstate_lock, NULL, RW_DEFAULT, NULL);
 805         /*
 806          * This initial dummy entry is required to setup for insque/remque.
 807          * It must be skipped over whenever the list is traversed.
 808          */
 809         oldstate = kmem_alloc(sizeof (rfs4_oldstate_t), KM_SLEEP);
 810         /* insque/remque require initial list entry to be self-terminated */
 811         oldstate->next = oldstate;
 812         oldstate->prev = oldstate;
 813         sip->oldstate = oldstate;
 814 
 815 
 816         sip->dss_npaths = dss_npaths;
 817         sip->dss_paths = kmem_alloc(dss_npaths *
 818             sizeof (rfs4_dss_path_t *), KM_SLEEP);
 819 
 820         for (i = 0; i < dss_npaths; i++) {
 821                 /* CSTYLED */
 822                 sip->dss_paths[i] = rfs4_dss_newpath(nsrv4, sip, dss_paths[i], i);
 823         }
 824 
 825         mutex_enter(&nsrv4->servinst_lock);
 826         if (nsrv4->nfs4_cur_servinst != NULL) {
 827                 /* add to linked list */
 828                 sip->prev = nsrv4->nfs4_cur_servinst;
 829                 nsrv4->nfs4_cur_servinst->next = sip;
 830         }
 831         if (start_grace)
 832                 rfs4_grace_start(sip);
 833         /* make the new instance "current" */
 834         nsrv4->nfs4_cur_servinst = sip;
 835 
 836         mutex_exit(&nsrv4->servinst_lock);
 837 }
 838 
 839 /*
 840  * In future, we might add a rfs4_servinst_destroy(sip) but, for now, destroy
 841  * all instances directly.
 842  */
 843 void
 844 rfs4_servinst_destroy_all(nfs4_srv_t *nsrv4)
 845 {
 846         rfs4_servinst_t *sip, *prev, *current;
 847 #ifdef DEBUG
 848         int n = 0;
 849 #endif
 850 
 851         mutex_enter(&nsrv4->servinst_lock);
 852         ASSERT(nsrv4->nfs4_cur_servinst != NULL);
 853         current = nsrv4->nfs4_cur_servinst;
 854         nsrv4->nfs4_cur_servinst = NULL;
 855         for (sip = current; sip != NULL; sip = prev) {
 856                 prev = sip->prev;
 857                 rw_destroy(&sip->rwlock);
 858                 if (sip->oldstate)
 859                         kmem_free(sip->oldstate, sizeof (rfs4_oldstate_t));
 860                 if (sip->dss_paths)
 861                         kmem_free(sip->dss_paths,
 862                             sip->dss_npaths * sizeof (rfs4_dss_path_t *));
 863                 kmem_free(sip, sizeof (rfs4_servinst_t));
 864 #ifdef DEBUG
 865                 n++;
 866 #endif
 867         }
 868         mutex_exit(&nsrv4->servinst_lock);
 869 }
 870 
 871 /*
 872  * Assign the current server instance to a client_t.
 873  * Should be called with cp->rc_dbe held.
 874  */
 875 void
 876 rfs4_servinst_assign(nfs4_srv_t *nsrv4, rfs4_client_t *cp,
 877     rfs4_servinst_t *sip)
 878 {
 879         ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0);
 880 
 881         /*
 882          * The lock ensures that if the current instance is in the process
 
 920 {
 921         int i;
 922 
 923         for (i = 0; i < count; i++) {
 924                 if (nfsnum == flavor_list[i])
 925                         return (TRUE);
 926         }
 927         return (FALSE);
 928 }
 929 
 930 /*
 931  * Used by rfs4_op_secinfo to get the security information from the
 932  * export structure associated with the component.
 933  */
 934 /* ARGSUSED */
 935 static nfsstat4
 936 do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
 937 {
 938         int error, different_export = 0;
 939         vnode_t *dvp, *vp;
 940         struct exportinfo *exi = NULL;
 941         fid_t fid;
 942         uint_t count, i;
 943         secinfo4 *resok_val;
 944         struct secinfo *secp;
 945         seconfig_t *si;
 946         bool_t did_traverse = FALSE;
 947         int dotdot, walk;
 948         nfs_export_t *ne = nfs_get_export();
 949 
 950         dvp = cs->vp;
 951         dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0');
 952 
 953         /*
 954          * If dotdotting, then need to check whether it's above the
 955          * root of a filesystem, or above an export point.
 956          */
 957         if (dotdot) {
 958 
 959                 /*
 960                  * If dotdotting at the root of a filesystem, then
 961                  * need to traverse back to the mounted-on filesystem
 962                  * and do the dotdot lookup there.
 963                  */
 964                 if (cs->vp->v_flag & VROOT) {
 965 
 966                         /*
 967                          * If at the system root, then can
 968                          * go up no further.
 969                          */
 970                         if (VN_CMP(dvp, ZONE_ROOTVP()))
 971                                 return (puterrno4(ENOENT));
 972 
 973                         /*
 974                          * Traverse back to the mounted-on filesystem
 975                          */
 976                         dvp = untraverse(cs->vp);
 977 
 978                         /*
 979                          * Set the different_export flag so we remember
 980                          * to pick up a new exportinfo entry for
 981                          * this new filesystem.
 982                          */
 983                         different_export = 1;
 984                 } else {
 985 
 986                         /*
 987                          * If dotdotting above an export point then set
 988                          * the different_export to get new export info.
 989                          */
 990                         different_export = nfs_exported(cs->exi, cs->vp);
 991                 }
 992         }
 993 
 994         /*
 995          * Get the vnode for the component "nm".
 996          */
 997         error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cs->cr,
 998             NULL, NULL, NULL);
 999         if (error)
1000                 return (puterrno4(error));
1001 
1002         /*
1003          * If the vnode is in a pseudo filesystem, or if the security flavor
1004          * used in the request is valid but not an explicitly shared flavor,
1005          * or the access bit indicates that this is a limited access,
1006          * check whether this vnode is visible.
1007          */
1008         if (!different_export &&
1009             (PSEUDO(cs->exi) || ! is_exported_sec(cs->nfsflavor, cs->exi) ||
1010             cs->access & CS_ACCESS_LIMITED)) {
1011                 if (! nfs_visible(cs->exi, vp, &different_export)) {
1012                         VN_RELE(vp);
1013                         return (puterrno4(ENOENT));
1014                 }
1015         }
1016 
1017         /*
1018          * If it's a mountpoint, then traverse it.
1019          */
1020         if (vn_ismntpt(vp)) {
1021                 if ((error = traverse(&vp)) != 0) {
1022                         VN_RELE(vp);
1023                         return (puterrno4(error));
1024                 }
1025                 /* remember that we had to traverse mountpoint */
1026                 did_traverse = TRUE;
1027                 different_export = 1;
1028         } else if (vp->v_vfsp != dvp->v_vfsp) {
1029                 /*
1030                  * If vp isn't a mountpoint and the vfs ptrs aren't the same,
1031                  * then vp is probably an LOFS object.  We don't need the
 
1033                  * a server fs boundary and need to call checkexport4.
1034                  * (LOFS lookup hides server fs mountpoints, and actually calls
1035                  * traverse)
1036                  */
1037                 different_export = 1;
1038         }
1039 
1040         /*
1041          * Get the export information for it.
1042          */
1043         if (different_export) {
1044 
1045                 bzero(&fid, sizeof (fid));
1046                 fid.fid_len = MAXFIDSZ;
1047                 error = vop_fid_pseudo(vp, &fid);
1048                 if (error) {
1049                         VN_RELE(vp);
1050                         return (puterrno4(error));
1051                 }
1052 
1053                 if (dotdot)
1054                         exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
1055                 else
1056                         exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
1057 
1058                 if (exi == NULL) {
1059                         if (did_traverse == TRUE) {
1060                                 /*
1061                                  * If this vnode is a mounted-on vnode,
1062                                  * but the mounted-on file system is not
1063                                  * exported, send back the secinfo for
1064                                  * the exported node that the mounted-on
1065                                  * vnode lives in.
1066                                  */
1067                                 exi = cs->exi;
1068                         } else {
1069                                 VN_RELE(vp);
1070                                 return (puterrno4(EACCES));
1071                         }
1072                 }
1073         } else {
1074                 exi = cs->exi;
1075         }
1076         ASSERT(exi != NULL);
1077 
1078 
1079         /*
1080          * Create the secinfo result based on the security information
1081          * from the exportinfo structure (exi).
1082          *
1083          * Return all flavors for a pseudo node.
1084          * For a real export node, return the flavor that the client
1085          * has access with.
1086          */
1087         ASSERT(RW_LOCK_HELD(&ne->exported_lock));
1088         if (PSEUDO(exi)) {
1089                 count = exi->exi_export.ex_seccnt; /* total sec count */
1090                 resok_val = kmem_alloc(count * sizeof (secinfo4), KM_SLEEP);
1091                 secp = exi->exi_export.ex_secinfo;
1092 
1093                 for (i = 0; i < count; i++) {
1094                         si = &secp[i].s_secinfo;
 
2685         fid_t fid;
2686         int attrdir, dotdot, walk;
2687         bool_t is_newvp = FALSE;
2688 
2689         if (cs->vp->v_flag & V_XATTRDIR) {
2690                 attrdir = 1;
2691                 ASSERT(get_fh4_flag(&cs->fh, FH4_ATTRDIR));
2692         } else {
2693                 attrdir = 0;
2694                 ASSERT(! get_fh4_flag(&cs->fh, FH4_ATTRDIR));
2695         }
2696 
2697         dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0');
2698 
2699         /*
2700          * If dotdotting, then need to check whether it's
2701          * above the root of a filesystem, or above an
2702          * export point.
2703          */
2704         if (dotdot) {
2705 
2706                 /*
2707                  * If dotdotting at the root of a filesystem, then
2708                  * need to traverse back to the mounted-on filesystem
2709                  * and do the dotdot lookup there.
2710                  */
2711                 if (cs->vp->v_flag & VROOT) {
2712 
2713                         /*
2714                          * If at the system root, then can
2715                          * go up no further.
2716                          */
2717                         if (VN_CMP(cs->vp, ZONE_ROOTVP()))
2718                                 return (puterrno4(ENOENT));
2719 
2720                         /*
2721                          * Traverse back to the mounted-on filesystem
2722                          */
2723                         cs->vp = untraverse(cs->vp);
2724 
2725                         /*
2726                          * Set the different_export flag so we remember
2727                          * to pick up a new exportinfo entry for
2728                          * this new filesystem.
2729                          */
2730                         different_export = 1;
2731                 } else {
 
 | 
 
 
 801         sip->next = NULL;
 802         sip->prev = NULL;
 803 
 804         rw_init(&sip->oldstate_lock, NULL, RW_DEFAULT, NULL);
 805         /*
 806          * This initial dummy entry is required to setup for insque/remque.
 807          * It must be skipped over whenever the list is traversed.
 808          */
 809         oldstate = kmem_alloc(sizeof (rfs4_oldstate_t), KM_SLEEP);
 810         /* insque/remque require initial list entry to be self-terminated */
 811         oldstate->next = oldstate;
 812         oldstate->prev = oldstate;
 813         sip->oldstate = oldstate;
 814 
 815 
 816         sip->dss_npaths = dss_npaths;
 817         sip->dss_paths = kmem_alloc(dss_npaths *
 818             sizeof (rfs4_dss_path_t *), KM_SLEEP);
 819 
 820         for (i = 0; i < dss_npaths; i++) {
 821                 sip->dss_paths[i] =
 822                     rfs4_dss_newpath(nsrv4, sip, dss_paths[i], i);
 823         }
 824 
 825         mutex_enter(&nsrv4->servinst_lock);
 826         if (nsrv4->nfs4_cur_servinst != NULL) {
 827                 /* add to linked list */
 828                 sip->prev = nsrv4->nfs4_cur_servinst;
 829                 nsrv4->nfs4_cur_servinst->next = sip;
 830         }
 831         if (start_grace)
 832                 rfs4_grace_start(sip);
 833         /* make the new instance "current" */
 834         nsrv4->nfs4_cur_servinst = sip;
 835 
 836         mutex_exit(&nsrv4->servinst_lock);
 837 }
 838 
 839 /*
 840  * In future, we might add a rfs4_servinst_destroy(sip) but, for now, destroy
 841  * all instances directly.
 842  */
 843 void
 844 rfs4_servinst_destroy_all(nfs4_srv_t *nsrv4)
 845 {
 846         rfs4_servinst_t *sip, *prev, *current;
 847 #ifdef DEBUG
 848         int n = 0;
 849 #endif
 850 
 851         mutex_enter(&nsrv4->servinst_lock);
 852         ASSERT(nsrv4->nfs4_cur_servinst != NULL);
 853         current = nsrv4->nfs4_cur_servinst;
 854         nsrv4->nfs4_cur_servinst = NULL;
 855         for (sip = current; sip != NULL; sip = prev) {
 856                 prev = sip->prev;
 857                 rw_destroy(&sip->rwlock);
 858                 if (sip->oldstate)
 859                         kmem_free(sip->oldstate, sizeof (rfs4_oldstate_t));
 860                 if (sip->dss_paths) {
 861                         int i = sip->dss_npaths;
 862 
 863                         while (i > 0) {
 864                                 i--;
 865                                 if (sip->dss_paths[i] != NULL) {
 866                                         char *path = sip->dss_paths[i]->path;
 867 
 868                                         if (path != NULL) {
 869                                                 kmem_free(path,
 870                                                     strlen(path) + 1);
 871                                         }
 872                                         kmem_free(sip->dss_paths[i],
 873                                             sizeof (rfs4_dss_path_t));
 874                                 }
 875                         }
 876                         kmem_free(sip->dss_paths,
 877                             sip->dss_npaths * sizeof (rfs4_dss_path_t *));
 878                 }
 879                 kmem_free(sip, sizeof (rfs4_servinst_t));
 880 #ifdef DEBUG
 881                 n++;
 882 #endif
 883         }
 884         mutex_exit(&nsrv4->servinst_lock);
 885 }
 886 
 887 /*
 888  * Assign the current server instance to a client_t.
 889  * Should be called with cp->rc_dbe held.
 890  */
 891 void
 892 rfs4_servinst_assign(nfs4_srv_t *nsrv4, rfs4_client_t *cp,
 893     rfs4_servinst_t *sip)
 894 {
 895         ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0);
 896 
 897         /*
 898          * The lock ensures that if the current instance is in the process
 
 936 {
 937         int i;
 938 
 939         for (i = 0; i < count; i++) {
 940                 if (nfsnum == flavor_list[i])
 941                         return (TRUE);
 942         }
 943         return (FALSE);
 944 }
 945 
 946 /*
 947  * Used by rfs4_op_secinfo to get the security information from the
 948  * export structure associated with the component.
 949  */
 950 /* ARGSUSED */
 951 static nfsstat4
 952 do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
 953 {
 954         int error, different_export = 0;
 955         vnode_t *dvp, *vp;
 956         struct exportinfo *exi;
 957         fid_t fid;
 958         uint_t count, i;
 959         secinfo4 *resok_val;
 960         struct secinfo *secp;
 961         seconfig_t *si;
 962         bool_t did_traverse = FALSE;
 963         int dotdot, walk;
 964         nfs_export_t *ne = nfs_get_export();
 965 
 966         dvp = cs->vp;
 967         exi = cs->exi;
 968         ASSERT(exi != NULL);
 969         dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0');
 970 
 971         /*
 972          * If dotdotting, then need to check whether it's above the
 973          * root of a filesystem, or above an export point.
 974          */
 975         if (dotdot) {
 976                 ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
 977                 /*
 978                  * If dotdotting at the root of a filesystem, then
 979                  * need to traverse back to the mounted-on filesystem
 980                  * and do the dotdot lookup there.
 981                  */
 982                 if ((dvp->v_flag & VROOT) || VN_IS_CURZONEROOT(dvp)) {
 983 
 984                         /*
 985                          * If at the system root, then can
 986                          * go up no further.
 987                          */
 988                         if (VN_CMP(dvp, ZONE_ROOTVP()))
 989                                 return (puterrno4(ENOENT));
 990 
 991                         /*
 992                          * Traverse back to the mounted-on filesystem
 993                          */
 994                         dvp = untraverse(dvp);
 995 
 996                         /*
 997                          * Set the different_export flag so we remember
 998                          * to pick up a new exportinfo entry for
 999                          * this new filesystem.
1000                          */
1001                         different_export = 1;
1002                 } else {
1003 
1004                         /*
1005                          * If dotdotting above an export point then set
1006                          * the different_export to get new export info.
1007                          */
1008                         different_export = nfs_exported(exi, dvp);
1009                 }
1010         }
1011 
1012         /*
1013          * Get the vnode for the component "nm".
1014          */
1015         error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cs->cr,
1016             NULL, NULL, NULL);
1017         if (error)
1018                 return (puterrno4(error));
1019 
1020         /*
1021          * If the vnode is in a pseudo filesystem, or if the security flavor
1022          * used in the request is valid but not an explicitly shared flavor,
1023          * or the access bit indicates that this is a limited access,
1024          * check whether this vnode is visible.
1025          */
1026         if (!different_export &&
1027             (PSEUDO(exi) || !is_exported_sec(cs->nfsflavor, exi) ||
1028             cs->access & CS_ACCESS_LIMITED)) {
1029                 if (! nfs_visible(exi, vp, &different_export)) {
1030                         VN_RELE(vp);
1031                         return (puterrno4(ENOENT));
1032                 }
1033         }
1034 
1035         /*
1036          * If it's a mountpoint, then traverse it.
1037          */
1038         if (vn_ismntpt(vp)) {
1039                 if ((error = traverse(&vp)) != 0) {
1040                         VN_RELE(vp);
1041                         return (puterrno4(error));
1042                 }
1043                 /* remember that we had to traverse mountpoint */
1044                 did_traverse = TRUE;
1045                 different_export = 1;
1046         } else if (vp->v_vfsp != dvp->v_vfsp) {
1047                 /*
1048                  * If vp isn't a mountpoint and the vfs ptrs aren't the same,
1049                  * then vp is probably an LOFS object.  We don't need the
 
1051                  * a server fs boundary and need to call checkexport4.
1052                  * (LOFS lookup hides server fs mountpoints, and actually calls
1053                  * traverse)
1054                  */
1055                 different_export = 1;
1056         }
1057 
1058         /*
1059          * Get the export information for it.
1060          */
1061         if (different_export) {
1062 
1063                 bzero(&fid, sizeof (fid));
1064                 fid.fid_len = MAXFIDSZ;
1065                 error = vop_fid_pseudo(vp, &fid);
1066                 if (error) {
1067                         VN_RELE(vp);
1068                         return (puterrno4(error));
1069                 }
1070 
1071                 /* We'll need to reassign "exi". */
1072                 if (dotdot)
1073                         exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
1074                 else
1075                         exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
1076 
1077                 if (exi == NULL) {
1078                         if (did_traverse == TRUE) {
1079                                 /*
1080                                  * If this vnode is a mounted-on vnode,
1081                                  * but the mounted-on file system is not
1082                                  * exported, send back the secinfo for
1083                                  * the exported node that the mounted-on
1084                                  * vnode lives in.
1085                                  */
1086                                 exi = cs->exi;
1087                         } else {
1088                                 VN_RELE(vp);
1089                                 return (puterrno4(EACCES));
1090                         }
1091                 }
1092         }
1093         ASSERT(exi != NULL);
1094 
1095 
1096         /*
1097          * Create the secinfo result based on the security information
1098          * from the exportinfo structure (exi).
1099          *
1100          * Return all flavors for a pseudo node.
1101          * For a real export node, return the flavor that the client
1102          * has access with.
1103          */
1104         ASSERT(RW_LOCK_HELD(&ne->exported_lock));
1105         if (PSEUDO(exi)) {
1106                 count = exi->exi_export.ex_seccnt; /* total sec count */
1107                 resok_val = kmem_alloc(count * sizeof (secinfo4), KM_SLEEP);
1108                 secp = exi->exi_export.ex_secinfo;
1109 
1110                 for (i = 0; i < count; i++) {
1111                         si = &secp[i].s_secinfo;
 
2702         fid_t fid;
2703         int attrdir, dotdot, walk;
2704         bool_t is_newvp = FALSE;
2705 
2706         if (cs->vp->v_flag & V_XATTRDIR) {
2707                 attrdir = 1;
2708                 ASSERT(get_fh4_flag(&cs->fh, FH4_ATTRDIR));
2709         } else {
2710                 attrdir = 0;
2711                 ASSERT(! get_fh4_flag(&cs->fh, FH4_ATTRDIR));
2712         }
2713 
2714         dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0');
2715 
2716         /*
2717          * If dotdotting, then need to check whether it's
2718          * above the root of a filesystem, or above an
2719          * export point.
2720          */
2721         if (dotdot) {
2722                 ASSERT(cs->exi != NULL);
2723                 ASSERT3U(cs->exi->exi_zoneid, ==, curzone->zone_id);
2724                 /*
2725                  * If dotdotting at the root of a filesystem, then
2726                  * need to traverse back to the mounted-on filesystem
2727                  * and do the dotdot lookup there.
2728                  */
2729                 if ((cs->vp->v_flag & VROOT) || VN_IS_CURZONEROOT(cs->vp)) {
2730 
2731                         /*
2732                          * If at the system root, then can
2733                          * go up no further.
2734                          */
2735                         if (VN_CMP(cs->vp, ZONE_ROOTVP()))
2736                                 return (puterrno4(ENOENT));
2737 
2738                         /*
2739                          * Traverse back to the mounted-on filesystem
2740                          */
2741                         cs->vp = untraverse(cs->vp);
2742 
2743                         /*
2744                          * Set the different_export flag so we remember
2745                          * to pick up a new exportinfo entry for
2746                          * this new filesystem.
2747                          */
2748                         different_export = 1;
2749                 } else {
 
 |