diff options
Diffstat (limited to 'block/iscsi.c')
| -rw-r--r-- | block/iscsi.c | 47 |
1 files changed, 35 insertions, 12 deletions
diff --git a/block/iscsi.c b/block/iscsi.c index 727dee50bf..a7e8c1ffaf 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -117,7 +117,6 @@ typedef struct IscsiAIOCB { QEMUBH *bh; IscsiLun *iscsilun; struct scsi_task *task; - uint8_t *buf; int status; int64_t sector_num; int nb_sectors; @@ -125,6 +124,7 @@ typedef struct IscsiAIOCB { #ifdef __linux__ sg_io_hdr_t *ioh; #endif + bool cancelled; } IscsiAIOCB; /* libiscsi uses time_t so its enough to process events every second */ @@ -150,9 +150,6 @@ iscsi_bh_cb(void *p) qemu_bh_delete(acb->bh); - g_free(acb->buf); - acb->buf = NULL; - acb->common.cb(acb->common.opaque, acb->status); if (acb->task != NULL) { @@ -291,14 +288,20 @@ static void iscsi_co_init_iscsitask(IscsiLun *iscsilun, struct IscsiTask *iTask) }; } +/* Called (via iscsi_service) with QemuMutex held. */ static void iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { IscsiAIOCB *acb = private_data; - acb->status = -ECANCELED; - iscsi_schedule_bh(acb); + /* If the command callback hasn't been called yet, drop the task */ + if (!acb->bh) { + /* Call iscsi_aio_ioctl_cb() with SCSI_STATUS_CANCELLED */ + iscsi_scsi_cancel_task(iscsi, acb->task); + } + + qemu_aio_unref(acb); /* acquired in iscsi_aio_cancel() */ } static void @@ -307,14 +310,25 @@ iscsi_aio_cancel(BlockAIOCB *blockacb) IscsiAIOCB *acb = (IscsiAIOCB *)blockacb; IscsiLun *iscsilun = acb->iscsilun; - if (acb->status != -EINPROGRESS) { + qemu_mutex_lock(&iscsilun->mutex); + + /* If it was cancelled or completed already, our work is done here */ + if (acb->cancelled || acb->status != -EINPROGRESS) { + qemu_mutex_unlock(&iscsilun->mutex); return; } + acb->cancelled = true; + + qemu_aio_ref(acb); /* released in iscsi_abort_task_cb() */ + /* send a task mgmt call to the target to cancel the task on the target */ - iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task, - iscsi_abort_task_cb, acb); + if (iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task, + iscsi_abort_task_cb, acb) < 0) { + qemu_aio_unref(acb); /* since iscsi_abort_task_cb() won't be called */ + } + qemu_mutex_unlock(&iscsilun->mutex); } static const AIOCBInfo iscsi_aiocb_info = { @@ -348,6 +362,8 @@ static void iscsi_timed_check_events(void *opaque) { IscsiLun *iscsilun = opaque; + qemu_mutex_lock(&iscsilun->mutex); + /* check for timed out requests */ iscsi_service(iscsilun->iscsi, 0); @@ -360,6 +376,8 @@ static void iscsi_timed_check_events(void *opaque) * to return to service once this situation changes. */ iscsi_set_events(iscsilun); + qemu_mutex_unlock(&iscsilun->mutex); + timer_mod(iscsilun->event_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + EVENT_INTERVAL); } @@ -933,8 +951,13 @@ iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status, { IscsiAIOCB *acb = opaque; - g_free(acb->buf); - acb->buf = NULL; + if (status == SCSI_STATUS_CANCELLED) { + if (!acb->bh) { + acb->status = -ECANCELED; + iscsi_schedule_bh(acb); + } + return; + } acb->status = 0; if (status < 0) { @@ -1010,8 +1033,8 @@ static BlockAIOCB *iscsi_aio_ioctl(BlockDriverState *bs, acb->iscsilun = iscsilun; acb->bh = NULL; acb->status = -EINPROGRESS; - acb->buf = NULL; acb->ioh = buf; + acb->cancelled = false; if (req != SG_IO) { iscsi_ioctl_handle_emulated(acb, req, buf); |