virtio-blk: use BDRV_REQ_REGISTERED_BUF optimization hint

Register guest RAM using BlockRAMRegistrar and set the
BDRV_REQ_REGISTERED_BUF flag so block drivers can optimize memory
accesses in I/O requests.

This is for vdpa-blk, vhost-user-blk, and other I/O interfaces that rely
on DMA mapping/unmapping.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
Message-id: 20221013185908.1297568-14-stefanha@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2022-10-13 14:59:08 -04:00
parent c5640b3e2f
commit baf422684d
2 changed files with 27 additions and 14 deletions

View File

@ -21,6 +21,7 @@
#include "hw/block/block.h" #include "hw/block/block.h"
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
#include "sysemu/blockdev.h" #include "sysemu/blockdev.h"
#include "sysemu/block-ram-registrar.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "sysemu/runstate.h" #include "sysemu/runstate.h"
#include "hw/virtio/virtio-blk.h" #include "hw/virtio/virtio-blk.h"
@ -362,12 +363,14 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
} }
} }
static inline void submit_requests(BlockBackend *blk, MultiReqBuffer *mrb, static inline void submit_requests(VirtIOBlock *s, MultiReqBuffer *mrb,
int start, int num_reqs, int niov) int start, int num_reqs, int niov)
{ {
BlockBackend *blk = s->blk;
QEMUIOVector *qiov = &mrb->reqs[start]->qiov; QEMUIOVector *qiov = &mrb->reqs[start]->qiov;
int64_t sector_num = mrb->reqs[start]->sector_num; int64_t sector_num = mrb->reqs[start]->sector_num;
bool is_write = mrb->is_write; bool is_write = mrb->is_write;
BdrvRequestFlags flags = 0;
if (num_reqs > 1) { if (num_reqs > 1) {
int i; int i;
@ -398,12 +401,18 @@ static inline void submit_requests(BlockBackend *blk, MultiReqBuffer *mrb,
num_reqs - 1); num_reqs - 1);
} }
if (blk_ram_registrar_ok(&s->blk_ram_registrar)) {
flags |= BDRV_REQ_REGISTERED_BUF;
}
if (is_write) { if (is_write) {
blk_aio_pwritev(blk, sector_num << BDRV_SECTOR_BITS, qiov, 0, blk_aio_pwritev(blk, sector_num << BDRV_SECTOR_BITS, qiov,
virtio_blk_rw_complete, mrb->reqs[start]); flags, virtio_blk_rw_complete,
mrb->reqs[start]);
} else { } else {
blk_aio_preadv(blk, sector_num << BDRV_SECTOR_BITS, qiov, 0, blk_aio_preadv(blk, sector_num << BDRV_SECTOR_BITS, qiov,
virtio_blk_rw_complete, mrb->reqs[start]); flags, virtio_blk_rw_complete,
mrb->reqs[start]);
} }
} }
@ -425,14 +434,14 @@ static int multireq_compare(const void *a, const void *b)
} }
} }
static void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb) static void virtio_blk_submit_multireq(VirtIOBlock *s, MultiReqBuffer *mrb)
{ {
int i = 0, start = 0, num_reqs = 0, niov = 0, nb_sectors = 0; int i = 0, start = 0, num_reqs = 0, niov = 0, nb_sectors = 0;
uint32_t max_transfer; uint32_t max_transfer;
int64_t sector_num = 0; int64_t sector_num = 0;
if (mrb->num_reqs == 1) { if (mrb->num_reqs == 1) {
submit_requests(blk, mrb, 0, 1, -1); submit_requests(s, mrb, 0, 1, -1);
mrb->num_reqs = 0; mrb->num_reqs = 0;
return; return;
} }
@ -452,11 +461,11 @@ static void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb)
* 3. merge would exceed maximum transfer length of backend device * 3. merge would exceed maximum transfer length of backend device
*/ */
if (sector_num + nb_sectors != req->sector_num || if (sector_num + nb_sectors != req->sector_num ||
niov > blk_get_max_iov(blk) - req->qiov.niov || niov > blk_get_max_iov(s->blk) - req->qiov.niov ||
req->qiov.size > max_transfer || req->qiov.size > max_transfer ||
nb_sectors > (max_transfer - nb_sectors > (max_transfer -
req->qiov.size) / BDRV_SECTOR_SIZE) { req->qiov.size) / BDRV_SECTOR_SIZE) {
submit_requests(blk, mrb, start, num_reqs, niov); submit_requests(s, mrb, start, num_reqs, niov);
num_reqs = 0; num_reqs = 0;
} }
} }
@ -472,7 +481,7 @@ static void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb)
num_reqs++; num_reqs++;
} }
submit_requests(blk, mrb, start, num_reqs, niov); submit_requests(s, mrb, start, num_reqs, niov);
mrb->num_reqs = 0; mrb->num_reqs = 0;
} }
@ -487,7 +496,7 @@ static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
* Make sure all outstanding writes are posted to the backing device. * Make sure all outstanding writes are posted to the backing device.
*/ */
if (mrb->is_write && mrb->num_reqs > 0) { if (mrb->is_write && mrb->num_reqs > 0) {
virtio_blk_submit_multireq(s->blk, mrb); virtio_blk_submit_multireq(s, mrb);
} }
blk_aio_flush(s->blk, virtio_blk_flush_complete, req); blk_aio_flush(s->blk, virtio_blk_flush_complete, req);
} }
@ -667,7 +676,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
if (mrb->num_reqs > 0 && (mrb->num_reqs == VIRTIO_BLK_MAX_MERGE_REQS || if (mrb->num_reqs > 0 && (mrb->num_reqs == VIRTIO_BLK_MAX_MERGE_REQS ||
is_write != mrb->is_write || is_write != mrb->is_write ||
!s->conf.request_merging)) { !s->conf.request_merging)) {
virtio_blk_submit_multireq(s->blk, mrb); virtio_blk_submit_multireq(s, mrb);
} }
assert(mrb->num_reqs < VIRTIO_BLK_MAX_MERGE_REQS); assert(mrb->num_reqs < VIRTIO_BLK_MAX_MERGE_REQS);
@ -774,7 +783,7 @@ void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
} while (!virtio_queue_empty(vq)); } while (!virtio_queue_empty(vq));
if (mrb.num_reqs) { if (mrb.num_reqs) {
virtio_blk_submit_multireq(s->blk, &mrb); virtio_blk_submit_multireq(s, &mrb);
} }
blk_io_unplug(s->blk); blk_io_unplug(s->blk);
@ -823,7 +832,7 @@ void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh)
} }
if (mrb.num_reqs) { if (mrb.num_reqs) {
virtio_blk_submit_multireq(s->blk, &mrb); virtio_blk_submit_multireq(s, &mrb);
} }
if (is_bh) { if (is_bh) {
blk_dec_in_flight(s->conf.conf.blk); blk_dec_in_flight(s->conf.conf.blk);
@ -1205,6 +1214,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
} }
s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
blk_ram_registrar_init(&s->blk_ram_registrar, s->blk);
blk_set_dev_ops(s->blk, &virtio_block_ops, s); blk_set_dev_ops(s->blk, &virtio_block_ops, s);
blk_iostatus_enable(s->blk); blk_iostatus_enable(s->blk);
@ -1230,6 +1240,7 @@ static void virtio_blk_device_unrealize(DeviceState *dev)
virtio_del_queue(vdev, i); virtio_del_queue(vdev, i);
} }
qemu_coroutine_dec_pool_size(conf->num_queues * conf->queue_size / 2); qemu_coroutine_dec_pool_size(conf->num_queues * conf->queue_size / 2);
blk_ram_registrar_destroy(&s->blk_ram_registrar);
qemu_del_vm_change_state_handler(s->change); qemu_del_vm_change_state_handler(s->change);
blockdev_mark_auto_del(s->blk); blockdev_mark_auto_del(s->blk);
virtio_cleanup(vdev); virtio_cleanup(vdev);

View File

@ -19,6 +19,7 @@
#include "hw/block/block.h" #include "hw/block/block.h"
#include "sysemu/iothread.h" #include "sysemu/iothread.h"
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "sysemu/block-ram-registrar.h"
#include "qom/object.h" #include "qom/object.h"
#define TYPE_VIRTIO_BLK "virtio-blk-device" #define TYPE_VIRTIO_BLK "virtio-blk-device"
@ -64,6 +65,7 @@ struct VirtIOBlock {
struct VirtIOBlockDataPlane *dataplane; struct VirtIOBlockDataPlane *dataplane;
uint64_t host_features; uint64_t host_features;
size_t config_size; size_t config_size;
BlockRAMRegistrar blk_ram_registrar;
}; };
typedef struct VirtIOBlockReq { typedef struct VirtIOBlockReq {