Package: dump Version: 0.4b47-4+~tjw12r5 Severity: important Dear Maintainer,
Dump includes data read from EXT2_EXTENT_FLAGS_UNINIT extents in the dump instead of writing zeros (or nothing) to the tape. This means that restores are corrupted. The attached patch is a quick fix for this. Better would be to not write the blocks to the tape at all and to try to reserve the blocks without writing on restore. (I think this will depend on blocksize on the restore FS and whether this is supported at all) I do intend to rework this so that the empty blocks aren't written to the tape but I recently switched to ext4 from ext3 and was getting corrupted backups that I needed to fix quickly. -- System Information: Debian Release: 12.7 APT prefers stable-security APT policy: (500, 'stable-security'), (500, 'stable') Architecture: amd64 (x86_64) Kernel: Linux 6.1.0-25-amd64 (SMP w/4 CPU threads; PREEMPT) Kernel taint flags: TAINT_WARN Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8), LANGUAGE not set Shell: /bin/sh linked to /usr/bin/dash Init: sysvinit (via /sbin/init) Versions of packages dump depends on: ii libblkid1 2.38.1-5+deb12u1 ii libbz2-1.0 1.0.8-5+b1 ii libc6 2.36-9+deb12u8 ii libcom-err2 1.47.0-2 ii libext2fs2 1.47.0-2 ii liblzo2-2 2.10-2 ii libreadline8 8.2-1.3 ii libselinux1 3.4-1+b6 ii tar 1.34+dfsg-1.2+deb12u1 ii zlib1g 1:1.2.13.dfsg-1 dump recommends no packages. dump suggests no packages. -- no debconf information
diff -urN dump-0.4b47.orig/common/slave.h dump-0.4b47/common/slave.h --- dump-0.4b47.orig/common/slave.h 2021-01-01 15:05:15.000000000 +0000 +++ dump-0.4b47/common/slave.h 2021-01-01 15:05:15.000000000 +0000 @@ -17,6 +17,7 @@ struct req { ext2_loff_t dblk; int count; + int uninit; }; #define SLAVES 3 /* 1 slave writing, 1 reading, 1 for slack */ diff -urN dump-0.4b47.orig/dump/dump.h dump-0.4b47/dump/dump.h --- dump-0.4b47.orig/dump/dump.h 2022-05-03 10:02:27.000000000 +0000 +++ dump-0.4b47/dump/dump.h 2022-05-03 10:02:27.000000000 +0000 @@ -140,7 +140,7 @@ int mapdirs (dump_ino_t maxino, long long *tapesize); /* file dumping routines */ -void blksout (blk64_t *blkp, int frags, dump_ino_t ino); +void blksout (blk64_t *blkp, int frags, dump_ino_t ino, int uninit); void bread (ext2_loff_t blkno, char *buf, size_t size); void dumpino (struct dinode *dp, dump_ino_t ino, int metaonly); #ifdef __linux__ @@ -153,7 +153,7 @@ /* tape writing routines */ int alloctape (void); void close_rewind (void); -void dumpblock (blk64_t blkno, int size); +void dumpblock (blk64_t blkno, int size, int uninit); void startnewtape (int top); time_t trewind (void); void writerec (const void *dp, int isspcl); diff -urN dump-0.4b47.orig/dump/tape.c dump-0.4b47/dump/tape.c --- dump-0.4b47.orig/dump/tape.c 2022-05-03 10:02:27.000000000 +0000 +++ dump-0.4b47/dump/tape.c 2022-05-03 10:02:27.000000000 +0000 @@ -238,6 +238,7 @@ { slp->req[trecno].dblk = (ext2_loff_t)0; slp->req[trecno].count = 1; + slp->req[trecno].uninit = 0; /* XXX post increment triggers an egcs-1.1.2-12 bug on alpha/sparc */ *(union u_spcl *)(*(nextblock)) = *(union u_spcl *)dp; @@ -254,7 +255,7 @@ } void -dumpblock(blk64_t blkno, int size) +dumpblock(blk64_t blkno, int size, int uninit) { int avail, tpblks; ext2_loff_t dblkno; @@ -264,6 +265,7 @@ while ((avail = MIN(tpblks, ntrec - trecno)) > 0) { slp->req[trecno].dblk = dblkno; slp->req[trecno].count = avail; + slp->req[trecno].uninit = uninit; trecno += avail; spcl.c_tapea += avail; if (trecno >= ntrec) @@ -1220,8 +1222,12 @@ trecno += p->count, p += p->count) { if (p->dblk) { /* read a disk block */ - bread(p->dblk, slp->tblock[trecno], - p->count * TP_BSIZE); + if(p->uninit) { + memset(slp->tblock[trecno], 0, p->count * TP_BSIZE); + } else { + bread(p->dblk, slp->tblock[trecno], + p->count * TP_BSIZE); + } } else { /* read record from pipe */ if (p->count != 1 || dump_atomic_read( cmd, (char *)slp->tblock[trecno], diff -urN dump-0.4b47.orig/dump/traverse.c dump-0.4b47/dump/traverse.c --- dump-0.4b47.orig/dump/traverse.c 2021-01-01 16:28:57.000000000 +0000 +++ dump-0.4b47/dump/traverse.c 2021-01-01 16:28:57.000000000 +0000 @@ -752,6 +752,7 @@ int cnt; int max; int next_block; + int uninit; }; /* @@ -768,13 +769,13 @@ for (i = p->next_block; i < blockcnt; i++) { p->buf[p->cnt++] = 0; if (p->cnt == p->max) { - blksout (p->buf, p->cnt, p->ino); + blksout (p->buf, p->cnt, p->ino, p->uninit); p->cnt = 0; } } p->buf[p->cnt++] = *blocknr; if (p->cnt == p->max) { - blksout (p->buf, p->cnt, p->ino); + blksout (p->buf, p->cnt, p->ino, p->uninit); p->cnt = 0; } p->next_block = blockcnt + 1; @@ -840,12 +841,56 @@ spcl.c_dinode.di_size = sblock->fs_bsize; spcl.c_flags |= DR_EXTATTRIBUTES; spcl.c_extattributes = EXT_XATTR; - blksout((blk64_t *)&dp->di_file_acl, EXT2_FRAGS_PER_BLOCK(fs->super), ino); + blksout((blk64_t *)&dp->di_file_acl, EXT2_FRAGS_PER_BLOCK(fs->super), ino, 0); spcl.c_flags &= ~DR_EXTATTRIBUTES; spcl.c_extattributes = 0; } } +#ifdef __linux__ +/* TODO - see bread for how dump deals with errors */ +static void iterate_extents(struct block_context* bc, ext2_filsys fs, ext2_ino_t ino) { + ext2_extent_handle_t handle = NULL; + struct ext2fs_extent extent; + int op = EXT2_EXTENT_ROOT; + errcode_t errcode; + int ret = 0; + + errcode = ext2fs_extent_open(fs, ino, &handle); + if (errcode) { + msg("failed to open ext2 inode %u: %s\n", ino, error_message(errcode)); + return; + } + while (1) { + + errcode = ext2fs_extent_get(handle, op, &extent); + if (errcode == EXT2_ET_EXTENT_NO_NEXT) + break; + if (errcode) { + msg("failed to get extents inode %u: %s\n", ino, error_message(errcode)); + goto out; + } + op = EXT2_EXTENT_NEXT; + + if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) { + continue; + } + if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) { + continue; + } + + bc->uninit = extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ? 1 : 0; + blk64_t start = extent.e_pblk; + e2_blkcnt_t blockcnt = extent.e_lblk; + for(blk64_t blocknr = start; blocknr < start + extent.e_len; ++blocknr, ++blockcnt) { + dumponeblock(fs, &blocknr, blockcnt, 0, 0, bc); + } + } +out: + ext2fs_extent_free(handle); +} +#endif + /* * Dump passes 3 and 4. * @@ -982,21 +1027,29 @@ bc.cnt = 0; bc.ino = ino; bc.next_block = 0; + bc.uninit = 0; - ext2fs_block_iterate3(fs, (ext2_ino_t)ino, BLOCK_FLAG_DATA_ONLY, NULL, dumponeblock, (void *)&bc); + if (dp->di_mode & S_IFREG && dp->di_flags & EXT4_EXTENTS_FL) { + iterate_extents(&bc, fs, (ext2_ino_t)ino); + } else if (dp->di_mode & S_IFREG && dp->di_flags & EXT4_INLINE_DATA_FL) { + /* Untested - Can we ever get here? */ + msg("Unexpectedly got EXT4_INLINE_DATA_FL while dumping inode %lu\n", ino); + } else { + ext2fs_block_iterate3(fs, (ext2_ino_t)ino, BLOCK_FLAG_DATA_ONLY, NULL, dumponeblock, (void *)&bc); + } /* deal with holes at the end of the inode */ if (i_size > ((uint64_t)bc.next_block) * sblock->fs_fsize) { remaining = i_size - ((uint64_t)bc.next_block) * sblock->fs_fsize; for (i = 0; i < (int)howmany(remaining, sblock->fs_fsize); i++) { bc.buf[bc.cnt++] = 0; if (bc.cnt == bc.max) { - blksout (bc.buf, bc.cnt, bc.ino); + blksout (bc.buf, bc.cnt, bc.ino, bc.uninit); bc.cnt = 0; } } } if (bc.cnt > 0) { - blksout (bc.buf, bc.cnt, bc.ino); + blksout (bc.buf, bc.cnt, bc.ino, bc.uninit); } free(bc.buf); dump_xattr(ino, dp); @@ -1005,7 +1058,7 @@ cnt = NDADDR * sblock->fs_frag; else cnt = howmany(i_size, sblock->fs_fsize); - blksout(&dp->di_db[0], cnt, ino); + blksout(&dp->di_db[0], cnt, ino, 0); if ((int64_t) (size = i_size - NDADDR * sblock->fs_bsize) <= 0) { dump_xattr(ino, dp); return; @@ -1245,7 +1298,7 @@ cnt = NINDIR(sblock) * sblock->fs_frag; #endif *size -= NINDIR(sblock) * sblock->fs_bsize; - blksout(&idblk[0], cnt, ino); + blksout(&idblk[0], cnt, ino, 0); return; } ind_level--; @@ -1261,7 +1314,7 @@ * Collect up the data into tape record sized buffers and output them. */ void -blksout(blk64_t *blkp, int frags, dump_ino_t ino) +blksout(blk64_t *blkp, int frags, dump_ino_t ino, int uninit) { blk64_t *bp; int i, j, count, blks, tbperdb; @@ -1284,9 +1337,9 @@ for (j = i; j < count; j += tbperdb, bp++) { if (*bp != 0) { if (j + tbperdb <= count) - dumpblock(*bp, (int)sblock->fs_bsize); + dumpblock(*bp, (int)sblock->fs_bsize, uninit); else - dumpblock(*bp, (count - j) * TP_BSIZE); + dumpblock(*bp, (count - j) * TP_BSIZE, uninit); } } spcl.c_type = TS_ADDR;