3、使用seq_file接口的例子
本例通过/proc/seq_file_test文件输出Linux内核的十个随机数,并与printk打印的信息进行比较。
(1)、例子源代码
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/random.h>
- #include <linux/slab.h>
- #include <linux/proc_fs.h>
- #include <linux/seq_file.h>
- #include <linux/list.h>
- struct mylist_random {
- struct list_head list;
- char info[50];
- };
- static LIST_HEAD(test_list);
- static void *seq_start(struct seq_file *m, loff_t *pos)
- {
- return seq_list_start(&test_list, *pos);;
- }
- static void seq_stop(struct seq_file *m, void *v)
- {
- /* No cleanup needed in this example */
- }
- static void *seq_next(struct seq_file *m, void *v, loff_t *pos)
- {
- return seq_list_next(v, &test_list, pos);
- }
- static int seq_show(struct seq_file *m, void *v)
- {
- const struct mylist_random *p = list_entry(v, struct mylist_random, list);
- seq_printf(m, "%s", p->info);
- return 0;
- }
- static const struct seq_operations seq_test_ops = {
- .start = seq_start,
- .next = seq_next,
- .stop = seq_stop,
- .show = seq_show,
- };
- static int seq_test_open(struct inode *inode, struct file *file)
- {
- return seq_open(file, &seq_test_ops);
- }
- static const struct file_operations seq_test_fops = {
- .owner = THIS_MODULE,
- .open = seq_test_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
- };
- static int __init seq_test_init(void)
- {
- int i, count;
- struct mylist_random *mylist_node;
- struct proc_dir_entry *p;
- p = proc_create("seq_file_test", S_IRUGO, NULL, &seq_test_fops);
- if (!p)
- goto out;
- for(i = 0; i < 10; i++) {
- mylist_node = kmalloc(sizeof(struct mylist_random), GFP_ATOMIC);
- if (!mylist_node)
- return -ENOMEM;
- memset(mylist_node, 0, sizeof(struct mylist_random));
- get_random_bytes(&count, sizeof(int));
- sprintf(mylist_node->info, "random number %d: %d\n", i, count);
- printk("%s", mylist_node->info);
- list_add_tail(&mylist_node->list, &test_list);
- }
- return 0;
- out:
- remove_proc_entry("seq_file_test", NULL);
- return -EFAULT;
- }
- static void __exit seq_test_exit(void)
- {
- struct list_head *p, *q;
- struct mylist_random *mylist_node;
- list_for_each_safe(p, q, &test_list) {
- mylist_node = list_entry(p, struct mylist_random, list);
- list_del(p);
- kfree(mylist_node);
- }
- remove_proc_entry("seq_file_test", NULL);
- }
- module_init(seq_test_init);
- module_exit(seq_test_exit);
- MODULE_AUTHOR("Richard Tang <tanglinux@gmail.com>");
- MODULE_LICENSE("GPL");
#include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/random.h> #include <linux/slab.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/list.h> struct mylist_random { struct list_head list; char info[50]; }; static LIST_HEAD(test_list); static void *seq_start(struct seq_file *m, loff_t *pos) { return seq_list_start(&test_list, *pos);; } static void seq_stop(struct seq_file *m, void *v) { /* No cleanup needed in this example */ } static void *seq_next(struct seq_file *m, void *v, loff_t *pos) { return seq_list_next(v, &test_list, pos); } static int seq_show(struct seq_file *m, void *v) { const struct mylist_random *p = list_entry(v, struct mylist_random, list); seq_printf(m, "%s", p->info); return 0; } static const struct seq_operations seq_test_ops = { .start = seq_start, .next = seq_next, .stop = seq_stop, .show = seq_show, }; static int seq_test_open(struct inode *inode, struct file *file) { return seq_open(file, &seq_test_ops); } static const struct file_operations seq_test_fops = { .owner = THIS_MODULE, .open = seq_test_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; static int __init seq_test_init(void) { int i, count; struct mylist_random *mylist_node; struct proc_dir_entry *p; p = proc_create("seq_file_test", S_IRUGO, NULL, &seq_test_fops); if (!p) goto out; for(i = 0; i < 10; i++) { mylist_node = kmalloc(sizeof(struct mylist_random), GFP_ATOMIC); if (!mylist_node) return -ENOMEM; memset(mylist_node, 0, sizeof(struct mylist_random)); get_random_bytes(&count, sizeof(int)); sprintf(mylist_node->info, "random number %d: %d\n", i, count); printk("%s", mylist_node->info); list_add_tail(&mylist_node->list, &test_list); } return 0; out: remove_proc_entry("seq_file_test", NULL); return -EFAULT; } static void __exit seq_test_exit(void) { struct list_head *p, *q; struct mylist_random *mylist_node; list_for_each_safe(p, q, &test_list) { mylist_node = list_entry(p, struct mylist_random, list); list_del(p); kfree(mylist_node); } remove_proc_entry("seq_file_test", NULL); } module_init(seq_test_init); module_exit(seq_test_exit); MODULE_AUTHOR("Richard Tang <tanglinux@gmail.com>"); MODULE_LICENSE("GPL");
(2)、编译、执行
- //获得Ubuntu 11.04正在运行的内核版本
- $ cat /proc/version
- Linux version 2.6.38-13-generic (buildd@palmer) (gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4) ) #54-Ubuntu SMP Tue Jan 3 13:44:52 UTC 2012
- //根据上面获得的信息,在Makefile中指定Ubuntu 11.04的内核源码目录为/usr/src/linux-headers-2.6.38-13-generic/
- # Makefile
- KERN_DIR = /usr/src/linux-headers-2.6.38-13-generic/
- all:
- make -C $(KERN_DIR) M=`pwd` modules
- clean:
- make -C $(KERN_DIR) M=`pwd` modules clean
- obj-m += seq_file_test.o
- //编译,并把编译好的模块seq_file_test.ko加载到内核中
- $ make
- $ sudo insmod seq_file_test.ko
- //测试并比较采用以下两种不同方式输出的随机数
- $ cat /proc/seq_file_test
- random number 0: -1742888248
- random number 1: 764069878
- random number 2: -2023358059
- random number 3: 663883285
- random number 4: -1811369789
- random number 5: -568958269
- random number 6: 606443186
- random number 7: -2108607843
- random number 8: 762957660
- random number 9: -2142996661
- $ dmesg | tail -10
- [ 2186.806122] random number 0: -1742888248
- [ 2186.806436] random number 1: 764069878
- [ 2186.806448] random number 2: -2023358059
- [ 2186.806454] random number 3: 663883285
- [ 2186.806464] random number 4: -1811369789
- [ 2186.806470] random number 5: -568958269
- [ 2186.806488] random number 6: 606443186
- [ 2186.806493] random number 7: -2108607843
- [ 2186.806503] random number 8: 762957660
- [ 2186.806509] random number 9: -2142996661