iscsi-test-cu: support multiple iSCSI URLs for multipath

Connect to each iSCSI URL provided, and confirm that they all correspond
to the same multipathed logical unit by using the previously added
mpath_check_matching_ids() helper.

Signed-off-by: David Disseldorp <ddiss@suse.de>
This commit is contained in:
David Disseldorp
2015-05-25 15:38:41 +02:00
parent a291c2b308
commit 024fe873e3

View File

@@ -26,6 +26,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
@@ -50,11 +51,12 @@
#include "iscsi-support.h"
#include "iscsi-test-cu.h"
#include "iscsi-support.h"
#include "iscsi-multipath.h"
#define PROG "iscsi-test-cu"
int loglevel = LOG_NORMAL;
struct scsi_device *sd;
struct scsi_device *sd = NULL; /* mp_sds[0] alias */
static unsigned int maxsectbytes;
/*
@@ -613,7 +615,7 @@ print_usage(void)
"Usage: %s [-?|--help] print this message and exit\n",
PROG);
fprintf(stderr,
"or %s [OPTIONS] <iscsi-url>\n", PROG);
"or %s [OPTIONS] <iscsi-url> [multipath-iscsi-url]\n", PROG);
fprintf(stderr,
"Where OPTIONS are from:\n");
fprintf(stderr,
@@ -683,13 +685,20 @@ test_teardown(void)
int
suite_init(void)
{
if (sd->iscsi_url) {
if (sd->iscsi_ctx) {
iscsi_logout_sync(sd->iscsi_ctx);
iscsi_destroy_context(sd->iscsi_ctx);
int i;
for (i = 0; i < mp_num_sds; i++) {
if (!mp_sds[i]->iscsi_url) {
continue;
}
sd->iscsi_ctx = iscsi_context_login(initiatorname1, sd->iscsi_url, &sd->iscsi_lun);
if (sd->iscsi_ctx == NULL) {
if (mp_sds[i]->iscsi_ctx) {
iscsi_logout_sync(mp_sds[i]->iscsi_ctx);
iscsi_destroy_context(mp_sds[i]->iscsi_ctx);
}
mp_sds[i]->iscsi_ctx = iscsi_context_login(initiatorname1,
mp_sds[i]->iscsi_url,
&mp_sds[i]->iscsi_lun);
if (mp_sds[i]->iscsi_ctx == NULL) {
fprintf(stderr,
"error: Failed to login to target for test set-up\n");
return 1;
@@ -705,15 +714,19 @@ suite_init(void)
int
suite_cleanup(void)
{
int i;
#ifndef HAVE_CU_SUITEINFO_PSETUPFUNC
/* libcunit version 1 */
test_teardown();
#endif
if (sd->iscsi_url) {
if (sd->iscsi_ctx) {
iscsi_logout_sync(sd->iscsi_ctx);
iscsi_destroy_context(sd->iscsi_ctx);
sd->iscsi_ctx = NULL;
for (i = 0; i < mp_num_sds; i++) {
if (mp_sds[i]->iscsi_url) {
if (mp_sds[i]->iscsi_ctx) {
iscsi_logout_sync(mp_sds[i]->iscsi_ctx);
iscsi_destroy_context(mp_sds[i]->iscsi_ctx);
mp_sds[i]->iscsi_ctx = NULL;
}
}
}
return 0;
@@ -933,7 +946,7 @@ static void free_scsi_device(struct scsi_device *sdev)
close(sdev->sgio_fd);
sdev->sgio_fd = -1;
}
free(sd);
free(sdev);
}
int
@@ -972,10 +985,7 @@ main(int argc, char *argv[])
};
int i, c;
int opt_idx = 0;
sd = malloc(sizeof(struct scsi_device));
memset(sd, '\0', sizeof(struct scsi_device));
sd->sgio_fd = -1;
bool got_sgio_dev = false;
while ((c = getopt_long(argc, argv, "?hli:I:t:sdgfAsSnvxV", long_opts,
&opt_idx)) > 0) {
@@ -1034,29 +1044,40 @@ main(int argc, char *argv[])
}
}
if (optind < argc) {
/* parse all trailing arguments as device paths */
mp_num_sds = 0;
while (optind < argc) {
if (mp_num_sds >= MPATH_MAX_DEVS) {
fprintf(stderr, "Too many multipath device URLs\n");
print_usage();
free(testname_re);
return 10;
}
mp_sds[mp_num_sds] = malloc(sizeof(struct scsi_device));
memset(mp_sds[mp_num_sds], '\0', sizeof(struct scsi_device));
mp_sds[mp_num_sds]->sgio_fd = -1;
if (!strncmp(argv[optind], "iscsi://", 8)) {
sd->iscsi_url = strdup(argv[optind++]);
mp_sds[mp_num_sds]->iscsi_url = strdup(argv[optind++]);
#ifdef HAVE_SG_IO
} else {
sd->sgio_dev = strdup(argv[optind++]);
mp_sds[mp_num_sds]->sgio_dev = strdup(argv[optind++]);
got_sgio_dev = true;
#endif
}
}
if (optind < argc) {
fprintf(stderr, "error: too many arguments\n");
print_usage();
return 1;
mp_num_sds++;
}
/* XXX why is this done? */
real_iscsi_queue_pdu = dlsym(RTLD_NEXT, "iscsi_queue_pdu");
if (sd->iscsi_url == NULL && sd->sgio_dev== NULL ) {
if ((mp_num_sds == 0) || (mp_sds[0]->iscsi_url == NULL
&& mp_sds[0]->sgio_dev == NULL)) {
#ifdef HAVE_SG_IO
fprintf(stderr, "You must specify either an iSCSI URL or a device file\n");
#else
fprintf(stderr, "You must specify either an iSCSI URL\n");
fprintf(stderr, "You must specify an iSCSI URL\n");
#endif
print_usage();
if (testname_re)
@@ -1064,10 +1085,32 @@ main(int argc, char *argv[])
return 10;
}
if (connect_scsi_device(sd, initiatorname1)) {
fprintf(stderr, "Failed to connect to SCSI device\n");
free_scsi_device(sd);
return -1;
if ((mp_num_sds > 1) && got_sgio_dev) {
fprintf(stderr, "Multipath devices must be iSCSI only\n");
print_usage();
free(testname_re);
return 10;
}
/* sd remains an alias for the first device */
sd = mp_sds[0];
for (i = 0; i < mp_num_sds; i++) {
res = connect_scsi_device(mp_sds[i], initiatorname1);
if (res < 0) {
fprintf(stderr,
"Failed to connect to SCSI device %d\n", i);
goto err_sds_free;
}
}
if (mp_num_sds > 1) {
/* check that all multipath sds identify as the same LU */
res = mpath_check_matching_ids(mp_num_sds, mp_sds);
if (res < 0) {
fprintf(stderr, "multipath devices don't match\n");
goto err_sds_free;
}
}
/*
@@ -1079,21 +1122,18 @@ main(int argc, char *argv[])
readcapacity10(sd, &task, 0, 0, EXPECT_STATUS_GOOD);
if (task == NULL) {
printf("Failed to send READCAPACITY10 command: %s\n", sd->error_str);
free_scsi_device(sd);
return -1;
goto err_sds_free;
}
if (task->status != SCSI_STATUS_GOOD) {
printf("READCAPACITY10 command: failed with sense. %s\n", sd->error_str);
scsi_free_scsi_task(task);
free_scsi_device(sd);
return -1;
goto err_sds_free;
}
rc10 = scsi_datain_unmarshall(task);
if (rc10 == NULL) {
printf("failed to unmarshall READCAPACITY10 data.\n");
scsi_free_scsi_task(task);
free_scsi_device(sd);
return -1;
goto err_sds_free;
}
block_size = rc10->block_size;
num_blocks = rc10->lba + 1;
@@ -1103,16 +1143,14 @@ main(int argc, char *argv[])
readcapacity16(sd, &rc16_task, 96, EXPECT_STATUS_GOOD);
if (rc16_task == NULL) {
printf("Failed to send READCAPACITY16 command: %s\n", sd->error_str);
free_scsi_device(sd);
return -1;
goto err_sds_free;
}
if (rc16_task->status == SCSI_STATUS_GOOD) {
rc16 = scsi_datain_unmarshall(rc16_task);
if (rc16 == NULL) {
printf("failed to unmarshall READCAPACITY16 data. %s\n", sd->error_str);
scsi_free_scsi_task(rc16_task);
free_scsi_device(sd);
return -1;
goto err_sds_free;
}
block_size = rc16->block_length;
num_blocks = rc16->returned_lba + 1;
@@ -1123,7 +1161,7 @@ main(int argc, char *argv[])
inquiry(sd, &inq_task, 0, 0, 64, EXPECT_STATUS_GOOD);
if (inq_task == NULL || inq_task->status != SCSI_STATUS_GOOD) {
printf("Inquiry command failed : %s\n", sd->error_str);
return -1;
goto err_sds_free;
}
full_size = scsi_datain_getfullsize(inq_task);
if (full_size > inq_task->datain.size) {
@@ -1134,14 +1172,14 @@ main(int argc, char *argv[])
inquiry(sd, &inq_task, 0, 0, full_size, EXPECT_STATUS_GOOD);
if (inq_task == NULL) {
printf("Inquiry command failed : %s\n", sd->error_str);
return -1;
goto err_sds_free;
}
}
inq = scsi_datain_unmarshall(inq_task);
if (inq == NULL) {
printf("failed to unmarshall inquiry datain blob\n");
scsi_free_scsi_task(inq_task);
return -1;
goto err_sds_free;
}
sbc3_support = 0;
@@ -1168,14 +1206,14 @@ main(int argc, char *argv[])
EXPECT_STATUS_GOOD);
if (inq_bl_task == NULL) {
printf("Inquiry command failed : %s\n", sd->error_str);
return -1;
goto err_sds_free;
}
}
inq_bl = scsi_datain_unmarshall(inq_bl_task);
if (inq_bl == NULL) {
printf("failed to unmarshall inquiry datain blob\n");
return -1;
goto err_sds_free;
}
}
@@ -1188,7 +1226,7 @@ main(int argc, char *argv[])
inq_bdc = scsi_datain_unmarshall(inq_bdc_task);
if (inq_bdc == NULL) {
printf("failed to unmarshall inquiry datain blob\n");
return -1;
goto err_sds_free;
}
}
@@ -1199,7 +1237,7 @@ main(int argc, char *argv[])
EXPECT_STATUS_GOOD);
if (inq_lbp_task == NULL || inq_lbp_task->status != SCSI_STATUS_GOOD) {
printf("Inquiry command failed : %s\n", sd->error_str);
return -1;
goto err_sds_free;
}
full_size = scsi_datain_getfullsize(inq_lbp_task);
if (full_size > inq_lbp_task->datain.size) {
@@ -1211,14 +1249,14 @@ main(int argc, char *argv[])
full_size, EXPECT_STATUS_GOOD);
if (inq_lbp_task == NULL) {
printf("Inquiry command failed : %s\n", sd->error_str);
return -1;
goto err_sds_free;
}
}
inq_lbp = scsi_datain_unmarshall(inq_lbp_task);
if (inq_lbp == NULL) {
printf("failed to unmarshall inquiry datain blob\n");
return -1;
goto err_sds_free;
}
}
@@ -1227,8 +1265,7 @@ main(int argc, char *argv[])
EXPECT_STATUS_GOOD);
if (rsop_task == NULL) {
printf("Failed to send REPORT_SUPPORTED_OPCODES command: %s\n", sd->error_str);
free_scsi_device(sd);
return -1;
goto err_sds_free;
}
if (rsop_task->status == SCSI_STATUS_GOOD) {
rsop = scsi_datain_unmarshall(rsop_task);
@@ -1244,8 +1281,7 @@ main(int argc, char *argv[])
EXPECT_STATUS_GOOD);
if (task == NULL) {
printf("Failed to send MODE_SENSE6 command: %s\n", sd->error_str);
free_scsi_device(sd);
return -1;
goto err_sds_free;
}
if (task->status == SCSI_STATUS_GOOD) {
struct scsi_mode_sense *ms;
@@ -1254,7 +1290,7 @@ main(int argc, char *argv[])
if (ms == NULL) {
printf("failed to unmarshall mode sense datain blob\n");
scsi_free_scsi_task(task);
return -1;
goto err_sds_free;
}
readonly = !!(ms->device_specific_parameter & 0x80);
}
@@ -1268,7 +1304,7 @@ main(int argc, char *argv[])
if (CU_initialize_registry() != 0) {
fprintf(stderr, "error: unable to initialize test registry\n");
return 1;
goto err_sds_free;
}
if (CU_is_test_running()) {
fprintf(stderr, "error: test suite(s) already running!?\n");
@@ -1315,7 +1351,15 @@ main(int argc, char *argv[])
if (rsop_task != NULL) {
scsi_free_scsi_task(rsop_task);
}
free_scsi_device(sd);
for (i = 0; i < mp_num_sds; i++) {
free_scsi_device(mp_sds[i]);
}
return 0;
err_sds_free:
for (i = 0; i < mp_num_sds; i++) {
free_scsi_device(mp_sds[i]);
}
return -1;
}