Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 20 Sep 1999 12:19:43 -0700 (PDT)
From:      Matthew Dillon <dillon@apollo.backplane.com>
To:        current@freebsd.org
Subject:   request for review, patch to specfs to fix EOF condition alignment with buffer
Message-ID:  <199909201919.MAA83623@apollo.backplane.com>

next in thread | raw e-mail | index | archive | help
    This is a request for a review.  This patch fixes a bug in specfs
    relating to dealing with the EOF condition of a block device.

    If the EOF occurs in the middle of a block, specfs was not
    properly calculating the truncation for the I/O.

    This problem was first found by Tor.  Tor's example creates
    an oddly-sized VN partition and then  dd's from it.  Without the
    patch the dd believes that it can read 2880 sectors.  With the
    patch it correctly reads the last (truncated) block.

	dd if=/dev/zero of=/tmp/floppy.img bs=512 count=2879
	vnconfig -s labels -c /dev/vn0 /tmp/floppy.img
	dd if=/dev/vn0 of=/dev/null bs=8k

    Once this patch is committed, the only problem we will have is
    in recognizing the write-EOF case, which I will have a 
    recommendation for after this patch goes in.

    A similar problem in the VN device has already been fixed and
    committed.

					-Matt

Index: miscfs/specfs/spec_vnops.c
===================================================================
RCS file: /home/ncvs/src/sys/miscfs/specfs/spec_vnops.c,v
retrieving revision 1.108
diff -u -r1.108 spec_vnops.c
--- spec_vnops.c	1999/09/17 06:10:26	1.108
+++ spec_vnops.c	1999/09/20 17:50:48
@@ -311,19 +311,37 @@
 		do {
 			bn = btodb(uio->uio_offset) & ~(bscale - 1);
 			on = uio->uio_offset % bsize;
-			n = min((unsigned)(bsize - on), uio->uio_resid);
 			if (seqcount > 1) {
 				nextbn = bn + bscale;
 				error = breadn(vp, bn, (int)bsize, &nextbn,
 					(int *)&bsize, 1, NOCRED, &bp);
 			} else {
 				error = bread(vp, bn, (int)bsize, NOCRED, &bp);
+			}
+
+			/*
+			 * Figure out how much of the buffer is valid relative
+			 * to our offset into the buffer, which may be negative
+			 * if we are beyond the EOF.
+			 *
+			 * The valid size of the buffer is based on 
+			 * bp->b_bcount (which may have been truncated by
+			 * dscheck or the device) minus bp->b_resid, which
+			 * may be indicative of an I/O error if non-zero.
+			 */
+			n = bp->b_bcount - on;
+			if (n < 0) {
+				error = EINVAL;
+			} else {
+				n -= bp->b_resid;
+				if (n < 0)
+					error = EIO;
 			}
-			n = min(n, bsize - bp->b_resid);
 			if (error) {
 				brelse(bp);
 				return (error);
 			}
+			n = min(n, uio->uio_resid);
 			error = uiomove((char *)bp->b_data + on, n, uio);
 			brelse(bp);
 		} while (error == 0 && uio->uio_resid > 0 && n != 0);
@@ -403,16 +421,48 @@
 		do {
 			bn = btodb(uio->uio_offset) & ~blkmask;
 			on = uio->uio_offset % bsize;
+
+			/*
+			 * Calculate potential request size, determine
+			 * if we can avoid a read-before-write.
+			 */
 			n = min((unsigned)(bsize - on), uio->uio_resid);
 			if (n == bsize)
 				bp = getblk(vp, bn, bsize, 0, 0);
 			else
 				error = bread(vp, bn, bsize, NOCRED, &bp);
+
+			/*
+			 * n is the amount of effective space in the buffer
+			 * that we wish to write relative to our offset into
+			 * the buffer. We have to truncate it to the valid
+			 * size of the buffer relative to our offset into
+			 * the buffer (which may end up being negative if
+			 * we are beyond the EOF).
+			 *
+			 * The valid size of the buffer is based on 
+			 * bp->b_bcount (which may have been truncated by
+			 * dscheck or the device) minus bp->b_resid, which
+			 * may be indicative of an I/O error if non-zero.
+			 *
+			 * XXX In a newly created buffer, b_bcount == bsize
+			 * and, being asynchronous, we have no idea of the
+			 * EOF.
+			 */
+			if (error == 0) {
+				n = min(n, bp->b_bcount - on);
+				if (n < 0) {
+					error = EINVAL;
+				} else {
+					n -= bp->b_resid;
+					if (n < 0)
+						error = EIO;
+				}
+			}
 			if (error) {
 				brelse(bp);
 				return (error);
 			}
-			n = min(n, bsize - bp->b_resid);
 			error = uiomove((char *)bp->b_data + on, n, uio);
 			if (n + on == bsize)
 				bawrite(bp);


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199909201919.MAA83623>