Previously we use "-iscsi id=target-iqn,user=foo,password=bar,..." to specify iscsi connection parameters, unfortunately it doesn't work with qemu-img.
This patch adds per drive options to iscsi driver so that at least qemu-img can use the "json:{...}" filename magic. Signed-off-by: Fam Zheng <f...@redhat.com> --- block/iscsi.c | 83 +++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 19 deletions(-) diff --git a/block/iscsi.c b/block/iscsi.c index 5002916..9efb9ec 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1011,7 +1011,9 @@ retry: return 0; } -static void parse_chap(struct iscsi_context *iscsi, const char *target, +static void parse_chap(struct iscsi_context *iscsi, + QemuOpts *img_opts, + const char *target, Error **errp) { QemuOptsList *list; @@ -1025,19 +1027,22 @@ static void parse_chap(struct iscsi_context *iscsi, const char *target, } opts = qemu_opts_find(list, target); - if (opts == NULL) { + if (!opts) { opts = QTAILQ_FIRST(&list->head); - if (!opts) { - return; - } } - user = qemu_opt_get(opts, "user"); + user = qemu_opt_get(img_opts, "user"); + if (!user && opts) { + user = qemu_opt_get(opts, "user"); + } if (!user) { return; } - password = qemu_opt_get(opts, "password"); + password = qemu_opt_get(img_opts, "password"); + if (!password && opts) { + password = qemu_opt_get(opts, "password"); + } if (!password) { error_setg(errp, "CHAP username specified but no password was given"); return; @@ -1048,13 +1053,20 @@ static void parse_chap(struct iscsi_context *iscsi, const char *target, } } -static void parse_header_digest(struct iscsi_context *iscsi, const char *target, +static void parse_header_digest(struct iscsi_context *iscsi, + QemuOpts *img_opts, + const char *target, Error **errp) { QemuOptsList *list; QemuOpts *opts; const char *digest = NULL; + digest = qemu_opt_get(img_opts, "header-digest"); + if (digest) { + goto found; + } + list = qemu_find_opts("iscsi"); if (!list) { return; @@ -1073,6 +1085,7 @@ static void parse_header_digest(struct iscsi_context *iscsi, const char *target, return; } +found: if (!strcmp(digest, "CRC32C")) { iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C); } else if (!strcmp(digest, "NONE")) { @@ -1086,7 +1099,7 @@ static void parse_header_digest(struct iscsi_context *iscsi, const char *target, } } -static char *parse_initiator_name(const char *target) +static char *parse_initiator_name(QemuOpts *img_opts, const char *target) { QemuOptsList *list; QemuOpts *opts; @@ -1094,6 +1107,11 @@ static char *parse_initiator_name(const char *target) char *iscsi_name; UuidInfo *uuid_info; + name = qemu_opt_get(img_opts, "initiator-name"); + if (name) { + return g_strdup(name); + } + list = qemu_find_opts("iscsi"); if (list) { opts = qemu_opts_find(list, target); @@ -1120,12 +1138,17 @@ static char *parse_initiator_name(const char *target) return iscsi_name; } -static int parse_timeout(const char *target) +static int parse_timeout(QemuOpts *img_opts, const char *target) { QemuOptsList *list; QemuOpts *opts; const char *timeout; + timeout = qemu_opt_get(img_opts, "iscsi"); + if (timeout) { + goto out; + } + list = qemu_find_opts("iscsi"); if (list) { opts = qemu_opts_find(list, target); @@ -1134,13 +1157,14 @@ static int parse_timeout(const char *target) } if (opts) { timeout = qemu_opt_get(opts, "timeout"); - if (timeout) { - return atoi(timeout); - } } } - - return 0; +out: + if (timeout) { + return atoi(timeout); + } else { + return 0; + } } static void iscsi_nop_timed_event(void *opaque) @@ -1229,6 +1253,27 @@ static QemuOptsList runtime_opts = { .name = "filename", .type = QEMU_OPT_STRING, .help = "URL to the iscsi image", + },{ + .name = "user", + .type = QEMU_OPT_STRING, + .help = "username for CHAP authentication to target", + },{ + .name = "password", + .type = QEMU_OPT_STRING, + .help = "password for CHAP authentication to target", + },{ + .name = "header-digest", + .type = QEMU_OPT_STRING, + .help = "HeaderDigest setting. " + "{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}", + },{ + .name = "initiator-name", + .type = QEMU_OPT_STRING, + .help = "Initiator iqn name to use when connecting", + },{ + .name = "timeout", + .type = QEMU_OPT_NUMBER, + .help = "Request timeout in seconds (default 0 = no timeout)", }, { /* end of list */ } }, @@ -1390,7 +1435,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, memset(iscsilun, 0, sizeof(IscsiLun)); - initiator_name = parse_initiator_name(iscsi_url->target); + initiator_name = parse_initiator_name(opts, iscsi_url->target); iscsi = iscsi_create_context(initiator_name); if (iscsi == NULL) { @@ -1416,7 +1461,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, } /* check if we got CHAP username/password via the options */ - parse_chap(iscsi, iscsi_url->target, &local_err); + parse_chap(iscsi, opts, iscsi_url->target, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); ret = -EINVAL; @@ -1432,7 +1477,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); /* check if we got HEADER_DIGEST via the options */ - parse_header_digest(iscsi, iscsi_url->target, &local_err); + parse_header_digest(iscsi, opts, iscsi_url->target, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); ret = -EINVAL; @@ -1440,7 +1485,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, } /* timeout handling is broken in libiscsi before 1.15.0 */ - timeout = parse_timeout(iscsi_url->target); + timeout = parse_timeout(opts, iscsi_url->target); #if defined(LIBISCSI_API_VERSION) && LIBISCSI_API_VERSION >= 20150621 iscsi_set_timeout(iscsi, timeout); #else -- 2.5.0