diff options
author | mckusick <mckusick@FreeBSD.org> | 2003-05-07 18:27:09 +0000 |
---|---|---|
committer | mckusick <mckusick@FreeBSD.org> | 2003-05-07 18:27:09 +0000 |
commit | 2e1c393dfc9eb11b05e093718baa11cd6a695a7d (patch) | |
tree | a7524c265464698a3f6530ac94f5bfd5c18248e7 /sbin/dump | |
parent | 1d8f58ae39f8fac245c251478decd0c1cae5c402 (diff) | |
download | FreeBSD-src-2e1c393dfc9eb11b05e093718baa11cd6a695a7d.zip FreeBSD-src-2e1c393dfc9eb11b05e093718baa11cd6a695a7d.tar.gz |
Dump is hard-wired to believe that it can read disks on
1024-byte boundaries. For many years this was a reasonable
assumption. However, in recent years we have begun seeing
devices with 2048-byte sectors. These devices return errors
when dump tries to read starting in the middle of a sector
or when it tries to read only the first half of a sector.
Rather than change the native block size used by dump (and
thus create an incompatible dump format), this fix checks
for transfer requests that start and/or end on a non-sector
boundary. When such a read is detected, the new code reads
the entire sector and copies out just the part that dump
needs.
Reviewed by: Poul-Henning Kamp <phk@critter.freebsd.dk>
Approved by: re (John Baldwin <jhb@FreeBSD.org>)
Sponsored by: DARPA & NAI Labs.
Diffstat (limited to 'sbin/dump')
-rw-r--r-- | sbin/dump/main.c | 1 | ||||
-rw-r--r-- | sbin/dump/traverse.c | 51 |
2 files changed, 48 insertions, 4 deletions
diff --git a/sbin/dump/main.c b/sbin/dump/main.c index 6866eb7..54ac7f0 100644 --- a/sbin/dump/main.c +++ b/sbin/dump/main.c @@ -388,6 +388,7 @@ main(int argc, char *argv[]) sync(); sblock = (struct fs *)sblock_buf; for (i = 0; sblock_try[i] != -1; i++) { + sblock->fs_fsize = SBLOCKSIZE; /* needed in bread */ bread(sblock_try[i] >> dev_bshift, (char *) sblock, SBLOCKSIZE); if ((sblock->fs_magic == FS_UFS1_MAGIC || (sblock->fs_magic == FS_UFS2_MAGIC && diff --git a/sbin/dump/traverse.c b/sbin/dump/traverse.c index ec0d56e..0fd10c4 100644 --- a/sbin/dump/traverse.c +++ b/sbin/dump/traverse.c @@ -736,12 +736,55 @@ int breaderrors = 0; void bread(ufs2_daddr_t blkno, char *buf, int size) { - int cnt, i; + int secsize, bytes, resid, xfer, base, cnt, i; + static char *tmpbuf; + off_t offset; loop: - cnt = cread(diskfd, buf, size, ((off_t)blkno << dev_bshift)); - if (cnt == size) - return; + offset = blkno << dev_bshift; + secsize = sblock->fs_fsize; + base = offset % secsize; + resid = size % secsize; + /* + * If the transfer request starts or ends on a non-sector + * boundary, we must read the entire sector and copy out + * just the part that we need. + */ + if (base == 0 && resid == 0) { + cnt = cread(diskfd, buf, size, offset); + if (cnt == size) + return; + } else { + if (tmpbuf == NULL && (tmpbuf = malloc(secsize)) == 0) + quit("buffer malloc failed\n"); + xfer = 0; + bytes = size; + if (base != 0) { + cnt = cread(diskfd, tmpbuf, secsize, offset - base); + if (cnt != secsize) + goto bad; + xfer = secsize - base; + offset += xfer; + bytes -= xfer; + resid = bytes % secsize; + memcpy(buf, &tmpbuf[base], xfer); + } + if (bytes >= secsize) { + cnt = cread(diskfd, &buf[xfer], bytes - resid, offset); + if (cnt != bytes - resid) + goto bad; + xfer += cnt; + offset += cnt; + } + if (resid == 0) + return; + cnt = cread(diskfd, tmpbuf, secsize, offset); + if (cnt == secsize) { + memcpy(&buf[xfer], tmpbuf, resid); + return; + } + } +bad: if (blkno + (size / dev_bsize) > fsbtodb(sblock, sblock->fs_size)) { /* * Trying to read the final fragment. |