fixes, prometheus, lots of stuff
[distro-setup] / btrfsmaint
1 #!/bin/bash
2
3
4 [[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@"
5
6 source /a/bin/errhandle/err
7
8 # inspired from
9 # https://github.com/kdave/btrfsmaintenance
10
11
12 # Man page says we could also use a range, i suppose it would be
13 # logical to use a pattern like 5..10 10..20,
14 # but I don't know if this would help us at all.
15 dusage="5 10"
16 musage="5"
17
18 e() {
19 echo "cron: $*"
20 if ! $dryrun; then
21 "$@"
22 fi
23 }
24
25 check-idle() {
26 type -p xprintidle &>/dev/null || return 0
27 export DISPLAY=:0
28 # a hours, a movie could run that long.
29 idle_limit=$((1000 * 60 * 60 * 2))
30 idle_time=$idle_limit
31 while read -r user; do
32 new_idle_time=$(sudo -u $user xprintidle 2>/dev/null) ||:
33 if [[ $new_idle_time && $new_idle_time -lt $idle_time ]]; then
34 idle_time=$new_idle_time
35 fi
36 done < <(users | tr " " "\n" | sort -u)
37 if (( idle_time < idle_limit )); then
38 idle=false
39 else
40 idle=true
41 fi
42 }
43
44
45 usage() {
46 cat <<EOF
47 Usage: ${0##*/} [ARGS]
48 Do btrfs maintence or stop if xprintidle shows a user
49
50 force Run regardless of user idle status
51 check Only check if an existing maintence should be cancelled due to
52 nonidle user. Also, runs in a loop every 20 seconds for 10
53 minutes.
54
55 Note: Uses util-linux getopt option parsing: spaces between args and
56 options, short options can be combined, options before args.
57 EOF
58 exit $1
59 }
60
61
62 force=false
63 check=false
64 dryrun=false
65 if [[ $1 ]]; then
66 case $1 in
67 check)
68 check=true
69 ;;
70 force)
71 force=true
72 ;;
73 dryrun)
74 dryrun=true
75 ;;
76 *)
77 echo "$0: error: unexpected arg" >&2
78 usage 1
79 ;;
80 esac
81 fi
82
83
84 main() {
85 idle=true
86 if ! $force; then
87 check-idle
88 fi
89
90 tmp=$(mktemp)
91
92 fnd="findmnt --types btrfs --noheading"
93 for x in $($fnd --output "SOURCE" --nofsroot | sort -u); do
94 mnt=$($fnd --output "TARGET" --first-only --source $x)
95 [[ $mnt ]] || continue
96
97 if ! btrfs dev stats -c $mnt >$tmp; then
98 if diff -q $mnt/btrfs-dev-stats $tmp; then
99 diff -u $mnt/btrfs-dev-stats $tmp | mail -s "$HOSTNAME: error: btrfs dev stats -c $mnt" root@localhost
100 cat $tmp >$mnt/btrfs-dev-stats
101 fi
102 fi
103
104 if ! $idle; then
105 if $dryrun; then
106 echo "$0: not idle. if this wasnt a dry run, btrfs scrub cancel $mnt"
107 else
108 btrfs scrub cancel $mnt &>/dev/null ||:
109 continue
110 fi
111 fi
112 if $check; then
113 continue
114 fi
115
116 # for comparing before and after balance.
117 # the log is already fairly verbose, so commented.
118 # e btrfs filesystem df $mnt
119 # e df -H $mnt
120 if btrfs filesystem df $mnt | grep -q "Data+Metadata"; then
121 for usage in $dusage; do
122 e ionice -c 3 btrfs balance start -dusage=$usage -musage=$usage $mnt
123 done
124 else
125 e ionice -c 3 btrfs balance start -dusage=0 $mnt
126 for usage in $dusage; do
127 e ionice -c 3 btrfs balance start -dusage=$usage $mnt
128 done
129 e ionice -c 3 btrfs balance start -musage=0 $mnt
130 for usage in $musage; do
131 e ionice -c 3 btrfs balance start -musage=$usage $mnt
132 done
133 fi
134 date=
135 scrub_status=$(btrfs scrub status $mnt)
136 if printf "%s\n" "$scrub_status" | grep -i '^status:[[:space:]]*finished$' &>/dev/null; then
137 date=$(printf "%s\n" "$scrub_status" | sed -rn 's/^Scrub started:[[:space:]]*(.*)/\1/p')
138 fi
139 if [[ ! $date ]]; then
140 # output from older versions, at least btrfs v4.15.1
141 date=$(
142 printf "%s\n" "$scrub_status" | \
143 sed -rn 's/^\s*scrub started at (.*) and finished.*/\1/p'
144 )
145 fi
146 if [[ $date ]]; then
147 if $dryrun; then
148 echo "$0: last scrub finish for $mnt: $date"
149 fi
150 date=$(date --date="$date" +%s)
151 # if date is sooner than 90 days ago
152 # the wiki recommends 30 days or so, but
153 # it makes the comp lag like shit for a day,
154 # so I'm going with 90 days.
155 if (( date > $(date +%s) - 60*60*24*30 )); then
156 if $dryrun; then
157 echo "$0: skiping scrub of $mnt, last was $(( ($(date +%s) - date) / 60/60/24 )) days ago, < 30 days"
158 fi
159 continue
160 fi
161 fi
162 # -c 2 -n 4 is from btrfsmaintenance, does ionice
163 e btrfs scrub start -Bd -c 2 -n 4 $mnt
164 done
165 }
166
167 loop-main() {
168 while true; do
169 main
170 sleep 60
171 done
172 }
173
174 if $check; then
175 loop-main
176 else
177 main
178 fi