xref: /spdk/test/unit/lib/bdev/bdev_zone.c/bdev_zone_ut.c (revision 927f1fd57bd004df581518466ec4c1b8083e5d23)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE AiRE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 #include "spdk_cunit.h"
36 #include "spdk/env.h"
37 #include "spdk_internal/mock.h"
38 
39 #include "bdev/bdev_zone.c"
40 
41 DEFINE_STUB_V(bdev_io_init, (struct spdk_bdev_io *bdev_io,
42 			     struct spdk_bdev *bdev, void *cb_arg,
43 			     spdk_bdev_io_completion_cb cb));
44 
45 DEFINE_STUB_V(bdev_io_submit, (struct spdk_bdev_io *bdev_io));
46 
47 /* Construct zone_io_operation structure */
48 struct zone_io_operation {
49 	struct spdk_bdev_desc *desc;
50 	struct spdk_io_channel *ch;
51 	struct iovec iov;
52 	union {
53 		struct {
54 			uint64_t zone_id;
55 			size_t num_zones;
56 			enum spdk_bdev_zone_action zone_action;
57 			void *buf;
58 			struct spdk_bdev_zone_info *info_;
59 		} zone_mgmt;
60 		struct {
61 			void *md_buf;
62 			struct iovec *iovs;
63 			int iovcnt;
64 			uint64_t num_blocks;
65 			uint64_t offset_blocks;
66 			uint64_t start_lba;
67 		} bdev;
68 	};
69 	spdk_bdev_io_completion_cb cb;
70 	void *cb_arg;
71 	enum spdk_bdev_io_type io_type;
72 };
73 
74 /* Global variables */
75 struct zone_io_operation *g_zone_op = NULL;
76 static struct spdk_bdev *g_bdev = NULL;
77 static struct spdk_bdev_io  *g_bdev_io = NULL;
78 static struct spdk_bdev_zone_info g_zone_info = {0};
79 static enum spdk_bdev_zone_action g_zone_action = SPDK_BDEV_ZONE_OPEN;
80 static enum spdk_bdev_zone_action g_unexpected_zone_action = SPDK_BDEV_ZONE_CLOSE;
81 static enum spdk_bdev_io_type g_io_type = SPDK_BDEV_IO_TYPE_GET_ZONE_INFO;
82 
83 static uint64_t g_expected_zone_id;
84 static uint64_t g_expected_num_zones;
85 static uint64_t g_unexpected_zone_id;
86 static uint64_t g_unexpected_num_zones;
87 static uint64_t g_num_blocks;
88 static uint64_t g_unexpected_num_blocks;
89 static uint64_t g_start_lba;
90 static uint64_t g_unexpected_start_lba;
91 static uint64_t g_bdev_blocklen;
92 static uint64_t g_unexpected_bdev_blocklen;
93 static bool g_append_with_md;
94 static int g_unexpected_iovcnt;
95 static void *g_md_buf;
96 static void *g_unexpected_md_buf;
97 static void *g_buf;
98 static void *g_unexpected_buf;
99 
100 static int
101 test_setup(void)
102 {
103 	/* Initiate expected and unexpected value here */
104 	g_expected_zone_id = 0x1000;
105 	g_expected_num_zones = 1024;
106 	g_unexpected_zone_id = 0xFFFF;
107 	g_unexpected_num_zones = 0;
108 	g_num_blocks = 4096 * 1024;
109 	g_unexpected_num_blocks = 0;
110 	g_start_lba = 4096;
111 	g_unexpected_start_lba = 0;
112 	g_bdev_blocklen = 4096;
113 	g_unexpected_bdev_blocklen = 0;
114 	g_append_with_md = false;
115 	g_unexpected_iovcnt = 1000;
116 	g_md_buf = (void *)0xEFDCFEDE;
117 	g_unexpected_md_buf = (void *)0xFECDEFDC;
118 	g_buf = (void *)0xFEEDBEEF;
119 	g_unexpected_buf = (void *)0xDEADBEEF;
120 
121 	return 0;
122 }
123 
124 static int
125 test_cleanup(void)
126 {
127 	return 0;
128 }
129 
130 static void
131 start_operation(void)
132 {
133 	g_zone_op = calloc(1, sizeof(struct zone_io_operation));
134 	SPDK_CU_ASSERT_FATAL(g_zone_op != NULL);
135 
136 	switch (g_io_type) {
137 	case SPDK_BDEV_IO_TYPE_ZONE_APPEND:
138 		g_zone_op->bdev.iovs = &g_zone_op->iov;
139 		g_zone_op->bdev.iovs[0].iov_base = g_unexpected_buf;
140 		g_zone_op->bdev.iovs[0].iov_len = g_unexpected_num_blocks * g_unexpected_bdev_blocklen;
141 		g_zone_op->bdev.iovcnt = g_unexpected_iovcnt;
142 		g_zone_op->bdev.md_buf = g_unexpected_md_buf;
143 		g_zone_op->bdev.num_blocks = g_unexpected_num_blocks;
144 		g_zone_op->bdev.offset_blocks = g_unexpected_zone_id;
145 		g_zone_op->bdev.start_lba = g_unexpected_start_lba;
146 		break;
147 	default:
148 		g_zone_op->bdev.iovcnt = 0;
149 		g_zone_op->zone_mgmt.zone_id = g_unexpected_zone_id;
150 		g_zone_op->zone_mgmt.num_zones = g_unexpected_num_zones;
151 		g_zone_op->zone_mgmt.zone_action = g_unexpected_zone_action;
152 		g_zone_op->zone_mgmt.buf = g_unexpected_buf;
153 		break;
154 	}
155 }
156 
157 static void
158 stop_operation(void)
159 {
160 	free(g_bdev_io);
161 	free(g_bdev);
162 	free(g_zone_op);
163 	g_bdev_io = NULL;
164 	g_bdev = NULL;
165 	g_zone_op = NULL;
166 }
167 
168 struct spdk_bdev_io *
169 bdev_channel_get_io(struct spdk_bdev_channel *channel)
170 {
171 	struct spdk_bdev_io *bdev_io;
172 
173 	bdev_io = calloc(1, sizeof(struct spdk_bdev_io));
174 	SPDK_CU_ASSERT_FATAL(bdev_io != NULL);
175 
176 	bdev_io->internal.ch = channel;
177 	bdev_io->type = g_io_type;
178 
179 	CU_ASSERT(g_zone_op != NULL);
180 
181 	switch (g_io_type) {
182 	case SPDK_BDEV_IO_TYPE_GET_ZONE_INFO:
183 	case SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT:
184 		bdev_io->u.bdev.iovcnt = 0;
185 		bdev_io->u.zone_mgmt.zone_id  = g_zone_op->zone_mgmt.zone_id;
186 		bdev_io->u.zone_mgmt.num_zones = g_zone_op->zone_mgmt.num_zones;
187 		bdev_io->u.zone_mgmt.zone_action = g_zone_op->zone_mgmt.zone_action;
188 		bdev_io->u.zone_mgmt.buf = g_zone_op->zone_mgmt.buf;
189 		break;
190 	case SPDK_BDEV_IO_TYPE_ZONE_APPEND:
191 		bdev_io->u.bdev.iovs = g_zone_op->bdev.iovs;
192 		bdev_io->u.bdev.iovs[0].iov_base = g_zone_op->bdev.iovs[0].iov_base;
193 		bdev_io->u.bdev.iovs[0].iov_len = g_zone_op->bdev.iovs[0].iov_len;
194 		bdev_io->u.bdev.iovcnt = g_zone_op->bdev.iovcnt;
195 		bdev_io->u.bdev.md_buf = g_zone_op->bdev.md_buf;
196 		bdev_io->u.bdev.num_blocks = g_zone_op->bdev.num_blocks;
197 		bdev_io->u.bdev.offset_blocks = g_zone_op->bdev.offset_blocks;
198 		break;
199 	default:
200 		CU_ASSERT(0);
201 	}
202 
203 	g_bdev_io = bdev_io;
204 
205 	return bdev_io;
206 }
207 
208 int
209 spdk_bdev_open_ext(const char *bdev_name, bool write, spdk_bdev_event_cb_t event_cb,
210 		   void *event_ctx, struct spdk_bdev_desc **_desc)
211 {
212 	*_desc = (void *)0x1;
213 	return 0;
214 }
215 
216 struct spdk_io_channel *
217 spdk_bdev_get_io_channel(struct spdk_bdev_desc *desc)
218 {
219 	return (struct spdk_io_channel *)0x1;
220 }
221 
222 void
223 spdk_put_io_channel(struct spdk_io_channel *ch)
224 {
225 	CU_ASSERT(ch == (void *)1);
226 }
227 
228 struct spdk_bdev *
229 spdk_bdev_desc_get_bdev(struct spdk_bdev_desc *desc)
230 {
231 	struct spdk_bdev *bdev;
232 
233 	bdev = calloc(1, sizeof(struct spdk_bdev));
234 	SPDK_CU_ASSERT_FATAL(bdev != NULL);
235 
236 	if (g_io_type == SPDK_BDEV_IO_TYPE_ZONE_APPEND) {
237 		bdev->blocklen = g_bdev_blocklen;
238 	}
239 
240 	g_bdev = bdev;
241 
242 	return bdev;
243 }
244 
245 static void
246 test_get_zone_size(void)
247 {
248 	struct spdk_bdev bdev = {};
249 	uint64_t get_zone_size;
250 
251 	bdev.zone_size = 1024 * 4096;
252 
253 	get_zone_size = spdk_bdev_get_zone_size(&bdev);
254 	CU_ASSERT(get_zone_size == 1024 * 4096);
255 }
256 
257 static void
258 test_get_num_zones(void)
259 {
260 	struct spdk_bdev bdev = {};
261 	uint64_t get_num_zones;
262 
263 	bdev.blockcnt = 1024 * 1024 * 1024;
264 	bdev.zone_size = 1024 * 4096;
265 
266 	get_num_zones = spdk_bdev_get_num_zones(&bdev);
267 	CU_ASSERT(get_num_zones == 256);
268 }
269 
270 static void
271 test_get_zone_id(void)
272 {
273 	struct spdk_bdev bdev = {};
274 	uint64_t get_zone_id;
275 
276 	bdev.blockcnt = 1024 * 1024 * 1024;
277 	bdev.zone_size = 1024 * 4096;
278 
279 	get_zone_id = spdk_bdev_get_zone_id(&bdev, 0x800032);
280 	CU_ASSERT(get_zone_id == 0x800000);
281 }
282 
283 static void
284 test_get_max_zone_append_size(void)
285 {
286 	struct spdk_bdev bdev = {};
287 	uint32_t get_max_zone_append_size;
288 
289 	bdev.max_zone_append_size = 32;
290 
291 	get_max_zone_append_size = spdk_bdev_get_max_zone_append_size(&bdev);
292 	CU_ASSERT(get_max_zone_append_size == 32);
293 }
294 
295 static void
296 test_get_max_open_zones(void)
297 {
298 	struct spdk_bdev bdev = {};
299 	uint32_t get_max_open_zones;
300 
301 	bdev.max_open_zones = 8192;
302 
303 	get_max_open_zones = spdk_bdev_get_max_open_zones(&bdev);
304 	CU_ASSERT(get_max_open_zones == 8192);
305 }
306 
307 static void
308 test_get_max_active_zones(void)
309 {
310 	struct spdk_bdev bdev = {};
311 	uint32_t get_max_active_zones;
312 
313 	bdev.max_active_zones = 9216;
314 
315 	get_max_active_zones = spdk_bdev_get_max_active_zones(&bdev);
316 	CU_ASSERT(get_max_active_zones == 9216);
317 }
318 
319 static void
320 test_get_optimal_open_zones(void)
321 {
322 	struct spdk_bdev bdev = {};
323 	uint32_t get_optimal_open_zones;
324 
325 	bdev.optimal_open_zones = 4096;
326 
327 	get_optimal_open_zones = spdk_bdev_get_optimal_open_zones(&bdev);
328 	CU_ASSERT(get_optimal_open_zones == 4096);
329 }
330 
331 static void
332 test_bdev_io_get_append_location(void)
333 {
334 	struct spdk_bdev_io bdev_io = {};
335 	uint64_t get_offset_blocks;
336 
337 	bdev_io.u.bdev.offset_blocks = 1024 * 10;
338 
339 	get_offset_blocks = spdk_bdev_io_get_append_location(&bdev_io);
340 	CU_ASSERT(get_offset_blocks == 1024 * 10);
341 }
342 
343 static void
344 test_zone_get_operation(void)
345 {
346 	test_get_zone_size();
347 	test_get_num_zones();
348 	test_get_zone_id();
349 	test_get_max_zone_append_size();
350 	test_get_max_open_zones();
351 	test_get_max_active_zones();
352 	test_get_optimal_open_zones();
353 }
354 
355 #define DECLARE_VIRTUAL_BDEV_START() \
356     struct spdk_bdev bdev; \
357     struct spdk_io_channel *ch; \
358     struct spdk_bdev_desc *desc = NULL; \
359     int rc; \
360     memset(&bdev, 0, sizeof(bdev)); \
361     bdev.name = "bdev_zone_ut"; \
362     rc = spdk_bdev_open_ext(bdev.name, true, NULL, NULL, &desc); \
363     CU_ASSERT(rc == 0); \
364     SPDK_CU_ASSERT_FATAL(desc != NULL); \
365     ch = spdk_bdev_get_io_channel(desc); \
366     CU_ASSERT(ch != NULL);\
367 
368 static void
369 test_bdev_zone_get_info(void)
370 {
371 	DECLARE_VIRTUAL_BDEV_START();
372 
373 	g_zone_info.zone_id = g_expected_zone_id;
374 	g_io_type = SPDK_BDEV_IO_TYPE_GET_ZONE_INFO;
375 
376 	start_operation();
377 
378 	rc = spdk_bdev_get_zone_info(desc, ch, g_expected_zone_id, g_expected_num_zones, &g_zone_info, NULL,
379 				     NULL);
380 	CU_ASSERT(rc == 0);
381 	CU_ASSERT(g_bdev_io->type == SPDK_BDEV_IO_TYPE_GET_ZONE_INFO);
382 	CU_ASSERT(g_bdev_io->u.zone_mgmt.zone_id == g_expected_zone_id);
383 	CU_ASSERT(g_bdev_io->u.zone_mgmt.num_zones == g_expected_num_zones);
384 	CU_ASSERT(g_bdev_io->u.zone_mgmt.buf == &g_zone_info);
385 
386 	stop_operation();
387 }
388 
389 static void
390 test_bdev_zone_management(void)
391 {
392 	DECLARE_VIRTUAL_BDEV_START();
393 
394 	g_zone_info.zone_id = g_expected_zone_id;
395 	g_io_type = SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT;
396 
397 	start_operation();
398 
399 	rc = spdk_bdev_zone_management(desc, ch, g_expected_zone_id, g_zone_action, NULL,
400 				       NULL);
401 	CU_ASSERT(rc == 0);
402 	CU_ASSERT(g_bdev_io->type == SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT);
403 	CU_ASSERT(g_bdev_io->u.zone_mgmt.zone_id == g_expected_zone_id);
404 	CU_ASSERT(g_bdev_io->u.zone_mgmt.zone_action == g_zone_action);
405 	CU_ASSERT(g_bdev_io->u.zone_mgmt.num_zones == 1);
406 
407 	stop_operation();
408 }
409 
410 static void
411 test_bdev_zone_append(void)
412 {
413 	DECLARE_VIRTUAL_BDEV_START();
414 
415 	g_io_type = SPDK_BDEV_IO_TYPE_ZONE_APPEND;
416 	g_append_with_md = false;
417 
418 	start_operation();
419 
420 	rc = spdk_bdev_zone_append(desc, ch, g_buf, g_start_lba, g_num_blocks, NULL, NULL);
421 
422 	CU_ASSERT(rc == 0);
423 	CU_ASSERT(g_bdev_io->internal.desc == desc);
424 	CU_ASSERT(g_bdev_io->type == SPDK_BDEV_IO_TYPE_ZONE_APPEND);
425 	CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_base == g_buf);
426 	CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_len == g_num_blocks * g_bdev_blocklen);
427 	CU_ASSERT(g_bdev_io->u.bdev.iovcnt == 1);
428 	CU_ASSERT(g_bdev_io->u.bdev.md_buf == NULL);
429 	CU_ASSERT(g_bdev_io->u.bdev.num_blocks == g_num_blocks);
430 	CU_ASSERT(g_bdev_io->u.bdev.offset_blocks == g_expected_zone_id);
431 
432 	stop_operation();
433 }
434 
435 static void
436 test_bdev_zone_append_with_md(void)
437 {
438 	DECLARE_VIRTUAL_BDEV_START();
439 
440 	g_io_type = SPDK_BDEV_IO_TYPE_ZONE_APPEND;
441 	g_append_with_md = true;
442 
443 	start_operation();
444 
445 	rc = spdk_bdev_zone_append_with_md(desc, ch, g_buf, g_md_buf, g_start_lba, g_num_blocks, NULL,
446 					   NULL);
447 
448 	CU_ASSERT(rc == 0);
449 	CU_ASSERT(g_bdev_io->internal.desc == desc);
450 	CU_ASSERT(g_bdev_io->type == SPDK_BDEV_IO_TYPE_ZONE_APPEND);
451 	CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_base == g_buf);
452 	CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_len == g_num_blocks * g_bdev_blocklen);
453 	CU_ASSERT(g_bdev_io->u.bdev.iovcnt == 1);
454 	CU_ASSERT(g_bdev_io->u.bdev.md_buf == g_md_buf);
455 	CU_ASSERT(g_bdev_io->u.bdev.num_blocks == g_num_blocks);
456 	CU_ASSERT(g_bdev_io->u.bdev.offset_blocks == g_expected_zone_id);
457 
458 	stop_operation();
459 }
460 
461 int
462 main(int argc, char **argv)
463 {
464 	CU_pSuite suite = NULL;
465 	unsigned int num_failures;
466 
467 	CU_set_error_action(CUEA_ABORT);
468 	CU_initialize_registry();
469 
470 	suite = CU_add_suite("zone", test_setup, test_cleanup);
471 	CU_ADD_TEST(suite, test_zone_get_operation);
472 	CU_ADD_TEST(suite, test_bdev_zone_get_info);
473 	CU_ADD_TEST(suite, test_bdev_zone_management);
474 	CU_ADD_TEST(suite, test_bdev_zone_append);
475 	CU_ADD_TEST(suite, test_bdev_zone_append_with_md);
476 	CU_ADD_TEST(suite, test_bdev_io_get_append_location);
477 
478 	CU_basic_set_mode(CU_BRM_VERBOSE);
479 	CU_basic_run_tests();
480 	num_failures = CU_get_number_of_failures();
481 	CU_cleanup_registry();
482 	return num_failures;
483 }
484