From 61e68b3fbd3e2b7beb636bc56f78d9c1ca25e8f9 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 16 Sep 2014 15:20:17 +0800 Subject: scsi: Optimize scsi_req_alloc Zeroing sense buffer for each scsi request is not efficient, we can just leave it uninitialized because sense_len is set to 0. Move the implicitly zeroed fields to the end of the structure and use a partial memset. The explicitly initialized fields (by scsi_req_alloc or scsi_req_new) are moved to the beginning of the structure, before sense buffer, to skip the memset. Also change g_malloc0 to g_slice_alloc. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-bus.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 954c6072bf..af293b59da 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -551,8 +551,11 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d, SCSIRequest *req; SCSIBus *bus = scsi_bus_from_device(d); BusState *qbus = BUS(bus); + const int memset_off = offsetof(SCSIRequest, sense) + + sizeof(req->sense); - req = g_malloc0(reqops->size); + req = g_slice_alloc(reqops->size); + memset((uint8_t *)req + memset_off, 0, reqops->size - memset_off); req->refcount = 1; req->bus = bus; req->dev = d; @@ -560,7 +563,6 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d, req->lun = lun; req->hba_private = hba_private; req->status = -1; - req->sense_len = 0; req->ops = reqops; object_ref(OBJECT(d)); object_ref(OBJECT(qbus->parent)); @@ -1603,7 +1605,7 @@ void scsi_req_unref(SCSIRequest *req) } object_unref(OBJECT(req->dev)); object_unref(OBJECT(qbus->parent)); - g_free(req); + g_slice_free1(req->ops->size, req); } } -- cgit v1.2.3 From faf1e1fb4cdd3f1f71c948cb53e7d50f0798a202 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 16 Sep 2014 15:20:18 +0800 Subject: virtio-scsi: Optimize virtio_scsi_init_req The VirtQueueElement is a very big structure (>48k!), since it will be initialzed by virtqueue_pop, we can save the expensive zeroing here. This saves a few microseconds per request in my test: [fio-test] rw bs iodepth jobs bw iops latency -------------------------------------------------------------------------------------------- Before read 4k 1 1 110 28269 34 After read 4k 1 1 131 33745 28 Whereas, virtio-blk read 4k 1 1 217 55673 16 Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 86aba8851d..f0d21a3fda 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -24,12 +24,19 @@ typedef struct VirtIOSCSIReq { VirtIOSCSI *dev; VirtQueue *vq; - VirtQueueElement elem; QEMUSGList qsgl; + QEMUIOVector resp_iov; + + /* Note: + * - fields before elem are initialized by virtio_scsi_init_req; + * - elem is uninitialized at the time of allocation. + * - fields after elem are zeroed by virtio_scsi_init_req. + * */ + + VirtQueueElement elem; SCSIRequest *sreq; size_t resp_size; enum SCSIXferMode mode; - QEMUIOVector resp_iov; union { VirtIOSCSICmdResp cmd; VirtIOSCSICtrlTMFResp tmf; @@ -68,23 +75,26 @@ static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun) static VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq) { VirtIOSCSIReq *req; - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); - - req = g_malloc0(sizeof(*req) + vs->cdb_size); + VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s; + const size_t zero_skip = offsetof(VirtIOSCSIReq, elem) + + sizeof(VirtQueueElement); + req = g_slice_alloc(sizeof(*req) + vs->cdb_size); req->vq = vq; req->dev = s; - req->sreq = NULL; qemu_sglist_init(&req->qsgl, DEVICE(s), 8, &address_space_memory); qemu_iovec_init(&req->resp_iov, 1); + memset((uint8_t *)req + zero_skip, 0, sizeof(*req) - zero_skip); return req; } static void virtio_scsi_free_req(VirtIOSCSIReq *req) { + VirtIOSCSICommon *vs = (VirtIOSCSICommon *)req->dev; + qemu_iovec_destroy(&req->resp_iov); qemu_sglist_destroy(&req->qsgl); - g_free(req); + g_slice_free1(sizeof(*req) + vs->cdb_size, req); } static void virtio_scsi_complete_req(VirtIOSCSIReq *req) -- cgit v1.2.3 From 7ce0425575745a40e94e75426607e0bec17899fa Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 17 Sep 2014 12:40:07 +0200 Subject: vhost-scsi: use virtio_ldl_p This helps for cross-endian configurations. Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- hw/scsi/vhost-scsi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 7146e0ec49..308b393f96 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -23,6 +23,7 @@ #include "hw/virtio/vhost.h" #include "hw/virtio/virtio-scsi.h" #include "hw/virtio/virtio-bus.h" +#include "hw/virtio/virtio-access.h" /* Features supported by host kernel. */ static const int kernel_feature_bits[] = { @@ -163,8 +164,8 @@ static void vhost_scsi_set_config(VirtIODevice *vdev, VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); - if ((uint32_t) ldl_p(&scsiconf->sense_size) != vs->sense_size || - (uint32_t) ldl_p(&scsiconf->cdb_size) != vs->cdb_size) { + if ((uint32_t) virtio_ldl_p(vdev, &scsiconf->sense_size) != vs->sense_size || + (uint32_t) virtio_ldl_p(vdev, &scsiconf->cdb_size) != vs->cdb_size) { error_report("vhost-scsi does not support changing the sense data and CDB sizes"); exit(1); } -- cgit v1.2.3 From 9df7bfddcc25a22b99be5fe9b14ce367fa43b106 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 17 Sep 2014 18:10:37 +0200 Subject: virtio-scsi: clean up virtio_scsi_parse_cdb The command direction according to the guest-passed buffers is already stored in the VirtIOSCSIReq. We can use it instead of computing it again from req->elem. Cc: Laszlo Ersek Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index f0d21a3fda..6953cbe6dd 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -430,13 +430,7 @@ static int virtio_scsi_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, * host device passthrough. */ cmd->xfer = req->qsgl.size; - if (cmd->xfer == 0) { - cmd->mode = SCSI_XFER_NONE; - } else if (iov_size(req->elem.in_sg, req->elem.in_num) > req->resp_size) { - cmd->mode = SCSI_XFER_FROM_DEV; - } else { - cmd->mode = SCSI_XFER_TO_DEV; - } + cmd->mode = req->mode; return 0; } -- cgit v1.2.3 From bf359a445e780815866327891a845071197dfb63 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:00 +0800 Subject: virtio-scsi: Split virtio_scsi_handle_cmd_req from virtio_scsi_handle_cmd This is the "common part" to handle one cmd request. Refactor out for later usage of dataplane iothread code. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 117 +++++++++++++++++++------------------------------- 1 file changed, 43 insertions(+), 74 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 6953cbe6dd..57b2b7b3dc 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -21,41 +21,6 @@ #include #include "hw/virtio/virtio-access.h" -typedef struct VirtIOSCSIReq { - VirtIOSCSI *dev; - VirtQueue *vq; - QEMUSGList qsgl; - QEMUIOVector resp_iov; - - /* Note: - * - fields before elem are initialized by virtio_scsi_init_req; - * - elem is uninitialized at the time of allocation. - * - fields after elem are zeroed by virtio_scsi_init_req. - * */ - - VirtQueueElement elem; - SCSIRequest *sreq; - size_t resp_size; - enum SCSIXferMode mode; - union { - VirtIOSCSICmdResp cmd; - VirtIOSCSICtrlTMFResp tmf; - VirtIOSCSICtrlANResp an; - VirtIOSCSIEvent event; - } resp; - union { - struct { - VirtIOSCSICmdReq cmd; - uint8_t cdb[]; - } QEMU_PACKED; - VirtIOSCSICtrlTMFReq tmf; - VirtIOSCSICtrlANReq an; - } req; -} VirtIOSCSIReq; - -QEMU_BUILD_BUG_ON(offsetof(VirtIOSCSIReq, req.cdb) != - offsetof(VirtIOSCSIReq, req.cmd) + sizeof(VirtIOSCSICmdReq)); - static inline int virtio_scsi_get_lun(uint8_t *lun) { return ((lun[2] << 8) | lun[3]) & 0x3FFF; @@ -462,52 +427,56 @@ static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req) virtio_scsi_complete_cmd_req(req); } +void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req) +{ + VirtIOSCSICommon *vs = &s->parent_obj; + int n; + SCSIDevice *d; + int rc; + + rc = virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size, + sizeof(VirtIOSCSICmdResp) + vs->sense_size); + if (rc < 0) { + if (rc == -ENOTSUP) { + virtio_scsi_fail_cmd_req(req); + } else { + virtio_scsi_bad_req(); + } + return; + } + + d = virtio_scsi_device_find(s, req->req.cmd.lun); + if (!d) { + req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET; + virtio_scsi_complete_cmd_req(req); + return; + } + req->sreq = scsi_req_new(d, req->req.cmd.tag, + virtio_scsi_get_lun(req->req.cmd.lun), + req->req.cdb, req); + + if (req->sreq->cmd.mode != SCSI_XFER_NONE + && (req->sreq->cmd.mode != req->mode || + req->sreq->cmd.xfer > req->qsgl.size)) { + req->resp.cmd.response = VIRTIO_SCSI_S_OVERRUN; + virtio_scsi_complete_cmd_req(req); + return; + } + + n = scsi_req_enqueue(req->sreq); + if (n) { + scsi_req_continue(req->sreq); + } +} + static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) { /* use non-QOM casts in the data path */ VirtIOSCSI *s = (VirtIOSCSI *)vdev; - VirtIOSCSICommon *vs = &s->parent_obj; - VirtIOSCSIReq *req; - int n; while ((req = virtio_scsi_pop_req(s, vq))) { - SCSIDevice *d; - int rc; - - rc = virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size, - sizeof(VirtIOSCSICmdResp) + vs->sense_size); - if (rc < 0) { - if (rc == -ENOTSUP) { - virtio_scsi_fail_cmd_req(req); - } else { - virtio_scsi_bad_req(); - } - continue; - } - - d = virtio_scsi_device_find(s, req->req.cmd.lun); - if (!d) { - req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET; - virtio_scsi_complete_cmd_req(req); - continue; - } - req->sreq = scsi_req_new(d, req->req.cmd.tag, - virtio_scsi_get_lun(req->req.cmd.lun), - req->req.cdb, req); - - if (req->sreq->cmd.mode != SCSI_XFER_NONE - && (req->sreq->cmd.mode != req->mode || - req->sreq->cmd.xfer > req->qsgl.size)) { - req->resp.cmd.response = VIRTIO_SCSI_S_OVERRUN; - virtio_scsi_complete_cmd_req(req); - continue; - } - - n = scsi_req_enqueue(req->sreq); - if (n) { - scsi_req_continue(req->sreq); - } + virtio_scsi_handle_cmd_req(s, req); } } -- cgit v1.2.3 From dc56b7c4fb0c95a9648ad5bf29e09e5676404077 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:01 +0800 Subject: virtio-scsi: Split virtio_scsi_handle_ctrl_req from virtio_scsi_handle_ctrl To share with dataplane code. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 60 ++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 27 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 57b2b7b3dc..5f3c0c1087 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -308,40 +308,46 @@ fail: req->resp.tmf.response = VIRTIO_SCSI_S_BAD_TARGET; } -static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) +void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) { - VirtIOSCSI *s = (VirtIOSCSI *)vdev; - VirtIOSCSIReq *req; + VirtIODevice *vdev = (VirtIODevice *)s; + int type; - while ((req = virtio_scsi_pop_req(s, vq))) { - int type; + if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0, + &type, sizeof(type)) < sizeof(type)) { + virtio_scsi_bad_req(); + return; + } - if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0, - &type, sizeof(type)) < sizeof(type)) { + virtio_tswap32s(vdev, &req->req.tmf.type); + if (req->req.tmf.type == VIRTIO_SCSI_T_TMF) { + if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq), + sizeof(VirtIOSCSICtrlTMFResp)) < 0) { virtio_scsi_bad_req(); - continue; + } else { + virtio_scsi_do_tmf(s, req); } - virtio_tswap32s(vdev, &req->req.tmf.type); - if (req->req.tmf.type == VIRTIO_SCSI_T_TMF) { - if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq), - sizeof(VirtIOSCSICtrlTMFResp)) < 0) { - virtio_scsi_bad_req(); - } else { - virtio_scsi_do_tmf(s, req); - } - - } else if (req->req.tmf.type == VIRTIO_SCSI_T_AN_QUERY || - req->req.tmf.type == VIRTIO_SCSI_T_AN_SUBSCRIBE) { - if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlANReq), - sizeof(VirtIOSCSICtrlANResp)) < 0) { - virtio_scsi_bad_req(); - } else { - req->resp.an.event_actual = 0; - req->resp.an.response = VIRTIO_SCSI_S_OK; - } + } else if (req->req.tmf.type == VIRTIO_SCSI_T_AN_QUERY || + req->req.tmf.type == VIRTIO_SCSI_T_AN_SUBSCRIBE) { + if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlANReq), + sizeof(VirtIOSCSICtrlANResp)) < 0) { + virtio_scsi_bad_req(); + } else { + req->resp.an.event_actual = 0; + req->resp.an.response = VIRTIO_SCSI_S_OK; } - virtio_scsi_complete_req(req); + } + virtio_scsi_complete_req(req); +} + +static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOSCSI *s = (VirtIOSCSI *)vdev; + VirtIOSCSIReq *req; + + while ((req = virtio_scsi_pop_req(s, vq))) { + virtio_scsi_handle_ctrl_req(s, req); } } -- cgit v1.2.3 From c505333dab10cf7ffd3a30259c2df77d4d30343d Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:03 +0800 Subject: virtio-scsi: Make virtio_scsi_init_req public To share with datplane code later. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 5f3c0c1087..8cab75b6d6 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -37,7 +37,7 @@ static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun) return scsi_device_find(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun)); } -static VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq) +VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq) { VirtIOSCSIReq *req; VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s; -- cgit v1.2.3 From aa8e8f83d0458a87e9a86ccfedfe68999d2d0fa6 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:04 +0800 Subject: virtio-scsi: Make virtio_scsi_free_req public To share with dataplane code later. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 8cab75b6d6..c7ae83dc45 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -53,7 +53,7 @@ VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq) return req; } -static void virtio_scsi_free_req(VirtIOSCSIReq *req) +void virtio_scsi_free_req(VirtIOSCSIReq *req) { VirtIOSCSICommon *vs = (VirtIOSCSICommon *)req->dev; -- cgit v1.2.3 From 20e6dca1df6b6ea74c3d6af74dc2184f464b3035 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:05 +0800 Subject: virtio-scsi: Make virtio_scsi_push_event public Later this will be called by dataplane code. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index c7ae83dc45..58b420084e 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -561,8 +561,8 @@ static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, - uint32_t event, uint32_t reason) +void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, + uint32_t event, uint32_t reason) { VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); VirtIOSCSIReq *req; -- cgit v1.2.3 From 7779edfeb1822ff5f554a4c1f3e9798789a9352c Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:27 +0800 Subject: virtio-net: use aliases instead of duplicate qdev properties virtio-net-pci, virtio-net-s390, and virtio-net-ccw all duplicate the qdev properties of their VirtIONet child. This approach does not work well with string or pointer properties since we must be careful about leaking or double-freeing them. Use the QOM alias property to forward property accesses to the VirtIONet child. This way no duplication is necessary. Signed-off-by: Gonglei Reviewed-by: Cornelia Huck Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- hw/s390x/s390-virtio-bus.c | 3 +-- hw/s390x/virtio-ccw.c | 3 +-- hw/virtio/virtio-pci.c | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 6b6fb61c47..5b5d595834 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -161,6 +161,7 @@ static void s390_virtio_net_instance_init(Object *obj) VirtIONetS390 *dev = VIRTIO_NET_S390(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } static int s390_virtio_blk_init(VirtIOS390Device *s390_dev) @@ -493,10 +494,8 @@ static unsigned virtio_s390_get_features(DeviceState *d) /**************** S390 Virtio Bus Device Descriptions *******************/ static Property s390_virtio_net_properties[] = { - DEFINE_NIC_PROPERTIES(VirtIONetS390, vdev.nic_conf), DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features), DEFINE_VIRTIO_NET_FEATURES(VirtIOS390Device, host_features), - DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetS390, vdev.net_conf), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 33a1d863b1..7d675772e4 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -794,6 +794,7 @@ static void virtio_ccw_net_instance_init(Object *obj) VirtIONetCcw *dev = VIRTIO_NET_CCW(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev) @@ -1374,8 +1375,6 @@ static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f) static Property virtio_ccw_net_properties[] = { DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_VIRTIO_NET_FEATURES(VirtioCcwDevice, host_features[0]), - DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetCcw, vdev.net_conf), - DEFINE_NIC_PROPERTIES(VirtIONetCcw, vdev.nic_conf), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index f5608140f9..155fac9e87 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1425,8 +1425,6 @@ static Property virtio_net_properties[] = { VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false), DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features), - DEFINE_NIC_PROPERTIES(VirtIONetPCI, vdev.nic_conf), - DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetPCI, vdev.net_conf), DEFINE_PROP_END_OF_LIST(), }; @@ -1467,6 +1465,7 @@ static void virtio_net_pci_instance_init(Object *obj) VirtIONetPCI *dev = VIRTIO_NET_PCI(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } static const TypeInfo virtio_net_pci_info = { -- cgit v1.2.3 From 6a0c6b59788627541faf70864464f1e155dc18d7 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:28 +0800 Subject: virtio-net: fix virtio-net child refcount in transports object_initialize() leaves the object with a refcount of 1. object_property_add_child() adds its own reference which is dropped again when the property is deleted. The upshot of this is that we always have a refcount >= 1. Upon hot unplug the virtio-net child is not finalized! Drop our reference after the child property has been added to the parent. Signed-off-by: Gonglei Reviewed-by: Cornelia Huck Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- hw/s390x/s390-virtio-bus.c | 1 + hw/s390x/virtio-ccw.c | 1 + hw/virtio/virtio-pci.c | 1 + 3 files changed, 3 insertions(+) (limited to 'hw') diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 5b5d595834..297eac2367 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -161,6 +161,7 @@ static void s390_virtio_net_instance_init(Object *obj) VirtIONetS390 *dev = VIRTIO_NET_S390(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + object_unref(OBJECT(&dev->vdev)); qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 7d675772e4..bb699f27f6 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -794,6 +794,7 @@ static void virtio_ccw_net_instance_init(Object *obj) VirtIONetCcw *dev = VIRTIO_NET_CCW(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + object_unref(OBJECT(&dev->vdev)); qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 155fac9e87..b82b7380bb 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1465,6 +1465,7 @@ static void virtio_net_pci_instance_init(Object *obj) VirtIONetPCI *dev = VIRTIO_NET_PCI(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + object_unref(OBJECT(&dev->vdev)); qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } -- cgit v1.2.3 From c39343fd811a22c921fc08e9e6ca62c8e7539264 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:29 +0800 Subject: virtio/vhost-scsi: use aliases instead of duplicate qdev properties {virtio, vhost}-scsi-{pci, s390, ccw} all duplicate the qdev properties of their VirtIOSCSI/VHostSCSI child. This approach does not work well with string or pointer properties since we must be careful about leaking or double-freeing them. Use the QOM alias property to forward property accesses to the VirtIOSCSI/VHostSCSI child. This way no duplication is necessary. Signed-off-by: Gonglei Reviewed-by: Cornelia Huck Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- hw/s390x/s390-virtio-bus.c | 4 ++-- hw/s390x/virtio-ccw.c | 4 ++-- hw/virtio/virtio-pci.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 297eac2367..eaaa275775 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -258,6 +258,7 @@ static void s390_virtio_scsi_instance_init(Object *obj) VirtIOSCSIS390 *dev = VIRTIO_SCSI_S390(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } #ifdef CONFIG_VHOST_SCSI @@ -279,6 +280,7 @@ static void s390_vhost_scsi_instance_init(Object *obj) VHostSCSIS390 *dev = VHOST_SCSI_S390(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } #endif @@ -614,7 +616,6 @@ static const TypeInfo virtio_s390_device_info = { }; static Property s390_virtio_scsi_properties[] = { - DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIS390, vdev.parent_obj.conf), DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features), DEFINE_VIRTIO_SCSI_FEATURES(VirtIOS390Device, host_features), DEFINE_PROP_END_OF_LIST(), @@ -640,7 +641,6 @@ static const TypeInfo s390_virtio_scsi = { #ifdef CONFIG_VHOST_SCSI static Property s390_vhost_scsi_properties[] = { DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features), - DEFINE_VHOST_SCSI_PROPERTIES(VHostSCSIS390, vdev.parent_obj.conf), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index bb699f27f6..458aabc68b 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -938,6 +938,7 @@ static void virtio_ccw_scsi_instance_init(Object *obj) VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } #ifdef CONFIG_VHOST_SCSI @@ -959,6 +960,7 @@ static void vhost_ccw_scsi_instance_init(Object *obj) VHostSCSICcw *dev = VHOST_SCSI_CCW(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } #endif @@ -1481,7 +1483,6 @@ static const TypeInfo virtio_ccw_balloon = { static Property virtio_ccw_scsi_properties[] = { DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), - DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.parent_obj.conf), DEFINE_VIRTIO_SCSI_FEATURES(VirtioCcwDevice, host_features[0]), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), @@ -1510,7 +1511,6 @@ static const TypeInfo virtio_ccw_scsi = { #ifdef CONFIG_VHOST_SCSI static Property vhost_ccw_scsi_properties[] = { DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), - DEFINE_VHOST_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.parent_obj.conf), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index b82b7380bb..ef48983838 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1135,7 +1135,6 @@ static Property virtio_scsi_pci_properties[] = { DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, DEV_NVECTORS_UNSPECIFIED), DEFINE_VIRTIO_SCSI_FEATURES(VirtIOPCIProxy, host_features), - DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIPCI, vdev.parent_obj.conf), DEFINE_PROP_END_OF_LIST(), }; @@ -1187,6 +1186,7 @@ static void virtio_scsi_pci_instance_init(Object *obj) VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } static const TypeInfo virtio_scsi_pci_info = { @@ -1203,7 +1203,6 @@ static const TypeInfo virtio_scsi_pci_info = { static Property vhost_scsi_pci_properties[] = { DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, DEV_NVECTORS_UNSPECIFIED), - DEFINE_VHOST_SCSI_PROPERTIES(VHostSCSIPCI, vdev.parent_obj.conf), DEFINE_PROP_END_OF_LIST(), }; @@ -1243,6 +1242,7 @@ static void vhost_scsi_pci_instance_init(Object *obj) VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } static const TypeInfo vhost_scsi_pci_info = { -- cgit v1.2.3 From 1312f12bcc8911ed99b67227fb9d1607295f71ed Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:30 +0800 Subject: virtio/vhost-scsi: fix virtio-scsi/vhost-scsi child refcount in transports object_initialize() leaves the object with a refcount of 1. object_property_add_child() adds its own reference which is dropped again when the property is deleted. The upshot of this is that we always have a refcount >= 1. Upon hot unplug the virtio-scsi/vhost-scsi child is not finalized! Drop our reference after the child property has been added to the parent. Signed-off-by: Gonglei Reviewed-by: Cornelia Huck Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- hw/s390x/s390-virtio-bus.c | 2 ++ hw/s390x/virtio-ccw.c | 2 ++ hw/virtio/virtio-pci.c | 2 ++ 3 files changed, 6 insertions(+) (limited to 'hw') diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index eaaa275775..42760340f4 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -258,6 +258,7 @@ static void s390_virtio_scsi_instance_init(Object *obj) VirtIOSCSIS390 *dev = VIRTIO_SCSI_S390(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + object_unref(OBJECT(&dev->vdev)); qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } @@ -280,6 +281,7 @@ static void s390_vhost_scsi_instance_init(Object *obj) VHostSCSIS390 *dev = VHOST_SCSI_S390(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + object_unref(OBJECT(&dev->vdev)); qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } #endif diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 458aabc68b..a466674ba7 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -938,6 +938,7 @@ static void virtio_ccw_scsi_instance_init(Object *obj) VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + object_unref(OBJECT(&dev->vdev)); qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } @@ -960,6 +961,7 @@ static void vhost_ccw_scsi_instance_init(Object *obj) VHostSCSICcw *dev = VHOST_SCSI_CCW(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + object_unref(OBJECT(&dev->vdev)); qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } #endif diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index ef48983838..09f209325e 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1186,6 +1186,7 @@ static void virtio_scsi_pci_instance_init(Object *obj) VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + object_unref(OBJECT(&dev->vdev)); qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } @@ -1242,6 +1243,7 @@ static void vhost_scsi_pci_instance_init(Object *obj) VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + object_unref(OBJECT(&dev->vdev)); qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } -- cgit v1.2.3 From 4f456d8025c7259c66b2b2bcec99d5c6c94d99be Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:31 +0800 Subject: virtio-serial: use aliases instead of duplicate qdev properties virtio-serial-{pci, s390, ccw} all duplicate the qdev properties of their VirtIOSerial child. This approach does not work well with string or pointer properties since we must be careful about leaking or double-freeing them. Use the QOM alias property to forward property accesses to the VirtIOSerial child. This way no duplication is necessary. Signed-off-by: Gonglei Reviewed-by: Cornelia Huck Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- hw/s390x/s390-virtio-bus.c | 2 +- hw/s390x/virtio-ccw.c | 2 +- hw/virtio/virtio-pci.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 42760340f4..31f5286e3c 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -226,6 +226,7 @@ static void s390_virtio_serial_instance_init(Object *obj) VirtIOSerialS390 *dev = VIRTIO_SERIAL_S390(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } static int s390_virtio_scsi_init(VirtIOS390Device *s390_dev) @@ -537,7 +538,6 @@ static const TypeInfo s390_virtio_blk = { }; static Property s390_virtio_serial_properties[] = { - DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtIOSerialS390, vdev.serial), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index a466674ba7..271104d049 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -852,6 +852,7 @@ static void virtio_ccw_serial_instance_init(Object *obj) VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } static int virtio_ccw_balloon_init(VirtioCcwDevice *ccw_dev) @@ -1432,7 +1433,6 @@ static const TypeInfo virtio_ccw_blk = { static Property virtio_ccw_serial_properties[] = { DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), - DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtioSerialCcw, vdev.serial), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 09f209325e..3c1f37bfe4 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1387,7 +1387,6 @@ static Property virtio_serial_pci_properties[] = { VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtIOSerialPCI, vdev.serial), DEFINE_PROP_END_OF_LIST(), }; @@ -1410,6 +1409,7 @@ static void virtio_serial_pci_instance_init(Object *obj) VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } static const TypeInfo virtio_serial_pci_info = { -- cgit v1.2.3 From e77ca8b92af8a5213897331d676089e8919f383d Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:32 +0800 Subject: virtio-serial: fix virtio-serial child refcount in transports object_initialize() leaves the object with a refcount of 1. object_property_add_child() adds its own reference which is dropped again when the property is deleted. The upshot of this is that we always have a refcount >= 1. Upon hot unplug the virtio-serial child is not finalized! Drop our reference after the child property has been added to the parent. Signed-off-by: Gonglei Reviewed-by: Cornelia Huck Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- hw/s390x/s390-virtio-bus.c | 1 + hw/s390x/virtio-ccw.c | 1 + hw/virtio/virtio-pci.c | 1 + 3 files changed, 3 insertions(+) (limited to 'hw') diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 31f5286e3c..422402e564 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -227,6 +227,7 @@ static void s390_virtio_serial_instance_init(Object *obj) object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + object_unref(OBJECT(&dev->vdev)); } static int s390_virtio_scsi_init(VirtIOS390Device *s390_dev) diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 271104d049..5d7f3a6af7 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -853,6 +853,7 @@ static void virtio_ccw_serial_instance_init(Object *obj) object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + object_unref(OBJECT(&dev->vdev)); } static int virtio_ccw_balloon_init(VirtioCcwDevice *ccw_dev) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 3c1f37bfe4..4446d79269 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1410,6 +1410,7 @@ static void virtio_serial_pci_instance_init(Object *obj) object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + object_unref(OBJECT(&dev->vdev)); } static const TypeInfo virtio_serial_pci_info = { -- cgit v1.2.3 From 8ee486ae339f0e5236f4a9ab988fc963edcc73b5 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:33 +0800 Subject: virtio-rng: use aliases instead of duplicate qdev properties virtio-rng-{pci, s390, ccw} all duplicate the qdev properties of their VirtIORNG child. This approach does not work well with string or pointer properties since we must be careful about leaking or double-freeing them. Use the QOM alias property to forward property accesses to the VirtIORNG child. This way no duplication is necessary. Signed-off-by: Gonglei Reviewed-by: Cornelia Huck Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- hw/s390x/s390-virtio-bus.c | 2 +- hw/s390x/virtio-ccw.c | 2 +- hw/virtio/virtio-pci.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 422402e564..6d0a7f36e7 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -311,6 +311,7 @@ static void s390_virtio_rng_instance_init(Object *obj) VirtIORNGS390 *dev = VIRTIO_RNG_S390(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + qdev_alias_all_properties(DEVICE(&dev->vdev), obj); object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, (Object **)&dev->vdev.conf.rng, qdev_prop_allow_set_link_before_realize, @@ -561,7 +562,6 @@ static const TypeInfo s390_virtio_serial = { static Property s390_virtio_rng_properties[] = { DEFINE_VIRTIO_COMMON_FEATURES(VirtIOS390Device, host_features), - DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORNGS390, vdev.conf), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 5d7f3a6af7..da2e427716 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -1542,6 +1542,7 @@ static void virtio_ccw_rng_instance_init(Object *obj) VirtIORNGCcw *dev = VIRTIO_RNG_CCW(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + qdev_alias_all_properties(DEVICE(&dev->vdev), obj); object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, (Object **)&dev->vdev.conf.rng, qdev_prop_allow_set_link_before_realize, @@ -1550,7 +1551,6 @@ static void virtio_ccw_rng_instance_init(Object *obj) static Property virtio_ccw_rng_properties[] = { DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), - DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORNGCcw, vdev.conf), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 4446d79269..2b3a941876 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1483,7 +1483,6 @@ static const TypeInfo virtio_net_pci_info = { /* virtio-rng-pci */ static Property virtio_rng_pci_properties[] = { - DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORngPCI, vdev.conf), DEFINE_PROP_END_OF_LIST(), }; @@ -1525,6 +1524,7 @@ static void virtio_rng_initfn(Object *obj) VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + qdev_alias_all_properties(DEVICE(&dev->vdev), obj); object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, (Object **)&dev->vdev.conf.rng, qdev_prop_allow_set_link_before_realize, -- cgit v1.2.3 From 352fa88dfb2e9c72fa2a1506acb39f349d4befbf Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:34 +0800 Subject: virtio-rng: fix virtio-rng child refcount in transports object_initialize() leaves the object with a refcount of 1. object_property_add_child() adds its own reference which is dropped again when the property is deleted. The upshot of this is that we always have a refcount >= 1. Upon hot unplug the virtio-rng child is not finalized! Drop our reference after the child property has been added to the parent. Signed-off-by: Gonglei Reviewed-by: Cornelia Huck Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- hw/s390x/s390-virtio-bus.c | 1 + hw/s390x/virtio-ccw.c | 1 + hw/virtio/virtio-pci.c | 1 + 3 files changed, 3 insertions(+) (limited to 'hw') diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 6d0a7f36e7..ca682bb7e6 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -312,6 +312,7 @@ static void s390_virtio_rng_instance_init(Object *obj) object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + object_unref(OBJECT(&dev->vdev)); object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, (Object **)&dev->vdev.conf.rng, qdev_prop_allow_set_link_before_realize, diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index da2e427716..de0764de48 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -1543,6 +1543,7 @@ static void virtio_ccw_rng_instance_init(Object *obj) object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + object_unref(OBJECT(&dev->vdev)); object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, (Object **)&dev->vdev.conf.rng, qdev_prop_allow_set_link_before_realize, diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 2b3a941876..40652a7481 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1525,6 +1525,7 @@ static void virtio_rng_initfn(Object *obj) object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + object_unref(OBJECT(&dev->vdev)); object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, (Object **)&dev->vdev.conf.rng, qdev_prop_allow_set_link_before_realize, -- cgit v1.2.3 From 91ba21208839643603e7f7fa5864723c3f371ebe Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:35 +0800 Subject: virtio-balloon: fix virtio-balloon child refcount in transports object_initialize() leaves the object with a refcount of 1. object_property_add_child() adds its own reference which is dropped again when the property is deleted. The upshot of this is that we always have a refcount >= 1. Upon hot unplug the virtio-balloon child is not finalized! Drop our reference after the child property has been added to the parent. Signed-off-by: Gonglei Reviewed-by: Cornelia Huck Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- hw/s390x/virtio-ccw.c | 2 +- hw/virtio/virtio-pci.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index de0764de48..c074f64e92 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -900,7 +900,7 @@ static void virtio_ccw_balloon_instance_init(Object *obj) VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BALLOON); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - + object_unref(OBJECT(&dev->vdev)); object_property_add(obj, "guest-stats", "guest statistics", balloon_ccw_stats_get_all, NULL, NULL, dev, NULL); diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 40652a7481..62f84c4ac0 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1325,7 +1325,7 @@ static void virtio_balloon_pci_instance_init(Object *obj) VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BALLOON); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - + object_unref(OBJECT(&dev->vdev)); object_property_add(obj, "guest-stats", "guest statistics", balloon_pci_stats_get_all, NULL, NULL, dev, NULL); -- cgit v1.2.3 From 48833071d955406ebeddc365a8df8b5cb12b035f Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:36 +0800 Subject: virtio-9p: use aliases instead of duplicate qdev properties virtio-9p-pci all duplicate the qdev properties of their V9fsState child. This approach does not work well with string or pointer properties since we must be careful about leaking or double-freeing them. Use the QOM alias property to forward property accesses to the V9fsState child. This way no duplication is necessary. Signed-off-by: Gonglei Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- hw/virtio/virtio-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 62f84c4ac0..714286dab6 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -926,7 +926,6 @@ static Property virtio_9p_pci_properties[] = { DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), - DEFINE_VIRTIO_9P_PROPERTIES(V9fsPCIState, vdev.fsconf), DEFINE_PROP_END_OF_LIST(), }; @@ -950,6 +949,7 @@ static void virtio_9p_pci_instance_init(Object *obj) V9fsPCIState *dev = VIRTIO_9P_PCI(obj); object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_9P); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); + qdev_alias_all_properties(DEVICE(&dev->vdev), obj); } static const TypeInfo virtio_9p_pci_info = { -- cgit v1.2.3 From 8f3d60e568f53cb3ccdedd917f8e49cdb304973b Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:37 +0800 Subject: virtio-9p: fix virtio-9p child refcount in transports object_initialize() leaves the object with a refcount of 1. object_property_add_child() adds its own reference which is dropped again when the property is deleted. The upshot of this is that we always have a refcount >= 1. Upon unplug the virtio-9p child is not finalized! Drop our reference after the child property has been added to the parent. Signed-off-by: Gonglei Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- hw/virtio/virtio-pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'hw') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 714286dab6..8f3b79b03a 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -950,6 +950,7 @@ static void virtio_9p_pci_instance_init(Object *obj) object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_9P); object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + object_unref(OBJECT(&dev->vdev)); } static const TypeInfo virtio_9p_pci_info = { -- cgit v1.2.3 From c8075caf19b000b975349f8976958cedf7d2613a Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:38 +0800 Subject: virtio: add a wrapper for virtio-backend initialization For better code sharing, add a helper function that handles reference counting of the virtio backend for virtio proxy devices. Cc: Cornelia Huck Cc: Michael S. Tsirkin Signed-off-by: Gonglei Signed-off-by: Paolo Bonzini --- hw/s390x/s390-virtio-bus.c | 42 +++++++++++++++++---------------------- hw/s390x/virtio-ccw.c | 42 +++++++++++++++++---------------------- hw/virtio/virtio-pci.c | 49 ++++++++++++++++++++-------------------------- hw/virtio/virtio.c | 11 +++++++++++ 4 files changed, 68 insertions(+), 76 deletions(-) (limited to 'hw') diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index ca682bb7e6..f451ca1ed3 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -159,10 +159,9 @@ static int s390_virtio_net_init(VirtIOS390Device *s390_dev) static void s390_virtio_net_instance_init(Object *obj) { VirtIONetS390 *dev = VIRTIO_NET_S390(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_NET); } static int s390_virtio_blk_init(VirtIOS390Device *s390_dev) @@ -179,10 +178,9 @@ static int s390_virtio_blk_init(VirtIOS390Device *s390_dev) static void s390_virtio_blk_instance_init(Object *obj) { VirtIOBlkS390 *dev = VIRTIO_BLK_S390(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_BLK); object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread", &error_abort); } @@ -224,10 +222,9 @@ static int s390_virtio_serial_init(VirtIOS390Device *s390_dev) static void s390_virtio_serial_instance_init(Object *obj) { VirtIOSerialS390 *dev = VIRTIO_SERIAL_S390(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); - object_unref(OBJECT(&dev->vdev)); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SERIAL); } static int s390_virtio_scsi_init(VirtIOS390Device *s390_dev) @@ -258,10 +255,9 @@ static int s390_virtio_scsi_init(VirtIOS390Device *s390_dev) static void s390_virtio_scsi_instance_init(Object *obj) { VirtIOSCSIS390 *dev = VIRTIO_SCSI_S390(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SCSI); } #ifdef CONFIG_VHOST_SCSI @@ -281,10 +277,9 @@ static int s390_vhost_scsi_init(VirtIOS390Device *s390_dev) static void s390_vhost_scsi_instance_init(Object *obj) { VHostSCSIS390 *dev = VHOST_SCSI_S390(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_SCSI); } #endif @@ -309,10 +304,9 @@ static int s390_virtio_rng_init(VirtIOS390Device *s390_dev) static void s390_virtio_rng_instance_init(Object *obj) { VirtIORNGS390 *dev = VIRTIO_RNG_S390(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); - object_unref(OBJECT(&dev->vdev)); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_RNG); object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, (Object **)&dev->vdev.conf.rng, qdev_prop_allow_set_link_before_realize, diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index c074f64e92..5175d57733 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -792,10 +792,9 @@ static int virtio_ccw_net_init(VirtioCcwDevice *ccw_dev) static void virtio_ccw_net_instance_init(Object *obj) { VirtIONetCcw *dev = VIRTIO_NET_CCW(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_NET); } static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev) @@ -813,10 +812,9 @@ static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev) static void virtio_ccw_blk_instance_init(Object *obj) { VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_BLK); object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread", &error_abort); } @@ -850,10 +848,9 @@ static int virtio_ccw_serial_init(VirtioCcwDevice *ccw_dev) static void virtio_ccw_serial_instance_init(Object *obj) { VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); - object_unref(OBJECT(&dev->vdev)); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SERIAL); } static int virtio_ccw_balloon_init(VirtioCcwDevice *ccw_dev) @@ -938,10 +935,9 @@ static int virtio_ccw_scsi_init(VirtioCcwDevice *ccw_dev) static void virtio_ccw_scsi_instance_init(Object *obj) { VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SCSI); } #ifdef CONFIG_VHOST_SCSI @@ -961,10 +957,9 @@ static int vhost_ccw_scsi_init(VirtioCcwDevice *ccw_dev) static void vhost_ccw_scsi_instance_init(Object *obj) { VHostSCSICcw *dev = VHOST_SCSI_CCW(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_SCSI); } #endif @@ -1540,10 +1535,9 @@ static const TypeInfo vhost_ccw_scsi = { static void virtio_ccw_rng_instance_init(Object *obj) { VirtIORNGCcw *dev = VIRTIO_RNG_CCW(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); - object_unref(OBJECT(&dev->vdev)); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_RNG); object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, (Object **)&dev->vdev.conf.rng, qdev_prop_allow_set_link_before_realize, diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 8f3b79b03a..83a699fc23 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -947,10 +947,9 @@ static void virtio_9p_pci_class_init(ObjectClass *klass, void *data) static void virtio_9p_pci_instance_init(Object *obj) { V9fsPCIState *dev = VIRTIO_9P_PCI(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_9P); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); - object_unref(OBJECT(&dev->vdev)); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_9P); } static const TypeInfo virtio_9p_pci_info = { @@ -1112,10 +1111,9 @@ static void virtio_blk_pci_class_init(ObjectClass *klass, void *data) static void virtio_blk_pci_instance_init(Object *obj) { VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BLK); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_BLK); object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread", &error_abort); } @@ -1185,10 +1183,9 @@ static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data) static void virtio_scsi_pci_instance_init(Object *obj) { VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SCSI); } static const TypeInfo virtio_scsi_pci_info = { @@ -1242,10 +1239,9 @@ static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data) static void vhost_scsi_pci_instance_init(Object *obj) { VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VHOST_SCSI); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VHOST_SCSI); } static const TypeInfo vhost_scsi_pci_info = { @@ -1408,10 +1404,9 @@ static void virtio_serial_pci_class_init(ObjectClass *klass, void *data) static void virtio_serial_pci_instance_init(Object *obj) { VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SERIAL); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); - object_unref(OBJECT(&dev->vdev)); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_SERIAL); } static const TypeInfo virtio_serial_pci_info = { @@ -1467,10 +1462,9 @@ static void virtio_net_pci_class_init(ObjectClass *klass, void *data) static void virtio_net_pci_instance_init(Object *obj) { VirtIONetPCI *dev = VIRTIO_NET_PCI(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_NET); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - object_unref(OBJECT(&dev->vdev)); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_NET); } static const TypeInfo virtio_net_pci_info = { @@ -1523,10 +1517,9 @@ static void virtio_rng_pci_class_init(ObjectClass *klass, void *data) static void virtio_rng_initfn(Object *obj) { VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj); - object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_RNG); - object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); - qdev_alias_all_properties(DEVICE(&dev->vdev), obj); - object_unref(OBJECT(&dev->vdev)); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_RNG); object_property_add_link(obj, "rng", TYPE_RNG_BACKEND, (Object **)&dev->vdev.conf.rng, qdev_prop_allow_set_link_before_realize, diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 5c981801f3..2c236bf271 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1123,6 +1123,17 @@ static void virtio_vmstate_change(void *opaque, int running, RunState state) } } +void virtio_instance_init_common(Object *proxy_obj, void *data, + size_t vdev_size, const char *vdev_name) +{ + DeviceState *vdev = data; + + object_initialize(vdev, vdev_size, vdev_name); + object_property_add_child(proxy_obj, "virtio-backend", OBJECT(vdev), NULL); + object_unref(OBJECT(vdev)); + qdev_alias_all_properties(vdev, proxy_obj); +} + void virtio_init(VirtIODevice *vdev, const char *name, uint16_t device_id, size_t config_size) { -- cgit v1.2.3 From 19d339f11d0768df2b4e0c40530bb4ab53e6bb05 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:06 +0800 Subject: virtio-scsi: Add 'iothread' property to virtio-scsi Similar to this property in virtio-blk for dataplane, add it as a QOM link in virtio-scsi and an alias in virtio-scsi-pci and virtio-scsi-ccw, in order to assign an iothread to the device. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/s390x/virtio-ccw.c | 2 ++ hw/scsi/virtio-scsi.c | 11 +++++++++++ hw/virtio/virtio-pci.c | 2 ++ 3 files changed, 15 insertions(+) (limited to 'hw') diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 5175d57733..e7d3ea178a 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -938,6 +938,8 @@ static void virtio_ccw_scsi_instance_init(Object *obj) virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI); + object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread", + &error_abort); } #ifdef CONFIG_VHOST_SCSI diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 58b420084e..91ead26ff8 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -728,6 +728,16 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) virtio_scsi_save, virtio_scsi_load, s); } +static void virtio_scsi_instance_init(Object *obj) +{ + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(obj); + + object_property_add_link(obj, "iothread", TYPE_IOTHREAD, + (Object **)&vs->conf.iothread, + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); +} + void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); @@ -786,6 +796,7 @@ static const TypeInfo virtio_scsi_info = { .name = TYPE_VIRTIO_SCSI, .parent = TYPE_VIRTIO_SCSI_COMMON, .instance_size = sizeof(VirtIOSCSI), + .instance_init = virtio_scsi_instance_init, .class_init = virtio_scsi_class_init, }; diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 83a699fc23..bae62c8f66 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1186,6 +1186,8 @@ static void virtio_scsi_pci_instance_init(Object *obj) virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_SCSI); + object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread", + &error_abort); } static const TypeInfo virtio_scsi_pci_info = { -- cgit v1.2.3 From 91cb1c9b56064e7cba27ab310c9c4c477694589e Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:24 +0800 Subject: virtio-scsi-dataplane: Code to run virtio-scsi on iothread This implements the core part of dataplane feature of virtio-scsi. A few fields are added in VirtIOSCSICommon to maintain the dataplane status. These fields are managed by a new source file: virtio-scsi-dataplane.c. Most code in this file will run on an iothread, unless otherwise commented as in a global mutex context, such as those functions to start, stop and setting the iothread property. Upon start, we set up guest/host event notifiers, in a same way as virtio-blk does. The handlers then pop request from vring and call into virtio-scsi.c functions to process it. So we need to make sure make all those called functions work with iothread, too. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/Makefile.objs | 2 +- hw/scsi/virtio-scsi-dataplane.c | 222 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 hw/scsi/virtio-scsi-dataplane.c (limited to 'hw') diff --git a/hw/scsi/Makefile.objs b/hw/scsi/Makefile.objs index 121ddc5cf4..40c79d34c9 100644 --- a/hw/scsi/Makefile.objs +++ b/hw/scsi/Makefile.objs @@ -8,6 +8,6 @@ common-obj-$(CONFIG_ESP_PCI) += esp-pci.o obj-$(CONFIG_PSERIES) += spapr_vscsi.o ifeq ($(CONFIG_VIRTIO),y) -obj-y += virtio-scsi.o +obj-y += virtio-scsi.o virtio-scsi-dataplane.o obj-$(CONFIG_VHOST_SCSI) += vhost-scsi.o endif diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c new file mode 100644 index 0000000000..acbf622ed8 --- /dev/null +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -0,0 +1,222 @@ +/* + * Virtio SCSI dataplane + * + * Copyright Red Hat, Inc. 2014 + * + * Authors: + * Fam Zheng + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "hw/virtio/virtio-scsi.h" +#include "qemu/error-report.h" +#include +#include +#include +#include "hw/virtio/virtio-access.h" +#include "stdio.h" + +/* Context: QEMU global mutex held */ +void virtio_scsi_set_iothread(VirtIOSCSI *s, IOThread *iothread) +{ + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); + + assert(!s->ctx); + s->ctx = iothread_get_aio_context(vs->conf.iothread); + + /* Don't try if transport does not support notifiers. */ + if (!k->set_guest_notifiers || !k->set_host_notifier) { + fprintf(stderr, "virtio-scsi: Failed to set iothread " + "(transport does not support notifiers)"); + exit(1); + } +} + +static VirtIOSCSIVring *virtio_scsi_vring_init(VirtIOSCSI *s, + VirtQueue *vq, + EventNotifierHandler *handler, + int n) +{ + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + VirtIOSCSIVring *r = g_slice_new(VirtIOSCSIVring); + + /* Set up virtqueue notify */ + if (k->set_host_notifier(qbus->parent, n, true) != 0) { + fprintf(stderr, "virtio-scsi: Failed to set host notifier\n"); + exit(1); + } + r->host_notifier = *virtio_queue_get_host_notifier(vq); + r->guest_notifier = *virtio_queue_get_guest_notifier(vq); + aio_set_event_notifier(s->ctx, &r->host_notifier, handler); + + r->parent = s; + + if (!vring_setup(&r->vring, VIRTIO_DEVICE(s), n)) { + fprintf(stderr, "virtio-scsi: VRing setup failed\n"); + exit(1); + } + return r; +} + +VirtIOSCSIReq *virtio_scsi_pop_req_vring(VirtIOSCSI *s, + VirtIOSCSIVring *vring) +{ + VirtIOSCSIReq *req = virtio_scsi_init_req(s, NULL); + int r; + + req->vring = vring; + r = vring_pop((VirtIODevice *)s, &vring->vring, &req->elem); + if (r < 0) { + virtio_scsi_free_req(req); + req = NULL; + } + return req; +} + +void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req) +{ + vring_push(&req->vring->vring, &req->elem, + req->qsgl.size + req->resp_iov.size); + event_notifier_set(&req->vring->guest_notifier); +} + +static void virtio_scsi_iothread_handle_ctrl(EventNotifier *notifier) +{ + VirtIOSCSIVring *vring = container_of(notifier, + VirtIOSCSIVring, host_notifier); + VirtIOSCSI *s = VIRTIO_SCSI(vring->parent); + VirtIOSCSIReq *req; + + event_notifier_test_and_clear(notifier); + while ((req = virtio_scsi_pop_req_vring(s, vring))) { + virtio_scsi_handle_ctrl_req(s, req); + } +} + +static void virtio_scsi_iothread_handle_event(EventNotifier *notifier) +{ + VirtIOSCSIVring *vring = container_of(notifier, + VirtIOSCSIVring, host_notifier); + VirtIOSCSI *s = vring->parent; + VirtIODevice *vdev = VIRTIO_DEVICE(s); + + event_notifier_test_and_clear(notifier); + + if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { + return; + } + + if (s->events_dropped) { + virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0); + } +} + +static void virtio_scsi_iothread_handle_cmd(EventNotifier *notifier) +{ + VirtIOSCSIVring *vring = container_of(notifier, + VirtIOSCSIVring, host_notifier); + VirtIOSCSI *s = (VirtIOSCSI *)vring->parent; + VirtIOSCSIReq *req; + + event_notifier_test_and_clear(notifier); + while ((req = virtio_scsi_pop_req_vring(s, vring))) { + virtio_scsi_handle_cmd_req(s, req); + } +} + +/* Context: QEMU global mutex held */ +void virtio_scsi_dataplane_start(VirtIOSCSI *s) +{ + int i; + int rc; + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); + + if (s->dataplane_started || + s->dataplane_starting || + s->ctx != iothread_get_aio_context(vs->conf.iothread)) { + return; + } + + s->dataplane_starting = true; + + /* Set up guest notifier (irq) */ + rc = k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, true); + if (rc != 0) { + fprintf(stderr, "virtio-scsi: Failed to set guest notifiers, " + "ensure -enable-kvm is set\n"); + exit(1); + } + + aio_context_acquire(s->ctx); + s->ctrl_vring = virtio_scsi_vring_init(s, vs->ctrl_vq, + virtio_scsi_iothread_handle_ctrl, + 0); + s->event_vring = virtio_scsi_vring_init(s, vs->event_vq, + virtio_scsi_iothread_handle_event, + 1); + s->cmd_vrings = g_malloc0(sizeof(VirtIOSCSIVring) * vs->conf.num_queues); + for (i = 0; i < vs->conf.num_queues; i++) { + s->cmd_vrings[i] = + virtio_scsi_vring_init(s, vs->cmd_vqs[i], + virtio_scsi_iothread_handle_cmd, + i + 2); + } + + aio_context_release(s->ctx); + s->dataplane_starting = false; + s->dataplane_started = true; +} + +/* Context: QEMU global mutex held */ +void virtio_scsi_dataplane_stop(VirtIOSCSI *s) +{ + BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); + VirtIODevice *vdev = VIRTIO_DEVICE(s); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); + int i; + + if (!s->dataplane_started || s->dataplane_stopping) { + return; + } + s->dataplane_stopping = true; + assert(s->ctx == iothread_get_aio_context(vs->conf.iothread)); + + aio_context_acquire(s->ctx); + + aio_set_event_notifier(s->ctx, &s->ctrl_vring->host_notifier, NULL); + aio_set_event_notifier(s->ctx, &s->event_vring->host_notifier, NULL); + for (i = 0; i < vs->conf.num_queues; i++) { + aio_set_event_notifier(s->ctx, &s->cmd_vrings[i]->host_notifier, NULL); + } + + bdrv_drain_all(); /* ensure there are no in-flight requests */ + + aio_context_release(s->ctx); + + /* Sync vring state back to virtqueue so that non-dataplane request + * processing can continue when we disable the host notifier below. + */ + vring_teardown(&s->ctrl_vring->vring, vdev, 0); + vring_teardown(&s->event_vring->vring, vdev, 1); + for (i = 0; i < vs->conf.num_queues; i++) { + vring_teardown(&s->cmd_vrings[i]->vring, vdev, 2 + i); + } + + for (i = 0; i < vs->conf.num_queues + 2; i++) { + k->set_host_notifier(qbus->parent, i, false); + } + + /* Clean up guest notifier (irq) */ + k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false); + s->dataplane_stopping = false; + s->dataplane_started = false; +} -- cgit v1.2.3 From 63c7e542686ff9616816b527c824ec0ac1f73cbe Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:25 +0800 Subject: virtio-scsi: Hook up with dataplane This enables the virtio-scsi-dataplane code by setting the iothread in virtio-scsi device, and makes any function that is called by back from dataplane to cooperate with the caller: they need to be vring/iothread aware when handling the requests and using scsi devices on the bus. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 91ead26ff8..dc705f0fa5 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -69,13 +69,19 @@ static void virtio_scsi_complete_req(VirtIOSCSIReq *req) VirtIODevice *vdev = VIRTIO_DEVICE(s); qemu_iovec_from_buf(&req->resp_iov, 0, &req->resp, req->resp_size); - virtqueue_push(vq, &req->elem, req->qsgl.size + req->resp_iov.size); + if (req->vring) { + assert(req->vq == NULL); + virtio_scsi_vring_push_notify(req); + } else { + virtqueue_push(vq, &req->elem, req->qsgl.size + req->resp_iov.size); + virtio_notify(vdev, vq); + } + if (req->sreq) { req->sreq->hba_private = NULL; scsi_req_unref(req->sreq); } virtio_scsi_free_req(req); - virtio_notify(vdev, vq); } static void virtio_scsi_bad_req(void) @@ -208,6 +214,11 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) BusChild *kid; int target; + if (s->dataplane_started && bdrv_get_aio_context(d->conf.bs) != s->ctx) { + aio_context_acquire(s->ctx); + bdrv_set_aio_context(d->conf.bs, s->ctx); + aio_context_release(s->ctx); + } /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */ req->resp.tmf.response = VIRTIO_SCSI_S_OK; @@ -346,6 +357,10 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) VirtIOSCSI *s = (VirtIOSCSI *)vdev; VirtIOSCSIReq *req; + if (s->ctx) { + virtio_scsi_dataplane_start(s); + return; + } while ((req = virtio_scsi_pop_req(s, vq))) { virtio_scsi_handle_ctrl_req(s, req); } @@ -457,6 +472,11 @@ void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req) virtio_scsi_complete_cmd_req(req); return; } + if (s->dataplane_started && bdrv_get_aio_context(d->conf.bs) != s->ctx) { + aio_context_acquire(s->ctx); + bdrv_set_aio_context(d->conf.bs, s->ctx); + aio_context_release(s->ctx); + } req->sreq = scsi_req_new(d, req->req.cmd.tag, virtio_scsi_get_lun(req->req.cmd.lun), req->req.cdb, req); @@ -481,6 +501,10 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) VirtIOSCSI *s = (VirtIOSCSI *)vdev; VirtIOSCSIReq *req; + if (s->ctx) { + virtio_scsi_dataplane_start(s); + return; + } while ((req = virtio_scsi_pop_req(s, vq))) { virtio_scsi_handle_cmd_req(s, req); } @@ -531,6 +555,9 @@ static void virtio_scsi_reset(VirtIODevice *vdev) VirtIOSCSI *s = VIRTIO_SCSI(vdev); VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); + if (s->ctx) { + virtio_scsi_dataplane_stop(s); + } s->resetting++; qbus_reset_all(&s->bus.qbus); s->resetting--; @@ -573,10 +600,19 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, return; } - req = virtio_scsi_pop_req(s, vs->event_vq); + if (s->dataplane_started) { + assert(s->ctx); + aio_context_acquire(s->ctx); + } + + if (s->dataplane_started) { + req = virtio_scsi_pop_req_vring(s, s->event_vring); + } else { + req = virtio_scsi_pop_req(s, vs->event_vq); + } if (!req) { s->events_dropped = true; - return; + goto out; } if (s->events_dropped) { @@ -605,12 +641,20 @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, evt->lun[3] = dev->lun & 0xFF; } virtio_scsi_complete_req(req); +out: + if (s->dataplane_started) { + aio_context_release(s->ctx); + } } static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq) { VirtIOSCSI *s = VIRTIO_SCSI(vdev); + if (s->ctx) { + virtio_scsi_dataplane_start(s); + return; + } if (s->events_dropped) { virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0); } -- cgit v1.2.3 From dfb37cf7fa206afa6e212af16fee74427464f1d1 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:26 +0800 Subject: virtio-scsi: Add migration state notifier for dataplane code Similar to virtio-blk-dataplane, we stop the iothread while migration starts and restart it when migration finishes. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index dc705f0fa5..57efe65659 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -20,6 +20,7 @@ #include #include #include "hw/virtio/virtio-access.h" +#include "migration/migration.h" static inline int virtio_scsi_get_lun(uint8_t *lun) { @@ -357,7 +358,7 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) VirtIOSCSI *s = (VirtIOSCSI *)vdev; VirtIOSCSIReq *req; - if (s->ctx) { + if (s->ctx && !s->dataplane_disabled) { virtio_scsi_dataplane_start(s); return; } @@ -501,7 +502,7 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) VirtIOSCSI *s = (VirtIOSCSI *)vdev; VirtIOSCSIReq *req; - if (s->ctx) { + if (s->ctx && !s->dataplane_disabled) { virtio_scsi_dataplane_start(s); return; } @@ -651,7 +652,7 @@ static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq) { VirtIOSCSI *s = VIRTIO_SCSI(vdev); - if (s->ctx) { + if (s->ctx && !s->dataplane_disabled) { virtio_scsi_dataplane_start(s); return; } @@ -742,6 +743,31 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, } } +/* Disable dataplane thread during live migration since it does not + * update the dirty memory bitmap yet. + */ +static void virtio_scsi_migration_state_changed(Notifier *notifier, void *data) +{ + VirtIOSCSI *s = container_of(notifier, VirtIOSCSI, + migration_state_notifier); + MigrationState *mig = data; + + if (migration_in_setup(mig)) { + if (!s->dataplane_started) { + return; + } + virtio_scsi_dataplane_stop(s); + s->dataplane_disabled = true; + } else if (migration_has_finished(mig) || + migration_has_failed(mig)) { + if (s->dataplane_started) { + return; + } + bdrv_drain_all(); /* complete in-flight non-dataplane requests */ + s->dataplane_disabled = false; + } +} + static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); @@ -770,6 +796,8 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) register_savevm(dev, "virtio-scsi", virtio_scsi_id++, 1, virtio_scsi_save, virtio_scsi_load, s); + s->migration_state_notifier.notify = virtio_scsi_migration_state_changed; + add_migration_state_change_notifier(&s->migration_state_notifier); } static void virtio_scsi_instance_init(Object *obj) @@ -796,6 +824,7 @@ static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp) VirtIOSCSI *s = VIRTIO_SCSI(dev); unregister_savevm(dev, "virtio-scsi", s); + remove_migration_state_change_notifier(&s->migration_state_notifier); virtio_scsi_common_unrealize(dev, errp); } -- cgit v1.2.3 From 359eea71d98e7f2cf9efb5e65bb59a240bedb131 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:27 +0800 Subject: virtio-scsi: Two stages processing of cmd request Mechanical change, in preparation for bdrv_io_plug/bdrv_io_unplug. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi-dataplane.c | 4 +++- hw/scsi/virtio-scsi.c | 20 ++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index acbf622ed8..11f5705407 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -126,7 +126,9 @@ static void virtio_scsi_iothread_handle_cmd(EventNotifier *notifier) event_notifier_test_and_clear(notifier); while ((req = virtio_scsi_pop_req_vring(s, vring))) { - virtio_scsi_handle_cmd_req(s, req); + if (virtio_scsi_handle_cmd_req_prepare(s, req)) { + virtio_scsi_handle_cmd_req_submit(s, req); + } } } diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 57efe65659..6cf070f70e 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -449,10 +449,9 @@ static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req) virtio_scsi_complete_cmd_req(req); } -void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req) +bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) { VirtIOSCSICommon *vs = &s->parent_obj; - int n; SCSIDevice *d; int rc; @@ -464,14 +463,14 @@ void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req) } else { virtio_scsi_bad_req(); } - return; + return false; } d = virtio_scsi_device_find(s, req->req.cmd.lun); if (!d) { req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET; virtio_scsi_complete_cmd_req(req); - return; + return false; } if (s->dataplane_started && bdrv_get_aio_context(d->conf.bs) != s->ctx) { aio_context_acquire(s->ctx); @@ -487,11 +486,14 @@ void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req) req->sreq->cmd.xfer > req->qsgl.size)) { req->resp.cmd.response = VIRTIO_SCSI_S_OVERRUN; virtio_scsi_complete_cmd_req(req); - return; + return false; } + return true; +} - n = scsi_req_enqueue(req->sreq); - if (n) { +void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req) +{ + if (scsi_req_enqueue(req->sreq)) { scsi_req_continue(req->sreq); } } @@ -507,7 +509,9 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) return; } while ((req = virtio_scsi_pop_req(s, vq))) { - virtio_scsi_handle_cmd_req(s, req); + if (virtio_scsi_handle_cmd_req_prepare(s, req)) { + virtio_scsi_handle_cmd_req_submit(s, req); + } } } -- cgit v1.2.3 From 1880ad4f4e3b49f15c55e816d66b9690b3ede00c Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:28 +0800 Subject: virtio-scsi: Batched prepare for cmd reqs Queue the popped requests while calling virtio_scsi_handle_cmd_req_prepare(), then submit them after all prepared. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi-dataplane.c | 9 +++++++-- hw/scsi/virtio-scsi.c | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 11f5705407..b778e051f8 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -122,14 +122,19 @@ static void virtio_scsi_iothread_handle_cmd(EventNotifier *notifier) VirtIOSCSIVring *vring = container_of(notifier, VirtIOSCSIVring, host_notifier); VirtIOSCSI *s = (VirtIOSCSI *)vring->parent; - VirtIOSCSIReq *req; + VirtIOSCSIReq *req, *next; + QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs); event_notifier_test_and_clear(notifier); while ((req = virtio_scsi_pop_req_vring(s, vring))) { if (virtio_scsi_handle_cmd_req_prepare(s, req)) { - virtio_scsi_handle_cmd_req_submit(s, req); + QTAILQ_INSERT_TAIL(&reqs, req, next); } } + + QTAILQ_FOREACH_SAFE(req, &reqs, next, next) { + virtio_scsi_handle_cmd_req_submit(s, req); + } } /* Context: QEMU global mutex held */ diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 6cf070f70e..395178e949 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -502,7 +502,8 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) { /* use non-QOM casts in the data path */ VirtIOSCSI *s = (VirtIOSCSI *)vdev; - VirtIOSCSIReq *req; + VirtIOSCSIReq *req, *next; + QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs); if (s->ctx && !s->dataplane_disabled) { virtio_scsi_dataplane_start(s); @@ -510,9 +511,13 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) } while ((req = virtio_scsi_pop_req(s, vq))) { if (virtio_scsi_handle_cmd_req_prepare(s, req)) { - virtio_scsi_handle_cmd_req_submit(s, req); + QTAILQ_INSERT_TAIL(&reqs, req, next); } } + + QTAILQ_FOREACH_SAFE(req, &reqs, next, next) { + virtio_scsi_handle_cmd_req_submit(s, req); + } } static void virtio_scsi_get_config(VirtIODevice *vdev, -- cgit v1.2.3 From 5170f40b102bcabed54e8fa8ec86957e35c41d41 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:29 +0800 Subject: virtio-scsi: Call bdrv_io_plug/bdrv_io_unplug in cmd request handling Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 395178e949..09a39cb991 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -488,6 +488,8 @@ bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req) virtio_scsi_complete_cmd_req(req); return false; } + scsi_req_ref(req->sreq); + bdrv_io_plug(d->conf.bs); return true; } @@ -496,6 +498,8 @@ void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req) if (scsi_req_enqueue(req->sreq)) { scsi_req_continue(req->sreq); } + bdrv_io_unplug(req->sreq->dev->conf.bs); + scsi_req_unref(req->sreq); } static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) -- cgit v1.2.3 From 9786b592a93e557e575ea6f18ee1e1fc6d68dc7b Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:30 +0800 Subject: virtio-scsi: Process ".iothread" property We are ready, now let's effectively enable dataplane. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 09a39cb991..fa36e23a2d 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -754,6 +754,10 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, s->cmd_vqs[i] = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, cmd); } + + if (s->conf.iothread) { + virtio_scsi_set_iothread(VIRTIO_SCSI(s), s->conf.iothread); + } } /* Disable dataplane thread during live migration since it does not -- cgit v1.2.3 From eda470e41a753070e057380a9a71e2ad7347f667 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 24 Sep 2014 16:27:52 +0800 Subject: scsi: Drop scsi_req_abort The only user of this function is spapr_vscsi.c. We can convert to scsi_req_cancel plus adding a check in vscsi_request_cancelled. Suggested-by: Paolo Bonzini Signed-off-by: Fam Zheng [Drop prototype. - Paolo] Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-bus.c | 15 --------------- hw/scsi/spapr_vscsi.c | 13 ++++++++++--- 2 files changed, 10 insertions(+), 18 deletions(-) (limited to 'hw') diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index af293b59da..f90a2040a8 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -1736,21 +1736,6 @@ void scsi_req_cancel(SCSIRequest *req) scsi_req_unref(req); } -void scsi_req_abort(SCSIRequest *req, int status) -{ - if (!req->enqueued) { - return; - } - scsi_req_ref(req); - scsi_req_dequeue(req); - req->io_canceled = true; - if (req->ops->cancel_io) { - req->ops->cancel_io(req); - } - scsi_req_complete(req, status); - scsi_req_unref(req); -} - static int scsi_ua_precedence(SCSISense sense) { if (sense.key != UNIT_ATTENTION) { diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index 048cfc7b05..20b20f0bae 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -77,8 +77,9 @@ typedef struct vscsi_req { SCSIRequest *sreq; uint32_t qtag; /* qemu tag != srp tag */ bool active; - uint32_t data_len; bool writing; + bool dma_error; + uint32_t data_len; uint32_t senselen; uint8_t sense[SCSI_SENSE_BUF_SIZE]; @@ -536,8 +537,8 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len) } if (rc < 0) { fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc); - vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0); - scsi_req_abort(req->sreq, CHECK_CONDITION); + req->dma_error = true; + scsi_req_cancel(req->sreq); return; } @@ -591,6 +592,12 @@ static void vscsi_request_cancelled(SCSIRequest *sreq) { vscsi_req *req = sreq->hba_private; + if (req->dma_error) { + VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(sreq->bus->qbus.parent); + + vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0); + vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); + } vscsi_put_req(req); } -- cgit v1.2.3 From 6c25fa6cf8b58db72956e880d76e4adc301bb472 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 24 Sep 2014 16:27:53 +0800 Subject: scsi-generic: Handle canceled request in scsi_command_complete Now that we always called the cb in bdrv_aio_cancel, let's make scsi-generic callbacks check io_canceled flag similarly to scsi-disk. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-generic.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 20587b41c1..2a73a43d1d 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -93,6 +93,9 @@ static void scsi_command_complete(void *opaque, int ret) SCSIGenericReq *r = (SCSIGenericReq *)opaque; r->req.aiocb = NULL; + if (r->req.io_canceled) { + goto done; + } if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { r->req.sense_len = r->io_header.sb_len_wr; } @@ -133,6 +136,7 @@ static void scsi_command_complete(void *opaque, int ret) r, r->req.tag, status); scsi_req_complete(&r->req, status); +done: if (!r->req.io_canceled) { scsi_req_unref(&r->req); } @@ -186,8 +190,7 @@ static void scsi_read_complete(void * opaque, int ret) int len; r->req.aiocb = NULL; - if (ret) { - DPRINTF("IO error ret %d\n", ret); + if (ret || r->req.io_canceled) { scsi_command_complete(r, ret); return; } @@ -246,8 +249,7 @@ static void scsi_write_complete(void * opaque, int ret) DPRINTF("scsi_write_complete() ret = %d\n", ret); r->req.aiocb = NULL; - if (ret) { - DPRINTF("IO error\n"); + if (ret || r->req.io_canceled) { scsi_command_complete(r, ret); return; } -- cgit v1.2.3 From 3df9caf88f5c0859ae380101fea47609ba1dbfbd Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 24 Sep 2014 16:27:54 +0800 Subject: scsi: Unify request unref in scsi_req_cancel Before, scsi_req_cancel will take ownership of the canceled request and unref it. We did this because we didn't know whether AIO CB will be called or not during the cancelling, so we set the io_canceled flag before calling it, and skip unref in the potentially called callbacks, which is not very nice. Now, bdrv_aio_cancel has a stricter contract that the completion callbacks are always called, so we can remove the checks of req->io_canceled and just unref it in callbacks. It will also make implementing asynchronous cancellation easier. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c | 37 ++++++++----------------------------- hw/scsi/scsi-generic.c | 13 ++----------- 2 files changed, 10 insertions(+), 40 deletions(-) (limited to 'hw') diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 9645d0194a..2e45752da1 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -113,11 +113,6 @@ static void scsi_cancel_io(SCSIRequest *req) DPRINTF("Cancel tag=0x%x\n", req->tag); if (r->req.aiocb) { bdrv_aio_cancel(r->req.aiocb); - - /* This reference was left in by scsi_*_data. We take ownership of - * it the moment scsi_req_cancel is called, independent of whether - * bdrv_aio_cancel completes the request or not. */ - scsi_req_unref(&r->req); } r->req.aiocb = NULL; } @@ -197,9 +192,7 @@ static void scsi_aio_complete(void *opaque, int ret) scsi_req_complete(&r->req, GOOD); done: - if (!r->req.io_canceled) { - scsi_req_unref(&r->req); - } + scsi_req_unref(&r->req); } static bool scsi_is_cmd_fua(SCSICommand *cmd) @@ -246,9 +239,7 @@ static void scsi_write_do_fua(SCSIDiskReq *r) scsi_req_complete(&r->req, GOOD); done: - if (!r->req.io_canceled) { - scsi_req_unref(&r->req); - } + scsi_req_unref(&r->req); } static void scsi_dma_complete_noio(void *opaque, int ret) @@ -280,9 +271,7 @@ static void scsi_dma_complete_noio(void *opaque, int ret) } done: - if (!r->req.io_canceled) { - scsi_req_unref(&r->req); - } + scsi_req_unref(&r->req); } static void scsi_dma_complete(void *opaque, int ret) @@ -320,9 +309,7 @@ static void scsi_read_complete(void * opaque, int ret) scsi_req_data(&r->req, r->qiov.size); done: - if (!r->req.io_canceled) { - scsi_req_unref(&r->req); - } + scsi_req_unref(&r->req); } /* Actually issue a read to the block device. */ @@ -363,9 +350,7 @@ static void scsi_do_read(void *opaque, int ret) } done: - if (!r->req.io_canceled) { - scsi_req_unref(&r->req); - } + scsi_req_unref(&r->req); } /* Read more data from scsi device into buffer. */ @@ -481,9 +466,7 @@ static void scsi_write_complete(void * opaque, int ret) } done: - if (!r->req.io_canceled) { - scsi_req_unref(&r->req); - } + scsi_req_unref(&r->req); } static void scsi_write_data(SCSIRequest *req) @@ -1582,9 +1565,7 @@ static void scsi_unmap_complete(void *opaque, int ret) scsi_req_complete(&r->req, GOOD); done: - if (!r->req.io_canceled) { - scsi_req_unref(&r->req); - } + scsi_req_unref(&r->req); g_free(data); } @@ -1678,9 +1659,7 @@ static void scsi_write_same_complete(void *opaque, int ret) scsi_req_complete(&r->req, GOOD); done: - if (!r->req.io_canceled) { - scsi_req_unref(&r->req); - } + scsi_req_unref(&r->req); qemu_vfree(data->iov.iov_base); g_free(data); } diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 2a73a43d1d..e92b418933 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -137,9 +137,7 @@ static void scsi_command_complete(void *opaque, int ret) scsi_req_complete(&r->req, status); done: - if (!r->req.io_canceled) { - scsi_req_unref(&r->req); - } + scsi_req_unref(&r->req); } /* Cancel a pending data transfer. */ @@ -150,11 +148,6 @@ static void scsi_cancel_io(SCSIRequest *req) DPRINTF("Cancel tag=0x%x\n", req->tag); if (r->req.aiocb) { bdrv_aio_cancel(r->req.aiocb); - - /* This reference was left in by scsi_*_data. We take ownership of - * it independent of whether bdrv_aio_cancel completes the request - * or not. */ - scsi_req_unref(&r->req); } r->req.aiocb = NULL; } @@ -214,9 +207,7 @@ static void scsi_read_complete(void * opaque, int ret) bdrv_set_guest_block_size(s->conf.bs, s->blocksize); scsi_req_data(&r->req, len); - if (!r->req.io_canceled) { - scsi_req_unref(&r->req); - } + scsi_req_unref(&r->req); } } -- cgit v1.2.3 From a83cfd12d9868b6732e3c6e5b2cbd69a2e0ab689 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 24 Sep 2014 16:27:55 +0800 Subject: scsi: Drop SCSIReqOps.cancel_io The only two implementations are identical to each other, with nothing specific to device: they only call bdrv_aio_cancel with the SCSIRequest.aiocb. Let's move it to scsi-bus. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-bus.c | 4 ++-- hw/scsi/scsi-disk.c | 14 -------------- hw/scsi/scsi-generic.c | 13 ------------- 3 files changed, 2 insertions(+), 29 deletions(-) (limited to 'hw') diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index f90a2040a8..764f6cf3b5 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -1727,8 +1727,8 @@ void scsi_req_cancel(SCSIRequest *req) scsi_req_ref(req); scsi_req_dequeue(req); req->io_canceled = true; - if (req->ops->cancel_io) { - req->ops->cancel_io(req); + if (req->aiocb) { + bdrv_aio_cancel(req->aiocb); } if (req->bus->info->cancel) { req->bus->info->cancel(req); diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 2e45752da1..ef13e66160 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -105,18 +105,6 @@ static void scsi_check_condition(SCSIDiskReq *r, SCSISense sense) scsi_req_complete(&r->req, CHECK_CONDITION); } -/* Cancel a pending data transfer. */ -static void scsi_cancel_io(SCSIRequest *req) -{ - SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); - - DPRINTF("Cancel tag=0x%x\n", req->tag); - if (r->req.aiocb) { - bdrv_aio_cancel(r->req.aiocb); - } - r->req.aiocb = NULL; -} - static uint32_t scsi_init_iovec(SCSIDiskReq *r, size_t size) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); @@ -2325,7 +2313,6 @@ static const SCSIReqOps scsi_disk_emulate_reqops = { .send_command = scsi_disk_emulate_command, .read_data = scsi_disk_emulate_read_data, .write_data = scsi_disk_emulate_write_data, - .cancel_io = scsi_cancel_io, .get_buf = scsi_get_buf, }; @@ -2335,7 +2322,6 @@ static const SCSIReqOps scsi_disk_dma_reqops = { .send_command = scsi_disk_dma_command, .read_data = scsi_read_data, .write_data = scsi_write_data, - .cancel_io = scsi_cancel_io, .get_buf = scsi_get_buf, .load_request = scsi_disk_load_request, .save_request = scsi_disk_save_request, diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index e92b418933..7e85047d7c 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -140,18 +140,6 @@ done: scsi_req_unref(&r->req); } -/* Cancel a pending data transfer. */ -static void scsi_cancel_io(SCSIRequest *req) -{ - SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); - - DPRINTF("Cancel tag=0x%x\n", req->tag); - if (r->req.aiocb) { - bdrv_aio_cancel(r->req.aiocb); - } - r->req.aiocb = NULL; -} - static int execute_command(BlockDriverState *bdrv, SCSIGenericReq *r, int direction, BlockDriverCompletionFunc *complete) @@ -458,7 +446,6 @@ const SCSIReqOps scsi_generic_req_ops = { .send_command = scsi_send_command, .read_data = scsi_read_data, .write_data = scsi_write_data, - .cancel_io = scsi_cancel_io, .get_buf = scsi_get_buf, .load_request = scsi_generic_load_request, .save_request = scsi_generic_save_request, -- cgit v1.2.3 From d5776465ee9a55815792efa34d79de240f4ffd99 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 25 Sep 2014 10:20:47 +0800 Subject: scsi: Introduce scsi_req_cancel_complete Let the aio cb do the clean up and notification job after scsi_req_cancel, in preparation for asynchronous cancellation. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-bus.c | 14 ++++++++++---- hw/scsi/scsi-disk.c | 8 ++++++++ hw/scsi/scsi-generic.c | 1 + 3 files changed, 19 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 764f6cf3b5..c91db63696 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -1718,6 +1718,16 @@ void scsi_req_complete(SCSIRequest *req, int status) scsi_req_unref(req); } +/* Called by the devices when the request is canceled. */ +void scsi_req_cancel_complete(SCSIRequest *req) +{ + assert(req->io_canceled); + if (req->bus->info->cancel) { + req->bus->info->cancel(req); + } + scsi_req_unref(req); +} + void scsi_req_cancel(SCSIRequest *req) { trace_scsi_req_cancel(req->dev->id, req->lun, req->tag); @@ -1730,10 +1740,6 @@ void scsi_req_cancel(SCSIRequest *req) if (req->aiocb) { bdrv_aio_cancel(req->aiocb); } - if (req->bus->info->cancel) { - req->bus->info->cancel(req); - } - scsi_req_unref(req); } static int scsi_ua_precedence(SCSISense sense) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index ef13e66160..7a7938a5bf 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -168,6 +168,7 @@ static void scsi_aio_complete(void *opaque, int ret) r->req.aiocb = NULL; block_acct_done(bdrv_get_stats(s->qdev.conf.bs), &r->acct); if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } @@ -214,6 +215,7 @@ static void scsi_write_do_fua(SCSIDiskReq *r) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } @@ -240,6 +242,7 @@ static void scsi_dma_complete_noio(void *opaque, int ret) block_acct_done(bdrv_get_stats(s->qdev.conf.bs), &r->acct); } if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } @@ -280,6 +283,7 @@ static void scsi_read_complete(void * opaque, int ret) r->req.aiocb = NULL; block_acct_done(bdrv_get_stats(s->qdev.conf.bs), &r->acct); if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } @@ -312,6 +316,7 @@ static void scsi_do_read(void *opaque, int ret) block_acct_done(bdrv_get_stats(s->qdev.conf.bs), &r->acct); } if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } @@ -432,6 +437,7 @@ static void scsi_write_complete(void * opaque, int ret) block_acct_done(bdrv_get_stats(s->qdev.conf.bs), &r->acct); } if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } @@ -1524,6 +1530,7 @@ static void scsi_unmap_complete(void *opaque, int ret) r->req.aiocb = NULL; if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } @@ -1623,6 +1630,7 @@ static void scsi_write_same_complete(void *opaque, int ret) r->req.aiocb = NULL; block_acct_done(bdrv_get_stats(s->qdev.conf.bs), &r->acct); if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 7e85047d7c..01bca084e6 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -94,6 +94,7 @@ static void scsi_command_complete(void *opaque, int ret) r->req.aiocb = NULL; if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { -- cgit v1.2.3 From 8e0a9320e94930fd6e5c2906c478203b80392f5c Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Sun, 28 Sep 2014 09:48:00 +0800 Subject: scsi: Introduce scsi_req_cancel_async Devices will call this function to start an asynchronous cancellation. The bus->info->cancel will be called after the request is canceled. Devices will probably need to track a separate TMF request that triggers this cancellation, and wait until the cancellation is done before completing it. So we store a notifier list in SCSIRequest and in scsi_req_cancel_complete we notify them. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-bus.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'hw') diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index c91db63696..0f3e0395f5 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -566,6 +566,7 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d, req->ops = reqops; object_ref(OBJECT(d)); object_ref(OBJECT(qbus->parent)); + notifier_list_init(&req->cancel_notifiers); trace_scsi_req_alloc(req->dev->id, req->lun, req->tag); return req; } @@ -1715,6 +1716,9 @@ void scsi_req_complete(SCSIRequest *req, int status) scsi_req_ref(req); scsi_req_dequeue(req); req->bus->info->complete(req, req->status, req->resid); + + /* Cancelled requests might end up being completed instead of cancelled */ + notifier_list_notify(&req->cancel_notifiers, req); scsi_req_unref(req); } @@ -1725,9 +1729,31 @@ void scsi_req_cancel_complete(SCSIRequest *req) if (req->bus->info->cancel) { req->bus->info->cancel(req); } + notifier_list_notify(&req->cancel_notifiers, req); scsi_req_unref(req); } +/* Cancel @req asynchronously. @notifier is added to @req's cancellation + * notifier list, the bus will be notified the requests cancellation is + * completed. + * */ +void scsi_req_cancel_async(SCSIRequest *req, Notifier *notifier) +{ + trace_scsi_req_cancel(req->dev->id, req->lun, req->tag); + if (notifier) { + notifier_list_add(&req->cancel_notifiers, notifier); + } + if (req->io_canceled) { + return; + } + scsi_req_ref(req); + scsi_req_dequeue(req); + req->io_canceled = true; + if (req->aiocb) { + bdrv_aio_cancel_async(req->aiocb); + } +} + void scsi_req_cancel(SCSIRequest *req) { trace_scsi_req_cancel(req->dev->id, req->lun, req->tag); -- cgit v1.2.3 From 49e7e31aa00a9fb466203de19120fe5c4459cac0 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 30 Sep 2014 11:40:23 +0800 Subject: virtio-scsi: Handle TMF request cancellation asynchronously For VIRTIO_SCSI_T_TMF_ABORT_TASK and VIRTIO_SCSI_T_TMF_ABORT_TASK_SET, use scsi_req_cancel_async to start the cancellation. Because each tmf command may cancel multiple requests, we need to use a counter to track the number of remaining requests we still need to wait for. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 64 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 7 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index fa36e23a2d..203e62449a 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -208,12 +208,33 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) return req; } -static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) +typedef struct { + Notifier notifier; + VirtIOSCSIReq *tmf_req; +} VirtIOSCSICancelNotifier; + +static void virtio_scsi_cancel_notify(Notifier *notifier, void *data) +{ + VirtIOSCSICancelNotifier *n = container_of(notifier, + VirtIOSCSICancelNotifier, + notifier); + + if (--n->tmf_req->remaining == 0) { + virtio_scsi_complete_req(n->tmf_req); + } + g_slice_free(VirtIOSCSICancelNotifier, n); +} + +/* Return 0 if the request is ready to be completed and return to guest; + * -EINPROGRESS if the request is submitted and will be completed later, in the + * case of async cancellation. */ +static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) { SCSIDevice *d = virtio_scsi_device_find(s, req->req.tmf.lun); SCSIRequest *r, *next; BusChild *kid; int target; + int ret = 0; if (s->dataplane_started && bdrv_get_aio_context(d->conf.bs) != s->ctx) { aio_context_acquire(s->ctx); @@ -251,7 +272,14 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) */ req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; } else { - scsi_req_cancel(r); + VirtIOSCSICancelNotifier *notifier; + + req->remaining = 1; + notifier = g_slice_new(VirtIOSCSICancelNotifier); + notifier->tmf_req = req; + notifier->notifier.notify = virtio_scsi_cancel_notify; + scsi_req_cancel_async(r, ¬ifier->notifier); + ret = -EINPROGRESS; } } break; @@ -277,6 +305,13 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) { goto incorrect_lun; } + + /* Add 1 to "remaining" until virtio_scsi_do_tmf returns. + * This way, if the bus starts calling back to the notifiers + * even before we finish the loop, virtio_scsi_cancel_notify + * will not complete the TMF too early. + */ + req->remaining = 1; QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) { if (r->hba_private) { if (req->req.tmf.subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK_SET) { @@ -286,10 +321,19 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; break; } else { - scsi_req_cancel(r); + VirtIOSCSICancelNotifier *notifier; + + req->remaining++; + notifier = g_slice_new(VirtIOSCSICancelNotifier); + notifier->notifier.notify = virtio_scsi_cancel_notify; + notifier->tmf_req = req; + scsi_req_cancel_async(r, ¬ifier->notifier); } } } + if (--req->remaining > 0) { + ret = -EINPROGRESS; + } break; case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET: @@ -310,20 +354,22 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) break; } - return; + return ret; incorrect_lun: req->resp.tmf.response = VIRTIO_SCSI_S_INCORRECT_LUN; - return; + return ret; fail: req->resp.tmf.response = VIRTIO_SCSI_S_BAD_TARGET; + return ret; } void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) { VirtIODevice *vdev = (VirtIODevice *)s; int type; + int r = 0; if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0, &type, sizeof(type)) < sizeof(type)) { @@ -337,7 +383,7 @@ void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) sizeof(VirtIOSCSICtrlTMFResp)) < 0) { virtio_scsi_bad_req(); } else { - virtio_scsi_do_tmf(s, req); + r = virtio_scsi_do_tmf(s, req); } } else if (req->req.tmf.type == VIRTIO_SCSI_T_AN_QUERY || @@ -350,7 +396,11 @@ void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req) req->resp.an.response = VIRTIO_SCSI_S_OK; } } - virtio_scsi_complete_req(req); + if (r == 0) { + virtio_scsi_complete_req(req); + } else { + assert(r == -EINPROGRESS); + } } static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) -- cgit v1.2.3