Author: kib
Date: Sat Feb 29 22:10:00 2020
New Revision: 358476
URL: https://svnweb.freebsd.org/changeset/base/358476

Log:
  MFC r358252:
  Fix NFS client deadlock when read reports truncated node.

Modified:
  stable/12/sys/fs/nfsclient/nfs_clbio.c
  stable/12/sys/fs/nfsclient/nfs_clport.c
  stable/12/sys/sys/proc.h
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/fs/nfsclient/nfs_clbio.c
==============================================================================
--- stable/12/sys/fs/nfsclient/nfs_clbio.c      Sat Feb 29 21:55:48 2020        
(r358475)
+++ stable/12/sys/fs/nfsclient/nfs_clbio.c      Sat Feb 29 22:10:00 2020        
(r358476)
@@ -425,14 +425,11 @@ int
 ncl_bioread(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred)
 {
        struct nfsnode *np = VTONFS(vp);
-       int biosize, i;
        struct buf *bp, *rabp;
        struct thread *td;
        struct nfsmount *nmp = VFSTONFS(vp->v_mount);
        daddr_t lbn, rabn;
-       int bcount;
-       int seqcount;
-       int nra, error = 0, n = 0, on = 0;
+       int biosize, bcount, error, i, n, nra, on, save2, seqcount;
        off_t tmp_off;
 
        KASSERT(uio->uio_rw == UIO_READ, ("ncl_read mode"));
@@ -464,6 +461,8 @@ ncl_bioread(struct vnode *vp, struct uio *uio, int iof
                /* No caching/ no readaheads. Just read data into the user 
buffer */
                return ncl_readrpc(vp, uio, cred);
 
+       n = 0;
+       on = 0;
        biosize = vp->v_bufobj.bo_bsize;
        seqcount = (int)((off_t)(ioflag >> IO_SEQSHIFT) * biosize / BKVASIZE);
 
@@ -471,6 +470,7 @@ ncl_bioread(struct vnode *vp, struct uio *uio, int iof
        if (error)
                return error;
 
+       save2 = curthread_pflags2_set(TDP2_SBPAGES);
        do {
            u_quad_t nsize;
 
@@ -495,7 +495,9 @@ ncl_bioread(struct vnode *vp, struct uio *uio, int iof
                            rabp = nfs_getcacheblk(vp, rabn, biosize, td);
                            if (!rabp) {
                                error = newnfs_sigintr(nmp, td);
-                               return (error ? error : EINTR);
+                               if (error == 0)
+                                       error = EINTR;
+                               goto out;
                            }
                            if ((rabp->b_flags & (B_CACHE|B_DELWRI)) == 0) {
                                rabp->b_flags |= B_ASYNC;
@@ -526,7 +528,9 @@ ncl_bioread(struct vnode *vp, struct uio *uio, int iof
 
                if (!bp) {
                        error = newnfs_sigintr(nmp, td);
-                       return (error ? error : EINTR);
+                       if (error == 0)
+                               error = EINTR;
+                       goto out;
                }
 
                /*
@@ -540,7 +544,7 @@ ncl_bioread(struct vnode *vp, struct uio *uio, int iof
                    error = ncl_doio(vp, bp, cred, td, 0);
                    if (error) {
                        brelse(bp);
-                       return (error);
+                       goto out;
                    }
                }
 
@@ -561,7 +565,9 @@ ncl_bioread(struct vnode *vp, struct uio *uio, int iof
                bp = nfs_getcacheblk(vp, (daddr_t)0, NFS_MAXPATHLEN, td);
                if (!bp) {
                        error = newnfs_sigintr(nmp, td);
-                       return (error ? error : EINTR);
+                       if (error == 0)
+                               error = EINTR;
+                       goto out;
                }
                if ((bp->b_flags & B_CACHE) == 0) {
                    bp->b_iocmd = BIO_READ;
@@ -570,7 +576,7 @@ ncl_bioread(struct vnode *vp, struct uio *uio, int iof
                    if (error) {
                        bp->b_ioflags |= BIO_ERROR;
                        brelse(bp);
-                       return (error);
+                       goto out;
                    }
                }
                n = MIN(uio->uio_resid, NFS_MAXPATHLEN - bp->b_resid);
@@ -580,14 +586,17 @@ ncl_bioread(struct vnode *vp, struct uio *uio, int iof
                NFSINCRGLOBAL(nfsstatsv1.biocache_readdirs);
                if (np->n_direofoffset
                    && uio->uio_offset >= np->n_direofoffset) {
-                   return (0);
+                       error = 0;
+                       goto out;
                }
                lbn = (uoff_t)uio->uio_offset / NFS_DIRBLKSIZ;
                on = uio->uio_offset & (NFS_DIRBLKSIZ - 1);
                bp = nfs_getcacheblk(vp, lbn, NFS_DIRBLKSIZ, td);
                if (!bp) {
-                   error = newnfs_sigintr(nmp, td);
-                   return (error ? error : EINTR);
+                       error = newnfs_sigintr(nmp, td);
+                       if (error == 0)
+                               error = EINTR;
+                       goto out;
                }
                if ((bp->b_flags & B_CACHE) == 0) {
                    bp->b_iocmd = BIO_READ;
@@ -612,12 +621,16 @@ ncl_bioread(struct vnode *vp, struct uio *uio, int iof
                         */
                        for (i = 0; i <= lbn && !error; i++) {
                            if (np->n_direofoffset
-                               && (i * NFS_DIRBLKSIZ) >= np->n_direofoffset)
-                                   return (0);
+                               && (i * NFS_DIRBLKSIZ) >= np->n_direofoffset) {
+                                   error = 0;
+                                   goto out;
+                           }
                            bp = nfs_getcacheblk(vp, i, NFS_DIRBLKSIZ, td);
                            if (!bp) {
                                error = newnfs_sigintr(nmp, td);
-                               return (error ? error : EINTR);
+                               if (error == 0)
+                                       error = EINTR;
+                               goto out;
                            }
                            if ((bp->b_flags & B_CACHE) == 0) {
                                    bp->b_iocmd = BIO_READ;
@@ -646,7 +659,7 @@ ncl_bioread(struct vnode *vp, struct uio *uio, int iof
                     * we give up.
                     */
                    if (error)
-                           return (error);
+                           goto out;
                }
 
                /*
@@ -706,6 +719,12 @@ ncl_bioread(struct vnode *vp, struct uio *uio, int iof
            if (bp != NULL)
                brelse(bp);
        } while (error == 0 && uio->uio_resid > 0 && n > 0);
+out:
+       curthread_pflags2_restore(save2);
+       if ((curthread->td_pflags2 & TDP2_SBPAGES) == 0) {
+               NFSLOCKNODE(np);
+               ncl_pager_setsize(vp, NULL);
+       }
        return (error);
 }
 

Modified: stable/12/sys/fs/nfsclient/nfs_clport.c
==============================================================================
--- stable/12/sys/fs/nfsclient/nfs_clport.c     Sat Feb 29 21:55:48 2020        
(r358475)
+++ stable/12/sys/fs/nfsclient/nfs_clport.c     Sat Feb 29 22:10:00 2020        
(r358476)
@@ -597,7 +597,8 @@ ncl_pager_setsize(struct vnode *vp, u_quad_t *nsizep)
        setnsize = false;
 
        if (object != NULL && nsize != object->un_pager.vnp.vnp_size) {
-               if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE)
+               if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE &&
+                   (curthread->td_pflags2 & TDP2_SBPAGES) == 0)
                        setnsize = true;
                else
                        np->n_flag |= NVNSETSZSKIP;

Modified: stable/12/sys/sys/proc.h
==============================================================================
--- stable/12/sys/sys/proc.h    Sat Feb 29 21:55:48 2020        (r358475)
+++ stable/12/sys/sys/proc.h    Sat Feb 29 22:10:00 2020        (r358476)
@@ -497,6 +497,8 @@ do {                                                        
                \
 #define        TDP_FORKING     0x20000000 /* Thread is being created through 
fork() */
 #define        TDP_EXECVMSPC   0x40000000 /* Execve destroyed old vmspace */
 
+#define        TDP2_SBPAGES    0x00000001 /* Owns sbusy on some pages */
+
 /*
  * Reasons that the current thread can not be run yet.
  * More than one may apply.
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to