【问题标题】:copy_to_user() keeps printing message infinitelycopy_to_user() 不断打印消息
【发布时间】:2021-03-12 10:18:32
【问题描述】:

我正在学习"Linux device drivers"。我创建了一个名为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

驱动程序不断打印“Hello from the kernel world!”向终端发送消息。

【问题讨论】:

  • cat 将继续读取输入,直到 read() 函数返回 0(表示文件结束)或 -1(表示错误)。
  • 旁白:printk 消息应以换行符结束,除非您打算在其后面加上 KERN_CONT
  • 这能回答你的问题吗? cat function calling read() infinite times

标签: c linux linux-kernel linux-device-driver printk


【解决方案1】:

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',@98765434@1) /li>
  • 读取10,返回10(' ''t''h''e'' ''k''e''r'.'e'4@) /li>
  • 读10,返回9('l'' ''w''o''r''l''d''!''\n'
  • 读取 10,返回 0(文件结束)

【讨论】:

  • 感谢您的帮助。但是,当我在问题中发布的代码中将返回值更改为 0 return 0; 而不是 return len; 时,它不会在终端中打印任何内容。帮助我理解这一点。
  • @Vivek 返回值表示已经读取了多少,所以返回 0 表示没有读取任何内容。它还指示文件结束条件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-17
  • 2013-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多