tweaks after migration of narada
[sysadmin-cookbook] / recepies / smart / smart-test-relocate.pl
1 #!/usr/bin/perl
2
3 use warnings;
4 use strict;
5
6 my $drive = $ARGV[0] || die "usage: $0 /dev/sda\n";
7 my $delay = 15;
8 my $rewrite_sectors = 16;
9
10 my $test_started = 0;
11
12 sub write_sector {
13         my $s = shift;
14         system "hdparm --write-sector $s --yes-i-know-what-i-am-doing $drive";
15 }
16
17 sub smart_test {
18         my $sector = shift;
19         my $cmd = "smartctl -t select,$sector-max $drive";
20         warn "$cmd\n";
21         system $cmd;
22         $test_started = 1;
23 }
24
25 sub smart {
26         my $cmd = "smartctl -l selective $drive";
27         warn "$cmd\n";
28         open(my $fh, '-|', $cmd);
29         while(<$fh>) {
30                 chomp;
31                 print "# $_\n";
32                 if ( m/Completed_read_failure.*\((\d+)-\d+\)/ ) {
33                         my $sector = $1;
34                         print "rewrite sector: $sector\n";
35                         foreach my $s ( $sector .. $sector + $rewrite_sectors ) {
36                                 write_sector $s;
37                         }
38                         smart_test $sector;
39                         return 1;
40                 } elsif ( m/Self_test_in_progress/ ) {
41                         $test_started = 1;
42                         return 1;
43                 } elsif ( m/Not_testing/ ) {
44                         if ( $test_started ) {
45                                 smart_last_error();
46                                 return 1 if $test_started;
47                         }
48                         smart_test 0; # first-time invocation
49                 }
50         }
51         return 0;
52 }
53
54 sub smart_last_error {
55         my $cmd = "smartctl -l selftest $drive";
56         warn "$cmd\n";
57         open(my $fh, '-|', $cmd);
58         while(<$fh>) {
59                 chomp;
60                 print "# $_\n";
61                 if (/^#\s+1.+Completed: read failure\s+\S+\s+\S+\s+(\d+)/) {
62                         write_sector $1;
63                         smart_test $1;
64                         return 1;
65                 }
66         }
67 }
68
69 smart_last_error || smart_test 0;
70
71 while ( smart ) {
72         warn "sleep $delay s", ( $test_started ? " smart test running..." : "idle" ), "\n";
73         sleep $delay;
74 }