Linux Kernel List, Freeing memory - c

I am currently learning some Linux Driver writing, and i try to implement list with the Linux Kernel list API.
My code just allocate a list and add 2 elements to it.
All go Ok until i try to free the memory i allocate, here i got a segmentation fault, and from what i test, it come from list_del call.
But i cannot see where i did wrong.
Here is my code :
struct drv_cdev{
int devno;
};
struct drv_dev_itf {
struct drv_cdev cdev; //DATA
struct list_head cdev_list;
};
struct drv_dev {
int number;
struct list_head list_master;
struct drv_dev_itf drv_dev_itf;
};
void add_node(struct drv_dev *dev, int num)
{
struct drv_dev_itf *new_cdev;
new_cdev = kmalloc(sizeof(struct drv_dev_itf*), GFP_KERNEL);
new_cdev->cdev.devno = num;
INIT_LIST_HEAD(&new_cdev->cdev_list);
list_add(&new_cdev->cdev_list, &dev->list_master);
}
void destroy_list(struct drv_dev *dev)
{
struct list_head *position;
struct drv_dev_itf *data_structure;
list_for_each (position, &dev->list_master) {
data_structure = list_entry(position, struct drv_dev_itf, cdev_list);
printk("Devno testing : %d\n", data_structure->cdev.devno);
//dev_node_release(driver_class, &data_structure->cdev);
list_del(position);
printk("List head deleted\n");
/*kfree(data_structure);
printk("List data_structure deleted\n");*/
}
}
static int __init test_init(void)
{
struct drv_dev *dev;
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
INIT_LIST_HEAD(&dev->list_master);
add_node(dev, 1);
add_node(dev, 2);
destroy_list(dev);
kfree(dev);
return 0;
}
Thanks in advance for your answers, have a nice day.

Related

Linux kernel linked lists - and sorting

I'm implementing some system calls which are mainly supposed to maintain a list of processes, and a list of open files with each process. However I'm having a hard time debugging the code, which requires recompiling over and over again.
Here are probably my main problems:
When and how can I initialize the list keeping the processes? Currently I'm checking if the list is empty before initializing but it doesn't work. I also tried head == head->prev->next but failed.
What's the correct way to call the list_sort considering the related 'compare' function? I'm getting the error
[ 1827.710802] BUG: unable to handle kernel paging request at fffff550
[ 1827.710808] IP: [] compare+0x8/0x20
[ 1827.710814] *pde = 00a32067 *pte = 00000000
This is the code. I'd really appreciate you reviewing it, especially the init system call whose correct behavior the others rely on.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/pid.h>
#include <linux/list.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/fdtable.h>
#include <linux/list_sort.h>
#include <linux/slab.h>
struct fileDescriptor {
int fd;
struct list_head list;
};
struct processInfo {
struct task_struct task;
int len_files;
struct fileDescriptor listHead;
struct list_head list;
};
struct processInfo listHead;
int compare(void* priv, struct list_head *a, struct list_head *b)
{
struct processInfo *p1 = container_of(a, struct processInfo, list);
struct processInfo *p2 = container_of(b, struct processInfo, list);
if (p1->task.pid > p2->task.pid) return -1;
else return 1;
}
asmlinkage long sys_init_process_list(pid_t p)
{
struct pid* pid;
struct task_struct *task;
struct files_struct *processFiles;
struct fdtable *filesTable;
struct processInfo *newProcess;
if(list_empty(&listHead.list))
{
printk("____list_empty_____\n");
INIT_LIST_HEAD(&listHead.list);
}
else
printk("____list_not_empty_____\n");
pid = find_get_pid(p);
if (pid == NULL)
{
sys_init_process_list(1);
return 1;
}
else
{
struct list_head *list;
struct task_struct *childTask;
struct fileDescriptor *newfd;
int i = 0;
task = pid_task(pid, PIDTYPE_PID);
newProcess = (struct processInfo*) kmalloc(sizeof(*newProcess), GFP_KERNEL);
//copy task structure
newProcess->task = *task;
//adding file descriptors
INIT_LIST_HEAD(&(newProcess->listHead).list);
processFiles = task->files;
filesTable = files_fdtable(processFiles);
while (filesTable->fd[i] != NULL)
{
newfd = (struct fileDescriptor*) kmalloc(sizeof(*newfd), GFP_KERNEL);
newfd->fd = i;
INIT_LIST_HEAD(&newfd->list);
list_add_tail(&(newfd->list), &(newProcess->listHead).list);
i++;
}
newProcess->len_files = i;
INIT_LIST_HEAD(&newProcess->list);
// add the new node to mylist
list_add_tail(&(newProcess->list), &(listHead.list));
//adding childern
list_for_each(list, &task->children)
{
childTask = list_entry(list, struct task_struct, sibling);
sys_init_process_list(childTask->pid);
}
return 0;
}
}
//////////////////////////////////////////
asmlinkage long sys_sort_process_list(void)
{
if(list_empty(&listHead.list))
{
printk("empty list\n");
return 1;
}
list_sort(NULL, &listHead.list, compare);
return 0;
}
////////////////////////////////////////
asmlinkage long sys_print_process_list(void)
{
struct processInfo *aProcess;
if (sys_sort_process_list())
{
printk("empty list\n");
return 1;
}
list_for_each_entry(aProcess, &listHead.list, list)
{
printk("%d, %d\n", (aProcess->task).pid, aProcess->len_files);
}
return 0;
}
//////////////////////////////////////////////////
asmlinkage long sys_clear_process_list(void)
{
struct processInfo *aProcess, *tmp;
if(list_empty(&listHead.list))
{
printk("empty list\n");
return 1;
}
printk("deleting the list");
list_for_each_entry_safe(aProcess, tmp, &listHead.list, list)
{
printk("freeing %d", (aProcess->task).pid);
list_del(&aProcess->list);
kfree(aProcess);
}
return 0;
}
EDIT: I managed to somehow solve my problem with 'static definition' which is done at compile time, namely I turned
struct processInfo listHead;
to
struct processInfo listHead =
{
.list = LIST_HEAD_INIT(listHead.list)
}
and now everything seems to work just fine. I'm not sure if this is the best way though, so I'm going to keep the question open so other possible solutions may be added.
Unlike to many other object, zero-initialization of linked list leaves it in invalid state. That is, none of linked list's functions can be used for zero-initialized list. Even list_empty one.
Proper initialization of linked list includes LIST_HEAD_INIT (as a struct initializer) or INIT_LIST_HEAD (at runtime).

Simplistic ADT queue implementation using provided issue

/****************************************************************************/
/* File: queue.h
*/
/****************************************************************************/
/****************************************************************************/
/* */
/* Simple Queue ADT */
/* */
/* Declaration */
/* */
/****************************************************************************/
typedef struct {
int key;
int value;
} data_t;
typedef struct queueNode {
struct queueNode *next, *prev;
data_t *data;
} QueueNode;
typedef struct queueType {
QueueNode *head;
QueueNode *tail;
} Queue;
/********************************************************************
Alright, so above I have a file provided for me called Queue.h, this makes sense to me in some respect as it gives data_t a pair of values (value and key) and stores that in a QueueNode, which is placed in either the Tail or Head of a queue.
The problem I'm having is that I DO NOT KNOW how to use this to create a Class called Queue.c that does the following functions:
voidinitQueue(Queue *self){
}
void enQueue(Queue *self, data_t *data){
}
QueueNode *frontNode(Queue *self){
}
data_t *frontValue(Queue *self){
}
data_t *dequeue(Queue *self){
}
void removeNode(queue *self, queueNode *p){
}
QueueNode *findNode(queue *self, data_t *data){
}
void printQ(queue *self, char *label){
}
With this (not meant to be altered) main():
/*
int main ()
{
Queue myQueue;
QueueNode *p;
data_t data[10], d2;
int i;
initQueue (&myQueue);
for (i = 0; i < 10; i++) {
data[i].key = i;
data[i].value = 10*i;
enQueue (&myQueue, &data[i]);
}
printQ (&myQueue, "MyQueue:" );
}
*/
Now I'm not going to ask anyone to do this for me, that doesn't help me at all in the long run, but I have absolutely no idea what to do.
I have a basic understanding of how a queue works, my problem is how to execute it. I'm also learning java in another class right now and it's begun to confuse me what rule apply to what class (as in school class, not java class)
If someone could walk me through how one's meant to work with a few of these (or at least initQueue) I'd be really grateful, Ive been working on this for 12 hours now and I'm getting desperate....
Edit:
Update: This is what i have now:
void initQueue(Queue *self)
{
self->head = NULL;
self->tail = NULL;
}
void enQueue(Queue *self, data_t *data)
{
self->head = data;
}

kernel crash for spinlock concurrency in linux-kernel

I want to clear a list which type is defined by Kernel. I have two main structs, num_wrapper and num. num_wapper has a list of num, and kernel crashs when I do the del_all_node() function.
I try to mark the list_del, and the kernel will not be crash. I don't understand why there will be crash problem since I have use spin_lock to protect this num_list.
Any tips will be appreciate.
The following is the simplified code.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/slab.h>
struct num_wrapper {
struct list_head num_list;
spinlock_t list_lock;
u8 check_num;
};
struct num {
struct list_head node;
int number;
struct num_wrapper* num_w_ptr;
};
s32 del_all_node(struct num_wrapper *number_wrap)
{
struct num *tmp;
struct num *num_head;
spin_lock(&number_wrap->list_lock);
list_for_each_entry_safe(num_head, tmp, &number_wrap->num_list, node) {
printk("num_head is %d\n", num_head->number);
list_del(&num_head->node);//this line seems to have problem
}
spin_unlock(&number_wrap->list_lock);
return 0;
}
static int __init hello_init(void)
{
/*Setup Scenario*/
struct num_wrapper *number_wrap = kzalloc(sizeof(struct num_wrapper)
, GFP_KERNEL);
struct num *number = kzalloc(sizeof(struct num), GFP_KERNEL);
number->number = 10;
number_wrap->check_num = 20;
INIT_LIST_HEAD(&number->node);
INIT_LIST_HEAD(&number_wrap->num_list);
list_add_tail(&number->node, &number_wrap->num_list);
del_all_node(number_wrap);
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Good, haha\n");
}
module_init(hello_init);
module_exit(hello_exit);
update
After doing some debug, I seems to find root cause...
my scenario is as follows :
I have a private data struct which is included in the net_device struct.
And the following is the simplified scenario:
struct xx_if *xx_if; //this is private data in net_device
struct xx_if *tmp;
list_for_each_entry_safe(xx_if, tmp, xx_if_wrap->if_list, list) {
free_netdev(xx_if->ndev);
list_del(&xx_if->list);
}
Since free_netdev will also free the private data xx_if, the code broken...
My fix is change the sequence to these two statements, and it fix the crash problem.
Still strange thing is I have check whether xx_if is NULL, but still lead to crash if I don't interchange these two statements.
I don't clearly understand following code:
INIT_LIST_HEAD(&number->node);
INIT_LIST_HEAD(&number_wrap->num_list);
list_add_tail(&number->node, &number_wrap->num_list);
You init two different structures, then you add one type of list to another type of list.
Is that the way you can do?
I think, that you need something like this:
struct num{
u8 check_num;
struct list_head list;
};
struct num_wrapper{
struct num* num_ptr;
spinlock_t list_lock;
};
int init_num_wrapper(struct num_wrapper** prt){
if(!ptr && *ptr){
return -EINVAL;
}
*ptr = kzalloc(sizeof(struct num_wrapper), GFP_KERNEL);
if(!*ptr){
return -ENOMEM;
}
INIT_LIST_HEAD(& (*ptr)->num_ptr->list);
... init spinlock
return 0;
}
int add_num(num_wrapper* prt_wrap, u8 check_num){
... checking pointers
struct num num* = NULL;
num = kmalloc(sizeof(struct num), GFP_KERNEL);
if(! num){
return -ENOMEM;
}
INIT_LIST_HEAD(&num->list);
num->check_num = check_num;
spin_lock(&prt_wrap->list_lock);
list_add_tail(&num->list, &prt_wrap->num_ptr.list);
spin_unlock(&prt_wrap->list_lock);
return 0;
}
int remove_all_nodes(num_wrapper* prt_wrap){
... checking pointer
struct num *tmp = NULL;
struct num *num_head = NULL;
spin_lock(&number_wrap->list_lock);
list_for_each_entry_safe(num_head, tmp, &prt_wrap->list, list)
{
printk("num_head is %d\n", num_head->number);
list_del(&num_head->node);//this line seems to have problem
}
spin_unlock(&num_wrapper->list_lock);
return 0;
}
Update
Then, you can use above functions for manipulating of num_wrapper.
For example:
//...
struct num_wrapper* nums = NULL;
init_num_wrapper(&nums); // after this call, you will have inited nums var, which can be used with others functions for manipulating with num_wrapper list.
u8 num = 2;
add_num(nums, num); // after this call new node with num will be added to num_wrapper
//...

Value of struct member changes after printing C

I got this code and a strange behaviour while printing the id member variable of node.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
int id;
int visited;
// struct node *neighbors_[];
};
struct graph
{
struct node nodes[26];
int adjMat[26][26];
};
struct stack_item
{
struct node node;
struct stack_item *next_;
};
struct myStack
{
struct stack_item *anfang_;
};
void initGraph(struct graph *graph_);
void push(struct myStack *stack_, struct node node);
int main()
{
struct graph graph;
struct myStack stack;
char ausgabe[26]="";
initGraph(&graph);
//READ DATA
char line[200];
int firstTime=1,first;
first=0;
push(&stack,graph.nodes[first]);
printf("ID %i\n",stack.anfang_->node.id);
printf("ID %i\n",stack.anfang_->node.id);
//FINISHED DATA READING
//CALL DFS
//dfs(graph,stack,ausgabe);
}
void push(struct myStack *stack_, struct node node)
{
struct stack_item item;
item.node=node;
item.next_=stack_->anfang_;
stack_->anfang_=&item;
}
void initGraph(struct graph *graph_)
{
int i,j;
for(i=0; i<26; i++)
{
struct node node= {i,0};
graph_->nodes[i]=node;
for(j=0; j<26; j++)
{
graph_->adjMat[i][j]=0;
}
}
}
If i execute this, the first print command leads to 'ID 0',the second to 'ID 1980796117'. How can this value change by printing it? Could please anyone help me, i've got really no idea!
void push(struct myStack *stack_, struct node node)
{
struct stack_item item;
item.node=node;
item.next_=stack_->anfang_;
/* BAD! */
stack_->anfang_=&item;
}
item is a local variable which, when the push function returns, goes out of scope. Any existing pointers which refer to this object are now invalid, and dereferencing it results in undefined behavior.
You will need to dynamically allocate item (i.e., malloc) if you need it to persist once the function has returned.

Difference between LIST_HEAD_INIT and INIT_LIST_HEAD

I'm trying to understand the Linux kernel linked list API.
According to Linux Kernel Linked List I should initialize the list head by INIT_LIST_HEAD but here (Linux Kernel Program) it's suggested to use LIST_HEAD_INIT instead.
Here's a working code I wrote, but I'm not sure if I did it in proper way. Could someone verify that it's OK?
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
typedef struct edge_attr {
int d;
struct list_head list;
} edge_attributes_t;
typedef struct edge {
int id;
edge_attributes_t *attributes;
} edge_t;
int main () {
int i;
struct list_head *pos;
edge_attributes_t *elem;
edge_t *a = (edge_t*)malloc(sizeof(edge_t));
a->id = 12;
a->attributes = (edge_attributes_t*) malloc(sizeof(edge_attributes_t));
INIT_LIST_HEAD(&a->attributes->list);
for (i=0; i<5; ++i) {
elem = (edge_attributes_t*)malloc(sizeof(edge_attributes_t));
elem->d = i;
list_add(&elem->list, &a->attributes->list);
}
list_for_each(pos, &(a->attributes->list)) {
elem = list_entry(pos, edge_attributes_t, list);
printf("%d \n", elem->d);
}
return 0;
}
LIST_HEAD_INIT is a static initializer, INIT_LIST_HEAD is a function. They both initialise a list_head to be empty.
If you are statically declaring a list_head, you should use LIST_HEAD_INIT, eg:
static struct list_head mylist = LIST_HEAD_INIT(mylist);
You should use INIT_LIST_HEAD() for a list head that is dynamically allocated, usually part of another structure. There are many examples in the kernel source.
A quick LXR search shows:
#define LIST_HEAD_INIT(name) { &(name), &(name) }
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
So INIT_LIST_HEAD gets a struct list_head * and initializes it, while LIST_HEAD_INIT returns the address of the passed pointer in a suitable fashioned for use as an initializer for a list:
struct list_head lst1;
/* .... */
INIT_LIST_HEAD(&lst1);
struct list_head lst2 = LIST_HEAD_INIT(lst2);

Resources