本例通过/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