为什么从linux模块读取工作逐字符,而不是整个字符串

时间:2015-07-03 16:24:06

标签: c linux string linux-kernel

我的内核模块的读取功能如下。它只是从内核缓冲区中读取一个字符并将其复制到用户缓冲区中。 一旦我到达内核缓冲区的末尾,我返回0.这非常有效。

static ssize_t debugfs_read(struct file *f, char __user *buf,
    size_t length, loff_t *offset)
{
    ssize_t rc = 0;

    pr_info("%s.\n", "In read");

    rc = copy_to_user(buf, &kbuffer[*offset], 1);



    if (rc < 0)
        return -EFAULT;

    if (kbuffer[*offset] == '\0')
        return 0;

    *offset = *offset + 1;

    return 1;
}

现在如果我尝试将整个内核缓冲区一次性复制到用户缓冲区中,  模块不会打印任何内容。

为什么?这种情况下的代码:

static ssize_t debugfs_read(struct file *f, char __user *buf,
    size_t length, loff_t *offset)
{
    ssize_t rc = 0;

    pr_info("%s.\n", "In read");

    rc = copy_to_user(buf, &kbuffer, BUFF_LEN);


    if (rc != 0)
        return -EFAULT;

    return 0;
}

编辑:

在使用已接受答案的解决方案时,我意识到内核会调用read两次。这是strace

read(3, "s03324135655\0", 65536)        = 13
write(1, "s03324135655\0", 13)          = 13
read(3, "", 65536)                      = 0

为什么?是因为我们必须从模块完成reading后返回0?第二个系统调用有一个空字符串,基本上规定没有东西要读,我们应该返回零。

1 个答案:

答案 0 :(得分:2)

  1. 如果给你一个带缓冲区的长度,你需要使用它。如果提供的缓冲区小于内核缓冲区,则您不想踩踏其他用户空间内存。
  2. 您需要返回复制到缓冲区的字节数。您的逐个字符的代码返回1,但是在成功的情况下,复制整个缓冲区的代码总是返回0,这告诉调用者您向缓冲区写了0个字节。
  3. 您还需要考虑偏移参数。
  4. 所以,不要自己实现所有这些逻辑,只需使用simple_read_from_buffer,这会为你做到这一点:

    static ssize_t debugfs_read(struct file *f, char __user *buf,
        size_t length, loff_t *offset)
    {
        return simple_read_from_buffer(buf, length, offset, &kbuffer, BUFF_LEN);
    }