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.
This commit is contained in:
Kevin McCormick 2016-10-10 09:58:00 -07:00
parent 6d906ad640
commit fcd5fb0e08

View File

@ -57,6 +57,22 @@ ZFS() {
fi 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 ### defaults
### ###
@ -65,12 +81,14 @@ dateopts="+%F_%T"
keep=5 keep=5
verbose=false verbose=false
quiet=false quiet=false
catchup=false
### ###
### parse options ### parse options
### ###
while getopts "hvqk:t:d:" opt ; do while getopts "chvqk:t:d:" opt ; do
case $opt in case $opt in
c) catchup=true ;;
h) usage 0 ;; h) usage 0 ;;
v) v)
verbose=true 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" die 1 "destination fs '$destfs' doesn't exist"
fi fi
###
### fix interrupted transfer
###
if $catchup ; then
catchup || die $? "catchup failed"
exit 0
fi
### ###
### create new snapshot on src ### create new snapshot on src
### ###