2026-09-01
Every block I/O request in Linux passes through an I/O scheduler before reaching the device. The scheduler's job is to reorder and merge requests to minimize seek time on spinning disks. For a rotational drive, sorting requests by sector (the classic elevator algorithm) can turn a 10ms seek storm into a smooth sweep across the platter. But NVMe drives don't seek — and the scheduler that helped HDDs actively hurts them.
Linux exposes the scheduler per-device at /sys/block/nvme0n1/queue/scheduler. The choices you'll see include none, mq-deadline, kyber, and bfq. Since kernel 5.0, everything runs on blk-mq (multi-queue block layer), where each CPU has its own submission queue and the device has multiple hardware queues that can be serviced in parallel.
mq-deadline maintains two sorted red-black trees (read and write) plus two FIFO lists with expiration deadlines (500ms reads, 5s writes). It serves sorted requests until a deadline expires, then switches to the FIFO head to prevent starvation. This is great for a SATA SSD or HDD where the device can process one request at a time and merging adjacent sectors saves real work.
none does nothing — it hands requests directly from the per-CPU submit queue to the device's hardware queue. On an NVMe drive with 64K hardware queue depth and 8+ parallel queues, this is exactly what you want. The device's internal FTL reorders better than the kernel can, and every cycle spent in the scheduler is pure overhead.
Real example: On a Samsung 980 Pro running fio with 4KB random reads at queue depth 32, switching from mq-deadline to none typically drops p99 latency from ~180μs to ~110μs and lifts IOPS from ~620K to ~900K. The scheduler was adding a lock-protected tree operation to a workload where reordering had zero benefit.
Rule of thumb for scheduler selection:
none — the device is faster than the scheduler.mq-deadline — some merging still helps, seek cost is zero.bfq or mq-deadline — seek reordering is the whole game.bfq — its per-cgroup fairness prevents one process from starving your UI.Modern kernels detect NVMe and default to none automatically, but virtualized environments and older distros often still ship mq-deadline as the default. Check with cat /sys/block/*/queue/scheduler — the choice in brackets is active.
none) beats every clever reordering algorithm because the device's own FTL handles it better and every kernel cycle spent sorting is latency you'll never get back.
