Date: Wed, 5 Apr 2017 17:11:39 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r316529 - head/sys/fs/nfsclient Message-ID: <201704051711.v35HBdWF072551@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Wed Apr 5 17:11:39 2017 New Revision: 316529 URL: https://svnweb.freebsd.org/changeset/base/316529 Log: 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 Modified: head/sys/fs/nfsclient/nfs_clbio.c head/sys/fs/nfsclient/nfs_clvnops.c Modified: head/sys/fs/nfsclient/nfs_clbio.c ============================================================================== --- head/sys/fs/nfsclient/nfs_clbio.c Wed Apr 5 16:57:53 2017 (r316528) +++ head/sys/fs/nfsclient/nfs_clbio.c Wed Apr 5 17:11:39 2017 (r316529) @@ -394,8 +394,8 @@ nfs_bioread_check_cons(struct vnode *vp, */ 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, 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, 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, } out: ncl_downgrade_vnlock(vp, old_lock); - return error; + return (error); } /* @@ -623,6 +627,9 @@ ncl_bioread(struct vnode *vp, struct uio 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; } Modified: head/sys/fs/nfsclient/nfs_clvnops.c ============================================================================== --- head/sys/fs/nfsclient/nfs_clvnops.c Wed Apr 5 16:57:53 2017 (r316528) +++ head/sys/fs/nfsclient/nfs_clvnops.c Wed Apr 5 17:11:39 2017 (r316529) @@ -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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201704051711.v35HBdWF072551>