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:
parent
35cb1748d5
commit
f2917853f7
103
block/iscsi.c
103
block/iscsi.c
@ -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)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user