Kernel list_for_each_safe use

Keywords: Linux Makefile

I'm a beginner. I've been learning the course of national inlay. I used to take notes on the book. Today I learned the kernel list. The teacher left a small problem. I did it myself. It's my experience
You must not laugh
The source program is as follows:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/list.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Xie");
MODULE_DESCRIPTION("List Module");
MODULE_ALIAS("List module");
struct student {
    char name[100];
    int num;
    struct list_head list;
};
struct student *pstudent;
struct student *tmp_student;
struct list_head student_list;
struct list_head *pos, *node; //add node
int mylist_init() {
    int i=0;
    INIT_LIST_HEAD(&student_list);

    pstudent = kmalloc(sizeof(struct student)*5, GFP_KERNEL);
    memset(pstudent, 0, sizeof(struct student)*5);
    
    for (i=0; i<5; i++) {
        sprintf(pstudent[i].name, "Student%d", i+1);
        pstudent[i].num = i+1;
        list_add(&(pstudent[i].list), &student_list);
    }

    list_for_each(pos, &student_list) {
        tmp_student = list_entry(pos, struct student, list);
        printk("<0>student %d name: %s\n", tmp_student->num, tmp_student->name);
    }
    
    return 0;
}

void mylist_exit() {
    int i;
    /*Experiment: change for to list_for_each to traverse the deleted node, observe the phenomenon to occur, and consider solutions */
    for (i=0; i<5; i++) {
        list_del(&(pstudent[i].list));
    
    kfree(pstudent);
}

module_init(mylist_init);
module_exit(mylist_exit);

The contents of the makefile file are as follows / / by the way, review the basic knowledge of the module. There are so many things about linux. It seems that the embedded system has a long way to go

ifneq ($(KERNELRELEASE),)
    obj-m := mylist.o
else
    KDIR := /lib/modules/2.6.18-53.el5/build
    all:
        make -C $(KDIR) M=$(PWD) modules
    clean:
        rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif

According to the thinking questions left by the teacher:
If it's a list_for_each traverses the delete node, and I start with the following changes
void mylist_exit()

 list_ for_ each(pos,&student_ List); / / what's written here is really a mess. Anyway, the situation is a crash,
    list_ del(&student_ List); / / the format here is not correct, list_ for_ The prototype of list is for, and then the statement is {}. Here
kfree(pstudent); / / none. In addition, use list_ Only when the entry mentions data can it traverse the operation
}
In a word, it's been a crash. Later, I also changed some formats. It's still a crash. I asked my friends in the group to use the list_for_list_safe can be deleted safely
So I went to G and found that:
Function prototype analysis

#define list_for_each(pos, head) \
for (pos = (head)->next; prefetch(pos->next), pos != (head); \
pos = pos->next)

By definition, list_ Del (pos) (point the front and back pointer of pos to the undefined state) panel, list_ del_ Init (pos) (the pointer before and after pos points to itself) causes a dead cycle. - when deleting, the list pointer becomes a special type, so it crashes

#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)

It can be seen from the definition that the safe function first caches the post pointer of pos to n, processes a process and then assigns it back to pos, avoiding this situation.
Therefore, the former can be used when only traversing the linked list and not deleting nodes. If there is any operation to delete nodes, the latter should be used.

According to the description of safe, it is specially prepared for deleting nodes: iterate over a list safe against removal of list entry.
Other processes with safe are also based on this reason.

Changes are made below
The modification procedure is as follows:
First, define a node pointer of the same type as pos to save the post pointer of pos
Then modify exit_ The mylist function is modified as follows:

void mylist_exit()
{ 
     //int i ;
     /* Experiment: change for to list_for_each to traverse the delete node, observe the phenomenon to occur, and consider solutions */
     //for(i=0;i<5;i++)
     list_for_each_safe(pos,node,&student_list)
     {
        //list_del(&(pstudent[i].list));
        tmp_student = list_entry(pos,struct student,list);//Extracting data, I don't know at first, ah
        list_del(&(tmp_student->list));
        printk("<0>student %d name: %s is being deleted.\n",tmp_student->num,tmp_student->name);
     }
 
     kfree(pstudent);
}

In this way, there will be no crash

Posted by nonphixion on Fri, 19 Jun 2020 04:00:00 -0700