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.
This commit is contained in:
parent
1d8f58ae39
commit
2e1c393dfc
@ -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 &&
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user