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
|