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