Package: dump Version: 0.4b47-4+~tjw12r5 Severity: normal Dear Maintainer,
Dump cannot handle more than 2^32 blocks. This was reported upstream some years ago along with a patch that I am including here. I'm reporting this as I have another ext4 patch that I've built on top of this one. I've also attached a testcase that doesn't require >12TB of data to reproduce (it needs about 3GB of available disk space) It's crafted to my setup and will require modification for anybody else to use. -- 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/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,8 +140,8 @@ int mapdirs (dump_ino_t maxino, long long *tapesize); /* file dumping routines */ -void blksout (blk_t *blkp, int frags, dump_ino_t ino); -void bread (ext2_loff_t blkno, char *buf, int size); +void blksout (blk64_t *blkp, int frags, dump_ino_t ino); +void bread (ext2_loff_t blkno, char *buf, size_t size); void dumpino (struct dinode *dp, dump_ino_t ino, int metaonly); #ifdef __linux__ void dumpdirino (struct dinode *dp, dump_ino_t ino); @@ -153,7 +153,7 @@ /* tape writing routines */ int alloctape (void); void close_rewind (void); -void dumpblock (blk_t blkno, int size); +void dumpblock (blk64_t blkno, int size); 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 @@ -254,7 +254,7 @@ } void -dumpblock(blk_t blkno, int size) +dumpblock(blk64_t blkno, int size) { int avail, tpblks; ext2_loff_t dblkno; 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 @@ -748,7 +748,7 @@ struct block_context { ext2_ino_t ino; - blk_t *buf; + blk64_t *buf; int cnt; int max; int next_block; @@ -758,8 +758,8 @@ * Dump a block to the tape */ static int -dumponeblock(UNUSED(ext2_filsys fs), blk_t *blocknr, e2_blkcnt_t blockcnt, - UNUSED(blk_t ref_block), UNUSED(int ref_offset), void * private) +dumponeblock(UNUSED(ext2_filsys fs), blk64_t *blocknr, e2_blkcnt_t blockcnt, + UNUSED(blk64_t ref_block), UNUSED(int ref_offset), void * private) { struct block_context *p; e2_blkcnt_t i; @@ -840,7 +840,7 @@ spcl.c_dinode.di_size = sblock->fs_bsize; spcl.c_flags |= DR_EXTATTRIBUTES; spcl.c_extattributes = EXT_XATTR; - blksout(&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); spcl.c_flags &= ~DR_EXTATTRIBUTES; spcl.c_extattributes = 0; } @@ -978,12 +978,12 @@ } #ifdef __linux__ bc.max = NINDIR(sblock) * EXT2_FRAGS_PER_BLOCK(fs->super); - bc.buf = malloc (bc.max * sizeof (int)); + bc.buf = malloc (bc.max * sizeof (blk64_t)); bc.cnt = 0; bc.ino = ino; bc.next_block = 0; - ext2fs_block_iterate2(fs, (ext2_ino_t)ino, BLOCK_FLAG_DATA_ONLY, NULL, dumponeblock, (void *)&bc); + 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; @@ -1261,9 +1261,9 @@ * Collect up the data into tape record sized buffers and output them. */ void -blksout(blk_t *blkp, int frags, dump_ino_t ino) +blksout(blk64_t *blkp, int frags, dump_ino_t ino) { - blk_t *bp; + blk64_t *bp; int i, j, count, blks, tbperdb; blks = howmany(frags * sblock->fs_fsize, TP_BSIZE); @@ -1394,7 +1394,7 @@ int breaderrors = 0; void -bread(ext2_loff_t blkno, char *buf, int size) +bread(ext2_loff_t blkno, char *buf, size_t size) { int cnt, i;
#!/bin/bash set -Eeuo pipefail homedir=$( readlink -f $( dirname $0 ) ) cd $homedir rm -f d1 rm -f d2 rm -fr d1.mnt rm -fr d2.mnt rm -fr mnt rm -fr restore cleanup() { umount $homedir/mnt >&/dev/null || true vgchange -an vg30T >&/dev/null || true [[ -z ${ld3} ]] || losetup -d ${ld3} >&/dev/null || true [[ -z ${ld2} ]] || losetup -d ${ld2} >&/dev/null || true umount $homedir/d1.mnt >&/dev/null || true umount $homedir/d2.mnt >&/dev/null || true [[ -z ${ld1} ]] || losetup -d ${ld1} >&/dev/null || true [[ -z ${ld0} ]] || losetup -d ${ld0} >&/dev/null || true rm -f $homedir/d1 rm -f $homedir/d2 rm -fr $homedir/d1.mnt rm -fr $homedir/d2.mnt rm -fr $homedir/mnt rm -fr $homedir/restore } trap cleanup EXIT tfdfr=0 tfdbr=0 tbdfr=0 tbdbr=0 cfdfr=0 cfdbr=0 cbdfr=0 cbdbr=0 mkdir -p mnt truncate -s 3G d1 ld0=$( losetup -f ) losetup ${ld0} d1 mkfs.ext4 ${ld0} >&/dev/null mkdir -p d1.mnt mount ${ld0} d1.mnt truncate -s 1G d2 ld1=$( losetup -f ) losetup ${ld1} d2 mkfs.ext4 ${ld1} >&/dev/null mkdir -p d2.mnt mount ${ld1} d2.mnt truncate -s 15T d1.mnt/pv truncate -s 15T d2.mnt/pv ld2=$( losetup -f ) losetup ${ld2} d1.mnt/pv ld3=$( losetup -f ) losetup ${ld3} d2.mnt/pv vgcreate vg30T ${ld2} ${ld3} >&/dev/null lvcreate -n big -l 7860000 vg30T >&/dev/null mkfs.ext4 /dev/vg30T/big >&/dev/null mount /dev/vg30T/big mnt echo "fallocate bigfile1 - this is slow" fallocate -l 10T mnt/bigfile1 echo "fallocate bigfile2 - this is slow" fallocate -l 10T mnt/bigfile2 dd if=/dev/urandom of=mnt/bigblock bs=1K count=10K >&/dev/null echo "Removing bigfiles - this is slow" rm mnt/bigfile1 mnt/bigfile2 sync umount mnt mount -o ro /dev/vg30T/big mnt #debugfs -R "stat bigblock" /dev/vg30T/big | cat #debugfs -R "stat bigblock" /dev/vg30T/big | tail -n 1 #debugfs -R "stat bigblock" /dev/vg30T/big | tail -n 1 | sed 's/.*-//' extent=$( debugfs -R "stat bigblock" /dev/vg30T/big 2>/dev/null | tail -n 1 | sed 's/.*-//' ) if [[ $extent -le 4294967295 ]]; then echo "bigblock does not extend to an extent >= 2^32. Test needs fixing" exit 1 fi test_pipe() { $1 -q -0 $3 -f - 2>/dev/null | $2 -C -D mnt/ -f - >&/dev/null } test_file() { rm -fr restore mkdir -p restore cd restore $1 -q -0 $3 -f - 2>/dev/null | $2 -r -f - >&/dev/null || return 1 rm restoresymtable cd .. diff -q -ur --no-dereference mnt/ restore/ >&/dev/null || return 1 } dumpdev=/dev/vg30T/big echo echo "Testing fixed dump, fixed restore compare" test_pipe dump restore $dumpdev || cfdfr=1 echo echo "Testing fixed dump, bookworm restore compare" test_pipe dump restore.orig $dumpdev || cfdbr=1 echo echo "Testing bookworm dump, fixed restore compare" test_pipe dump.orig restore $dumpdev || cbdfr=1 echo echo "Testing bookworm dump, bookworm restore compare" test_pipe dump.orig restore.orig $dumpdev || cbdbr=1 echo echo echo "Testing fixed dump, fixed restore" test_file dump restore $dumpdev || tfdfr=1 echo echo "Testing fixed dump, bookworm restore" test_file dump restore.orig $dumpdev || tfdbr=1 echo echo "Testing bookworm dump, fixed restore" test_file dump.orig restore $dumpdev || tbdfr=1 echo echo "Testing bookworm dump, bookworm restore" test_file dump.orig restore.orig $dumpdev || tbdbr=1 echo umount mnt >& /dev/null vgchange -an vg30T >& /dev/null losetup -d ${ld3} losetup -d ${ld2} umount d1.mnt umount d2.mnt losetup -d ${ld1} losetup -d ${ld0} rmdir mnt rmdir d1.mnt rmdir d2.mnt rm -f d1 rm -f d2 rm -fr restore echo echo echo [[ $tfdfr -eq $cfdfr ]] || echo "SERIOUS BUG --- Mismatch between restore -C and actual restore for fixed dump and fixed restore" >&2 [[ $tfdfr -eq 0 ]] || echo "SERIOUS BUG --- mismatch between fixed dump and fixed restore" >&2 [[ $tbdbr -eq $cbdbr ]] || echo "Bookworm BUG -- Mismatch between restore -C and actual restore for bookworm dump and bookworm restore" >&2 [[ $tbdbr -eq 0 ]] || echo "Bookworm BUG -- mismatch between bookworm dump and bookworm restore" >&2 [[ $tfdbr -eq $cfdbr ]] || echo "Compatibility - Mismatch between restore -C and actual restore for fixed dump and bookworm restore" >&2 [[ $tfdbr -eq 0 ]] || echo "Compatibility - Bookworm restore fails to handle fixed dump data" >&2 [[ $tbdfr -eq $cbdfr ]] || echo "Compatibility - Mismatch between restore -C and actual restore for bookworm dump and fixed restore" >&2 [[ $tbdfr -eq 0 ]] || echo "Compatibility - Bookworm dump generates invalid dump data" >&2