* [Qemu-devel] [PATCH for-2.5 0/3] scsi: preparations for thread-safe virtio-scsi dataplane
@ 2015-08-06 10:01 Paolo Bonzini
2015-08-06 10:01 ` [Qemu-devel] [PATCH 1/3] scsi: create restart bottom half in the right AioContext Paolo Bonzini
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Paolo Bonzini @ 2015-08-06 10:01 UTC (permalink / raw)
To: qemu-devel; +Cc: lvivier, famz
As a preparation for making virtio-scsi dataplane really thread-safe,
this series fixes a bug in rerror/werror=stop (patch 1) and cleans up
the code so that AIO callbacks are clearly identified. These will need
to acquire/release the AioContext, so it's important not to miss any
of them.
Paolo
Paolo Bonzini (3):
scsi: create restart bottom half in the right AioContext
scsi-disk: identify AIO callbacks more clearly
scsi-generic: identify AIO callbacks more clearly
hw/scsi/scsi-bus.c | 3 +-
hw/scsi/scsi-disk.c | 91 +++++++++++++++++++++++++++++++++-----------------
hw/scsi/scsi-generic.c | 66 ++++++++++++++++++++++--------------
3 files changed, 104 insertions(+), 56 deletions(-)
--
2.4.3
^ permalink raw reply [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH 1/3] scsi: create restart bottom half in the right AioContext
2015-08-06 10:01 [Qemu-devel] [PATCH for-2.5 0/3] scsi: preparations for thread-safe virtio-scsi dataplane Paolo Bonzini
@ 2015-08-06 10:01 ` Paolo Bonzini
2015-08-06 10:01 ` [Qemu-devel] [PATCH 2/3] scsi-disk: identify AIO callbacks more clearly Paolo Bonzini
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Paolo Bonzini @ 2015-08-06 10:01 UTC (permalink / raw)
To: qemu-devel; +Cc: lvivier, famz
This matches commit 4407c1c (virtio-blk: Schedule BH in the right context,
2014-06-17), which did the same thing for virtio-blk.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi/scsi-bus.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index f0ae462..ffac8f4 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -136,7 +136,8 @@ static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
return;
}
if (!s->bh) {
- s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
+ AioContext *ctx = blk_get_aio_context(s->conf.blk);
+ s->bh = aio_bh_new(ctx, scsi_dma_restart_bh, s);
qemu_bh_schedule(s->bh);
}
}
--
2.4.3
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH 2/3] scsi-disk: identify AIO callbacks more clearly
2015-08-06 10:01 [Qemu-devel] [PATCH for-2.5 0/3] scsi: preparations for thread-safe virtio-scsi dataplane Paolo Bonzini
2015-08-06 10:01 ` [Qemu-devel] [PATCH 1/3] scsi: create restart bottom half in the right AioContext Paolo Bonzini
@ 2015-08-06 10:01 ` Paolo Bonzini
2015-08-06 12:35 ` Fam Zheng
2015-08-06 10:01 ` [Qemu-devel] [PATCH 3/3] scsi-generic: " Paolo Bonzini
2015-08-06 12:38 ` [Qemu-devel] [PATCH for-2.5 0/3] scsi: preparations for thread-safe virtio-scsi dataplane Fam Zheng
3 siblings, 1 reply; 6+ messages in thread
From: Paolo Bonzini @ 2015-08-06 10:01 UTC (permalink / raw)
To: qemu-devel; +Cc: lvivier, famz
Functions that are not callbacks should assert that aiocb is NULL and
have a non-opaque argument (usually a pointer to SCSIDiskReq).
AIO callbacks should assert that aiocb is not NULL and take care of
calling block_acct done. They also have an opaque argument.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi/scsi-disk.c | 91 +++++++++++++++++++++++++++++++++++------------------
1 file changed, 61 insertions(+), 30 deletions(-)
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 64f0694..8fb0f43 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -217,6 +217,8 @@ static void scsi_write_do_fua(SCSIDiskReq *r)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+ assert(r->req.aiocb == NULL);
+
if (r->req.io_canceled) {
scsi_req_cancel_complete(&r->req);
goto done;
@@ -235,15 +237,10 @@ done:
scsi_req_unref(&r->req);
}
-static void scsi_dma_complete_noio(void *opaque, int ret)
+static void scsi_dma_complete_noio(SCSIDiskReq *r, int ret)
{
- SCSIDiskReq *r = (SCSIDiskReq *)opaque;
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+ assert(r->req.aiocb == NULL);
- if (r->req.aiocb != NULL) {
- r->req.aiocb = NULL;
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
- }
if (r->req.io_canceled) {
scsi_req_cancel_complete(&r->req);
goto done;
@@ -271,9 +268,13 @@ done:
static void scsi_dma_complete(void *opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
assert(r->req.aiocb != NULL);
- scsi_dma_complete_noio(opaque, ret);
+ r->req.aiocb = NULL;
+
+ block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ scsi_dma_complete_noio(r, ret);
}
static void scsi_read_complete(void * opaque, int ret)
@@ -308,16 +309,13 @@ done:
}
/* Actually issue a read to the block device. */
-static void scsi_do_read(void *opaque, int ret)
+static void scsi_do_read(SCSIDiskReq *r, int ret)
{
- SCSIDiskReq *r = opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint32_t n;
- if (r->req.aiocb != NULL) {
- r->req.aiocb = NULL;
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
- }
+ assert (r->req.aiocb == NULL);
+
if (r->req.io_canceled) {
scsi_req_cancel_complete(&r->req);
goto done;
@@ -349,6 +347,18 @@ done:
scsi_req_unref(&r->req);
}
+static void scsi_do_read_cb(void *opaque, int ret)
+{
+ SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+ assert (r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
+
+ block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ scsi_do_read(opaque, ret);
+}
+
/* Read more data from scsi device into buffer. */
static void scsi_read_data(SCSIRequest *req)
{
@@ -384,7 +394,7 @@ static void scsi_read_data(SCSIRequest *req)
if (first && scsi_is_cmd_fua(&r->req.cmd)) {
block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
BLOCK_ACCT_FLUSH);
- r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_do_read, r);
+ r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_do_read_cb, r);
} else {
scsi_do_read(r, 0);
}
@@ -430,16 +440,12 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
return action != BLOCK_ERROR_ACTION_IGNORE;
}
-static void scsi_write_complete(void * opaque, int ret)
+static void scsi_write_complete_noio(SCSIDiskReq *r, int ret)
{
- SCSIDiskReq *r = (SCSIDiskReq *)opaque;
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint32_t n;
- if (r->req.aiocb != NULL) {
- r->req.aiocb = NULL;
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
- }
+ assert (r->req.aiocb == NULL);
+
if (r->req.io_canceled) {
scsi_req_cancel_complete(&r->req);
goto done;
@@ -467,6 +473,18 @@ done:
scsi_req_unref(&r->req);
}
+static void scsi_write_complete(void * opaque, int ret)
+{
+ SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+ assert (r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
+
+ block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ scsi_write_complete_noio(r, ret);
+}
+
static void scsi_write_data(SCSIRequest *req)
{
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
@@ -480,18 +498,18 @@ static void scsi_write_data(SCSIRequest *req)
scsi_req_ref(&r->req);
if (r->req.cmd.mode != SCSI_XFER_TO_DEV) {
DPRINTF("Data transfer direction invalid\n");
- scsi_write_complete(r, -EINVAL);
+ scsi_write_complete_noio(r, -EINVAL);
return;
}
if (!r->req.sg && !r->qiov.size) {
/* Called for the first time. Ask the driver to send us more data. */
r->started = true;
- scsi_write_complete(r, 0);
+ scsi_write_complete_noio(r, 0);
return;
}
if (s->tray_open) {
- scsi_write_complete(r, -ENOMEDIUM);
+ scsi_write_complete_noio(r, -ENOMEDIUM);
return;
}
@@ -500,7 +518,7 @@ static void scsi_write_data(SCSIRequest *req)
if (r->req.sg) {
scsi_dma_complete_noio(r, 0);
} else {
- scsi_write_complete(r, 0);
+ scsi_write_complete_noio(r, 0);
}
return;
}
@@ -1557,15 +1575,17 @@ typedef struct UnmapCBData {
int count;
} UnmapCBData;
-static void scsi_unmap_complete(void *opaque, int ret)
+static void scsi_unmap_complete(void *opaque, int ret);
+
+static void scsi_unmap_complete_noio(UnmapCBData *data, int ret)
{
- UnmapCBData *data = opaque;
SCSIDiskReq *r = data->r;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint64_t sector_num;
uint32_t nb_sectors;
- r->req.aiocb = NULL;
+ assert(r->req.aiocb == NULL);
+
if (r->req.io_canceled) {
scsi_req_cancel_complete(&r->req);
goto done;
@@ -1601,6 +1621,17 @@ done:
g_free(data);
}
+static void scsi_unmap_complete(void *opaque, int ret)
+{
+ UnmapCBData *data = opaque;
+ SCSIDiskReq *r = data->r;
+
+ assert(r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
+
+ scsi_unmap_complete_noio(data, ret);
+}
+
static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
@@ -1638,7 +1669,7 @@ static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
/* The matching unref is in scsi_unmap_complete, before data is freed. */
scsi_req_ref(&r->req);
- scsi_unmap_complete(data, 0);
+ scsi_unmap_complete_noio(data, 0);
return;
invalid_param_len:
--
2.4.3
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH 3/3] scsi-generic: identify AIO callbacks more clearly
2015-08-06 10:01 [Qemu-devel] [PATCH for-2.5 0/3] scsi: preparations for thread-safe virtio-scsi dataplane Paolo Bonzini
2015-08-06 10:01 ` [Qemu-devel] [PATCH 1/3] scsi: create restart bottom half in the right AioContext Paolo Bonzini
2015-08-06 10:01 ` [Qemu-devel] [PATCH 2/3] scsi-disk: identify AIO callbacks more clearly Paolo Bonzini
@ 2015-08-06 10:01 ` Paolo Bonzini
2015-08-06 12:38 ` [Qemu-devel] [PATCH for-2.5 0/3] scsi: preparations for thread-safe virtio-scsi dataplane Fam Zheng
3 siblings, 0 replies; 6+ messages in thread
From: Paolo Bonzini @ 2015-08-06 10:01 UTC (permalink / raw)
To: qemu-devel; +Cc: lvivier, famz
Functions that are not callbacks should assert that aiocb is NULL and
have a SCSIGenericReq argument.
AIO callbacks should assert that aiocb is not NULL. They also have an
opaque argument.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi/scsi-generic.c | 66 +++++++++++++++++++++++++++++++-------------------
1 file changed, 41 insertions(+), 25 deletions(-)
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index e53470f..1b6350b 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -88,12 +88,12 @@ static void scsi_free_request(SCSIRequest *req)
}
/* Helper function for command completion. */
-static void scsi_command_complete(void *opaque, int ret)
+static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
{
int status;
- SCSIGenericReq *r = (SCSIGenericReq *)opaque;
- r->req.aiocb = NULL;
+ assert(r->req.aiocb == NULL);
+
if (r->req.io_canceled) {
scsi_req_cancel_complete(&r->req);
goto done;
@@ -142,6 +142,15 @@ done:
scsi_req_unref(&r->req);
}
+static void scsi_command_complete(void *opaque, int ret)
+{
+ SCSIGenericReq *r = (SCSIGenericReq *)opaque;
+
+ assert(r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
+ scsi_command_complete_noio(r, ret);
+}
+
static int execute_command(BlockBackend *blk,
SCSIGenericReq *r, int direction,
BlockCompletionFunc *complete)
@@ -172,33 +181,37 @@ static void scsi_read_complete(void * opaque, int ret)
SCSIDevice *s = r->req.dev;
int len;
+ assert(r->req.aiocb != NULL);
r->req.aiocb = NULL;
+
if (ret || r->req.io_canceled) {
- scsi_command_complete(r, ret);
+ scsi_command_complete_noio(r, ret);
return;
}
+
len = r->io_header.dxfer_len - r->io_header.resid;
DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
r->len = -1;
if (len == 0) {
- scsi_command_complete(r, 0);
- } else {
- /* Snoop READ CAPACITY output to set the blocksize. */
- if (r->req.cmd.buf[0] == READ_CAPACITY_10 &&
- (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) {
- s->blocksize = ldl_be_p(&r->buf[4]);
- s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL;
- } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
- (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
- s->blocksize = ldl_be_p(&r->buf[8]);
- s->max_lba = ldq_be_p(&r->buf[0]);
- }
- blk_set_guest_block_size(s->conf.blk, s->blocksize);
+ scsi_command_complete_noio(r, 0);
+ return;
+ }
- scsi_req_data(&r->req, len);
- scsi_req_unref(&r->req);
+ /* Snoop READ CAPACITY output to set the blocksize. */
+ if (r->req.cmd.buf[0] == READ_CAPACITY_10 &&
+ (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) {
+ s->blocksize = ldl_be_p(&r->buf[4]);
+ s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL;
+ } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
+ (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
+ s->blocksize = ldl_be_p(&r->buf[8]);
+ s->max_lba = ldq_be_p(&r->buf[0]);
}
+ blk_set_guest_block_size(s->conf.blk, s->blocksize);
+
+ scsi_req_data(&r->req, len);
+ scsi_req_unref(&r->req);
}
/* Read more data from scsi device into buffer. */
@@ -213,14 +226,14 @@ static void scsi_read_data(SCSIRequest *req)
/* The request is used as the AIO opaque value, so add a ref. */
scsi_req_ref(&r->req);
if (r->len == -1) {
- scsi_command_complete(r, 0);
+ scsi_command_complete_noio(r, 0);
return;
}
ret = execute_command(s->conf.blk, r, SG_DXFER_FROM_DEV,
scsi_read_complete);
if (ret < 0) {
- scsi_command_complete(r, ret);
+ scsi_command_complete_noio(r, ret);
}
}
@@ -230,9 +243,12 @@ static void scsi_write_complete(void * opaque, int ret)
SCSIDevice *s = r->req.dev;
DPRINTF("scsi_write_complete() ret = %d\n", ret);
+
+ assert(r->req.aiocb != NULL);
r->req.aiocb = NULL;
+
if (ret || r->req.io_canceled) {
- scsi_command_complete(r, ret);
+ scsi_command_complete_noio(r, ret);
return;
}
@@ -242,7 +258,7 @@ static void scsi_write_complete(void * opaque, int ret)
DPRINTF("block size %d\n", s->blocksize);
}
- scsi_command_complete(r, ret);
+ scsi_command_complete_noio(r, ret);
}
/* Write data to a scsi device. Returns nonzero on failure.
@@ -264,7 +280,7 @@ static void scsi_write_data(SCSIRequest *req)
scsi_req_ref(&r->req);
ret = execute_command(s->conf.blk, r, SG_DXFER_TO_DEV, scsi_write_complete);
if (ret < 0) {
- scsi_command_complete(r, ret);
+ scsi_command_complete_noio(r, ret);
}
}
@@ -306,7 +322,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
ret = execute_command(s->conf.blk, r, SG_DXFER_NONE,
scsi_command_complete);
if (ret < 0) {
- scsi_command_complete(r, ret);
+ scsi_command_complete_noio(r, ret);
return 0;
}
return 0;
--
2.4.3
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [PATCH 2/3] scsi-disk: identify AIO callbacks more clearly
2015-08-06 10:01 ` [Qemu-devel] [PATCH 2/3] scsi-disk: identify AIO callbacks more clearly Paolo Bonzini
@ 2015-08-06 12:35 ` Fam Zheng
0 siblings, 0 replies; 6+ messages in thread
From: Fam Zheng @ 2015-08-06 12:35 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: lvivier, qemu-devel
On Thu, 08/06 12:01, Paolo Bonzini wrote:
> /* Actually issue a read to the block device. */
> -static void scsi_do_read(void *opaque, int ret)
> +static void scsi_do_read(SCSIDiskReq *r, int ret)
> {
> - SCSIDiskReq *r = opaque;
> SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
> uint32_t n;
>
> - if (r->req.aiocb != NULL) {
> - r->req.aiocb = NULL;
> - block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
> - }
> + assert (r->req.aiocb == NULL);
> +
> if (r->req.io_canceled) {
> scsi_req_cancel_complete(&r->req);
> goto done;
> @@ -349,6 +347,18 @@ done:
> scsi_req_unref(&r->req);
> }
>
> +static void scsi_do_read_cb(void *opaque, int ret)
> +{
> + SCSIDiskReq *r = (SCSIDiskReq *)opaque;
> + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
> +
> + assert (r->req.aiocb != NULL);
Majority of asserts across the code base don't get whitespace in the middle,
but 4 out of 8 in this patch do :)
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [PATCH for-2.5 0/3] scsi: preparations for thread-safe virtio-scsi dataplane
2015-08-06 10:01 [Qemu-devel] [PATCH for-2.5 0/3] scsi: preparations for thread-safe virtio-scsi dataplane Paolo Bonzini
` (2 preceding siblings ...)
2015-08-06 10:01 ` [Qemu-devel] [PATCH 3/3] scsi-generic: " Paolo Bonzini
@ 2015-08-06 12:38 ` Fam Zheng
3 siblings, 0 replies; 6+ messages in thread
From: Fam Zheng @ 2015-08-06 12:38 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: lvivier, qemu-devel
On Thu, 08/06 12:01, Paolo Bonzini wrote:
> As a preparation for making virtio-scsi dataplane really thread-safe,
> this series fixes a bug in rerror/werror=stop (patch 1) and cleans up
> the code so that AIO callbacks are clearly identified. These will need
> to acquire/release the AioContext, so it's important not to miss any
> of them.
Except the minor whitespace problem in patch 2,
Reviewed-by: Fam Zheng <famz@redhat.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2015-08-06 12:38 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-08-06 10:01 [Qemu-devel] [PATCH for-2.5 0/3] scsi: preparations for thread-safe virtio-scsi dataplane Paolo Bonzini
2015-08-06 10:01 ` [Qemu-devel] [PATCH 1/3] scsi: create restart bottom half in the right AioContext Paolo Bonzini
2015-08-06 10:01 ` [Qemu-devel] [PATCH 2/3] scsi-disk: identify AIO callbacks more clearly Paolo Bonzini
2015-08-06 12:35 ` Fam Zheng
2015-08-06 10:01 ` [Qemu-devel] [PATCH 3/3] scsi-generic: " Paolo Bonzini
2015-08-06 12:38 ` [Qemu-devel] [PATCH for-2.5 0/3] scsi: preparations for thread-safe virtio-scsi dataplane Fam Zheng
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).