ホットプラグ可能な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 に答える