The TrueNAS v25 spindown patch reads /run/middleware/standby_disks using:
If the state file contains a trailing newline, for example:
the resulting list is:
['sda', 'sdc', 'sde', 'sdf', 'sdg\n']
Therefore the last disk is no longer matched correctly:
'sdg' in file.read().split(',')
# False
This causes the standby guard in DiskEntry.temp() to fail specifically for the last entry in standby_disks.
Observed behavior
On TrueNAS SCALE 25.10, five HDDs were configured with a 10-minute standby timer.
Four disks consistently entered standby while one remained active/idle.
Initially this appeared to be related to a specific HDD, /dev/sdX assignment, or SATA port. Multiple physical disk/port swaps showed that this was not the case: the affected physical disk changed.
Tracing with bpftrace finally showed recurring 512-byte device requests against the disk that would not enter standby.
Example:
14:58:08 BLOCK ... comm=python.d.plugin bytes=512 sector=0 nr_sector=0
14:59:53 BLOCK ... comm=IoThread bytes=512 sector=0 nr_sector=0
15:03:08 BLOCK ... comm=python.d.plugin bytes=512 sector=0 nr_sector=0
15:04:53 BLOCK ... comm=IoThread bytes=512 sector=0 nr_sector=0
The processes were identified as:
python.d.plugin — TrueNAS/Netdata disk-temperature collector
middlewared / IoThread — middleware disk-temperature polling
The Netdata temperature collector runs every 300 seconds.
Isolation of the device request
Individual DiskEntry properties were tested while tracing block:block_rq_issue.
The following produced no disk request:
DiskEntry.serial
DiskEntry.lunid
DiskEntry.identifier
Only:
generated the 512-byte disk request.
Before the fix:
/run/middleware/standby_disks:
'sda,sdc,sde,sdf,sdg\n'
sdg present: False
DiskEntry(name="sdg", devpath="/dev/sdg").temp()
→ TempEntry(temp_c=41.0, crit=70.0)
This means the standby guard was not triggered and temp1_input was read through the drivetemp kernel driver.
That temperature read issues a command to the HDD and resets/restarts the ATA idle timer before the configured standby timeout can expire.
Root cause
Two locations in spindown-v25.patch parse the file without removing trailing whitespace:
The final element therefore retains the newline.
This also explains why the problem appeared to move between disks after /dev/sdX assignments changed: it followed the final entry in standby_disks, not a specific physical HDD or SATA port.
Proposed fix
In middlewared/utils/disks_/disk_class.py:
- if self.name in file.read().split(','):
+ if self.name in file.read().strip().split(','):
And in middlewared/plugins/disk.py:
- disk_list = file.read().split(',')
+ disk_list = file.read().strip().split(',')
A more defensive alternative would be:
[x.strip() for x in file.read().split(',') if x.strip()]
although .strip().split(',') is sufficient for the observed state-file format.
Verification
After changing both reads to:
file.read().strip().split(',')
the same direct temperature test returned:
TempEntry(temp_c=None, crit=None)
and the block_rq_issue trace remained completely empty.
Finally, all five HDDs were tested simultaneously with a 10-minute ATA standby timer.
Result after approximately 11 minutes:
sdg drive state is: standby
sde drive state is: standby
sdf drive state is: standby
sdc drive state is: standby
sda drive state is: standby
So the change reproducibly fixes the spindown failure.
Environment
- TrueNAS SCALE 25.10
- Native TrueNAS HDD standby: 10 minutes
TrueNAS-Tricks v25 spindown patch
- Multiple SATA HDDs
- Verified using
bpftrace on block:block_rq_issue
The TrueNAS v25 spindown patch reads
/run/middleware/standby_disksusing:If the state file contains a trailing newline, for example:
the resulting list is:
Therefore the last disk is no longer matched correctly:
This causes the standby guard in
DiskEntry.temp()to fail specifically for the last entry instandby_disks.Observed behavior
On TrueNAS SCALE 25.10, five HDDs were configured with a 10-minute standby timer.
Four disks consistently entered standby while one remained
active/idle.Initially this appeared to be related to a specific HDD,
/dev/sdXassignment, or SATA port. Multiple physical disk/port swaps showed that this was not the case: the affected physical disk changed.Tracing with
bpftracefinally showed recurring 512-byte device requests against the disk that would not enter standby.Example:
The processes were identified as:
python.d.plugin— TrueNAS/Netdata disk-temperature collectormiddlewared/IoThread— middleware disk-temperature pollingThe Netdata temperature collector runs every 300 seconds.
Isolation of the device request
Individual
DiskEntryproperties were tested while tracingblock:block_rq_issue.The following produced no disk request:
Only:
generated the 512-byte disk request.
Before the fix:
This means the standby guard was not triggered and
temp1_inputwas read through thedrivetempkernel driver.That temperature read issues a command to the HDD and resets/restarts the ATA idle timer before the configured standby timeout can expire.
Root cause
Two locations in
spindown-v25.patchparse the file without removing trailing whitespace:The final element therefore retains the newline.
This also explains why the problem appeared to move between disks after
/dev/sdXassignments changed: it followed the final entry instandby_disks, not a specific physical HDD or SATA port.Proposed fix
In
middlewared/utils/disks_/disk_class.py:And in
middlewared/plugins/disk.py:A more defensive alternative would be:
although
.strip().split(',')is sufficient for the observed state-file format.Verification
After changing both reads to:
the same direct temperature test returned:
and the
block_rq_issuetrace remained completely empty.Finally, all five HDDs were tested simultaneously with a 10-minute ATA standby timer.
Result after approximately 11 minutes:
So the change reproducibly fixes the spindown failure.
Environment
TrueNAS-Tricksv25 spindown patchbpftraceonblock:block_rq_issue