purge old leaf subvols
authorIan Kelling <iank@fsf.org>
Sat, 30 Mar 2019 18:54:08 +0000 (14:54 -0400)
committerIan Kelling <iank@fsf.org>
Sat, 30 Mar 2019 18:54:08 +0000 (14:54 -0400)
mount-latest-subvol

index 186b9602dd72010b67a3da62a100717c932950fd..bf5ec9c844e27221d0a91548dfc834f16fdb6b05 100644 (file)
 [[ $EUID == 0 ]] || exec sudo -E "$BASH_SOURCE" "$@"
 
 errcatch() {
-    set -E; shopt -s extdebug
-    _err-trap() {
-        err=$?
-        exec >&2
-        set +x
-        echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]}:in \`$BASH_COMMAND' returned $err"
-        bash-trace 2
-        echo "$0: exiting with code $err"
-        exit $err
-    }
-    trap _err-trap ERR
-    set -o pipefail
+  set -E; shopt -s extdebug
+  _err-trap() {
+    err=$?
+    exec >&2
+    set +x
+    echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]}:in \`$BASH_COMMAND' returned $err"
+    bash-trace 2
+    echo "$0: exiting with code $err"
+    exit $err
+  }
+  trap _err-trap ERR
+  set -o pipefail
 }
 bash-trace() {
-    local -i argc_index=0 frame i start=${1:-1} max_indent=8 indent
-    local source
-    local extdebug=false
-    if [[ $(shopt -p extdebug) == *-s* ]]; then
-        extdebug=true
-    fi
+  local -i argc_index=0 frame i start=${1:-1} max_indent=8 indent
+  local source
+  local extdebug=false
+  if [[ $(shopt -p extdebug) == *-s* ]]; then
+    extdebug=true
+  fi
 
-    for ((frame=0; frame < ${#FUNCNAME[@]}-1; frame++)); do
-        argc=${BASH_ARGC[frame]}
-        argc_index+=$argc
-        ((frame < start)) && continue
-        if (( ${#BASH_SOURCE[@]} > 1 )); then
-            source="${BASH_SOURCE[frame+1]}:${BASH_LINENO[frame]}:"
-        fi
-        indent=$((frame-start+1))
-        indent=$((indent < max_indent ? indent : max_indent))
-        printf "%${indent}s↳%sin \`%s" '' "$source" "${FUNCNAME[frame]}"
-        if $extdebug; then
-            for ((i=argc_index-1; i >= argc_index-argc; i--)); do
-                printf " %s" "${BASH_ARGV[i]}"
-            done
-        fi
-        echo \'
-    done
+  for ((frame=0; frame < ${#FUNCNAME[@]}-1; frame++)); do
+    argc=${BASH_ARGC[frame]}
+    argc_index+=$argc
+    ((frame < start)) && continue
+    if (( ${#BASH_SOURCE[@]} > 1 )); then
+      source="${BASH_SOURCE[frame+1]}:${BASH_LINENO[frame]}:"
+    fi
+    indent=$((frame-start+1))
+    indent=$((indent < max_indent ? indent : max_indent))
+    printf "%${indent}s↳%sin \`%s" '' "$source" "${FUNCNAME[frame]}"
+    if $extdebug; then
+      for ((i=argc_index-1; i >= argc_index-argc; i--)); do
+        printf " %s" "${BASH_ARGV[i]}"
+      done
+    fi
+    echo \'
+  done
 }
 errcatch
 
 tu() {
-    while read -r line; do
-        file="$1"
-        grep -xFq "$line" "$file" || tee -a "$file"<<<"$line"
-    done
+  while read -r line; do
+    file="$1"
+    grep -xFq "$line" "$file" || tee -a "$file"<<<"$line"
+  done
 }
 e() { printf "%s\n" "$*"; "$@"; }
 mnt() {
-    dir=$1
-    if ! mountpoint $dir &>/dev/null; then
-        mkdir -p $dir
-        e mount $dir
-    fi
+  dir=$1
+  if ! mountpoint $dir &>/dev/null; then
+    mkdir -p $dir
+    e mount $dir
+  fi
 }
 fstab() {
-    while read -r start mpoint end; do
-        l="$start $mpoint $end"
-        # kill off any lines that duplicate the mount point.
-        sed --follow-symlinks -ri "\%$l%b;\%^\s*\S+\s+$mpoint\s%d" /etc/fstab
-        tu /etc/fstab <<<"$l"
-    done
+  while read -r start mpoint end; do
+    l="$start $mpoint $end"
+    # kill off any lines that duplicate the mount point.
+    sed --follow-symlinks -ri "\%$l%b;\%^\s*\S+\s+$mpoint\s%d" /etc/fstab
+    tu /etc/fstab <<<"$l"
+  done
 }
 kill-dir() {
-    for sig; do
-        echo kill-dir $sig
-        found_pids=false
-        if pids=$(timeout 4 lsof -t $dir); then
-            found_pids=true
-            timeout 4 lsof -w $dir
-            kill -$sig $pids
-        fi
-        # fuser will find open sockets that lsof won't, for example from gpg-agent.
-        # note: -v shows kernel processes, which then doesn't return true when we want
-        if timeout 4 fuser -m $dir &>/dev/null; then
-            found_pids=true
-            fuser -$sig -mvk $dir
-        fi
-        sleep .5
-        if ! $found_pids; then
-            return 0
-        fi
-    done
-    return 1
+  for sig; do
+    echo kill-dir $sig
+    found_pids=false
+    if pids=$(timeout 4 lsof -t $dir); then
+      found_pids=true
+      timeout 4 lsof -w $dir
+      kill -$sig $pids
+    fi
+    # fuser will find open sockets that lsof won't, for example from gpg-agent.
+    # note: -v shows kernel processes, which then doesn't return true when we want
+    if timeout 4 fuser -m $dir &>/dev/null; then
+      found_pids=true
+      fuser -$sig -mvk $dir
+    fi
+    sleep .5
+    if ! $found_pids; then
+      return 0
+    fi
+  done
+  return 1
 }
 
 force=false
 if [[ $1 == -f ]]; then
-    force=true
+  force=true
 fi
 
 ret=0
@@ -125,7 +125,7 @@ shopt -s nullglob
 # to home directories
 f=(/mnt/root/btrbk/q.*)
 if [[ -e $f ]]; then
-    fstab <<EOF
+  fstab <<EOF
 $first_root_crypt  /q  btrfs  noatime,subvol=q,gid=1000  0 0
 /q/p  /p  none  bind  0 0
 EOF
@@ -133,144 +133,151 @@ fi
 
 f=(/mnt/root/btrbk/o.*)
 if [[ -e $f ]]; then
-    fstab <<EOF
+  fstab <<EOF
 $first_root_crypt  /o  btrfs  noatime,subvol=o  0 0
 /o/m  /m  none  bind  0 0
 EOF
 fi
 
 if [[ $HOSTNAME == frodo ]]; then
-    fstab <<EOF
+  fstab <<EOF
 $first_root_crypt  /i  btrfs  noatime,subvol=i  0 0
 EOF
 fi
 ##### end setup fstab for subvols we care about ######
 
 for vol in q a o i; do
-    d=/$vol
-    if ! awk '{print $2}' /etc/fstab | grep -xF $d &>/dev/null; then
-        continue
-    fi
+  d=/$vol
+  if ! awk '{print $2}' /etc/fstab | grep -xF $d &>/dev/null; then
+    continue
+  fi
 
 
-    ##### begin building up list of bind mounts  ######
-    binds=() # list of bind mounts
-    roots=($d) # list of bind mounts, plus the original mount
-    while true; do
-        new_roots=()
-        for r in ${roots[@]}; do
-            # eg. when r=/q/p, for lines like
-            # /q/p  /p  none  bind  0 0
-            # output /p
-            new_roots+=($(sed -rn "s#^$r/\S+\s+(\S+)\s+none\s+bind\s.*#\1#p" /etc/fstab))
-        done
-        (( ${#new_roots} )) || break
-        binds+=(${new_roots[@]})
-        roots=( ${new_roots[@]} )
+  ##### begin building up list of bind mounts  ######
+  binds=() # list of bind mounts
+  roots=($d) # list of bind mounts, plus the original mount
+  while true; do
+    new_roots=()
+    for r in ${roots[@]}; do
+      # eg. when r=/q/p, for lines like
+      # /q/p  /p  none  bind  0 0
+      # output /p
+      new_roots+=($(sed -rn "s#^$r/\S+\s+(\S+)\s+none\s+bind\s.*#\1#p" /etc/fstab))
     done
-    ##### end building up list of bind mounts  ######
-
+    (( ${#new_roots} )) || break
+    binds+=(${new_roots[@]})
+    roots=( ${new_roots[@]} )
+  done
+  ##### end building up list of bind mounts  ######
 
-    # if latest is already mounted, make sure binds are mounted and move on
-    if e check-subvol-stale $d; then
-        mnt $d
-        for b in ${binds[@]}; do
-            mnt $b
-        done
-        continue
-    fi
 
-    fresh_snap=$(</nocow/btrfs-stale/$vol)
-    if [[ ! $fresh_snap ]]; then
-        echo "$0: error. empty fresh_snap var"
-        ret=1
-        continue
-    fi
+  # if latest is already mounted, make sure binds are mounted and move on
+  if e check-subvol-stale $d; then
+    mnt $d
+    for b in ${binds[@]}; do
+      mnt $b
+    done
+    continue
+  fi
 
-    umount_ret=true
-    unmounted=()
-    for dir in $(echo $d ${binds[*]}\ |tac -s\ ); do
-        if mountpoint $dir; then
-            if e umount -R $dir; then
-                unmounted+=($dir)
-            else
-                if ! kill-dir TERM TERM TERM INT INT HUP HUP; then
-                    if $force; then  kill-dir KILL; fi
-                fi
+  fresh_snap=$(</nocow/btrfs-stale/$vol)
+  if [[ ! $fresh_snap ]]; then
+    echo "$0: error. empty fresh_snap var"
+    ret=1
+    continue
+  fi
 
-                if e umount -R $dir; then
-                    unmounted+=($dir)
-                else
-                    echo "$0: failed to umount $dir"
-                    umount_ret=false
-                    ret=1
-                    continue
-                fi
-            fi
+  umount_ret=true
+  unmounted=()
+  for dir in $(echo $d ${binds[*]}\ |tac -s\ ); do
+    if mountpoint $dir; then
+      if e umount -R $dir; then
+        unmounted+=($dir)
+      else
+        if ! kill-dir TERM TERM TERM INT INT HUP HUP; then
+          if $force; then  kill-dir KILL; fi
         fi
-    done
 
-    if ! $umount_ret; then
-        for dir in ${unmounted[@]}; do
-            mnt $dir
-        done
-        continue
+        if e umount -R $dir; then
+          unmounted+=($dir)
+        else
+          echo "$0: failed to umount $dir"
+          umount_ret=false
+          ret=1
+          continue
+        fi
+      fi
     fi
+  done
 
-    # todo: decipher /mnt/root, like we do in check-subvol-stale
-    cd /mnt/root
-    if [[ -e $vol ]]; then
-        e mv $vol $vol.leaf.$(date +%Y-%m-%dT%H:%M:%S-%z)
-    fi
-    # Note, we make a few assumptions in this script, like
-    # $d was not a different subvol id than $vol, and
-    # things otherwise didn't get mounted very strangely.
-    e btrfs sub snapshot $fresh_snap $vol
-    for dir in $d ${binds[@]}; do
-        e mnt $dir
+  if ! $umount_ret; then
+    for dir in ${unmounted[@]}; do
+      mnt $dir
     done
-    stale_dir=/nocow/btrfs-stale
-    rm -f $stale_dir/$d
+    continue
+  fi
+
+  # todo: decipher /mnt/root, like we do in check-subvol-stale
+  cd /mnt/root
+  if [[ -e $vol ]]; then
+    e mv $vol $vol.leaf.$(date +%Y-%m-%dT%H:%M:%S%z)
+    leaf_vols=($vol.leaf.*)
+    for leaf in ${leaf_vols[@]}; do
+      leaf_secs=$(date -d ${leaf#$vol.leaf.} +%s)
+      if (( $(date +%s) - 60*60*24*60 > leaf_secs )); then # 60 days
+        e btrfs sub del $leaf
+      fi
+    done
+  fi
+  # Note, we make a few assumptions in this script, like
+  # $d was not a different subvol id than $vol, and
+  # things otherwise didn't get mounted very strangely.
+  e btrfs sub snapshot $fresh_snap $vol
+  for dir in $d ${binds[@]}; do
+    e mnt $dir
+  done
+  stale_dir=/nocow/btrfs-stale
+  rm -f $stale_dir/$d
 done
 
 ### disabled
 if [[ $HOSTNAME == kdxxxxxxxxx ]]; then
-    # partitioned it with fai partitioner outside of fai,
-    # because it\'s worth it to have 1% space reserved for boot and
-    # swap partitions in case I ever want to boot off those drives.
-    # as root:
-    # . /a/bin/fai/fai-wrapper
-    # eval-fai-classfile /a/bin/fai/fai/config/class/51-multi-boot
-    # fai-setclass ROTATIONAL
-    # export LUKS_DIR=/q/root/luks/
-    # # because the partition nums existed already
-    # fai-setclass REPARTITION
-    # /a/bin/fai/fai/config/hooks/partition.DEFAULT
+  # partitioned it with fai partitioner outside of fai,
+  # because it\'s worth it to have 1% space reserved for boot and
+  # swap partitions in case I ever want to boot off those drives.
+  # as root:
+  # . /a/bin/fai/fai-wrapper
+  # eval-fai-classfile /a/bin/fai/fai/config/class/51-multi-boot
+  # fai-setclass ROTATIONAL
+  # export LUKS_DIR=/q/root/luks/
+  # # because the partition nums existed already
+  # fai-setclass REPARTITION
+  # /a/bin/fai/fai/config/hooks/partition.DEFAULT
 
-    devs=(
-        ata-TOSHIBA_MD04ACA500_84REK6NTFS9A-part1
-        ata-TOSHIBA_MD04ACA500_84R2K773FS9A-part1
-        ata-TOSHIBA_MD04ACA500_8471K430FS9A-part1
-        ata-TOSHIBA_MD04ACA500_8481K493FS9A-part1
-    )
-    first=true
-    for dev in ${devs[@]}; do
-        if $first; then
-            first=false
-            tu /etc/fstab <<EOF
+  devs=(
+    ata-TOSHIBA_MD04ACA500_84REK6NTFS9A-part1
+    ata-TOSHIBA_MD04ACA500_84R2K773FS9A-part1
+    ata-TOSHIBA_MD04ACA500_8471K430FS9A-part1
+    ata-TOSHIBA_MD04ACA500_8481K493FS9A-part1
+  )
+  first=true
+  for dev in ${devs[@]}; do
+    if $first; then
+      first=false
+      tu /etc/fstab <<EOF
 /dev/mapper/crypt_dev_$dev /i btrfs  noatime,subvol=i,noauto  0 0
 /dev/mapper/crypt_dev_$dev /mnt/iroot btrfs  noatime,subvolid=0,noauto  0 0
 EOF
-        fi
-        tu /etc/crypttab <<EOF
+    fi
+    tu /etc/crypttab <<EOF
 crypt_dev_$dev  /dev/disk/by-id/$dev  /q/root/luks/host-kd  discard,luks
 EOF
-        if [[ ! -e /dev/mapper/crypt_dev_$dev ]]; then
-            cryptdisks_start crypt_dev_$dev
-        fi
-    done
-    # note, could do an else here and have some kind of mount for /i
-    # on other hosts.
+    if [[ ! -e /dev/mapper/crypt_dev_$dev ]]; then
+      cryptdisks_start crypt_dev_$dev
+    fi
+  done
+  # note, could do an else here and have some kind of mount for /i
+  # on other hosts.
 fi
 
 exit $ret