New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve WriteResidual tests #345
Improve WriteResidual tests #345
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was thoroughly reviewed internally and tested with the changes to be sent upstream by @nastya-nizharadze: https://github.com/roolebo/linux/commits/target-write-residuals-v1-feedback
test-tool/test_write10_residuals.c
Outdated
@@ -75,11 +75,15 @@ test_write10_residuals(void) | |||
return; | |||
} | |||
logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); | |||
if (task->status != SCSI_STATUS_GOOD) { | |||
ok = task->status == SCSI_STATUS_GOOD || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please introduce a function or macro instead of repeating this comparison multiple times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @bvanassche,
It is a good practice to separate a refactoring and a changes for the more convenient review. All repetitions are removed in the next commit. Even if I introduce a function or a macro, it will be removed by the next commit. However, if you think that it is really better to remove the duplication in this commit, please tell me and I will do it.
Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a good practice not to introduce repetitive code. Please introduce a helper function in this commit that returns the result of the following expression:
task->status == SCSI_STATUS_GOOD ||
 (task->status == SCSI_STATUS_CHECK_CONDITION &&
 task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
 task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_FIELD_IN_INFORMATION_UNIT
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
1112923
to
a2fa59b
Compare
Hi @bvanassche, Our patches have been added to the 5.12/scsi-staging Now TCM send ASCQ = 0x03, INVALID FIELD IN COMMAND INFORMATION UNIT for residual write case. Could you please tell me whether it is really necessary to make the previously requested changes? Thanks! |
test-tool/test_write_residuals.h
Outdated
unsigned int residuals_kind; | ||
size_t residuals_amount; | ||
bool check_overwrite; | ||
const char log_messages[100]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please change the type of the log message from const char [100] into const char* to reduce the space occupied by this data structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
const char log_messages[100]; | ||
}; | ||
|
||
extern bool command_is_implemented; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the purpose of this global variable? Since it is set but not used, can it be removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This variable is needed because if the command is not implemented, testing should end. It is used in test_write10_residuals.c, test_write12_residuals.c and test_write12_residuals.c
if (!command_is_implemented) {
CU_PASS("WRITE10 is not implemented.");
return;
}
test-tool/test_write_residuals.h
Outdated
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <stdbool.h> | ||
|
||
#include <CUnit/CUnit.h> | ||
|
||
#include "iscsi.h" | ||
#include "iscsi-private.h" | ||
#include "scsi-lowlevel.h" | ||
#include "iscsi-test-cu.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove all include directives except #include <stddef.h> (for size_t).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
int ok; | ||
unsigned int i; | ||
/* testing scenarios */ | ||
const struct residuals_test_data write10_residuals[] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please change 'const' into 'static const'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am using block_size
variable to initialize this structure. Therefore I can not make it static.
int ok; | ||
unsigned int i; | ||
/* testing scenarios */ | ||
const struct residuals_test_data write12_residuals[] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here and in the other source files: please change 'const' into 'static const'.
test-tool/test_write_residuals.c
Outdated
|
||
if (scsi_status != SCSI_STATUS_GOOD) { | ||
logging(LOG_VERBOSE, "Verify that blocks were NOT " | ||
"overwritten and still contains 'a'"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
contains -> contain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
include/iscsi-private.h
Outdated
@@ -40,6 +40,9 @@ extern "C" { | |||
#ifndef ARRAY_SIZE | |||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | |||
#endif | |||
#ifndef DIV_ROUND_UP | |||
#define DIV_ROUND_UP(x, y) (((x) + ((y) - 1)) / (y)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are more parentheses in this expression than necessary. I think that ((y) - 1) can be changed into (y) - 1 without changing the result of this expression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
test-tool/test_write10_residuals.c
Outdated
@@ -75,11 +75,15 @@ test_write10_residuals(void) | |||
return; | |||
} | |||
logging(LOG_VERBOSE, "Verify that the target returned SUCCESS"); | |||
if (task->status != SCSI_STATUS_GOOD) { | |||
ok = task->status == SCSI_STATUS_GOOD || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a good practice not to introduce repetitive code. Please introduce a helper function in this commit that returns the result of the following expression:
task->status == SCSI_STATUS_GOOD ||
 (task->status == SCSI_STATUS_CHECK_CONDITION &&
 task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST &&
 task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_FIELD_IN_INFORMATION_UNIT
According to the RFC 7143 11.4.5.1: "Targets may set the residual count,and initiators may use it when the response code is Command Completed at Target (even if the status returned is not GOOD)." Therefore valid retuned status may be not only GOOD. Also this check: task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_FIELD_IN_INFORMATION_UNIT would make Underflow/Overflow response universal for FC/ISCSI.
test-tool/test_write_residuals.c
Outdated
memset(scratch, 'b', (tdata->xfer_len * tdata->buf_len)); | ||
memset(scratch, 'b', tdata->buf_len); | ||
} else { | ||
memset(scratch, 0xa6, (tdata->xfer_len * tdata->buf_len)); | ||
memset(scratch, 0xa6, tdata->buf_len); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these changes perhaps a bug fix for the previous patch in this series? If so, please move these into the previous patch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
test-tool/test_write_residuals.h
Outdated
size_t cdb_size; | ||
unsigned int xfer_len; | ||
unsigned int buf_len; | ||
unsigned int residuals_kind; | ||
size_t residuals_amount; | ||
bool check_overwrite; | ||
const char *log_messages; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please document the meaning of each member of this data structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Looking at test_write10_residuals.c, test_write12_residuals.c and test_write16_residuals.c tests the similarity of the testing scenario can be found. There are several EDTL and SPDTL combinations which are the same for different length write command tests. They form the core of testing scenario of these commands. There aren't so much differences in the way of testing these combinations itself either. It is possible to move the main parameters describing the testing scenario into a separate structure and move the scenario itself into a separate function. It will increase the readability and reduce the duplicate code of these tests.
…FCP-4 According to FCP-4 there are several possibilities for target to react on incorrect data length field value in CDB: a) process the command normally except that data beyond the FCP_DL count shall not be requested or transferred; b) transfer no data and return CHECK CONDITION status with the sense key set to ILLEGAL REQUEST and the additional sense code set to INVALID FIELD IN COMMAND INFORMATION UNIT; Add check to support the second one and accept no data write.
Check if the residual data does not owerwrite existing data blocks has now been added for all testing data to improve the uniformity of test runs, increase test readability and remove the duplicate testing data records.
Thanks! |
Linux target implementation, TCM, doesn’t pass write residuals tests (Write10Residuals, Write12Residualds, Write16Residuals).
One of the reason why they fail is because TCM doesn’t complete writes that have residuals with GOOD status, instead it replies with CHECK CONDITION and INVALID FIELD IN CDB sense code. The sense code doesn’t seem to be a valid reply but it's legit for a target to reply with CHECK CONDITION as outlined in the discussion on T10, RFC 7143 (11.4.5.1. Field Semantics):
and FCP-4 (9.4.2 FCP_DATA IUs for read and write operations):
To allow different replies from different targets, b) from FCP-4 was added as an alternative valid reply. With the PR, libiscsi supports both GOOD and CHECK CONDITION with INVALID FIELD IN COMMAND INFORMATION UNIT.
The tests have also been refactored to make sure that no transfer happens if target replies with INVALID FIELD IN COMMAND INFORMATION UNIT. As a side effect of the refactoring, most of the code duplication was removed.
After refactoring, it turned out that some test cases duplicate each other, so they were removed.
As soon as I send patches in TCM to fix sense key I will attach the link to it here.