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 <famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Fam Zheng 2014-09-28 09:48:00 +08:00 committed by Paolo Bonzini
parent d5776465ee
commit 8e0a9320e9
2 changed files with 29 additions and 0 deletions

View file

@ -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);