> The main issue which all proposed solutions share is when > there's a large array, say, md0, and a small array, say, > md1, both shares the same set of underlying disks, so md > subystem will not check/repair them in parallel. In this > situation, we will never check md1 if checking md0 takes > more time than we allow in a month (28 days).
What do you think about suggested above solution (set sync_force_parallel to 1 during cronjobs)? This workaround is implemented in the updated (attached) patch. See also: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=556610#74 BTW, how bad is in general to set sync_force_parallel to 1 per default? (Cc'd to Neil Brown.) I think, it would be nice to end (not pause) check if it's reached sync_max. Perhaps, there is deep reasons why md's interface doesn't work in this way. Neil, could you explan this a bit? > I'll think about it all more. Any news?
--- /etc/cron.d/mdadm.orig 2013-12-25 19:00:14.000000000 +0400 +++ /etc/cron.d/mdadm 2013-12-25 19:01:50.000000000 +0400 @@ -5,8 +5,7 @@ # distributed under the terms of the Artistic Licence 2.0 # -# By default, run at 00:57 on every Sunday, but do nothing unless the day of -# the month is less than or equal to 7. Thus, only run on the first Sunday of -# each month. crontab(5) sucks, unfortunately, in this regard; therefore this -# hack (see #380425). -57 0 * * 0 root if [ -x /usr/share/mdadm/checkarray ] && [ $(date +\%d) -le 7 ]; then /usr/share/mdadm/checkarray --cron --all --idle --quiet; fi +# By default, start (or continue unfinished checks) at 00:57 +# and stop (interrupt) checks at 01:57. +57 0 * * * root [ -x /usr/share/mdadm/checkarray ] && /usr/share/mdadm/checkarray --cron --all --idle --quiet +57 1 * * * root [ -x /usr/share/mdadm/checkarray ] && /usr/share/mdadm/checkarray --cron --all --idle --quiet --interrupt --- /usr/share/mdadm/checkarray.orig 2013-01-24 17:26:51.000000000 +0400 +++ /usr/share/mdadm/checkarray 2013-12-25 18:58:56.000000000 +0400 @@ -27,10 +27,12 @@ -a|--all check all assembled arrays (ignores arrays in command line). -s|--status print redundancy check status of devices. -x|--cancel queue a request to cancel a running redundancy check. + --interrupt queue a request to interrupt a running redundancy check. -i|--idle perform check in a lowest scheduling class (idle) -l|--slow perform check in a lower-than-standard scheduling class -f|--fast perform check in higher-than-standard scheduling class --realtime perform check in real-time scheduling class (DANGEROUS!) + --split n check next 1/n'th part (n <= 28) of every specified device (override CHECK_SPLIT) -c|--cron honour AUTOCHECK setting in /etc/default/mdadm. -q|--quiet suppress informational messages (use twice to suppress error messages too). @@ -50,7 +52,7 @@ } SHORTOPTS=achVqQsxilf -LONGOPTS=all,cron,help,version,quiet,real-quiet,status,cancel,idle,slow,fast,realtime +LONGOPTS=all,cron,help,version,quiet,real-quiet,status,cancel,interrupt,idle,slow,fast,realtime,split: eval set -- $(getopt -o $SHORTOPTS -l $LONGOPTS -n $PROGNAME -- "$@") @@ -62,20 +64,31 @@ action=check ionice= -for opt in $@; do - case "$opt" in - -a|--all) all=1;; - -s|--status) action=status;; - -x|--cancel) action=idle;; - -i|--idle) ionice=idle;; - -l|--slow) ionice=low;; - -f|--fast) ionice=high;; - --realtime) ionice=realtime;; - -c|--cron) cron=1;; - -q|--quiet) quiet=$(($quiet+1));; - -Q|--real-quiet) quiet=$(($quiet+2));; # for compatibility +while true +do + case "$1" in + -a|--all) all=1; shift;; + -s|--status) action=status; shift;; + -x|--cancel) action=cancel; shift;; + --interrupt) action=interrupt; shift;; + -i|--idle) ionice=idle; shift;; + -l|--slow) ionice=low; shift;; + -f|--fast) ionice=high; shift;; + --realtime) ionice=realtime; shift;; + --split) CHECK_SPLIT=$2; shift 2;; + -c|--cron) cron=1; shift;; + -q|--quiet) quiet=$(($quiet+1)); shift;; + -Q|--real-quiet) quiet=$(($quiet+2)); shift;; # for compatibility -h|--help) usage; exit 0;; -V|--version) about; exit 0;; + --) shift; break;; + *) echo "$PROGNAME: E: invalid option: $1. Try --help." >&2; exit 1;; + esac +done + +for opt in $@ +do + case $opt in /dev/md/*|md/*) arrays="${arrays:+$arrays }md${opt#*md/}";; /dev/md*|md*) arrays="${arrays:+$arrays }${opt#/dev/}";; /sys/block/md*) arrays="${arrays:+$arrays }${opt#/sys/block/}";; @@ -99,6 +112,20 @@ exit 0 fi +CHECK_SPLIT=${CHECK_SPLIT:-28} + +if [ $CHECK_SPLIT -gt 28 ] +then + CHECK_SPLIT=28 + echo "$PROGNAME: W: CHECK_SPLIT > 28, reset to 28." >&2 +fi + +if [ $CHECK_SPLIT -lt 1 ] +then + CHECK_SPLIT=1 + echo "$PROGNAME: W: CHECK_SPLIT < 1, reset to 1." >&2 +fi + if [ ! -f /proc/mdstat ]; then [ $quiet -lt 2 ] && echo "$PROGNAME: E: MD subsystem not loaded, or /proc unavailable." >&2 exit 2 @@ -159,10 +186,34 @@ continue fi + chunk_size=$(cat $MDBASE/chunk_size) + # set one to safe value if raid level has no chunk_size (e.g., raid 1): + [ $chunk_size -lt 1 ] && chunk_size=1 + + array_size=$(cat $MDBASE/../size) + array_size=$(($array_size >> 1)) + + check_size=$(($array_size / $CHECK_SPLIT)) + # ensure it's of multiple $chunk_size: + check_size=$(($check_size - $check_size % $chunk_size)) + [ $check_size -eq 0 ] && check_size=$chunk_size + case "$action" in - idle) - echo $action > $MDBASE/sync_action + cancel|interrupt) + echo 0 > $MDBASE/sync_force_parallel # XXX + + completed=$(cut -d ' ' -f1 $MDBASE/sync_completed) + [ $completed = "none" ] && completed=0 + echo "idle" > $MDBASE/sync_action [ $quiet -lt 1 ] && echo "$PROGNAME: I: cancel request queued for array $array." >&2 + + if [ "$action" = "cancel" ] + then + completed=0 + echo max > $MDBASE/sync_max + fi + # save sync_min, it must be a multiple of chunk_size: + echo $(($completed - $completed%$chunk_size)) > $MDBASE/sync_min ;; check) @@ -186,6 +237,21 @@ fi fi + echo 1 > $MDBASE/sync_force_parallel # XXX + + sync_min=$(cat $MDBASE/sync_min) + sync_max=$(cat $MDBASE/sync_max) + + [ $sync_max = "max" ] && sync_max=0 + + if [ $sync_min -eq $sync_max ] + then + sync_max=$(($sync_max + $check_size)) + [ $sync_max -ge $array_size ] && sync_max=$array_size + + echo $sync_max > $MDBASE/sync_max + fi + # queue request for the array. The kernel will make sure that these requests # are properly queued so as to not kill one of the array. echo $action > $MDBASE/sync_action