X-Git-Url: https://iankelling.org/git/?p=distro-setup;a=blobdiff_plain;f=check-subvol-stale;h=bdb47492ef07b132914b21ec6773014675dca38f;hp=c6497b5c3f1c0b030c3032ffe5502deab01497d0;hb=65351382939fa95fb1e05d7d83eb58d27c3c6133;hpb=e7708e1261357b00d17f4baffb7051e97f7e8623 diff --git a/check-subvol-stale b/check-subvol-stale index c6497b5..bdb4749 100644 --- a/check-subvol-stale +++ b/check-subvol-stale @@ -35,78 +35,110 @@ if [[ ! $@ ]]; then echo "$0: error: expected mountpoint argument" fi +stale-file() { + stale_dir=/nocow/btrfs-stale + stale_file=$stale_dir/$vol + if $stale; then + mkdir -p $stale_dir + printf "%s\n" $freshest_snap > $stale_file + ret=1 + else + rm -f $stale_file + fi + +} + ret=0 for d; do vol=${d##*/} - cd /mnt/root/btrbk - snaps=($vol.20*) # Assumes we are in the 21st century. + dev=$(sed -rn "s,^\s*([^#]\S*)\s+$d\s.*,\1,p" /etc/fstab|head -n1) + subvol_dir=$(sed -rn "s,^\s*[^#]\S*\s+$d\s.*\bsubvol=([a-zA-A/]+).*,\1,p" /etc/fstab|head -n1) + # note, we need $dev because $d might not be mounted, and we do this loop + # because the device in fstab for the rootfs can be different. + for devx in $(btrfs fi show $dev| sed -rn 's#.*path (/\S+)$#\1#p'); do + root_dir=$(sed -rn "s,^\s*$devx\s+(\S+).*\bsubvolid=0\b.*,\1,p" /etc/fstab|head -n1) + if [[ $root_dir ]]; then break; fi + done + svp=$root_dir/$subvol_dir # subvolume path + + snaps=($root_dir/btrbk/$subvol_dir.20*) # Assumes we are in the 21st century. if [[ ! $snaps ]]; then # no snapshots yet + echo "$0: warning. no snapshots found. this is expected for a brand new volume" continue fi + + # get info on last received sub + last_received_gen=0 + for f in ${snaps[@]}; do + show="$(btrfs sub show $f)" + if echo "$show" | grep -E "Received UUID:\s+[[:alnum:]]" &>/dev/null; then + cgen=$(echo "$show" | sed -rn 's,^\s*Gen at creation:\s+([0-9]+).*,\1,p') + if [[ $cgen -gt $last_received_gen ]]; then + last_received_cgen=$cgen + last_received=$f + fi + fi + done + + # Get last_snap by date. # when a btrbk bugfix makes it into the distro, # we might replace this with btrbk list latest /mnt/root/$vol | ... - # note: this is duplicated in mount-latest-subvol last_snap=$( - for f in ${snaps[@]}; do - printf "%s %s\n" $(date -d $(sed -r 's/(.{4})(..)(.{5})(..)(.*)/\1-\2-\3:\4:\5/' <<<${f#$vol.}) +%s) $f + for s in ${snaps[@]}; do + f=${s##*/} + unix_time=$(date -d $(sed -r 's/(.{4})(..)(.{5})(..)(.*)/\1-\2-\3:\4:\5/' <<<${f#$vol.}) +%s) + printf "%s %s\n" $unix_time $s done | sort -r | head -n 1 | awk '{print $2}' ) if [[ ! $last_snap ]]; then # should not happen. - echo "$0: error: could not find latest snapshot for $d among ${snaps[@]}" + echo "$0: error: could not find latest snapshot for $svp among ${snaps[*]}" ret=1 continue fi - # check that $d has $last_snap as a snapshot, - # or else $d is a snapshot of $last_snap. In the second - # case, we use a uuid comparison, which if I remember from the - # docs, is a bit more robust, perhaps to renames. - if btrfs sub show $d 2>/dev/null | sed '0,/^\s*Snapshot(s):/d;s/^\s*//' | \ - grep -xF btrbk/$last_snap &>/dev/null; then - stale=false - else - last_snap_uuid=$(btrfs sub show $last_snap| awk '$1 == "UUID:" {print $2}') - if btrfs sub show $d| grep "^\s*Parent UUID:\s*$last_snap_uuid$" &>/dev/null; then - stale=false - fi + if [[ ! -e $svp ]]; then + echo "$0: warning: subvol does not exist: $svp" + echo "$0 assuming this host was just for receiving and latest snap is freshest" + freshest_snap=$last_snap + stale=true + stale-file + continue fi - # check if $d is a snapshot of any of the btrbk backups other than the latest - if [[ ! $stale ]]; then - for f in ${snaps[@]}; do - if [[ $f == $last_snap ]]; then continue; fi - uuid=$(btrfs sub show $f| awk '$1 == "UUID:" {print $2}') - if btrfs sub show $d| grep "^\s*Parent UUID:\s*$uuid$" &>/dev/null; then - stale=true - echo "$d stale: it's a snapshot of $f" - break - fi - done - fi - # check if $d generation is later than last_snap - if [[ ! $stale ]]; then - last_snap_gen=$(btrfs sub show $last_snap| awk '$1 == "Generation:" {print $2}') - d_gen=$(btrfs sub show $d| awk '$1 == "Generation:" {print $2}') - if (( d_gen < last_snap_gen )); then + + # if there is a last_received, we can assume stale or fresh if we are newer/older + if [[ $last_received ]]; then + svp_cgen=$(btrfs sub show $svp | sed -rn 's,^\s*Gen at creation:\s+([0-9]+).*,\1,p') + if [[ $svp_cgen -ge $last_received_cgen ]]; then stale=false else - echo "$d stale: it's generation, $d_gen, is earlier than the last snapshot's, $last_snap_gen" + echo "$svp stale: it's gen at creation, $svp_cgen, is earlier than the last received snapshot, $last_received's gen at creation: $last_received_cgen" + freshest_snap=$last_received stale=true fi + stale-file + continue fi - - stale_dir=/nocow/btrfs-stale - stale_file=$stale_dir/$vol - if $stale; then - mkdir -p $stale_dir - printf "%s\n" $last_snap > $stale_file - ret=1 - continue - else - rm -f $stale_file + # fallback to using last_snap as the freshest + freshest_snap=$last_snap + stale=true + # fresh if $svp has $last_snap as a snapshot, + if btrfs sub show $svp 2>/dev/null | sed '0,/^\s*Snapshot(s):/d;s/^\s*//' | \ + grep -xF btrbk/$last_snap &>/dev/null; then + stale=false + else # or else $svp is a snapshot of $last_snap. we use a uuid + # comparison, which if I remember from the docs, is a bit more + # robust, perhaps to renames. + last_snap_uuid=$(btrfs sub show $last_snap| awk '$1 == "UUID:" {print $2}') + if btrfs sub show $svp| grep "^\s*Parent UUID:\s*$last_snap_uuid$" &>/dev/null; then + stale=false + fi fi + + stale-file + done exit $ret