2

我正在研究一个linux内核,所以我尝试编写一个简单的模块。

以下代码应该控制调用read()的次数:/proc/proc_test

#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
#include <asm/current.h>

static int __init init(void);
static void __exit stop(void);
static int proc_read(char *buffer, char **start, off_t offset, int size, int *eof, void *data);

static int counter = 0;

static int proc_read(char *buffer, char **start, off_t offset, int size, int *eof, void *data) {
    if (size < 256) return -ENOMEM;
    return sprintf(buffer, "counter = %d\n", counter++); <-- supposed to be incremented once
}

static int __init init() {
    if (create_proc_read_entry("proc_test", 0, NULL, proc_read, NULL) == 0) {
        printk(KERN_ERR "Can not creat entry\n");
        return -ENOMEM;
    }
    printk("Entry created!\n");
    return 0;
}

static void __exit stop() {
    remove_proc_entry("proc_test", NULL);
    printk("Entry removed!\n");
    return;
}

module_init(init);
module_exit(stop);

MODULE_LICENSE("GPL");

我面临的问题是,当我从/proc/proc_test/using cator读取时tail,计数器增加 3 而不是 1。

输出:

cat /proc/proc_test 
counter = 0

cat /proc/proc_test 
counter = 3

cat /proc/proc_test 
counter = 6

我究竟做错了什么?

4

3 回答 3

3

试试这个:

static int proc_read(char *buffer, char **start, off_t offset, int size, int *eof, void *data) {
    if (size < 256) return -ENOMEM;
    int count= sprintf(buffer, "counter = %d\n", counter++);
    *eof = 1;
    return count;
}

设置 *eof=1,您的驱动程序会通知内核(以及想要读取您的 proc 文件的应用程序)您的驱动程序已到达 EOF。

于 2012-09-10T14:52:47.543 回答
3

唯一错误的是你有一个不合理的期望。是什么让你认为cat /proc/proc_test只会调用read一次?

$ strace cat /proc/self/stat | grep read
read(3, "17423 (cat) R 17420 17420 13224 "..., 32768) = 238
read(3, "", 32768)                      = 0
$
于 2012-09-10T14:52:55.873 回答
1

Even though this answer has a good hint, I have been having this issue too. Setting *eof = 1 theoretically should have solved the problem but somehow it doesn't.

My fix was to also add this on the top of the function:

if (offset > 0)    // even though I set *eof = 1, the kernel is still calling me, so return 0 for it to stop
    return 0;

The comment above is in fact what I had written in my own module.

What this does is to make sure only the first call to your function (in which offset is 0) does anything.

于 2012-09-10T15:12:37.493 回答