Question

I have block driver for a hot-pluggable PCI storage device. if the device is removed during IO, I never seem to get a call to release (i.e. mydev_blk_release(struct gendisk *gd, fmode_t mode)), which I think is preventing del_gendisk() from completing, thus hanging the cleanup of the driver. I am ending all requests on the queue once an eject happens, but it still doesn't seem to cause a release. What is the right way to terminate requests and delete the gendisk in the case of vanished media?

Était-ce utile?

La solution

This is caused by not ending the request that is broken by the device removal. In my driver, I had the folowing 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);
    }
}

This will prevent the requests entering the driver's workqueue when the device disappears (signified by the loss of mydev). However this hung because the last request was not actually completed, causing q->rq->elvpriv (now called q->nr_rqs_elvpriv) to remain at 1, which caused blk_drain_queue() to spin forever, which hung blk_cleanup_queue() and prevented the driver being able to remove the device.

The solution looks like this (in the workqueue callback function in my driver, but this depends on how you structure the IO work):

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
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top