Print this page
7378 exported_lock held during nfs4 compound processing
@@ -870,10 +870,11 @@
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,11 +962,11 @@
} 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.
+ * a server fs boundary and need to call checkexport.
* (LOFS lookup hides server fs mountpoints, and actually calls
* traverse)
*/
different_export = 1;
}
@@ -982,15 +983,15 @@
VN_RELE(vp);
return (puterrno4(error));
}
if (dotdot)
- exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
+ oexi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
else
- exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
+ oexi = checkexport(&vp->v_vfsp->vfs_fsid, &fid, vp);
- if (exi == NULL) {
+ 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,10 +1001,12 @@
exi = cs->exi;
} else {
VN_RELE(vp);
return (puterrno4(EACCES));
}
+ } else {
+ exi = oexi;
}
} else {
exi = cs->exi;
}
ASSERT(exi != NULL);
@@ -1015,11 +1018,11 @@
*
* 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));
+ 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,11 +1111,13 @@
}
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,11 +2614,11 @@
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;
+ struct exportinfo *exi = NULL, *pre_exi = NULL, *oexi = NULL;
nfsstat4 stat;
fid_t fid;
int attrdir, dotdot, walk;
bool_t is_newvp = FALSE;
@@ -2703,11 +2708,11 @@
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
+ * need pre_tvp below if checkexport fails
*/
VN_HOLD(pre_tvp);
if ((error = traverse(&vp)) != 0) {
VN_RELE(vp);
VN_RELE(pre_tvp);
@@ -2739,11 +2744,11 @@
}
if (dotdot)
exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
else
- exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
+ exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid, vp);
if (exi == NULL) {
if (pre_tvp) {
/*
* If this vnode is a mounted-on vnode,
@@ -2753,19 +2758,23 @@
* 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,20 +3451,26 @@
*/
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
+ * should use is what checkexport returns, because root_exi is
* actually a mostly empty struct.
*/
- exi = checkexport4(&fh_fmtp->fh4_fsid,
+ exi = checkexport(&fh_fmtp->fh4_fsid,
(fid_t *)&fh_fmtp->fh4_xlen, NULL);
- cs->exi = ((exi != NULL) ? exi : exi_public);
+ 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,10 +3483,12 @@
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,13 +3496,16 @@
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,11 +3554,13 @@
*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,
+ 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,25 +3630,28 @@
* 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);
+ 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,13 +3660,16 @@
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,11 +4843,15 @@
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,11 +4876,15 @@
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,22 +5845,10 @@
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();
@@ -5889,15 +5913,18 @@
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.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,11 +7521,13 @@
* 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,
+ 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;