From 77d8e41be786e39653b0a2f8d6c7bb20023db450 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 1 Aug 2012 16:32:40 +1000 Subject: [PATCH] TESTS: Add a mechanism to temporarily disable the session reconnect Some tests may cause a target to drop the session. For these tests we DO want the test tool to detect that the command failed and later reconnect the session again when we proceed to the next subtest Signed-off-by: Ronnie Sahlberg --- include/iscsi-private.h | 3 ++ lib/connect.c | 55 ++++++++++++++++++++++++++++++++- lib/libiscsi.def | 1 + lib/libiscsi.syms | 1 + test-tool/0105_read10_invalid.c | 10 ++++++ test-tool/0122_read6_invalid.c | 8 +++++ 6 files changed, 77 insertions(+), 1 deletion(-) diff --git a/include/iscsi-private.h b/include/iscsi-private.h index d57d5a2..0fdd237 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -117,6 +117,8 @@ struct iscsi_context { int lun; const char *portal; + int no_auto_reconnect; + int reconnect_deferred; }; #define ISCSI_PDU_IMMEDIATE 0x40 @@ -271,6 +273,7 @@ unsigned long crc32c(char *buf, int len); struct scsi_task *iscsi_scsi_get_task_from_pdu(struct iscsi_pdu *pdu); int iscsi_reconnect(struct iscsi_context *iscsi); +void iscsi_set_noautoreconnect(struct iscsi_context *iscsi, int state); #ifdef __cplusplus } diff --git a/lib/connect.c b/lib/connect.c index b584ac2..8e39c40 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -145,9 +145,62 @@ iscsi_full_connect_async(struct iscsi_context *iscsi, const char *portal, return 0; } +/* Set auto reconnect status. If state !0 then we will not reconnect + automatically upon session failure. +*/ +void iscsi_set_noautoreconnect(struct iscsi_context *iscsi, int state) +{ + iscsi->no_auto_reconnect = state; + + /* If the session was dropped while auto reconnect was disabled + then we explicitely reconnect here again. + */ + if (!state && iscsi->reconnect_deferred) { + iscsi->reconnect_deferred = 0; + iscsi_reconnect(iscsi); + } +} + int iscsi_reconnect(struct iscsi_context *old_iscsi) { - struct iscsi_context *iscsi; + struct iscsi_context *iscsi = old_iscsi; + + /* This is mainly for tests, where we do not want to automatically + reconnect but rather want the commands to fail with an error + if the target drops the session. + */ + if (iscsi->no_auto_reconnect) { + struct iscsi_pdu *pdu; + + iscsi->reconnect_deferred = 1; + + while ((pdu = iscsi->outqueue)) { + SLIST_REMOVE(&iscsi->outqueue, pdu); + if ( !(pdu->flags & ISCSI_PDU_NO_CALLBACK)) { + /* If an error happened during connect/login, + we dont want to call any of the callbacks. + */ + if (iscsi->is_loggedin) { + pdu->callback(iscsi, SCSI_STATUS_CANCELLED, + NULL, pdu->private_data); + } + } + iscsi_free_pdu(iscsi, pdu); + } + while ((pdu = iscsi->waitpdu)) { + SLIST_REMOVE(&iscsi->waitpdu, pdu); + /* If an error happened during connect/login, + we dont want to call any of the callbacks. + */ + if (iscsi->is_loggedin) { + pdu->callback(iscsi, SCSI_STATUS_CANCELLED, + NULL, pdu->private_data); + } + iscsi_free_pdu(iscsi, pdu); + } + + return 0; + } try_again: diff --git a/lib/libiscsi.def b/lib/libiscsi.def index e9f400e..3e3ddab 100644 --- a/lib/libiscsi.def +++ b/lib/libiscsi.def @@ -46,6 +46,7 @@ iscsi_readcapacity10_task iscsi_readcapacity16_sync iscsi_readcapacity16_task iscsi_reconnect +iscsi_set_noautoreconnect iscsi_reportluns_sync iscsi_reportluns_task iscsi_scsi_cancel_all_tasks diff --git a/lib/libiscsi.syms b/lib/libiscsi.syms index c523c7e..1bb1719 100644 --- a/lib/libiscsi.syms +++ b/lib/libiscsi.syms @@ -44,6 +44,7 @@ iscsi_readcapacity10_task iscsi_readcapacity16_sync iscsi_readcapacity16_task iscsi_reconnect +iscsi_set_noautoreconnect iscsi_reportluns_sync iscsi_reportluns_task iscsi_scsi_cancel_all_tasks diff --git a/test-tool/0105_read10_invalid.c b/test-tool/0105_read10_invalid.c index f2ff2a9..bc49203 100644 --- a/test-tool/0105_read10_invalid.c +++ b/test-tool/0105_read10_invalid.c @@ -19,6 +19,7 @@ #include #include #include "iscsi.h" +#include "iscsi-private.h" #include "scsi-lowlevel.h" #include "iscsi-test.h" @@ -52,6 +53,7 @@ int T0105_read10_invalid(const char *initiator, const char *url, int data_loss _ ret = 0; + /* Try a read of 1 block but xferlength == 0 */ printf("Read10 1 block but with iscsi ExpectedDataTransferLength==0 ... "); @@ -69,6 +71,11 @@ int T0105_read10_invalid(const char *initiator, const char *url, int data_loss _ task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 0; + /* we dont want autoreconnect since some targets will drop the session + * on this condition. + */ + iscsi_set_noautoreconnect(iscsi, 1); + if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read10 command: %s\n", iscsi_get_error(iscsi)); @@ -95,6 +102,9 @@ int T0105_read10_invalid(const char *initiator, const char *url, int data_loss _ test2: + /* in case the previous test failed the session */ + iscsi_set_noautoreconnect(iscsi, 0); + /* Try a read of 1 block but xferlength == 1024 */ printf("Read10 1 block but with iscsi ExpectedDataTransferLength==1024 ... "); diff --git a/test-tool/0122_read6_invalid.c b/test-tool/0122_read6_invalid.c index 64ca63f..dfab56a 100644 --- a/test-tool/0122_read6_invalid.c +++ b/test-tool/0122_read6_invalid.c @@ -69,6 +69,11 @@ int T0122_read6_invalid(const char *initiator, const char *url, int data_loss _U task->xfer_dir = SCSI_XFER_READ; task->expxferlen = 0; + /* we dont want autoreconnect since some targets will drop the session + * on this condition. + */ + iscsi_set_noautoreconnect(iscsi, 1); + if (iscsi_scsi_command_sync(iscsi, lun, task, NULL) == NULL) { printf("[FAILED]\n"); printf("Failed to send read6 command: %s\n", iscsi_get_error(iscsi)); @@ -95,6 +100,9 @@ int T0122_read6_invalid(const char *initiator, const char *url, int data_loss _U test2: + /* in case the previous test failed the session */ + iscsi_set_noautoreconnect(iscsi, 0); + /* Try a read of 1 block but xferlength == 1024 */ printf("Read6 1 block but with iscsi ExpectedDataTransferLength==1024 ... ");