From owner-freebsd-current Mon Sep 20 12:30:42 1999 Delivered-To: freebsd-current@freebsd.org Received: from proxy4.ba.best.com (proxy4.ba.best.com [206.184.139.15]) by hub.freebsd.org (Postfix) with ESMTP id CD3EB14BF8 for ; Mon, 20 Sep 1999 12:30:36 -0700 (PDT) (envelope-from dillon@apollo.backplane.com) Received: from apollo.backplane.com ([209.157.86.2]) by proxy4.ba.best.com (8.9.3/8.9.2/best.out) with ESMTP id MAA00450 for ; Mon, 20 Sep 1999 12:19:43 -0700 (PDT) Received: (from dillon@localhost) by apollo.backplane.com (8.9.3/8.9.1) id MAA83623; Mon, 20 Sep 1999 12:19:43 -0700 (PDT) (envelope-from dillon) Date: Mon, 20 Sep 1999 12:19:43 -0700 (PDT) From: Matthew Dillon Message-Id: <199909201919.MAA83623@apollo.backplane.com> To: current@freebsd.org Subject: request for review, patch to specfs to fix EOF condition alignment with buffer Sender: owner-freebsd-current@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG 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