diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2014-07-10 09:33:44 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2014-07-10 09:33:44 +0000 |
commit | 44a3f33f71ec399163c8d24788579119b8ae38aa (patch) | |
tree | 8839511a83a366b3194c9a96af34d00fe04cd25e | |
parent | b940550b4030589eaf347e9efa434c0830c0e9df (diff) |
Add internal buffering when dumping a device with non-512 byte
sectors. This ensures that the requested data, and all the requested
data, is actually read from the device.
Should have no effect on 512-byte sector devices, but makes dump work
on 4096-byte sector devices.
Problem noted by and fix tested by David Vasek.
-rw-r--r-- | sbin/dump/traverse.c | 58 |
1 files changed, 50 insertions, 8 deletions
diff --git a/sbin/dump/traverse.c b/sbin/dump/traverse.c index 0d786fef5e1..97faff55214 100644 --- a/sbin/dump/traverse.c +++ b/sbin/dump/traverse.c @@ -1,4 +1,4 @@ -/* $OpenBSD: traverse.c,v 1.35 2014/06/13 20:43:06 naddy Exp $ */ +/* $OpenBSD: traverse.c,v 1.36 2014/07/10 09:33:43 krw Exp $ */ /* $NetBSD: traverse.c,v 1.17 1997/06/05 11:13:27 lukem Exp $ */ /*- @@ -804,15 +804,48 @@ int breaderrors = 0; void bread(daddr_t blkno, char *buf, int size) { + static char *mybuf = NULL; + char *mybufp, *bufp, *np; + static size_t mybufsz = 0; off_t offset; int cnt, i; - u_int32_t secsize = lab.d_secsize; + u_int64_t secno, seccount; + u_int32_t secoff, secsize = lab.d_secsize; - offset = blkno * DEV_BSIZE; + /* + * We must read an integral number of sectors large enough to contain + * all the requested data. The read must begin at a sector. + */ + if (DL_BLKOFFSET(&lab, blkno) == 0 && size % secsize == 0) { + secno = DL_BLKTOSEC(&lab, blkno); + secoff = 0; + seccount = size / secsize; + bufp = buf; + } else { + secno = DL_BLKTOSEC(&lab, blkno); + secoff = DL_BLKOFFSET(&lab, blkno); + seccount = DL_BLKTOSEC(&lab, (size + secoff) / DEV_BSIZE); + if (seccount * secsize < (size + secoff)) + seccount++; + if (mybufsz < seccount * secsize) { + np = reallocarray(mybuf, seccount, secsize); + if (np == NULL) { + msg("No memory to read %llu %u-byte sectors", + seccount, secsize); + dumpabort(0); + } + mybufsz = seccount * secsize; + mybuf = np; + } + bufp = mybuf; + } + + offset = secno * secsize; loop: - if ((cnt = pread(diskfd, buf, size, offset)) == size) - return; + if ((cnt = pread(diskfd, bufp, seccount * secsize, offset)) == + seccount * secsize) + goto done; if (blkno + (size / DEV_BSIZE) > fsbtodb(sblock, sblock->fs_ffs1_size)) { /* @@ -826,6 +859,7 @@ loop: * us into trouble. (mkm 9/25/83) */ size -= secsize; + seccount--; goto loop; } if (cnt == -1) @@ -848,9 +882,12 @@ loop: /* * Zero buffer, then try to read each sector of buffer separately. */ - memset(buf, 0, size); - for (i = 0; i < size; i += secsize, buf += secsize) { - if ((cnt = pread(diskfd, buf, secsize, offset + i)) == + if (bufp == mybuf) + memset(bufp, 0, mybufsz); + else + memset(bufp, 0, size); + for (i = 0, mybufp = bufp; i < size; i += secsize, mybufp += secsize) { + if ((cnt = pread(diskfd, mybufp, secsize, offset + i)) == secsize) continue; if (cnt == -1) { @@ -863,4 +900,9 @@ loop: "got=%d\n", disk, (long long)(offset + i) / DEV_BSIZE, secsize, cnt); } + +done: + /* If necessary, copy out data that was read. */ + if (bufp == mybuf) + memcpy(buf, bufp + secoff, size); } |