[net.bugs.4bsd] block size bug in dump, 4.2BSD

dave@onfcanim.UUCP (Dave Martindale) (11/29/85)

When writing out the contents of a file to the tape, dump does all its
calculations in terms of the frag size of the filesystem it is
dumping.  Thus the amount of data written to tape is always a multiple
of the frag size (rounded up to a multiple of TP_BSIZE, if the frag
size is smaller than TP_BSIZE).

Unfortunately, restore expects the length of data on tape to be the
size listed in the inode rounded up to a multiple of TP_BSIZE.  It
doesn't care what the filesystem's frag size was (and indeed it
shouldn't, since it may be restoring to a filesystem with a different
frag size).

The result is that when you dump a filesystem with a frag size bigger
than 1024 (TP_BSIZE) and then try to restore from that tape, restore
will produce a large number of messages (almost 1 per file) about
skipping blocks to resync if you try to restore from that tape.

As far as I can tell, the extra data written will always be zero, and
thus restore will always be able to resynchronize without losing
anything, but this is very annoying.

From the looks of the code, I think dump will also mess up royally
trying to dump a filesystem with a block size that is smaller than
TP_BSIZE.  Since I don't see why you'd ever want such a filesystem,
I'm not going to worry about it.

To fix the first problem, just pass blksout() the number of tape blocks
rather than frags to write:

*** old/dumptraverse.c	Tue Feb  5 01:02:55 1985
--- dumptraverse.c	Thu Nov 28 23:40:43 1985
***************
*** 163,169
  		return;
  	}
  	if (ip->di_size > NDADDR * sblock->fs_bsize)
! 		i = NDADDR * sblock->fs_frag;
  	else
  		i = howmany(ip->di_size, sblock->fs_fsize);
  	blksout(&ip->di_db[0], i);

--- 163,169 -----
  		return;
  	}
  	if (ip->di_size > NDADDR * sblock->fs_bsize)
! 		i = howmany(NDADDR * sblock->fs_bsize, TP_BSIZE);
  	else
  		i = howmany(ip->di_size, TP_BSIZE);
  	blksout(&ip->di_db[0], i);
***************
*** 165,171
  	if (ip->di_size > NDADDR * sblock->fs_bsize)
  		i = NDADDR * sblock->fs_frag;
  	else
! 		i = howmany(ip->di_size, sblock->fs_fsize);
  	blksout(&ip->di_db[0], i);
  	size = ip->di_size - NDADDR * sblock->fs_bsize;
  	if (size <= 0)

--- 165,171 -----
  	if (ip->di_size > NDADDR * sblock->fs_bsize)
  		i = howmany(NDADDR * sblock->fs_bsize, TP_BSIZE);
  	else
! 		i = howmany(ip->di_size, TP_BSIZE);
  	blksout(&ip->di_db[0], i);
  	size = ip->di_size - NDADDR * sblock->fs_bsize;
  	if (size <= 0)
***************
*** 191,197
  		bzero(idblk, sblock->fs_bsize);
  	if (lvl <= 0) {
  		if (*size < NINDIR(sblock) * sblock->fs_bsize)
! 			cnt = howmany(*size, sblock->fs_fsize);
  		else
  			cnt = NINDIR(sblock) * sblock->fs_frag;
  		*size -= NINDIR(sblock) * sblock->fs_bsize;

--- 191,197 -----
  		bzero(idblk, sblock->fs_bsize);
  	if (lvl <= 0) {
  		if (*size < NINDIR(sblock) * sblock->fs_bsize)
! 			cnt = howmany(*size, TP_BSIZE);
  		else
  			cnt = howmany(NINDIR(sblock) * sblock->fs_bsize,
  			    TP_BSIZE);
***************
*** 193,199
  		if (*size < NINDIR(sblock) * sblock->fs_bsize)
  			cnt = howmany(*size, sblock->fs_fsize);
  		else
! 			cnt = NINDIR(sblock) * sblock->fs_frag;
  		*size -= NINDIR(sblock) * sblock->fs_bsize;
  		blksout(&idblk[0], cnt);
  		return;

--- 193,200 -----
  		if (*size < NINDIR(sblock) * sblock->fs_bsize)
  			cnt = howmany(*size, TP_BSIZE);
  		else
! 			cnt = howmany(NINDIR(sblock) * sblock->fs_bsize,
! 			    TP_BSIZE);
  		*size -= NINDIR(sblock) * sblock->fs_bsize;
  		blksout(&idblk[0], cnt);
  		return;
***************
*** 206,212
  	}
  }
  
! blksout(blkp, frags)
  	daddr_t *blkp;
  	int frags;
  {

--- 207,213 -----
  	}
  }
  
! blksout(blkp, blks)
  	daddr_t *blkp;
  	int blks;
  {
***************
*** 208,214
  
  blksout(blkp, frags)
  	daddr_t *blkp;
! 	int frags;
  {
  	int i, j, count, blks, tbperdb;
  

--- 209,215 -----
  
  blksout(blkp, blks)
  	daddr_t *blkp;
! 	int blks;
  {
  	int i, j, count, tbperdb;
  
***************
*** 210,216
  	daddr_t *blkp;
  	int frags;
  {
! 	int i, j, count, blks, tbperdb;
  
  	blks = howmany(frags * sblock->fs_fsize, TP_BSIZE);
  	tbperdb = sblock->fs_bsize / TP_BSIZE;

--- 211,217 -----
  	daddr_t *blkp;
  	int blks;
  {
! 	int i, j, count, tbperdb;
  
  	tbperdb = sblock->fs_bsize / TP_BSIZE;
  	for (i = 0; i < blks; i += TP_NINDIR) {
***************
*** 212,218
  {
  	int i, j, count, blks, tbperdb;
  
- 	blks = howmany(frags * sblock->fs_fsize, TP_BSIZE);
  	tbperdb = sblock->fs_bsize / TP_BSIZE;
  	for (i = 0; i < blks; i += TP_NINDIR) {
  		if (i + TP_NINDIR > blks)

--- 213,218 -----
  {
  	int i, j, count, tbperdb;
  
  	tbperdb = sblock->fs_bsize / TP_BSIZE;
  	for (i = 0; i < blks; i += TP_NINDIR) {
  		if (i + TP_NINDIR > blks)