33cae4a36280351c170155f11fc83ba8ca3b2102
4 [[ $EUID == 0 ]] ||
exec sudo
-E "${BASH_SOURCE[0]}" "$@"
6 source /a
/bin
/errhandle
/err
9 # https://github.com/kdave/btrfsmaintenance
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.
26 type -p xprintidle
&>/dev
/null ||
return 0
28 # a hours, a movie could run that long.
29 idle_limit
=$
((1000 * 60 * 60 * 2))
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
36 done < <(users |
tr " " "\n" |
sort -u)
37 if (( idle_time
< idle_limit
)); then
46 Usage: ${0##*/} [ARGS]
47 Do btrfs maintence or stop if xprintidle shows a user
49 force Run regardless of user idle status on all disks.
50 check Only check if an existing maintence should be cancelled due to
51 nonidle user. Also, runs in a loop every 20 seconds for 10
54 Note: Uses util-linux getopt option parsing: spaces between args and
55 options, short options can be combined, options before args.
76 echo "$0: error: unexpected arg" >&2
90 # When the cron kicks in, we may not be idle (physically sleeping) yet, so
92 while ! $idle && (( min
< max_min
)); do
97 # If we've waited a really long time for idle, just give up.
98 if (( min
== max_min
)); then
106 fnd
="findmnt --types btrfs --noheading"
107 for x
in $
($fnd --output "SOURCE" --nofsroot |
sort -u); do
108 mnt
=$
($fnd --output "TARGET" --first-only --source $x)
109 [[ $mnt ]] ||
continue
111 #### begin look for diff in stats, eg: increasing error count ####
113 # Only run for $check, since it runs in parallel to non-check, avoid
116 if ! btrfs dev stats
-c $mnt >$tmp; then
117 if diff -q $mnt/btrfs-dev-stats
$tmp; then
118 diff -u $mnt/btrfs-dev-stats
$tmp |
mail -s "$HOSTNAME: error: btrfs dev stats -c $mnt" root@localhost
119 cat $tmp >$mnt/btrfs-dev-stats
124 #### end look for diff in stats, eg: increasing error count ####
129 echo "$0: not idle. if this wasnt a dry run, btrfs scrub cancel $mnt"
131 btrfs scrub cancel
$mnt &>/dev
/null ||
:
137 # for comparing before and after balance.
138 # the log is already fairly verbose, so commented.
139 # e btrfs filesystem df $mnt
141 if btrfs filesystem df
$mnt |
grep -q "Data+Metadata"; then
142 for usage
in $dusage; do
143 e ionice
-c 3 btrfs balance start
-dusage=$usage -musage=$usage $mnt
146 e ionice
-c 3 btrfs balance start
-dusage=0 $mnt
147 for usage
in $dusage; do
148 e ionice
-c 3 btrfs balance start
-dusage=$usage $mnt
150 e ionice
-c 3 btrfs balance start
-musage=0 $mnt
151 for usage
in $musage; do
152 e ionice
-c 3 btrfs balance start
-musage=$usage $mnt
156 scrub_status
=$
(btrfs scrub status
$mnt)
157 if printf "%s\n" "$scrub_status" |
grep -i '^status:[[:space:]]*finished$' &>/dev
/null
; then
158 date=$
(printf "%s\n" "$scrub_status" |
sed -rn 's/^Scrub started:[[:space:]]*(.*)/\1/p')
160 if [[ ! $date ]]; then
161 # output from older versions, at least btrfs v4.15.1
163 printf "%s\n" "$scrub_status" | \
164 sed -rn 's/^\s*scrub started at (.*) and finished.*/\1/p'
169 echo "$0: last scrub finish for $mnt: $date"
171 date=$
(date --date="$date" +%s
)
172 # if date is sooner than 60 days ago
173 # the wiki recommends 30 days or so, but
174 # I'm going with 60 days.
175 if (( date > EPOCHSECONDS
- 60*60*24*60 )); then
177 echo "$0: skiping scrub of $mnt, last was $(( (EPOCHSECONDS - date) / 60/60/24 )) days ago, < 30 days"
182 # -c 2 -n 4 is from btrfsmaintenance, does ionice
183 e btrfs scrub start
-Bd -c 2 -n 4 $mnt
185 # We normally only do one disk since this is meant to be run while I sleep
186 # and if we try to do all disks, we invariably end up doing a scrub still
187 # after I've woken up. So, just do one per day.