Print this page
7378 exported_lock held during nfs4 compound processing


 855         int i;
 856 
 857         for (i = 0; i < count; i++) {
 858                 if (nfsnum == flavor_list[i])
 859                         return (TRUE);
 860         }
 861         return (FALSE);
 862 }
 863 
 864 /*
 865  * Used by rfs4_op_secinfo to get the security information from the
 866  * export structure associated with the component.
 867  */
 868 /* ARGSUSED */
 869 static nfsstat4
 870 do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
 871 {
 872         int error, different_export = 0;
 873         vnode_t *dvp, *vp;
 874         struct exportinfo *exi = NULL;

 875         fid_t fid;
 876         uint_t count, i;
 877         secinfo4 *resok_val;
 878         struct secinfo *secp;
 879         seconfig_t *si;
 880         bool_t did_traverse = FALSE;
 881         int dotdot, walk;
 882 
 883         dvp = cs->vp;
 884         dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0');
 885 
 886         /*
 887          * If dotdotting, then need to check whether it's above the
 888          * root of a filesystem, or above an export point.
 889          */
 890         if (dotdot) {
 891 
 892                 /*
 893                  * If dotdotting at the root of a filesystem, then
 894                  * need to traverse back to the mounted-on filesystem


 946                         return (puterrno4(ENOENT));
 947                 }
 948         }
 949 
 950         /*
 951          * If it's a mountpoint, then traverse it.
 952          */
 953         if (vn_ismntpt(vp)) {
 954                 if ((error = traverse(&vp)) != 0) {
 955                         VN_RELE(vp);
 956                         return (puterrno4(error));
 957                 }
 958                 /* remember that we had to traverse mountpoint */
 959                 did_traverse = TRUE;
 960                 different_export = 1;
 961         } else if (vp->v_vfsp != dvp->v_vfsp) {
 962                 /*
 963                  * If vp isn't a mountpoint and the vfs ptrs aren't the same,
 964                  * then vp is probably an LOFS object.  We don't need the
 965                  * realvp, we just need to know that we might have crossed
 966                  * a server fs boundary and need to call checkexport4.
 967                  * (LOFS lookup hides server fs mountpoints, and actually calls
 968                  * traverse)
 969                  */
 970                 different_export = 1;
 971         }
 972 
 973         /*
 974          * Get the export information for it.
 975          */
 976         if (different_export) {
 977 
 978                 bzero(&fid, sizeof (fid));
 979                 fid.fid_len = MAXFIDSZ;
 980                 error = vop_fid_pseudo(vp, &fid);
 981                 if (error) {
 982                         VN_RELE(vp);
 983                         return (puterrno4(error));
 984                 }
 985 
 986                 if (dotdot)
 987                         exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
 988                 else
 989                         exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
 990 
 991                 if (exi == NULL) {
 992                         if (did_traverse == TRUE) {
 993                                 /*
 994                                  * If this vnode is a mounted-on vnode,
 995                                  * but the mounted-on file system is not
 996                                  * exported, send back the secinfo for
 997                                  * the exported node that the mounted-on
 998                                  * vnode lives in.
 999                                  */
1000                                 exi = cs->exi;
1001                         } else {
1002                                 VN_RELE(vp);
1003                                 return (puterrno4(EACCES));
1004                         }


1005                 }
1006         } else {
1007                 exi = cs->exi;
1008         }
1009         ASSERT(exi != NULL);
1010 
1011 
1012         /*
1013          * Create the secinfo result based on the security information
1014          * from the exportinfo structure (exi).
1015          *
1016          * Return all flavors for a pseudo node.
1017          * For a real export node, return the flavor that the client
1018          * has access with.
1019          */
1020         ASSERT(RW_LOCK_HELD(&exported_lock));
1021         if (PSEUDO(exi)) {
1022                 count = exi->exi_export.ex_seccnt; /* total sec count */
1023                 resok_val = kmem_alloc(count * sizeof (secinfo4), KM_SLEEP);
1024                 secp = exi->exi_export.ex_secinfo;
1025 
1026                 for (i = 0; i < count; i++) {
1027                         si = &secp[i].s_secinfo;
1028                         resok_val[i].flavor = si->sc_rpcnum;
1029                         if (resok_val[i].flavor == RPCSEC_GSS) {
1030                                 rpcsec_gss_info *info;
1031 
1032                                 info = &resok_val[i].flavor_info;
1033                                 info->qop = si->sc_qop;
1034                                 info->service = (rpc_gss_svc_t)si->sc_service;
1035 
1036                                 /* get oid opaque data */
1037                                 info->oid.sec_oid4_len =
1038                                     si->sc_gss_mech_type->length;
1039                                 info->oid.sec_oid4_val = kmem_alloc(
1040                                     si->sc_gss_mech_type->length, KM_SLEEP);


1093 
1094                                         /* get oid opaque data */
1095                                         info->oid.sec_oid4_len =
1096                                             si->sc_gss_mech_type->length;
1097                                         info->oid.sec_oid4_val = kmem_alloc(
1098                                             si->sc_gss_mech_type->length,
1099                                             KM_SLEEP);
1100                                         bcopy(si->sc_gss_mech_type->elements,
1101                                             info->oid.sec_oid4_val,
1102                                             info->oid.sec_oid4_len);
1103                                 }
1104                                 k++;
1105                         }
1106                         if (k >= ret_cnt)
1107                                 break;
1108                 }
1109                 resp->SECINFO4resok_len = ret_cnt;
1110                 resp->SECINFO4resok_val = resok_val;
1111                 kmem_free(flavor_list, count * sizeof (int));
1112         }
1113 


1114         VN_RELE(vp);
1115         return (NFS4_OK);
1116 }
1117 
1118 /*
1119  * SECINFO (Operation 33): Obtain required security information on
1120  * the component name in the format of (security-mechanism-oid, qop, service)
1121  * triplets.
1122  */
1123 /* ARGSUSED */
1124 static void
1125 rfs4_op_secinfo(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
1126     struct compound_state *cs)
1127 {
1128         SECINFO4args *args = &argop->nfs_argop4_u.opsecinfo;
1129         SECINFO4res *resp = &resop->nfs_resop4_u.opsecinfo;
1130         utf8string *utfnm = &args->name;
1131         uint_t len;
1132         char *nm;
1133         struct sockaddr *ca;


2594         else
2595                 resp->cinfo.atomic = FALSE;
2596 
2597         *cs->statusp = resp->status = NFS4_OK;
2598 out:
2599         DTRACE_NFSV4_2(op__link__done, struct compound_state *, cs,
2600             LINK4res *, resp);
2601 }
2602 
2603 /*
2604  * Used by rfs4_op_lookup and rfs4_op_lookupp to do the actual work.
2605  */
2606 
2607 /* ARGSUSED */
2608 static nfsstat4
2609 do_rfs4_op_lookup(char *nm, struct svc_req *req, struct compound_state *cs)
2610 {
2611         int error;
2612         int different_export = 0;
2613         vnode_t *vp, *pre_tvp = NULL, *oldvp = NULL;
2614         struct exportinfo *exi = NULL, *pre_exi = NULL;
2615         nfsstat4 stat;
2616         fid_t fid;
2617         int attrdir, dotdot, walk;
2618         bool_t is_newvp = FALSE;
2619 
2620         if (cs->vp->v_flag & V_XATTRDIR) {
2621                 attrdir = 1;
2622                 ASSERT(get_fh4_flag(&cs->fh, FH4_ATTRDIR));
2623         } else {
2624                 attrdir = 0;
2625                 ASSERT(! get_fh4_flag(&cs->fh, FH4_ATTRDIR));
2626         }
2627 
2628         dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0');
2629 
2630         /*
2631          * If dotdotting, then need to check whether it's
2632          * above the root of a filesystem, or above an
2633          * export point.
2634          */


2688          * checked via PUTROOTFH/PUTPUBFH or PUTFH.
2689          */
2690         if (!different_export &&
2691             (PSEUDO(cs->exi) || ! is_exported_sec(cs->nfsflavor, cs->exi) ||
2692             cs->access & CS_ACCESS_LIMITED)) {
2693                 if (! nfs_visible(cs->exi, vp, &different_export)) {
2694                         VN_RELE(vp);
2695                         return (puterrno4(ENOENT));
2696                 }
2697         }
2698 
2699         /*
2700          * If it's a mountpoint, then traverse it.
2701          */
2702         if (vn_ismntpt(vp)) {
2703                 pre_exi = cs->exi;   /* save pre-traversed exportinfo */
2704                 pre_tvp = vp;           /* save pre-traversed vnode     */
2705 
2706                 /*
2707                  * hold pre_tvp to counteract rele by traverse.  We will
2708                  * need pre_tvp below if checkexport4 fails
2709                  */
2710                 VN_HOLD(pre_tvp);
2711                 if ((error = traverse(&vp)) != 0) {
2712                         VN_RELE(vp);
2713                         VN_RELE(pre_tvp);
2714                         return (puterrno4(error));
2715                 }
2716                 different_export = 1;
2717         } else if (vp->v_vfsp != cs->vp->v_vfsp) {
2718                 /*
2719                  * The vfsp comparison is to handle the case where
2720                  * a LOFS mount is shared.  lo_lookup traverses mount points,
2721                  * and NFS is unaware of local fs transistions because
2722                  * v_vfsmountedhere isn't set.  For this special LOFS case,
2723                  * the dir and the obj returned by lookup will have different
2724                  * vfs ptrs.
2725                  */
2726                 different_export = 1;
2727         }
2728 
2729         if (different_export) {
2730 
2731                 bzero(&fid, sizeof (fid));
2732                 fid.fid_len = MAXFIDSZ;
2733                 error = vop_fid_pseudo(vp, &fid);
2734                 if (error) {
2735                         VN_RELE(vp);
2736                         if (pre_tvp)
2737                                 VN_RELE(pre_tvp);
2738                         return (puterrno4(error));
2739                 }
2740 
2741                 if (dotdot)
2742                         exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
2743                 else
2744                         exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
2745 
2746                 if (exi == NULL) {
2747                         if (pre_tvp) {
2748                                 /*
2749                                  * If this vnode is a mounted-on vnode,
2750                                  * but the mounted-on file system is not
2751                                  * exported, send back the filehandle for
2752                                  * the mounted-on vnode, not the root of
2753                                  * the mounted-on file system.
2754                                  */
2755                                 VN_RELE(vp);
2756                                 vp = pre_tvp;
2757                                 exi = pre_exi;


2758                         } else {
2759                                 VN_RELE(vp);
2760                                 return (puterrno4(EACCES));
2761                         }
2762                 } else if (pre_tvp) {
2763                         /* we're done with pre_tvp now. release extra hold */
2764                         VN_RELE(pre_tvp);
2765                 }
2766 


2767                 cs->exi = exi;
2768 
2769                 /*
2770                  * Now we do a checkauth4. The reason is that
2771                  * this client/user may not have access to the new
2772                  * exported file system, and if he does,
2773                  * the client/user may be mapped to a different uid.
2774                  *
2775                  * We start with a new cr, because the checkauth4 done
2776                  * in the PUT*FH operation over wrote the cred's uid,
2777                  * gid, etc, and we want the real thing before calling
2778                  * checkauth4()
2779                  */
2780                 crfree(cs->cr);
2781                 cs->cr = crdup(cs->basecr);
2782 
2783                 oldvp = cs->vp;
2784                 cs->vp = vp;
2785                 is_newvp = TRUE;
2786 


3427                 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
3428                 goto out;
3429         }
3430 
3431         error = makefh4(&cs->fh, vp, exi_public);
3432         if (error != 0) {
3433                 *cs->statusp = resp->status = puterrno4(error);
3434                 goto out;
3435         }
3436         sav_exi = cs->exi;
3437         if (exi_public == exi_root) {
3438                 /*
3439                  * No filesystem is actually shared public, so we default
3440                  * to exi_root. In this case, we must check whether root
3441                  * is exported.
3442                  */
3443                 fh_fmtp = (nfs_fh4_fmt_t *)cs->fh.nfs_fh4_val;
3444 
3445                 /*
3446                  * if root filesystem is exported, the exportinfo struct that we
3447                  * should use is what checkexport4 returns, because root_exi is
3448                  * actually a mostly empty struct.
3449                  */
3450                 exi = checkexport4(&fh_fmtp->fh4_fsid,
3451                     (fid_t *)&fh_fmtp->fh4_xlen, NULL);
3452                 cs->exi = ((exi != NULL) ? exi : exi_public);





3453         } else {
3454                 /*
3455                  * it's a properly shared filesystem
3456                  */

3457                 cs->exi = exi_public;
3458         }
3459 
3460         if (is_system_labeled()) {
3461                 bslabel_t *clabel;
3462 
3463                 ASSERT(req->rq_label != NULL);
3464                 clabel = req->rq_label;
3465                 DTRACE_PROBE2(tx__rfs4__log__info__opputpubfh__clabel, char *,
3466                     "got client label from request(1)",
3467                     struct svc_req *, req);
3468                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3469                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3470                             cs->exi)) {
3471                                 *cs->statusp = resp->status =
3472                                     NFS4ERR_SERVERFAULT;


3473                                 goto out;
3474                         }
3475                 }
3476         }
3477 
3478         VN_HOLD(vp);
3479         cs->vp = vp;
3480 
3481         if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
3482                 VN_RELE(cs->vp);
3483                 cs->vp = NULL;

3484                 cs->exi = sav_exi;
3485                 goto out;
3486         }


3487 
3488         *cs->statusp = resp->status = NFS4_OK;
3489 out:
3490         DTRACE_NFSV4_2(op__putpubfh__done, struct compound_state *, cs,
3491             PUTPUBFH4res *, resp);
3492 }
3493 
3494 /*
3495  * XXX - issue with put*fh operations. Suppose /export/home is exported.
3496  * Suppose an NFS client goes to mount /export/home/joe. If /export, home,
3497  * or joe have restrictive search permissions, then we shouldn't let
3498  * the client get a file handle. This is easy to enforce. However, we
3499  * don't know what security flavor should be used until we resolve the
3500  * path name. Another complication is uid mapping. If root is
3501  * the user, then it will be mapped to the anonymous user by default,
3502  * but we won't know that till we've resolved the path name. And we won't
3503  * know what the anonymous user is.
3504  * Luckily, SECINFO is specified to take a full filename.
3505  * So what we will have to in rfs4_op_lookup is check that flavor of
3506  * the target object matches that of the request, and if root was the


3519         DTRACE_NFSV4_2(op__putfh__start, struct compound_state *, cs,
3520             PUTFH4args *, args);
3521 
3522         if (cs->vp) {
3523                 VN_RELE(cs->vp);
3524                 cs->vp = NULL;
3525         }
3526 
3527         if (cs->cr) {
3528                 crfree(cs->cr);
3529                 cs->cr = NULL;
3530         }
3531 
3532 
3533         if (args->object.nfs_fh4_len < NFS_FH4_LEN) {
3534                 *cs->statusp = resp->status = NFS4ERR_BADHANDLE;
3535                 goto out;
3536         }
3537 
3538         fh_fmtp = (nfs_fh4_fmt_t *)args->object.nfs_fh4_val;
3539         cs->exi = checkexport4(&fh_fmtp->fh4_fsid, (fid_t *)&fh_fmtp->fh4_xlen,


3540             NULL);
3541 
3542         if (cs->exi == NULL) {
3543                 *cs->statusp = resp->status = NFS4ERR_STALE;
3544                 goto out;
3545         }
3546 
3547         cs->cr = crdup(cs->basecr);
3548 
3549         ASSERT(cs->cr != NULL);
3550 
3551         if (! (cs->vp = nfs4_fhtovp(&args->object, cs->exi, &resp->status))) {
3552                 *cs->statusp = resp->status;
3553                 goto out;
3554         }
3555 
3556         if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
3557                 VN_RELE(cs->vp);
3558                 cs->vp = NULL;
3559                 goto out;


3593         /*
3594          * Using rootdir, the system root vnode,
3595          * get its fid.
3596          */
3597         bzero(&fid, sizeof (fid));
3598         fid.fid_len = MAXFIDSZ;
3599         error = vop_fid_pseudo(rootdir, &fid);
3600         if (error != 0) {
3601                 *cs->statusp = resp->status = puterrno4(error);
3602                 goto out;
3603         }
3604 
3605         /*
3606          * Then use the root fsid & fid it to find out if it's exported
3607          *
3608          * If the server root isn't exported directly, then
3609          * it should at least be a pseudo export based on
3610          * one or more exports further down in the server's
3611          * file tree.
3612          */
3613         exi = checkexport4(&rootdir->v_vfsp->vfs_fsid, &fid, NULL);
3614         if (exi == NULL || exi->exi_export.ex_flags & EX_PUBLIC) {
3615                 NFS4_DEBUG(rfs4_debug,
3616                     (CE_WARN, "rfs4_op_putrootfh: export check failure"));
3617                 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;


3618                 goto out;
3619         }
3620 
3621         /*
3622          * Now make a filehandle based on the root
3623          * export and root vnode.
3624          */
3625         error = makefh4(&cs->fh, rootdir, exi);
3626         if (error != 0) {
3627                 *cs->statusp = resp->status = puterrno4(error);

3628                 goto out;
3629         }
3630 
3631         sav_exi = cs->exi;
3632         cs->exi = exi;
3633 
3634         VN_HOLD(rootdir);
3635         cs->vp = rootdir;
3636 
3637         if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
3638                 VN_RELE(rootdir);
3639                 cs->vp = NULL;

3640                 cs->exi = sav_exi;
3641                 goto out;
3642         }


3643 
3644         *cs->statusp = resp->status = NFS4_OK;
3645         cs->deleg = FALSE;
3646 out:
3647         DTRACE_NFSV4_2(op__putrootfh__done, struct compound_state *, cs,
3648             PUTROOTFH4res *, resp);
3649 }
3650 
3651 /*
3652  * set_rdattr_params sets up the variables used to manage what information
3653  * to get for each directory entry.
3654  */
3655 static nfsstat4
3656 set_rdattr_params(struct nfs4_svgetit_arg *sargp,
3657     bitmap4 attrs, bool_t *need_to_lookup)
3658 {
3659         uint_t  va_mask;
3660         nfsstat4 status;
3661         bitmap4 objbits;
3662 


4800 
4801 /* ARGSUSED */
4802 static void
4803 rfs4_op_restorefh(nfs_argop4 *args, nfs_resop4 *resop, struct svc_req *req,
4804     struct compound_state *cs)
4805 {
4806         RESTOREFH4res *resp = &resop->nfs_resop4_u.oprestorefh;
4807 
4808         DTRACE_NFSV4_1(op__restorefh__start, struct compound_state *, cs);
4809 
4810         /* No need to check cs->access - we are not accessing any object */
4811         if ((cs->saved_vp == NULL) || (cs->saved_fh.nfs_fh4_val == NULL)) {
4812                 *cs->statusp = resp->status = NFS4ERR_RESTOREFH;
4813                 goto out;
4814         }
4815         if (cs->vp != NULL) {
4816                 VN_RELE(cs->vp);
4817         }
4818         cs->vp = cs->saved_vp;
4819         cs->saved_vp = NULL;


4820         cs->exi = cs->saved_exi;


4821         nfs_fh4_copy(&cs->saved_fh, &cs->fh);
4822         *cs->statusp = resp->status = NFS4_OK;
4823         cs->deleg = FALSE;
4824 
4825 out:
4826         DTRACE_NFSV4_2(op__restorefh__done, struct compound_state *, cs,
4827             RESTOREFH4res *, resp);
4828 }
4829 
4830 /* ARGSUSED */
4831 static void
4832 rfs4_op_savefh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
4833     struct compound_state *cs)
4834 {
4835         SAVEFH4res *resp = &resop->nfs_resop4_u.opsavefh;
4836 
4837         DTRACE_NFSV4_1(op__savefh__start, struct compound_state *, cs);
4838 
4839         /* No need to check cs->access - we are not accessing any object */
4840         if (cs->vp == NULL) {
4841                 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
4842                 goto out;
4843         }
4844         if (cs->saved_vp != NULL) {
4845                 VN_RELE(cs->saved_vp);
4846         }
4847         cs->saved_vp = cs->vp;
4848         VN_HOLD(cs->saved_vp);


4849         cs->saved_exi = cs->exi;


4850         /*
4851          * since SAVEFH is fairly rare, don't alloc space for its fh
4852          * unless necessary.
4853          */
4854         if (cs->saved_fh.nfs_fh4_val == NULL) {
4855                 cs->saved_fh.nfs_fh4_val = kmem_alloc(NFS4_FHSIZE, KM_SLEEP);
4856         }
4857         nfs_fh4_copy(&cs->fh, &cs->saved_fh);
4858         *cs->statusp = resp->status = NFS4_OK;
4859 
4860 out:
4861         DTRACE_NFSV4_2(op__savefh__done, struct compound_state *, cs,
4862             SAVEFH4res *, resp);
4863 }
4864 
4865 /*
4866  * rfs4_verify_attr is called when nfsv4 Setattr failed, but we wish to
4867  * return the bitmap of attrs that were set successfully. It is also
4868  * called by Verify/Nverify to test the vattr/vfsstat attrs. It should
4869  * always be called only after rfs4_do_set_attrs().


5794                 DTRACE_NFSV4_2(compound__start, struct compound_state *,
5795                     &cs, COMPOUND4args *, args);
5796                 crfree(cr);
5797                 DTRACE_NFSV4_2(compound__done, struct compound_state *,
5798                     &cs, COMPOUND4res *, resp);
5799                 svcerr_badcred(req->rq_xprt);
5800                 if (rv != NULL)
5801                         *rv = 1;
5802                 return;
5803         }
5804         resp->array_len = args->array_len;
5805         resp->array = kmem_zalloc(args->array_len * sizeof (nfs_resop4),
5806             KM_SLEEP);
5807 
5808         cs.basecr = cr;
5809 
5810         DTRACE_NFSV4_2(compound__start, struct compound_state *, &cs,
5811             COMPOUND4args *, args);
5812 
5813         /*
5814          * For now, NFS4 compound processing must be protected by
5815          * exported_lock because it can access more than one exportinfo
5816          * per compound and share/unshare can now change multiple
5817          * exinfo structs.  The NFS2/3 code only refs 1 exportinfo
5818          * per proc (excluding public exinfo), and exi_count design
5819          * is sufficient to protect concurrent execution of NFS2/3
5820          * ops along with unexport.  This lock will be removed as
5821          * part of the NFSv4 phase 2 namespace redesign work.
5822          */
5823         rw_enter(&exported_lock, RW_READER);
5824 
5825         /*
5826          * If this is the first compound we've seen, we need to start all
5827          * new instances' grace periods.
5828          */
5829         if (rfs4_seen_first_compound == 0) {
5830                 rfs4_grace_start_new();
5831                 /*
5832                  * This must be set after rfs4_grace_start_new(), otherwise
5833                  * another thread could proceed past here before the former
5834                  * is finished.
5835                  */
5836                 rfs4_seen_first_compound = 1;
5837         }
5838 
5839         for (i = 0; i < args->array_len && cs.cont; i++) {
5840                 nfs_argop4 *argop;
5841                 nfs_resop4 *resop;
5842                 uint_t op;
5843 
5844                 argop = &args->array[i];
5845                 resop = &resp->array[i];


5874                         cs.cont = FALSE;
5875                 }
5876 
5877                 /*
5878                  * If not at last op, and if we are to stop, then
5879                  * compact the results array.
5880                  */
5881                 if ((i + 1) < args->array_len && !cs.cont) {
5882                         nfs_resop4 *new_res = kmem_alloc(
5883                             (i+1) * sizeof (nfs_resop4), KM_SLEEP);
5884                         bcopy(resp->array,
5885                             new_res, (i+1) * sizeof (nfs_resop4));
5886                         kmem_free(resp->array,
5887                             args->array_len * sizeof (nfs_resop4));
5888 
5889                         resp->array_len =  i + 1;
5890                         resp->array = new_res;
5891                 }
5892         }
5893 
5894         rw_exit(&exported_lock);
5895 
5896         DTRACE_NFSV4_2(compound__done, struct compound_state *, &cs,
5897             COMPOUND4res *, resp);
5898 




5899         if (cs.vp)
5900                 VN_RELE(cs.vp);
5901         if (cs.saved_vp)
5902                 VN_RELE(cs.saved_vp);
5903         if (cs.saved_fh.nfs_fh4_val)
5904                 kmem_free(cs.saved_fh.nfs_fh4_val, NFS4_FHSIZE);
5905 
5906         if (cs.basecr)
5907                 crfree(cs.basecr);
5908         if (cs.cr)
5909                 crfree(cs.cr);
5910         /*
5911          * done with this compound request, free the label
5912          */
5913 
5914         if (req->rq_label != NULL) {
5915                 kmem_free(req->rq_label, sizeof (bslabel_t));
5916                 req->rq_label = NULL;
5917         }
5918 }


7479                 if (!replay)
7480                         rfs4_update_open_resp(oo, resop, &cs->fh);
7481 
7482                 /*
7483                  * REPLAY case: Only if the previous response was OK
7484                  * do we copy the filehandle.  If not OK, no
7485                  * filehandle to copy.
7486                  */
7487                 if (replay == TRUE &&
7488                     resp->status == NFS4_OK &&
7489                     oo->ro_reply_fh.nfs_fh4_val) {
7490                         /*
7491                          * If this is a replay, we must restore the
7492                          * current filehandle/vp to that of what was
7493                          * returned originally.  Try our best to do
7494                          * it.
7495                          */
7496                         nfs_fh4_fmt_t *fh_fmtp =
7497                             (nfs_fh4_fmt_t *)oo->ro_reply_fh.nfs_fh4_val;
7498 
7499                         cs->exi = checkexport4(&fh_fmtp->fh4_fsid,


7500                             (fid_t *)&fh_fmtp->fh4_xlen, NULL);
7501 
7502                         if (cs->exi == NULL) {
7503                                 resp->status = NFS4ERR_STALE;
7504                                 goto finish;
7505                         }
7506 
7507                         VN_RELE(cs->vp);
7508 
7509                         cs->vp = nfs4_fhtovp(&oo->ro_reply_fh, cs->exi,
7510                             &resp->status);
7511 
7512                         if (cs->vp == NULL)
7513                                 goto finish;
7514 
7515                         nfs_fh4_copy(&oo->ro_reply_fh, &cs->fh);
7516                 }
7517 
7518                 /*
7519                  * If this was a replay, no need to update the




 855         int i;
 856 
 857         for (i = 0; i < count; i++) {
 858                 if (nfsnum == flavor_list[i])
 859                         return (TRUE);
 860         }
 861         return (FALSE);
 862 }
 863 
 864 /*
 865  * Used by rfs4_op_secinfo to get the security information from the
 866  * export structure associated with the component.
 867  */
 868 /* ARGSUSED */
 869 static nfsstat4
 870 do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
 871 {
 872         int error, different_export = 0;
 873         vnode_t *dvp, *vp;
 874         struct exportinfo *exi = NULL;
 875         struct exportinfo *oexi = NULL;
 876         fid_t fid;
 877         uint_t count, i;
 878         secinfo4 *resok_val;
 879         struct secinfo *secp;
 880         seconfig_t *si;
 881         bool_t did_traverse = FALSE;
 882         int dotdot, walk;
 883 
 884         dvp = cs->vp;
 885         dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0');
 886 
 887         /*
 888          * If dotdotting, then need to check whether it's above the
 889          * root of a filesystem, or above an export point.
 890          */
 891         if (dotdot) {
 892 
 893                 /*
 894                  * If dotdotting at the root of a filesystem, then
 895                  * need to traverse back to the mounted-on filesystem


 947                         return (puterrno4(ENOENT));
 948                 }
 949         }
 950 
 951         /*
 952          * If it's a mountpoint, then traverse it.
 953          */
 954         if (vn_ismntpt(vp)) {
 955                 if ((error = traverse(&vp)) != 0) {
 956                         VN_RELE(vp);
 957                         return (puterrno4(error));
 958                 }
 959                 /* remember that we had to traverse mountpoint */
 960                 did_traverse = TRUE;
 961                 different_export = 1;
 962         } else if (vp->v_vfsp != dvp->v_vfsp) {
 963                 /*
 964                  * If vp isn't a mountpoint and the vfs ptrs aren't the same,
 965                  * then vp is probably an LOFS object.  We don't need the
 966                  * realvp, we just need to know that we might have crossed
 967                  * a server fs boundary and need to call checkexport.
 968                  * (LOFS lookup hides server fs mountpoints, and actually calls
 969                  * traverse)
 970                  */
 971                 different_export = 1;
 972         }
 973 
 974         /*
 975          * Get the export information for it.
 976          */
 977         if (different_export) {
 978 
 979                 bzero(&fid, sizeof (fid));
 980                 fid.fid_len = MAXFIDSZ;
 981                 error = vop_fid_pseudo(vp, &fid);
 982                 if (error) {
 983                         VN_RELE(vp);
 984                         return (puterrno4(error));
 985                 }
 986 
 987                 if (dotdot)
 988                         oexi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
 989                 else
 990                         oexi = checkexport(&vp->v_vfsp->vfs_fsid, &fid, vp);
 991 
 992                 if (oexi == NULL) {
 993                         if (did_traverse == TRUE) {
 994                                 /*
 995                                  * If this vnode is a mounted-on vnode,
 996                                  * but the mounted-on file system is not
 997                                  * exported, send back the secinfo for
 998                                  * the exported node that the mounted-on
 999                                  * vnode lives in.
1000                                  */
1001                                 exi = cs->exi;
1002                         } else {
1003                                 VN_RELE(vp);
1004                                 return (puterrno4(EACCES));
1005                         }
1006                 } else {
1007                         exi = oexi;
1008                 }
1009         } else {
1010                 exi = cs->exi;
1011         }
1012         ASSERT(exi != NULL);
1013 
1014 
1015         /*
1016          * Create the secinfo result based on the security information
1017          * from the exportinfo structure (exi).
1018          *
1019          * Return all flavors for a pseudo node.
1020          * For a real export node, return the flavor that the client
1021          * has access with.
1022          */
1023         rw_enter(&exported_lock, RW_READER);
1024         if (PSEUDO(exi)) {
1025                 count = exi->exi_export.ex_seccnt; /* total sec count */
1026                 resok_val = kmem_alloc(count * sizeof (secinfo4), KM_SLEEP);
1027                 secp = exi->exi_export.ex_secinfo;
1028 
1029                 for (i = 0; i < count; i++) {
1030                         si = &secp[i].s_secinfo;
1031                         resok_val[i].flavor = si->sc_rpcnum;
1032                         if (resok_val[i].flavor == RPCSEC_GSS) {
1033                                 rpcsec_gss_info *info;
1034 
1035                                 info = &resok_val[i].flavor_info;
1036                                 info->qop = si->sc_qop;
1037                                 info->service = (rpc_gss_svc_t)si->sc_service;
1038 
1039                                 /* get oid opaque data */
1040                                 info->oid.sec_oid4_len =
1041                                     si->sc_gss_mech_type->length;
1042                                 info->oid.sec_oid4_val = kmem_alloc(
1043                                     si->sc_gss_mech_type->length, KM_SLEEP);


1096 
1097                                         /* get oid opaque data */
1098                                         info->oid.sec_oid4_len =
1099                                             si->sc_gss_mech_type->length;
1100                                         info->oid.sec_oid4_val = kmem_alloc(
1101                                             si->sc_gss_mech_type->length,
1102                                             KM_SLEEP);
1103                                         bcopy(si->sc_gss_mech_type->elements,
1104                                             info->oid.sec_oid4_val,
1105                                             info->oid.sec_oid4_len);
1106                                 }
1107                                 k++;
1108                         }
1109                         if (k >= ret_cnt)
1110                                 break;
1111                 }
1112                 resp->SECINFO4resok_len = ret_cnt;
1113                 resp->SECINFO4resok_val = resok_val;
1114                 kmem_free(flavor_list, count * sizeof (int));
1115         }
1116         rw_exit(&exported_lock);
1117         if (oexi)
1118                 exi_rele(oexi);
1119         VN_RELE(vp);
1120         return (NFS4_OK);
1121 }
1122 
1123 /*
1124  * SECINFO (Operation 33): Obtain required security information on
1125  * the component name in the format of (security-mechanism-oid, qop, service)
1126  * triplets.
1127  */
1128 /* ARGSUSED */
1129 static void
1130 rfs4_op_secinfo(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
1131     struct compound_state *cs)
1132 {
1133         SECINFO4args *args = &argop->nfs_argop4_u.opsecinfo;
1134         SECINFO4res *resp = &resop->nfs_resop4_u.opsecinfo;
1135         utf8string *utfnm = &args->name;
1136         uint_t len;
1137         char *nm;
1138         struct sockaddr *ca;


2599         else
2600                 resp->cinfo.atomic = FALSE;
2601 
2602         *cs->statusp = resp->status = NFS4_OK;
2603 out:
2604         DTRACE_NFSV4_2(op__link__done, struct compound_state *, cs,
2605             LINK4res *, resp);
2606 }
2607 
2608 /*
2609  * Used by rfs4_op_lookup and rfs4_op_lookupp to do the actual work.
2610  */
2611 
2612 /* ARGSUSED */
2613 static nfsstat4
2614 do_rfs4_op_lookup(char *nm, struct svc_req *req, struct compound_state *cs)
2615 {
2616         int error;
2617         int different_export = 0;
2618         vnode_t *vp, *pre_tvp = NULL, *oldvp = NULL;
2619         struct exportinfo *exi = NULL, *pre_exi = NULL, *oexi = NULL;
2620         nfsstat4 stat;
2621         fid_t fid;
2622         int attrdir, dotdot, walk;
2623         bool_t is_newvp = FALSE;
2624 
2625         if (cs->vp->v_flag & V_XATTRDIR) {
2626                 attrdir = 1;
2627                 ASSERT(get_fh4_flag(&cs->fh, FH4_ATTRDIR));
2628         } else {
2629                 attrdir = 0;
2630                 ASSERT(! get_fh4_flag(&cs->fh, FH4_ATTRDIR));
2631         }
2632 
2633         dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0');
2634 
2635         /*
2636          * If dotdotting, then need to check whether it's
2637          * above the root of a filesystem, or above an
2638          * export point.
2639          */


2693          * checked via PUTROOTFH/PUTPUBFH or PUTFH.
2694          */
2695         if (!different_export &&
2696             (PSEUDO(cs->exi) || ! is_exported_sec(cs->nfsflavor, cs->exi) ||
2697             cs->access & CS_ACCESS_LIMITED)) {
2698                 if (! nfs_visible(cs->exi, vp, &different_export)) {
2699                         VN_RELE(vp);
2700                         return (puterrno4(ENOENT));
2701                 }
2702         }
2703 
2704         /*
2705          * If it's a mountpoint, then traverse it.
2706          */
2707         if (vn_ismntpt(vp)) {
2708                 pre_exi = cs->exi;   /* save pre-traversed exportinfo */
2709                 pre_tvp = vp;           /* save pre-traversed vnode     */
2710 
2711                 /*
2712                  * hold pre_tvp to counteract rele by traverse.  We will
2713                  * need pre_tvp below if checkexport fails
2714                  */
2715                 VN_HOLD(pre_tvp);
2716                 if ((error = traverse(&vp)) != 0) {
2717                         VN_RELE(vp);
2718                         VN_RELE(pre_tvp);
2719                         return (puterrno4(error));
2720                 }
2721                 different_export = 1;
2722         } else if (vp->v_vfsp != cs->vp->v_vfsp) {
2723                 /*
2724                  * The vfsp comparison is to handle the case where
2725                  * a LOFS mount is shared.  lo_lookup traverses mount points,
2726                  * and NFS is unaware of local fs transistions because
2727                  * v_vfsmountedhere isn't set.  For this special LOFS case,
2728                  * the dir and the obj returned by lookup will have different
2729                  * vfs ptrs.
2730                  */
2731                 different_export = 1;
2732         }
2733 
2734         if (different_export) {
2735 
2736                 bzero(&fid, sizeof (fid));
2737                 fid.fid_len = MAXFIDSZ;
2738                 error = vop_fid_pseudo(vp, &fid);
2739                 if (error) {
2740                         VN_RELE(vp);
2741                         if (pre_tvp)
2742                                 VN_RELE(pre_tvp);
2743                         return (puterrno4(error));
2744                 }
2745 
2746                 if (dotdot)
2747                         exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
2748                 else
2749                         exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid, vp);
2750 
2751                 if (exi == NULL) {
2752                         if (pre_tvp) {
2753                                 /*
2754                                  * If this vnode is a mounted-on vnode,
2755                                  * but the mounted-on file system is not
2756                                  * exported, send back the filehandle for
2757                                  * the mounted-on vnode, not the root of
2758                                  * the mounted-on file system.
2759                                  */
2760                                 VN_RELE(vp);
2761                                 vp = pre_tvp;
2762                                 exi = pre_exi;
2763                                 if (exi)
2764                                         exi_hold(exi);
2765                         } else {
2766                                 VN_RELE(vp);
2767                                 return (puterrno4(EACCES));
2768                         }
2769                 } else if (pre_tvp) {
2770                         /* we're done with pre_tvp now. release extra hold */
2771                         VN_RELE(pre_tvp);
2772                 }
2773 
2774                 if (cs->exi)
2775                         exi_rele(cs->exi);
2776                 cs->exi = exi;
2777 
2778                 /*
2779                  * Now we do a checkauth4. The reason is that
2780                  * this client/user may not have access to the new
2781                  * exported file system, and if he does,
2782                  * the client/user may be mapped to a different uid.
2783                  *
2784                  * We start with a new cr, because the checkauth4 done
2785                  * in the PUT*FH operation over wrote the cred's uid,
2786                  * gid, etc, and we want the real thing before calling
2787                  * checkauth4()
2788                  */
2789                 crfree(cs->cr);
2790                 cs->cr = crdup(cs->basecr);
2791 
2792                 oldvp = cs->vp;
2793                 cs->vp = vp;
2794                 is_newvp = TRUE;
2795 


3436                 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
3437                 goto out;
3438         }
3439 
3440         error = makefh4(&cs->fh, vp, exi_public);
3441         if (error != 0) {
3442                 *cs->statusp = resp->status = puterrno4(error);
3443                 goto out;
3444         }
3445         sav_exi = cs->exi;
3446         if (exi_public == exi_root) {
3447                 /*
3448                  * No filesystem is actually shared public, so we default
3449                  * to exi_root. In this case, we must check whether root
3450                  * is exported.
3451                  */
3452                 fh_fmtp = (nfs_fh4_fmt_t *)cs->fh.nfs_fh4_val;
3453 
3454                 /*
3455                  * if root filesystem is exported, the exportinfo struct that we
3456                  * should use is what checkexport returns, because root_exi is
3457                  * actually a mostly empty struct.
3458                  */
3459                 exi = checkexport(&fh_fmtp->fh4_fsid,
3460                     (fid_t *)&fh_fmtp->fh4_xlen, NULL);
3461                 if (exi) {
3462                         cs->exi = exi;
3463                 } else {
3464                         exi_hold(exi_public);
3465                         cs->exi = exi_public;
3466                 }
3467         } else {
3468                 /*
3469                  * it's a properly shared filesystem
3470                  */
3471                 exi_hold(exi_public);
3472                 cs->exi = exi_public;
3473         }
3474 
3475         if (is_system_labeled()) {
3476                 bslabel_t *clabel;
3477 
3478                 ASSERT(req->rq_label != NULL);
3479                 clabel = req->rq_label;
3480                 DTRACE_PROBE2(tx__rfs4__log__info__opputpubfh__clabel, char *,
3481                     "got client label from request(1)",
3482                     struct svc_req *, req);
3483                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3484                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3485                             cs->exi)) {
3486                                 *cs->statusp = resp->status =
3487                                     NFS4ERR_SERVERFAULT;
3488                                 if (sav_exi)
3489                                         exi_rele(sav_exi);
3490                                 goto out;
3491                         }
3492                 }
3493         }
3494 
3495         VN_HOLD(vp);
3496         cs->vp = vp;
3497 
3498         if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
3499                 VN_RELE(cs->vp);
3500                 cs->vp = NULL;
3501                 exi_rele(cs->exi);
3502                 cs->exi = sav_exi;
3503                 goto out;
3504         }
3505         if (sav_exi)
3506                 exi_rele(sav_exi);
3507 
3508         *cs->statusp = resp->status = NFS4_OK;
3509 out:
3510         DTRACE_NFSV4_2(op__putpubfh__done, struct compound_state *, cs,
3511             PUTPUBFH4res *, resp);
3512 }
3513 
3514 /*
3515  * XXX - issue with put*fh operations. Suppose /export/home is exported.
3516  * Suppose an NFS client goes to mount /export/home/joe. If /export, home,
3517  * or joe have restrictive search permissions, then we shouldn't let
3518  * the client get a file handle. This is easy to enforce. However, we
3519  * don't know what security flavor should be used until we resolve the
3520  * path name. Another complication is uid mapping. If root is
3521  * the user, then it will be mapped to the anonymous user by default,
3522  * but we won't know that till we've resolved the path name. And we won't
3523  * know what the anonymous user is.
3524  * Luckily, SECINFO is specified to take a full filename.
3525  * So what we will have to in rfs4_op_lookup is check that flavor of
3526  * the target object matches that of the request, and if root was the


3539         DTRACE_NFSV4_2(op__putfh__start, struct compound_state *, cs,
3540             PUTFH4args *, args);
3541 
3542         if (cs->vp) {
3543                 VN_RELE(cs->vp);
3544                 cs->vp = NULL;
3545         }
3546 
3547         if (cs->cr) {
3548                 crfree(cs->cr);
3549                 cs->cr = NULL;
3550         }
3551 
3552 
3553         if (args->object.nfs_fh4_len < NFS_FH4_LEN) {
3554                 *cs->statusp = resp->status = NFS4ERR_BADHANDLE;
3555                 goto out;
3556         }
3557 
3558         fh_fmtp = (nfs_fh4_fmt_t *)args->object.nfs_fh4_val;
3559         if (cs->exi)
3560                 exi_rele(cs->exi);
3561         cs->exi = checkexport(&fh_fmtp->fh4_fsid, (fid_t *)&fh_fmtp->fh4_xlen,
3562             NULL);
3563 
3564         if (cs->exi == NULL) {
3565                 *cs->statusp = resp->status = NFS4ERR_STALE;
3566                 goto out;
3567         }
3568 
3569         cs->cr = crdup(cs->basecr);
3570 
3571         ASSERT(cs->cr != NULL);
3572 
3573         if (! (cs->vp = nfs4_fhtovp(&args->object, cs->exi, &resp->status))) {
3574                 *cs->statusp = resp->status;
3575                 goto out;
3576         }
3577 
3578         if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
3579                 VN_RELE(cs->vp);
3580                 cs->vp = NULL;
3581                 goto out;


3615         /*
3616          * Using rootdir, the system root vnode,
3617          * get its fid.
3618          */
3619         bzero(&fid, sizeof (fid));
3620         fid.fid_len = MAXFIDSZ;
3621         error = vop_fid_pseudo(rootdir, &fid);
3622         if (error != 0) {
3623                 *cs->statusp = resp->status = puterrno4(error);
3624                 goto out;
3625         }
3626 
3627         /*
3628          * Then use the root fsid & fid it to find out if it's exported
3629          *
3630          * If the server root isn't exported directly, then
3631          * it should at least be a pseudo export based on
3632          * one or more exports further down in the server's
3633          * file tree.
3634          */
3635         exi = checkexport(&rootdir->v_vfsp->vfs_fsid, &fid, NULL);
3636         if (exi == NULL || exi->exi_export.ex_flags & EX_PUBLIC) {
3637                 NFS4_DEBUG(rfs4_debug,
3638                     (CE_WARN, "rfs4_op_putrootfh: export check failure"));
3639                 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
3640                 if (exi)
3641                         exi_rele(exi);
3642                 goto out;
3643         }
3644 
3645         /*
3646          * Now make a filehandle based on the root
3647          * export and root vnode.
3648          */
3649         error = makefh4(&cs->fh, rootdir, exi);
3650         if (error != 0) {
3651                 *cs->statusp = resp->status = puterrno4(error);
3652                 exi_rele(exi);
3653                 goto out;
3654         }
3655 
3656         sav_exi = cs->exi;
3657         cs->exi = exi;
3658 
3659         VN_HOLD(rootdir);
3660         cs->vp = rootdir;
3661 
3662         if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
3663                 VN_RELE(rootdir);
3664                 cs->vp = NULL;
3665                 exi_rele(exi);
3666                 cs->exi = sav_exi;
3667                 goto out;
3668         }
3669         if (sav_exi)
3670                 exi_rele(sav_exi);
3671 
3672         *cs->statusp = resp->status = NFS4_OK;
3673         cs->deleg = FALSE;
3674 out:
3675         DTRACE_NFSV4_2(op__putrootfh__done, struct compound_state *, cs,
3676             PUTROOTFH4res *, resp);
3677 }
3678 
3679 /*
3680  * set_rdattr_params sets up the variables used to manage what information
3681  * to get for each directory entry.
3682  */
3683 static nfsstat4
3684 set_rdattr_params(struct nfs4_svgetit_arg *sargp,
3685     bitmap4 attrs, bool_t *need_to_lookup)
3686 {
3687         uint_t  va_mask;
3688         nfsstat4 status;
3689         bitmap4 objbits;
3690 


4828 
4829 /* ARGSUSED */
4830 static void
4831 rfs4_op_restorefh(nfs_argop4 *args, nfs_resop4 *resop, struct svc_req *req,
4832     struct compound_state *cs)
4833 {
4834         RESTOREFH4res *resp = &resop->nfs_resop4_u.oprestorefh;
4835 
4836         DTRACE_NFSV4_1(op__restorefh__start, struct compound_state *, cs);
4837 
4838         /* No need to check cs->access - we are not accessing any object */
4839         if ((cs->saved_vp == NULL) || (cs->saved_fh.nfs_fh4_val == NULL)) {
4840                 *cs->statusp = resp->status = NFS4ERR_RESTOREFH;
4841                 goto out;
4842         }
4843         if (cs->vp != NULL) {
4844                 VN_RELE(cs->vp);
4845         }
4846         cs->vp = cs->saved_vp;
4847         cs->saved_vp = NULL;
4848         if (cs->exi)
4849                 exi_rele(cs->exi);
4850         cs->exi = cs->saved_exi;
4851         if (cs->exi)
4852                 exi_hold(cs->exi);
4853         nfs_fh4_copy(&cs->saved_fh, &cs->fh);
4854         *cs->statusp = resp->status = NFS4_OK;
4855         cs->deleg = FALSE;
4856 
4857 out:
4858         DTRACE_NFSV4_2(op__restorefh__done, struct compound_state *, cs,
4859             RESTOREFH4res *, resp);
4860 }
4861 
4862 /* ARGSUSED */
4863 static void
4864 rfs4_op_savefh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
4865     struct compound_state *cs)
4866 {
4867         SAVEFH4res *resp = &resop->nfs_resop4_u.opsavefh;
4868 
4869         DTRACE_NFSV4_1(op__savefh__start, struct compound_state *, cs);
4870 
4871         /* No need to check cs->access - we are not accessing any object */
4872         if (cs->vp == NULL) {
4873                 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
4874                 goto out;
4875         }
4876         if (cs->saved_vp != NULL) {
4877                 VN_RELE(cs->saved_vp);
4878         }
4879         cs->saved_vp = cs->vp;
4880         VN_HOLD(cs->saved_vp);
4881         if (cs->saved_exi)
4882                 exi_rele(cs->saved_exi);
4883         cs->saved_exi = cs->exi;
4884         if (cs->saved_exi)
4885                 exi_hold(cs->saved_exi);
4886         /*
4887          * since SAVEFH is fairly rare, don't alloc space for its fh
4888          * unless necessary.
4889          */
4890         if (cs->saved_fh.nfs_fh4_val == NULL) {
4891                 cs->saved_fh.nfs_fh4_val = kmem_alloc(NFS4_FHSIZE, KM_SLEEP);
4892         }
4893         nfs_fh4_copy(&cs->fh, &cs->saved_fh);
4894         *cs->statusp = resp->status = NFS4_OK;
4895 
4896 out:
4897         DTRACE_NFSV4_2(op__savefh__done, struct compound_state *, cs,
4898             SAVEFH4res *, resp);
4899 }
4900 
4901 /*
4902  * rfs4_verify_attr is called when nfsv4 Setattr failed, but we wish to
4903  * return the bitmap of attrs that were set successfully. It is also
4904  * called by Verify/Nverify to test the vattr/vfsstat attrs. It should
4905  * always be called only after rfs4_do_set_attrs().


5830                 DTRACE_NFSV4_2(compound__start, struct compound_state *,
5831                     &cs, COMPOUND4args *, args);
5832                 crfree(cr);
5833                 DTRACE_NFSV4_2(compound__done, struct compound_state *,
5834                     &cs, COMPOUND4res *, resp);
5835                 svcerr_badcred(req->rq_xprt);
5836                 if (rv != NULL)
5837                         *rv = 1;
5838                 return;
5839         }
5840         resp->array_len = args->array_len;
5841         resp->array = kmem_zalloc(args->array_len * sizeof (nfs_resop4),
5842             KM_SLEEP);
5843 
5844         cs.basecr = cr;
5845 
5846         DTRACE_NFSV4_2(compound__start, struct compound_state *, &cs,
5847             COMPOUND4args *, args);
5848 
5849         /*












5850          * If this is the first compound we've seen, we need to start all
5851          * new instances' grace periods.
5852          */
5853         if (rfs4_seen_first_compound == 0) {
5854                 rfs4_grace_start_new();
5855                 /*
5856                  * This must be set after rfs4_grace_start_new(), otherwise
5857                  * another thread could proceed past here before the former
5858                  * is finished.
5859                  */
5860                 rfs4_seen_first_compound = 1;
5861         }
5862 
5863         for (i = 0; i < args->array_len && cs.cont; i++) {
5864                 nfs_argop4 *argop;
5865                 nfs_resop4 *resop;
5866                 uint_t op;
5867 
5868                 argop = &args->array[i];
5869                 resop = &resp->array[i];


5898                         cs.cont = FALSE;
5899                 }
5900 
5901                 /*
5902                  * If not at last op, and if we are to stop, then
5903                  * compact the results array.
5904                  */
5905                 if ((i + 1) < args->array_len && !cs.cont) {
5906                         nfs_resop4 *new_res = kmem_alloc(
5907                             (i+1) * sizeof (nfs_resop4), KM_SLEEP);
5908                         bcopy(resp->array,
5909                             new_res, (i+1) * sizeof (nfs_resop4));
5910                         kmem_free(resp->array,
5911                             args->array_len * sizeof (nfs_resop4));
5912 
5913                         resp->array_len =  i + 1;
5914                         resp->array = new_res;
5915                 }
5916         }
5917 

5918 
5919         DTRACE_NFSV4_2(compound__done, struct compound_state *, &cs,
5920             COMPOUND4res *, resp);
5921 
5922         if (cs.exi)
5923                 exi_rele(cs.exi);
5924         if (cs.saved_exi)
5925                 exi_rele(cs.saved_exi);
5926         if (cs.vp)
5927                 VN_RELE(cs.vp);
5928         if (cs.saved_vp)
5929                 VN_RELE(cs.saved_vp);
5930         if (cs.saved_fh.nfs_fh4_val)
5931                 kmem_free(cs.saved_fh.nfs_fh4_val, NFS4_FHSIZE);
5932 
5933         if (cs.basecr)
5934                 crfree(cs.basecr);
5935         if (cs.cr)
5936                 crfree(cs.cr);
5937         /*
5938          * done with this compound request, free the label
5939          */
5940 
5941         if (req->rq_label != NULL) {
5942                 kmem_free(req->rq_label, sizeof (bslabel_t));
5943                 req->rq_label = NULL;
5944         }
5945 }


7506                 if (!replay)
7507                         rfs4_update_open_resp(oo, resop, &cs->fh);
7508 
7509                 /*
7510                  * REPLAY case: Only if the previous response was OK
7511                  * do we copy the filehandle.  If not OK, no
7512                  * filehandle to copy.
7513                  */
7514                 if (replay == TRUE &&
7515                     resp->status == NFS4_OK &&
7516                     oo->ro_reply_fh.nfs_fh4_val) {
7517                         /*
7518                          * If this is a replay, we must restore the
7519                          * current filehandle/vp to that of what was
7520                          * returned originally.  Try our best to do
7521                          * it.
7522                          */
7523                         nfs_fh4_fmt_t *fh_fmtp =
7524                             (nfs_fh4_fmt_t *)oo->ro_reply_fh.nfs_fh4_val;
7525 
7526                         if (cs->exi)
7527                                 exi_rele(cs->exi);
7528                         cs->exi = checkexport(&fh_fmtp->fh4_fsid,
7529                             (fid_t *)&fh_fmtp->fh4_xlen, NULL);
7530 
7531                         if (cs->exi == NULL) {
7532                                 resp->status = NFS4ERR_STALE;
7533                                 goto finish;
7534                         }
7535 
7536                         VN_RELE(cs->vp);
7537 
7538                         cs->vp = nfs4_fhtovp(&oo->ro_reply_fh, cs->exi,
7539                             &resp->status);
7540 
7541                         if (cs->vp == NULL)
7542                                 goto finish;
7543 
7544                         nfs_fh4_copy(&oo->ro_reply_fh, &cs->fh);
7545                 }
7546 
7547                 /*
7548                  * If this was a replay, no need to update the