块设备驱动程序中的生产者消费者实现?

时间:2011-07-19 04:49:14

标签: linux linux-kernel block device-driver producer-consumer

我正在尝试在我的块级驱动程序(Linux内核版本2.6.39.1)中实现类似生产者的情况。我的块驱动程序make_request_fn从用户级应用程序接收struct bio流。收到这些BIO后,他们排队等候。接下来,我创建一个新的struct bio,它将保存排队的BIO中存在的所有信息。只有在较低级别驱动程序struct request中有request_queue个插槽时,才会提交此新“merged_bio”。与此同时,我的块驱动程序将继续从userlevel应用程序接收BIO并将它们排队(密集的负载情况)。现在,为了减少延迟,我想确保在BIO排队时,包含最旧BIO的批次出列,从而最大限度地减少队列中的空闲时间。我很困惑我应该如何实现这种流水线情况(每个请求延迟较低),其中我的驱动程序make_request_fn是BIO的生产者,而调用submit_bio()的函数是这些BIO的使用者。可能的方法包括:

  1. Tasklets - 在struct requestrequest_queue广告位空闲后,让小程序从队列中继续使用BIO。这种方法不起作用,因为tasklet处理函数不是原子的,因为它调用submit_bio(),后者又调用了schedule()

  2. 工作队列 - 由于工作队列的处理函数可以休眠,因此它们的延迟可能比tasklet高。这可能会影响我的驱动程序的性能,因为BIO可能会在很多之后提交给较低级别​​的驱动程序,而不是make_request_fn实际排队的时间。我不确定对性能的影响有多大(我的驱动程序实现了快速记录设备。) 工作队列的另一个问题是如何以及何时安排工作队列?一旦请求槽可用,就必须提交merged_bio。因此,必须有某种“信令”机制,一旦struct request可用,就会安排工作队列。我没有看到如何在没有信令或request_queue机制的情况下连续监视poll()的空闲时隙,然后明确地调度工作队列。是的,我们无法从之前完成的BIO的回调函数中调用submit_bio()

  3. 内核线程 - 我认为这是第三种选择。我对内核线程没有太多了解,但这是我计划如何实现的:我的驱动程序make_request_fn将继续将BIO排入队列。将创建一个新的内核线程,当struct request插槽可用时(而不是其他情况),该线程将继续消耗队列 中的BIO。因此,每次调度此内核线程时,它都会检查一个空的请求槽,然后从队列中消耗一批BIO并调用submit_bio()

  4. 更聪明的东西?

  5. stackoverflow的成员可以帮助我选择一种智能有效的方式来实现这种情况吗?谢谢!

    UPDATE :我尝试了workqueue方法,但它只是导致我的内核崩溃(/ var / log / messages包含乱码文本,所以我没有任何日志可以共享)。以下是我如何实现工作队列:

    工作队列将使用的数据结构:

    struct my_work_struct {
       struct work_struct wk;
       pitdev_t *pd;    /* Pointer to my block device */
       int subdev_index;    /* Indexes the disk that is currently in picture -- pd->subdev[subdev_index] */
    };
    
    struct pitdev_struct {
    /* Driver related data */
    struct my_work_struct *work;
    } *pd;
    
    typedef struct pitdev_struct pitdev_t;
    

    初始化我的工作项:

    /* Allocate memory for both pd and pd->work */
    
    INIT_WORK(&pd->work->wk, my_work_fn);
    
    pd->work->pd = pd;
    pd->work->subdev_index = 0;
    

    我的工作职能定义:

    void my_work_fn(struct work_struct *work)
    {
       struct my_work_struct *temp = container_of(work, struct my_work_struct, wk);
       pitdev_t *pd = temp->pd;
       int sub_index = temp->subdev_index;
    
       /* Create a BIO and submit it*/
       submit_bio(WRITE, merged_bio);
    }
    

    merged_bio->bi_end_io中,我安排了我的工作项目:

    schedule_work(&pd->work->wk);
    

    这样做是为了在上一个BIO成功转移后不久安排下一个要提交的BIO。对submit_bio()的第一次调用是在没有的情况下使用工作队列完成。第一次致电submit_bio()时没有任何问题;在调用时,我使用工作项调用submit_bio(),系统崩溃。

    有什么想法吗?

0 个答案:

没有答案