334 lines
10 KiB
Diff
334 lines
10 KiB
Diff
|
From e450cd0c7256039a42167621ff8125067feca6ad Mon Sep 17 00:00:00 2001
|
||
|
From: Peter Lieven <pl@dlhnet.de>
|
||
|
Date: Sat, 17 Nov 2012 14:37:39 +0100
|
||
|
Subject: [PATCH] iscsi: fix deadlock during login
|
||
|
|
||
|
If the connection is interrupted before the first login is successfully
|
||
|
completed qemu-kvm is waiting forever in qemu_aio_wait().
|
||
|
|
||
|
This is fixed by performing an sync login to the target. If the
|
||
|
connection breaks after the first successful login errors are
|
||
|
handled internally by libiscsi.
|
||
|
|
||
|
Signed-off-by: Peter Lieven <pl@kamp.de>
|
||
|
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||
|
(cherry picked from commit e829b0bb054ed3389e5b22dad61875e51674e629)
|
||
|
|
||
|
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
|
||
|
---
|
||
|
block/iscsi.c | 251 ++++++++++++++++------------------------------------------
|
||
|
1 file changed, 70 insertions(+), 181 deletions(-)
|
||
|
|
||
|
diff --git a/block/iscsi.c b/block/iscsi.c
|
||
|
index 817196a..1836c71 100644
|
||
|
--- a/block/iscsi.c
|
||
|
+++ b/block/iscsi.c
|
||
|
@@ -65,13 +65,6 @@ typedef struct IscsiAIOCB {
|
||
|
#endif
|
||
|
} IscsiAIOCB;
|
||
|
|
||
|
-struct IscsiTask {
|
||
|
- IscsiLun *iscsilun;
|
||
|
- BlockDriverState *bs;
|
||
|
- int status;
|
||
|
- int complete;
|
||
|
-};
|
||
|
-
|
||
|
static void
|
||
|
iscsi_bh_cb(void *p)
|
||
|
{
|
||
|
@@ -384,7 +377,7 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
||
|
*(uint16_t *)&acb->task->cdb[7] = htons(num_sectors);
|
||
|
break;
|
||
|
}
|
||
|
-
|
||
|
+
|
||
|
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
|
||
|
iscsi_aio_read16_cb,
|
||
|
NULL,
|
||
|
@@ -669,163 +662,6 @@ iscsi_getlength(BlockDriverState *bs)
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
-static void
|
||
|
-iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status,
|
||
|
- void *command_data, void *opaque)
|
||
|
-{
|
||
|
- struct IscsiTask *itask = opaque;
|
||
|
- struct scsi_readcapacity16 *rc16;
|
||
|
- struct scsi_task *task = command_data;
|
||
|
-
|
||
|
- if (status != 0) {
|
||
|
- error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
|
||
|
- iscsi_get_error(iscsi));
|
||
|
- itask->status = 1;
|
||
|
- itask->complete = 1;
|
||
|
- scsi_free_scsi_task(task);
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- rc16 = scsi_datain_unmarshall(task);
|
||
|
- if (rc16 == NULL) {
|
||
|
- error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
|
||
|
- itask->status = 1;
|
||
|
- itask->complete = 1;
|
||
|
- scsi_free_scsi_task(task);
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- itask->iscsilun->block_size = rc16->block_length;
|
||
|
- itask->iscsilun->num_blocks = rc16->returned_lba + 1;
|
||
|
- itask->bs->total_sectors = itask->iscsilun->num_blocks *
|
||
|
- itask->iscsilun->block_size / BDRV_SECTOR_SIZE ;
|
||
|
-
|
||
|
- itask->status = 0;
|
||
|
- itask->complete = 1;
|
||
|
- scsi_free_scsi_task(task);
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status,
|
||
|
- void *command_data, void *opaque)
|
||
|
-{
|
||
|
- struct IscsiTask *itask = opaque;
|
||
|
- struct scsi_readcapacity10 *rc10;
|
||
|
- struct scsi_task *task = command_data;
|
||
|
-
|
||
|
- if (status != 0) {
|
||
|
- error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
|
||
|
- iscsi_get_error(iscsi));
|
||
|
- itask->status = 1;
|
||
|
- itask->complete = 1;
|
||
|
- scsi_free_scsi_task(task);
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- rc10 = scsi_datain_unmarshall(task);
|
||
|
- if (rc10 == NULL) {
|
||
|
- error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
|
||
|
- itask->status = 1;
|
||
|
- itask->complete = 1;
|
||
|
- scsi_free_scsi_task(task);
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- itask->iscsilun->block_size = rc10->block_size;
|
||
|
- if (rc10->lba == 0) {
|
||
|
- /* blank disk loaded */
|
||
|
- itask->iscsilun->num_blocks = 0;
|
||
|
- } else {
|
||
|
- itask->iscsilun->num_blocks = rc10->lba + 1;
|
||
|
- }
|
||
|
- itask->bs->total_sectors = itask->iscsilun->num_blocks *
|
||
|
- itask->iscsilun->block_size / BDRV_SECTOR_SIZE ;
|
||
|
-
|
||
|
- itask->status = 0;
|
||
|
- itask->complete = 1;
|
||
|
- scsi_free_scsi_task(task);
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-iscsi_inquiry_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
||
|
- void *opaque)
|
||
|
-{
|
||
|
- struct IscsiTask *itask = opaque;
|
||
|
- struct scsi_task *task = command_data;
|
||
|
- struct scsi_inquiry_standard *inq;
|
||
|
-
|
||
|
- if (status != 0) {
|
||
|
- itask->status = 1;
|
||
|
- itask->complete = 1;
|
||
|
- scsi_free_scsi_task(task);
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- inq = scsi_datain_unmarshall(task);
|
||
|
- if (inq == NULL) {
|
||
|
- error_report("iSCSI: Failed to unmarshall inquiry data.");
|
||
|
- itask->status = 1;
|
||
|
- itask->complete = 1;
|
||
|
- scsi_free_scsi_task(task);
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- itask->iscsilun->type = inq->periperal_device_type;
|
||
|
-
|
||
|
- scsi_free_scsi_task(task);
|
||
|
-
|
||
|
- switch (itask->iscsilun->type) {
|
||
|
- case TYPE_DISK:
|
||
|
- task = iscsi_readcapacity16_task(iscsi, itask->iscsilun->lun,
|
||
|
- iscsi_readcapacity16_cb, opaque);
|
||
|
- if (task == NULL) {
|
||
|
- error_report("iSCSI: failed to send readcapacity16 command.");
|
||
|
- itask->status = 1;
|
||
|
- itask->complete = 1;
|
||
|
- return;
|
||
|
- }
|
||
|
- break;
|
||
|
- case TYPE_ROM:
|
||
|
- task = iscsi_readcapacity10_task(iscsi, itask->iscsilun->lun,
|
||
|
- 0, 0,
|
||
|
- iscsi_readcapacity10_cb, opaque);
|
||
|
- if (task == NULL) {
|
||
|
- error_report("iSCSI: failed to send readcapacity16 command.");
|
||
|
- itask->status = 1;
|
||
|
- itask->complete = 1;
|
||
|
- return;
|
||
|
- }
|
||
|
- break;
|
||
|
- default:
|
||
|
- itask->status = 0;
|
||
|
- itask->complete = 1;
|
||
|
- }
|
||
|
-}
|
||
|
-
|
||
|
-static void
|
||
|
-iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
||
|
- void *opaque)
|
||
|
-{
|
||
|
- struct IscsiTask *itask = opaque;
|
||
|
- struct scsi_task *task;
|
||
|
-
|
||
|
- if (status != 0) {
|
||
|
- itask->status = 1;
|
||
|
- itask->complete = 1;
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- task = iscsi_inquiry_task(iscsi, itask->iscsilun->lun,
|
||
|
- 0, 0, 36,
|
||
|
- iscsi_inquiry_cb, opaque);
|
||
|
- if (task == NULL) {
|
||
|
- error_report("iSCSI: failed to send inquiry command.");
|
||
|
- itask->status = 1;
|
||
|
- itask->complete = 1;
|
||
|
- return;
|
||
|
- }
|
||
|
-}
|
||
|
-
|
||
|
static int parse_chap(struct iscsi_context *iscsi, const char *target)
|
||
|
{
|
||
|
QemuOptsList *list;
|
||
|
@@ -938,7 +774,10 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
|
||
|
IscsiLun *iscsilun = bs->opaque;
|
||
|
struct iscsi_context *iscsi = NULL;
|
||
|
struct iscsi_url *iscsi_url = NULL;
|
||
|
- struct IscsiTask task;
|
||
|
+ struct scsi_task *task = NULL;
|
||
|
+ struct scsi_inquiry_standard *inq = NULL;
|
||
|
+ struct scsi_readcapacity10 *rc10 = NULL;
|
||
|
+ struct scsi_readcapacity16 *rc16 = NULL;
|
||
|
char *initiator_name = NULL;
|
||
|
int ret;
|
||
|
|
||
|
@@ -1001,33 +840,80 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
|
||
|
/* check if we got HEADER_DIGEST via the options */
|
||
|
parse_header_digest(iscsi, iscsi_url->target);
|
||
|
|
||
|
- task.iscsilun = iscsilun;
|
||
|
- task.status = 0;
|
||
|
- task.complete = 0;
|
||
|
- task.bs = bs;
|
||
|
+ if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) {
|
||
|
+ error_report("iSCSI: Failed to connect to LUN : %s",
|
||
|
+ iscsi_get_error(iscsi));
|
||
|
+ ret = -EINVAL;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
|
||
|
iscsilun->iscsi = iscsi;
|
||
|
iscsilun->lun = iscsi_url->lun;
|
||
|
|
||
|
- if (iscsi_full_connect_async(iscsi, iscsi_url->portal, iscsi_url->lun,
|
||
|
- iscsi_connect_cb, &task)
|
||
|
- != 0) {
|
||
|
- error_report("iSCSI: Failed to start async connect.");
|
||
|
+ task = iscsi_inquiry_sync(iscsi, iscsilun->lun, 0, 0, 36);
|
||
|
+
|
||
|
+ if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||
|
+ error_report("iSCSI: failed to send inquiry command.");
|
||
|
ret = -EINVAL;
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
- while (!task.complete) {
|
||
|
- iscsi_set_events(iscsilun);
|
||
|
- qemu_aio_wait();
|
||
|
- }
|
||
|
- if (task.status != 0) {
|
||
|
- error_report("iSCSI: Failed to connect to LUN : %s",
|
||
|
- iscsi_get_error(iscsi));
|
||
|
+ inq = scsi_datain_unmarshall(task);
|
||
|
+ if (inq == NULL) {
|
||
|
+ error_report("iSCSI: Failed to unmarshall inquiry data.");
|
||
|
ret = -EINVAL;
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
+ iscsilun->type = inq->periperal_device_type;
|
||
|
+
|
||
|
+ scsi_free_scsi_task(task);
|
||
|
+
|
||
|
+ switch (iscsilun->type) {
|
||
|
+ case TYPE_DISK:
|
||
|
+ task = iscsi_readcapacity16_sync(iscsi, iscsilun->lun);
|
||
|
+ if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||
|
+ error_report("iSCSI: failed to send readcapacity16 command.");
|
||
|
+ ret = -EINVAL;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ rc16 = scsi_datain_unmarshall(task);
|
||
|
+ if (rc16 == NULL) {
|
||
|
+ error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
|
||
|
+ ret = -EINVAL;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ iscsilun->block_size = rc16->block_length;
|
||
|
+ iscsilun->num_blocks = rc16->returned_lba + 1;
|
||
|
+ break;
|
||
|
+ case TYPE_ROM:
|
||
|
+ task = iscsi_readcapacity10_sync(iscsi, iscsilun->lun, 0, 0);
|
||
|
+ if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||
|
+ error_report("iSCSI: failed to send readcapacity10 command.");
|
||
|
+ ret = -EINVAL;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ rc10 = scsi_datain_unmarshall(task);
|
||
|
+ if (rc10 == NULL) {
|
||
|
+ error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
|
||
|
+ ret = -EINVAL;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ iscsilun->block_size = rc10->block_size;
|
||
|
+ if (rc10->lba == 0) {
|
||
|
+ /* blank disk loaded */
|
||
|
+ iscsilun->num_blocks = 0;
|
||
|
+ } else {
|
||
|
+ iscsilun->num_blocks = rc10->lba + 1;
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ bs->total_sectors = iscsilun->num_blocks *
|
||
|
+ iscsilun->block_size / BDRV_SECTOR_SIZE ;
|
||
|
+
|
||
|
/* Medium changer or tape. We dont have any emulation for this so this must
|
||
|
* be sg ioctl compatible. We force it to be sg, otherwise qemu will try
|
||
|
* to read from the device to guess the image format.
|
||
|
@@ -1046,6 +932,9 @@ out:
|
||
|
if (iscsi_url != NULL) {
|
||
|
iscsi_destroy_url(iscsi_url);
|
||
|
}
|
||
|
+ if (task != NULL) {
|
||
|
+ scsi_free_scsi_task(task);
|
||
|
+ }
|
||
|
|
||
|
if (ret) {
|
||
|
if (iscsi != NULL) {
|
||
|
--
|
||
|
1.8.0.2
|
||
|
|