Handle possible vnode reclamation after ncl_vinvalbuf() call.
ncl_vinvalbuf() might need to upgrade vnode lock, allowing the vnode to be reclaimed by other thread. Handle the situation, indicated by the returned error zero and VI_DOOMED iflag set, converting it into EBADF. Handle all calls, even where the vnode is exclusively locked right now. Reviewed by: markj, rmacklem Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks X-Differential revision: https://reviews.freebsd.org/D10241
This commit is contained in:
parent
0226f65940
commit
48fe926362
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=316529
@ -394,8 +394,8 @@ nfs_bioread_check_cons(struct vnode *vp, struct thread *td, struct ucred *cred)
|
||||
*/
|
||||
old_lock = ncl_upgrade_vnlock(vp);
|
||||
if (vp->v_iflag & VI_DOOMED) {
|
||||
ncl_downgrade_vnlock(vp, old_lock);
|
||||
return (EBADF);
|
||||
error = EBADF;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mtx_lock(&np->n_mtx);
|
||||
@ -406,7 +406,9 @@ nfs_bioread_check_cons(struct vnode *vp, struct thread *td, struct ucred *cred)
|
||||
panic("nfs: bioread, not dir");
|
||||
ncl_invaldir(vp);
|
||||
error = ncl_vinvalbuf(vp, V_SAVE, td, 1);
|
||||
if (error)
|
||||
if (error == 0 && (vp->v_iflag & VI_DOOMED) != 0)
|
||||
error = EBADF;
|
||||
if (error != 0)
|
||||
goto out;
|
||||
}
|
||||
np->n_attrstamp = 0;
|
||||
@ -429,7 +431,9 @@ nfs_bioread_check_cons(struct vnode *vp, struct thread *td, struct ucred *cred)
|
||||
if (vp->v_type == VDIR)
|
||||
ncl_invaldir(vp);
|
||||
error = ncl_vinvalbuf(vp, V_SAVE, td, 1);
|
||||
if (error)
|
||||
if (error == 0 && (vp->v_iflag & VI_DOOMED) != 0)
|
||||
error = EBADF;
|
||||
if (error != 0)
|
||||
goto out;
|
||||
mtx_lock(&np->n_mtx);
|
||||
np->n_mtime = vattr.va_mtime;
|
||||
@ -439,7 +443,7 @@ nfs_bioread_check_cons(struct vnode *vp, struct thread *td, struct ucred *cred)
|
||||
}
|
||||
out:
|
||||
ncl_downgrade_vnlock(vp, old_lock);
|
||||
return error;
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -623,6 +627,9 @@ ncl_bioread(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred)
|
||||
while (error == NFSERR_BAD_COOKIE) {
|
||||
ncl_invaldir(vp);
|
||||
error = ncl_vinvalbuf(vp, 0, td, 1);
|
||||
if (error == 0 && (vp->v_iflag & VI_DOOMED) != 0)
|
||||
return (EBADF);
|
||||
|
||||
/*
|
||||
* Yuck! The directory has been modified on the
|
||||
* server. The only way to get the block is by
|
||||
@ -943,8 +950,11 @@ ncl_write(struct vop_write_args *ap)
|
||||
#endif
|
||||
np->n_attrstamp = 0;
|
||||
KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
|
||||
error = ncl_vinvalbuf(vp, V_SAVE, td, 1);
|
||||
if (error)
|
||||
error = ncl_vinvalbuf(vp, V_SAVE | ((ioflag &
|
||||
IO_VMIO) != 0 ? V_VMIO : 0), td, 1);
|
||||
if (error == 0 && (vp->v_iflag & VI_DOOMED) != 0)
|
||||
error = EBADF;
|
||||
if (error != 0)
|
||||
return (error);
|
||||
} else
|
||||
mtx_unlock(&np->n_mtx);
|
||||
@ -1023,8 +1033,12 @@ ncl_write(struct vop_write_args *ap)
|
||||
if (wouldcommit > nmp->nm_wcommitsize) {
|
||||
np->n_attrstamp = 0;
|
||||
KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
|
||||
error = ncl_vinvalbuf(vp, V_SAVE, td, 1);
|
||||
if (error)
|
||||
error = ncl_vinvalbuf(vp, V_SAVE | ((ioflag &
|
||||
IO_VMIO) != 0 ? V_VMIO : 0), td, 1);
|
||||
if (error == 0 &&
|
||||
(vp->v_iflag & VI_DOOMED) != 0)
|
||||
error = EBADF;
|
||||
if (error != 0)
|
||||
return (error);
|
||||
wouldcommit = biosize;
|
||||
}
|
||||
|
@ -520,6 +520,8 @@ nfs_open(struct vop_open_args *ap)
|
||||
if (np->n_flag & NMODIFIED) {
|
||||
mtx_unlock(&np->n_mtx);
|
||||
error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1);
|
||||
if (error == 0 && (vp->v_iflag & VI_DOOMED) != 0)
|
||||
return (EBADF);
|
||||
if (error == EINTR || error == EIO) {
|
||||
if (NFS_ISV4(vp))
|
||||
(void) nfsrpc_close(vp, 0, ap->a_td);
|
||||
@ -556,6 +558,8 @@ nfs_open(struct vop_open_args *ap)
|
||||
np->n_direofoffset = 0;
|
||||
mtx_unlock(&np->n_mtx);
|
||||
error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1);
|
||||
if (error == 0 && (vp->v_iflag & VI_DOOMED) != 0)
|
||||
return (EBADF);
|
||||
if (error == EINTR || error == EIO) {
|
||||
if (NFS_ISV4(vp))
|
||||
(void) nfsrpc_close(vp, 0, ap->a_td);
|
||||
@ -576,6 +580,8 @@ nfs_open(struct vop_open_args *ap)
|
||||
if (np->n_directio_opens == 0) {
|
||||
mtx_unlock(&np->n_mtx);
|
||||
error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1);
|
||||
if (error == 0 && (vp->v_iflag & VI_DOOMED) != 0)
|
||||
return (EBADF);
|
||||
if (error) {
|
||||
if (NFS_ISV4(vp))
|
||||
(void) nfsrpc_close(vp, 0, ap->a_td);
|
||||
@ -714,8 +720,11 @@ nfs_close(struct vop_close_args *ap)
|
||||
* np->n_flag &= ~NMODIFIED;
|
||||
*/
|
||||
}
|
||||
} else
|
||||
error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1);
|
||||
} else {
|
||||
error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1);
|
||||
if (error == 0 && (vp->v_iflag & VI_DOOMED) != 0)
|
||||
return (EBADF);
|
||||
}
|
||||
mtx_lock(&np->n_mtx);
|
||||
}
|
||||
/*
|
||||
@ -931,13 +940,13 @@ nfs_setattr(struct vop_setattr_args *ap)
|
||||
if (np->n_flag & NMODIFIED) {
|
||||
tsize = np->n_size;
|
||||
mtx_unlock(&np->n_mtx);
|
||||
if (vap->va_size == 0)
|
||||
error = ncl_vinvalbuf(vp, 0, td, 1);
|
||||
else
|
||||
error = ncl_vinvalbuf(vp, V_SAVE, td, 1);
|
||||
if (error) {
|
||||
vnode_pager_setsize(vp, tsize);
|
||||
return (error);
|
||||
error = ncl_vinvalbuf(vp, vap->va_size == 0 ?
|
||||
0 : V_SAVE, td, 1);
|
||||
if (error == 0 && (vp->v_iflag & VI_DOOMED) != 0)
|
||||
error = EBADF;
|
||||
if (error != 0) {
|
||||
vnode_pager_setsize(vp, tsize);
|
||||
return (error);
|
||||
}
|
||||
/*
|
||||
* Call nfscl_delegmodtime() to set the modify time
|
||||
@ -961,8 +970,10 @@ nfs_setattr(struct vop_setattr_args *ap)
|
||||
if ((vap->va_mtime.tv_sec != VNOVAL || vap->va_atime.tv_sec != VNOVAL) &&
|
||||
(np->n_flag & NMODIFIED) && vp->v_type == VREG) {
|
||||
mtx_unlock(&np->n_mtx);
|
||||
if ((error = ncl_vinvalbuf(vp, V_SAVE, td, 1)) != 0 &&
|
||||
(error == EINTR || error == EIO))
|
||||
error = ncl_vinvalbuf(vp, V_SAVE, td, 1);
|
||||
if (error == 0 && (vp->v_iflag & VI_DOOMED) != 0)
|
||||
return (EBADF);
|
||||
if (error == EINTR || error == EIO)
|
||||
return (error);
|
||||
} else
|
||||
mtx_unlock(&np->n_mtx);
|
||||
@ -1665,8 +1676,10 @@ nfs_remove(struct vop_remove_args *ap)
|
||||
* unnecessary delayed writes later.
|
||||
*/
|
||||
error = ncl_vinvalbuf(vp, 0, cnp->cn_thread, 1);
|
||||
/* Do the rpc */
|
||||
if (error != EINTR && error != EIO)
|
||||
if (error == 0 && (vp->v_iflag & VI_DOOMED) != 0)
|
||||
error = EBADF;
|
||||
else if (error != EINTR && error != EIO)
|
||||
/* Do the rpc */
|
||||
error = nfs_removerpc(dvp, vp, cnp->cn_nameptr,
|
||||
cnp->cn_namelen, cnp->cn_cred, cnp->cn_thread);
|
||||
/*
|
||||
@ -3055,6 +3068,10 @@ nfs_advlock(struct vop_advlock_args *ap)
|
||||
if ((np->n_flag & NMODIFIED) || ret ||
|
||||
np->n_change != va.va_filerev) {
|
||||
(void) ncl_vinvalbuf(vp, V_SAVE, td, 1);
|
||||
if ((vp->v_iflag & VI_DOOMED) != 0) {
|
||||
NFSVOPUNLOCK(vp, 0);
|
||||
return (EBADF);
|
||||
}
|
||||
np->n_attrstamp = 0;
|
||||
KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
|
||||
ret = VOP_GETATTR(vp, &va, cred);
|
||||
|
Loading…
Reference in New Issue
Block a user