【问题标题】:Linux kernel module strange behaviourLinux内核模块奇怪的行为
【发布时间】:2012-09-10 14:47:40
【问题描述】:

我正在研究一个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");

我面临的问题是,当我使用cattail/proc/proc_test/ 中读取数据时,计数器会增加 3 而不是 1。

输出:

cat /proc/proc_test 
counter = 0

cat /proc/proc_test 
counter = 3

cat /proc/proc_test 
counter = 6

我做错了什么?

【问题讨论】:

    标签: c linux-kernel


    【解决方案1】:

    试试这个:

    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。

    【讨论】:

    • 如果你想使用 dd 读取数据会发生什么(一次获取 100 个字节): $ dd if=/proc/proc_test of=test.out bs=100 count=1
    • dd: 读取 `/proc/proc_test': 无法分配内存 0+0 记录 0+0 记录中 0 字节 (0 B) 复制,0.000511612 秒,0.0 kB/s
    【解决方案2】:

    唯一的错误是你有一个不合理的期望。是什么让您认为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
    $
    

    【讨论】:

    • 它计算在模块创建的伪文件上执行的read 系统调用,而不是进程执行的所有读取。虽然正确,但您的示例显示从具有相同描述符 ID 的不同文件读取(可能在第一次和第二次 read 调用之间关闭然后重新打开),不仅是 /proc/self/stat,而且可能有点误导。跨度>
    • @HristoIliev:已更正。谢谢。我的意思是,在那个时候期待阅读是不合理的。
    • 我发现cat 确实调用了read() 两次(通过printk() 的current->pid 和current->comm 输出检查它),所以感谢问题解释。有没有比 Shahbaz 的回答更好的方法来防止增加?我怎样才能知道谁第三次打电话给read()
    【解决方案3】:

    尽管this answer 有一个很好的提示,但我也遇到了这个问题。设置*eof = 1理论上应该可以解决问题,但不知何故并没有。

    我的解决方法是在函数顶部添加这个:

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

    上面的评论其实是我在自己的模块里写的。

    这样做是为了确保只有对您的函数的第一次调用(其中offset 为 0)才起作用。

    【讨论】:

    • 这似乎是一个解决方案。无论如何,我应该更加小心read() 电话。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-10
    • 2014-01-24
    • 1970-01-01
    • 1970-01-01
    • 2019-04-01
    • 1970-01-01
    相关资源
    最近更新 更多