iscsi: correctly propagate errors in iscsi_open

Before:
    $ ./qemu-io-old
    qemu-io-old> open -r -o file.driver=iscsi,file.filename=foo
    Failed to parse URL : foo
    qemu-io-old: can't open device (null): Could not open 'foo': Invalid argument

After:
    $ ./qemu-io
    qemu-io> open -r -o file.driver=iscsi,file.filename=foo
    qemu-io: can't open device (null): Failed to parse URL : foo

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Paolo Bonzini 2014-02-17 14:43:53 +01:00 committed by Kevin Wolf
parent 35cb1748d5
commit f2917853f7
1 changed files with 53 additions and 50 deletions

View File

@ -856,7 +856,8 @@ retry:
#endif /* SCSI_SENSE_ASCQ_CAPACITY_DATA_HAS_CHANGED */ #endif /* SCSI_SENSE_ASCQ_CAPACITY_DATA_HAS_CHANGED */
static int parse_chap(struct iscsi_context *iscsi, const char *target) static void parse_chap(struct iscsi_context *iscsi, const char *target,
Error **errp)
{ {
QemuOptsList *list; QemuOptsList *list;
QemuOpts *opts; QemuOpts *opts;
@ -865,37 +866,35 @@ static int parse_chap(struct iscsi_context *iscsi, const char *target)
list = qemu_find_opts("iscsi"); list = qemu_find_opts("iscsi");
if (!list) { if (!list) {
return 0; return;
} }
opts = qemu_opts_find(list, target); opts = qemu_opts_find(list, target);
if (opts == NULL) { if (opts == NULL) {
opts = QTAILQ_FIRST(&list->head); opts = QTAILQ_FIRST(&list->head);
if (!opts) { if (!opts) {
return 0; return;
} }
} }
user = qemu_opt_get(opts, "user"); user = qemu_opt_get(opts, "user");
if (!user) { if (!user) {
return 0; return;
} }
password = qemu_opt_get(opts, "password"); password = qemu_opt_get(opts, "password");
if (!password) { if (!password) {
error_report("CHAP username specified but no password was given"); error_setg(errp, "CHAP username specified but no password was given");
return -1; return;
} }
if (iscsi_set_initiator_username_pwd(iscsi, user, password)) { if (iscsi_set_initiator_username_pwd(iscsi, user, password)) {
error_report("Failed to set initiator username and password"); error_setg(errp, "Failed to set initiator username and password");
return -1;
} }
return 0;
} }
static void parse_header_digest(struct iscsi_context *iscsi, const char *target) static void parse_header_digest(struct iscsi_context *iscsi, const char *target,
Error **errp)
{ {
QemuOptsList *list; QemuOptsList *list;
QemuOpts *opts; QemuOpts *opts;
@ -928,7 +927,7 @@ static void parse_header_digest(struct iscsi_context *iscsi, const char *target)
} else if (!strcmp(digest, "NONE-CRC32C")) { } else if (!strcmp(digest, "NONE-CRC32C")) {
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
} else { } else {
error_report("Invalid header-digest setting : %s", digest); error_setg(errp, "Invalid header-digest setting : %s", digest);
} }
} }
@ -986,12 +985,11 @@ static void iscsi_nop_timed_event(void *opaque)
} }
#endif #endif
static int iscsi_readcapacity_sync(IscsiLun *iscsilun) static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp)
{ {
struct scsi_task *task = NULL; struct scsi_task *task = NULL;
struct scsi_readcapacity10 *rc10 = NULL; struct scsi_readcapacity10 *rc10 = NULL;
struct scsi_readcapacity16 *rc16 = NULL; struct scsi_readcapacity16 *rc16 = NULL;
int ret = 0;
int retries = ISCSI_CMD_RETRIES; int retries = ISCSI_CMD_RETRIES;
do { do {
@ -1006,8 +1004,7 @@ static int iscsi_readcapacity_sync(IscsiLun *iscsilun)
if (task != NULL && task->status == SCSI_STATUS_GOOD) { if (task != NULL && task->status == SCSI_STATUS_GOOD) {
rc16 = scsi_datain_unmarshall(task); rc16 = scsi_datain_unmarshall(task);
if (rc16 == NULL) { if (rc16 == NULL) {
error_report("iSCSI: Failed to unmarshall readcapacity16 data."); error_setg(errp, "iSCSI: Failed to unmarshall readcapacity16 data.");
ret = -EINVAL;
} else { } else {
iscsilun->block_size = rc16->block_length; iscsilun->block_size = rc16->block_length;
iscsilun->num_blocks = rc16->returned_lba + 1; iscsilun->num_blocks = rc16->returned_lba + 1;
@ -1021,8 +1018,7 @@ static int iscsi_readcapacity_sync(IscsiLun *iscsilun)
if (task != NULL && task->status == SCSI_STATUS_GOOD) { if (task != NULL && task->status == SCSI_STATUS_GOOD) {
rc10 = scsi_datain_unmarshall(task); rc10 = scsi_datain_unmarshall(task);
if (rc10 == NULL) { if (rc10 == NULL) {
error_report("iSCSI: Failed to unmarshall readcapacity10 data."); error_setg(errp, "iSCSI: Failed to unmarshall readcapacity10 data.");
ret = -EINVAL;
} else { } else {
iscsilun->block_size = rc10->block_size; iscsilun->block_size = rc10->block_size;
if (rc10->lba == 0) { if (rc10->lba == 0) {
@ -1035,20 +1031,18 @@ static int iscsi_readcapacity_sync(IscsiLun *iscsilun)
} }
break; break;
default: default:
return 0; return;
} }
} while (task != NULL && task->status == SCSI_STATUS_CHECK_CONDITION } while (task != NULL && task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_UNIT_ATTENTION && task->sense.key == SCSI_SENSE_UNIT_ATTENTION
&& retries-- > 0); && retries-- > 0);
if (task == NULL || task->status != SCSI_STATUS_GOOD) { if (task == NULL || task->status != SCSI_STATUS_GOOD) {
error_report("iSCSI: failed to send readcapacity10 command."); error_setg(errp, "iSCSI: failed to send readcapacity10 command.");
ret = -EINVAL;
} }
if (task) { if (task) {
scsi_free_scsi_task(task); scsi_free_scsi_task(task);
} }
return ret;
} }
/* TODO Convert to fine grained options */ /* TODO Convert to fine grained options */
@ -1066,7 +1060,7 @@ static QemuOptsList runtime_opts = {
}; };
static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun, static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
int evpd, int pc) int evpd, int pc, Error **errp)
{ {
int full_size; int full_size;
struct scsi_task *task = NULL; struct scsi_task *task = NULL;
@ -1088,8 +1082,8 @@ static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
return task; return task;
fail: fail:
error_report("iSCSI: Inquiry command failed : %s", error_setg(errp, "iSCSI: Inquiry command failed : %s",
iscsi_get_error(iscsi)); iscsi_get_error(iscsi));
if (task) { if (task) {
scsi_free_scsi_task(task); scsi_free_scsi_task(task);
return NULL; return NULL;
@ -1120,27 +1114,25 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
int ret; int ret;
if ((BDRV_SECTOR_SIZE % 512) != 0) { if ((BDRV_SECTOR_SIZE % 512) != 0) {
error_report("iSCSI: Invalid BDRV_SECTOR_SIZE. " error_setg(errp, "iSCSI: Invalid BDRV_SECTOR_SIZE. "
"BDRV_SECTOR_SIZE(%lld) is not a multiple " "BDRV_SECTOR_SIZE(%lld) is not a multiple "
"of 512", BDRV_SECTOR_SIZE); "of 512", BDRV_SECTOR_SIZE);
return -EINVAL; return -EINVAL;
} }
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err); qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) { if (local_err) {
qerror_report_err(local_err); error_propagate(errp, local_err);
error_free(local_err);
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
filename = qemu_opt_get(opts, "filename"); filename = qemu_opt_get(opts, "filename");
iscsi_url = iscsi_parse_full_url(iscsi, filename); iscsi_url = iscsi_parse_full_url(iscsi, filename);
if (iscsi_url == NULL) { if (iscsi_url == NULL) {
error_report("Failed to parse URL : %s", filename); error_setg(errp, "Failed to parse URL : %s", filename);
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
@ -1151,13 +1143,13 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
iscsi = iscsi_create_context(initiator_name); iscsi = iscsi_create_context(initiator_name);
if (iscsi == NULL) { if (iscsi == NULL) {
error_report("iSCSI: Failed to create iSCSI context."); error_setg(errp, "iSCSI: Failed to create iSCSI context.");
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
if (iscsi_set_targetname(iscsi, iscsi_url->target)) { if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
error_report("iSCSI: Failed to set target name."); error_setg(errp, "iSCSI: Failed to set target name.");
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
@ -1166,21 +1158,22 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
ret = iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, ret = iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user,
iscsi_url->passwd); iscsi_url->passwd);
if (ret != 0) { if (ret != 0) {
error_report("Failed to set initiator username and password"); error_setg(errp, "Failed to set initiator username and password");
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
} }
/* check if we got CHAP username/password via the options */ /* check if we got CHAP username/password via the options */
if (parse_chap(iscsi, iscsi_url->target) != 0) { parse_chap(iscsi, iscsi_url->target, &local_err);
error_report("iSCSI: Failed to set CHAP user/password"); if (local_err != NULL) {
error_propagate(errp, local_err);
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) { if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) {
error_report("iSCSI: Failed to set session type to normal."); error_setg(errp, "iSCSI: Failed to set session type to normal.");
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
@ -1188,10 +1181,15 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
/* check if we got HEADER_DIGEST via the options */ /* check if we got HEADER_DIGEST via the options */
parse_header_digest(iscsi, iscsi_url->target); parse_header_digest(iscsi, iscsi_url->target, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
ret = -EINVAL;
goto out;
}
if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) { if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) {
error_report("iSCSI: Failed to connect to LUN : %s", error_setg(errp, "iSCSI: Failed to connect to LUN : %s",
iscsi_get_error(iscsi)); iscsi_get_error(iscsi));
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
@ -1203,14 +1201,14 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
task = iscsi_inquiry_sync(iscsi, iscsilun->lun, 0, 0, 36); task = iscsi_inquiry_sync(iscsi, iscsilun->lun, 0, 0, 36);
if (task == NULL || task->status != SCSI_STATUS_GOOD) { if (task == NULL || task->status != SCSI_STATUS_GOOD) {
error_report("iSCSI: failed to send inquiry command."); error_setg(errp, "iSCSI: failed to send inquiry command.");
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
inq = scsi_datain_unmarshall(task); inq = scsi_datain_unmarshall(task);
if (inq == NULL) { if (inq == NULL) {
error_report("iSCSI: Failed to unmarshall inquiry data."); error_setg(errp, "iSCSI: Failed to unmarshall inquiry data.");
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
@ -1218,7 +1216,9 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
iscsilun->type = inq->periperal_device_type; iscsilun->type = inq->periperal_device_type;
iscsilun->has_write_same = true; iscsilun->has_write_same = true;
if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) { iscsi_readcapacity_sync(iscsilun, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
goto out; goto out;
} }
bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun); bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun);
@ -1236,14 +1236,15 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
if (iscsilun->lbpme) { if (iscsilun->lbpme) {
struct scsi_inquiry_logical_block_provisioning *inq_lbp; struct scsi_inquiry_logical_block_provisioning *inq_lbp;
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1, task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING); SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING,
errp);
if (task == NULL) { if (task == NULL) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
inq_lbp = scsi_datain_unmarshall(task); inq_lbp = scsi_datain_unmarshall(task);
if (inq_lbp == NULL) { if (inq_lbp == NULL) {
error_report("iSCSI: failed to unmarshall inquiry datain blob"); error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
@ -1256,14 +1257,14 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
if (iscsilun->lbp.lbpu || iscsilun->lbp.lbpws) { if (iscsilun->lbp.lbpu || iscsilun->lbp.lbpws) {
struct scsi_inquiry_block_limits *inq_bl; struct scsi_inquiry_block_limits *inq_bl;
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1, task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1,
SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS); SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS, errp);
if (task == NULL) { if (task == NULL) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
inq_bl = scsi_datain_unmarshall(task); inq_bl = scsi_datain_unmarshall(task);
if (inq_bl == NULL) { if (inq_bl == NULL) {
error_report("iSCSI: failed to unmarshall inquiry datain blob"); error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob");
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
@ -1354,14 +1355,16 @@ static int iscsi_reopen_prepare(BDRVReopenState *state,
static int iscsi_truncate(BlockDriverState *bs, int64_t offset) static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
{ {
IscsiLun *iscsilun = bs->opaque; IscsiLun *iscsilun = bs->opaque;
int ret = 0; Error *local_err = NULL;
if (iscsilun->type != TYPE_DISK) { if (iscsilun->type != TYPE_DISK) {
return -ENOTSUP; return -ENOTSUP;
} }
if ((ret = iscsi_readcapacity_sync(iscsilun)) != 0) { iscsi_readcapacity_sync(iscsilun, &local_err);
return ret; if (local_err != NULL) {
error_free(local_err);
return -EIO;
} }
if (offset > iscsi_getlength(bs)) { if (offset > iscsi_getlength(bs)) {