From owner-svn-src-head@freebsd.org Wed Apr 5 17:11:40 2017 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 7ED73D30EF9; Wed, 5 Apr 2017 17:11:40 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 5C15BE6D; Wed, 5 Apr 2017 17:11:40 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v35HBdrA072671; Wed, 5 Apr 2017 17:11:39 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v35HBdWF072551; Wed, 5 Apr 2017 17:11:39 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201704051711.v35HBdWF072551@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Wed, 5 Apr 2017 17:11:39 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r316529 - head/sys/fs/nfsclient X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 05 Apr 2017 17:11:40 -0000 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);