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.
This commit is contained in:
Ronnie Sahlberg
2012-11-27 19:51:22 -08:00
parent 22a8d221bf
commit efc556e2e9
4 changed files with 143 additions and 1 deletions

View File

@@ -0,0 +1,135 @@
/*
Copyright (C) 2012 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <arpa/inet.h>
#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;
}

View File

@@ -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 }
};

View File

@@ -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);