]>
Commit | Line | Data |
---|---|---|
df881f75 N |
1 | #!/bin/bash |
2 | ||
3 | # Copyright (C) 2014 Neil Brown <neilb@suse.de> | |
4 | # | |
5 | # | |
6 | # This program is free software; you can redistribute it and/or modify | |
7 | # it under the terms of the GNU General Public License as published by | |
8 | # the Free Software Foundation; either version 2 of the License, or | |
9 | # (at your option) any later version. | |
10 | # | |
11 | # This program is distributed in the hope that it will be useful, | |
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | # GNU General Public License for more details. | |
15 | # | |
16 | # Author: Neil Brown | |
17 | # Email: <neilb@suse.de> | |
18 | ||
19 | # This script should be run periodically to automatically | |
20 | # perform a 'check' on any md arrays. | |
21 | # | |
22 | # It supports a 'time budget' such that any incomplete 'check' | |
23 | # will be checkpointed when that time has expired. | |
24 | # A subsequent invocation can allow the 'check' to continue. | |
25 | # | |
26 | # Options are: | |
27 | # --continue Don't start new checks, only continue old ones. | |
868ab80d | 28 | # --duration This is passed to "date --date=$duration" to find out |
df881f75 N |
29 | # when to finish |
30 | # | |
31 | # To support '--continue', arrays are identified by UUID and the 'sync_completed' | |
32 | # value is stored in /var/lib/mdcheck/$UUID | |
33 | ||
34 | # convert a /dev/md name into /sys/.../md equivalent | |
35 | sysname() { | |
36 | set `ls -lLd $1` | |
37 | maj=${5%,} | |
38 | min=$6 | |
39 | readlink -f /sys/dev/block/$maj:$min | |
40 | } | |
41 | ||
42 | args=$(getopt -o hcd: -l help,continue,duration: -n mdcheck -- "$@") | |
43 | rv=$? | |
44 | if [ $rv -ne 0 ]; then exit $rv; fi | |
45 | ||
46 | eval set -- $args | |
47 | ||
48 | cont= | |
49 | endtime= | |
50 | while [ " $1" != " --" ] | |
51 | do | |
52 | case $1 in | |
53 | --help ) | |
54 | echo >&2 'Usage: mdcheck [--continue] [--duration time-offset]' | |
55 | echo >&2 ' time-offset must be understood by "date --date"' | |
56 | exit 0 | |
57 | ;; | |
58 | --continue ) cont=yes ;; | |
59 | --duration ) shift; dur=$1 | |
868ab80d | 60 | endtime=$(date --date "$dur" "+%s") |
df881f75 N |
61 | ;; |
62 | esac | |
63 | shift | |
64 | done | |
65 | shift | |
66 | ||
67 | # We need a temp file occasionally... | |
68 | tmp=/var/lib/mdcheck/.md-check-$$ | |
69 | trap 'rm -f "$tmp"' 0 | |
70 | ||
71 | ||
72 | # firstly, clean out really old state files | |
73 | mkdir -p /var/lib/mdcheck | |
74 | find /var/lib/mdcheck -name "MD_UUID*" -type f -mtime +180 -exec rm {} \; | |
75 | ||
76 | # Now look at each md device. | |
77 | cnt=0 | |
78 | for dev in /dev/md?* | |
79 | do | |
36dab45b | 80 | [ -e "$dev" ] || continue |
df881f75 N |
81 | sys=`sysname $dev` |
82 | if [ ! -f "$sys/md/sync_action" ] | |
83 | then # cannot check this array | |
84 | continue | |
85 | fi | |
86 | if [ "`cat $sys/md/sync_action`" != 'idle' ] | |
87 | then # This array is busy | |
88 | continue | |
89 | fi | |
90 | ||
979b1feb | 91 | mdadm --detail --export "$dev" | grep '^MD_UUID=' > $tmp || continue |
df881f75 N |
92 | source $tmp |
93 | fl="/var/lib/mdcheck/MD_UUID_$MD_UUID" | |
94 | if [ -z "$cont" ] | |
95 | then | |
96 | start=0 | |
97 | elif [ -z "$MD_UUID" -o ! -f "$fl" ] | |
98 | then | |
99 | # Nothing to continue here | |
100 | continue | |
101 | else | |
102 | start=`cat "$fl"` | |
103 | fi | |
104 | ||
105 | cnt=$[cnt+1] | |
106 | eval MD_${cnt}_fl=\$fl | |
107 | eval MD_${cnt}_sys=\$sys | |
108 | echo $start > $fl | |
109 | echo $start > $sys/md/sync_min | |
110 | echo check > $sys/md/sync_action | |
111 | done | |
112 | ||
113 | if [ -z "$endtime" ] | |
114 | then | |
115 | exit 0 | |
116 | fi | |
117 | ||
118 | while [ `date +%s` -lt $endtime ] | |
119 | do | |
120 | any= | |
121 | for i in `eval echo {1..$cnt}` | |
122 | do | |
123 | eval fl=\$MD_${i}_fl | |
124 | eval sys=\$MD_${i}_sys | |
125 | ||
126 | if [ -z "$fl" ]; then continue; fi | |
127 | ||
128 | if [ "`cat $sys/md/sync_action`" != 'check' ] | |
129 | then | |
130 | eval MD_${i}_fl= | |
131 | rm -f $fl | |
132 | continue; | |
133 | fi | |
134 | read a rest < $sys/md/sync_completed | |
135 | echo $a > $fl | |
136 | any=yes | |
137 | done | |
138 | if [ -z "$any" ]; then exit 0; fi | |
139 | sleep 120 | |
140 | done | |
141 | ||
142 | # We've waited, and there are still checks running. | |
143 | # Time to stop them. | |
144 | for i in `eval echo {1..$cnt}` | |
145 | do | |
146 | eval fl=\$MD_${i}_fl | |
147 | eval sys=\$MD_${i}_sys | |
148 | ||
149 | if [ -z "$fl" ]; then continue; fi | |
150 | ||
151 | if [ "`cat $sys/md/sync_action`" != 'check' ] | |
152 | then | |
153 | eval MD_${i}_fl= | |
154 | rm -f $fl | |
155 | continue; | |
156 | fi | |
157 | echo idle > $sys/md/sync_action | |
158 | cat $sys/md/sync_min > $fl | |
159 | done |