Warm tip: This article is reproduced from serverfault.com, please click

c-copy_to_user()无限打印消息

(c - copy_to_user() keeps printing message infinitely)

发布于 2020-11-30 13:27:43

我正在学习“ 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

驱动程序不断打印“内核世界你好!” 消息到终端。

Questioner
Vivek
Viewed
0
Ian Abbott 2020-11-30 22:43:28

诸如此类的程序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(文件结束)