8. Kernel Data Structures¶
- Kernel gives you linked list and red black tree implementations.
- You need not code your own linked list for your code.
- The linked list is extensively used by the kernel.
- Red Black tree is used in the Completely Fair Schedular.
8.1. Using Kernel’s linked list for your data structure¶
Let us write a small application.
The application will show the kernel’s linked list in a graphical way. How can we do it.
What we will do
- We will implement the kernel linked list.
- We will give a proc interface to user. When the user write’s
add [int]to the file we will add it to the linked list. - Writing
delete [int]will delete the node with the provided value from the linked list. - Writing
printwill print the whole linked list. The list can be viewed through thedmesgcommand.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | /*
* <PD> Program for linked list manipulation using proc </PD>
*/
#include "ll.h"
struct list_head todo_list;
int todo_add_entry(int number)
{
struct todo_struct *new_node = kmalloc((size_t) (sizeof(struct todo_struct)), GFP_KERNEL);
if (!new_node) {
printk(KERN_INFO
"Memory allocation failed, this should never fail due to GFP_KERNEL flag\n");
return 1;
}
new_node->priority = number;
list_add_tail(&(new_node->list), &todo_list);
return 0;
}
void show_list(void)
{
struct todo_struct *entry = NULL;
list_for_each_entry(entry, &todo_list, list) {
printk(KERN_INFO "Node is %d\n", entry->priority);
}
}
int delete_node(int number)
{
struct todo_struct *entry = NULL;
list_for_each_entry(entry, &todo_list, list) {
if (entry->priority == number) {
printk(KERN_INFO "Found the element %d\n",
entry->priority);
list_del(&(entry->list));
kfree(entry);
return 0;
}
}
printk(KERN_INFO "Could not find the element %d\n", number);
return 1;
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #include <linux/module.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#ifndef LL_H
#define LL_H
#define NODE "driver/mmmod"
/*
* Linked List Node
*/
struct todo_struct {
struct list_head list;
int priority;
};
/*
* Linked list related functions
*/
void show_list(void);
int todo_add_entry(int);
/*
* Proc Interface related function
*/
void proc_cleanup(void);
int ll_proc_init (void);
int configure_proc_entry(void);
ssize_t my_proc_read (struct file *filp,char *buf,size_t count,loff_t *offp );
ssize_t my_proc_write(struct file *filp, const char __user * buffer, size_t count, loff_t *pos);
int configure_proc_entry(void);
int delete_node (int);
void destroy(void);
#endif
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | /*
* Module to show how to use the kernel linked list for managing data
* 1. Add node to linked list
* 2. Print the list
* 3. Delete nodes from the list
* The modules exposes a /proc interface on which if you cat
* 1. add 5 -- it adds five
* 2. print -- it prints the linked list
* 3. delete 5 -- it deletes the node in the linked list
* 4. destroy -- destroys the whole linked list
*/
#include "ll.h"
extern struct proc_dir_entry *proc;
extern struct list_head todo_list;
static int __init my_init(void)
{
printk(KERN_INFO "Hello from Linked List Module");
if (ll_proc_init()) {
printk(KERN_INFO "Falied to create the proc interface");
return -EFAULT;
}
INIT_LIST_HEAD(&todo_list);
return 0;
}
static void __exit my_exit(void)
{
if (proc) {
proc_cleanup();
pr_info("Removed the entry");
}
printk(KERN_INFO "Bye from Hello Module");
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("abr");
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | // Module to make a read entry in the proc file system.
// Module to write a command line calculator
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/types.h>
#include "ll.h"
struct proc_dir_entry *proc;
int len,temp;
char *msg;
#define PROC_NAME "linked_list"
ssize_t my_proc_write(struct file *filp, const char __user * buffer, size_t count, loff_t *pos)
{
char *str;
char command[20];
int val = 0;
printk("Calling Proc Write");
str = kmalloc((size_t) count, GFP_KERNEL);
if (copy_from_user(str, buffer, count)) {
kfree(str);
return -EFAULT;
}
sscanf(str, "%s %d", command, &val);
printk("First Arguement %s\n", command);
printk("Second Argument %d\n", val);
if (!strcmp(command, "add")) {
/* Add node */
printk(KERN_INFO "Adding data to linked list %d\n", val);
todo_add_entry(val);
}
if (!strcmp(command, "delete")) {
/* Delete Node */
printk(KERN_INFO "Deleting node from linked list %d\n", val);
if (delete_node(val)) {
printk(KERN_INFO "Delete failed \n");
}
}
if (!strcmp(command, "print")) {
/* Print the linked list */
printk(KERN_INFO "Printing the linked list\n");
show_list();
}
kfree(str);
return count;
}
ssize_t my_proc_read (struct file *filp,char *buf,size_t count,loff_t *offp )
{
char *data;
int err;
data=PDE_DATA(file_inode(filp));
if(!(data)){
printk(KERN_INFO "Null data");
return 0;
}
if(count>temp) {
count=temp;
}
temp=temp-count;
err = copy_to_user(buf,data, count);
if (err) {
printk(KERN_INFO "Error in copying data.");
}
if(count==0) {
temp=len;
}
return count;
}
struct file_operations proc_fops = {
.read = my_proc_read,
.write = my_proc_write,
};
int create_new_proc_entry(void) {
msg="Hello World";
proc=proc_create_data(PROC_NAME, 0666, NULL, &proc_fops, msg);
len=strlen(msg);
temp=len;
if (proc) {
return 0;
} else {
return -1;
}
}
int ll_proc_init (void) {
create_new_proc_entry();
return 0;
}
void proc_cleanup(void) {
remove_proc_entry("hello", NULL);
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
obj-m += ll_module.o
obj-m += ll_proc.o
obj-m += ll.o
obj-m += ll_driver.o
ll_driver-objs := ll_module.o ll_proc.o ll.o
export KROOT=/lib/modules/$(shell uname -r)/build
#export KROOT=/lib/modules/$(uname)3.2.0-23-generic/build
allofit: modules
modules: clean
@$(MAKE) -C $(KROOT) M=$(PWD) modules
modules_install:
@$(MAKE) -C $(KROOT) M=$(PWD) modules_install
kernel_clean:
@$(MAKE) -C $(KROOT) M=$(PWD) clean
clean: kernel_clean
rm -rf Module.symvers modules.order
insert: modules
sudo dmesg -c
sudo insmod ll_driver.ko
remove: clean
sudo rmmod ll_driver.ko
|
8.2. Examples¶
- Lets just print the empty list.
echo "print" > /proc/linked_list
root@lkw:~/doc_linux_kernel_workbook/doc/code/07_data_structures/01_ll# dmesg
[ 578.782533] ll_driver: module verification failed: signature and/or required key missing - tainting kernel
[ 578.783117] Hello from Linked List Module
[ 630.344370] Calling Proc Write
[ 630.344376] First Arguement print
[ 630.344378] Second Argument 0
[ 630.344380] Printing the linked list
- Now let us add some nodes.
root@lkw:~/doc_linux_kernel_workbook/doc/code/07_data_structures/01_ll# echo "add 10" > /proc/linked_list
root@lkw:~/doc_linux_kernel_workbook/doc/code/07_data_structures/01_ll# echo "add 20" > /proc/linked_list
root@lkw:~/doc_linux_kernel_workbook/doc/code/07_data_structures/01_ll# echo "add 30" > /proc/linked_list
root@lkw:~/doc_linux_kernel_workbook/doc/code/07_data_structures/01_ll# dmesg
[ 578.782533] ll_driver: module verification failed: signature and/or required key missing - tainting kernel
[ 578.783117] Hello from Linked List Module
[ 630.344370] Calling Proc Write
[ 630.344376] First Arguement print
[ 630.344378] Second Argument 0
[ 630.344380] Printing the linked list
[ 642.095630] Calling Proc WriteFirst Arguement add
[ 642.095638] Second Argument 10
[ 642.095640] Adding data to linked list 10
[ 645.399251] Calling Proc WriteFirst Arguement add
[ 645.399256] Second Argument 20
[ 645.399257] Adding data to linked list 20
[ 647.542762] Calling Proc WriteFirst Arguement add
[ 647.542767] Second Argument 30
[ 647.542768] Adding data to linked list 30
- Let us print again.
root@lkw:~/doc_linux_kernel_workbook/doc/code/07_data_structures/01_ll# echo "print" > /proc/linked_list
- Let us delete some nodes.
root@lkw:~/doc_linux_kernel_workbook/doc/code/07_data_structures/01_ll# echo "delete 30" > /proc/linked_list
- Let us delete a non existent node.
root@lkw:~/doc_linux_kernel_workbook/doc/code/07_data_structures/01_ll# echo "delete 0" > /proc/linked_list
- Delete more node.
root@lkw:~/doc_linux_kernel_workbook/doc/code/07_data_structures/01_ll# echo "delete 10" > /proc/linked_list
- Print.
root@lkw:~/doc_linux_kernel_workbook/doc/code/07_data_structures/01_ll# echo "print" > /proc/linked_list
- Check the
dmesgcommands output.
root@lkw:~/doc_linux_kernel_workbook/doc/code/07_data_structures/01_ll# dmesg
[ 578.782533] ll_driver: module verification failed: signature and/or required key missing - tainting kernel
[ 578.783117] Hello from Linked List Module
[ 630.344370] Calling Proc Write
[ 630.344376] First Arguement print
[ 630.344378] Second Argument 0
[ 630.344380] Printing the linked list
[ 642.095630] Calling Proc WriteFirst Arguement add
[ 642.095638] Second Argument 10
[ 642.095640] Adding data to linked list 10
[ 645.399251] Calling Proc WriteFirst Arguement add
[ 645.399256] Second Argument 20
[ 645.399257] Adding data to linked list 20
[ 647.542762] Calling Proc WriteFirst Arguement add
[ 647.542767] Second Argument 30
[ 647.542768] Adding data to linked list 30
[ 653.222910] Calling Proc WriteFirst Arguement print
[ 653.222916] Second Argument 0
[ 653.222918] Printing the linked list
[ 653.222919] Node is 10
[ 653.222920] Node is 20
[ 653.222921] Node is 30
[ 659.727435] Calling Proc WriteFirst Arguement delete
[ 659.727440] Second Argument 30
[ 659.727442] Deleting node from linked list 30
[ 659.727443] Found the element 30
[ 665.175263] Calling Proc WriteFirst Arguement delete
[ 665.175274] Second Argument 0
[ 665.175277] Deleting node from linked list 0
[ 665.175281] Could not find the element 0
[ 665.175282] Delete failed
[ 667.134783] Calling Proc WriteFirst Arguement delete
[ 667.134789] Second Argument 10
[ 667.134791] Deleting node from linked list 10
[ 667.134792] Found the element 10
[ 668.942912] Calling Proc WriteFirst Arguement print
[ 668.942917] Second Argument 0
[ 668.942919] Printing the linked list
[ 668.942920] Node is 20