Linux Kernel

Linux is a kernel designed to be similar to the original UNIX kernel. It is a modern, free, and open source alternative that was originally created by Linus Torvalds. It is built to work on many processor architectures. “Linux” is sometimes used to generally describe the many operating systems that use the Linux kernel. [1] In the context of this Root Pages guide, the focus is on the actual kernel.

Each kernel new kernel in development normally goes through 7 to 9 weeks of release candidates before it is marked as stable. [12] At some point after the Linux git repository has added more than 2 million git objects, the major version number is increased. [13] The latest kernels can be found here.

The types of Linux kernel releases include:

  • mainline = The latest development release that is working towards a stable release.

  • stable = The current stable release.

  • longterm = Long-term supported kernels are older versions that primarily only receive bug fixes.

  • linux-next = Daily unstable development releases from the “master” git branch.

System Calls

Programs use system calls to interact with the kernel to do tasks.

Common system calls:






Accept an incoming network connection.



Associate a network socket to a specific IP address.



Change to a different working directory.



Change the mode permissions.



Change the owner permissions.



Change the working root directory.



Close a file.



Make an external network connection.



Execute/start a program.



End a process.



Spawn a new process.



Find the group ID.



Find the user ID.



Send a signal to a process.



Create a shortcut that mirrors an existing inode (a hard link).



Create a directory.



Create a file (node).



Mount a file system onto a directory.



Modify the priority of a process.



Open a file.



Temporarily stop a process from running until a signal is given to continue.



Stream output data from one process to another.



Read data from a file.



Change a process’ group ID.



Change a process’ kernel scheduling priority.



Change a process’ user ID.



Create a socket that can listen for requests. This can be a UNIX file socket, network port, or a special process.



Create a shortcut that redirects to another file (a symbolic link).



Flush data from memory to the disk.



View a file’s metadata.



A count of seconds since 1970-01-01.



View and modify user process limits.



Delete a directory.



View and modify the default permissions of files and directories.



Wait for a child process to end.



Write data to a file.



The root user with the user ID of 0 has access to all capabilities exposed by the Linux kernel. All other users are considered unprivileged and do not have access to any of the capabilities. Each capability allows certain system calls and other specific actions. Unprivileged users can be run binaries that a root user enables specific privileged capabilities on.

Common capabilities in the Linux kernel:



System Calls


Change ownership of files and directories.



Kill any process.

ioctl, kill


Access to all networking functions.



Bind to a port below 1024.



Provide a process most of the privileged capabilities.

accept, bdflush, clone, execve, fanotify_init, ioctl, ioprio_set, keyctl, lookup_dcookie, madvise, mount, nfsservctl, open, pipe, pivot_root, ptrace, quotactl, random, sched, seccomp, setdomainname, sethostname, setns, swapoff, swapon, syslog, umount, unshare, xattr


Change the root directory and namespace.

chroot, nets


Change the priority of a process.

ioprio_set, mbind, migrate_pages, move_pages, nice, sched_setattr, sched_setparam, sched_setscheduler, setpriority


Change resource limits and quotas.

fcntl, ioctl, mq_overview, msgop, msgctl, prctl, setrlimit, unix


Change the system time.

adjtimex, settimeofday, stime



The kernel is composed of a large number of modules. These can be found here:


View all of the loaded modules:

$ sudo lsmod

Custom modules can be compiled for a specific kernel and copied in their respective driver directory. A few common drivers types are “iscsi”, “net/ethernet”, “net/wireless”, “usb”, “pci”, “video”, etc.


After copying over the necessary *.ko file(s) for custom modules, load

$ sudo depmod <MODULE>

If there are a large number of new modules, it is possible to make sure all module dependencies are installed.

$ sudo depmod --all

Modules can be temporarily loaded:

$ sudo modprobe <MODULE>

Or permanently add the module to a file with the extension “.conf” in the modules load directory.

Files: /etc/modules-load.d/*.conf

Modules can be deactivated by running one of these two commands:

$ sudo rmmod <MODULE>
$ sudo modprobe -r <MODULE>

Modules can also be blocked from starting on boot:

File: /etc/modprobe.d/blacklist.conf

blacklist <MODULE>




View all of the available options for a kernel module [15]:

$ modinfo --parameters <KERNEL_MODULE> # Method 1
$ ls -1 /sys/module/<KERNEL_MODULE>/parameters/ # Method 2

Temporarily set module parameters:

$ sudo modprobe -r <KERNEL_MODULE>

There are two ways to permanently set options: (1) modprobe configuration or (2) GRUB configuration.

  1. modprobe:

    $ sudo vim /etc/modprobe.d/<MODPROBE_FILENAME>.conf
  2. GRUB:

    $ vim /etc/default/grub
    $ sudo grub-mkconfig -o /boot/grub/grub.cfg


Create a short and/or memorable alias name for the kernel module:

$ sudo vim /etc/modprobe.d/<MODPROBE_FILENAME>.conf




The Linux kernel handles incoming requests differently depending on the CPU scheduler. The CPU scheduler is determined at compile time for the kernel and cannot be changed later. [5][32] For compiling with different CPU schedulers, use linux-tkg. [32] The current CPU scheduler is EEVDF [35] which provides lower latency than CFS. [36]


First Linux Kernel Release









Symmetric Multiprocessing (SMP)


Round-Robin Scheduler



Unofficial CPU schedulers [32]:

  • bmq

  • bore

  • pds

There are 6 different kernel scheduling classes/policies that can be set to processes manually. These are set by using the chrt command.

Policies [38][39]:

  • SCHED_BATCH = Batch handles CPU-intensive tasks with real time priority.

  • SCHED_DEADLINE = Available since Linux 3.14. [37] Prioritize processes based on what needs to be completed first based on the values of deadline, period, and runtime.

  • SCHED_FIFO (first-in first-out) = Handles each task that is requested, in order.

  • SCHED_IDLE = Tasks will only be processed when the processor is mostly idle.

  • SCHED_OTHER (CFS) = All tasks are treated equally and are handled with the same amount of priority.

  • SCHED_RR (round robin) = This is similar to SCHED_BATCH except that tasks are handled for a short amount of time before moving onto a different task to handle.

The relevant sysctl parameters can be adjusted for system-wide scheduling settings can be found by running:

$ sudo sysctl -a | grep "sched_"



The kernel provides many input/output (I/O) schedulers to configure how a hard drive handles a queue of read/write requests from the operating system. Different schedulers can be used to adjust performance based on the hardware and/or software requirements. There are two types of scheulers:

  • Non-multiqueue = Legacy. These are single-threaded. Deprecated since Linux 5.3.

  • Multiqueue = Modern. These are multi-threaded.

Non-multiqueue Schedulers:

  • cfq = Completely Fair Queueing. All I/O requests are treated equally and are handled in the order that they are received. [6]

    • Usage: MMC and SD cards. [28]

    • This is the only non-multiqueue scheduler that ionice works with to change the I/O priority. [25]

  • deadline = Large I/O requests are done in high-priority sectors until smaller I/O requests are about to time out. Then Deadline takes care of the small tasks before continuing with the original large I/O task.

    • Usage: spinning hard disk drive with heavy I/O operations.

  • noop = No Operation. Only basic merging of read and/or write requests and no rescheduling.

    • Usage: virtual drives (such as QCOW2) where the hypervisor node handles the I/O scheduling [7], SSDs, or RAID cards with write-back cache where the firmware of the hardware takes care of the sorting. [6]

Multiqueue Schedulers:

  • bfq = Budget Fair Queuing. The multiqueue equivalent for CFQ.

    • This is the only multiqueue scheduler that ionice works with to change the I/O priority. [27]

  • kyber = A small scheduler that uses minimal logic to provide higher throughput and lower latency. [29]

  • mq-deadline = The multiqueue equivalent for Deadline.

  • none = The multiqueue equivalent for NOOP.


Temporarily change the scheduler to one of the three options:

$ sudo echo [bfq|kyber|mq-deadline|none] > /sys/block/<DEVICE>/queue/scheduler

Permanently change the scheduler by appending the existing GRUB_CMDLINE_LINUX kernel arguments:

$ sudo vim /etc/default/grub
$ sudo grub-mkconfig -o /boot/grub/grub.cfg



When using the BFQ or CFQ scheduler, the ionice command can be used to set different priorities for running processes. Typical usage of the command is to run ionice -c <IONICE_CLASS> -n <PRIORITY> -p <PID>.


  • 0 = None. On modern Linux, this is the same as 2 (best-effort).

  • 1 = Realtime. Use the I/O immediately.

  • 2 = Best-effort. This is the default if no class is provided. Use a round-robin algorithm.

  • 3 = Idle. Wait for the I/O usage to be low.


  • 0 = Highest.

  • 7 = Lowest.

Give a running process the highest I/O priority:

$ ionice -c 1 -n 0 <PID>

Give a running process the lowest I/O priority:

$ ionice -c 3 -n 7 <PID>


Initial RAM File System

The initramfs (initial RAM file system) is used to boot up a system before loading the full Linux kernel. It is the successor to the initrd (initial RAM disk). A boot loader, such as GRUB, loads the initramfs first. This usually contains a minimum copy of the kernel and drivers required to boot up the system. Once the boot initialization is complete, the initramfs continues to load all of the available kernel modules. [8][9]

Arch Linux

All modifications of the initramfs in Arch Linux are handled by the “mkinitcpio” utility.

File: /etc/mkinitcpio.conf

  • MODULES = A list of kernel modules to compile in.

  • FILES = A list of files that should be included in the initramfs.

  • BINARIES = A list of binaries that should be included to use in the initramfs environment. This is useful for having more recovery utilities. The “mkinitcpio” program will automatically detect the binary’s dependencies and add them to the initramfs image.

  • HOOKS = Custom hooks for compiling in certain software packages.

    • Common hooks:

      • btrfs = BtrFS RAID.

      • net = Add networking.

      • mdadm = mdadm software RAID modules.

      • fsck = FSCK utilities for available operating systems.

      • encrypt = LUKS encryption modules.

      • lvm2 = Logical volume manager (LVM) modules.

      • shutdown = Allows the initramfs to properly shutdown.

Create a new initramfs.

$ sudo mkinitcpio



On Red Hat Enterprise Linux (RHEL) based operating systems (such as RHEL itself, CentOS, and Fedora), Dracut is used to manage the initramfs.

File: /etc/dracut.conf

  • add_drivers+= A list of kernel modules to compile in.

  • install_items+= A list of files to compile in.

  • add_dracutmodules+= A list of Dracut modules to compile.




  • Install the build dependencies for the Linux kernel:

    • Debian:

      $ sudo apt-get install bc build-essential cpio dwarves findutils flex git kmod libelf-dev libncurses5-dev libssl-dev linux-source rsync
    • Fedora:

      $ sudo dnf install bc bison diffutils elfutils-libelf-devel findutils flex git gcc make openssl-devel rpm-build rsync
  • Download the Linux kernel source code:

    • Using the newest kernels from here.

    • Or using any kernel version from here.

    • Or from the stable kernel git repository:

      • Using a specific version tag:

        $ git clone --depth=1 --branch v<VERSION_MAJOR>.<VERSION_MINOR>.<VERSION_PATCH>
      • Using a specific version branch:

        $ git clone --depth=1 --branch linux-<VERSION_MAJOR>.<VERSION_MINOR>.y
  • Add the kernel headers to the system to help with building DKMS modules in the future. The “linux” folder will need to later be renamed to reflect the output of uname -r of the installed kernel.

    • Arch Linux:

      $ sudo cp -r ./linux* /usr/lib/modules/
    • Debian:

      $ sudo cp -r ./linux* /usr/src/
    • Fedora:

      $ sudo cp -r ./linux* /usr/src/kernels/
  • Create the .config file in the top-level of the kernel directory. It defines what features will be built for the Linux kernel.

    • Use a default configuration:

      $ cd ./linux/
      $ make defconfig
  • Build the Linux kernel:

    • Generic:

      $ make -j $(nproc)
    • DEB (Debian) packages:

      $ make -j $(nproc) bindeb-pkg
    • RPM (Fedora) packages:

      $ make -j $(nproc) binrpm-pkg
  • Install the Linux kernel:

    • Generic:

      $ sudo make install
      $ sudo make modules_install
    • DEB (Debian) packages:

      $ sudo dpkg -i ../linux-*.deb
    • RPM (Fedora) packages:

      $ sudo rpm -iU ~/rpmbuild/RPMS/x86_64/kernel-*.rpm



  • Install the required packages to build Fedora packages:

    $ sudo dnf install fedora-packager fedpkg grubby ncurses-devel pesign rpmdevtools
  • Download the Fedora package for the Linux kernel. This first requires increasing the git buffer size or else the download of the large git repository will fail.

    $ git config --global http.postBuffer 157286400
    $ fedpkg clone -a kernel
    $ cd kernel
  • Switch to the desired branch to build.

    $ git checkout origin/f<FEDORA_MAJOR_VERSION>
  • Install the build dependencies of the Linux kernel and the source files needed for building the RPMs.

    $ sudo dnf install 'dnf-command(builddep)'
    $ sudo dnf builddep kernel.spec
    $ fedpkg sources
  • Fix the PKI signing keys permissions which are required for the Linux kernel.

    $ sudo /usr/libexec/pesign/pesign-authorize
  • Change the build name to something other than the default of “local”. This prevents conflicts with other kernels built with the default options. In the example below, it is changed to “custom”. [20]

    $ sed -i 's/# define buildid .local/%define buildid .custom/g' kernel.spec
  • Build the kernel.

    • RPM

      • Build and package a release kernel as RPMs using Mock to isolate dependencies. By default, kernels are built with debugging support which are slower and bigger. They are named kernel-debug-<VERSION>.rpm. [23] This can be disabled. [21][22] If the user doing the build is not in the mock group, the fedpkg command will manually prompt the user to enter the root password.

        $ sudo usermod -a -G mock ${USER}
        $ fedpkg --release f<FEDORA_MAJOR_VERSION> mockbuild --without debug --without debuginfo --with release --with headers
      • The resulting RPMs will be saved to: $(pwd)/results_kernel/<KERNEL_FULL_VERSION>/<RPM_RELEASE>.<RPM_LOCAL_NAME>.fc<FEDORA_MAJOR_VERSION>. For example, the directory should look similar to this:

        $ ls -1 results_kernel/6.3.13/200.custom.fc38/
    • SRPM

      • Build a source RPM package with the sources for the release kernel. This is normally configured via RPM build configurations (BCONF) statements such as --with and --without [24] but it is not possible to create a SRPM with those pre-defined. Fedora Copr also does not support changing these values. Instead, manually modify the kernel.spec file.

        $ sed -i s'/%define with_debug     %{?_without_debug:     0} %{?!_without_debug:     1}/%define with_debug 0/'g kernel.spec
        $ sed -i s'/%define with_debuginfo %{?_without_debuginfo: 0} %{?!_without_debuginfo: 1}/%define with_debuginfo 0/'g kernel.spec
        $ sed -i s'/%define with_release   %{?_with_release:      1} %{?!_with_release:      0}/%define with_release 1/'g kernel.spec
        $ sed -i s'/%define with_headers   %{?_without_headers:   0} %{?!_without_headers:   1}/%define with_headers 1/'g kernel.spec
        $ sed -i s'/with_headers 0/with_headers 1/'g kernel.spec
        $ fedpkg --release f38 srpm
      • The resulting SRPM will be saved to the current working directory.

        $ ls -1 | grep src.rpm



The latest Linux kernels for both Debian and Ubuntu are provided by the Ubuntu project.

  • These are the required DEB packages that need to be downloaded and installed:

    • linux-headers (all) = The full Linux kernel source code.

    • linux-headers (generic) = The source code specific to a CPU architecture.

    • linux-image-unsigned = The Linux kernel image.

    • linux-modules = Additional/useful Linux kernel modules.

  • Find the desired Linux kernel version from here. Set these variables based on the built packages. This example is for Linux 5.10.0.

    $ export KERNEL_VERSION_SHORT="5.10"
    $ export KERNEL_VERSION_FULL="5.10.0-051000"
    $ export KERNEL_DATE="202012132330"
    $ export KERNEL_ARCHITECTURE="amd64" # Or use "arm64" or "ppc64el".
  • Download the required packages.

  • Install the packages.

    $ sudo dpkg -i ./*.deb



Errors Messages


This is a list of common errors and warnings that make occur while building a kernel and how to resolve them.

  • .config:<LINE_NUMBER>:warning: symbol value '<SYMBOL_VALUE>' invalid for <CONFIG_OPTION> = The symbol (y, n, or m) is invalid. Use a different symbol.

  • .config:<LINE_NUMBER>:warning: override: reassigning to symbol <CONFIG_OPTION> = A configuration option is listed more than once. Remove the duplicates.



  1. “About Linux Kernel.” The Linux Kernel Archives. April 23, 2017. Accessed July 9, 2016.

  2. “UNIX System Calls.” University of Miami’s Department of Computer Science. August 22, 2016. Accessed July 1, 2017.

  3. “Kernel modules.” The Arch Linux Wiki. August 8, 2016. Accessed November 19, 2016.

  4. “Tuning the Task Scheduler.” openSUSE Documentation. December 15, 2016. Accessed July 9, 2017.

  5. “Change Linux CPU default scheduler.” A else B. January 6, 2016. Accessed July 9, 2017.

  6. Linux System Programming. (Love: O’Reilly Media, Inc., 2007).

  7. “What is the suggested I/O scheduler to improve disk performance when using Red Hat Enterprise Linux with virtualization?” Red Hat Knowledgebase. December 16, 2016. Accessed December 18, 2016.

  8. ‘The Kernel Newbie Corner: “initrd” and “initramfs”–What’s Up With That?’ September 30, 2009. Accessed November 19, 2016.

  9. “ramfs, rootfs and initramfs.” The Linux Kernel Documentation. May 29, 2015. Accessed November 19, 2016.

  10. “mkinitcpio.” The Arch Linux Wiki. November 13, 2016. Accessed November 19, 2016.

  11. “Dracut.” The Linux Kernel Archives. October, 2013. Accessed November 19, 2016.

  12. “Which Linux Kernel Version Is ‘Stable’?” February 3, 2018. Accessed September 25, 2018.

  13. “Linux Kernel 5.0 to Be Released When We Hit 6M Git Objects, Says Linus Torvalds.” Softpedia News. October 9, 2016. Accessed September 25, 2018.

  14. “How to install Linux 5.8 Kernel on Ubuntu 20.04 LTS.” Linux Shout. August 5, 2020. Accessed December 13, 2020.

  15. “How can I know/list available options for kernel modules?” Ask Ubuntu. December 13, 2017. Accessed January 21, 2021.

  16. “Kernel module.” Arch Wiki. October 14, 2020. Accessed January 21, 2021.

  17. “capabilities (7).” Linux manual page. June 20, 2021. Accessed August 2, 2021.

  18. “BuildADebianKernelPackage.” Debian Wiki. December 1, 2021. Accessed January 10, 2022.

  19. “How to compile vanilla Linux kernel from source on Fedora.” May 30, 2019. Accessed January 10, 2022.

  20. “Building a custom kernel.” Fedora Project Wiki. August 16, 2022. Accessed July 19, 2023.

  21. “Build a fedora kernel: Updated.” ASUS NoteBook Linux. Accessed July 19, 2023.

  22. “Has anyone managed to build a Fedora patched kernel in 2022?” Reddit r/Fedora. December 12, 2022. Accessed July 19, 2023.

  23. “KernelDebugStrategy.” Fedora Project Wiki. August 11, 2016. Accessed July 28, 2023.

  24. “Conditional Builds.” RPM Package Manager. Accessed July 30, 2023.

  25. “Block io priorities.” The Linux Kernel documentation. March 11, 2005. Accessed August 13, 2023.

  26. “Linux Tips: nice and ionice.” Tiger Computing. June 12, 2018. Accessed August 13, 2023.

  27. “Tuning I/O performance.” System Analysis and Tuning Guide. Accessed August 23, 2023.

  28. “Linux 6.3 Now Suggests The BFQ I/O Scheduler When Building MMC/SD Support.” Phoronix. March 1, 2023. Accessed August 13, 2023.

  29. “Two new block I/O schedulers for 4.12.” April 24, 2017. Accessed August 13, 2023.

  30. “Noop now named none.” SUSE Communities. November 29, 2019. Accessed August 13, 2023.

  31. “IOSchedulers.” Ubuntu Wiki. September 10, 2019. Accessed August 13, 2023.

  32. “How can I change the CPU scheduler?” Reddit r/archlinux. January 31, 2023. Accessed January 16, 2023.

  33. “Inside the Linux 2.6 Completely Fair Scheduler.” IBM Developer. September 19, 2018. Accessed January 30, 2024.

  34. “A brief history of the Linux Kernel’s process scheduler: The very first scheduler, v0.01.” DEV Community Satoru Takeuchi. December 3, 2019. Accessed January 30, 2024.

  35. “EEVDF Scheduler Merged For Linux 6.6, Intel Hybrid Cluster Scheduling Re-Introduced.” Phoronix. August 29, 2023. Accessed January 30, 2024.

  36. “Updated EEVDF Linux CPU Scheduler Patches Posted That Plan To Replace CFS.” Phoronix. June 1, 2023. Accessed January 30, 2024.

  37. “Deadline scheduler merged for 3.14.” January 22, 2014. Accessed January 30, 2024.

  38. “Chapter 5. Priorities and policies.” Red Hat Customer Portal. Accessed January 30, 2024.

  39. “chrt command in Linux with examples.” GeeksforGeeks. May 15, 2019. Accessed January 30, 2024.