move SMART error handling into get_disks

because we never ever want to die in get_disks because of a
single disk, but the nodes/xyz/disks/smart API path is
allowed to fail if a disk device is unsupported by smartctl
or something else goes wrong.
This commit is contained in:
Fabian Grünbichler
2016-09-28 13:42:22 +02:00
committed by Dietmar Maurer
parent d547f26c7d
commit acd3d91649
2 changed files with 34 additions and 35 deletions

View File

@ -138,6 +138,8 @@ __PACKAGE__->register_method ({
$result = PVE::Diskmanage::get_smart_data($disk); $result = PVE::Diskmanage::get_smart_data($disk);
} }
$result->{health} = 'UNKOWN' if !defined $result->{health};
return $result; return $result;
}}); }});

View File

@ -110,7 +110,6 @@ sub get_smart_data {
if ((defined($returncode) && ($returncode & 0b00000011)) || $err) { if ((defined($returncode) && ($returncode & 0b00000011)) || $err) {
die "Error getting S.M.A.R.T. data: Exit code: $returncode\n"; die "Error getting S.M.A.R.T. data: Exit code: $returncode\n";
} }
$smartdata->{health} = 'UNKOWN' if !defined $smartdata->{health};
return $smartdata; return $smartdata;
} }
@ -119,22 +118,19 @@ sub get_smart_health {
return "NOT A DEVICE" if !assert_blockdev($disk, 1); return "NOT A DEVICE" if !assert_blockdev($disk, 1);
my $message = "UNKOWN"; my $message;
eval { run_command([$SMARTCTL, '-H', $disk], noerr => 1, outfunc => sub {
run_command([$SMARTCTL, '-H', $disk], noerr => 1, outfunc => sub { my ($line) = @_;
my ($line) = @_;
if ($line =~ m/test result: (.*)$/) { if ($line =~ m/test result: (.*)$/) {
$message = $1; $message = $1;
} elsif ($line =~ m/open device: (.*) failed: (.*)$/) { } elsif ($line =~ m/open device: (.*) failed: (.*)$/) {
$message = "FAILED TO OPEN"; $message = "FAILED TO OPEN";
} elsif ($line =~ m/^SMART Disabled/) { } elsif ($line =~ m/^SMART Disabled/) {
$message = "SMART DISABLED"; $message = "SMART DISABLED";
} }
}); });
};
# we ignore errors here because by default we want to return UNKNOWN
return $message; return $message;
} }
@ -366,29 +362,30 @@ sub get_disks {
} }
} }
my $health; my $health = 'UNKNOWN';
my $wearout; my $wearout;
if ($type eq 'ssd' && !defined($disk)) { eval {
# if we have an ssd we try to get the wearout indicator if ($type eq 'ssd' && !defined($disk)) {
my $smartdata = get_smart_data($devpath); # if we have an ssd we try to get the wearout indicator
$health = $smartdata->{health}; $wearout = 'N/A';
foreach my $attr (@{$smartdata->{attributes}}) { my $smartdata = get_smart_data($devpath);
# ID 233 is media wearout indicator on intel and sandisk $health = $smartdata->{health};
# ID 177 is media wearout indicator on samsung foreach my $attr (@{$smartdata->{attributes}}) {
next if ($attr->{id} != 233 && $attr->{id} != 177); # ID 233 is media wearout indicator on intel and sandisk
next if ($attr->{name} !~ m/wear/i); # ID 177 is media wearout indicator on samsung
$wearout = $attr->{value}; next if ($attr->{id} != 233 && $attr->{id} != 177);
next if ($attr->{name} !~ m/wear/i);
$wearout = $attr->{value};
# prefer the 233 value # prefer the 233 value
last if ($attr->{id} == 233); last if ($attr->{id} == 233);
}
} elsif (!defined($disk)) {
# we do not need smart data if we check a single disk
# because this functionality is only for disk_is_used
$health = get_smart_health($devpath) if !defined($disk);
} }
};
$wearout = 'N/A' if !defined($wearout);
} elsif (!defined($disk)) {
# we do not need smart data if we check a single disk
# because this functionality is only for disk_is_used
$health = get_smart_health($devpath) if !defined($disk);
}
my $used; my $used;