Kernel Data Structures for Drivers
When writing device drivers in C, you will often need to manage collections of data, keep track of device states, and ensure efficient access to this information inside the kernel. The Linux kernel provides its own set of data structures for these purposes, with linked lists being one of the most fundamental. Unlike user space, where you might use standard library containers, kernel code relies on its own implementations for safety, performance, and flexibility. The most common structure for linked lists in the kernel is the list_head, which allows you to create doubly-linked lists that can be embedded within your own structures. This makes it easy to keep track of multiple devices, buffers, or requests in a clean and organized way.
kernel_list_example.c
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/list.h> struct my_device { int id; struct list_head list; }; static LIST_HEAD(device_list); static int __init list_example_init(void) { struct my_device *dev1, *dev2; dev1 = kmalloc(sizeof(*dev1), GFP_KERNEL); dev2 = kmalloc(sizeof(*dev2), GFP_KERNEL); dev1->id = 1; dev2->id = 2; INIT_LIST_HEAD(&dev1->list); INIT_LIST_HEAD(&dev2->list); list_add(&dev1->list, &device_list); list_add(&dev2->list, &device_list); printk(KERN_INFO "Devices added to list\n"); return 0; } static void __exit list_example_exit(void) { struct my_device *dev, *tmp; list_for_each_entry_safe(dev, tmp, &device_list, list) { list_del(&dev->list); kfree(dev); } printk(KERN_INFO "Devices removed from list\n"); } module_init(list_example_init); module_exit(list_example_exit); MODULE_LICENSE("GPL");
Linked lists, as seen in the example above, are extremely useful for device drivers because they allow you to dynamically add, remove, and traverse device-specific data structures without worrying about fixed array sizes or memory fragmentation. By embedding a list_head in your own structure, you can easily maintain a list of all active devices, pending I/O requests, or any similar collection. The kernel provides helper macros and functions to safely add, remove, and iterate over these lists, making your code more robust and maintainable.
kernel_list_iteration.c
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/list.h> struct my_device { int id; struct list_head list; }; static LIST_HEAD(device_list); static int __init list_iter_example_init(void) { struct my_device *dev1, *dev2, *dev; dev1 = kmalloc(sizeof(*dev1), GFP_KERNEL); dev2 = kmalloc(sizeof(*dev2), GFP_KERNEL); dev1->id = 10; dev2->id = 20; INIT_LIST_HEAD(&dev1->list); INIT_LIST_HEAD(&dev2->list); list_add(&dev1->list, &device_list); list_add(&dev2->list, &device_list); list_for_each_entry(dev, &device_list, list) { printk(KERN_INFO "Device ID: %d\n", dev->id); } return 0; } static void __exit list_iter_example_exit(void) { struct my_device *dev, *tmp; list_for_each_entry_safe(dev, tmp, &device_list, list) { list_del(&dev->list); kfree(dev); } } module_init(list_iter_example_init); module_exit(list_iter_example_exit); MODULE_LICENSE("GPL");
Thanks for your feedback!
Ask AI
Ask AI
Ask anything or try one of the suggested questions to begin our chat
Can you show me an example of how to define and use a `list_head` in a device driver?
What are some common helper macros for working with linked lists in the Linux kernel?
How do I safely add or remove elements from a kernel linked list?
Awesome!
Completion rate improved to 3.85
Kernel Data Structures for Drivers
Swipe to show menu
When writing device drivers in C, you will often need to manage collections of data, keep track of device states, and ensure efficient access to this information inside the kernel. The Linux kernel provides its own set of data structures for these purposes, with linked lists being one of the most fundamental. Unlike user space, where you might use standard library containers, kernel code relies on its own implementations for safety, performance, and flexibility. The most common structure for linked lists in the kernel is the list_head, which allows you to create doubly-linked lists that can be embedded within your own structures. This makes it easy to keep track of multiple devices, buffers, or requests in a clean and organized way.
kernel_list_example.c
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/list.h> struct my_device { int id; struct list_head list; }; static LIST_HEAD(device_list); static int __init list_example_init(void) { struct my_device *dev1, *dev2; dev1 = kmalloc(sizeof(*dev1), GFP_KERNEL); dev2 = kmalloc(sizeof(*dev2), GFP_KERNEL); dev1->id = 1; dev2->id = 2; INIT_LIST_HEAD(&dev1->list); INIT_LIST_HEAD(&dev2->list); list_add(&dev1->list, &device_list); list_add(&dev2->list, &device_list); printk(KERN_INFO "Devices added to list\n"); return 0; } static void __exit list_example_exit(void) { struct my_device *dev, *tmp; list_for_each_entry_safe(dev, tmp, &device_list, list) { list_del(&dev->list); kfree(dev); } printk(KERN_INFO "Devices removed from list\n"); } module_init(list_example_init); module_exit(list_example_exit); MODULE_LICENSE("GPL");
Linked lists, as seen in the example above, are extremely useful for device drivers because they allow you to dynamically add, remove, and traverse device-specific data structures without worrying about fixed array sizes or memory fragmentation. By embedding a list_head in your own structure, you can easily maintain a list of all active devices, pending I/O requests, or any similar collection. The kernel provides helper macros and functions to safely add, remove, and iterate over these lists, making your code more robust and maintainable.
kernel_list_iteration.c
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/list.h> struct my_device { int id; struct list_head list; }; static LIST_HEAD(device_list); static int __init list_iter_example_init(void) { struct my_device *dev1, *dev2, *dev; dev1 = kmalloc(sizeof(*dev1), GFP_KERNEL); dev2 = kmalloc(sizeof(*dev2), GFP_KERNEL); dev1->id = 10; dev2->id = 20; INIT_LIST_HEAD(&dev1->list); INIT_LIST_HEAD(&dev2->list); list_add(&dev1->list, &device_list); list_add(&dev2->list, &device_list); list_for_each_entry(dev, &device_list, list) { printk(KERN_INFO "Device ID: %d\n", dev->id); } return 0; } static void __exit list_iter_example_exit(void) { struct my_device *dev, *tmp; list_for_each_entry_safe(dev, tmp, &device_list, list) { list_del(&dev->list); kfree(dev); } } module_init(list_iter_example_init); module_exit(list_iter_example_exit); MODULE_LICENSE("GPL");
Thanks for your feedback!