Managing I/O and CPU Scheduling with the RT Kernel
I/O and CPU scheduling using the RT kernel in SUSE Linux Enterprise Server optimizes resource
allocation to ensure deterministic execution for latency-sensitive tasks. By configuring block device
schedulers, assigning process I/O priorities with ionice and isolating CPU cores using
systemd and taskset, administrators prevent disk starvation and latency spikes.
This coordination guarantees predictable response times and maximum system throughput for mission-critical
real-time applications.
Prerequisites
Installed RT kernel on SUSE Linux Enterprise Server
Access to a command-line terminal with
systemd,taskset,chrtandioniceavailable
1 How does I/O scheduling work? #
Handling I/O requests predictably is critical for deterministic performance in real-time systems. High CPU availability yields limited benefits if tasks stall while awaiting disk access.
The Linux storage subsystem organizes process disk access into three distinct scheduling classes:
- Real-time (class 1)
Grants highest priority for disk access. Requests in this class are served before any other class. Within the real-time class, priority is fine-tuned with
nicelevels from0(highest priority) to7(lowest priority).Warning: Risk of disk bandwidth starvationAssigning real-time I/O priorities incorrectly can deprive other system processes of disk bandwidth.
Assign real-time I/O class only to thoroughly tested critical tasks.
- Best-effort (class 2)
The default scheduling class for standard system processes. Priority is derived from the process CPU
nicevalue (ranging from0to7).- Idle (class 3)
Processes receive disk access only when no other process requests disk I/O. Ideal for background workloads such as logging or maintenance.
2 How to manage process I/O priorities with ionice? #
Inspect and adjust process I/O scheduling classes and priority levels using the
ionice utility.
ionice #To view or modify process I/O scheduling attributes, perform the following steps.
To set the I/O scheduling class of the current shell to
idle, run:>ionice -c3 -p$$To print the I/O scheduling class and priority of the current shell, run
ionicewithout additional parameters:>ioniceTo set the I/O scheduling class of the process with the process ID
42to real-time and its priority level to2, run:>sudoionice -c1 -p42 -n2To start the Bash shell in the
idleclass, run:>ionice -c3 /bin/bash
3 Changing the block device I/O scheduler #
Display and change the I/O scheduler of a block device.
noneThe
nonescheduler is a simple scheduler that performs no reordering of I/O requests. This scheduler is mainly used for specialized environments that run their own schedulers optimized for the used hardware, such as fast NVMe storage, storage systems or hardware RAID controllers.mq-deadlineThe main point of deadline scheduling is to try hard to answer a request before a given deadline. This results in good I/O for a random single I/O in real-time environments.
In principle, the
mq-deadlinescheduler uses two lists with all requests. One is sorted by block sequences to reduce seeking latencies, the other is sorted by expire times for each request. Normally, requests are served according to the block sequence, but if a request reaches its deadline, the scheduler starts to work on this request.bfqThe Budget Fair Queueing (BFQ) scheduler uses a separate I/O queue for each process and tries to divide the bandwidth fairly between all requesting processes.
To print the current scheduler of a block device such as
/dev/sda, use the following command:>cat /sys/block/sda/queue/schedulernone [mq-deadline] bfqThe scheduler in square brackets is the active one. In this case, the scheduler for
/dev/sdais set tomq-deadline.To change the scheduler, write one of the listed names to
/sys/block/DEVICE/queue/scheduler. For example, to set the I/O scheduler of the device/dev/sdatonone, use the following command asroot:#echo "none" > /sys/block/sda/queue/scheduler
To set other variables in the /sys/ file system, use a
similar approach.
4 Tuning block device I/O scheduler parameters #
Fine-tune operational parameters of active block device schedulers in
sysfs to optimize read and write latency for real-time applications.
All schedulers, except for the none scheduler, have
several common parameters that may be tuned for each block device. You can
access these parameters with sysfs
in the /sys/block/DEVICE/queue/iosched/
directory. The following parameters are tunable for the respective
scheduler:
mq-deadline scheduler #read_expireThe main focus of this scheduler is to limit the start latency for a request to a given time. Therefore, for each request, a deadline is calculated from the current time plus the value of
read_expirein milliseconds.write_expireSimilar to
read_expirefor write requests.fifo_batchIf a request hits its deadline, it is necessary to move the request from the sorted I/O scheduler list to the dispatch queue. The variable
fifo_batchcontrols how many requests are moved, depending on the cost of each request.front_mergesThe scheduler normally tries to find contiguous I/O requests and merges them. There are two kinds of merges: The new I/O request may be in front of the existing I/O request (front merge), or it may follow behind the existing request (back merge). Most merges are back merges. Therefore, you can disable the front merge functionality by setting
front_mergesto0.writes_starvedIf certain read or write requests hit their deadline, the scheduler prefers the read requests by default. To prevent write requests from being postponed forever, the variable
writes_starvedcontrols how often read requests are preferred until write requests are preferred over read requests.
bfq scheduler #back_seek_maxandback_seek_penaltyThe scheduler normally dispatches requests in a strict ascending order. When needed, it also allows small backward seeks, but it applies a penalty on them. The maximum backward sector seek is defined with
back_seek_max, and the multiplier for the penalty is set byback_seek_penalty.fifo_expire_asyncandfifo_expire_syncThe
fifo_expire_*variables define the timeout in milliseconds for asynchronous and synchronous I/O requests. Setfifo_expire_synclower thanfifo_expire_asyncto prioritize synchronous requests over asynchronous operations.slice_idleandslice_idle_usDefines how long the I/O scheduler idles before servicing the next thread to maintain sequential I/O locality.
slice_idlespecifies this time in milliseconds, whileslice_idle_usspecifies it in microseconds.
5 CPU partitioning and affinity #
Understand how systemd resource control partitions CPUs to isolate
real-time workloads.
SUSE Linux Enterprise Server partitions CPUs with the cpuset controller of the unified
cgroups v2 hierarchy, which you manage through systemd. You assign CPUs
to slices, services and scopes with the AllowedCPUs=
property. The setting can be persistent or transient.
A unit can only use the CPUs that its parent slice allows. Therefore, to
dedicate CPUs to real-time workloads, restrict the primary system slices
(such as system.slice and
user.slice) to the remaining CPUs. The affinity of an
individual process, set with taskset, is limited in
the same way.
For a complete shielding procedure, refer to the article Shielding Linux Resources on SUSE Linux Enterprise Server.
6 Managing CPU shielding with systemd, taskset and chrt #
Isolate real-time workloads on dedicated logical CPUs using systemd resource control,
taskset and chrt.
To restrict general processes to CPUs 0 to
2 and dedicate CPU 3 to a
critical task, perform the following steps:
Restrict the system slices to CPUs
0-2. The setting is persistent. To apply it only until the next reboot, add the--runtimeoption.>sudosystemctl set-property system.slice AllowedCPUs=0-2>sudosystemctl set-property user.slice AllowedCPUs=0-2>sudosystemctl set-property init.scope AllowedCPUs=0-2To run an application in its own slice and restrict it to CPU
3, use a transient scope:>sudosystemd-run --scope --slice=realtime.slice --property=AllowedCPUs=3 APPLICATIONTo print the CPU affinity of the application started in the previous step, use
tasksetwith its process ID PID:>taskset -c -p PIDTo change the affinity, run the command as
root. The CPU list must be within the CPUs that the slice of the process allows. In this example, that is CPU3:>sudotaskset -c -p 3 PIDTo assign the
SCHED_FIFOreal-time scheduling policy with the priority40to the process, run:>sudochrt --fifo -p 40 PID
7 Multi-queue I/O schedulers and key parameters #
This section provides an overview of the available multi-queue block device I/O schedulers
and their sysfs tuning parameters.
7.1 Available multi-queue I/O schedulers #
| Scheduler | Typical use | Description |
|---|---|---|
none | High-performance NVMe SSDs | Performs no reordering of requests and passes them directly to the hardware queues. |
mq-deadline | SATA, SAS and traditional HDDs | The system default for most block devices. Tries to serve each request before its deadline to limit latency spikes and prevent write starvation. |
bfq | Desktop environments and I/O-bound cgroups | Divides storage bandwidth proportionally between requesting processes or cgroups to maintain interactive responsiveness under heavy background loads. |
7.2 Key sysfs parameters #
mq-deadline parameters #| Parameter | Unit | Description |
|---|---|---|
read_expire | Milliseconds | Deadline for starting to serve a read request. |
write_expire | Milliseconds | Deadline for starting to serve a write request. |
fifo_batch | Requests | Number of requests moved to the dispatch queue at once when a request hits its deadline. |
front_merges | Flag (0 or 1) | Enables or disables front merges of contiguous requests. |
writes_starved | Count | How many times read requests are preferred before a pending write request is served. |
8 For more information #
The Real-Time Linux wiki: https://wiki.linuxfoundation.org/realtime/start
systemdresource control (AllowedCPUs=and other settings): the man page ofsystemd.resource-control(man 5 systemd.resource-control), or the upstream documentation at https://www.freedesktop.org/software/systemd/man/systemd.resource-control.htmlThe kernel documentation about control groups v2 (
Documentation/admin-guide/cgroup-v2.rst): https://docs.kernel.org/admin-guide/cgroup-v2.htmlDetailed information about kernel control groups
CPU shielding in detail: Shielding Linux Resources on SUSE Linux Enterprise Server
9 Legal Notice #
Copyright© 2006– 2026 SUSE LLC and contributors. All rights reserved.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or (at your option) version 1.3; with the Invariant Section being this copyright notice and license. A copy of the license version 1.2 is included in the section entitled “GNU Free Documentation License”.
For SUSE trademarks, see https://www.suse.com/company/legal/. All other third-party trademarks are the property of their respective owners. Trademark symbols (®, ™ etc.) denote trademarks of SUSE and its affiliates. Asterisks (*) denote third-party trademarks.
All information found in this book has been compiled with utmost attention to detail. However, this does not guarantee complete accuracy. Neither SUSE LLC, its affiliates, the authors, nor the translators shall be held liable for possible errors or the consequences thereof.