简体   繁体   中英

Linux kernel module strange behaviour

I am studying a linux kernel, so I try to write a simple modules.

The following code is supposed to control how many times read() for the /proc/proc_test is called:

#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");

I am facing the issue that when I read from the /proc/proc_test/ using cat or tail , the counter is incremented by 3 instead of by 1.

Output:

cat /proc/proc_test 
counter = 0

cat /proc/proc_test 
counter = 3

cat /proc/proc_test 
counter = 6

What am I doing wrong?

try this:

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;
}

setting *eof=1, your driver informs the kernel (and the application which want to read your proc file) that your driver reached EOF.

The only thing wrong is that you have an unreasonable expectation. What makes you think cat /proc/proc_test will only call read once?

$ strace cat /proc/self/stat | grep read
read(3, "17423 (cat) R 17420 17420 13224 "..., 32768) = 238
read(3, "", 32768)                      = 0
$

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM