Storage subsystem performance on an Ubuntu server or workstation is heavily influenced by how the Linux kernel schedules read and write operations. The kernel’s multi-queue block layer (blk-mq) relies on specialized I/O Schedulers to determine the order in which storage requests are queued, merged, and dispatched to underlying physical drives. While modern NVMe drives thrive when bypassing scheduling logic entirely, rotational hard drives (HDDs) and database arrays require sophisticated fair-queuing algorithms to prevent request starvation. Understanding how to check and tune your block I/O scheduler ensures optimal disk throughput and low storage latency.
Overview of Linux Block I/O Schedulers
Modern Ubuntu installations include four standard multi-queue schedulers:
- none: Completely bypasses kernel request queuing and sends I/O commands directly to the drive controller. This is the optimal configuration for ultra-fast NVMe SSDs that handle hardware-level parallel queues natively.
- mq-deadline: Implements a deterministic deadline algorithm that ensures no individual read or write operation waits longer than a fixed expiration threshold. It is the recommended scheduler for standard SATA SSDs.
- bfq (Budget Fair Queueing): Allocates disk bandwidth budgets proportionally to active processes. It provides exceptional desktop responsiveness and prevents heavy background transfers from freezing interactive applications.
- kyber: A lightweight, latency-oriented scheduler designed specifically for fast flash storage arrays under high multi-tenant contention.
Checking the Active I/O Scheduler for a Disk
The Linux kernel exposes block device parameters through the /sys virtual filesystem. To inspect your active scheduler:
- Open the Terminal application on Ubuntu (press Ctrl + Alt + T).
- Identify your target storage device name (such as
sdafor SATA ornvme0n1for NVMe) usinglsblk. - Inspect the scheduler virtual file:
cat /sys/block/sda/queue/scheduler - The terminal outputs the available schedulers, with the currently active algorithm enclosed in square brackets:
[mq-deadline] none bfq - For an NVMe device:
Outputs:cat /sys/block/nvme0n1/queue/scheduler[none] mq-deadline kyber bfq
Temporarily Changing the Scheduler at Runtime
You can dynamically alter the active scheduler for testing without rebooting Ubuntu:
- Write the preferred scheduler name directly into the device’s
queue/schedulerfile using root privileges:sudo tee /sys/block/sda/queue/scheduler <<< "bfq" - Confirm the updated status:
cat /sys/block/sda/queue/scheduler - The brackets will now surround your new selection:
mq-deadline none [bfq].
Permanently Setting Schedulers via Udev Rules
Because changes to /sys are ephemeral and reset upon reboot, use a custom udev rule to enforce scheduler policies permanently across system restarts:
- Create a new udev configuration file:
sudo nano /etc/udev/rules.d/60-io-schedulers.rules - Add matching rules targeting rotational disks, SATA SSDs, and NVMe devices:
# Set 'none' for NVMe devices ACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/scheduler}="none" # Set 'mq-deadline' for non-rotational SATA SSDs ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline" # Set 'bfq' for mechanical rotational hard drives ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="bfq" - Save and exit the file (press Ctrl + O, then Ctrl + X).
- Trigger the updated udev rules:
sudo udevadm control --reload && sudo udevadm trigger