我正在学习"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
驱动程序不断打印";你好,来自内核世界"消息发送到终端。
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: Readn");
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(文件结尾(