@cryptotaxi247 / netdata-1 / commits / 7aeb251f5

go.d smartctl: use scan-open when "no_check_power_mode" is "never" (#18146)

Ilya Mashchenko committed Jul 14, 2024 at 23:01 UTC 7aeb251f5486706c1f553da4938cb66cc93268eb
4 files changed +42 -14
src/go/plugin/go.d/modules/smartctl/exec.go
+4
@@ -33,6 +33,10 @@ func (e *smartctlCliExec) scan() (*gjson.Result, error) {
33 return e.execute("smartctl-json-scan")
34 }
35
36 +func (e *smartctlCliExec) scanOpen() (*gjson.Result, error) {
37 + return e.execute("smartctl-json-scan-open")
38 +}
39 +
40 func (e *smartctlCliExec) deviceInfo(deviceName, deviceType, powerMode string) (*gjson.Result, error) {
41 return e.execute("smartctl-json-device-info",
42 "--deviceName", deviceName,
src/go/plugin/go.d/modules/smartctl/scan.go
+33 -14
@@ -6,6 +6,8 @@ import (
6 "errors"
7 "fmt"
8 "strings"
9 +
10 + "github.com/tidwall/gjson"
11 )
12
13 type scanDevice struct {
@@ -24,7 +26,22 @@ func (s *scanDevice) shortName() string {
26 }
27
28 func (s *Smartctl) scanDevices() (map[string]*scanDevice, error) {
27 - resp, err := s.exec.scan()
29 + powerModeNever := s.NoCheckPowerMode == "never"
30 +
31 + var resp *gjson.Result
32 + var err error
33 +
34 + // Issue on Discord: https://discord.com/channels/847502280503590932/1261747175361347644/1261747175361347644
35 + // "sat" devices being identified as "scsi" with --scan, and then later
36 + // code attempts to validate the type by calling `smartctl` with the "scsi" type.
37 + // This validation can trigger unintended "Enabling discard_zeroes_data" messages in system logs (dmesg).
38 + // To address this specific issue we use `smartctl --scan-open` as a workaround.
39 + // This method reliably identifies device types.
40 + if powerModeNever {
41 + resp, err = s.exec.scanOpen()
42 + } else {
43 + resp, err = s.exec.scan()
44 + }
45 if err != nil {
46 return nil, fmt.Errorf("failed to scan devices: %v", err)
47 }
@@ -35,7 +52,7 @@ func (s *Smartctl) scanDevices() (map[string]*scanDevice, error) {
52 dev := &scanDevice{
53 name: d.Get("name").String(),
54 infoName: d.Get("info_name").String(),
38 - typ: d.Get("type").String(), // guessed type (we do '--scan' not '--scan-open')
55 + typ: d.Get("type").String(), // guessed type when using '--scan' instead of '--scan-open'
56 }
57
58 if dev.name == "" || dev.typ == "" {
@@ -48,19 +65,21 @@ func (s *Smartctl) scanDevices() (map[string]*scanDevice, error) {
65 continue
66 }
67
51 - if dev.typ == "scsi" {
52 - // `smartctl --scan` attempts to guess the device type based on the path, but this can be unreliable.
53 - // Accurate device type information is crucial because we use the `--device` option to gather data.
54 - // Using the wrong type can lead to issues.
55 - // For example, using 'scsi' for 'sat' devices prevents `smartctl` from issuing the necessary ATA commands.
56 - d := scanDevice{name: dev.name, typ: "sat"}
57 - if _, ok := s.scannedDevices[d.key()]; ok {
58 - dev.typ = "sat"
59 - } else {
60 - resp, _ := s.exec.deviceInfo(dev.name, dev.typ, s.NoCheckPowerMode)
61 - if resp != nil && isExitStatusHasBit(resp, 2) {
62 - s.Debugf("changing device '%s' type 'scsi' -> 'sat'", dev.name)
68 + if !powerModeNever {
69 + if dev.typ == "scsi" {
70 + // `smartctl --scan` attempts to guess the device type based on the path, but this can be unreliable.
71 + // Accurate device type information is crucial because we use the `--device` option to gather data.
72 + // Using the wrong type can lead to issues.
73 + // For example, using 'scsi' for 'sat' devices prevents `smartctl` from issuing the necessary ATA commands.
74 + d := scanDevice{name: dev.name, typ: "sat"}
75 + if _, ok := s.scannedDevices[d.key()]; ok {
76 dev.typ = "sat"
77 + } else {
78 + resp, _ := s.exec.deviceInfo(dev.name, dev.typ, s.NoCheckPowerMode)
79 + if resp != nil && isExitStatusHasBit(resp, 2) {
80 + s.Debugf("changing device '%s' type 'scsi' -> 'sat'", dev.name)
81 + dev.typ = "sat"
82 + }
83 }
84 }
85 }
src/go/plugin/go.d/modules/smartctl/smartctl.go
+1
@@ -83,6 +83,7 @@ type (
83 }
84 smartctlCli interface {
85 scan() (*gjson.Result, error)
86 + scanOpen() (*gjson.Result, error)
87 deviceInfo(deviceName, deviceType, powerMode string) (*gjson.Result, error)
88 }
89 )
src/go/plugin/go.d/modules/smartctl/smartctl_test.go
+4
@@ -477,6 +477,10 @@ func (m *mockSmartctlCliExec) scan() (*gjson.Result, error) {
477 return &res, nil
478 }
479
480 +func (m *mockSmartctlCliExec) scanOpen() (*gjson.Result, error) {
481 + return m.scan()
482 +}
483 +
484 func (m *mockSmartctlCliExec) deviceInfo(deviceName, deviceType, powerMode string) (*gjson.Result, error) {
485 if m.deviceDataFunc == nil {
486 return nil, nil