19.02.2013 Views

Module I-7410 Advanced Linux Kernel Data Structures

Module I-7410 Advanced Linux Kernel Data Structures

Module I-7410 Advanced Linux Kernel Data Structures

SHOW MORE
SHOW LESS

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 />

/* GPL­only 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 non­NULL,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 GPL­compatible */<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 hello­main and hello­func<br />

of a previous exercise.<br />

V1.5 © 2012 by franz.meyer@bfh.ch Slide-19

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!