summaryrefslogtreecommitdiffstats
path: root/qemu/hw/block/virtio-blk.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/hw/block/virtio-blk.c')
-rw-r--r--qemu/hw/block/virtio-blk.c158
1 files changed, 63 insertions, 95 deletions
diff --git a/qemu/hw/block/virtio-blk.c b/qemu/hw/block/virtio-blk.c
index 1556c9cf5..3f88f8cf5 100644
--- a/qemu/hw/block/virtio-blk.c
+++ b/qemu/hw/block/virtio-blk.c
@@ -11,6 +11,8 @@
*
*/
+#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "qemu-common.h"
#include "qemu/iov.h"
#include "qemu/error-report.h"
@@ -20,7 +22,6 @@
#include "sysemu/blockdev.h"
#include "hw/virtio/virtio-blk.h"
#include "dataplane/virtio-blk.h"
-#include "migration/migration.h"
#include "block/scsi.h"
#ifdef __linux__
# include <scsi/sg.h>
@@ -28,26 +29,23 @@
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"
-VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
+void virtio_blk_init_request(VirtIOBlock *s, VirtIOBlockReq *req)
{
- VirtIOBlockReq *req = g_slice_new(VirtIOBlockReq);
req->dev = s;
req->qiov.size = 0;
req->in_len = 0;
req->next = NULL;
req->mr_next = NULL;
- return req;
}
void virtio_blk_free_request(VirtIOBlockReq *req)
{
if (req) {
- g_slice_free(VirtIOBlockReq, req);
+ g_free(req);
}
}
-static void virtio_blk_complete_request(VirtIOBlockReq *req,
- unsigned char status)
+static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
{
VirtIOBlock *s = req->dev;
VirtIODevice *vdev = VIRTIO_DEVICE(s);
@@ -56,12 +54,11 @@ static void virtio_blk_complete_request(VirtIOBlockReq *req,
stb_p(&req->in->status, status);
virtqueue_push(s->vq, &req->elem, req->in_len);
- virtio_notify(vdev, s->vq);
-}
-
-static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
-{
- req->dev->complete_request(req, status);
+ if (s->dataplane_started && !s->dataplane_disabled) {
+ virtio_blk_data_plane_notify(s->dataplane);
+ } else {
+ virtio_notify(vdev, s->vq);
+ }
}
static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
@@ -72,11 +69,14 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
VirtIOBlock *s = req->dev;
if (action == BLOCK_ERROR_ACTION_STOP) {
+ /* Break the link as the next request is going to be parsed from the
+ * ring again. Otherwise we may end up doing a double completion! */
+ req->mr_next = NULL;
req->next = s->rq;
s->rq = req;
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
- block_acct_done(blk_get_stats(s->blk), &req->acct);
+ block_acct_failed(blk_get_stats(s->blk), &req->acct);
virtio_blk_free_request(req);
}
@@ -189,13 +189,11 @@ out:
static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
{
- VirtIOBlockReq *req = virtio_blk_alloc_request(s);
+ VirtIOBlockReq *req = virtqueue_pop(s->vq, sizeof(VirtIOBlockReq));
- if (!virtqueue_pop(s->vq, &req->elem)) {
- virtio_blk_free_request(req);
- return NULL;
+ if (req) {
+ virtio_blk_init_request(s, req);
}
-
return req;
}
@@ -404,24 +402,16 @@ void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb)
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) {
+ /*
+ * NOTE: We cannot merge the requests in below situations:
+ * 1. requests are not sequential
+ * 2. merge would exceed maximum number of IOVs
+ * 3. merge would exceed maximum transfer length of backend device
+ */
+ if (sector_num + nb_sectors != req->sector_num ||
+ niov > blk_get_max_iov(blk) - req->qiov.niov ||
+ req->qiov.size / BDRV_SECTOR_SIZE > max_xfer_len ||
+ nb_sectors > max_xfer_len - req->qiov.size / BDRV_SECTOR_SIZE) {
submit_requests(blk, mrb, start, num_reqs, niov);
num_reqs = 0;
}
@@ -536,6 +526,8 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
if (!virtio_blk_sect_range_ok(req->dev, req->sector_num,
req->qiov.size)) {
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
+ block_acct_invalid(blk_get_stats(req->dev->blk),
+ is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
virtio_blk_free_request(req);
return;
}
@@ -586,19 +578,12 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
}
}
-static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
{
- VirtIOBlock *s = VIRTIO_BLK(vdev);
VirtIOBlockReq *req;
MultiReqBuffer mrb = {};
- /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start
- * dataplane here instead of waiting for .set_status().
- */
- if (s->dataplane) {
- virtio_blk_data_plane_start(s->dataplane);
- return;
- }
+ blk_io_plug(s->blk);
while ((req = virtio_blk_get_request(s))) {
virtio_blk_handle_request(req, &mrb);
@@ -607,6 +592,24 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
if (mrb.num_reqs) {
virtio_blk_submit_multireq(s->blk, &mrb);
}
+
+ blk_io_unplug(s->blk);
+}
+
+static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIOBlock *s = (VirtIOBlock *)vdev;
+
+ if (s->dataplane) {
+ /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start
+ * dataplane here instead of waiting for .set_status().
+ */
+ virtio_blk_data_plane_start(s->dataplane);
+ if (!s->dataplane_disabled) {
+ return;
+ }
+ }
+ virtio_blk_handle_vq(s, vq);
}
static void virtio_blk_dma_restart_bh(void *opaque)
@@ -731,7 +734,7 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features,
virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY);
virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY);
virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE);
- if (__virtio_has_feature(features, VIRTIO_F_VERSION_1)) {
+ if (virtio_has_feature(features, VIRTIO_F_VERSION_1)) {
if (s->conf.scsi) {
error_setg(errp, "Please set scsi=off for virtio-blk devices in order to use virtio 1.0");
return 0;
@@ -782,10 +785,11 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
*
* s->blk would erroneously be placed in writethrough mode.
*/
- if (!virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) {
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) {
aio_context_acquire(blk_get_aio_context(s->blk));
blk_set_enable_write_cache(s->blk,
- virtio_has_feature(vdev, VIRTIO_BLK_F_WCE));
+ virtio_vdev_has_feature(vdev,
+ VIRTIO_BLK_F_WCE));
aio_context_release(blk_get_aio_context(s->blk));
}
}
@@ -793,6 +797,11 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
static void virtio_blk_save(QEMUFile *f, void *opaque)
{
VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
+ VirtIOBlock *s = VIRTIO_BLK(vdev);
+
+ if (s->dataplane) {
+ virtio_blk_data_plane_stop(s->dataplane);
+ }
virtio_save(vdev, f);
}
@@ -804,8 +813,7 @@ static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f)
while (req) {
qemu_put_sbyte(f, 1);
- qemu_put_buffer(f, (unsigned char *)&req->elem,
- sizeof(VirtQueueElement));
+ qemu_put_virtqueue_element(f, &req->elem);
req = req->next;
}
qemu_put_sbyte(f, 0);
@@ -828,16 +836,11 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
VirtIOBlock *s = VIRTIO_BLK(vdev);
while (qemu_get_sbyte(f)) {
- VirtIOBlockReq *req = virtio_blk_alloc_request(s);
- qemu_get_buffer(f, (unsigned char *)&req->elem,
- sizeof(VirtQueueElement));
+ VirtIOBlockReq *req;
+ req = qemu_get_virtqueue_element(f, sizeof(VirtIOBlockReq));
+ virtio_blk_init_request(s, req);
req->next = s->rq;
s->rq = req;
-
- virtqueue_map_sg(req->elem.in_sg, req->elem.in_addr,
- req->elem.in_num, 1);
- virtqueue_map_sg(req->elem.out_sg, req->elem.out_addr,
- req->elem.out_num, 0);
}
return 0;
@@ -854,36 +857,6 @@ static const BlockDevOps virtio_block_ops = {
.resize_cb = virtio_blk_resize,
};
-/* Disable dataplane thread during live migration since it does not
- * update the dirty memory bitmap yet.
- */
-static void virtio_blk_migration_state_changed(Notifier *notifier, void *data)
-{
- VirtIOBlock *s = container_of(notifier, VirtIOBlock,
- migration_state_notifier);
- MigrationState *mig = data;
- Error *err = NULL;
-
- if (migration_in_setup(mig)) {
- if (!s->dataplane) {
- return;
- }
- virtio_blk_data_plane_destroy(s->dataplane);
- s->dataplane = NULL;
- } else if (migration_has_finished(mig) ||
- migration_has_failed(mig)) {
- if (s->dataplane) {
- return;
- }
- blk_drain_all(); /* complete in-flight non-dataplane requests */
- virtio_blk_data_plane_create(VIRTIO_DEVICE(s), &s->conf,
- &s->dataplane, &err);
- if (err != NULL) {
- error_report_err(err);
- }
- }
-}
-
static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
@@ -918,15 +891,12 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
s->sector_mask = (s->conf.conf.logical_block_size / BDRV_SECTOR_SIZE) - 1;
s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
- s->complete_request = virtio_blk_complete_request;
virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err);
if (err != NULL) {
error_propagate(errp, err);
virtio_cleanup(vdev);
return;
}
- s->migration_state_notifier.notify = virtio_blk_migration_state_changed;
- add_migration_state_change_notifier(&s->migration_state_notifier);
s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
@@ -942,7 +912,6 @@ static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIOBlock *s = VIRTIO_BLK(dev);
- remove_migration_state_change_notifier(&s->migration_state_notifier);
virtio_blk_data_plane_destroy(s->dataplane);
s->dataplane = NULL;
qemu_del_vm_change_state_handler(s->change);
@@ -970,11 +939,10 @@ static Property virtio_blk_properties[] = {
DEFINE_PROP_STRING("serial", VirtIOBlock, conf.serial),
DEFINE_PROP_BIT("config-wce", VirtIOBlock, conf.config_wce, 0, true),
#ifdef __linux__
- DEFINE_PROP_BIT("scsi", VirtIOBlock, conf.scsi, 0, true),
+ DEFINE_PROP_BIT("scsi", VirtIOBlock, conf.scsi, 0, false),
#endif
DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0,
true),
- DEFINE_PROP_BIT("x-data-plane", VirtIOBlock, conf.data_plane, 0, false),
DEFINE_PROP_END_OF_LIST(),
};