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 ... ");