sensors: take a SAS drive's standby, whose mode holds spaces
The third review found the asleep match took only one-word modes, so a SAS drive in STANDBY BY TIMER or LOW POWER was read as a failed answer and lost its reading.
This commit is contained in:
@@ -49,13 +49,16 @@ another process, and go on whatever the drives do.
|
||||
- `-n standby,2,3` makes smartctl stop with status 2 when the drive is in standby or asleep. The drive
|
||||
reader then keeps the reading before, and since when the drive has been asleep. A drive counts as asleep
|
||||
on status 2 with either an ATA power mode of STANDBY or SLEEP, or smartctl's own words "Device is in
|
||||
<mode> mode, exit(2)" (a SAS drive, or one the operating system powered down). An open failure is
|
||||
neither, whatever its words.
|
||||
<mode> mode, exit(2)" (a SAS drive, whose modes hold spaces such as STANDBY BY TIMER or LOW POWER, or
|
||||
one the operating system powered down). An open failure is neither, whatever its words.
|
||||
- It stops with status 3 when the drive cannot say (a USB bridge that does not pass CHECK POWER MODE on).
|
||||
Such a drive is not read, and is said as not read.
|
||||
- smartctl is told the drive's kind (`-d nvme`, `-d sat` for an ATA drive or one behind USB, `-d scsi`)
|
||||
so it does not probe. A drive of a kind the module cannot tell (virtio, MMC) is read with smartctl's own
|
||||
detection.
|
||||
- smartctl is told the drive's kind (`-d nvme`, `-d sat` for an ATA drive or any drive behind USB,
|
||||
`-d scsi`) so it does not probe. A drive behind a USB-to-NVMe enclosure or a vendor's own bridge does not
|
||||
answer to `sat`, and is said as not read. A drive of a kind the module cannot tell (virtio, MMC) is read
|
||||
with smartctl's own detection.
|
||||
- Known limits: a smartctl stuck in the kernel outlives the drive reader, and a restarted reader starts a
|
||||
new read beside it; all drives are read at once, with no cap per controller or bridge.
|
||||
- Reading SMART from an awake drive can restart its standby timer, so a drive read more often than its
|
||||
timer is set for never spins down. No mesh tool reads a drive's standby timer, so whether the servers'
|
||||
drives spin down is not known. A spinning drive is therefore read once an hour, timed from its last
|
||||
|
||||
@@ -540,7 +540,10 @@ func asleep(s smartJSON) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
var sleepWords = regexp.MustCompile(`^Device is in [A-Z_]+( \(OS\))? mode, exit\(2\)$`)
|
||||
// sleepWords are smartctl's words when -n standby stopped it: an ATA mode (STANDBY, SLEEP), a SAS mode,
|
||||
// which holds spaces (STANDBY BY TIMER, STANDBY_Y BY COMMAND, LOW POWER), or STANDBY (OS). An idle mode
|
||||
// never stops smartctl under -n standby, so it never appears here.
|
||||
var sleepWords = regexp.MustCompile(`^Device is in [A-Z_]+( [A-Z_]+)*( \(OS\))? mode, exit\(2\)$`)
|
||||
|
||||
func saysNoPowerMode(s smartJSON) bool {
|
||||
for _, msg := range s.Smartctl.Messages {
|
||||
|
||||
@@ -103,18 +103,22 @@ func TestABoardChipsOwnSensorDoesNotStopItsFanAndACPUSensorDoes(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// D: a SAS drive in standby says so in words and no ATA power mode; status 2 with those words is asleep.
|
||||
// D: a SAS drive in standby says so in words and no ATA power mode, and its modes hold spaces
|
||||
// (scsiprint.cpp of smartmontools 7.5); status 2 with those words is asleep. An idle mode never stops
|
||||
// smartctl under -n standby, so it never says so.
|
||||
func TestASASDriveInStandbyIsAsleep(t *testing.T) {
|
||||
f := newFake(t)
|
||||
f.drive("sdm", "ST4000NM0023", "SEAGATE ", 100, true)
|
||||
d := f.machine().BlockDrives()[0]
|
||||
sas := `{"smartctl":{"messages":[{"string":"Device is in STANDBY mode, exit(2)","severity":"information"}],"exit_status":2},` +
|
||||
`"device":{"name":"/dev/sdm","type":"scsi","protocol":"SCSI"}}`
|
||||
f.answers[smartctlLine("sdm", "scsi")] = Ran{Stdout: sas, Status: 2}
|
||||
before := DriveReading{ReadAt: f.now.Add(-time.Hour), Smartctl: []byte(ataPassed)}
|
||||
got := f.machine().ReadDrive(d, &before)
|
||||
if !got.Asleep || string(got.Smartctl) != ataPassed || got.AsleepSince == nil {
|
||||
t.Errorf("a SAS drive in standby keeps its reading: %+v", got)
|
||||
for _, mode := range []string{"STANDBY BY TIMER", "STANDBY BY COMMAND", "STANDBY_Y BY TIMER", "STANDBY_Y BY COMMAND", "LOW POWER", "SLEEP"} {
|
||||
f := newFake(t)
|
||||
f.drive("sdm", "ST4000NM0023", "SEAGATE ", 100, true)
|
||||
d := f.machine().BlockDrives()[0]
|
||||
sas := `{"smartctl":{"messages":[{"string":"Device is in ` + mode + ` mode, exit(2)","severity":"information"}],"exit_status":2},` +
|
||||
`"device":{"name":"/dev/sdm","type":"scsi","protocol":"SCSI"}}`
|
||||
f.answers[smartctlLine("sdm", "scsi")] = Ran{Stdout: sas, Status: 2}
|
||||
before := DriveReading{ReadAt: f.now.Add(-time.Hour), Smartctl: []byte(ataPassed)}
|
||||
got := f.machine().ReadDrive(d, &before)
|
||||
if !got.Asleep || string(got.Smartctl) != ataPassed || got.AsleepSince == nil {
|
||||
t.Errorf("a SAS drive in %s keeps its reading: %+v", mode, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user