Linux read proc file seq

  

In linux through the proc file system for user state and kernel state interaction or kernel fine-tuning are a relatively simple and effective means. Recently, due to project needs, you need to output the data of a kernel module to the user mode through proc, and take the opportunity to learn seq_file. Make a simple record here, and the wrong place is welcome to criticize and correct. To use seq_file, you need #include

Ok, no more nonsense, let's get started, ^_^. Suppose, in one of our kernel modules, there is a set of data stored in iterable data structures (such as linked lists, arrays, etc.), I want to output them to the user state through proc, and view them through cat, etc. How to do it. For the sake of simplicity, suppose we have a linked list of data, the head of the linked list is pointed to by a variable called list_head, which itself is protected with a read-write spin lock. The structure of a linked list node is as follows:

struct node{

struct node *next;

int num;

};

Struct node* list_head;//chain table header

DEFINE_RWLOCK(list_lock);//Define and initialize a read-write spin lock.

seq_file defines a set of function pointers for iteration, which functions like a forward iterator in C++, but with a member called show for outputting node information. This set of function pointers is declared in a structure called struct seq_operations as follows:

struct seq_operations {

void * (*start) (struct seq_file *m, loff_t *pos);

void (*stop) (struct seq_file *m, void *v);

void * (*next) (struct seq_file *m, void *v, loff_t *pos); Br>

int (*show) (struct seq_file *m, void *v);

};

start can do some resource acquisition and initialization work, quite c++ constructor The role, its return value will be passed to them as the second parameter of the first call show and next, then each time will call next, and show; start if return NULL, then directly call stop will not call show and Next. If there are some headers to output, you can return to the SEQ_START_TOKEN kernel. It is defined as:

#define SEQ_START_TOKEN ((void *)1)

The return value of next will be used as the show and the next call. The second argument of next (that is, v) is passed to them, and when next returns NULL, stop is called.

The role of stop is similar to the role of destructors in c++ classes, responsible for resource cleanup and return operations.

The show function returns 0 correctly, and the error returns the corresponding error code.

Note that the output information is larger than the buffer allocated by the kernel at a time (such as the specific reason, the next time you write about the implementation of seq_read and other functions, it will be clear at the time) start, show, next , stop may be called multiple times, which requires the third parameter pos of start and next to distinguish them. So their order of invocation can be described as follows: start->show->next->show->next->show->...->next->stop.

Note that it may also be as follows (start stop call multiple times): start->show->next->show->next->show->...->next- >stop->start->show->next...->next->stop. These iterative functions can be defined in our example as follows:

static void * my_start(struct seq_file*m, l loff_t *pos)

{

int i = 1;

struct node* tmp_entry;

read_lock_bh(list_lock);//Get a read-write spin lock

if(*pos==0){

return SEQ_START_TOKEN;

}

for(tmp_entry = list_head;tmp_entry != NULL; tmp_entry=tmp-entry->next){

if(i ==*pos)

return tmp_entry;

++i;

}

return NULL;

}

static void my_stop (struct seq_file *m, void *v)

{

read_unlock_bh(tmp_lock);//release spin lock

seq_printf(m, "\ \ -------------data information end---------------------------" ;);

}

static void * my_next(struct seq_file *m, void *v, loff_t *pos)

{

++* Pos;

return (SEQ_START_TOKEN==v)?list_head:((struct node*)v)-&g t;next;

}

static int my_show(struct seq_file *m, void *v)

{

struct node* tmp_entry;

static int line_count= 0;

if(SEQ_START_TOKEN==v){

seq_printf(m,"\ \ ---------- ---data informations start---------------------------\ \ ");

}else{< Br>

tmp_entry = (struct node*)v;

seq_file(m," %d ",tmp_entry->num);

if(++line_count= =10){//One line outputs ten data

seq_printf(m,"\ ");

line_count=0;

}

}

return 0;

}

Then, define a struct seq_operations as follows:

static const struct seq_operations my_seq_ops={

.start = my_start,

.next = my_next,

.stop = my_stop,

.show = my_show,

};

At this point, we also need to define a function to output the address of my_seq_ops to the kernel. As follows,

static int proc_my_test_open((struct inode *inode, struct file *file)

{

return seq_open(file,&my_seq_ops);

}

Finally define a struct file_operations structure, our proc_my_test_open is passed to the kernel, and proc_create is called, creating a proc directory and you're done. The code is as follows:

static const struct file_operations my_file_ops={

.owner = THIS_MODULE,

.open = proc_my_test_open,

.read = seq_read,< Br>

.llseek = seq_lseek,

.release = seq_release,

};

my_file_opsproc_create("my_test", 0, NULL, &my_file_ops) ;

In fact, for simple output, you can simply define a show function and then through single_open instead of our seq_open here, this method is relatively simple, the specific method can be google.

Copyright © Windows knowledge All Rights Reserved