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;