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 [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message
To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message