1

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

4

1 回答 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 回答