From: Paolo Bonzini <pbonzini@redhat.com>
To: Fam Zheng <famz@redhat.com>, qemu-devel@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>, Stefan Hajnoczi <stefanha@redhat.com>
Subject: Re: [Qemu-devel] [PATCH 1/3] scsi-bus: Unify request unref in scsi_req_cancel
Date: Thu, 18 Sep 2014 10:59:04 +0200 [thread overview]
Message-ID: <541A9ED8.9080100@redhat.com> (raw)
In-Reply-To: <1411007799-23199-2-git-send-email-famz@redhat.com>
Il 18/09/2014 04:36, Fam Zheng ha scritto:
> Before, scsi_req_cancel will take ownership of the canceled request and
> unref it. This is because we didn't know if AIO CB will be called or not
> during the cancelling, so we set the io_canceled flag before calling it,
> and skip to unref in the potentially called callbacks, which is not
> very nice.
>
> Now, bdrv_aio_cancel has a stricter contract that the completion
> callback is always called, so we can remove the special case of
> req->io_canceled.
>
> It will also make implementing asynchronous cancellation easier.
>
> Also, as the existing SCSIReqOps.cancel_io implementations are exactly
> the same, we can move the code to bus for now as we are touching them in
> this patch.
>
> All AIO callbacks in devices, those will be called because of
> bdrv_aio_cancel, should call scsi_req_canceled if req->io_canceled is
> set. That's the uniform place we release the reference we grabbed in
> scsi_req_cancel and notify buses.
>
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---
> hw/scsi/scsi-bus.c | 30 ++++++++++++-------------
> hw/scsi/scsi-disk.c | 59 ++++++++++++++------------------------------------
> hw/scsi/scsi-generic.c | 28 +++++-------------------
> include/hw/scsi/scsi.h | 2 +-
> 4 files changed, 37 insertions(+), 82 deletions(-)
>
> diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
> index 954c607..74172cc 100644
> --- a/hw/scsi/scsi-bus.c
> +++ b/hw/scsi/scsi-bus.c
> @@ -1613,7 +1613,6 @@ void scsi_req_continue(SCSIRequest *req)
> {
> if (req->io_canceled) {
> trace_scsi_req_continue_canceled(req->dev->id, req->lun, req->tag);
> - return;
I think this is incorrect; same in scsi_req_data.
As discussed on IRC, scsi-generic is the case where this happens. We
can change it to use the same io_canceled handling as everyone else, so
that the subsequent changes are more mechanical.
> }
> trace_scsi_req_continue(req->dev->id, req->lun, req->tag);
> if (req->cmd.mode == SCSI_XFER_TO_DEV) {
> @@ -1631,7 +1630,6 @@ void scsi_req_data(SCSIRequest *req, int len)
> uint8_t *buf;
> if (req->io_canceled) {
> trace_scsi_req_data_canceled(req->dev->id, req->lun, req->tag, len);
> - return;
> }
> trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
> assert(req->cmd.mode != SCSI_XFER_NONE);
> @@ -1716,35 +1714,37 @@ void scsi_req_complete(SCSIRequest *req, int status)
> scsi_req_unref(req);
> }
>
> +/* Called by the devices when the request is canceled. */
> +void scsi_req_canceled(SCSIRequest *req)
> +{
> + assert(req->io_canceled);
> + if (req->bus->info->cancel) {
> + req->bus->info->cancel(req);
> + }
> + scsi_req_unref(req);
> +}
I think this patch does a bit too much. I would do it like this:
- first, as mentioned above, make scsi-generic follow the usual pattern with
if (req->io_canceled) {
goto done;
}
...
done:
if (!req->io_canceled)
scsi_req_unref(&r->req);
}
- second, remove the scsi_req_unref from the scsi_cancel_io
implementations, and remove the "if" statement around
done:
if (!r->req.io_canceled) {
scsi_req_unref(&r->req);
}
We can do this now that the callback is always invoked, and it
simplifies the reference counting quite a bit.
- third, uninline scsi_cancel_io and introduce scsi_req_canceled
> void scsi_req_cancel(SCSIRequest *req)
> {
> trace_scsi_req_cancel(req->dev->id, req->lun, req->tag);
> - if (!req->enqueued) {
> + if (req->io_canceled) {
> return;
> }
> 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);
> - }
> - scsi_req_unref(req);
> }
>
> void scsi_req_abort(SCSIRequest *req, int status)
> {
> - if (!req->enqueued) {
> + if (req->io_canceled) {
> 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_cancel(req);
This is a problem, because we would complete the request twice: once
from scsi_req_canceled, once in scsi_req_complete below.
Let's just drop scsi_req_abort. The only user can be removed like this:
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index 048cfc7..ec5dc0d 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,10 @@ static void vscsi_request_cancelled(SCSIRequest *sreq)
{
vscsi_req *req = sreq->hba_private;
+ if (req->dma_error) {
+ vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
+ vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+ }
vscsi_put_req(req);
}
(Yet another separate patch...)
I like this patch. It is very mechanical, which makes it easier to
review than the size would suggest. However, splitting it would make
the review even easier. :)
Paolo
> scsi_req_complete(req, status);
> scsi_req_unref(req);
> }
> diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
> index e34a544..56d7e6d 100644
> --- a/hw/scsi/scsi-disk.c
> +++ b/hw/scsi/scsi-disk.c
> @@ -105,23 +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);
> -
> - /* 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;
> -}
> -
> static uint32_t scsi_init_iovec(SCSIDiskReq *r, size_t size)
> {
> SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
> @@ -185,6 +168,7 @@ static void scsi_aio_complete(void *opaque, int ret)
> r->req.aiocb = NULL;
> bdrv_acct_done(s->qdev.conf.bs, &r->acct);
> if (r->req.io_canceled) {
> + scsi_req_canceled(&r->req);
> goto done;
> }
>
> @@ -197,9 +181,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)
> @@ -233,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_canceled(&r->req);
> goto done;
> }
>
> @@ -245,9 +228,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)
> @@ -260,6 +241,7 @@ static void scsi_dma_complete_noio(void *opaque, int ret)
> bdrv_acct_done(s->qdev.conf.bs, &r->acct);
> }
> if (r->req.io_canceled) {
> + scsi_req_canceled(&r->req);
> goto done;
> }
>
> @@ -279,9 +261,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)
> @@ -302,6 +282,7 @@ static void scsi_read_complete(void * opaque, int ret)
> r->req.aiocb = NULL;
> bdrv_acct_done(s->qdev.conf.bs, &r->acct);
> if (r->req.io_canceled) {
> + scsi_req_canceled(&r->req);
> goto done;
> }
>
> @@ -319,9 +300,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. */
> @@ -336,6 +315,7 @@ static void scsi_do_read(void *opaque, int ret)
> bdrv_acct_done(s->qdev.conf.bs, &r->acct);
> }
> if (r->req.io_canceled) {
> + scsi_req_canceled(&r->req);
> goto done;
> }
>
> @@ -361,9 +341,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. */
> @@ -456,6 +434,7 @@ static void scsi_write_complete(void * opaque, int ret)
> bdrv_acct_done(s->qdev.conf.bs, &r->acct);
> }
> if (r->req.io_canceled) {
> + scsi_req_canceled(&r->req);
> goto done;
> }
>
> @@ -478,9 +457,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)
> @@ -1548,6 +1525,7 @@ static void scsi_unmap_complete(void *opaque, int ret)
>
> r->req.aiocb = NULL;
> if (r->req.io_canceled) {
> + scsi_req_canceled(&r->req);
> goto done;
> }
>
> @@ -1577,9 +1555,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);
> }
>
> @@ -1649,6 +1625,7 @@ static void scsi_write_same_complete(void *opaque, int ret)
> r->req.aiocb = NULL;
> bdrv_acct_done(s->qdev.conf.bs, &r->acct);
> if (r->req.io_canceled) {
> + scsi_req_canceled(&r->req);
> goto done;
> }
>
> @@ -1672,9 +1649,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);
> }
> @@ -2337,7 +2312,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,
> };
>
> @@ -2347,7 +2321,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 20587b4..5bde909 100644
> --- a/hw/scsi/scsi-generic.c
> +++ b/hw/scsi/scsi-generic.c
> @@ -132,27 +132,12 @@ static void scsi_command_complete(void *opaque, int ret)
> DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
> r, r->req.tag, status);
>
> - scsi_req_complete(&r->req, status);
> if (!r->req.io_canceled) {
> - 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);
> -
> - /* 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);
> + scsi_req_complete(&r->req, status);
> + } else {
> + scsi_req_canceled(&r->req);
> }
> - r->req.aiocb = NULL;
> + scsi_req_unref(&r->req);
> }
>
> static int execute_command(BlockDriverState *bdrv,
> @@ -211,9 +196,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);
> }
> }
>
> @@ -465,7 +448,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 2e3a8f9..25a5617 100644
> --- a/include/hw/scsi/scsi.h
> +++ b/include/hw/scsi/scsi.h
> @@ -123,7 +123,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);
> @@ -259,6 +258,7 @@ 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_canceled(SCSIRequest *req);
> void scsi_req_cancel(SCSIRequest *req);
> void scsi_req_retry(SCSIRequest *req);
> void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
>
next prev parent reply other threads:[~2014-09-18 8:59 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-09-18 2:36 [Qemu-devel] [PATCH 0/3] virtio-scsi: Asynchronous cancellation Fam Zheng
2014-09-18 2:36 ` [Qemu-devel] [PATCH 1/3] scsi-bus: Unify request unref in scsi_req_cancel Fam Zheng
2014-09-18 8:59 ` Paolo Bonzini [this message]
2014-09-18 2:36 ` [Qemu-devel] [PATCH 2/3] scsi: Introduce scsi_req_cancel_async Fam Zheng
2014-09-18 9:17 ` Paolo Bonzini
2014-09-18 9:18 ` Paolo Bonzini
2014-09-18 2:36 ` [Qemu-devel] [PATCH 3/3] virtio-scsi: Handle TMF request cancellation asynchronously Fam Zheng
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=541A9ED8.9080100@redhat.com \
--to=pbonzini@redhat.com \
--cc=famz@redhat.com \
--cc=kwolf@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).