Author: kib
Date: Wed Aug 29 15:50:09 2012
New Revision: 239845
URL: http://svn.freebsd.org/changeset/base/239845

Log:
  MFC r236687:
  Improve handling of uiomove(9) errors for the NFS client.

Modified:
  stable/9/sys/fs/nfsclient/nfs_clbio.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/fs/   (props changed)

Modified: stable/9/sys/fs/nfsclient/nfs_clbio.c
==============================================================================
--- stable/9/sys/fs/nfsclient/nfs_clbio.c       Wed Aug 29 15:46:01 2012        
(r239844)
+++ stable/9/sys/fs/nfsclient/nfs_clbio.c       Wed Aug 29 15:50:09 2012        
(r239845)
@@ -873,8 +873,9 @@ ncl_write(struct vop_write_args *ap)
        struct nfsmount *nmp = VFSTONFS(vp->v_mount);
        daddr_t lbn;
        int bcount;
-       int n, on, error = 0;
-       off_t tmp_off;
+       int bp_cached, n, on, error = 0;
+       size_t orig_resid, local_resid;
+       off_t orig_size, tmp_off;
 
        KASSERT(uio->uio_rw == UIO_WRITE, ("ncl_write mode"));
        KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread,
@@ -926,6 +927,11 @@ flush_and_restart:
                        mtx_unlock(&np->n_mtx);
        }
 
+       orig_resid = uio->uio_resid;
+       mtx_lock(&np->n_mtx);
+       orig_size = np->n_size;
+       mtx_unlock(&np->n_mtx);
+
        /*
         * If IO_APPEND then load uio_offset.  We restart here if we cannot
         * get the append lock.
@@ -1103,7 +1109,10 @@ again:
                 * normally.
                 */
 
+               bp_cached = 1;
                if (on == 0 && n == bcount) {
+                       if ((bp->b_flags & B_CACHE) == 0)
+                               bp_cached = 0;
                        bp->b_flags |= B_CACHE;
                        bp->b_flags &= ~B_INVAL;
                        bp->b_ioflags &= ~BIO_ERROR;
@@ -1169,8 +1178,24 @@ again:
                        goto again;
                }
 
+               local_resid = uio->uio_resid;
                error = uiomove((char *)bp->b_data + on, n, uio);
 
+               if (error != 0 && !bp_cached) {
+                       /*
+                        * This block has no other content then what
+                        * possibly was written by the faulty uiomove.
+                        * Release it, forgetting the data pages, to
+                        * prevent the leak of uninitialized data to
+                        * usermode.
+                        */
+                       bp->b_ioflags |= BIO_ERROR;
+                       brelse(bp);
+                       uio->uio_offset -= local_resid - uio->uio_resid;
+                       uio->uio_resid = local_resid;
+                       break;
+               }
+
                /*
                 * Since this block is being modified, it must be written
                 * again and not just committed.  Since write clustering does
@@ -1179,17 +1204,18 @@ again:
                 */
                bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK);
 
-               if (error) {
-                       bp->b_ioflags |= BIO_ERROR;
-                       brelse(bp);
-                       break;
-               }
+               /*
+                * Get the partial update on the progress made from
+                * uiomove, if an error occured.
+                */
+               if (error != 0)
+                       n = local_resid - uio->uio_resid;
 
                /*
                 * Only update dirtyoff/dirtyend if not a degenerate
                 * condition.
                 */
-               if (n) {
+               if (n > 0) {
                        if (bp->b_dirtyend > 0) {
                                bp->b_dirtyoff = min(on, bp->b_dirtyoff);
                                bp->b_dirtyend = max((on + n), bp->b_dirtyend);
@@ -1218,8 +1244,22 @@ again:
                } else {
                        bdwrite(bp);
                }
+
+               if (error != 0)
+                       break;
        } while (uio->uio_resid > 0 && n > 0);
 
+       if (error != 0) {
+               if (ioflag & IO_UNIT) {
+                       VATTR_NULL(&vattr);
+                       vattr.va_size = orig_size;
+                       /* IO_SYNC is handled implicitely */
+                       (void)VOP_SETATTR(vp, &vattr, cred);
+                       uio->uio_offset -= orig_resid - uio->uio_resid;
+                       uio->uio_resid = orig_resid;
+               }
+       }
+
        return (error);
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to