From 61e68b3fbd3e2b7beb636bc56f78d9c1ca25e8f9 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 16 Sep 2014 15:20:17 +0800 Subject: [PATCH 01/39] 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 +++++--- include/hw/scsi/scsi.h | 21 ++++++++++++++------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 954c6072bf6a..af293b59dac4 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); } } diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 2e3a8f987db3..6271ad3034b6 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -50,17 +50,24 @@ struct SCSIRequest { uint32_t tag; uint32_t lun; uint32_t status; + void *hba_private; size_t resid; SCSICommand cmd; + + /* Note: + * - fields before sense are initialized by scsi_req_alloc; + * - sense[] is uninitialized; + * - fields after sense are memset to 0 by scsi_req_alloc. + * */ + + uint8_t sense[SCSI_SENSE_BUF_SIZE]; + uint32_t sense_len; + bool enqueued; + bool io_canceled; + bool retry; + bool dma_started; BlockDriverAIOCB *aiocb; QEMUSGList *sg; - bool dma_started; - uint8_t sense[SCSI_SENSE_BUF_SIZE]; - uint32_t sense_len; - bool enqueued; - bool io_canceled; - bool retry; - void *hba_private; QTAILQ_ENTRY(SCSIRequest) next; }; From faf1e1fb4cdd3f1f71c948cb53e7d50f0798a202 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 16 Sep 2014 15:20:18 +0800 Subject: [PATCH 02/39] 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(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 86aba8851d8c..f0d21a3fdaa3 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) From 7ce0425575745a40e94e75426607e0bec17899fa Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 17 Sep 2014 12:40:07 +0200 Subject: [PATCH 03/39] 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(-) diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 7146e0ec49b3..308b393f9659 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); } From 9df7bfddcc25a22b99be5fe9b14ce367fa43b106 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 17 Sep 2014 18:10:37 +0200 Subject: [PATCH 04/39] 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(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index f0d21a3fdaa3..6953cbe6dd0c 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; } From bf359a445e780815866327891a845071197dfb63 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:00 +0800 Subject: [PATCH 05/39] 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 ++++++++++++-------------------- include/hw/virtio/virtio-scsi.h | 36 ++++++++++ 2 files changed, 79 insertions(+), 74 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 6953cbe6dd0c..57b2b7b3dc12 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); } } diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 188a2d91449f..7b65f5e6d994 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -172,6 +172,41 @@ typedef struct { bool events_dropped; } VirtIOSCSI; +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)); + #define DEFINE_VIRTIO_SCSI_PROPERTIES(_state, _conf_field) \ DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1), \ DEFINE_PROP_UINT32("max_sectors", _state, _conf_field.max_sectors, 0xFFFF),\ @@ -192,5 +227,6 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, HandleOutput cmd); void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); +void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req); #endif /* _QEMU_VIRTIO_SCSI_H */ From dc56b7c4fb0c95a9648ad5bf29e09e5676404077 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:01 +0800 Subject: [PATCH 06/39] 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 ++++++++++++++++++--------------- include/hw/virtio/virtio-scsi.h | 1 + 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 57b2b7b3dc12..5f3c0c1087fb 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -308,40 +308,46 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) 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); } } diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 7b65f5e6d994..b91d32633ada 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -227,6 +227,7 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, HandleOutput cmd); void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); +void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req); void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req); #endif /* _QEMU_VIRTIO_SCSI_H */ From c505333dab10cf7ffd3a30259c2df77d4d30343d Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:03 +0800 Subject: [PATCH 07/39] 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 +- include/hw/virtio/virtio-scsi.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 5f3c0c1087fb..8cab75b6d656 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; diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index b91d32633ada..b99763c19c75 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -229,5 +229,6 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req); void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req); +VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq); #endif /* _QEMU_VIRTIO_SCSI_H */ From aa8e8f83d0458a87e9a86ccfedfe68999d2d0fa6 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:04 +0800 Subject: [PATCH 08/39] 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 +- include/hw/virtio/virtio-scsi.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 8cab75b6d656..c7ae83dc45e5 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; diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index b99763c19c75..713df63aceae 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -230,5 +230,6 @@ void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req); void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req); VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq); +void virtio_scsi_free_req(VirtIOSCSIReq *req); #endif /* _QEMU_VIRTIO_SCSI_H */ From 20e6dca1df6b6ea74c3d6af74dc2184f464b3035 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:05 +0800 Subject: [PATCH 09/39] 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 ++-- include/hw/virtio/virtio-scsi.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index c7ae83dc45e5..58b420084ea9 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; diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 713df63aceae..6cd2f5764d13 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -231,5 +231,7 @@ void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req); void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req); VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq); void virtio_scsi_free_req(VirtIOSCSIReq *req); +void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, + uint32_t event, uint32_t reason); #endif /* _QEMU_VIRTIO_SCSI_H */ From 7779edfeb1822ff5f554a4c1f3e9798789a9352c Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:27 +0800 Subject: [PATCH 10/39] 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(-) diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 6b6fb61c4727..5b5d5958340a 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 33a1d863b1e1..7d675772e48d 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 f5608140f9e9..155fac9e87b9 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 = { From 6a0c6b59788627541faf70864464f1e155dc18d7 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:28 +0800 Subject: [PATCH 11/39] 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(+) diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 5b5d5958340a..297eac23675f 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 7d675772e48d..bb699f27f654 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 155fac9e87b9..b82b7380bb7c 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); } From c39343fd811a22c921fc08e9e6ca62c8e7539264 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:29 +0800 Subject: [PATCH 12/39] 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(-) diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 297eac23675f..eaaa275775f2 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 bb699f27f654..458aabc68bd4 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 b82b7380bb7c..ef4898383864 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 = { From 1312f12bcc8911ed99b67227fb9d1607295f71ed Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:30 +0800 Subject: [PATCH 13/39] 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(+) diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index eaaa275775f2..42760340f476 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 458aabc68bd4..a466674ba7bd 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 ef4898383864..09f209325e58 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); } From 4f456d8025c7259c66b2b2bcec99d5c6c94d99be Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:31 +0800 Subject: [PATCH 14/39] 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(-) diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 42760340f476..31f5286e3c37 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 a466674ba7bd..271104d049c0 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 09f209325e58..3c1f37bfe493 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 = { From e77ca8b92af8a5213897331d676089e8919f383d Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:32 +0800 Subject: [PATCH 15/39] 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(+) diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 31f5286e3c37..422402e564a0 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 271104d049c0..5d7f3a6af765 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 3c1f37bfe493..4446d7926995 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 = { From 8ee486ae339f0e5236f4a9ab988fc963edcc73b5 Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:33 +0800 Subject: [PATCH 16/39] 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(-) diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 422402e564a0..6d0a7f36e78c 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 5d7f3a6af765..da2e427716d4 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 4446d7926995..2b3a94187674 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, From 352fa88dfb2e9c72fa2a1506acb39f349d4befbf Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:34 +0800 Subject: [PATCH 17/39] 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(+) diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 6d0a7f36e78c..ca682bb7e6ae 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 da2e427716d4..de0764de4815 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 2b3a94187674..40652a748103 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, From 91ba21208839643603e7f7fa5864723c3f371ebe Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:35 +0800 Subject: [PATCH 18/39] 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(-) diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index de0764de4815..c074f64e9200 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 40652a748103..62f84c4ac028 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); From 48833071d955406ebeddc365a8df8b5cb12b035f Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:36 +0800 Subject: [PATCH 19/39] 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(-) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 62f84c4ac028..714286dab6bb 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 = { From 8f3d60e568f53cb3ccdedd917f8e49cdb304973b Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:37 +0800 Subject: [PATCH 20/39] 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(+) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 714286dab6bb..8f3b79b03a81 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 = { From c8075caf19b000b975349f8976958cedf7d2613a Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 30 Sep 2014 14:10:38 +0800 Subject: [PATCH 21/39] 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 +++++++++ include/hw/virtio/virtio.h | 3 +++ 5 files changed, 71 insertions(+), 76 deletions(-) diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index ca682bb7e6ae..f451ca1ed365 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 c074f64e9200..5175d5773348 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 8f3b79b03a81..83a699fc23c9 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 5c981801f3b1..2c236bf271bc 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) { diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index a60104ca24fa..0726d76f49f5 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -161,6 +161,9 @@ typedef struct VirtioDeviceClass { int (*load)(VirtIODevice *vdev, QEMUFile *f, int version_id); } VirtioDeviceClass; +void virtio_instance_init_common(Object *proxy_obj, void *data, + size_t vdev_size, const char *vdev_name); + void virtio_init(VirtIODevice *vdev, const char *name, uint16_t device_id, size_t config_size); void virtio_cleanup(VirtIODevice *vdev); From 19d339f11d0768df2b4e0c40530bb4ab53e6bb05 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 6 Aug 2014 13:35:06 +0800 Subject: [PATCH 22/39] 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 ++ include/hw/virtio/virtio-scsi.h | 1 + 4 files changed, 16 insertions(+) diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 5175d5773348..e7d3ea178a53 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 58b420084ea9..91ead26ff89d 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 83a699fc23c9..bae62c8f660f 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 = { diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 6cd2f5764d13..2ff145a4eca1 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -151,6 +151,7 @@ struct VirtIOSCSIConf { uint32_t cmd_per_lun; char *vhostfd; char *wwpn; + IOThread *iothread; }; typedef struct VirtIOSCSICommon { From 244e2898b7a7735b3da114c120abe206af56a167 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 24 Sep 2014 15:21:41 +0800 Subject: [PATCH 23/39] virtio-scsi: Add VirtIOSCSIVring in VirtIOSCSIReq Move VirtIOSCSIReq to header and add one field "vring" as a wrapper structure of Vring, VirtIOSCSIVring. This is necessary for coming dataplane code that runs uses vring on iothread. Signed-off-by: Fam Zheng Signed-off-by: Paolo Bonzini --- include/hw/virtio/virtio-scsi.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 2ff145a4eca1..e886517c6d66 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -17,6 +17,8 @@ #include "hw/virtio/virtio.h" #include "hw/pci/pci.h" #include "hw/scsi/scsi.h" +#include "sysemu/iothread.h" +#include "hw/virtio/dataplane/vring.h" #define TYPE_VIRTIO_SCSI_COMMON "virtio-scsi-common" #define VIRTIO_SCSI_COMMON(obj) \ @@ -154,6 +156,15 @@ struct VirtIOSCSIConf { IOThread *iothread; }; +struct VirtIOSCSI; + +typedef struct { + struct VirtIOSCSI *parent; + Vring vring; + EventNotifier host_notifier; + EventNotifier guest_notifier; +} VirtIOSCSIVring; + typedef struct VirtIOSCSICommon { VirtIODevice parent_obj; VirtIOSCSIConf conf; @@ -165,7 +176,7 @@ typedef struct VirtIOSCSICommon { VirtQueue **cmd_vqs; } VirtIOSCSICommon; -typedef struct { +typedef struct VirtIOSCSI { VirtIOSCSICommon parent_obj; SCSIBus bus; @@ -186,6 +197,8 @@ typedef struct VirtIOSCSIReq { * */ VirtQueueElement elem; + /* Set by dataplane code. */ + VirtIOSCSIVring *vring; SCSIRequest *sreq; size_t resp_size; enum SCSIXferMode mode; From 91cb1c9b56064e7cba27ab310c9c4c477694589e Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:24 +0800 Subject: [PATCH 24/39] 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 ++++++++++++++++++++++++++++++++ include/hw/virtio/virtio-scsi.h | 19 +++ 3 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 hw/scsi/virtio-scsi-dataplane.c diff --git a/hw/scsi/Makefile.objs b/hw/scsi/Makefile.objs index 121ddc5cf45b..40c79d34c9e9 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 000000000000..acbf622ed8f2 --- /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; +} diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index e886517c6d66..8e1968f9e894 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -182,6 +182,18 @@ typedef struct VirtIOSCSI { SCSIBus bus; int resetting; bool events_dropped; + + /* Fields for dataplane below */ + AioContext *ctx; /* one iothread per virtio-scsi-pci for now */ + + /* Vring is used instead of vq in dataplane code, because of the underlying + * memory layer thread safety */ + VirtIOSCSIVring *ctrl_vring; + VirtIOSCSIVring *event_vring; + VirtIOSCSIVring **cmd_vrings; + bool dataplane_started; + bool dataplane_starting; + bool dataplane_stopping; } VirtIOSCSI; typedef struct VirtIOSCSIReq { @@ -248,4 +260,11 @@ void virtio_scsi_free_req(VirtIOSCSIReq *req); void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, uint32_t event, uint32_t reason); +void virtio_scsi_set_iothread(VirtIOSCSI *s, IOThread *iothread); +void virtio_scsi_dataplane_start(VirtIOSCSI *s); +void virtio_scsi_dataplane_stop(VirtIOSCSI *s); +void virtio_scsi_vring_push_notify(VirtIOSCSIReq *req); +VirtIOSCSIReq *virtio_scsi_pop_req_vring(VirtIOSCSI *s, + VirtIOSCSIVring *vring); + #endif /* _QEMU_VIRTIO_SCSI_H */ From 63c7e542686ff9616816b527c824ec0ac1f73cbe Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:25 +0800 Subject: [PATCH 25/39] 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(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 91ead26ff89d..dc705f0fa52a 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); } From dfb37cf7fa206afa6e212af16fee74427464f1d1 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:26 +0800 Subject: [PATCH 26/39] 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 ++++++++++++++++++++++++++++++--- include/hw/virtio/virtio-scsi.h | 2 ++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index dc705f0fa52a..57efe656598a 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); } diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 8e1968f9e894..1a6a919960b0 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -194,6 +194,8 @@ typedef struct VirtIOSCSI { bool dataplane_started; bool dataplane_starting; bool dataplane_stopping; + bool dataplane_disabled; + Notifier migration_state_notifier; } VirtIOSCSI; typedef struct VirtIOSCSIReq { From 359eea71d98e7f2cf9efb5e65bb59a240bedb131 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:27 +0800 Subject: [PATCH 27/39] 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 ++++++++++++-------- include/hw/virtio/virtio-scsi.h | 3 ++- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index acbf622ed8f2..11f570540727 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 57efe656598a..6cf070f70ede 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); + } } } diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 1a6a919960b0..1cc759a64402 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -256,7 +256,8 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req); -void virtio_scsi_handle_cmd_req(VirtIOSCSI *s, VirtIOSCSIReq *req); +bool virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req); +void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req); VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq); void virtio_scsi_free_req(VirtIOSCSIReq *req); void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, From 1880ad4f4e3b49f15c55e816d66b9690b3ede00c Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:28 +0800 Subject: [PATCH 28/39] 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 +++++++-- include/hw/virtio/virtio-scsi.h | 4 ++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 11f570540727..b778e051f885 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 6cf070f70ede..395178e949b9 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, diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 1cc759a64402..60dbfc99a875 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -213,6 +213,10 @@ typedef struct VirtIOSCSIReq { VirtQueueElement elem; /* Set by dataplane code. */ VirtIOSCSIVring *vring; + + /* Used for two-stage request submission */ + QTAILQ_ENTRY(VirtIOSCSIReq) next; + SCSIRequest *sreq; size_t resp_size; enum SCSIXferMode mode; From 5170f40b102bcabed54e8fa8ec86957e35c41d41 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:29 +0800 Subject: [PATCH 29/39] 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(+) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 395178e949b9..09a39cb99191 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) From 9786b592a93e557e575ea6f18ee1e1fc6d68dc7b Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 23 Sep 2014 15:49:30 +0800 Subject: [PATCH 30/39] 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(+) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 09a39cb99191..fa36e23a2de6 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 From eda470e41a753070e057380a9a71e2ad7347f667 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 24 Sep 2014 16:27:52 +0800 Subject: [PATCH 31/39] 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 ++++++++++--- include/hw/scsi/scsi.h | 1 - 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index af293b59dac4..f90a2040a86d 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 048cfc7b0542..20b20f0bae33 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); } diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 6271ad3034b6..169e8dfd4425 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -265,7 +265,6 @@ void scsi_req_data(SCSIRequest *req, int len); void scsi_req_complete(SCSIRequest *req, int status); uint8_t *scsi_req_get_buf(SCSIRequest *req); int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len); -void scsi_req_abort(SCSIRequest *req, int status); void scsi_req_cancel(SCSIRequest *req); void scsi_req_retry(SCSIRequest *req); void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense); From 6c25fa6cf8b58db72956e880d76e4adc301bb472 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 24 Sep 2014 16:27:53 +0800 Subject: [PATCH 32/39] 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(-) diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 20587b41c1cb..2a73a43d1d3b 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; } From 3df9caf88f5c0859ae380101fea47609ba1dbfbd Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 24 Sep 2014 16:27:54 +0800 Subject: [PATCH 33/39] 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(-) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 9645d0194a8c..2e45752da14d 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 2a73a43d1d3b..e92b418933b9 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); } } From a83cfd12d9868b6732e3c6e5b2cbd69a2e0ab689 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 24 Sep 2014 16:27:55 +0800 Subject: [PATCH 34/39] 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 ------------- include/hw/scsi/scsi.h | 1 - 4 files changed, 2 insertions(+), 30 deletions(-) diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index f90a2040a86d..764f6cf3b56b 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 2e45752da14d..ef13e6616002 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 e92b418933b9..7e85047d7c1e 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -140,18 +140,6 @@ static void scsi_command_complete(void *opaque, int ret) 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, diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 169e8dfd4425..0290873120cb 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -130,7 +130,6 @@ struct SCSIReqOps { int32_t (*send_command)(SCSIRequest *req, uint8_t *buf); void (*read_data)(SCSIRequest *req); void (*write_data)(SCSIRequest *req); - void (*cancel_io)(SCSIRequest *req); uint8_t *(*get_buf)(SCSIRequest *req); void (*save_request)(QEMUFile *f, SCSIRequest *req); From d5776465ee9a55815792efa34d79de240f4ffd99 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 25 Sep 2014 10:20:47 +0800 Subject: [PATCH 35/39] 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 + include/hw/scsi/scsi.h | 1 + 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 764f6cf3b56b..c91db636960f 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 ef13e6616002..7a7938a5bffe 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 7e85047d7c1e..01bca084e6e3 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) { diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 0290873120cb..2127a335ba88 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -264,6 +264,7 @@ void scsi_req_data(SCSIRequest *req, int len); void scsi_req_complete(SCSIRequest *req, int status); uint8_t *scsi_req_get_buf(SCSIRequest *req); int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len); +void scsi_req_cancel_complete(SCSIRequest *req); void scsi_req_cancel(SCSIRequest *req); void scsi_req_retry(SCSIRequest *req); void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense); From 8e0a9320e94930fd6e5c2906c478203b80392f5c Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Sun, 28 Sep 2014 09:48:00 +0800 Subject: [PATCH 36/39] 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 ++++++++++++++++++++++++++ include/hw/scsi/scsi.h | 3 +++ 2 files changed, 29 insertions(+) diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index c91db636960f..0f3e0395f5c6 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); diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h index 2127a335ba88..b61bedb28cec 100644 --- a/include/hw/scsi/scsi.h +++ b/include/hw/scsi/scsi.h @@ -5,6 +5,7 @@ #include "block/block.h" #include "hw/block/block.h" #include "sysemu/sysemu.h" +#include "qemu/notify.h" #define MAX_SCSI_DEVS 255 @@ -53,6 +54,7 @@ struct SCSIRequest { void *hba_private; size_t resid; SCSICommand cmd; + NotifierList cancel_notifiers; /* Note: * - fields before sense are initialized by scsi_req_alloc; @@ -266,6 +268,7 @@ uint8_t *scsi_req_get_buf(SCSIRequest *req); int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len); void scsi_req_cancel_complete(SCSIRequest *req); void scsi_req_cancel(SCSIRequest *req); +void scsi_req_cancel_async(SCSIRequest *req, Notifier *notifier); void scsi_req_retry(SCSIRequest *req); void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense); void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense); From 49e7e31aa00a9fb466203de19120fe5c4459cac0 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 30 Sep 2014 11:40:23 +0800 Subject: [PATCH 37/39] 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 +++++++++++++++++++++++++++++---- include/hw/virtio/virtio-scsi.h | 9 +++-- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index fa36e23a2de6..203e62449aa1 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) diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 60dbfc99a875..d6e5e7935c7b 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -214,8 +214,13 @@ typedef struct VirtIOSCSIReq { /* Set by dataplane code. */ VirtIOSCSIVring *vring; - /* Used for two-stage request submission */ - QTAILQ_ENTRY(VirtIOSCSIReq) next; + union { + /* Used for two-stage request submission */ + QTAILQ_ENTRY(VirtIOSCSIReq) next; + + /* Used for cancellation of request during TMFs */ + int remaining; + }; SCSIRequest *sreq; size_t resp_size; From be4d57c1ea7f17b9cadb0150b330efd9b6026972 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Tue, 30 Sep 2014 09:09:11 +0200 Subject: [PATCH 38/39] util: introduce bitmap_try_new regular bitmap_new simply aborts if the memory allocation fails. bitmap_try_new returns NULL on failure and allows for proper error handling. Signed-off-by: Peter Lieven Signed-off-by: Paolo Bonzini --- include/qemu/bitmap.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h index 1babd5d81222..edf4f17d9ca3 100644 --- a/include/qemu/bitmap.h +++ b/include/qemu/bitmap.h @@ -88,10 +88,19 @@ int slow_bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1, int slow_bitmap_intersects(const unsigned long *bitmap1, const unsigned long *bitmap2, long bits); -static inline unsigned long *bitmap_new(long nbits) +static inline unsigned long *bitmap_try_new(long nbits) { long len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); - return g_malloc0(len); + return g_try_malloc0(len); +} + +static inline unsigned long *bitmap_new(long nbits) +{ + unsigned long *ptr = bitmap_try_new(nbits); + if (ptr == NULL) { + abort(); + } + return ptr; } static inline void bitmap_zero(unsigned long *dst, long nbits) From a9fe4c957b762dbb814c254204c082bab93c8459 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Tue, 30 Sep 2014 09:09:12 +0200 Subject: [PATCH 39/39] block/iscsi: handle failure on malloc of the allocationmap Signed-off-by: Peter Lieven Signed-off-by: Paolo Bonzini --- block/iscsi.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/block/iscsi.c b/block/iscsi.c index 3c1b4167041e..26bded31c82b 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -317,6 +317,13 @@ static bool is_request_lun_aligned(int64_t sector_num, int nb_sectors, return 1; } +static unsigned long *iscsi_allocationmap_init(IscsiLun *iscsilun) +{ + return bitmap_try_new(DIV_ROUND_UP(sector_lun2qemu(iscsilun->num_blocks, + iscsilun), + iscsilun->cluster_sectors)); +} + static void iscsi_allocationmap_set(IscsiLun *iscsilun, int64_t sector_num, int nb_sectors) { @@ -1403,9 +1410,10 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, iscsilun->cluster_sectors = (iscsilun->bl.opt_unmap_gran * iscsilun->block_size) >> BDRV_SECTOR_BITS; if (iscsilun->lbprz && !(bs->open_flags & BDRV_O_NOCACHE)) { - iscsilun->allocationmap = - bitmap_new(DIV_ROUND_UP(bs->total_sectors, - iscsilun->cluster_sectors)); + iscsilun->allocationmap = iscsi_allocationmap_init(iscsilun); + if (iscsilun->allocationmap == NULL) { + ret = -ENOMEM; + } } } @@ -1498,10 +1506,7 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset) if (iscsilun->allocationmap != NULL) { g_free(iscsilun->allocationmap); - iscsilun->allocationmap = - bitmap_new(DIV_ROUND_UP(sector_lun2qemu(iscsilun->num_blocks, - iscsilun), - iscsilun->cluster_sectors)); + iscsilun->allocationmap = iscsi_allocationmap_init(iscsilun); } return 0;