#!/bin/bash [[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@" source /a/bin/errhandle/err # inspired from # https://github.com/kdave/btrfsmaintenance # Man page says we could also use a range, i suppose it would be # logical to use a pattern like 5..10 10..20, # but I don't know if this would help us at all. dusage="5 10" musage="5" e() { echo "cron: $*" if ! $dryrun; then "$@" fi } check-idle() { type -p xprintidle &>/dev/null || return 0 export DISPLAY=:0 # a hours, a movie could run that long. idle_limit=$((1000 * 60 * 60 * 2)) idle_time=$idle_limit while read -r user; do new_idle_time=$(sudo -u $user xprintidle 2>/dev/null) ||: if [[ $new_idle_time && $new_idle_time -lt $idle_time ]]; then idle_time=$new_idle_time fi done < <(users | tr " " "\n" | sort -u) if (( idle_time < idle_limit )); then idle=false else idle=true fi } usage() { cat <&2 usage 1 ;; esac fi main() { idle=true if ! $force; then check-idle fi tmp=$(mktemp) fnd="findmnt --types btrfs --noheading" for x in $($fnd --output "SOURCE" --nofsroot | sort -u); do mnt=$($fnd --output "TARGET" --first-only --source $x) [[ $mnt ]] || continue if ! btrfs dev stats -c $mnt >$tmp; then if diff -q $mnt/btrfs-dev-stats $tmp; then diff -u $mnt/btrfs-dev-stats $tmp | mail -s "$HOSTNAME: error: btrfs dev stats -c $mnt" root@localhost cat $tmp >$mnt/btrfs-dev-stats fi fi if ! $idle; then if $dryrun; then echo "$0: not idle. if this wasnt a dry run, btrfs scrub cancel $mnt" else btrfs scrub cancel $mnt &>/dev/null ||: continue fi fi if $check; then continue fi # for comparing before and after balance. # the log is already fairly verbose, so commented. # e btrfs filesystem df $mnt # e df -H $mnt if btrfs filesystem df $mnt | grep -q "Data+Metadata"; then for usage in $dusage; do e ionice -c 3 btrfs balance start -dusage=$usage -musage=$usage $mnt done else e ionice -c 3 btrfs balance start -dusage=0 $mnt for usage in $dusage; do e ionice -c 3 btrfs balance start -dusage=$usage $mnt done e ionice -c 3 btrfs balance start -musage=0 $mnt for usage in $musage; do e ionice -c 3 btrfs balance start -musage=$usage $mnt done fi date= scrub_status=$(btrfs scrub status $mnt) if printf "%s\n" "$scrub_status" | grep -i '^status:[[:space:]]*finished$' &>/dev/null; then date=$(printf "%s\n" "$scrub_status" | sed -rn 's/^Scrub started:[[:space:]]*(.*)/\1/p') fi if [[ ! $date ]]; then # output from older versions, at least btrfs v4.15.1 date=$( printf "%s\n" "$scrub_status" | \ sed -rn 's/^\s*scrub started at (.*) and finished.*/\1/p' ) fi if [[ $date ]]; then if $dryrun; then echo "$0: last scrub finish for $mnt: $date" fi date=$(date --date="$date" +%s) # if date is sooner than 90 days ago # the wiki recommends 30 days or so, but # it makes the comp lag like shit for a day, # so I'm going with 90 days. if (( date > EPOCHSECONDS - 60*60*24*30 )); then if $dryrun; then echo "$0: skiping scrub of $mnt, last was $(( (EPOCHSECONDS - date) / 60/60/24 )) days ago, < 30 days" fi continue fi fi # -c 2 -n 4 is from btrfsmaintenance, does ionice e btrfs scrub start -Bd -c 2 -n 4 $mnt done } loop-main() { while true; do main sleep 60 done } if $check; then loop-main else main fi