From f960fc3b6fa20e112107950f18aa37771772caa3 Mon Sep 17 00:00:00 2001 From: Dominik Csapak Date: Fri, 4 Jun 2021 15:59:46 +0200 Subject: [PATCH] fix #3433: use PVE's wearout logic in PBS in PVE, the logic how wearout gets read from the smartctl output was changed from a vendor -> id map to a sorted list of specific attribute field names. copy that list to pbs (in the same order), and use that to get the wearout in the future we might want to split the disk logic into its own crate and reuse it in pve Signed-off-by: Dominik Csapak --- src/tools/disks/smart.rs | 57 +++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/src/tools/disks/smart.rs b/src/tools/disks/smart.rs index d7f05226..b615603e 100644 --- a/src/tools/disks/smart.rs +++ b/src/tools/disks/smart.rs @@ -1,3 +1,6 @@ +use std::collections::{HashMap, HashSet}; + +use lazy_static::lazy_static; use anyhow::{bail, Error}; use ::serde::{Deserialize, Serialize}; @@ -95,10 +98,10 @@ pub fn get_smart_data( let mut wearout = None; let mut attributes = Vec::new(); + let mut wearout_candidates = HashMap::new(); // ATA devices if let Some(list) = output["ata_smart_attributes"]["table"].as_array() { - let wearout_id = lookup_vendor_wearout_id(disk); for item in list { let id = match item["id"].as_u64() { Some(id) => id, @@ -135,8 +138,8 @@ pub fn get_smart_data( None => continue, // skip attributes without threshold entry }; - if id == wearout_id { - wearout = Some(normalized); + if WEAROUT_FIELD_NAMES.contains(&name as &str) { + wearout_candidates.insert(name.clone(), normalized); } attributes.push(SmartAttribute { @@ -151,6 +154,15 @@ pub fn get_smart_data( } } + if !wearout_candidates.is_empty() { + for field in WEAROUT_FIELD_ORDER { + if let Some(value) = wearout_candidates.get(field as &str) { + wearout = Some(*value); + break; + } + } + } + // NVME devices if let Some(list) = output["nvme_smart_health_information_log"].as_object() { for (name, value) in list { @@ -186,27 +198,24 @@ pub fn get_smart_data( Ok(SmartData { status, wearout, attributes }) } -fn lookup_vendor_wearout_id(disk: &super::Disk) -> u64 { +static WEAROUT_FIELD_ORDER: &[&'static str] = &[ + "Media_Wearout_Indicator", + "SSD_Life_Left", + "Wear_Leveling_Count", + "Perc_Write/Erase_Ct_BC", + "Perc_Rated_Life_Remain", + "Remaining_Lifetime_Perc", + "Percent_Lifetime_Remain", + "Lifetime_Left", + "PCT_Life_Remaining", + "Lifetime_Remaining", + "Percent_Life_Remaining", + "Percent_Lifetime_Used", + "Perc_Rated_Life_Used" +]; - static VENDOR_MAP: &[(&str, u64)] = &[ - ("kingston", 231), - ("samsung", 177), - ("intel", 233), - ("sandisk", 233), - ("crucial", 202), - ]; - - let result = 233; // default - let model = match disk.model() { - Some(model) => model.to_string_lossy().to_lowercase(), - None => return result, +lazy_static! { + static ref WEAROUT_FIELD_NAMES: HashSet<&'static str> = { + WEAROUT_FIELD_ORDER.iter().cloned().collect() }; - - for (vendor, attr_id) in VENDOR_MAP { - if model.contains(vendor) { - return *attr_id; - } - } - - result }