cache: fix vexec panic when racing against vgone
Use of dead_vnodeops would result in a panic instead of returning the intended EOPNOTSUPP error. While here make sure to abort, not just try to return a partial result. The former allows the regular lookup to restart from scratch, while the latter makes it stuck with an unusable vnode. Reported by: kevans
This commit is contained in:
parent
b56d7f9663
commit
eb88fed446
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=366582
@ -79,6 +79,7 @@ struct vop_vector dead_vnodeops = {
|
||||
.vop_vptocnp = VOP_EBADF,
|
||||
.vop_unset_text = dead_unset_text,
|
||||
.vop_write = dead_write,
|
||||
.vop_fplookup_vexec = VOP_EOPNOTSUPP,
|
||||
};
|
||||
VFS_VOP_VECTOR_REGISTER(dead_vnodeops);
|
||||
|
||||
|
@ -4040,32 +4040,46 @@ cache_fplookup_parse_advance(struct cache_fpl *fpl)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* See the API contract for VOP_FPLOOKUP_VEXEC.
|
||||
*/
|
||||
static int __noinline
|
||||
cache_fplookup_failed_vexec(struct cache_fpl *fpl, int error)
|
||||
{
|
||||
struct vnode *dvp;
|
||||
seqc_t dvp_seqc;
|
||||
|
||||
dvp = fpl->dvp;
|
||||
dvp_seqc = fpl->dvp_seqc;
|
||||
|
||||
/*
|
||||
* Hack: they may be looking up foo/bar, where foo is a
|
||||
* regular file. In such a case we need to turn ENOTDIR,
|
||||
* but we may happen to get here with a different error.
|
||||
*/
|
||||
if (fpl->dvp->v_type != VDIR) {
|
||||
if (dvp->v_type != VDIR) {
|
||||
/*
|
||||
* The check here is predominantly to catch
|
||||
* EOPNOTSUPP from dead_vnodeops. If the vnode
|
||||
* gets doomed past this point it is going to
|
||||
* fail seqc verification.
|
||||
*/
|
||||
if (VN_IS_DOOMED(dvp)) {
|
||||
return (cache_fpl_aborted(fpl));
|
||||
}
|
||||
error = ENOTDIR;
|
||||
}
|
||||
|
||||
switch (error) {
|
||||
case EAGAIN:
|
||||
/*
|
||||
* Can happen when racing against vgone.
|
||||
* */
|
||||
case EOPNOTSUPP:
|
||||
cache_fpl_partial(fpl);
|
||||
if (!vn_seqc_consistent(dvp, dvp_seqc)) {
|
||||
error = cache_fpl_aborted(fpl);
|
||||
} else {
|
||||
cache_fpl_partial(fpl);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* See the API contract for VOP_FPLOOKUP_VEXEC.
|
||||
*/
|
||||
if (!vn_seqc_consistent(fpl->dvp, fpl->dvp_seqc)) {
|
||||
if (!vn_seqc_consistent(dvp, dvp_seqc)) {
|
||||
error = cache_fpl_aborted(fpl);
|
||||
} else {
|
||||
cache_fpl_smr_exit(fpl);
|
||||
|
Loading…
Reference in New Issue
Block a user