scsi: ufs: rework unit test infrastructure
Upgrade the APIs used. Encapsulate test ops (read/write/open functions) and dentry creation in macros. Fix naming collisions with mmc tests. Change-Id: I5c48b369beaf902f8187ced9d884a2149a8644f0 Signed-off-by: Dolev Raviv <draviv@codeaurora.org>
This commit is contained in:
parent
29cfc516b3
commit
e6628ef0a2
1 changed files with 174 additions and 261 deletions
|
@ -46,23 +46,44 @@
|
||||||
#define test_pr_info(fmt, args...) pr_info("%s: "fmt"\n", MODULE_NAME, args)
|
#define test_pr_info(fmt, args...) pr_info("%s: "fmt"\n", MODULE_NAME, args)
|
||||||
#define test_pr_err(fmt, args...) pr_err("%s: "fmt"\n", MODULE_NAME, args)
|
#define test_pr_err(fmt, args...) pr_err("%s: "fmt"\n", MODULE_NAME, args)
|
||||||
|
|
||||||
|
#define TEST_OPS(test_name, upper_case_name) \
|
||||||
|
static int ufs_test_ ## test_name ## _show(struct seq_file *file, \
|
||||||
|
void *data) \
|
||||||
|
{ return ufs_test_show(file, UFS_TEST_ ## upper_case_name); } \
|
||||||
|
static int ufs_test_ ## test_name ## _open(struct inode *inode, \
|
||||||
|
struct file *file) \
|
||||||
|
{ return single_open(file, ufs_test_ ## test_name ## _show, \
|
||||||
|
inode->i_private); } \
|
||||||
|
static ssize_t ufs_test_ ## test_name ## _write(struct file *file, \
|
||||||
|
const char __user *buf, size_t count, loff_t *ppos) \
|
||||||
|
{ return ufs_test_write(file, buf, count, ppos, \
|
||||||
|
UFS_TEST_ ## upper_case_name); } \
|
||||||
|
const struct file_operations ufs_test_ ## test_name ## _ops = { \
|
||||||
|
.open = ufs_test_ ## test_name ## _open, \
|
||||||
|
.read = seq_read, \
|
||||||
|
.write = ufs_test_ ## test_name ## _write, \
|
||||||
|
};
|
||||||
|
|
||||||
|
#define add_test(utd, test_name, upper_case_name) \
|
||||||
|
ufs_test_add_test(utd, UFS_TEST_ ## upper_case_name, "ufs_test_"#test_name,\
|
||||||
|
&(ufs_test_ ## test_name ## _ops)); \
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum ufs_test_testcases {
|
enum ufs_test_testcases {
|
||||||
UFS_TEST_WRITE_READ_TEST,
|
UFS_TEST_WRITE_READ_TEST,
|
||||||
|
|
||||||
TEST_LONG_SEQUENTIAL_READ,
|
UFS_TEST_LONG_SEQUENTIAL_READ,
|
||||||
TEST_LONG_SEQUENTIAL_WRITE,
|
UFS_TEST_LONG_SEQUENTIAL_WRITE,
|
||||||
};
|
|
||||||
|
|
||||||
struct ufs_test_debug {
|
NUM_TESTS,
|
||||||
struct dentry *write_read_test; /* basic test */
|
|
||||||
struct dentry *random_test_seed; /* parameters in utils */
|
|
||||||
struct dentry *long_sequential_read_test;
|
|
||||||
struct dentry *long_sequential_write_test;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ufs_test_data {
|
struct ufs_test_data {
|
||||||
/* Data structure for debugfs dentrys */
|
/* Data structure for debugfs dentrys */
|
||||||
struct ufs_test_debug debug;
|
struct dentry **test_list;
|
||||||
/*
|
/*
|
||||||
* Data structure containing individual test information, including
|
* Data structure containing individual test information, including
|
||||||
* self-defined specific data
|
* self-defined specific data
|
||||||
|
@ -72,8 +93,6 @@ struct ufs_test_data {
|
||||||
struct blk_dev_test_type bdt;
|
struct blk_dev_test_type bdt;
|
||||||
/* A wait queue for OPs to complete */
|
/* A wait queue for OPs to complete */
|
||||||
wait_queue_head_t wait_q;
|
wait_queue_head_t wait_q;
|
||||||
/* a flag for read compleation */
|
|
||||||
bool read_completed;
|
|
||||||
/* a flag for write compleation */
|
/* a flag for write compleation */
|
||||||
bool write_completed;
|
bool write_completed;
|
||||||
/*
|
/*
|
||||||
|
@ -81,13 +100,40 @@ struct ufs_test_data {
|
||||||
* disabled and 2 BIOs are written.
|
* disabled and 2 BIOs are written.
|
||||||
*/
|
*/
|
||||||
unsigned int random_test_seed;
|
unsigned int random_test_seed;
|
||||||
|
struct dentry *random_test_seed_dentry;
|
||||||
|
|
||||||
/* A counter for the number of test requests completed */
|
/* A counter for the number of test requests completed */
|
||||||
unsigned int completed_req_count;
|
unsigned int completed_req_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ufs_test_data *utd;
|
static struct ufs_test_data *utd;
|
||||||
|
|
||||||
static bool message_repeat;
|
static int ufs_test_add_test(struct ufs_test_data *utd,
|
||||||
|
enum ufs_test_testcases test_id, char *test_str,
|
||||||
|
const struct file_operations *test_fops)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct dentry *tests_root;
|
||||||
|
|
||||||
|
if (test_id >= NUM_TESTS)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
tests_root = test_iosched_get_debugfs_tests_root();
|
||||||
|
if (!tests_root) {
|
||||||
|
test_pr_err("%s: Failed to create debugfs root.", __func__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
utd->test_list[test_id] = debugfs_create_file(test_str,
|
||||||
|
S_IRUGO | S_IWUGO, tests_root,
|
||||||
|
NULL, test_fops);
|
||||||
|
if (!utd->test_list[test_id]) {
|
||||||
|
test_pr_err("%s: Could not create the test %s", test_str,
|
||||||
|
__func__);
|
||||||
|
ret = -ENOMEM;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static char *ufs_test_get_test_case_str(struct test_data *td)
|
static char *ufs_test_get_test_case_str(struct test_data *td)
|
||||||
{
|
{
|
||||||
|
@ -100,10 +146,10 @@ static char *ufs_test_get_test_case_str(struct test_data *td)
|
||||||
case UFS_TEST_WRITE_READ_TEST:
|
case UFS_TEST_WRITE_READ_TEST:
|
||||||
return "UFS write read test";
|
return "UFS write read test";
|
||||||
break;
|
break;
|
||||||
case TEST_LONG_SEQUENTIAL_READ:
|
case UFS_TEST_LONG_SEQUENTIAL_READ:
|
||||||
return "UFS long sequential read test";
|
return "UFS long sequential read test";
|
||||||
break;
|
break;
|
||||||
case TEST_LONG_SEQUENTIAL_WRITE:
|
case UFS_TEST_LONG_SEQUENTIAL_WRITE:
|
||||||
return "UFS long sequential write test";
|
return "UFS long sequential write test";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -140,16 +186,53 @@ static void ufs_test_write_read_test_end_io_fn(struct request *rq, int err)
|
||||||
struct test_request *test_rq = (struct test_request *)rq->elv.priv[0];
|
struct test_request *test_rq = (struct test_request *)rq->elv.priv[0];
|
||||||
BUG_ON(!test_rq);
|
BUG_ON(!test_rq);
|
||||||
|
|
||||||
|
test_pr_info("%s: request %d completed, err=%d",
|
||||||
|
__func__, test_rq->req_id, err);
|
||||||
test_rq->req_completed = 1;
|
test_rq->req_completed = 1;
|
||||||
test_rq->req_result = err;
|
test_rq->req_result = err;
|
||||||
|
|
||||||
test_pr_info("%s: request %d completed, err=%d",
|
|
||||||
__func__, test_rq->req_id, err);
|
|
||||||
|
|
||||||
utd->write_completed = true;
|
utd->write_completed = true;
|
||||||
wake_up(&utd->wait_q);
|
wake_up(&utd->wait_q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ufs_test_show(struct seq_file *file, int test_case)
|
||||||
|
{
|
||||||
|
char *test_description;
|
||||||
|
|
||||||
|
switch (test_case) {
|
||||||
|
case UFS_TEST_WRITE_READ_TEST:
|
||||||
|
test_description = "\nufs_write_read_test\n"
|
||||||
|
"=========\n"
|
||||||
|
"Description:\n"
|
||||||
|
"This test write once a random block and than reads it to "
|
||||||
|
"verify its content. Used to debug first time transactions.\n";
|
||||||
|
break;
|
||||||
|
case UFS_TEST_LONG_SEQUENTIAL_READ:
|
||||||
|
test_description = "\nufs_long_sequential_read_test\n"
|
||||||
|
"=========\n"
|
||||||
|
"Description:\n"
|
||||||
|
"This test runs the following scenarios\n"
|
||||||
|
"- Long Sequential Read Test: this test measures read "
|
||||||
|
"throughput at the driver level by sequentially reading many "
|
||||||
|
"large requests.\n";
|
||||||
|
break;
|
||||||
|
case UFS_TEST_LONG_SEQUENTIAL_WRITE:
|
||||||
|
test_description = "\nufs_long_sequential_write_test\n"
|
||||||
|
"=========\n"
|
||||||
|
"Description:\n"
|
||||||
|
"This test runs the following scenarios\n"
|
||||||
|
"- Long Sequential Write Test: this test measures write "
|
||||||
|
"throughput at the driver level by sequentially writing many "
|
||||||
|
"large requests\n";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
test_description = "Unknown test";
|
||||||
|
}
|
||||||
|
|
||||||
|
seq_puts(file, test_description);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct gendisk *ufs_test_get_rq_disk(void)
|
static struct gendisk *ufs_test_get_rq_disk(void)
|
||||||
{
|
{
|
||||||
struct request_queue *req_q = test_iosched_get_req_queue();
|
struct request_queue *req_q = test_iosched_get_req_queue();
|
||||||
|
@ -200,8 +283,8 @@ static int ufs_test_run_write_read_test(struct test_data *td)
|
||||||
, __func__, num_bios, td->wr_rd_next_req_id);
|
, __func__, num_bios, td->wr_rd_next_req_id);
|
||||||
|
|
||||||
utd->write_completed = false;
|
utd->write_completed = false;
|
||||||
ret = test_iosched_add_wr_rd_test_req(0, WRITE, start_sec,
|
ret = test_iosched_add_wr_rd_test_req(0, WRITE, start_sec, num_bios,
|
||||||
num_bios, TEST_PATTERN_5A,
|
TEST_PATTERN_5A,
|
||||||
ufs_test_write_read_test_end_io_fn);
|
ufs_test_write_read_test_end_io_fn);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -228,81 +311,14 @@ static int ufs_test_run_write_read_test(struct test_data *td)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
int ufs_test_write_read_test_open_cb(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
file->private_data = inode->i_private;
|
|
||||||
message_repeat = 1;
|
|
||||||
test_pr_info("%s:UFS test initialized", __func__);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ufs_test_write_read_test_write_cb(struct file *file,
|
|
||||||
const char __user *buf,
|
|
||||||
size_t count, loff_t *ppos)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
int i;
|
|
||||||
int number;
|
|
||||||
|
|
||||||
sscanf(buf, "%d", &number);
|
|
||||||
|
|
||||||
if (number <= 0)
|
|
||||||
number = 1;
|
|
||||||
|
|
||||||
test_pr_info("%s:the test will run for %d iterations.",
|
|
||||||
__func__, number);
|
|
||||||
memset(&utd->test_info, 0, sizeof(struct test_info));
|
|
||||||
|
|
||||||
/* Initializing test */
|
|
||||||
utd->test_info.data = utd;
|
|
||||||
utd->test_info.get_test_case_str_fn = ufs_test_get_test_case_str;
|
|
||||||
utd->test_info.testcase = UFS_TEST_WRITE_READ_TEST;
|
|
||||||
utd->test_info.get_rq_disk_fn = ufs_test_get_rq_disk;
|
|
||||||
utd->test_info.run_test_fn = ufs_test_run_write_read_test;
|
|
||||||
|
|
||||||
/* Running the test multiple times */
|
|
||||||
for (i = 0; i < number; ++i) {
|
|
||||||
ret = test_iosched_start_test(&utd->test_info);
|
|
||||||
if (ret) {
|
|
||||||
test_pr_err("%s: Test failed.", __func__);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test_pr_info("%s: Completed all the ufs test iterations.", __func__);
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ufs_test_write_read_test_read_cb(struct file *file,
|
|
||||||
char __user *buffer, size_t count, loff_t *offset)
|
|
||||||
{
|
|
||||||
memset((void *) buffer, 0, count);
|
|
||||||
|
|
||||||
snprintf(buffer, count, "\nThis is a UFS write-read test for debug.\n");
|
|
||||||
|
|
||||||
if (message_repeat == 1) {
|
|
||||||
message_repeat = 0;
|
|
||||||
return strnlen(buffer, count);
|
|
||||||
} else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct file_operations write_read_test_ops = {
|
|
||||||
.open = ufs_test_write_read_test_open_cb,
|
|
||||||
.write = ufs_test_write_read_test_write_cb,
|
|
||||||
.read = ufs_test_write_read_test_read_cb,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void long_seq_test_free_end_io_fn(struct request *rq, int err)
|
static void long_seq_test_free_end_io_fn(struct request *rq, int err)
|
||||||
{
|
{
|
||||||
struct test_request *test_rq;
|
struct test_request *test_rq;
|
||||||
struct test_data *ptd = test_get_test_data();
|
struct test_data *ptd = test_get_test_data();
|
||||||
|
|
||||||
if (rq)
|
if (rq) {
|
||||||
test_rq = (struct test_request *)rq->elv.priv[0];
|
test_rq = (struct test_request *)rq->elv.priv[0];
|
||||||
else {
|
} else {
|
||||||
test_pr_err("%s: error: NULL request", __func__);
|
test_pr_err("%s: error: NULL request", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -319,8 +335,9 @@ static void long_seq_test_free_end_io_fn(struct request *rq, int err)
|
||||||
kfree(test_rq);
|
kfree(test_rq);
|
||||||
utd->completed_req_count++;
|
utd->completed_req_count++;
|
||||||
|
|
||||||
test_pr_err("%s: request %d completed, err=%d",
|
if (err)
|
||||||
__func__, test_rq->req_id, err);
|
test_pr_err("%s: request %d completed, err=%d", __func__,
|
||||||
|
test_rq->req_id, err);
|
||||||
|
|
||||||
check_test_completion();
|
check_test_completion();
|
||||||
|
|
||||||
|
@ -337,7 +354,7 @@ static int run_long_seq_test(struct test_data *td)
|
||||||
utd->completed_req_count = 0;
|
utd->completed_req_count = 0;
|
||||||
inserted_requests = 0;
|
inserted_requests = 0;
|
||||||
|
|
||||||
if (td->test_info.testcase == TEST_LONG_SEQUENTIAL_READ)
|
if (td->test_info.testcase == UFS_TEST_LONG_SEQUENTIAL_READ)
|
||||||
direction = READ;
|
direction = READ;
|
||||||
else
|
else
|
||||||
direction = WRITE;
|
direction = WRITE;
|
||||||
|
@ -381,11 +398,13 @@ static int run_long_seq_test(struct test_data *td)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int long_seq_test_calc_throughput(struct test_data *td)
|
||||||
void long_seq_test_calc_throughput(unsigned long mtime,
|
|
||||||
unsigned long byte_count)
|
|
||||||
{
|
{
|
||||||
unsigned long fraction, integer;
|
unsigned long fraction, integer;
|
||||||
|
unsigned long mtime, byte_count;
|
||||||
|
|
||||||
|
mtime = ktime_to_ms(utd->test_info.test_duration);
|
||||||
|
byte_count = utd->test_info.test_byte_count;
|
||||||
|
|
||||||
test_pr_info("%s: time is %lu msec, size is %lu.%lu MiB",
|
test_pr_info("%s: time is %lu msec, size is %lu.%lu MiB",
|
||||||
__func__, mtime, LONG_TEST_SIZE_INTEGER(byte_count),
|
__func__, mtime, LONG_TEST_SIZE_INTEGER(byte_count),
|
||||||
|
@ -403,168 +422,80 @@ void long_seq_test_calc_throughput(unsigned long mtime,
|
||||||
|
|
||||||
test_pr_info("%s: Throughput: %lu.%lu MiB/sec\n",
|
test_pr_info("%s: Throughput: %lu.%lu MiB/sec\n",
|
||||||
__func__, integer, fraction);
|
__func__, integer, fraction);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t long_sequential_read_test_write(struct file *file,
|
static ssize_t ufs_test_write(struct file *file, const char __user *buf,
|
||||||
const char __user *buf,
|
size_t count, loff_t *ppos, int test_case)
|
||||||
size_t count,
|
|
||||||
loff_t *ppos)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int i = 0;
|
int i;
|
||||||
int number = -1;
|
int number;
|
||||||
unsigned long mtime, byte_count;
|
|
||||||
|
|
||||||
test_pr_info("%s: -- UFS Long Sequential Read TEST --", __func__);
|
ret = kstrtoint_from_user(buf, count, 0, &number);
|
||||||
|
if (ret < 0) {
|
||||||
sscanf(buf, "%d", &number);
|
test_pr_err("%s: Error while reading test parameter value %d",
|
||||||
|
__func__, ret);
|
||||||
if (number <= 0)
|
return ret;
|
||||||
number = 1;
|
|
||||||
|
|
||||||
memset(&utd->test_info, 0, sizeof(struct test_info));
|
|
||||||
|
|
||||||
utd->test_info.data = utd;
|
|
||||||
utd->test_info.get_rq_disk_fn = ufs_test_get_rq_disk;
|
|
||||||
utd->test_info.run_test_fn = run_long_seq_test;
|
|
||||||
utd->test_info.get_test_case_str_fn = ufs_test_get_test_case_str;
|
|
||||||
utd->test_info.testcase = TEST_LONG_SEQUENTIAL_READ;
|
|
||||||
|
|
||||||
for (i = 0 ; i < number ; ++i) {
|
|
||||||
test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
|
|
||||||
test_pr_info("%s: ====================", __func__);
|
|
||||||
|
|
||||||
ret = test_iosched_start_test(&utd->test_info);
|
|
||||||
if (ret)
|
|
||||||
break;
|
|
||||||
|
|
||||||
mtime = ktime_to_ms(utd->test_info.test_duration);
|
|
||||||
byte_count = utd->test_info.test_byte_count;
|
|
||||||
|
|
||||||
long_seq_test_calc_throughput(mtime, byte_count);
|
|
||||||
|
|
||||||
/* Allow FS requests to be dispatched */
|
|
||||||
msleep(1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t long_sequential_read_test_read(struct file *file,
|
|
||||||
char __user *buffer,
|
|
||||||
size_t count,
|
|
||||||
loff_t *offset)
|
|
||||||
{
|
|
||||||
memset((void *)buffer, 0, count);
|
|
||||||
|
|
||||||
snprintf(buffer, count,
|
|
||||||
"\nufs_long_sequential_read_test\n"
|
|
||||||
"=========\n"
|
|
||||||
"Description:\n"
|
|
||||||
"This test runs the following scenarios\n"
|
|
||||||
"- Long Sequential Read Test: this test measures read "
|
|
||||||
"throughput at the driver level by sequentially reading many "
|
|
||||||
"large requests.\n");
|
|
||||||
|
|
||||||
if (message_repeat == 1) {
|
|
||||||
message_repeat = 0;
|
|
||||||
return strnlen(buffer, count);
|
|
||||||
} else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool message_repeat;
|
|
||||||
static int test_open(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
file->private_data = inode->i_private;
|
|
||||||
message_repeat = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct file_operations long_sequential_read_test_ops = {
|
|
||||||
.open = test_open,
|
|
||||||
.write = long_sequential_read_test_write,
|
|
||||||
.read = long_sequential_read_test_read,
|
|
||||||
};
|
|
||||||
|
|
||||||
static ssize_t long_sequential_write_test_write(struct file *file,
|
|
||||||
const char __user *buf,
|
|
||||||
size_t count,
|
|
||||||
loff_t *ppos)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
int i = 0;
|
|
||||||
int number = -1;
|
|
||||||
unsigned long mtime, byte_count;
|
|
||||||
|
|
||||||
test_pr_info("%s: -- UFS Long Sequential Write TEST --", __func__);
|
|
||||||
|
|
||||||
sscanf(buf, "%d", &number);
|
|
||||||
|
|
||||||
if (number <= 0)
|
if (number <= 0)
|
||||||
number = 1;
|
number = 1;
|
||||||
|
|
||||||
|
test_pr_info("%s:the test will run for %d iterations.",
|
||||||
|
__func__, number);
|
||||||
memset(&utd->test_info, 0, sizeof(struct test_info));
|
memset(&utd->test_info, 0, sizeof(struct test_info));
|
||||||
|
|
||||||
|
/* Initializing test */
|
||||||
utd->test_info.data = utd;
|
utd->test_info.data = utd;
|
||||||
utd->test_info.get_rq_disk_fn = ufs_test_get_rq_disk;
|
|
||||||
utd->test_info.get_test_case_str_fn = ufs_test_get_test_case_str;
|
utd->test_info.get_test_case_str_fn = ufs_test_get_test_case_str;
|
||||||
utd->test_info.run_test_fn = run_long_seq_test;
|
utd->test_info.testcase = test_case;
|
||||||
utd->test_info.testcase = TEST_LONG_SEQUENTIAL_WRITE;
|
utd->test_info.get_rq_disk_fn = ufs_test_get_rq_disk;
|
||||||
|
|
||||||
for (i = 0 ; i < number ; ++i) {
|
switch (test_case) {
|
||||||
|
case UFS_TEST_WRITE_READ_TEST:
|
||||||
|
utd->test_info.run_test_fn = ufs_test_run_write_read_test;
|
||||||
|
break;
|
||||||
|
case UFS_TEST_LONG_SEQUENTIAL_READ:
|
||||||
|
case UFS_TEST_LONG_SEQUENTIAL_WRITE:
|
||||||
|
utd->test_info.run_test_fn = run_long_seq_test;
|
||||||
|
utd->test_info.post_test_fn = long_seq_test_calc_throughput;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
test_pr_err("%s: Unknown test-case: %d", __func__, test_case);
|
||||||
|
WARN_ON(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Running the test multiple times */
|
||||||
|
for (i = 0; i < number; ++i) {
|
||||||
test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
|
test_pr_info("%s: Cycle # %d / %d", __func__, i+1, number);
|
||||||
test_pr_info("%s: ====================", __func__);
|
test_pr_info("%s: ====================", __func__);
|
||||||
|
|
||||||
utd->test_info.test_byte_count = 0;
|
utd->test_info.test_byte_count = 0;
|
||||||
ret = test_iosched_start_test(&utd->test_info);
|
ret = test_iosched_start_test(&utd->test_info);
|
||||||
if (ret)
|
if (ret) {
|
||||||
break;
|
test_pr_err("%s: Test failed, err=%d.", __func__, ret);
|
||||||
|
return ret;
|
||||||
mtime = ktime_to_ms(utd->test_info.test_duration);
|
}
|
||||||
byte_count = utd->test_info.test_byte_count;
|
|
||||||
|
|
||||||
long_seq_test_calc_throughput(mtime, byte_count);
|
|
||||||
|
|
||||||
/* Allow FS requests to be dispatched */
|
/* Allow FS requests to be dispatched */
|
||||||
msleep(1000);
|
msleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_pr_info("%s: Completed all the ufs test iterations.", __func__);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t long_sequential_write_test_read(struct file *file,
|
TEST_OPS(write_read_test, WRITE_READ_TEST);
|
||||||
char __user *buffer,
|
TEST_OPS(long_sequential_read, LONG_SEQUENTIAL_READ);
|
||||||
size_t count,
|
TEST_OPS(long_sequential_write, LONG_SEQUENTIAL_WRITE);
|
||||||
loff_t *offset)
|
|
||||||
{
|
|
||||||
memset((void *)buffer, 0, count);
|
|
||||||
|
|
||||||
snprintf(buffer, count,
|
|
||||||
"\nufs_long_sequential_write_test\n"
|
|
||||||
"=========\n"
|
|
||||||
"Description:\n"
|
|
||||||
"This test runs the following scenarios\n"
|
|
||||||
"- Long Sequential Write Test: this test measures write "
|
|
||||||
"throughput at the driver level by sequentially writing many "
|
|
||||||
"large requests\n");
|
|
||||||
|
|
||||||
if (message_repeat == 1) {
|
|
||||||
message_repeat = 0;
|
|
||||||
return strnlen(buffer, count);
|
|
||||||
} else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct file_operations long_sequential_write_test_ops = {
|
|
||||||
.open = test_open,
|
|
||||||
.write = long_sequential_write_test_write,
|
|
||||||
.read = long_sequential_write_test_read,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void ufs_test_debugfs_cleanup(void)
|
static void ufs_test_debugfs_cleanup(void)
|
||||||
{
|
{
|
||||||
debugfs_remove_recursive(test_iosched_get_debugfs_tests_root());
|
debugfs_remove_recursive(test_iosched_get_debugfs_tests_root());
|
||||||
|
kfree(utd->test_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ufs_test_debugfs_init(void)
|
static int ufs_test_debugfs_init(void)
|
||||||
|
@ -575,59 +506,43 @@ static int ufs_test_debugfs_init(void)
|
||||||
utils_root = test_iosched_get_debugfs_utils_root();
|
utils_root = test_iosched_get_debugfs_utils_root();
|
||||||
tests_root = test_iosched_get_debugfs_tests_root();
|
tests_root = test_iosched_get_debugfs_tests_root();
|
||||||
|
|
||||||
|
utd->test_list = kmalloc(sizeof(struct dentry *) * NUM_TESTS,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!utd->test_list) {
|
||||||
|
test_pr_err("%s: failed to allocate tests dentrys", __func__);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
if (!utils_root || !tests_root) {
|
if (!utils_root || !tests_root) {
|
||||||
test_pr_err("%s: Failed to create debugfs root.", __func__);
|
test_pr_err("%s: Failed to create debugfs root.", __func__);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto exit;
|
goto exit_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
utd->debug.random_test_seed = debugfs_create_u32("random_test_seed",
|
utd->random_test_seed_dentry = debugfs_create_u32("random_test_seed",
|
||||||
S_IRUGO | S_IWUGO, utils_root, &utd->random_test_seed);
|
S_IRUGO | S_IWUGO, utils_root, &utd->random_test_seed);
|
||||||
|
|
||||||
if (!utd->debug.random_test_seed) {
|
if (!utd->random_test_seed_dentry) {
|
||||||
test_pr_err("%s: Could not create debugfs random_test_seed.",
|
test_pr_err("%s: Could not create debugfs random_test_seed.",
|
||||||
__func__);
|
__func__);
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
utd->debug.write_read_test = debugfs_create_file("ufs_write_read_test",
|
|
||||||
S_IRUGO | S_IWUGO, tests_root,
|
|
||||||
NULL, &write_read_test_ops);
|
|
||||||
|
|
||||||
if (!utd->debug.write_read_test) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto exit_err;
|
goto exit_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
utd->debug.long_sequential_read_test = debugfs_create_file(
|
ret = add_test(utd, write_read_test, WRITE_READ_TEST);
|
||||||
"ufs_long_sequential_read_test",
|
if (ret)
|
||||||
S_IRUGO | S_IWUGO,
|
|
||||||
tests_root,
|
|
||||||
NULL,
|
|
||||||
&long_sequential_read_test_ops);
|
|
||||||
|
|
||||||
if (!utd->debug.long_sequential_read_test) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto exit_err;
|
goto exit_err;
|
||||||
}
|
ret = add_test(utd, long_sequential_read, LONG_SEQUENTIAL_READ);
|
||||||
|
if (ret)
|
||||||
utd->debug.long_sequential_write_test = debugfs_create_file(
|
goto exit_err;
|
||||||
"ufs_long_sequential_write_test",
|
ret = add_test(utd, long_sequential_write, LONG_SEQUENTIAL_WRITE);
|
||||||
S_IRUGO | S_IWUGO,
|
if (ret)
|
||||||
tests_root,
|
|
||||||
NULL,
|
|
||||||
&long_sequential_write_test_ops);
|
|
||||||
|
|
||||||
if (!utd->debug.long_sequential_write_test) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto exit_err;
|
goto exit_err;
|
||||||
}
|
|
||||||
|
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
exit_err:
|
exit_err:
|
||||||
debugfs_remove_recursive(tests_root);
|
ufs_test_debugfs_cleanup();
|
||||||
exit:
|
exit:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -665,10 +580,8 @@ static void __exit ufs_test_exit(void)
|
||||||
test_iosched_unregister(&utd->bdt);
|
test_iosched_unregister(&utd->bdt);
|
||||||
kfree(utd);
|
kfree(utd);
|
||||||
}
|
}
|
||||||
module_init(ufs_test_init)
|
module_init(ufs_test_init);
|
||||||
;
|
module_exit(ufs_test_exit);
|
||||||
module_exit(ufs_test_exit)
|
|
||||||
;
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
MODULE_DESCRIPTION("UFC test");
|
MODULE_DESCRIPTION("UFC test");
|
||||||
|
|
Loading…
Add table
Reference in a new issue