summaryrefslogtreecommitdiff
path: root/include/linux/test-iosched.h
blob: 8036d4b682feefb7efa741af1b3bdd6d50b9337a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * 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.
 *
 * The test scheduler allows to test the block device by dispatching
 * specific requests according to the test case and declare PASS/FAIL
 * according to the requests completion error code.
 * Each test is exposed via debugfs and can be triggered by writing to
 * the debugfs file.
 *
 */

#ifndef _LINUX_TEST_IOSCHED_H
#define _LINUX_TEST_IOSCHED_H

/*
 * Patterns definitions for read/write requests data
 */
#define TEST_PATTERN_SEQUENTIAL	-1
#define TEST_PATTERN_5A		0x5A5A5A5A
#define TEST_PATTERN_FF		0xFFFFFFFF
#define TEST_NO_PATTERN		0xDEADBEEF
#define BIO_U32_SIZE 1024
#define TEST_BIO_SIZE		PAGE_SIZE	/* use one page bios */

struct test_iosched;

typedef int (prepare_test_fn) (struct test_iosched *);
typedef int (run_test_fn) (struct test_iosched *);
typedef int (check_test_result_fn) (struct test_iosched *);
typedef int (post_test_fn) (struct test_iosched *);
typedef char* (get_test_case_str_fn) (int);
typedef int (blk_dev_test_init_fn) (struct test_iosched *);
typedef void (blk_dev_test_exit_fn) (struct test_iosched *);
typedef struct gendisk* (get_rq_disk_fn) (struct test_iosched *);
typedef bool (check_test_completion_fn) (struct test_iosched *);

/**
 * enum test_state - defines the state of the test
 */
enum test_state {
	TEST_IDLE,
	TEST_RUNNING,
	TEST_COMPLETED,
};

/**
 * enum test_results - defines the success orfailure of the test
 */
enum test_results {
	TEST_NO_RESULT,
	TEST_FAILED,
	TEST_PASSED,
	TEST_NOT_SUPPORTED,
};

/**
 * enum req_unique_type - defines a unique request type
 */
enum req_unique_type {
	REQ_UNIQUE_NONE,
	REQ_UNIQUE_DISCARD,
	REQ_UNIQUE_FLUSH,
};

/**
 * struct test_debug - debugfs directories
 * @debug_root:		The test-iosched debugfs root directory
 * @debug_utils_root:	test-iosched debugfs utils root
 *			directory
 * @debug_tests_root:	test-iosched debugfs tests root
 *			directory
 * @debug_test_result:	Exposes the test result to the user
 *			space
 * @start_sector:	The start sector for read/write requests
 */
struct test_debug {
	struct dentry *debug_root;
	struct dentry *debug_utils_root;
	struct dentry *debug_tests_root;
	struct dentry *debug_test_result;
	struct dentry *start_sector;
};

/**
 * struct test_request - defines a test request
 * @queuelist:		The test requests list
 * @bios_buffer:	Write/read requests data buffer
 * @buf_size:		Write/read requests data buffer size (in
 *			bytes)
 * @rq:			A block request, to be dispatched
 * @req_completed:	A flag to indicate if the request was
 *			completed
 * @req_result:		Keeps the error code received in the
 *			request completion callback
 * @is_err_expected:	A flag to indicate if the request should
 *			fail
 * @wr_rd_data_pattern:	A pattern written to the write data
 *			buffer. Can be used in read requests to
 *			verify the data
 * @req_id:		A unique ID to identify a test request
 *			to ease the debugging of the test cases
 */
struct test_request {
	struct list_head queuelist;
	unsigned int *bios_buffer;
	int buf_size;
	struct request *rq;
	bool req_completed;
	int req_result;
	int is_err_expected;
	int wr_rd_data_pattern;
	int req_id;
};

/**
 * struct test_info - specific test information
 * @testcase:		The current running test case
 * @timeout_msec:	Test specific test timeout
 * @buf_size:		Write/read requests data buffer size (in
 *			bytes)
 * @prepare_test_fn:	Test specific test preparation callback
 * @run_test_fn:	Test specific test running callback
 * @check_test_result_fn: Test specific test result checking
 *			callback
 * @get_test_case_str_fn: Test specific function to get the test name
 * @test_duration:	A ktime value saved for timing
 *			calculations
 * @data:		Test specific private data
 * @test_byte_count:	Total number of bytes dispatched in
 *			the test
 */
struct test_info {
	int testcase;
	unsigned timeout_msec;
	prepare_test_fn *prepare_test_fn;
	run_test_fn *run_test_fn;
	check_test_result_fn *check_test_result_fn;
	post_test_fn *post_test_fn;
	get_test_case_str_fn *get_test_case_str_fn;
	ktime_t test_duration;
	get_rq_disk_fn *get_rq_disk_fn;
	check_test_completion_fn *check_test_completion_fn;
	void *data;
	unsigned long test_byte_count;
};

/**
 * struct blk_dev_test_type - identifies block device test
 * @list:		list head pointer
 * @type_prefix:	prefix of device class name, i.e. "mmc"/ "sd"
 * @init_fn:		block device test init callback
 * @exit_fn:		block device test exit callback
 */
struct blk_dev_test_type {
	struct list_head list;
	const char *type_prefix;
	blk_dev_test_init_fn *init_fn;
	blk_dev_test_exit_fn *exit_fn;
};

/**
 * struct test_data - global test iosched data
 * @queue:		The test IO scheduler requests list
 * @test_queue:		The test requests list
 * @dispatched_queue:   The queue contains requests dispatched
 *			from @test_queue
 * @reinsert_queue:     The queue contains reinserted from underlying
 *			driver requests
 * @urgent_queue:       The queue contains requests for urgent delivery
 *			These requests will be delivered before @test_queue
 *			and @reinsert_queue requests
 * @test_count:         Number of requests in the @test_queue
 * @dispatched_count:   Number of requests in the @dispatched_queue
 * @reinsert_count:     Number of requests in the @reinsert_queue
 * @urgent_count:       Number of requests in the @urgent_queue
 * @wait_q:		A wait queue for waiting for the test
 *			requests completion
 * @test_state:		Indicates if there is a running test.
 *			Used for dispatch function
 * @test_result:	Indicates if the test passed or failed
 * @debug:		The test debugfs entries
 * @req_q:		The block layer request queue
 * @num_of_write_bios:	The number of write BIOs added to the test requests.
 *			Used to calcualte the sector number of
 *			new BIOs.
 * @start_sector:	The address of the first sector that can
 *			be accessed by the test
 * @wr_rd_next_req_id:	A unique ID to identify WRITE/READ
 *			request to ease the debugging of the
 *			test cases
 * @unique_next_req_id:	A unique ID to identify
 *			FLUSH/DISCARD/SANITIZE request to ease
 *			the debugging of the test cases
 * @lock:		A lock to verify running a single test
 *			at a time
 * @test_info:		A specific test data to be set by the
 *			test invokation function
 * @ignore_round:	A boolean variable indicating that a
 *			test round was disturbed by an external
 *			flush request, therefore disqualifying
 *			the results
 * @blk_dev_test_data:	associated specific block device test utility
 */
struct test_iosched {
	struct list_head queue;
	struct list_head test_queue;
	struct list_head dispatched_queue;
	struct list_head reinsert_queue;
	struct list_head urgent_queue;
	unsigned int  test_count;
	unsigned int  dispatched_count;
	unsigned int  reinsert_count;
	unsigned int  urgent_count;
	wait_queue_head_t wait_q;
	enum test_state test_state;
	enum test_results test_result;
	struct test_debug debug;
	struct request_queue *req_q;
	int num_of_write_bios;
	u32 start_sector;
	int wr_rd_next_req_id;
	int unique_next_req_id;
	spinlock_t lock;
	struct test_info test_info;
	bool fs_wr_reqs_during_test;
	bool ignore_round;
	bool notified_urgent;
	void *blk_dev_test_data;
};

extern int test_iosched_start_test(struct test_iosched *,
	struct test_info *t_info);
extern void test_iosched_mark_test_completion(struct test_iosched *);
extern void check_test_completion(struct test_iosched *);
extern int test_iosched_add_unique_test_req(struct test_iosched *,
	int is_err_expcted, enum req_unique_type req_unique,
	int start_sec, int nr_sects, rq_end_io_fn *end_req_io);
extern int test_iosched_add_wr_rd_test_req(struct test_iosched *,
	int is_err_expcted, int direction, int start_sec, int num_bios,
	int pattern, rq_end_io_fn *end_req_io);
extern struct test_request *test_iosched_create_test_req(struct test_iosched *,
	int is_err_expcted, int direction, int start_sec, int num_bios,
	int pattern, rq_end_io_fn *end_req_io);

extern void test_iosched_set_test_result(struct test_iosched*, int test_result);

extern void test_iosched_set_ignore_round(struct test_iosched *,
	bool ignore_round);

extern void test_iosched_register(struct blk_dev_test_type *bdt);

extern void test_iosched_unregister(struct blk_dev_test_type *bdt);

extern void test_iosched_add_urgent_req(struct test_iosched *,
	struct test_request *);

extern void check_test_completion(struct test_iosched *);

extern int compare_buffer_to_pattern(struct test_request *test_rq);

#endif /* _LINUX_TEST_IOSCHED_H */