From 924a7003b0f2a2c647f5b3e7c9ecd5c2c8f72dc9 Mon Sep 17 00:00:00 2001 From: Kirk McKusick Date: Wed, 7 May 2003 18:27:09 +0000 Subject: 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 Approved by: re (John Baldwin ) Sponsored by: DARPA & NAI Labs. --- sbin/dump/main.c | 1 + sbin/dump/traverse.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 4 deletions(-) (limited to 'sbin/dump') diff --git a/sbin/dump/main.c b/sbin/dump/main.c index 6866eb7bf8c9..54ac7f093710 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 ec0d56e547ff..0fd10c469a88 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. -- cgit v1.3