#include <sys/ioctl.h>
#include "qapi/error.h"
#include "qemu/error-report.h"
-#include "qemu/queue.h"
+#include "qemu/module.h"
#include "monitor/monitor.h"
#include "migration/blocker.h"
#include "hw/virtio/vhost-scsi.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"
#include "hw/fw-path-provider.h"
+#include "hw/qdev-properties.h"
#include "qemu/cutils.h"
/* Features supported by host kernel. */
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
bool start = (val & VIRTIO_CONFIG_S_DRIVER_OK);
+ if (!vdev->vm_running) {
+ start = false;
+ }
+
if (vsc->dev.started == start) {
return;
}
{
}
+static int vhost_scsi_pre_save(void *opaque)
+{
+ VHostSCSICommon *vsc = opaque;
+
+ /* At this point, backend must be stopped, otherwise
+ * it might keep writing to memory. */
+ assert(!vsc->dev.started);
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_virtio_vhost_scsi = {
+ .name = "virtio-vhost_scsi",
+ .minimum_version_id = 1,
+ .version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_VIRTIO_DEVICE,
+ VMSTATE_END_OF_LIST()
+ },
+ .pre_save = vhost_scsi_pre_save,
+};
+
static void vhost_scsi_realize(DeviceState *dev, Error **errp)
{
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
goto close_fd;
}
- error_setg(&vsc->migration_blocker,
- "vhost-scsi does not support migration");
- migrate_add_blocker(vsc->migration_blocker, &err);
- if (err) {
- error_propagate(errp, err);
- error_free(vsc->migration_blocker);
- goto close_fd;
+ if (!vsc->migratable) {
+ error_setg(&vsc->migration_blocker,
+ "vhost-scsi does not support migration in all cases. "
+ "When external environment supports it (Orchestrator migrates "
+ "target SCSI device state or use shared storage over network), "
+ "set 'migratable' property to true to enable migration.");
+ migrate_add_blocker(vsc->migration_blocker, &err);
+ if (err) {
+ error_propagate(errp, err);
+ error_free(vsc->migration_blocker);
+ goto free_virtio;
+ }
}
vsc->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
- vsc->dev.vqs = g_new(struct vhost_virtqueue, vsc->dev.nvqs);
+ vsc->dev.vqs = g_new0(struct vhost_virtqueue, vsc->dev.nvqs);
vsc->dev.vq_index = 0;
vsc->dev.backend_features = 0;
return;
free_vqs:
- migrate_del_blocker(vsc->migration_blocker);
+ if (!vsc->migratable) {
+ migrate_del_blocker(vsc->migration_blocker);
+ }
g_free(vsc->dev.vqs);
+ free_virtio:
+ virtio_scsi_common_unrealize(dev);
close_fd:
close(vhostfd);
return;
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev);
+ struct vhost_virtqueue *vqs = vsc->dev.vqs;
- migrate_del_blocker(vsc->migration_blocker);
- error_free(vsc->migration_blocker);
+ if (!vsc->migratable) {
+ migrate_del_blocker(vsc->migration_blocker);
+ error_free(vsc->migration_blocker);
+ }
/* This will stop vhost backend. */
vhost_scsi_set_status(vdev, 0);
vhost_dev_cleanup(&vsc->dev);
- g_free(vsc->dev.vqs);
+ g_free(vqs);
- virtio_scsi_common_unrealize(dev, errp);
+ virtio_scsi_common_unrealize(dev);
}
static Property vhost_scsi_properties[] = {
DEFINE_PROP_BIT64("t10_pi", VHostSCSICommon, host_features,
VIRTIO_SCSI_F_T10_PI,
false),
+ DEFINE_PROP_BOOL("migratable", VHostSCSICommon, migratable, false),
DEFINE_PROP_END_OF_LIST(),
};
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(klass);
dc->props = vhost_scsi_properties;
+ dc->vmsd = &vmstate_virtio_vhost_scsi;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
vdc->realize = vhost_scsi_realize;
vdc->unrealize = vhost_scsi_unrealize;