void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb) { int i = 0, start = 0, num_reqs = 0, niov = 0, nb_sectors = 0; int max_xfer_len = 0; int64_t sector_num = 0; if (mrb->num_reqs == 1) { submit_requests(blk, mrb, 0, 1, -1); mrb->num_reqs = 0; return; } max_xfer_len = blk_get_max_transfer_length(mrb->reqs[0]->dev->blk); max_xfer_len = MIN_NON_ZERO(max_xfer_len, BDRV_REQUEST_MAX_SECTORS); qsort(mrb->reqs, mrb->num_reqs, sizeof(*mrb->reqs), &multireq_compare); for (i = 0; i < mrb->num_reqs; i++) { VirtIOBlockReq *req = mrb->reqs[i]; if (num_reqs > 0) { bool merge = true; /* merge would exceed maximum number of IOVs */ if (niov + req->qiov.niov > IOV_MAX) { merge = false; } /* merge would exceed maximum transfer length of backend device */ if (req->qiov.size / BDRV_SECTOR_SIZE + nb_sectors > max_xfer_len) { merge = false; } /* requests are not sequential */ if (sector_num + nb_sectors != req->sector_num) { merge = false; } if (!merge) { submit_requests(blk, mrb, start, num_reqs, niov); num_reqs = 0; } } if (num_reqs == 0) { sector_num = req->sector_num; nb_sectors = niov = 0; start = i; } nb_sectors += req->qiov.size / BDRV_SECTOR_SIZE; niov += req->qiov.niov; num_reqs++; } submit_requests(blk, mrb, start, num_reqs, niov); mrb->num_reqs = 0; }