From efc556e2e960e0aaef7e866958f7ed9014e2ff17 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Tue, 27 Nov 2012 19:51:22 -0800 Subject: [PATCH] TESTS: Create a test that tries to overflow the maxcmdsn counter so that i/o from the initiator stops flowing and are just queued locally until teh cmdsn window opens up again. Send a lot of writes that block until we have processed the R2T back from the target and verify we can still make process when we have saturated the cmdsn window and are also blocked waiting for R2Ts. --- Makefile.am | 3 +- test-tool/1040_saturate_maxcmdsn.c | 135 +++++++++++++++++++++++++++++ test-tool/iscsi-test.c | 5 ++ test-tool/iscsi-test.h | 1 + 4 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 test-tool/1040_saturate_maxcmdsn.c diff --git a/Makefile.am b/Makefile.am index 5ef88d1..12ee18f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -147,7 +147,8 @@ bin_iscsi_test_SOURCES = test-tool/iscsi-test.c \ test-tool/1010_datasn_invalid.c \ test-tool/1020_bufferoffset_invalid.c \ test-tool/1030_unsolicited_data_overflow.c \ - test-tool/1031_unsolicited_data_out.c + test-tool/1031_unsolicited_data_out.c \ + test-tool/1040_saturate_maxcmdsn.c endif diff --git a/test-tool/1040_saturate_maxcmdsn.c b/test-tool/1040_saturate_maxcmdsn.c new file mode 100644 index 0000000..958b6be --- /dev/null +++ b/test-tool/1040_saturate_maxcmdsn.c @@ -0,0 +1,135 @@ +/* + Copyright (C) 2012 by Ronnie Sahlberg + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include +#include +#include "iscsi.h" +#include "iscsi-private.h" +#include "scsi-lowlevel.h" +#include "iscsi-test.h" + +static int num_cmds_in_flight; + +static void test_cb(struct iscsi_context *iscsi _U_, int status _U_, + void *command_data _U_, void *private_data) +{ + struct iscsi_async_state *state = private_data; + + if (--num_cmds_in_flight == 0) { + state->finished = 1; + } +} + + +int T1040_saturate_maxcmdsn(const char *initiator, const char *url, int data_loss, int show_info) +{ + struct iscsi_context *iscsi; + struct scsi_task *task; + struct scsi_readcapacity16 *rc16; + int i, ret, lun; + uint32_t block_size; + unsigned char data[4096 * 2]; + struct iscsi_async_state test_state; + + printf("1040_saturate_maxcmdsn:\n"); + printf("=======================\n"); + if (show_info) { + printf("Test sending so many commands we saturate maxcmdsn we do recover eventually\n"); + printf("1, Send 1024 commands in one go and make sure we eventually finish the queue of commands in flight\n"); + printf("\n"); + return 0; + } + + iscsi = iscsi_context_login(initiator, url, &lun); + if (iscsi == NULL) { + printf("Failed to login to target\n"); + return -1; + } + + /* find the size of the LUN */ + task = iscsi_readcapacity16_sync(iscsi, lun); + if (task == NULL) { + printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi)); + ret = -1; + goto finished; + } + if (task->status != SCSI_STATUS_GOOD) { + printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi)); + ret = -1; + scsi_free_scsi_task(task); + goto finished; + } + rc16 = scsi_datain_unmarshall(task); + if (rc16 == NULL) { + printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi)); + ret = -1; + scsi_free_scsi_task(task); + goto finished; + } + block_size = rc16->block_length; + scsi_free_scsi_task(task); + + + if (!data_loss) { + printf("--dataloss flag is not set. Skipping test\n"); + ret = -2; + goto finished; + } + + + ret = 0; + + iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_NO; + iscsi->target_max_recv_data_segment_length = block_size; + + printf("Send 1024 Writes each needing a R2T so that we saturate the maxcmdsn queue ... "); + /* we dont want autoreconnect since some targets will drop the + * on this condition. + */ + iscsi_set_noautoreconnect(iscsi, 1); + + for (i = 0; i < 1024; i++) { + num_cmds_in_flight++; + task = iscsi_write10_task(iscsi, lun, 0, data, 2 * block_size, block_size, + 0, 0, 0, 0, 0, + test_cb, &test_state); + if (task == NULL) { + printf("[FAILED]\n"); + printf("Failed to send WRITE10 command: %s\n", iscsi_get_error(iscsi)); + ret++; + goto test2; + } + } + test_state.task = task; + test_state.finished = 0; + test_state.status = 0; + wait_until_test_finished(iscsi, &test_state); + if (num_cmds_in_flight != 0) { + printf("[FAILED]\n"); + printf("Did not complete all I/O before deadline.\n"); + ret++; + goto test2; + } + printf("[OK]\n"); + + +test2: + +finished: + iscsi_destroy_context(iscsi); + return ret; +} diff --git a/test-tool/iscsi-test.c b/test-tool/iscsi-test.c index 29c8423..dee15bd 100644 --- a/test-tool/iscsi-test.c +++ b/test-tool/iscsi-test.c @@ -245,6 +245,11 @@ struct scsi_test tests[] = { { "T1030_unsolicited_data_overflow", T1030_unsolicited_data_overflow }, { "T1031_unsolicited_data_out", T1031_unsolicited_data_out }, +/* Test that if we start blocking new I/O due to saturating maxcmdsn + that we eventualld do recover and finish +*/ +{ "T1040_saturate_maxcmdsn", T1040_saturate_maxcmdsn }, + { NULL, NULL } }; diff --git a/test-tool/iscsi-test.h b/test-tool/iscsi-test.h index 3327280..41c401b 100644 --- a/test-tool/iscsi-test.h +++ b/test-tool/iscsi-test.h @@ -182,3 +182,4 @@ int T1010_datasn_invalid(const char *initiator, const char *url, int data_loss, int T1020_bufferoffset_invalid(const char *initiator, const char *url, int data_loss, int show_info); int T1030_unsolicited_data_overflow(const char *initiator, const char *url, int data_loss, int show_info); int T1031_unsolicited_data_out(const char *initiator, const char *url, int data_loss, int show_info); +int T1040_saturate_maxcmdsn(const char *initiator, const char *url, int data_loss, int show_info);