You ran ls, cp, or opened a file and got something like Input/output error, or Buffer I/O error on dev sda1, logical block 1234567, async page read in dmesg. That's the kernel saying: I asked the disk for a sector and the disk didn't give it to me. The disk either couldn't read it, the controller dropped the request, or the cable is flaking out.
The reason this is scary and not just annoying: on spinning rust and flash alike, an I/O error is almost never a software bug. It's a hardware-level signal. Treat it that way until you've proven otherwise.
Step 1: The 30-Second Sanity Check
Run this before you do anything else:
dmesg | tail -50
Look for lines containing ata, sd, nvme, EXT4-fs error, or Buffer I/O error. The kernel usually names the device (sda, nvme0n1, sdb) and the sector. Write those down.
Then check whether the filesystem is simply remounted read-only:
mount | grep ro,
cat /proc/mounts | awk '$4 ~ /ro/ {print $2}'
If your root or home is now ro, that's the kernel protecting you. It hit enough errors that it gave up writing. You can remount read-write once, briefly, with:
sudo mount -o remount,rw /
Don't make a habit of it. If remounting rw works and everything's fine, you probably had a transient USB disconnect or a SATA cable that wiggled loose. If errors come back within a minute, go to step 2.
If this is a USB stick or a USB-SATA enclosure on a laptop running Ubuntu 22.04 or Debian 12, unplug it, wait 10 seconds, and try a different port. USB autosuspend has caused more phantom I/O errors than I care to count. Add usbcore.autosuspend=-1 to your kernel cmdline if it keeps happening.
Step 2: The 5-Minute Fix — Check the Filesystem
If the device is still readable but the filesystem is complaining, unmount it and run fsck. Not on a mounted filesystem. Ever. Mounted fsck corrupts more data than the original error did.
sudo umount /dev/sda1
sudo fsck -f -y /dev/sda1
For ext4, add -c if you want a badblocks scan baked in (slow, but thorough):
sudo fsck.ext4 -f -c -y /dev/sda1
For XFS, use xfs_repair instead — never fsck.xfs, which is a stub that does nothing useful:
sudo umount /dev/sda1
sudo xfs_repair /dev/sda1
The reason step 2 works when it works: many I/O errors are logical, not physical. A power loss during a write can leave the journal and the inode table disagreeing. fsck replays the journal and reconciles them. That's a real fix, not a bandage.
If fsck reports bad blocks and repairs them, run it a second time. Then a third. If it keeps finding new bad blocks, that's not corruption — that's surface degradation. Go to step 3.
Step 3: The 15-Minute Diagnosis — Is the Disk Dying?
Install smartmontools and read the SMART data. This is the part everyone skips and then regrets.
sudo apt install smartmontools # Debian/Ubuntu
sudo dnf install smartmontools # Fedora/RHEL
sudo smartctl -a /dev/sda
Four attributes matter more than the rest:
| Attribute | ID | What it means |
|---|---|---|
| Reallocated_Sector_Ct | 5 | Grown sectors the drive remapped. Any nonzero trend is bad. |
| Current_Pending_Sector | 197 | Sectors the drive can't read but hasn't remapped yet. These cause I/O errors. |
| Offline_Uncorrectable | 198 | Confirmed unreadable sectors. |
| UDMA_CRC_Error_Count | 199 | Cable or controller problem. Disk is fine, cabling isn't. |
If attribute 199 is climbing and 5, 197, 198 are flat: swap the SATA cable. That's it. Ninety percent of "I/O error on /dev/sda" cases on older desktops are a $4 cable that got baked by a hot GPU.
If 197 or 198 is nonzero and growing, run a long self-test:
sudo smartctl -t long /dev/sda
# wait for the test to finish, then:
sudo smartctl -l selftest /dev/sda
For NVMe, the same idea, different command syntax:
sudo nvme smart-log /dev/nvme0
Look at media_errors and percentage_used. A Samsung 970 EVO at 105% used with media_errors climbing is done. Back up now, not after the next reboot.
Rescuing data off a disk that's throwing I/O errors
Don't use cp or rsync for this. They retry forever and beat the failing sectors to death. Use ddrescue:
sudo apt install gddrescue
sudo ddrescue -d -r3 /dev/sda /mnt/backup/sda.img /mnt/backup/sda.map
The reason ddrescue is the right tool: it reads forward, skips bad sectors, and comes back for them later with progressively smaller reads. It never hammers a dying head against the same platter spot. You can also point it at individual files if the filesystem is still mountable — but mount read-only and with noload (ext4) to avoid journal replay writing anything back.
sudo mount -o ro,noload /dev/sda1 /mnt/rescue
When to just replace the drive
If SMART shows reallocated sectors, pending sectors, uncorrectable sectors, or an NVMe with nonzero media errors, the drive is on its way out. There's no software fix. Copy what you can, order a replacement, and stop trusting it. A 2 TB Samsung 870 EVO costs less than a weekend of data recovery.
If SMART is clean, the cable is new, and errors still show up under load: check /var/log/kern.log for ata bus error or link is slow to respond. That points at the SATA controller or the power supply. A PSU that sags under load causes I/O errors that vanish on a known-good machine — and no disk utility will ever tell you that.