From f8fe87cb783f3eb76bfa7a1554168aeebb31b407 Mon Sep 17 00:00:00 2001 From: Arjen Heidinga Date: Tue, 23 May 2023 10:15:03 +0200 Subject: [PATCH 1/4] Do not failis total data bytes written is zero It appears that complete unused NVME drives (at least SAMSUNG MZQL27T6HBLA-00A07) report just '0' if there is nothing ever written to the drive. With several hotspares this breaks. I have no idea what if ever anything else than '0' is returned, but this catches that too. ``` # for I in {0..6}; do smartctl -x /dev/nvme$I -d nvme| grep -F 'Data Units Written'; done Data Units Written: 10,478,811 [5.36 TB] Data Units Written: 2,938,151 [1.50 TB] Data Units Written: 2,943,329 [1.50 TB] Data Units Written: 0 Data Units Written: 0 Data Units Written: 0 Data Units Written: 0 ``` I'f like a little guidance on writing a unittest for this (and the PR69). Should I give the smartctl -x output? --- pySMART/interface/nvme.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pySMART/interface/nvme.py b/pySMART/interface/nvme.py index cb4c28f..adaee4e 100644 --- a/pySMART/interface/nvme.py +++ b/pySMART/interface/nvme.py @@ -589,10 +589,15 @@ def parse(self, data: Iterator[str]) -> None: value.split(' ', 1)[1][1:-1].replace(',', '.')) elif name == 'Data Units Written': # Format: 1,234,567 [2.00 TB] - self.dataUnitsWritten = int( - value.split(' ')[0].replace(',', '').replace('.', '').replace('’', '')) - self.bytesWritten = humanfriendly.parse_size( - value.split(' ', 1)[1][1:-1].replace(',', '.')) + # Or : 0 + if value.isdigit(): + self.dataUnitsWritten = 0 + self.bytesWritten = 0 + else: + self.dataUnitsWritten = int( + value.split(' ')[0].replace(',', '').replace('.', '').replace('’', '')) + self.bytesWritten = humanfriendly.parse_size( + value.split(' ', 1)[1][1:-1].replace(',', '.')) elif name == 'Host Read Commands': self.hostReadCommands = int( value.replace(',', '').replace('.', '').replace('’', '')) From 8c30f37bf44ab9bd6c2f859b6e6fd4d2a9bab1da Mon Sep 17 00:00:00 2001 From: Arjen Heidinga Date: Tue, 23 May 2023 10:20:54 +0200 Subject: [PATCH 2/4] Set theactual value instead of 0 I am an idiot, sorry. --- pySMART/interface/nvme.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pySMART/interface/nvme.py b/pySMART/interface/nvme.py index adaee4e..7ce6311 100644 --- a/pySMART/interface/nvme.py +++ b/pySMART/interface/nvme.py @@ -591,8 +591,8 @@ def parse(self, data: Iterator[str]) -> None: # Format: 1,234,567 [2.00 TB] # Or : 0 if value.isdigit(): - self.dataUnitsWritten = 0 - self.bytesWritten = 0 + self.dataUnitsWritten = int(value) + self.bytesWritten = int(value) else: self.dataUnitsWritten = int( value.split(' ')[0].replace(',', '').replace('.', '').replace('’', '')) From 9d15d969189ce18be9626b9fd328845a3f263371 Mon Sep 17 00:00:00 2001 From: Rafael Leira Date: Fri, 26 May 2023 12:04:37 +0200 Subject: [PATCH 3/4] take into account that 'Data Units Read' also might be 0 --- pySMART/interface/nvme.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pySMART/interface/nvme.py b/pySMART/interface/nvme.py index 7ce6311..20ccbab 100644 --- a/pySMART/interface/nvme.py +++ b/pySMART/interface/nvme.py @@ -583,10 +583,15 @@ def parse(self, data: Iterator[str]) -> None: self.percentageUsed = int(value[:-1]) elif name == 'Data Units Read': # Format: 1,234,567 [2.00 TB] - self.dataUnitsRead = int( - value.split(' ')[0].replace(',', '').replace('.', '').replace('’', '')) - self.bytesRead = humanfriendly.parse_size( - value.split(' ', 1)[1][1:-1].replace(',', '.')) + # Or : 0 + if value.isdigit(): + self.dataUnitsRead = int(value) + self.bytesRead = int(value) + else: + self.dataUnitsRead = int( + value.split(' ')[0].replace(',', '').replace('.', '').replace('’', '')) + self.bytesRead = humanfriendly.parse_size( + value.split(' ', 1)[1][1:-1].replace(',', '.')) elif name == 'Data Units Written': # Format: 1,234,567 [2.00 TB] # Or : 0 From ace7f46c5d48e113760c9c60bca8395db25d43ca Mon Sep 17 00:00:00 2001 From: Rafael Leira Date: Fri, 26 May 2023 12:04:50 +0200 Subject: [PATCH 4/4] added some artificial tests --- .../nvme_8/_-d_nvme_--all__dev_nvme0n1 | 64 +++ tests/dataset/singletests/nvme_8/device.json | 381 ++++++++++++++++++ 2 files changed, 445 insertions(+) create mode 100644 tests/dataset/singletests/nvme_8/_-d_nvme_--all__dev_nvme0n1 create mode 100644 tests/dataset/singletests/nvme_8/device.json diff --git a/tests/dataset/singletests/nvme_8/_-d_nvme_--all__dev_nvme0n1 b/tests/dataset/singletests/nvme_8/_-d_nvme_--all__dev_nvme0n1 new file mode 100644 index 0000000..fe871a3 --- /dev/null +++ b/tests/dataset/singletests/nvme_8/_-d_nvme_--all__dev_nvme0n1 @@ -0,0 +1,64 @@ +smartctl 7.3 2022-02-28 r5338 [x86_64-linux-5.15.103] (local build) +Copyright (C) 2002-22, Bruce Allen, Christian Franke, www.smartmontools.org + +=== START OF INFORMATION SECTION === +Model Number: WDS200T1X0E-00AFY0 +Serial Number: XXXXXXXXXXXX +Firmware Version: 614600WD +PCI Vendor/Subsystem ID: 0x15b7 +IEEE OUI Identifier: 0x001b44 +Total NVM Capacity: 2’000’398’934’016 [2.00 TB] +Unallocated NVM Capacity: 0 +Controller ID: 8224 +NVMe Version: 1.4 +Number of Namespaces: 1 +Namespace 1 Size/Capacity: 2’000’398’934’016 [2.00 TB] +Namespace 1 Formatted LBA Size: 512 +Namespace 1 IEEE EUI-64: 001b44 8b451ffb99 +Local Time is: Thu Mar 23 21:15:53 2023 CET +Firmware Updates (0x14): 2 Slots, no Reset required +Optional Admin Commands (0x0017): Security Format Frmw_DL Self_Test +Optional NVM Commands (0x005f): Comp Wr_Unc DS_Mngmt Wr_Zero Sav/Sel_Feat Timestmp +Log Page Attributes (0x1e): Cmd_Eff_Lg Ext_Get_Lg Telmtry_Lg Pers_Ev_Lg +Maximum Data Transfer Size: 128 Pages +Warning Comp. Temp. Threshold: 84 Celsius +Critical Comp. Temp. Threshold: 88 Celsius +Namespace 1 Features (0x02): NA_Fields + +Supported Power States +St Op Max Active Idle RL RT WL WT Ent_Lat Ex_Lat + 0 + 9.00W 9.00W - 0 0 0 0 0 0 + 1 + 4.10W 4.10W - 0 0 0 0 0 0 + 2 + 3.50W 3.50W - 0 0 0 0 0 0 + 3 - 0.0250W - - 3 3 3 3 5000 10000 + 4 - 0.0050W - - 4 4 4 4 3900 45700 + +Supported LBA Sizes (NSID 0x1) +Id Fmt Data Metadt Rel_Perf + 0 + 512 0 2 + 1 - 4096 0 1 + +=== START OF SMART DATA SECTION === +SMART overall-health self-assessment test result: PASSED + +SMART/Health Information (NVMe Log 0x02) +Critical Warning: 0x00 +Temperature: 44 Celsius +Available Spare: 100% +Available Spare Threshold: 10% +Percentage Used: 0% +Data Units Read: 0 +Data Units Written: 0 +Host Read Commands: 0 +Host Write Commands: 0 +Controller Busy Time: 403 +Power Cycles: 25 +Power On Hours: 3’457 +Unsafe Shutdowns: 10 +Media and Data Integrity Errors: 0 +Error Information Log Entries: 0 +Warning Comp. Temperature Time: 0 +Critical Comp. Temperature Time: 0 + +Error Information (NVMe Log 0x01, 16 of 256 entries) +No Errors Logged diff --git a/tests/dataset/singletests/nvme_8/device.json b/tests/dataset/singletests/nvme_8/device.json new file mode 100644 index 0000000..add912f --- /dev/null +++ b/tests/dataset/singletests/nvme_8/device.json @@ -0,0 +1,381 @@ +{ + "name": "/dev/nvme0n1", + "interface": "nvme", + "values": { + "abridged": false, + "name": "nvme0n1", + "family": null, + "model": "WDS200T1X0E-00AFY0", + "serial": "XXXXXXXXXXXX", + "firmware": "614600WD", + "smart_capable": true, + "smart_enabled": true, + "assessment": "PASS", + "messages": [], + "is_ssd": true, + "rotation_rate": null, + "attributes": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "test_capabilities": { + "offline": false, + "short": true, + "long": true, + "conveyance": false, + "selective": false + }, + "tests": [], + "diagnostics": { + "_block_size": 512, + "Reallocated_Sector_Ct": null, + "Start_Stop_Spec": null, + "Start_Stop_Cycles": null, + "Start_Stop_Pct_Left": null, + "Load_Cycle_Spec": null, + "Load_Cycle_Count": null, + "Load_Cycle_Pct_Left": null, + "Power_On_Hours": null, + "Life_Left": null, + "Corrected_Reads": null, + "Corrected_Writes": null, + "Corrected_Verifies": null, + "_Uncorrected_Reads": null, + "_Uncorrected_Writes": null, + "_Uncorrected_Verifies": null, + "_Reads_GB": null, + "_Writes_GB": null, + "_Verifies_GB": null, + "_Reads_count": null, + "_Writes_count": null, + "_Verifies_count": null, + "Non_Medium_Errors": null, + "Reads_GB": null, + "Reads_count": null, + "Uncorrected_Reads": null, + "Uncorrected_Verifies": null, + "Uncorrected_Writes": null, + "Verifies_GB": null, + "Verifies_count": null, + "Writes_GB": null, + "Writes_count": null, + "block_size": 512 + }, + "temperature": 44, + "temperatures": {}, + "logical_sector_size": 512, + "physical_sector_size": null, + "if_attributes": { + "critialWarning": null, + "temperature": 44, + "availableSpare": 100, + "availableSpareThreshold": 10, + "percentageUsed": 0, + "dataUnitsRead": 0, + "bytesRead": 0, + "dataUnitsWritten": 0, + "bytesWritten": 0, + "hostReadCommands": 0, + "hostWriteCommands": 0, + "controllerBusyTime": 403, + "powerCycles": 25, + "powerOnHours": 3457, + "unsafeShutdowns": 10, + "integrityErrors": 0, + "errorEntries": 0, + "warningTemperatureTime": null, + "criticalTemperatureTime": 0, + "errors": [], + "tests": [], + "criticalWarning": 0 + }, + "capacity": "2.00 TB", + "dev_interface": "nvme", + "dev_reference": "/dev/nvme0n1", + "diags": { + "Reallocated_Sector_Ct": "-", + "Start_Stop_Spec": "-", + "Start_Stop_Cycles": "-", + "Start_Stop_Pct_Left": "-", + "Load_Cycle_Spec": "-", + "Load_Cycle_Count": "-", + "Load_Cycle_Pct_Left": "-", + "Power_On_Hours": "-", + "Life_Left": "-", + "Corrected_Reads": "-", + "Corrected_Writes": "-", + "Corrected_Verifies": "-", + "Uncorrected_Reads": "-", + "Uncorrected_Writes": "-", + "Uncorrected_Verifies": "-", + "Reads_GB": "-", + "Writes_GB": "-", + "Verifies_GB": "-", + "Reads_count": "-", + "Writes_count": "-", + "Verifies_count": "-", + "block_size": "512", + "Non-Medium_Errors": "-" + }, + "interface": "nvme", + "sector_size": 512, + "size": 2000398934016, + "size_raw": "2.00 TB", + "smartctl_interface": "nvme", + "vendor": "WDS" + } +} \ No newline at end of file