The branch main has been updated by kib:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=8ef0c11e7ce79106130012cb929a8324045f7ff9

commit 8ef0c11e7ce79106130012cb929a8324045f7ff9
Author:     Konstantin Belousov <k...@freebsd.org>
AuthorDate: 2021-11-15 20:24:46 +0000
Commit:     Konstantin Belousov <k...@freebsd.org>
CommitDate: 2021-11-16 17:13:29 +0000

    nfsclient: upgrade vnode lock in VOP_OPEN()/VOP_CLOSE() if we need to flush 
buffers
    
    VOP_FSYNC() asserts that the vnode is exclusively locked for NFS.
    If we try to execute file with recently modified content, the assert is
    triggered.
    
    Reviewed by:    rmacklem
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D32999
---
 sys/fs/nfsclient/nfs_clvnops.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index d4545cf2d840..920bf2524c01 100644
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -647,6 +647,11 @@ nfs_open(struct vop_open_args *ap)
        NFSLOCKNODE(np);
        if (np->n_flag & NMODIFIED) {
                NFSUNLOCKNODE(np);
+               if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) {
+                       NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY);
+                       if (VN_IS_DOOMED(vp))
+                               return (EBADF);
+               }
                error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1);
                if (error == EINTR || error == EIO) {
                        if (NFS_ISV4(vp))
@@ -683,6 +688,11 @@ nfs_open(struct vop_open_args *ap)
                        if (vp->v_type == VDIR)
                                np->n_direofoffset = 0;
                        NFSUNLOCKNODE(np);
+                       if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) {
+                               NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY);
+                               if (VN_IS_DOOMED(vp))
+                                       return (EBADF);
+                       }
                        error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1);
                        if (error == EINTR || error == EIO) {
                                if (NFS_ISV4(vp))
@@ -703,6 +713,11 @@ nfs_open(struct vop_open_args *ap)
            (vp->v_type == VREG)) {
                if (np->n_directio_opens == 0) {
                        NFSUNLOCKNODE(np);
+                       if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) {
+                               NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY);
+                               if (VN_IS_DOOMED(vp))
+                                       return (EBADF);
+                       }
                        error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1);
                        if (error) {
                                if (NFS_ISV4(vp))
@@ -748,6 +763,11 @@ nfs_open(struct vop_open_args *ap)
        if (vp->v_writecount <= -1) {
                if ((obj = vp->v_object) != NULL &&
                    vm_object_mightbedirty(obj)) {
+                       if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) {
+                               NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY);
+                               if (VN_IS_DOOMED(vp))
+                                       return (EBADF);
+                       }
                        VM_OBJECT_WLOCK(obj);
                        vm_object_page_clean(obj, 0, 0, OBJPC_SYNC);
                        VM_OBJECT_WUNLOCK(obj);
@@ -831,6 +851,11 @@ nfs_close(struct vop_close_args *ap)
             * mmap'ed writes or via write().
             */
            if (nfs_clean_pages_on_close && vp->v_object) {
+               if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) {
+                       NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY);
+                       if (VN_IS_DOOMED(vp) && ap->a_fflag != FNONBLOCK)
+                               return (EBADF);
+               }
                VM_OBJECT_WLOCK(vp->v_object);
                vm_object_page_clean(vp->v_object, 0, 0, 0);
                VM_OBJECT_WUNLOCK(vp->v_object);
@@ -855,11 +880,22 @@ nfs_close(struct vop_close_args *ap)
                     * traditional vnode locking implemented for Vnode Ops.
                     */
                    int cm = newnfs_commit_on_close ? 1 : 0;
+                   if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) {
+                           NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY);
+                           if (VN_IS_DOOMED(vp) && ap->a_fflag != FNONBLOCK)
+                                   return (EBADF);
+                   }
                    error = ncl_flush(vp, MNT_WAIT, ap->a_td, cm, 0);
                    /* np->n_flag &= ~NMODIFIED; */
                } else if (NFS_ISV4(vp)) { 
                        if (nfscl_mustflush(vp) != 0) {
                                int cm = newnfs_commit_on_close ? 1 : 0;
+                               if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) {
+                                       NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY);
+                                       if (VN_IS_DOOMED(vp) && ap->a_fflag !=
+                                           FNONBLOCK)
+                                               return (EBADF);
+                               }
                                error = ncl_flush(vp, MNT_WAIT, ap->a_td,
                                    cm, 0);
                                /*
@@ -869,6 +905,12 @@ nfs_close(struct vop_close_args *ap)
                                 */
                        }
                } else {
+                       if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) {
+                               NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY);
+                               if (VN_IS_DOOMED(vp) && ap->a_fflag !=
+                                   FNONBLOCK)
+                                       return (EBADF);
+                       }
                        error = ncl_vinvalbuf(vp, V_SAVE, ap->a_td, 1);
                }
                NFSLOCKNODE(np);

Reply via email to