Module I-7410 Advanced Linux Kernel Data Structures
Module I-7410 Advanced Linux Kernel Data Structures
Module I-7410 Advanced Linux Kernel Data Structures
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
Bern University of Applied Sciences<br />
Engineering and Information Technology<br />
<strong>Module</strong> I-<strong>7410</strong><br />
<strong>Advanced</strong> <strong>Linux</strong><br />
By Franz Meyer<br />
Version 1.4<br />
March 2012<br />
<strong>Kernel</strong> <strong>Data</strong><br />
<strong>Structures</strong>
Bern University of Applied Sciences<br />
School of Information Technology TI<br />
<strong>Module</strong>: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
Introduction to <strong>Linux</strong> <strong>Kernel</strong> Lists (1)<br />
Lists are very frequently used in operating system kernels to link data<br />
structures that represent all existing instances of various kernel<br />
objects such as<br />
Process descriptor objects<br />
File descriptor objects<br />
Memory regions<br />
For processes, for example, there are at least linked lists<br />
To link the process descriptors of all processes in the system<br />
To link the process descriptors of all runnable processes (run lists aka ready<br />
queue).<br />
Many lists in the <strong>Linux</strong> kernel are doubly linked using a header node<br />
List traversal in both directions<br />
Insertions at both ends: head (LIFO list), tail (FIFO list)<br />
Deletions are easy<br />
Introduction to <strong>Linux</strong> <strong>Kernel</strong> <strong>Data</strong> <strong>Structures</strong><br />
V1.4 © 2012 by franz.meyer@bfh.ch Slide-2
Bern University of Applied Sciences<br />
School of Information Technology TI<br />
Introduction to <strong>Linux</strong> <strong>Kernel</strong> <strong>Data</strong> <strong>Structures</strong><br />
<strong>Module</strong>: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
Introduction to <strong>Linux</strong> <strong>Kernel</strong> Lists (2)<br />
Basic <strong>Data</strong> Structure (defined in ):<br />
struct list_head {<br />
struct list_head *prev, *next;<br />
}<br />
The structure list_head is used throughout the <strong>Linux</strong> kernel for<br />
both list headers and list nodes in a kernel list.<br />
The structure list_head is often embedded in a larger structure<br />
(container).<br />
The pointers next and prev point to list_head structures not to<br />
the containers of the list_head structures.<br />
V1.4 © 2012 by franz.meyer@bfh.ch Slide-3
Bern University of Applied Sciences<br />
School of Information Technology TI<br />
Introduction to <strong>Linux</strong> <strong>Kernel</strong> <strong>Data</strong> <strong>Structures</strong><br />
<strong>Kernel</strong> List Header<br />
<strong>Module</strong>: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
List header<br />
to define and to initialize a list header use the macros LIST_HEAD(list_name)<br />
and LIST_HEAD_INIT(name) as well as the inline function INIT_LIST_HEAD()<br />
#define LIST_HEAD_INIT(name) { &(name), &(name) }<br />
#define LIST_HEAD(name) \<br />
struct list_head name = LIST_HEAD_INIT(name)<br />
static inline void<br />
INIT_LIST_HEAD(struct list_head *list) {<br />
list>next = list;<br />
list>prev = list;<br />
}<br />
List header<br />
struct list_head<br />
next<br />
prev<br />
V1.4 © 2012 by franz.meyer@bfh.ch Slide-4
Bern University of Applied Sciences<br />
School of Information Technology TI<br />
Introduction to <strong>Linux</strong> <strong>Kernel</strong> <strong>Data</strong> <strong>Structures</strong><br />
<strong>Kernel</strong> List<br />
<strong>Module</strong>: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
<strong>Kernel</strong> lists are<br />
Often circular<br />
List items include the list_head structure to establish a node in the list.<br />
The pointers next and prev in the list_head structure point to the other<br />
struct list_head structure rather than to the base address of the whole<br />
data structure<br />
struct S<br />
struct S<br />
struct<br />
list_head<br />
next<br />
prev<br />
List tail (last node)<br />
struct<br />
list_head<br />
next<br />
prev<br />
List header<br />
struct<br />
list_head<br />
next<br />
prev<br />
List head (first node)<br />
more<br />
list<br />
nodes<br />
V1.4 © 2012 by franz.meyer@bfh.ch Slide-5
Bern University of Applied Sciences<br />
School of Information Technology TI<br />
Introduction to <strong>Linux</strong> <strong>Kernel</strong> <strong>Data</strong> <strong>Structures</strong><br />
<strong>Kernel</strong> List Macros (1)<br />
<strong>Module</strong>: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
The macros come from file: usr/include/linux/list.h<br />
Macro Name Description<br />
list_add(n,p) Insert a new item pointed to by n right after the item<br />
specified by p. If p points to the list header, you insert<br />
the new item at the list head (beginning).<br />
list_add_tail(n,p) Insert a new item pointed to by n right before<br />
the item specified by p. If p points to the list header,<br />
you insert the new item at the list tail (end).<br />
del(p) Delete an item pointed to by p. Does not free memory<br />
belonging to node p.<br />
list_empty(p) Check if a list starting at the header given by pointer p<br />
is empty.<br />
V1.4 © 2012 by franz.meyer@bfh.ch Slide-6
Bern University of Applied Sciences<br />
School of Information Technology TI<br />
Introduction to <strong>Linux</strong> <strong>Kernel</strong> <strong>Data</strong> <strong>Structures</strong><br />
<strong>Kernel</strong> List Macros (2)<br />
<strong>Module</strong>: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
Macro Name Description<br />
list_entry(p,t,m) Return the address of the data structure of type t<br />
(the container). The list_head field in t has the<br />
name m and the address p.<br />
__list_for_each(p,h) Iterate over the list specified by the address<br />
of its header h. The iterator p is a pointer to the<br />
current list_head field. No pre-fetch.<br />
list_for_each(p,h) Iterator with pre-fetch of the the next element ptr.<br />
list_for_each_entry(p,h,m) Similar to list_for_each<br />
but the macro returns a pointer to the data<br />
structure that contains the list_head sub-<br />
structure in field m. Note: for kernel use only.<br />
list_for_each_entry_safe(p,p1,h,m) Safe iterator. Similar<br />
to list_for_each_entry but p1 specifies<br />
another pointer p as temporary storage<br />
V1.4 © 2012 by franz.meyer@bfh.ch Slide-7
Bern University of Applied Sciences<br />
School of Information Technology TI<br />
Introduction to <strong>Linux</strong> <strong>Kernel</strong> <strong>Data</strong> <strong>Structures</strong><br />
<strong>Kernel</strong> List Macros (3)<br />
<strong>Module</strong>: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
Example: Build a LIFO list (stack) and a FIFO list (queue)<br />
<strong>Data</strong> <strong>Structures</strong> and variables<br />
struct list_el { /* a list element */<br />
int id; /* a field */<br />
struct list_head link; /* the link field */<br />
}<br />
LIST_HEAD(hdr_lifo); /*define LIFO list header*/<br />
LIST_HEAD(hdr_fifo); /*define FIFO list header*/<br />
/* define some list elements */<br />
struct list_el lifo1, lifo2, fifo1, fifo2;<br />
V1.4 © 2012 by franz.meyer@bfh.ch Slide-8
Bern University of Applied Sciences<br />
School of Information Technology TI<br />
Introduction to <strong>Linux</strong> <strong>Kernel</strong> <strong>Data</strong> <strong>Structures</strong><br />
<strong>Kernel</strong> List Macros (4)<br />
<strong>Module</strong>: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
Example, cont: Build a LIFO list (stack) and a FIFO list (queue)<br />
Use macros to build a LIFO and a FIFO list<br />
/* the LIFO list (stack) */<br />
list_add(&lifo1.link, &hdr_lifo);<br />
list_add(&lifo2.link, &hdr_lifo);<br />
/* the FIFO list (queue) */<br />
list_add_tail(&fifo1.link, &hdr_fifo);<br />
list_add_tail(&fifo2.link, &hdr_fifo);<br />
V1.4 © 2012 by franz.meyer@bfh.ch Slide-9
Bern University of Applied Sciences<br />
School of Information Technology TI<br />
Introduction to <strong>Linux</strong> <strong>Kernel</strong> <strong>Data</strong> <strong>Structures</strong><br />
<strong>Kernel</strong> List Macros (5)<br />
<strong>Module</strong>: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
Example, cont: Get the address of the first element in the FIFO list<br />
struct list_el *ple;<br />
ple = list_entry(&hdr_fifo.next,struct list_el,link);<br />
Example, cont: Use simple iterator macro to count the number of<br />
elements in the FIFO list. You need not access fields in the elements.<br />
struct list_head *pln; /* iterator */<br />
int nItems = 0; /* number of elements */<br />
/*REMARK: Use this iterator for very short lists*/<br />
__list_for_each(pln, &hdr_fifo) {<br />
nItems++;<br />
}<br />
V1.4 © 2012 by franz.meyer@bfh.ch Slide-10
Bern University of Applied Sciences<br />
School of Information Technology TI<br />
Introduction to <strong>Linux</strong> <strong>Kernel</strong> <strong>Data</strong> <strong>Structures</strong><br />
<strong>Kernel</strong> List Macros (6)<br />
<strong>Module</strong>: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
Example, cont: Iterate safeley through the elements of the LIFO list<br />
and print the id field of each list element.<br />
struct list_el *ple, *ple1;<br />
list_for_each_entry_safe(ple,ple1,&hdr_lifo,link) {<br />
printf(“ple:%p id:%i\n”, ple, ple>id);<br />
}<br />
V1.4 © 2012 by franz.meyer@bfh.ch Slide-11
Berne University of Applied Sciences<br />
School of Information Technology HTI<br />
Course: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
Example: <strong>Module</strong> Representation in the <strong>Kernel</strong> (1)<br />
A module is represented by a struct module<br />
struct module {<br />
enum module_state state; /*LIVE,COMING,GOING*/<br />
struct list_head list; /*member list,head:modules*/<br />
char name[MODULE_NAME_LEN]; /* unique module name */<br />
...<br />
const struct kernel_symbol *syms; /*exported symbols*/<br />
unsigned int num_syms;<br />
const unsigned long *crcs; /*check sums on names*/<br />
/* GPLonly exported symbols. */<br />
const struct kernel_symbol *gpl_syms;<br />
unsigned int num_gpl_syms;<br />
const unsigned long *gpl_crcs;<br />
unsigned int num_exentries; /* Exception table */<br />
const struct exception_table_entry *extable;<br />
Introduction to <strong>Module</strong>s<br />
V1.5 © 2012 by franz.meyer@bfh.ch Slide-12
}<br />
Introduction to <strong>Module</strong>s<br />
Berne University of Applied Sciences<br />
School of Information Technology HTI<br />
Course: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
Example: <strong>Module</strong> Representation in the <strong>Kernel</strong> (2)<br />
struct module, cont<br />
int (*init)(void); /*Startup function*/<br />
void *module_init; /*If nonNULL,returned after init*/<br />
void *module_core; /*actual code + data*/<br />
unsigned long init_size, core_size;<br />
unsigned long init_text_size, core_text_size;<br />
struct mod_arch_specific arch;<br />
int unsafe; /* Am I unsafe to unload? */<br />
int license_gplok; /* Am I GPLcompatible */<br />
...<br />
struct list_head source_list; /*what depends on me*/<br />
struct list_head target_list; /*what do I depend on*/<br />
struct task_struct *waiter; /* Who is waiting for us*/<br />
void (*exit)(void); /*Destruction function. */<br />
char *args; /*command line args */<br />
V1.5 © 2012 by franz.meyer@bfh.ch Slide-13
Berne University of Applied Sciences<br />
School of Information Technology HTI<br />
Course: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
Example: <strong>Module</strong> Representation in the <strong>Kernel</strong> (3)<br />
<strong>Kernel</strong> <strong>Module</strong>s List<br />
struct list_head {<br />
struct list_head *next, *prev;<br />
}<br />
struct<br />
list_head<br />
list_head<br />
modules<br />
Introduction to <strong>Module</strong>s<br />
struct module<br />
state<br />
list_head list<br />
char name[]<br />
other<br />
fields<br />
struct module<br />
state<br />
list_head list<br />
char name[]<br />
other<br />
fields<br />
V1.5 © 2012 by franz.meyer@bfh.ch Slide-14
Berne University of Applied Sciences<br />
School of Information Technology HTI<br />
Course: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
Example: <strong>Module</strong> Representation in the <strong>Kernel</strong> (4)<br />
Representation of Dependencies<br />
struct module_use {<br />
struct list_head source_list, target_list;<br />
struct module *source, *target;<br />
}<br />
Example: <strong>Module</strong> msdos uses module vfat<br />
struct<br />
module<br />
struct<br />
module_use<br />
Introduction to <strong>Module</strong>s<br />
name=msdos<br />
list_head source_list<br />
list_head target_list<br />
list_head source_list<br />
list_head target_list<br />
struct module *source<br />
struct module *target<br />
name=vfat<br />
list_head source_list<br />
list_head target_list<br />
V1.5 © 2012 by franz.meyer@bfh.ch Slide-15
Berne University of Applied Sciences<br />
School of Information Technology HTI<br />
Course: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
Example: <strong>Module</strong> Representation in the <strong>Kernel</strong> (5)<br />
Code that produces module dependency: a uses b<br />
<strong>Module</strong> a is the source and module b is the target<br />
int add_module_usage(struct module *a, *b)<br />
{<br />
struct module_use *use;<br />
use = kmalloc(sizeof(struct module_use),GFP_ATOMIC);<br />
if (!use)<br />
return ENOMEM;<br />
use>source = a; use>target = b;<br />
list_add(&use>source_list, &b>source_list);<br />
list_add(&use>target_list, &a>target_list);<br />
return 0;<br />
}<br />
Introduction to <strong>Module</strong>s<br />
V1.5 © 2012 by franz.meyer@bfh.ch Slide-16
Bern University of Applied Sciences<br />
School of Information Technology TI<br />
Introduction to <strong>Linux</strong> <strong>Kernel</strong> <strong>Data</strong> <strong>Structures</strong><br />
<strong>Module</strong>: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
<strong>Kernel</strong> Queue – Exercise (1)<br />
Problem 1<br />
<strong>Kernel</strong> list exist in the kernel and are hidden to user space programs.<br />
To experiment with kernel lists it is suggested to write a kernel loadable<br />
module.<br />
Write a simple module in file klist.c that defines a data structure<br />
struct S with some simple fields like a numeric id, and with three list<br />
node fields (of type struct list_head). Define a few instances of<br />
the data structure S. For simplicity define an array of structures S to<br />
avoid dynamic memory allocation operations. Now link all instances of<br />
S by using the first list node field. Let this queue begin at a header<br />
variable (of type list_head) called head_all.<br />
Use the second and the third list node field to establish sub-queues<br />
formed by a sub-set of existing items S. For example, (1) link all nodes<br />
with an even node-id in ascending order starting at a header field called<br />
head_even, and (2) link all nodes with an odd node-id in descending<br />
order starting at a header field called head_odd.<br />
V1.4 © 2012 by franz.meyer@bfh.ch Slide-17
Bern University of Applied Sciences<br />
School of Information Technology TI<br />
Introduction to <strong>Linux</strong> <strong>Kernel</strong> <strong>Data</strong> <strong>Structures</strong><br />
<strong>Module</strong>: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
<strong>Kernel</strong> Lists – Exercise (2)<br />
Problem 1, cont.<br />
Use the macros introduced before to iterate over the lists described<br />
above in two rounds:<br />
(1) Iterate and count the number of elements in the list. To do that you<br />
need not access any fields of the structure S. What is the iterator?<br />
(2) Iterate and print various fields of the data structure S. What is the<br />
iterator?<br />
(3) Iterate through the substructures formed by nodes with even and<br />
odd node id.<br />
Write a make file to generate the .ko file (kernel object). The command<br />
$ make modules will generate the kernel object, and the command<br />
$ make modules_install will install the module in the directory<br />
/lib/modules//extra.<br />
Use the /sbin/modprobe or the /sbin/insmod utility to load the<br />
module. The utility rmmod or modprobe r unloads the module.<br />
V1.4 © 2012 by franz.meyer@bfh.ch Slide-18
Introduction to <strong>Module</strong>s<br />
Berne University of Applied Sciences<br />
School of Information Technology HTI<br />
<strong>Kernel</strong> Lists – Exercise (3)<br />
Course: <strong>Advanced</strong> <strong>Linux</strong><br />
FS-2012<br />
Problem 2<br />
Write a kernel module called list_modules.c that displays the kernel module<br />
list and possible dependencies, similar to the lsmod command. For each module<br />
in the list check to see if there are dependencies. If so, display all dependent<br />
modules. Recall that dependencies are associated with two lists: (1) list of used<br />
modules, and (2) list of modules that uses this module. Compare your output<br />
with the result of the lsmod command or of the cat /proc/modules command.<br />
Notes<br />
- Be careful with your list algorithm. If not correctly programmed your machine<br />
may hang.<br />
- The modules code is in file /usr/src/linux/kernel/module.c. Here, the<br />
module list variable (modules) is defined as static, which means that the<br />
variable is not visible in other kernel modules. To fix that write a global function<br />
void * get_modules() { return &modules; }<br />
EXPORT_SYMBOL(get_modules);<br />
Then recompile the kernel by: make uImage and install its image.<br />
- When you are accessing the module list, lock it first, and unlock it when you are<br />
done. Use the exported lock variable module_mutex for that purpose.<br />
- To test your program load the dependent modules hellomain and hellofunc<br />
of a previous exercise.<br />
V1.5 © 2012 by franz.meyer@bfh.ch Slide-19