Linux kernel IO期间移除介质后清理块设备时删除磁盘

Linux kernel IO期间移除介质后清理块设备时删除磁盘,linux-kernel,linux-device-driver,device-driver,block-device,Linux Kernel,Linux Device Driver,Device Driver,Block Device,我有一个热插拔PCI存储设备的块驱动程序。如果在IO期间删除了设备,我似乎从未收到过释放调用(即mydev\u blk\u release(struct gendisk*gd,fmode\u t mode)),我认为这会阻止del\u gendisk()完成,从而挂起驱动程序的清理。一旦发生弹出,我将结束队列上的所有请求,但它似乎仍然不会导致释放。在介质消失的情况下,终止请求和删除gendisk的正确方法是什么?这是由于没有结束因设备移除而中断的请求造成的。在我的驱动程序中,我有以下请求\u f

我有一个热插拔PCI存储设备的块驱动程序。如果在IO期间删除了设备,我似乎从未收到过释放调用(即
mydev\u blk\u release(struct gendisk*gd,fmode\u t mode)
),我认为这会阻止
del\u gendisk()
完成,从而挂起驱动程序的清理。一旦发生弹出,我将结束队列上的所有请求,但它似乎仍然不会导致释放。在介质消失的情况下,终止请求和删除gendisk的正确方法是什么?

这是由于没有结束因设备移除而中断的请求造成的。在我的驱动程序中,我有以下
请求\u fn

static void mydev\u submit\u req(结构请求队列*q)
{
struct mydev_info*mydev=q->queuedata;
如果(!mydev){
结构请求*req;
while((req=blk\u fetch\u request(q))!=NULL){
req->cmd_标志|=req_安静;
__blk_end_request_all(请求,-ENODEV);
}
}否则{
队列工作(mydev->wq,&mydev->work);
}
}
这将防止在设备消失时请求进入驱动程序的工作队列(表示丢失
mydev
)。但是,由于最后一个请求没有实际完成,导致
q->rq->elvpriv
(现在称为
q->nr\u rqs\u elvpriv
)保持在1,这导致
blk\u drain\u queue()
永远旋转,从而挂起
blk\u cleanup\u queue()
,并阻止驱动程序移除设备

解决方案如下所示(在我的驱动程序中的workqueue回调函数中,但这取决于IO工作的结构):

req=blk\u fetch\u请求(q);
while(请求){
//如果磁盘在传输过程中弹出,则返回-ENODEV
//字节告诉我们我们成功地完成了多少字节
res=mydev_do_req(q、req和字节);
如果(不太可能(res==-ENODEV)){
开发错误(&mydev->pdev->dev,
“设备在传输过程中弹出,返回\n”);
//结束当前请求,因为我们启动了它
//这就是我们所缺少的
__blk_end_request_all(请求,-ENODEV);
打破
//滚出-下一天队列的其余部分将被清空
//提交请求
}else if(!\u blk\u end\u请求(请求、恢复、字节)){
req=blk_fetch_request(q);//获取下一个请求
}
}

这是由于没有结束因设备移除而中断的请求而导致的。在我的驱动程序中,我有以下
请求\u fn

static void mydev\u submit\u req(结构请求队列*q)
{
struct mydev_info*mydev=q->queuedata;
如果(!mydev){
结构请求*req;
while((req=blk\u fetch\u request(q))!=NULL){
req->cmd_标志|=req_安静;
__blk_end_request_all(请求,-ENODEV);
}
}否则{
队列工作(mydev->wq,&mydev->work);
}
}
这将防止在设备消失时请求进入驱动程序的工作队列(表示丢失
mydev
)。但是,由于最后一个请求没有实际完成,导致
q->rq->elvpriv
(现在称为
q->nr\u rqs\u elvpriv
)保持在1,这导致
blk\u drain\u queue()
永远旋转,从而挂起
blk\u cleanup\u queue()
,并阻止驱动程序移除设备

解决方案如下所示(在我的驱动程序中的workqueue回调函数中,但这取决于IO工作的结构):

req=blk\u fetch\u请求(q);
while(请求){
//如果磁盘在传输过程中弹出,则返回-ENODEV
//字节告诉我们我们成功地完成了多少字节
res=mydev_do_req(q、req和字节);
如果(不太可能(res==-ENODEV)){
开发错误(&mydev->pdev->dev,
“设备在传输过程中弹出,返回\n”);
//结束当前请求,因为我们启动了它
//这就是我们所缺少的
__blk_end_request_all(请求,-ENODEV);
打破
//滚出-下一天队列的其余部分将被清空
//提交请求
}else if(!\u blk\u end\u请求(请求、恢复、字节)){
req=blk_fetch_request(q);//获取下一个请求
}
}