getpages/putpages fixup part 1 - Add support for UIO_NOCOPY VOP_WRITEs to
authorMatthew Dillon <dillon@dragonflybsd.org>
Tue, 21 Aug 2007 17:26:48 +0000 (17:26 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Tue, 21 Aug 2007 17:26:48 +0000 (17:26 +0000)
filesystems which use the buffer cache and assert that UIO_NOCOPY is not
being used for filesystems which do not.

For filesystems using the buffer cache all we have to do is force a
read-before-write to fill in any missing pieces of the buffer.

UIO_NOCOPY writes are used for buffer-cache-backed filesystems which do
not implement their own vop_putpages code.  At the moment this is only
the msdosfs.

sys/kern/kern_physio.c
sys/netproto/ncp/ncp_subr.c
sys/netproto/smb/smb_smb.c
sys/vfs/gnu/ext2fs/ext2_readwrite.c
sys/vfs/hpfs/hpfs_vnops.c
sys/vfs/msdosfs/msdosfs_vnops.c
sys/vfs/nfs/nfs_bio.c
sys/vfs/ntfs/ntfs_subr.c
sys/vfs/specfs/spec_vnops.c
sys/vfs/ufs/ufs_readwrite.c
sys/vfs/userfs/userfs_vnops.c

index aa9b960..d8aed75 100644 (file)
@@ -17,7 +17,7 @@
  *    are met.
  *
  * $FreeBSD: src/sys/kern/kern_physio.c,v 1.46.2.4 2003/11/14 09:51:47 simokawa Exp $
- * $DragonFly: src/sys/kern/kern_physio.c,v 1.24 2006/12/23 00:35:04 swildner Exp $
+ * $DragonFly: src/sys/kern/kern_physio.c,v 1.25 2007/08/21 17:26:45 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -61,6 +61,9 @@ physio(cdev_t dev, struct uio *uio, int ioflag)
                dev->si_iosize_max = DFLTPHYS;
        }
 
+       /* Must be a real uio */
+       KKASSERT(uio->uio_segflg != UIO_NOCOPY);
+
        /* Don't check block number overflow for D_MEM */
        if ((dev_dflags(dev) & D_TYPEMASK) == D_MEM)
                chk_blockno = 0;
index 081b996..b244afe 100644 (file)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/netncp/ncp_subr.c,v 1.2.2.1 2001/02/22 08:54:11 bp Exp $
- * $DragonFly: src/sys/netproto/ncp/ncp_subr.c,v 1.10 2006/12/22 23:57:54 swildner Exp $
+ * $DragonFly: src/sys/netproto/ncp/ncp_subr.c,v 1.11 2007/08/21 17:26:46 dillon Exp $
  */
 #include <sys/param.h>
 #include <sys/errno.h>
@@ -231,6 +231,7 @@ ncp_write(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *c
                kprintf("%s: can't handle iovcnt>1 !!!\n", __func__);
                return EIO;
        }
+       KKASSERT(uiop->uio_segflg != UIO_NOCOPY);
        tsiz = uiop->uio_resid;
        while (tsiz > 0) {
                len = min(4096 - (uiop->uio_offset % 4096), tsiz);
index 52bd0bb..e41518b 100644 (file)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/netsmb/smb_smb.c,v 1.1.2.3 2002/12/14 14:44:19 fjoe Exp $
- * $DragonFly: src/sys/netproto/smb/smb_smb.c,v 1.6 2006/09/05 00:55:49 dillon Exp $
+ * $DragonFly: src/sys/netproto/smb/smb_smb.c,v 1.7 2007/08/21 17:26:47 dillon Exp $
  */
 /*
  * various SMB requests. Most of the routines merely packs data into mbufs.
@@ -572,6 +572,9 @@ smb_smb_write(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
        u_int8_t wc;
        int error, blksz;
 
+       /* write data must be real */
+       KKASSERT(uio->uio_segflg != UIO_NOCOPY);
+
        blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
        if (blksz > 0xffff)
                blksz = 0xffff;
index f424c8e..7a5553a 100644 (file)
@@ -38,7 +38,7 @@
  *
  *     @(#)ufs_readwrite.c     8.7 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/gnu/ext2fs/ext2_readwrite.c,v 1.18.2.2 2000/12/22 18:44:33 dillon Exp $
- * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_readwrite.c,v 1.13 2007/02/22 15:50:49 corecode Exp $
+ * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_readwrite.c,v 1.14 2007/08/21 17:26:48 dillon Exp $
  */
 
 #define        BLKSIZE(a, b, c)        blksize(a, b, c)
@@ -238,15 +238,13 @@ ext2_write(struct vop_write_args *ap)
                 * by ensuring that newly allocated blocks are zerod.  The
                 * race can occur even in the case where the write covers
                 * the entire block.
+                *
+                * Just set B_CLRBUF unconditionally, even if the write
+                * covers the whole block.  This also handles the UIO_NOCOPY
+                * case.  See ffs_write() in ufs for a more sophisticated
+                * version.
                 */
                flags |= B_CLRBUF;
-#if 0
-               if (fs->s_frag_size > xfersize)
-                       flags |= B_CLRBUF;
-               else
-                       flags &= ~B_CLRBUF;
-#endif
-
                error = ext2_balloc(ip,
                    lbn, blkoffset + xfersize, ap->a_cred, &bp, flags);
                if (error)
index 1efab42..84b6b78 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/fs/hpfs/hpfs_vnops.c,v 1.2.2.2 2002/01/15 18:35:09 semenu Exp $
- * $DragonFly: src/sys/vfs/hpfs/hpfs_vnops.c,v 1.43 2007/08/13 17:31:56 dillon Exp $
+ * $DragonFly: src/sys/vfs/hpfs/hpfs_vnops.c,v 1.44 2007/08/21 17:26:48 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -404,7 +404,16 @@ hpfs_write(struct vop_write_args *ap)
                dprintf(("hpfs_write: bn: 0x%x (0x%x) towrite: 0x%x (0x%x)\n",
                        bn, runl, towrite, xfersz));
 
-               if ((off == 0) && (towrite == xfersz)) {
+               /*
+                * We do not have to issue a read-before-write if the xfer
+                * size does not cover the whole block.
+                *
+                * In the UIO_NOCOPY case, however, we are not overwriting
+                * anything and must do a read-before-write to fill in
+                * any missing pieces.
+                */
+               if (off == 0 && towrite == xfersz &&
+                   uio->uio_segflg != UIO_NOCOPY) {
                        bp = getblk(hp->h_devvp, dbtodoff(bn), xfersz, 0, 0);
                        clrbuf(bp);
                } else {
index 8ad3ff5..ce77d82 100644 (file)
@@ -1,5 +1,5 @@
 /* $FreeBSD: src/sys/msdosfs/msdosfs_vnops.c,v 1.95.2.4 2003/06/13 15:05:47 trhodes Exp $ */
-/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_vnops.c,v 1.50 2007/08/13 17:31:56 dillon Exp $ */
+/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_vnops.c,v 1.51 2007/08/21 17:26:48 dillon Exp $ */
 /*     $NetBSD: msdosfs_vnops.c,v 1.68 1998/02/10 14:10:04 mrg Exp $   */
 
 /*-
@@ -749,16 +749,21 @@ msdosfs_write(struct vop_write_args *ap)
                        vnode_pager_setsize(vp, dep->de_FileSize);
                }
 
+               /*
+                * If either the whole cluster gets written, or we write
+                * the cluster from its start beyond EOF, then no need to
+                * read data from disk.
+                *
+                * If UIO_NOCOPY is set we have to do a read-before-write
+                * to fill in any missing pieces of the buffer since no
+                * actual overwrite will occur.
+                */
                cn = de_off2cn(pmp, uio->uio_offset);
                if ((uio->uio_offset & pmp->pm_crbomask) == 0
+                   && uio->uio_segflg != UIO_NOCOPY
                    && (de_off2cn(pmp, uio->uio_offset + uio->uio_resid) 
                        > de_off2cn(pmp, uio->uio_offset)
                        || uio->uio_offset + uio->uio_resid >= dep->de_FileSize)) {
-                       /*
-                        * If either the whole cluster gets written,
-                        * or we write the cluster from its start beyond EOF,
-                        * then no need to read data from disk.
-                        */
                        bp = getblk(thisvp, de_cn2doff(pmp, cn),
                                    pmp->pm_bpcluster, 0, 0);
                        clrbuf(bp);
index 9a9a5b2..5ecd032 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     @(#)nfs_bio.c   8.9 (Berkeley) 3/30/95
  * $FreeBSD: /repoman/r/ncvs/src/sys/nfsclient/nfs_bio.c,v 1.130 2004/04/14 23:23:55 peadar Exp $
- * $DragonFly: src/sys/vfs/nfs/nfs_bio.c,v 1.40 2007/02/22 15:50:50 corecode Exp $
+ * $DragonFly: src/sys/vfs/nfs/nfs_bio.c,v 1.41 2007/08/21 17:26:48 dillon Exp $
  */
 
 
@@ -938,9 +938,13 @@ again:
                 *
                 * B_CACHE may also be set due to the buffer being cached
                 * normally.
+                *
+                * When doing a UIO_NOCOPY write the buffer is not
+                * overwritten and we cannot just set B_CACHE unconditionally
+                * for full-block writes.
                 */
 
-               if (on == 0 && n == bcount) {
+               if (on == 0 && n == bcount && uio->uio_segflg != UIO_NOCOPY) {
                        bp->b_flags |= B_CACHE;
                        bp->b_flags &= ~(B_ERROR | B_INVAL);
                }
index 1d5b39d..eec2c03 100644 (file)
@@ -26,7 +26,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/ntfs/ntfs_subr.c,v 1.7.2.4 2001/10/12 22:08:49 semenu Exp $
- * $DragonFly: src/sys/vfs/ntfs/ntfs_subr.c,v 1.25 2006/12/23 00:41:30 swildner Exp $
+ * $DragonFly: src/sys/vfs/ntfs/ntfs_subr.c,v 1.26 2007/08/21 17:26:48 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -1404,8 +1404,8 @@ ntfs_writentvattr_plain(struct ntfsmount *ntmp,   struct ntnode *ip,
                                (u_int32_t) cn, (u_int32_t) cl, 
                                (u_int32_t) off, (u_int32_t) tocopy, 
                                (u_int32_t) left));
-                       if ((off == 0) && (tocopy == ntfs_cntob(cl)))
-                       {
+                       if (off == 0 && tocopy == ntfs_cntob(cl) &&
+                           uio->uio_segflg != UIO_NOCOPY) {
                                bp = getblk(ntmp->ntm_devvp, ntfs_cntodoff(cn),
                                            ntfs_cntob(cl), 0, 0);
                                clrbuf(bp);
index 10c56ed..45c3d4f 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)spec_vnops.c        8.14 (Berkeley) 5/21/95
  * $FreeBSD: src/sys/miscfs/specfs/spec_vnops.c,v 1.131.2.4 2001/02/26 04:23:20 jlemon Exp $
- * $DragonFly: src/sys/vfs/specfs/spec_vnops.c,v 1.55 2007/08/13 17:31:56 dillon Exp $
+ * $DragonFly: src/sys/vfs/specfs/spec_vnops.c,v 1.56 2007/08/21 17:26:48 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -360,6 +360,8 @@ spec_write(struct vop_write_args *ap)
        uio = ap->a_uio;
        td = uio->uio_td;
 
+       KKASSERT(uio->uio_segflg != UIO_NOCOPY);
+
        if (dev == NULL)                /* device was revoked */
                return (EBADF);
 
index c9f8d25..1a73c33 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)ufs_readwrite.c     8.11 (Berkeley) 5/8/95
  * $FreeBSD: src/sys/ufs/ufs/ufs_readwrite.c,v 1.65.2.14 2003/04/04 22:21:29 tegge Exp $
- * $DragonFly: src/sys/vfs/ufs/ufs_readwrite.c,v 1.22 2007/08/13 17:31:57 dillon Exp $
+ * $DragonFly: src/sys/vfs/ufs/ufs_readwrite.c,v 1.23 2007/08/21 17:26:48 dillon Exp $
  */
 
 #define        BLKSIZE(a, b, c)        blksize(a, b, c)
@@ -315,9 +315,10 @@ ffs_write(struct vop_write_args *ap)
 
                /*      
                 * We must perform a read-before-write if the transfer
-                * size does not cover the entire buffer.
+                * size does not cover the entire buffer, or if doing
+                * a dummy write to flush the buffer.
                 */
-               if (fs->fs_bsize > xfersize)
+               if (xfersize < fs->fs_bsize || uio->uio_segflg == UIO_NOCOPY)
                        flags |= B_CLRBUF;
                else
                        flags &= ~B_CLRBUF;
@@ -333,7 +334,7 @@ ffs_write(struct vop_write_args *ap)
                 * race where another process may see the garbage prior to
                 * the uiomove() for a write replacing it.
                 */
-               if ((bp->b_flags & B_CACHE) == 0 && fs->fs_bsize <= xfersize)
+               if ((bp->b_flags & B_CACHE) == 0 && (flags & B_CLRBUF) == 0)
                        vfs_bio_clrbuf(bp);
                if (ioflag & IO_DIRECT)
                        bp->b_flags |= B_DIRECT;
index 9fe9fe4..4c92a98 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sys/vfs/userfs/userfs_vnops.c,v 1.1 2007/08/13 17:49:17 dillon Exp $
+ * $DragonFly: src/sys/vfs/userfs/userfs_vnops.c,v 1.2 2007/08/21 17:26:48 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -282,7 +282,7 @@ user_vop_write (struct vop_write_args *ap)
                 * on USERFS_BSIZE boundaries.
                 *
                 * XXX not optimized for complete write-overs or file
-                * extensions.
+                * extensions.  Note: must bread on UIO_NOCOPY writes.
                 */
                offset = (int)uio->uio_offset & USERFS_BMASK;
                error = bread(vp, uio->uio_offset - offset, USERFS_BSIZE, &bp);