From: Fam Zheng <famz@redhat.com>
To: qemu-devel@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Stefan Hajnoczi <stefanha@redhat.com>
Subject: [Qemu-devel] [PATCH 2/3] scsi: Introduce scsi_req_cancel_async
Date: Thu, 18 Sep 2014 10:36:38 +0800 [thread overview]
Message-ID: <1411007799-23199-3-git-send-email-famz@redhat.com> (raw)
In-Reply-To: <1411007799-23199-1-git-send-email-famz@redhat.com>
Devices can call this function to start an asynchronous cancellation.
The bus->info->cancel will be called later.
Two fields are added to SCSIRequest to respectively keep track of:
1) The list of (TMF) requests that are waiting for this request to be
canceled.
2) The number of (IO) requests that this request (as a TMF request) is
waiting for.
So when scsi_req_cancel_async is called, the tmf request is tracked with
these fields. When cancel is done, we check if we should notify the bus.
If this is the last canceled request this tmf request is waiting for
(cancel_dep_count drops to 0), we call .cancel_dep_complete so the bus
can complete it.
Signed-off-by: Fam Zheng <famz@redhat.com>
---
hw/scsi/scsi-bus.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++--
include/hw/scsi/scsi.h | 14 ++++++++++++++
2 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 74172cc..47ad0b4 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -552,7 +552,7 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
SCSIBus *bus = scsi_bus_from_device(d);
BusState *qbus = BUS(bus);
- req = g_malloc0(reqops->size);
+ req = g_malloc0(reqops ? reqops->size : sizeof(SCSIRequest));
req->refcount = 1;
req->bus = bus;
req->dev = d;
@@ -564,6 +564,7 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
req->ops = reqops;
object_ref(OBJECT(d));
object_ref(OBJECT(qbus->parent));
+ QTAILQ_INIT(&req->cancel_deps);
trace_scsi_req_alloc(req->dev->id, req->lun, req->tag);
return req;
}
@@ -1598,7 +1599,7 @@ void scsi_req_unref(SCSIRequest *req)
if (bus->info->free_request && req->hba_private) {
bus->info->free_request(bus, req->hba_private);
}
- if (req->ops->free_req) {
+ if (req->ops && req->ops->free_req) {
req->ops->free_req(req);
}
object_unref(OBJECT(req->dev));
@@ -1717,13 +1718,58 @@ void scsi_req_complete(SCSIRequest *req, int status)
/* Called by the devices when the request is canceled. */
void scsi_req_canceled(SCSIRequest *req)
{
+ SCSIRequestReference *ref, *next;
assert(req->io_canceled);
if (req->bus->info->cancel) {
req->bus->info->cancel(req);
}
+ QTAILQ_FOREACH_SAFE(ref, &req->cancel_deps, next, next) {
+ SCSIRequest *r = ref->req;
+ assert(r->cancel_dep_count);
+ r->cancel_dep_count--;
+ if (!r->cancel_dep_count && req->bus->info->cancel_dep_complete) {
+ req->bus->info->cancel_dep_complete(r);
+ }
+ QTAILQ_REMOVE(&req->cancel_deps, ref, next);
+ scsi_req_unref(r);
+ g_free(ref);
+ }
scsi_req_unref(req);
}
+static void scsi_req_cancel_dep_add(SCSIRequest *req, SCSIRequest *tmf_req)
+{
+ SCSIRequestReference *ref = g_new0(SCSIRequestReference, 1);
+ ref->req = tmf_req;
+ tmf_req->cancel_dep_count++;
+ scsi_req_ref(tmf_req);
+ QTAILQ_INSERT_TAIL(&req->cancel_deps, ref, next);
+}
+
+/* Cancel @req asynchronously.
+ * @tmf_req is added to @req's cancellation dependency list, the bus will be
+ * notified with @tmf_req when all the requests it depends on are canceled.
+ *
+ * @red: The request to cancel.
+ * @tmf_req: The tmf request which cancels @req.
+ * */
+void scsi_req_cancel_async(SCSIRequest *req, SCSIRequest *tmf_req)
+{
+ trace_scsi_req_cancel(req->dev->id, req->lun, req->tag);
+ if (tmf_req) {
+ scsi_req_cancel_dep_add(req, tmf_req);
+ }
+ 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 25a5617..d0e0fb4 100644
--- a/include/hw/scsi/scsi.h
+++ b/include/hw/scsi/scsi.h
@@ -42,6 +42,13 @@ struct SCSICommand {
enum SCSIXferMode mode;
};
+struct SCSIRequest;
+
+typedef struct SCSIRequestReference {
+ struct SCSIRequest *req;
+ QTAILQ_ENTRY(SCSIRequestReference) next;
+} SCSIRequestReference;
+
struct SCSIRequest {
SCSIBus *bus;
SCSIDevice *dev;
@@ -62,6 +69,11 @@ struct SCSIRequest {
bool retry;
void *hba_private;
QTAILQ_ENTRY(SCSIRequest) next;
+
+ /* List of requests that depend on this one */
+ QTAILQ_HEAD(, SCSIRequestReference) cancel_deps;
+ /* The number of requests this one depends on */
+ int cancel_dep_count;
};
#define TYPE_SCSI_DEVICE "scsi-device"
@@ -137,6 +149,7 @@ struct SCSIBusInfo {
void (*transfer_data)(SCSIRequest *req, uint32_t arg);
void (*complete)(SCSIRequest *req, uint32_t arg, size_t resid);
void (*cancel)(SCSIRequest *req);
+ void (*cancel_dep_complete)(SCSIRequest *req);
void (*hotplug)(SCSIBus *bus, SCSIDevice *dev);
void (*hot_unplug)(SCSIBus *bus, SCSIDevice *dev);
void (*change)(SCSIBus *bus, SCSIDevice *dev, SCSISense sense);
@@ -260,6 +273,7 @@ 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_cancel_async(SCSIRequest *req, SCSIRequest *tmf_req);
void scsi_req_retry(SCSIRequest *req);
void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense);
--
1.9.3
next prev parent reply other threads:[~2014-09-18 2:37 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
2014-09-18 2:36 ` Fam Zheng [this message]
2014-09-18 9:17 ` [Qemu-devel] [PATCH 2/3] scsi: Introduce scsi_req_cancel_async 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=1411007799-23199-3-git-send-email-famz@redhat.com \
--to=famz@redhat.com \
--cc=kwolf@redhat.com \
--cc=pbonzini@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).