我有一个热插拔 PCI 存储设备的块驱动程序。如果在 IO 期间删除了设备,我似乎从来没有接到过释放(即mydev_blk_release(struct gendisk *gd, fmode_t mode)
)的调用,我认为这会阻止del_gendisk()
完成,从而挂起驱动程序的清理。一旦发生弹出,我将结束队列中的所有请求,但它似乎仍然不会导致释放。在媒体消失的情况下,终止请求和删除 gendisk 的正确方法是什么?
问问题
444 次
1 回答
1
这是由于未结束因设备移除而中断的请求所致。在我的驱动程序中,我有以下内容request_fn
:
static void mydev_submit_req(struct request_queue *q)
{
struct mydev_info *mydev = q->queuedata;
if (!mydev){
struct request* req;
while ((req = blk_fetch_request(q)) != NULL){
req->cmd_flags |= REQ_QUIET;
__blk_end_request_all(req, -ENODEV);
}
} else {
queue_work(mydev->wq, &mydev->work);
}
}
这将防止在设备消失时请求进入驱动程序的工作队列(由 的丢失表示mydev
)。然而,这个挂起是因为最后一个请求实际上并没有完成,导致q->rq->elvpriv
(现在称为q->nr_rqs_elvpriv
)保持在 1,这导致blk_drain_queue()
永远旋转,这挂起blk_cleanup_queue()
并阻止驱动程序能够移除设备。
解决方案如下所示(在我的驱动程序中的工作队列回调函数中,但这取决于您如何构建 IO 工作):
req = blk_fetch_request(q);
while (req) {
// returns -ENODEV if the disk is ejected during transfer
//bytes tells us how many bytes we managed to do
res = mydev_do_req(q, req, &bytes);
if (unlikely(res == -ENODEV)) {
dev_err(&mydev->pdev->dev,
"device ejected during transfer, returning\n");
//end the current request, since we started it
//THIS IS WHAT WAS MISSING
__blk_end_request_all(req, -ENODEV);
break;
//get out - the rest of the queue will be emptied on the next
//submit_req
} else if (!__blk_end_request(req, res, bytes)) {
req = blk_fetch_request(q); //get the next request
}
}
于 2013-01-21T17:42:04.787 回答