1

我正在学习“Linux 设备驱动程序”。我创建了一个名为char_device. 当我从设备读取数据时,它会不断将消息打印到终端,使机器无限崩溃。

驱动中读操作的源码:

static ssize_t my_read(struct file *my_file, char __user *buf, size_t len, loff_t *off) {
    uint8_t *message = "Hello from the kernel world!\n";
    size_t datalen = strlen(message);
    
    if(len > datalen) {
        len = datalen;
    }
    printk(KERN_INFO "Char driver: Read");
    if(copy_to_user(buf, message, len)) {
        return -EFAULT;
    }

    return len;
}

用于读取设备的用户空间命令:

cat /dev/char_device

驱动程序不断打印“来自内核世界的你好!” 向终端发送消息。

4

1 回答 1

5

诸如此类的程序cat将读取当前输入文件,直到遇到文件结束条件或读取错误。按照惯例,read()当请求非零数据量时,返回值 0 表示文件结束条件。返回值-1表示读取错误,错误号在errno变量中。

在内核级别,read文件操作处理程序应返回 0 以指示文件结束条件(但也可以在请求数量为 0 时这样做),并应返回否定errno值以指示读取错误。

OP 的当前read文件操作处理程序,my_read将字符串文字的内容,复制"Hello from the kernel world!\n"到用户内存缓冲区,限制为请求的读取量或字符串的长度,以最小者为准。它从不返回文件结束条件。它返回 0 的唯一时间是请求的数量为 0 时,但这不是有效的文件结束条件。

可以做的一件事my_read是使用传入的文件位置信息来确定从哪里开始读取,并限制要复制的数量。它应该相应地更新位置。然后当没有更多数据要复制时,它可以返回 0 来指示文件结束。这是一个可能的实现:

static ssize_t my_read(struct file *my_file, char __user *buf, size_t len, loff_t *off) {
    char *message = "Hello from the kernel world!\n";
    size_t datalen = strlen(message);
   
    if (*off >= datalen) {
        return 0; /* end of file */
    } 
    if(len > datalen - *off) {
        len = datalen - *off;
    }
    printk(KERN_INFO "Char driver: Read\n");
    if(copy_to_user(buf, message, len)) {
        return -EFAULT;
    }

    *off += len;
    return len;
}

行为的一个变化是长度为 10(例如)的连续读取量将从前一个停止的read位置开始,例如:

  • 读取 10,返回 10 ( 'H', 'e', 'l', 'l', 'o', ' ', 'f', 'r', 'o', 'm')
  • 读取 10,返回 10 ( ' ', 't', 'h', 'e', ' ', 'k', 'e', 'r'. 'n', 'e')
  • 读取 10,返回 9 ( 'l', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\n')
  • 读取 10,返回 0(文件结束)
于 2020-11-30T14:34:57.713 回答