From fcd5fb0e08446a10f948d5022121a4e36339ba16 Mon Sep 17 00:00:00 2001 From: Kevin McCormick Date: Mon, 10 Oct 2016 09:58:00 -0700 Subject: [PATCH] Implement catchup mode to fix interrupted transfer When zfs send -R is interrupted, some child filesystems will be at a more recent snapshot than their parent. There's then no way to do a zfs send -R from the root/parent, as the children are inconsistent. Catchup mode handles recursion on its own, instead of relying on zfs to do it. Basically picking a single consistent snapshot across the board, then bringing all to that level. --- backup-zfs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/backup-zfs b/backup-zfs index fdab0e9..7f81d68 100755 --- a/backup-zfs +++ b/backup-zfs @@ -57,6 +57,22 @@ ZFS() { fi } +# If initial zfs send -R is interrupted, it can't be resumed. +# Rolling back all filesystems to the last consistent snapshot ought +# to do the trick, but that's annoying to throw that data away. +catchup() { + srcparent="${srcfs%/*}" # all but last child component of srcfs + root="${srcfs#*/}" # last child component of srcfs + target="$(ZFS "$srchost" list -d 1 -t snapshot -H -S creation -o name $srcfs | cut -f2 -d@ | grep "^$tag" | head -n1)" + for fs in $(ZFS "$desthost" list -Ho name -r "$destfs/$root" | tac) ; do + child="${fs#$destfs/}" + destsnap=$(ZFS "$desthost" list -Ho name -S creation -d1 -t snapshot $destfs/$child | head -n1 | cut -f2 -d@) + if [[ $destsnap != $target ]] ; then + ZFS "$srchost" send $send_opts -R -I @$destsnap $srcparent/$child@$target | ZFS "$desthost" receive $recv_opts -Fue "$destfs/${child%/*}" + fi + done +} + ### ### defaults ### @@ -65,12 +81,14 @@ dateopts="+%F_%T" keep=5 verbose=false quiet=false +catchup=false ### ### parse options ### -while getopts "hvqk:t:d:" opt ; do +while getopts "chvqk:t:d:" opt ; do case $opt in + c) catchup=true ;; h) usage 0 ;; v) verbose=true @@ -118,6 +136,14 @@ if [[ $(ZFS "$desthost" list -H -o name "$destfs" 2>/dev/null) != $destfs ]] ; t die 1 "destination fs '$destfs' doesn't exist" fi +### +### fix interrupted transfer +### +if $catchup ; then + catchup || die $? "catchup failed" + exit 0 +fi + ### ### create new snapshot on src ###