scsi

scsi_mq_ops里面的commit_rqs:

用来一批IO一起发送时,在最后一个IO时才写doorbell。
使用场景:
block层unplug时候会产生一批IO:
do while把所有plug的IO都下发

void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule)
{
    LIST_HEAD(list);

    if (list_empty(&plug->mq_list))
        return;
    list_splice_init(&plug->mq_list, &list);

    if (plug->rq_count > 2 && plug->multiple_queues)
        list_sort(NULL, &list, plug_rq_cmp);

    plug->rq_count = 0;

    do {
        struct list_head rq_list;
        struct request *rq, *head_rq = list_entry_rq(list.next);
        struct list_head *pos = &head_rq->queuelist; /* skip first */
        struct blk_mq_hw_ctx *this_hctx = head_rq->mq_hctx;
        struct blk_mq_ctx *this_ctx = head_rq->mq_ctx;
        unsigned int depth = 1;

        list_for_each_continue(pos, &list) {
            rq = list_entry_rq(pos);
            BUG_ON(!rq->q);
            if (rq->mq_hctx != this_hctx || rq->mq_ctx != this_ctx)
                break;
            depth++;
        }

        list_cut_before(&rq_list, &list, pos);
        trace_block_unplug(head_rq->q, depth, !from_schedule);
        blk_mq_sched_insert_requests(this_hctx, this_ctx, &rq_list,
                        from_schedule);
    } while(!list_empty(&list));
}

为什么要最后一个IO才写doorbell:
适用于写doorbell开销比较大的场合,例如虚拟化硬件(比如virtio-scsi)

if (shost->hostt->commit_rqs)
        tag_set->ops = &scsi_mq_ops;
    else
        tag_set->ops = &scsi_mq_ops_no_commit;

block层调用commit_rqs,场合一:

void blk_mq_try_issue_list_directly(struct blk_mq_hw_ctx *hctx,
        struct list_head *list)
{
    int queued = 0;
    int errors = 0;

    while (!list_empty(list)) {
        blk_status_t ret;
        struct request *rq = list_first_entry(list, struct request,
                queuelist);

        list_del_init(&rq->queuelist);
        ret = blk_mq_request_issue_directly(rq, list_empty(list));
        if (ret != BLK_STS_OK) {
            if (ret == BLK_STS_RESOURCE ||
                    ret == BLK_STS_DEV_RESOURCE) {
                blk_mq_request_bypass_insert(rq, false,
                            list_empty(list));
                break;
            }
            blk_mq_end_request(rq, ret);
            errors++;
        } else
            queued++;
    }

    /*
     * If we didn't flush the entire list, we could have told
     * the driver there was more coming, but that turned out to
     * be a lie.
     */
    if ((!list_empty(list) || errors) &&
         hctx->queue->mq_ops->commit_rqs && queued)
        hctx->queue->mq_ops->commit_rqs(hctx);
}

参考https://lore.kernel.org/lkml/...

你可能感兴趣的:(android)