Loading drivers/scsi/ufs/ufs_test.c +174 −261 Original line number Diff line number Diff line Loading @@ -44,23 +44,44 @@ #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_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 { UFS_TEST_WRITE_READ_TEST, TEST_LONG_SEQUENTIAL_READ, TEST_LONG_SEQUENTIAL_WRITE, }; UFS_TEST_LONG_SEQUENTIAL_READ, UFS_TEST_LONG_SEQUENTIAL_WRITE, struct ufs_test_debug { 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; NUM_TESTS, }; struct ufs_test_data { /* Data structure for debugfs dentrys */ struct ufs_test_debug debug; struct dentry **test_list; /* * Data structure containing individual test information, including * self-defined specific data Loading @@ -70,8 +91,6 @@ struct ufs_test_data { struct blk_dev_test_type bdt; /* A wait queue for OPs to complete */ wait_queue_head_t wait_q; /* a flag for read compleation */ bool read_completed; /* a flag for write compleation */ bool write_completed; /* Loading @@ -79,13 +98,40 @@ struct ufs_test_data { * disabled and 2 BIOs are written. */ unsigned int random_test_seed; struct dentry *random_test_seed_dentry; /* A counter for the number of test requests completed */ unsigned int completed_req_count; }; 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) { Loading @@ -98,10 +144,10 @@ static char *ufs_test_get_test_case_str(struct test_data *td) case UFS_TEST_WRITE_READ_TEST: return "UFS write read test"; break; case TEST_LONG_SEQUENTIAL_READ: case UFS_TEST_LONG_SEQUENTIAL_READ: return "UFS long sequential read test"; break; case TEST_LONG_SEQUENTIAL_WRITE: case UFS_TEST_LONG_SEQUENTIAL_WRITE: return "UFS long sequential write test"; break; default: Loading Loading @@ -138,16 +184,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]; BUG_ON(!test_rq); test_rq->req_completed = 1; test_rq->req_result = err; test_pr_info("%s: request %d completed, err=%d", __func__, test_rq->req_id, err); test_rq->req_completed = 1; test_rq->req_result = err; utd->write_completed = true; 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) { struct request_queue *req_q = test_iosched_get_req_queue(); Loading Loading @@ -198,8 +281,8 @@ static int ufs_test_run_write_read_test(struct test_data *td) , __func__, num_bios, td->wr_rd_next_req_id); utd->write_completed = false; ret = test_iosched_add_wr_rd_test_req(0, WRITE, start_sec, num_bios, TEST_PATTERN_5A, ret = test_iosched_add_wr_rd_test_req(0, WRITE, start_sec, num_bios, TEST_PATTERN_5A, ufs_test_write_read_test_end_io_fn); if (ret) { Loading @@ -226,81 +309,14 @@ static int ufs_test_run_write_read_test(struct test_data *td) 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) { struct test_request *test_rq; struct test_data *ptd = test_get_test_data(); if (rq) if (rq) { test_rq = (struct test_request *)rq->elv.priv[0]; else { } else { test_pr_err("%s: error: NULL request", __func__); return; } Loading @@ -317,8 +333,9 @@ static void long_seq_test_free_end_io_fn(struct request *rq, int err) kfree(test_rq); utd->completed_req_count++; test_pr_err("%s: request %d completed, err=%d", __func__, test_rq->req_id, err); if (err) test_pr_err("%s: request %d completed, err=%d", __func__, test_rq->req_id, err); check_test_completion(); Loading @@ -335,7 +352,7 @@ static int run_long_seq_test(struct test_data *td) utd->completed_req_count = 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; else direction = WRITE; Loading Loading @@ -379,11 +396,13 @@ static int run_long_seq_test(struct test_data *td) return ret; } void long_seq_test_calc_throughput(unsigned long mtime, unsigned long byte_count) static int long_seq_test_calc_throughput(struct test_data *td) { 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", __func__, mtime, LONG_TEST_SIZE_INTEGER(byte_count), Loading @@ -401,168 +420,80 @@ void long_seq_test_calc_throughput(unsigned long mtime, test_pr_info("%s: Throughput: %lu.%lu MiB/sec\n", __func__, integer, fraction); } static ssize_t long_sequential_read_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 Read TEST --", __func__); sscanf(buf, "%d", &number); if (number <= 0) 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) static ssize_t ufs_test_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos, int test_case) { int ret = 0; int i = 0; int number = -1; unsigned long mtime, byte_count; test_pr_info("%s: -- UFS Long Sequential Write TEST --", __func__); int i; int number; sscanf(buf, "%d", &number); ret = kstrtoint_from_user(buf, count, 0, &number); if (ret < 0) { test_pr_err("%s: Error while reading test parameter value %d", __func__, ret); return ret; } 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_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.testcase = test_case; utd->test_info.get_rq_disk_fn = ufs_test_get_rq_disk; 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.testcase = TEST_LONG_SEQUENTIAL_WRITE; 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: ====================", __func__); utd->test_info.test_byte_count = 0; 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); if (ret) { test_pr_err("%s: Test failed, err=%d.", __func__, ret); return ret; } /* Allow FS requests to be dispatched */ msleep(1000); } return count; } static ssize_t long_sequential_write_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_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"); test_pr_info("%s: Completed all the ufs test iterations.", __func__); if (message_repeat == 1) { message_repeat = 0; return strnlen(buffer, count); } else return 0; return count; } const struct file_operations long_sequential_write_test_ops = { .open = test_open, .write = long_sequential_write_test_write, .read = long_sequential_write_test_read, }; TEST_OPS(write_read_test, WRITE_READ_TEST); TEST_OPS(long_sequential_read, LONG_SEQUENTIAL_READ); TEST_OPS(long_sequential_write, LONG_SEQUENTIAL_WRITE); static void ufs_test_debugfs_cleanup(void) { debugfs_remove_recursive(test_iosched_get_debugfs_tests_root()); kfree(utd->test_list); } static int ufs_test_debugfs_init(void) Loading @@ -573,59 +504,43 @@ static int ufs_test_debugfs_init(void) utils_root = test_iosched_get_debugfs_utils_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) { test_pr_err("%s: Failed to create debugfs root.", __func__); 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); if (!utd->debug.random_test_seed) { if (!utd->random_test_seed_dentry) { test_pr_err("%s: Could not create debugfs random_test_seed.", __func__); 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; } utd->debug.long_sequential_read_test = debugfs_create_file( "ufs_long_sequential_read_test", S_IRUGO | S_IWUGO, tests_root, NULL, &long_sequential_read_test_ops); if (!utd->debug.long_sequential_read_test) { ret = -ENOMEM; ret = add_test(utd, write_read_test, WRITE_READ_TEST); if (ret) goto exit_err; } utd->debug.long_sequential_write_test = debugfs_create_file( "ufs_long_sequential_write_test", S_IRUGO | S_IWUGO, tests_root, NULL, &long_sequential_write_test_ops); if (!utd->debug.long_sequential_write_test) { ret = -ENOMEM; ret = add_test(utd, long_sequential_read, LONG_SEQUENTIAL_READ); if (ret) goto exit_err; ret = add_test(utd, long_sequential_write, LONG_SEQUENTIAL_WRITE); if (ret) goto exit_err; } goto exit; exit_err: debugfs_remove_recursive(tests_root); ufs_test_debugfs_cleanup(); exit: return ret; } Loading Loading @@ -663,10 +578,8 @@ static void __exit ufs_test_exit(void) test_iosched_unregister(&utd->bdt); kfree(utd); } module_init(ufs_test_init) ; module_exit(ufs_test_exit) ; module_init(ufs_test_init); module_exit(ufs_test_exit); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("UFC test"); Loading Loading
drivers/scsi/ufs/ufs_test.c +174 −261 Original line number Diff line number Diff line Loading @@ -44,23 +44,44 @@ #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_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 { UFS_TEST_WRITE_READ_TEST, TEST_LONG_SEQUENTIAL_READ, TEST_LONG_SEQUENTIAL_WRITE, }; UFS_TEST_LONG_SEQUENTIAL_READ, UFS_TEST_LONG_SEQUENTIAL_WRITE, struct ufs_test_debug { 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; NUM_TESTS, }; struct ufs_test_data { /* Data structure for debugfs dentrys */ struct ufs_test_debug debug; struct dentry **test_list; /* * Data structure containing individual test information, including * self-defined specific data Loading @@ -70,8 +91,6 @@ struct ufs_test_data { struct blk_dev_test_type bdt; /* A wait queue for OPs to complete */ wait_queue_head_t wait_q; /* a flag for read compleation */ bool read_completed; /* a flag for write compleation */ bool write_completed; /* Loading @@ -79,13 +98,40 @@ struct ufs_test_data { * disabled and 2 BIOs are written. */ unsigned int random_test_seed; struct dentry *random_test_seed_dentry; /* A counter for the number of test requests completed */ unsigned int completed_req_count; }; 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) { Loading @@ -98,10 +144,10 @@ static char *ufs_test_get_test_case_str(struct test_data *td) case UFS_TEST_WRITE_READ_TEST: return "UFS write read test"; break; case TEST_LONG_SEQUENTIAL_READ: case UFS_TEST_LONG_SEQUENTIAL_READ: return "UFS long sequential read test"; break; case TEST_LONG_SEQUENTIAL_WRITE: case UFS_TEST_LONG_SEQUENTIAL_WRITE: return "UFS long sequential write test"; break; default: Loading Loading @@ -138,16 +184,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]; BUG_ON(!test_rq); test_rq->req_completed = 1; test_rq->req_result = err; test_pr_info("%s: request %d completed, err=%d", __func__, test_rq->req_id, err); test_rq->req_completed = 1; test_rq->req_result = err; utd->write_completed = true; 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) { struct request_queue *req_q = test_iosched_get_req_queue(); Loading Loading @@ -198,8 +281,8 @@ static int ufs_test_run_write_read_test(struct test_data *td) , __func__, num_bios, td->wr_rd_next_req_id); utd->write_completed = false; ret = test_iosched_add_wr_rd_test_req(0, WRITE, start_sec, num_bios, TEST_PATTERN_5A, ret = test_iosched_add_wr_rd_test_req(0, WRITE, start_sec, num_bios, TEST_PATTERN_5A, ufs_test_write_read_test_end_io_fn); if (ret) { Loading @@ -226,81 +309,14 @@ static int ufs_test_run_write_read_test(struct test_data *td) 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) { struct test_request *test_rq; struct test_data *ptd = test_get_test_data(); if (rq) if (rq) { test_rq = (struct test_request *)rq->elv.priv[0]; else { } else { test_pr_err("%s: error: NULL request", __func__); return; } Loading @@ -317,8 +333,9 @@ static void long_seq_test_free_end_io_fn(struct request *rq, int err) kfree(test_rq); utd->completed_req_count++; test_pr_err("%s: request %d completed, err=%d", __func__, test_rq->req_id, err); if (err) test_pr_err("%s: request %d completed, err=%d", __func__, test_rq->req_id, err); check_test_completion(); Loading @@ -335,7 +352,7 @@ static int run_long_seq_test(struct test_data *td) utd->completed_req_count = 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; else direction = WRITE; Loading Loading @@ -379,11 +396,13 @@ static int run_long_seq_test(struct test_data *td) return ret; } void long_seq_test_calc_throughput(unsigned long mtime, unsigned long byte_count) static int long_seq_test_calc_throughput(struct test_data *td) { 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", __func__, mtime, LONG_TEST_SIZE_INTEGER(byte_count), Loading @@ -401,168 +420,80 @@ void long_seq_test_calc_throughput(unsigned long mtime, test_pr_info("%s: Throughput: %lu.%lu MiB/sec\n", __func__, integer, fraction); } static ssize_t long_sequential_read_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 Read TEST --", __func__); sscanf(buf, "%d", &number); if (number <= 0) 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) static ssize_t ufs_test_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos, int test_case) { int ret = 0; int i = 0; int number = -1; unsigned long mtime, byte_count; test_pr_info("%s: -- UFS Long Sequential Write TEST --", __func__); int i; int number; sscanf(buf, "%d", &number); ret = kstrtoint_from_user(buf, count, 0, &number); if (ret < 0) { test_pr_err("%s: Error while reading test parameter value %d", __func__, ret); return ret; } 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_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.testcase = test_case; utd->test_info.get_rq_disk_fn = ufs_test_get_rq_disk; 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.testcase = TEST_LONG_SEQUENTIAL_WRITE; 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: ====================", __func__); utd->test_info.test_byte_count = 0; 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); if (ret) { test_pr_err("%s: Test failed, err=%d.", __func__, ret); return ret; } /* Allow FS requests to be dispatched */ msleep(1000); } return count; } static ssize_t long_sequential_write_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_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"); test_pr_info("%s: Completed all the ufs test iterations.", __func__); if (message_repeat == 1) { message_repeat = 0; return strnlen(buffer, count); } else return 0; return count; } const struct file_operations long_sequential_write_test_ops = { .open = test_open, .write = long_sequential_write_test_write, .read = long_sequential_write_test_read, }; TEST_OPS(write_read_test, WRITE_READ_TEST); TEST_OPS(long_sequential_read, LONG_SEQUENTIAL_READ); TEST_OPS(long_sequential_write, LONG_SEQUENTIAL_WRITE); static void ufs_test_debugfs_cleanup(void) { debugfs_remove_recursive(test_iosched_get_debugfs_tests_root()); kfree(utd->test_list); } static int ufs_test_debugfs_init(void) Loading @@ -573,59 +504,43 @@ static int ufs_test_debugfs_init(void) utils_root = test_iosched_get_debugfs_utils_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) { test_pr_err("%s: Failed to create debugfs root.", __func__); 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); if (!utd->debug.random_test_seed) { if (!utd->random_test_seed_dentry) { test_pr_err("%s: Could not create debugfs random_test_seed.", __func__); 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; } utd->debug.long_sequential_read_test = debugfs_create_file( "ufs_long_sequential_read_test", S_IRUGO | S_IWUGO, tests_root, NULL, &long_sequential_read_test_ops); if (!utd->debug.long_sequential_read_test) { ret = -ENOMEM; ret = add_test(utd, write_read_test, WRITE_READ_TEST); if (ret) goto exit_err; } utd->debug.long_sequential_write_test = debugfs_create_file( "ufs_long_sequential_write_test", S_IRUGO | S_IWUGO, tests_root, NULL, &long_sequential_write_test_ops); if (!utd->debug.long_sequential_write_test) { ret = -ENOMEM; ret = add_test(utd, long_sequential_read, LONG_SEQUENTIAL_READ); if (ret) goto exit_err; ret = add_test(utd, long_sequential_write, LONG_SEQUENTIAL_WRITE); if (ret) goto exit_err; } goto exit; exit_err: debugfs_remove_recursive(tests_root); ufs_test_debugfs_cleanup(); exit: return ret; } Loading Loading @@ -663,10 +578,8 @@ static void __exit ufs_test_exit(void) test_iosched_unregister(&utd->bdt); kfree(utd); } module_init(ufs_test_init) ; module_exit(ufs_test_exit) ; module_init(ufs_test_init); module_exit(ufs_test_exit); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("UFC test"); Loading