
Major and Minor Numbers in Linux Kernel
March 18, 2026
Hello everyone, In this article, we will discuss the upper and lower layers of major and minor numbers in character/block devices within the Linux kernel.
Topics: * What is a kernel module? * What are character devices? * What are major and minor numbers? * How do modules request major and minor numbers? * Additional tips and summary * References
What is a Kernel Module?
Kernel modules are compiled pieces of code that can be loaded into or unloaded from the kernel without requiring a reboot. As you can see, they are excellent for addressing the significant limitations of monolithic kernels, allowing us to structure kernel code into manageable pieces.
To view loaded modules in the kernel, you can use the command:
$lsmod
Example:
mateo@fedora:~$ lsmod
Module Size Used by
xfs 3796992 0
nilfs2 360448 0
jfs 344064 0
nls_ucs2_utils 8192 1 jfs
uhid 28672 0
ses 20480 0
enclosure 24576 1 ses
scsi_transport_sas 61440 1 ses
uas 40960 0
usb_storage 94208 1 uas
rfcomm 110592 18
snd_seq_dummy 12288 0
snd_hrtimer 12288 1
nft_fib_inet 12288 1
What are Character Devices?
Character devices are a type of kernel module that enables communication between userspace and kernelspace using simple system calls such as open, read, write, and close.
For instance, when you plug in your thumb drive, the kernel loads a specific kernel module to manage communication between the kernel and the thumb drive. After loading, the kernel creates character devices in /dev/.
Example:
mateo@fedora:~$ ls /dev/nvme*
/dev/nvme0 /dev/nvme0n1 /dev/nvme0n1p1 /dev/nvme0n1p2 /dev/nvme0n1p3
What are Major and Minor Numbers?
After covering some foundational(and boring) topics, we can now discuss the main subject. You might have wondered about the numbers next to the owner and group when using ls -l /dev/. In brief, each kernel module (character/block device) has a unique identifier within the kernel, which we call the major number.
mateo@fedora:~$ ls -l /dev/
total 0
crw-------. 1 root root 10, 260 Mar 15 21:06 acpi_thermal_rel
crw-r--r--. 1 root root 10, 235 Mar 15 21:06 autofs
Technically, the kernel maintains a table in include/linux/major.h. When you call register_chrdev_region() (to request a specific major number for a device) or alloc_chrdev_region() (to request a free, random major number from the kernel), the kernel assigns a number to the module.
Now that we understand major numbers, let’s discuss minor numbers. Since multiple character/block devices can utilize a single module, they might share the same major number. But what about the minor number? Each device has its own unique minor number. Let’s take an example: When you plug in your thumb drive, the kernel loads its module, which is assigned a specific major number (e.g., 42).
The kernel then creates a device node for each partition, and each of these nodes receives a specific minor number.
Example Structure:
nvme0n1
├─nvme0n1p1
├─nvme0n1p2
└─nvme0n1p3
Corresponding ls -l output:
mateo@fedora:~$ ls -l /dev/nvme0n1*
brw-rw----. 1 root disk 259, 0 Mar 17 19:05 /dev/nvme0n1
brw-rw----. 1 root disk 259, 1 Mar 17 19:05 /dev/nvme0n1p1
brw-rw----. 1 root disk 259, 2 Mar 17 19:05 /dev/nvme0n1p2
brw-rw----. 1 root disk 259, 3 Mar 17 19:05 /dev/nvme0n1p3
How Modules Request Major and Minor Numbers
Before diving into this, it’s important to know that there are two methods: static and dynamic. Static Registration:
int register_chrdev_region(dev_t first, unsigned count, const char *name);
first: The requested major number. count: The number of minor numbers to allocate for this major number. name: The name of the character device.
Example:
// MKDEV creates a dev_t from major and minor numbers.
dev_t mam = MKDEV(3, 0);
register_chrdev_region(mam, 1, "mateo_test_dev");
Dynamic Registration:
int alloc_chrdev_region(dev_t *_dev, unsigned int firstminor, unsigned count, const char *name);
Example:
dev_t dev;
alloc_chrdev_region(&dev, 0, 1, "mateo_test_dev");
// Extract the major number
int mj_number = MAJOR(dev);
// Create a minor number for the device (using the extracted major number)
dev = MKDEV(mj_number, 0);
These major and minor numbers are stored in /proc/devices in userspace.
Example Output:
mateo@fedora:~$ cat /proc/devices
Character devices:
1 mem
4 /dev/vc/0
4 tty
4 ttyS
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
Additional Tips and Summary
In conclusion, we’ve touched upon where major and minor numbers are used. Actually, when we perform an operation on a device (like open, read, write, close), the kernel uses the major and minor numbers to find and execute the correct functionality.
Within the kernel, the major and minor numbers for character and block devices are stored in different structures. For character devices, this information is managed in fs/char_dev.c via a static array:
static struct char_device_struct *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
This structure is defined statically, meaning we do not directly access it from the kernel symbol table. Reference
Corbet, J., Rubini, A., & Kroah-Hartman, G. (2005). Linux Device Drivers (3rd ed.). O’Reilly Media.