Print this page
7378 exported_lock held during nfs4 compound processing

*** 870,879 **** --- 870,880 ---- do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp) { int error, different_export = 0; vnode_t *dvp, *vp; struct exportinfo *exi = NULL; + struct exportinfo *oexi = NULL; fid_t fid; uint_t count, i; secinfo4 *resok_val; struct secinfo *secp; seconfig_t *si;
*** 961,971 **** } else if (vp->v_vfsp != dvp->v_vfsp) { /* * If vp isn't a mountpoint and the vfs ptrs aren't the same, * then vp is probably an LOFS object. We don't need the * realvp, we just need to know that we might have crossed ! * a server fs boundary and need to call checkexport4. * (LOFS lookup hides server fs mountpoints, and actually calls * traverse) */ different_export = 1; } --- 962,972 ---- } else if (vp->v_vfsp != dvp->v_vfsp) { /* * If vp isn't a mountpoint and the vfs ptrs aren't the same, * then vp is probably an LOFS object. We don't need the * realvp, we just need to know that we might have crossed ! * a server fs boundary and need to call checkexport. * (LOFS lookup hides server fs mountpoints, and actually calls * traverse) */ different_export = 1; }
*** 982,996 **** VN_RELE(vp); return (puterrno4(error)); } if (dotdot) ! exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE); else ! exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); ! if (exi == NULL) { if (did_traverse == TRUE) { /* * If this vnode is a mounted-on vnode, * but the mounted-on file system is not * exported, send back the secinfo for --- 983,997 ---- VN_RELE(vp); return (puterrno4(error)); } if (dotdot) ! oexi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE); else ! oexi = checkexport(&vp->v_vfsp->vfs_fsid, &fid, vp); ! if (oexi == NULL) { if (did_traverse == TRUE) { /* * If this vnode is a mounted-on vnode, * but the mounted-on file system is not * exported, send back the secinfo for
*** 1000,1009 **** --- 1001,1012 ---- exi = cs->exi; } else { VN_RELE(vp); return (puterrno4(EACCES)); } + } else { + exi = oexi; } } else { exi = cs->exi; } ASSERT(exi != NULL);
*** 1015,1025 **** * * Return all flavors for a pseudo node. * For a real export node, return the flavor that the client * has access with. */ ! ASSERT(RW_LOCK_HELD(&exported_lock)); if (PSEUDO(exi)) { count = exi->exi_export.ex_seccnt; /* total sec count */ resok_val = kmem_alloc(count * sizeof (secinfo4), KM_SLEEP); secp = exi->exi_export.ex_secinfo; --- 1018,1028 ---- * * Return all flavors for a pseudo node. * For a real export node, return the flavor that the client * has access with. */ ! rw_enter(&exported_lock, RW_READER); if (PSEUDO(exi)) { count = exi->exi_export.ex_seccnt; /* total sec count */ resok_val = kmem_alloc(count * sizeof (secinfo4), KM_SLEEP); secp = exi->exi_export.ex_secinfo;
*** 1108,1118 **** } resp->SECINFO4resok_len = ret_cnt; resp->SECINFO4resok_val = resok_val; kmem_free(flavor_list, count * sizeof (int)); } ! VN_RELE(vp); return (NFS4_OK); } /* --- 1111,1123 ---- } resp->SECINFO4resok_len = ret_cnt; resp->SECINFO4resok_val = resok_val; kmem_free(flavor_list, count * sizeof (int)); } ! rw_exit(&exported_lock); ! if (oexi) ! exi_rele(oexi); VN_RELE(vp); return (NFS4_OK); } /*
*** 2609,2619 **** do_rfs4_op_lookup(char *nm, struct svc_req *req, struct compound_state *cs) { int error; int different_export = 0; vnode_t *vp, *pre_tvp = NULL, *oldvp = NULL; ! struct exportinfo *exi = NULL, *pre_exi = NULL; nfsstat4 stat; fid_t fid; int attrdir, dotdot, walk; bool_t is_newvp = FALSE; --- 2614,2624 ---- do_rfs4_op_lookup(char *nm, struct svc_req *req, struct compound_state *cs) { int error; int different_export = 0; vnode_t *vp, *pre_tvp = NULL, *oldvp = NULL; ! struct exportinfo *exi = NULL, *pre_exi = NULL, *oexi = NULL; nfsstat4 stat; fid_t fid; int attrdir, dotdot, walk; bool_t is_newvp = FALSE;
*** 2703,2713 **** pre_exi = cs->exi; /* save pre-traversed exportinfo */ pre_tvp = vp; /* save pre-traversed vnode */ /* * hold pre_tvp to counteract rele by traverse. We will ! * need pre_tvp below if checkexport4 fails */ VN_HOLD(pre_tvp); if ((error = traverse(&vp)) != 0) { VN_RELE(vp); VN_RELE(pre_tvp); --- 2708,2718 ---- pre_exi = cs->exi; /* save pre-traversed exportinfo */ pre_tvp = vp; /* save pre-traversed vnode */ /* * hold pre_tvp to counteract rele by traverse. We will ! * need pre_tvp below if checkexport fails */ VN_HOLD(pre_tvp); if ((error = traverse(&vp)) != 0) { VN_RELE(vp); VN_RELE(pre_tvp);
*** 2739,2749 **** } if (dotdot) exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE); else ! exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); if (exi == NULL) { if (pre_tvp) { /* * If this vnode is a mounted-on vnode, --- 2744,2754 ---- } if (dotdot) exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE); else ! exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid, vp); if (exi == NULL) { if (pre_tvp) { /* * If this vnode is a mounted-on vnode,
*** 2753,2771 **** --- 2758,2780 ---- * the mounted-on file system. */ VN_RELE(vp); vp = pre_tvp; exi = pre_exi; + if (exi) + exi_hold(exi); } else { VN_RELE(vp); return (puterrno4(EACCES)); } } else if (pre_tvp) { /* we're done with pre_tvp now. release extra hold */ VN_RELE(pre_tvp); } + if (cs->exi) + exi_rele(cs->exi); cs->exi = exi; /* * Now we do a checkauth4. The reason is that * this client/user may not have access to the new
*** 3442,3461 **** */ fh_fmtp = (nfs_fh4_fmt_t *)cs->fh.nfs_fh4_val; /* * if root filesystem is exported, the exportinfo struct that we ! * should use is what checkexport4 returns, because root_exi is * actually a mostly empty struct. */ ! exi = checkexport4(&fh_fmtp->fh4_fsid, (fid_t *)&fh_fmtp->fh4_xlen, NULL); ! cs->exi = ((exi != NULL) ? exi : exi_public); } else { /* * it's a properly shared filesystem */ cs->exi = exi_public; } if (is_system_labeled()) { bslabel_t *clabel; --- 3451,3476 ---- */ fh_fmtp = (nfs_fh4_fmt_t *)cs->fh.nfs_fh4_val; /* * if root filesystem is exported, the exportinfo struct that we ! * should use is what checkexport returns, because root_exi is * actually a mostly empty struct. */ ! exi = checkexport(&fh_fmtp->fh4_fsid, (fid_t *)&fh_fmtp->fh4_xlen, NULL); ! if (exi) { ! cs->exi = exi; ! } else { ! exi_hold(exi_public); ! cs->exi = exi_public; ! } } else { /* * it's a properly shared filesystem */ + exi_hold(exi_public); cs->exi = exi_public; } if (is_system_labeled()) { bslabel_t *clabel;
*** 3468,3477 **** --- 3483,3494 ---- if (!blequal(&l_admin_low->tsl_label, clabel)) { if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK, cs->exi)) { *cs->statusp = resp->status = NFS4ERR_SERVERFAULT; + if (sav_exi) + exi_rele(sav_exi); goto out; } } }
*** 3479,3491 **** --- 3496,3511 ---- cs->vp = vp; if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) { VN_RELE(cs->vp); cs->vp = NULL; + exi_rele(cs->exi); cs->exi = sav_exi; goto out; } + if (sav_exi) + exi_rele(sav_exi); *cs->statusp = resp->status = NFS4_OK; out: DTRACE_NFSV4_2(op__putpubfh__done, struct compound_state *, cs, PUTPUBFH4res *, resp);
*** 3534,3544 **** *cs->statusp = resp->status = NFS4ERR_BADHANDLE; goto out; } fh_fmtp = (nfs_fh4_fmt_t *)args->object.nfs_fh4_val; ! cs->exi = checkexport4(&fh_fmtp->fh4_fsid, (fid_t *)&fh_fmtp->fh4_xlen, NULL); if (cs->exi == NULL) { *cs->statusp = resp->status = NFS4ERR_STALE; goto out; --- 3554,3566 ---- *cs->statusp = resp->status = NFS4ERR_BADHANDLE; goto out; } fh_fmtp = (nfs_fh4_fmt_t *)args->object.nfs_fh4_val; ! if (cs->exi) ! exi_rele(cs->exi); ! cs->exi = checkexport(&fh_fmtp->fh4_fsid, (fid_t *)&fh_fmtp->fh4_xlen, NULL); if (cs->exi == NULL) { *cs->statusp = resp->status = NFS4ERR_STALE; goto out;
*** 3608,3632 **** * If the server root isn't exported directly, then * it should at least be a pseudo export based on * one or more exports further down in the server's * file tree. */ ! exi = checkexport4(&rootdir->v_vfsp->vfs_fsid, &fid, NULL); if (exi == NULL || exi->exi_export.ex_flags & EX_PUBLIC) { NFS4_DEBUG(rfs4_debug, (CE_WARN, "rfs4_op_putrootfh: export check failure")); *cs->statusp = resp->status = NFS4ERR_SERVERFAULT; goto out; } /* * Now make a filehandle based on the root * export and root vnode. */ error = makefh4(&cs->fh, rootdir, exi); if (error != 0) { *cs->statusp = resp->status = puterrno4(error); goto out; } sav_exi = cs->exi; cs->exi = exi; --- 3630,3657 ---- * If the server root isn't exported directly, then * it should at least be a pseudo export based on * one or more exports further down in the server's * file tree. */ ! exi = checkexport(&rootdir->v_vfsp->vfs_fsid, &fid, NULL); if (exi == NULL || exi->exi_export.ex_flags & EX_PUBLIC) { NFS4_DEBUG(rfs4_debug, (CE_WARN, "rfs4_op_putrootfh: export check failure")); *cs->statusp = resp->status = NFS4ERR_SERVERFAULT; + if (exi) + exi_rele(exi); goto out; } /* * Now make a filehandle based on the root * export and root vnode. */ error = makefh4(&cs->fh, rootdir, exi); if (error != 0) { *cs->statusp = resp->status = puterrno4(error); + exi_rele(exi); goto out; } sav_exi = cs->exi; cs->exi = exi;
*** 3635,3647 **** --- 3660,3675 ---- cs->vp = rootdir; if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) { VN_RELE(rootdir); cs->vp = NULL; + exi_rele(exi); cs->exi = sav_exi; goto out; } + if (sav_exi) + exi_rele(sav_exi); *cs->statusp = resp->status = NFS4_OK; cs->deleg = FALSE; out: DTRACE_NFSV4_2(op__putrootfh__done, struct compound_state *, cs,
*** 4815,4825 **** --- 4843,4857 ---- if (cs->vp != NULL) { VN_RELE(cs->vp); } cs->vp = cs->saved_vp; cs->saved_vp = NULL; + if (cs->exi) + exi_rele(cs->exi); cs->exi = cs->saved_exi; + if (cs->exi) + exi_hold(cs->exi); nfs_fh4_copy(&cs->saved_fh, &cs->fh); *cs->statusp = resp->status = NFS4_OK; cs->deleg = FALSE; out:
*** 4844,4854 **** --- 4876,4890 ---- if (cs->saved_vp != NULL) { VN_RELE(cs->saved_vp); } cs->saved_vp = cs->vp; VN_HOLD(cs->saved_vp); + if (cs->saved_exi) + exi_rele(cs->saved_exi); cs->saved_exi = cs->exi; + if (cs->saved_exi) + exi_hold(cs->saved_exi); /* * since SAVEFH is fairly rare, don't alloc space for its fh * unless necessary. */ if (cs->saved_fh.nfs_fh4_val == NULL) {
*** 5809,5830 **** DTRACE_NFSV4_2(compound__start, struct compound_state *, &cs, COMPOUND4args *, args); /* - * For now, NFS4 compound processing must be protected by - * exported_lock because it can access more than one exportinfo - * per compound and share/unshare can now change multiple - * exinfo structs. The NFS2/3 code only refs 1 exportinfo - * per proc (excluding public exinfo), and exi_count design - * is sufficient to protect concurrent execution of NFS2/3 - * ops along with unexport. This lock will be removed as - * part of the NFSv4 phase 2 namespace redesign work. - */ - rw_enter(&exported_lock, RW_READER); - - /* * If this is the first compound we've seen, we need to start all * new instances' grace periods. */ if (rfs4_seen_first_compound == 0) { rfs4_grace_start_new(); --- 5845,5854 ----
*** 5889,5903 **** resp->array_len = i + 1; resp->array = new_res; } } - rw_exit(&exported_lock); DTRACE_NFSV4_2(compound__done, struct compound_state *, &cs, COMPOUND4res *, resp); if (cs.vp) VN_RELE(cs.vp); if (cs.saved_vp) VN_RELE(cs.saved_vp); if (cs.saved_fh.nfs_fh4_val) --- 5913,5930 ---- resp->array_len = i + 1; resp->array = new_res; } } DTRACE_NFSV4_2(compound__done, struct compound_state *, &cs, COMPOUND4res *, resp); + if (cs.exi) + exi_rele(cs.exi); + if (cs.saved_exi) + exi_rele(cs.saved_exi); if (cs.vp) VN_RELE(cs.vp); if (cs.saved_vp) VN_RELE(cs.saved_vp); if (cs.saved_fh.nfs_fh4_val)
*** 7494,7504 **** * it. */ nfs_fh4_fmt_t *fh_fmtp = (nfs_fh4_fmt_t *)oo->ro_reply_fh.nfs_fh4_val; ! cs->exi = checkexport4(&fh_fmtp->fh4_fsid, (fid_t *)&fh_fmtp->fh4_xlen, NULL); if (cs->exi == NULL) { resp->status = NFS4ERR_STALE; goto finish; --- 7521,7533 ---- * it. */ nfs_fh4_fmt_t *fh_fmtp = (nfs_fh4_fmt_t *)oo->ro_reply_fh.nfs_fh4_val; ! if (cs->exi) ! exi_rele(cs->exi); ! cs->exi = checkexport(&fh_fmtp->fh4_fsid, (fid_t *)&fh_fmtp->fh4_xlen, NULL); if (cs->exi == NULL) { resp->status = NFS4ERR_STALE; goto finish;