我正在编写内核驱动程序以使用PCI Express设备发送/接收数据。对于驱动程序的第一个版本,我创建了一个字符设备接口,用户可以使用文件读取数据。
我想实现阻塞读取,其中用户请求数据并且驱动程序填充用户缓冲区。为了屏蔽用户的read
电话,我使用的是completion
结构。
当加载驱动程序并且用户请求读取时,驱动程序会按预期阻塞。如果我要完成阅读,那么一切都运行正常。
为了安全起见,无论何时移除模块,我都会调用complete_all
函数,以防有人在读取事务中删除模块或设备。
调用remove
或exit
函数并且模块和用户应用程序都被阻止。我已经尝试了以下三个功能(显示了相关结果)。
wait_completion(&dev->read_complete);
//无限期阻止,我需要重置计算机retval = wait_for_completion_interruptible(&dev->read_complete);
//我可以手动终止用户应用程序,然后删除驱动程序retval = wait_for_completion_killable(&dev->read_complete);
//与可中断相同我的期望是,当调用remove函数时,我可以调用complete_all(&dev->read_complete)
并且read函数将返回错误。
为了消除外部因素我已经在github上做了一个回购,所以如果有人想看到自己的行为,他们只需要克隆并按照说明操作:
模块的相关部分在这里(/src/mymodule.c)
typedef struct {
struct cdev cdv;
struct class *cls;
struct device *dev;
struct completion complete;
} mymodule_t;
mymodule_t mymod;
//Sysfs 'mymodule_test' attribute (all but the actual function is left out for brevity)
static ssize_t mymodule_test_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int retval = 0;
int value = 0;
if (sscanf(buf, "%d", &value) == 1)
{
retval = strlen(buf);
}
if (value)
{
printk("Value is: %d\n", value);
if (!completion_done(&mymod.complete))
{
complete(&mymod.complete);
}
printk("Sent Completion\n");
}
return retval;
}
//FOPS (all but 'read' function is left out for brevity)
ssize_t mymodule_read(struct file *filp, char * buf, size_t count, loff_t *f_pos)
{
printk("Read!\n");
if (completion_done(&mymod.complete))
{
reinit_completion(&mymod.complete);
}
printk("Wait for Completion\n");
wait_for_completion_interruptible(&mymod.complete);
printk("After Completion\n");
return 0;
}
static int __init mymodule_init(void)
{
...
//Register class and device
//Configure character driver with fops
init_completion(&mymod.complete);
...
}
static void __exit mymodule_exit(void)
{
...
if (!completion_done(&mymod.complete))
{
printk("Send a completion!\n");
complete(&mymod.complete);
}
//Clean up the rest of the module
...
}
module_init(mymodule_init);
module_exit(mymodule_exit);
以下是我用来执行此操作的用户态应用程序:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include "mymodule.h"
#define FILEPATH "/dev/mymodule0"
#define TEST_SIZE 10
int main(void)
{
int fn = -1;
char buf[TEST_SIZE];
printf("Attempting to open file module file...\n");
fn = open(FILEPATH, O_RDWR);
if (fn < 0)
{
printf("Failed to open file!\n");
return -1;
}
printf("Attempting to read from the file...\n");
read(fn, &buf, TEST_SIZE);
printf("Finished reading from file\n");
return 0;
}
这是我
时的dmesg输出[3217633.993937] Registering Driver [3217633.993995] Driver Initialized! [3217643.747791] Opened! [3217643.747800] Read! [3217643.747801] Wait for Completion [3217646.436780] Value is: 1 [3217646.436792] Sent Completion [3217646.436806] After Completion [3217646.437010] Closed! [3217727.378388] Cleanup Module [3217727.378393] Check if we need to complete anything [3217727.378395] Send a completion! [3217727.378397] Unregistering Character Driver [3217727.378400] Give back all the numbers we requested [3217727.378402] Remove the class driver [3217727.378571] Release the class [3217727.378593] Finished Cleanup Module, Exiting
如果我运行以下命令:
[3218223.442777] Registering Driver [3218223.442934] Driver Initialized! [3218229.378396] Opened! [3218229.378419] Read! [3218229.378422] Wait for Completion
然后模块没有卸载。如果这是一个真实的设备,如USB硬盘驱动器,用户可能会在读取事务中删除设备。这似乎是错误的,或者我可能错过了一些东西。我错过了什么吗?
答案 0 :(得分:0)
虽然可以随时删除设备 ,但驱动程序(例如内核模块)无法卸载在使用该设备的某些操作期间(例如,阅读)。是向上级(例如文件系统)报告设备缺失的驱动程序。