learn/CompTIA Linux+

Hardware and kernel issues

The logs mention a device you have never heard of

Lesson 70 of 76·Deep dive·22 min read·updated ·linuxlinux-plustroubleshootinghardwarekernel

On the examCompTIA Linux+ XK0-006 (V8)

  • 5.2Given a scenario, analyze and troubleshoot hardware, storage, and Linux OS issues.Domain 5.0 Troubleshooting·22% of the exam

All 29 objectives, and which are covered

Before this

What you will be able to do

  • Read dmesg for hardware errors and say which layer reported them
  • Decide whether a fault is hardware or software
  • Check a disk's own opinion of its health with SMART
  • Explain what a tainted kernel means and why support asks
  • Recognise memory errors, and know what ECC does and does not do

Before you read. The kernel log has three lines in it about dm-0, a device nobody configured, and the application is throwing errors that mention nothing of the sort.

Somewhere below the software there is a piece of hardware, or something pretending to be one, and it has stopped cooperating.

Hardware problems are the ones people reach for last, which is usually correct because they are the least common. When they do occur they are unmistakable if you know the vocabulary, and baffling if you do not, because the kernel names devices and layers rather than the applications you recognise.

This lesson is about reading those messages, and about the harder judgement underneath: deciding whether the hardware is genuinely at fault before somebody spends a day replacing a healthy disk.

Some words you will need

ring buffer
The kernel's in-memory log. What dmesg prints.
block layer
The kernel between filesystems and storage drivers. Reports as blk_update_request.
SMART
Self-monitoring built into drives. The disk's own view of its health.
taint
A flag recording that something happened which makes the kernel's behaviour unsupportable.
MCE
Machine check exception. The CPU reporting a hardware error to the operating system.
ECC
Memory that detects and corrects single-bit errors, and reports them.
device-mapper
The kernel layer behind LVM, encryption, and RAID. Its devices appear as dm-N.

What breaks without this

Healthy hardware gets replaced. A driver problem or a cable produces identical symptoms to a failing disk, and the disk is what gets swapped.

Failing hardware gets ignored. Correctable errors are logged for weeks before the uncorrectable one, and nobody was reading the log.

Data is written to a dying disk. Every repair attempt and every retry makes recovery less likely.

Support declines the case. A tainted kernel means the vendor cannot reproduce your configuration, and that is the first thing they check.

The wrong layer is blamed. An application error about a file is the last link in a chain that started at the controller.

What a real I/O error looks like

Rather than describing one, here is a device built to fail. Device-mapper has an error target that returns a failure for every read, which produces the genuine article without harming anything.

A block device is created whose every read fails. What does dd report, and what does the kernel log?
# Fedora CoreOS 44.20260707.3.1 on a virtual machine, aarch64
$ sudo dmsetup remove faultydisk 2>/dev/null
echo "--- a block device whose every read fails, built with device-mapper ---"
sudo dmsetup create faultydisk --table "0 2048 error"
sudo dd if=/dev/mapper/faultydisk of=/dev/null bs=512 count=1 2>&1 | tail -3
echo "--- what the kernel logged about it ---"
sudo dmesg | tail -3
sudo dmsetup remove faultydisk
--- a block device whose every read fails, built with device-mapper ---
0+0 records in
0+0 records out
0 bytes copied, 8.8084e-05 s, 0.0 kB/s
--- what the kernel logged about it ---
[30718.870606] Buffer I/O error on dev dm-0, logical block 0, async page read
[30718.870633] Buffer I/O error on dev dm-0, logical block 0, async page read
[30718.882536] Buffer I/O error on dev dm-0, logical block 0, async page read

Look at what dd said: 0 bytes copied, no error text of its own worth reading. The tool that failed is nearly silent. The kernel is where the explanation is.

Buffer I/O error on dev dm-0, logical block 0 names three things: the layer that noticed, the device, and the exact block. That precision is the point of reading dmesg rather than application logs.

Learn the shape of these messages, because the prefix tells you the layer:

Message begins Layer Suggests
Buffer I/O error on dev Block layer, buffered read path The device below returned a failure
blk_update_request: I/O error, dev sda, sector N Block layer The most common real disk error. Note the sector
critical medium error SCSI The drive could not read that physical area. Genuine media failure
ata1.00: failed command: ATA driver Often cabling or a controller, not always the drive
EXT4-fs error (device sda1) Filesystem Filesystem noticed inconsistency. May be caused by the layer below
nvme nvme0: I/O N QID N timeout NVMe driver Device stopped responding. Firmware, thermal, or power
Machine check events logged CPU Hardware error the processor detected. Take seriously

The distinction that matters most is between a device that returned an error and a device that stopped answering. An error means the hardware is working well enough to say no. A timeout means it stopped responding entirely, which is more often a controller, a cable, power, or firmware than the media itself.

And dm-0 deserves a note, because it is the name people find least helpful. Device-mapper numbers its devices, so the message tells you nothing about which volume it is. Translate it:

sudo dmsetup ls                    # names against dm-N
lsblk                              # the whole tree, names included
ls -l /dev/mapper/                 # symlinks pointing at dm-N

Present but not working

Three separate things that all have to be true for a device to work Hardware faults are easier to reason about when the three conditions are kept apart. The device may or may not be electrically present and enumerated on its bus, which lspci and lsusb answer. A driver may or may not have been bound to it, which the kernel messages answer. Firmware the driver asked for may or may not have loaded, which is a separate failure again and one that leaves a device present, claimed, and useless. A device can pass the first two and still do nothing. enumerated lspci, lsusb a driver bound to it dmesg, lsmod firmware loaded the one people forget all three have to be true, and they fail independently a device can be present and claimed and still do nothing at all which is why lspci showing it is not the end of the check
Three conditions that fail independently, and the third is the one that gets skipped. A card that is enumerated and has its driver bound looks correct in every command people usually run, and does nothing whatsoever because the firmware blob the driver asked for was not on the filesystem.

The other family of hardware faults is the device that exists and does nothing, and the diagnostic question is whether the kernel found it, bound a driver to it, and brought it up. Those are three separate steps.

# Fedora CoreOS 44.20260707.3.1 on a virtual machine, aarch64
$ echo "--- what the kernel found on the PCI bus ---"; lspci 2>/dev/null | head -5 || echo "(no lspci on this image)"; echo "--- memory the firmware handed over ---"; sudo dmesg | grep -iE "Memory:|efi:" | head -3
--- what the kernel found on the PCI bus ---
00:00.0 Host bridge: Apple Inc. Device 1a05
00:01.0 Ethernet controller: Red Hat, Inc. Virtio 1.0 network device (rev 01)
00:05.0 Communication controller: Red Hat, Inc. Virtio 1.0 console (rev 01)
00:06.0 Mass storage controller: Red Hat, Inc. Virtio 1.0 block device (rev 01)
00:07.0 Mass storage controller: Red Hat, Inc. Virtio 1.0 file system (rev 01)
--- memory the firmware handed over ---

Five devices, and the mixture is worth noticing: an Apple host bridge because this is a virtual machine on Apple hardware, and Red Hat virtio devices for everything the hypervisor provides. On a physical server the same command lists real controllers and network cards.

lspci listing a device proves only that the bus enumerated it. The next question is whether a driver claimed it, and -k answers that:

lspci -k                    # each device with its kernel driver, if any
lspci -nn                   # with numeric vendor:device IDs, for searching

A device with no Kernel driver in use line is the classic “present but not working” case. It means the hardware is fine and the software to operate it is missing, which is a firmware package, a missing module, or a kernel too old for the part.

The sequence to work through:

Question Command
Did the bus find it? lspci, lsusb, lsblk
Did a driver bind to it? lspci -k, lsmod
Did the driver complain? dmesg | grep -i <driver>
Is firmware missing? dmesg | grep -i firmware
Is the interface up? ip link, per lesson 71

Missing firmware is worth calling out because the message is explicit and people still miss it. Many network and graphics devices need a binary blob loaded at initialisation, and dmesg will say Direct firmware load for ... failed with error -2. The device then exists and does nothing. The fix is a package, usually linux-firmware, and no amount of hardware replacement helps.

If you already administer Linux: asking the disk what it thinks, and reading the answer properly

Drives run continuous self-monitoring and will tell you what they have seen, if you ask. smartctl from smartmontools is how.

sudo smartctl -H /dev/sda           # overall pass or fail
sudo smartctl -a /dev/sda           # every attribute
sudo smartctl -l error /dev/sda     # the drive's own error log
sudo smartctl -t short /dev/sda     # start a self test, minutes
sudo smartctl -l selftest /dev/sda  # results

The overall health line is nearly useless on its own. It reports PASSED right up until a threshold is crossed, and drives routinely fail while passing. Read the attributes.

The attributes that actually predict failure, from published large-scale studies of drive populations:

Attribute Meaning
Reallocated_Sector_Ct Sectors found bad and remapped to spares. Any non-zero value is a warning; a rising one is a decision
Current_Pending_Sector Sectors that failed to read and are awaiting reallocation. Worse than reallocated, because data may be at risk now
Offline_Uncorrectable Could not be read or corrected at all
Reported_Uncorrect Errors the drive could not fix
UDMA_CRC_Error_Count Interface errors, which usually means a cable, not the drive

That last row saves whole afternoons. A drive throwing CRC errors is very often sitting on a bad SATA cable or a loose connector, and replacing the drive achieves nothing.

Rate of change matters more than absolute value. Five reallocated sectors that have been five for two years is a drive with a small manufacturing defect. Five that were zero last week is a drive to replace now. This is the argument for recording SMART attributes as metrics, per lesson 64, rather than reading them during an incident.

For NVMe the vocabulary changes and the tool is the same:

sudo smartctl -a /dev/nvme0        # or: sudo nvme smart-log /dev/nvme0

Watch percentage_used, which is the drive’s estimate of endurance consumed, media_errors, and critical_warning. NVMe drives also throttle when hot, so a suddenly slow NVMe with a high temperature is a cooling problem rather than a failing one.

Enable the daemon rather than checking by hand. smartd runs the tests on a schedule and alerts, which is the difference between finding out at 2am and finding out on a Tuesday afternoon.

A caution about virtual and network-attached disks. SMART passes through to real hardware, and a virtio disk, an iSCSI LUN, or a cloud volume has no SMART data to give you. smartctl on the VM used for these captures reports that the command does not exist, because the abstraction has no drive underneath it from the guest’s point of view. On those, health is the hypervisor’s or the provider’s to report, and asking the guest is the wrong question.

If you already administer Linux: what to do while the disk is still dying

Deciding a drive is failing is the easy half. What you do in the next hour decides how much data survives, and the instinct most people have is the wrong one.

Stop writing to it. Every write, every filesystem repair, and every retry consumes remaining life and can overwrite the sectors you were hoping to recover. Mount it read-only if it must stay mounted:

sudo mount -o remount,ro /mnt/data

Image before repairing. fsck on a failing device is the combination most likely to turn recoverable data into unrecoverable data, per lesson 67. Copy first, then work on the copy:

sudo ddrescue -f -n /dev/sdb /dev/sdc /var/tmp/rescue.map     # fast pass, skip errors
sudo ddrescue -d -f -r3 /dev/sdb /dev/sdc /var/tmp/rescue.map # retry the gaps

ddrescue rather than dd, and the reason is the map file. dd stops or stalls on the first bad sector and has no memory of where it got to. ddrescue copies everything readable first, records what it missed, and only then goes back for the difficult parts, so you get the maximum readable data in the minimum time on the drive. Interrupt it and it resumes from the map.

The order that gets the most data back:

  1. Stop writes. Unmount, or remount read-only.
  2. If the array is redundant, do not rebuild yet. A rebuild reads every sector of every remaining disk, which is exactly the workload most likely to kill a second marginal one. Back up first, per lesson 15.
  3. Image with ddrescue onto a healthy device.
  4. Verify the image mounts read-only.
  5. Repair the copy, never the original.
  6. Replace the hardware.

Two things that make the drive worse while you work: heat, and time spent spinning. Copy at a sensible speed rather than hammering it, and if the drive is audibly failing or repeatedly resetting, stop and consider whether the data is worth a professional recovery service. That decision belongs to whoever owns the data, not to whoever is holding the screwdriver.

And check the array’s own view before touching anything, because “one disk failed” and “the array is already degraded and this is the second” are very different situations:

cat /proc/mdstat                # software RAID
sudo mdadm --detail /dev/md0    # per-device state

Taint

The kernel keeps a flag recording whether anything has happened that makes its behaviour hard to reason about.

A machine that has loaded no proprietary modules and has never crashed is asked whether it is tainted. What number comes back?
# Fedora CoreOS 44.20260707.3.1 on a virtual machine, aarch64
$ echo "--- is the kernel tainted, and by what ---"; cat /proc/sys/kernel/tainted; echo "--- CPU, as the kernel sees it ---"; lscpu | grep -E "^(Architecture|CPU\(s\)|Model name|Vendor ID|Hypervisor)" 2>/dev/null
--- is the kernel tainted, and by what ---
0
--- CPU, as the kernel sees it ---
Architecture:                            aarch64
CPU(s):                                  5
Vendor ID:                               Apple
Model name:                              -

Zero, which is what a clean kernel reports. The value is a bitmask, so anything non-zero needs decoding:

cat /proc/sys/kernel/tainted                                    # the number
sudo dmesg | grep -i taint                                      # why, in words

The bits worth recognising:

Bit Value Means
0 1 A proprietary module was loaded
1 2 A module was force-loaded
4 16 A machine check exception occurred. Hardware error
5 32 A bad page was found. Memory problem
7 128 The kernel died previously, an oops or panic
9 512 A kernel warning was issued
12 4096 An out-of-tree module was loaded

Bits 4, 5, and 7 are the ones that matter for this lesson, because they are the kernel recording that something genuinely went wrong rather than that you installed a driver.

Why anybody cares: taint is the first thing a vendor’s support process checks. A kernel running a proprietary or out-of-tree module is not the kernel they ship, so they cannot reproduce your problem and will usually ask you to remove it before continuing. That is a reasonable position and it is worth knowing before you open the case rather than after.

If you already administer Linux: memory errors, and deciding hardware against software

Memory faults are the hardest of these to attribute, because bad memory corrupts whatever happens to be using it. The symptom is whichever program was unlucky, so it looks like a different software bug every time.

With ECC memory the machine tells you. Single-bit errors are corrected transparently and logged, and that log is an early warning worth acting on:

sudo edac-util -v                          # per-DIMM correctable and uncorrectable
sudo ras-mc-ctl --summary                  # if rasdaemon is running
sudo dmesg | grep -iE 'EDAC|Machine check|mce|Hardware Error'
sudo mcelog --client                       # on older systems

Correctable errors are the useful signal. ECC fixes them, nothing breaks, and a DIMM producing them at a rising rate is going to produce an uncorrectable one eventually. Replacing a module on the strength of correctable errors is cheap; discovering the problem through an uncorrectable one is a crash.

Without ECC you get no warning at all, which is the whole argument for it on anything that matters. A desktop with failing memory produces random segmentation faults in unrelated programs, filesystem corruption, and builds that fail differently each time. memtest86+ from boot media is the test, and it needs hours rather than minutes to be meaningful.

Machine check exceptions are the CPU reporting a hardware error directly. Machine check events logged in dmesg is never noise. Decode them with mcelog or rasdaemon, and treat repeated ones as a reason to move the workload off that machine.

The judgement: is this hardware or software? These lean hardware:

  • Errors that follow the machine rather than the workload. Move the job elsewhere and it is fine.
  • Multiple unrelated programs failing in unrelated ways.
  • Errors correlated with temperature, load, or time since power-on.
  • Anything in dmesg from a driver, the block layer, or EDAC.
  • Corruption that survives a reinstall.

And these lean software:

  • Reproducible on identical hardware elsewhere.
  • Started exactly when something was deployed or updated, per lesson 63.
  • Only one application affected, everything else healthy.
  • Clean dmesg. This is the strongest single signal. Genuine hardware problems almost always leave a trace in the kernel log, so a completely quiet dmesg is good evidence that the fault is above the kernel.

The cheapest discriminating test is to move the workload. If it follows the application to a different machine, it is software. If it stays with the machine, it is hardware. That is one afternoon and it settles arguments that otherwise run for weeks.

Across distributions

The kernel reports faults identically everywhere, because it is the same kernel. What varies is whether the tools to read those reports are installed and whether the firmware the hardware needs shipped with the system at all.

RHEL family Debian family
Kernel log dmesg, journalctl -k identical
SMART tools smartmontools, install it smartmontools, install it
PCI and USB inventory pciutils, usbutils identical package names
Non-free device firmware linux-firmware, installed by default firmware-linux-nonfree and friends, often not
Sensor readings lm_sensors lm-sensors, note the hyphen
Hardware inventory dmidecode, lshw identical
Taint flag reference /proc/sys/kernel/tainted identical

The firmware row is the one that produces a mystery. Debian split non-free firmware out of the default install for years on licensing grounds, so a network card or a GPU that works immediately on a RHEL machine comes up dead on a Debian one with Direct firmware load for ... failed with error -2 in dmesg. The hardware is fine, the driver is loaded, and the blob it wants to push into the device is simply not on the disk. Recent Debian installers offer to include it, which means you will meet both behaviours depending on how the machine was built.

smartmontools being absent by default on both families is worth knowing before you need it, because the moment you want SMART attributes is usually the moment the machine is misbehaving and you would rather not be installing packages onto it.

Prove it

Hardware faults appear in the kernel log and essentially nowhere else, so this is a short list:

# The kernel's own account, most recent last
sudo dmesg -T | tail -50
sudo journalctl -k -p err -b

# Did the kernel see the device, and did a driver bind to it
lspci -k | grep -A3 -i <device>
lsusb

# Is a firmware blob missing
sudo dmesg | grep -i firmware

# Storage health, on real disks only
sudo smartctl -H /dev/sda
sudo smartctl -A /dev/sda | grep -iE "reallocated|pending|uncorrect|crc"

# Has anything compromised the kernel's supportability
cat /proc/sys/kernel/tainted

A clean dmesg is a real result. Hardware that is genuinely failing is loud: resets, timeouts, medium errors, correctable ECC counts climbing. A machine behaving badly with nothing in the kernel log is evidence that the fault is above the hardware, and ruling out a whole layer in one command is worth doing early rather than after an afternoon of guessing.

What trips people up

1. Reading a PASSED health check as a healthy drive

The overall health line is one threshold test the firmware performs, and it stays at PASSED until an attribute crosses the vendor’s own limit. Reallocated_Sector_Ct and Current_Pending_Sector can be climbing steadily, with real read failures reaching the kernel, while that summary still says PASSED. Read the attributes and their trend.

2. Expecting SMART data from a virtual disk

A cloud volume or a hypervisor-provided disk has no SMART to report, so smartctl returns nothing useful and that says nothing about the underlying hardware, which belongs to somebody else. The equivalent evidence is I/O errors in dmesg and whatever the provider’s own status page offers.

3. Treating an error and a timeout as the same fault

A device that returns an error is answering: it received the request, tried, and failed, which points at the media. A device that times out has stopped responding, which points at the controller, the cable, or power. The second is more often something other than the disk itself.

4. Blaming the drive when the counter says cable

UDMA_CRC_Error_Count records corruption on the link between the controller and the drive, not on the platters. It climbs with a bad cable, a loose connector, or a backplane problem, and replacing a perfectly good disk leaves it climbing on the new one.

5. Assuming a listed device has a working driver

lspci shows what the bus enumerated, which is a question about the hardware being present. lspci -k shows whether a kernel module claimed it. A device listed with no Kernel driver in use line is visible and unusable, and the cause is a missing module or missing firmware rather than a fault.

6. Ignoring correctable ECC errors

By definition they were corrected, so nothing broke and it is tempting to move on. A rising rate of correctable errors on one DIMM is the standard warning that it is going to produce an uncorrectable one, which is the sort that takes the machine down without a log entry explaining why.

Work it through

A database server has been slow for two days and the application team reports occasional query timeouts. Nothing changed. top shows low CPU and the load average is high.

Reason it out before reading on.

Ask the kernel before asking anything else. High load with idle CPU means processes blocked rather than computing, and blocked usually means storage:

sudo dmesg -T | tail -50

Say it contains repeated lines like blk_update_request: I/O error, dev sda, sector 1234567 op 0x0:(READ) alongside ata1.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x6 frozen.

The device is answering badly rather than not answering. The device is returning errors and the link is being reset, which is the hardware answering badly rather than not answering. Each reset stalls every request in flight, which is exactly what produces intermittent timeouts on an otherwise idle machine.

Get the drive’s own account of itself:

sudo smartctl -H /dev/sda
sudo smartctl -A /dev/sda | grep -iE "reallocated|pending|crc"

Two readings, two different conclusions. Current_Pending_Sector climbing means the media is failing and the drive should be replaced. UDMA_CRC_Error_Count climbing with the other attributes flat means the link is at fault, so reseat or replace the cable before condemning a healthy disk.

PASSED is not where to stop. If the health line says PASSED and the attributes are climbing, the attributes win. The threshold has not been crossed yet, and the trend is what tells you when it will be.

The general lesson is about which layer to interrogate first. The report was about query timeouts, and nothing about the diagnosis went near the database. The load average being high while the CPU was idle pointed one layer down, and one dmesg decided it.

Try it

Optional, and most of it is read-only, so it is safe on a machine you care about.

  1. Run sudo dmesg -T | less on a machine that has been up for a while and read it from the top. The boot-time hardware enumeration is the best free tour of what the kernel thinks the machine is.
  2. Run lspci -k and find a device with no Kernel driver in use line. On a VM there is usually at least one. Work out whether that matters.
  3. Run sudo smartctl -A on a real disk and write down Reallocated_Sector_Ct, Current_Pending_Sector, and UDMA_CRC_Error_Count. That is your baseline, and the numbers mean nothing without one. On a VM, confirm what the command says instead and why.
  4. Read /proc/sys/kernel/tainted. If it is not zero, decode it against the kernel documentation and work out which module did it.

Verification step. Step 3 is complete when you can say what those three numbers were and, more usefully, where you wrote them down. A SMART attribute read once during an incident is nearly useless, because the question is always whether it is rising.

For the exam

dmesg and journalctl -k are where hardware errors appear, not in application logs.

blk_update_request: I/O error names the device and sector. Media problems are critical medium error.

A device that returns an error is answering; a device that times out has stopped. The second is more often the controller, cable, or power.

lspci shows enumeration, lspci -k shows whether a driver bound. No driver means missing module or firmware.

Direct firmware load ... failed means a missing firmware package, usually linux-firmware.

SMART: Reallocated_Sector_Ct and Current_Pending_Sector predict failure. UDMA_CRC_Error_Count means the cable.

A PASSED health check does not mean a healthy drive. Read the attributes.

Virtual and network-attached disks have no SMART data.

A tainted kernel is recorded in /proc/sys/kernel/tainted, and vendors check it before accepting a support case.

ECC corrects and logs single-bit errors. Correctable errors rising is the warning to act on.

A completely clean dmesg is evidence against a hardware fault.

Check yourself

An application reports a read failure and its own log says almost nothing. Where do you look? dmesg or journalctl -k. The kernel names the layer, the device, and the block; the tool above it often just reports zero bytes.

What does Buffer I/O error on dev dm-0, logical block 0 tell you? The block layer failed a read, on a device-mapper device, at a specific block. dmsetup ls or lsblk translates dm-0 into a name you recognise.

Difference between a device returning an I/O error and a device timing out? An error means it is working well enough to refuse. A timeout means it stopped responding, which points more often at the controller, cable, power, or firmware than at the media.

A device appears in lspci and nothing works. What next? lspci -k to see whether a driver bound. No driver means a missing module or missing firmware, not broken hardware.

Direct firmware load for ... failed with error -2. What is the fix? Install the firmware package, usually linux-firmware. Replacing hardware will not help.

Which SMART attribute usually means a cable rather than a drive? UDMA_CRC_Error_Count.

SMART reports PASSED. Is the drive healthy? Not necessarily. The overall verdict stays PASSED until a threshold is crossed. Read Reallocated_Sector_Ct and Current_Pending_Sector, and watch their rate of change.

Which is more urgent, reallocated sectors or pending sectors? Pending. Those are sectors that failed to read and have not been remapped yet, so data may be at risk now.

smartctl returns nothing useful on a cloud volume. Why? There is no physical drive from the guest’s point of view. Health for that storage is the provider’s to report.

What does a non-zero /proc/sys/kernel/tainted mean, and who cares? Something happened that makes kernel behaviour hard to support: a proprietary module, a forced module load, a previous oops, a machine check. Vendor support checks it first.

Which taint bits indicate genuine hardware trouble? Bit 4 (machine check exception) and bit 5 (bad page). Bit 7 records a previous oops or panic.

Programs crash randomly and differently each time, with no pattern. What do you suspect? Memory. With ECC, check edac-util for correctable errors. Without ECC, run memtest86+ for hours.

What does ECC give you that non-ECC does not? It corrects single-bit errors and, more usefully, logs them, so a failing module announces itself before it causes a crash.

One test to decide hardware against software? Move the workload to another machine. If the fault follows the workload it is software; if it stays with the machine it is hardware.

Where this sits

Lesson 10 covered the kernel and its modules, and lesson 11 covered device discovery. This lesson is the same territory when something has gone wrong. Lesson 67 handles the filesystem sitting on top of a failing device, and lesson 76 covers a disk that is slow rather than broken, which is a different investigation with a different answer.

References

The commands here were run on a real machine, not written from memory. The transcripts come from Fedora CoreOS 44.20260707.3.1 on aarch64. The I/O errors are genuine kernel messages, produced by building a device-mapper error target so that every read really did fail, and the device was removed in the same command that created it. The lspci listing shows an Apple host bridge beside Red Hat virtio devices because that is what this virtual machine actually is. smartctl is not installed on that image, which is the reason the SMART section carries no transcript and says so.