1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2026 Western Digital. All rights reserved.
4 */
5
6 #include <linux/cleanup.h>
7 #include <linux/sizes.h>
8
9 #include "btrfs-tests.h"
10 #include "../space-info.h"
11 #include "../volumes.h"
12 #include "../zoned.h"
13
14 #define WP_MISSING_DEV ((u64)-1)
15 #define WP_CONVENTIONAL ((u64)-2)
16 #define ZONE_SIZE SZ_256M
17
18 #define HALF_STRIPE_LEN (BTRFS_STRIPE_LEN >> 1)
19
20 struct load_zone_info_test_vector {
21 u64 raid_type;
22 u64 num_stripes;
23 u64 alloc_offsets[8];
24 u64 last_alloc;
25 u64 bg_length;
26 bool degraded;
27
28 int expected_result;
29 u64 expected_alloc_offset;
30
31 const char *description;
32 };
33
34 struct zone_info {
35 u64 physical;
36 u64 capacity;
37 u64 alloc_offset;
38 };
39
test_load_zone_info(struct btrfs_fs_info * fs_info,const struct load_zone_info_test_vector * test)40 static int test_load_zone_info(struct btrfs_fs_info *fs_info,
41 const struct load_zone_info_test_vector *test)
42 {
43 struct btrfs_block_group *bg __free(btrfs_free_dummy_block_group) = NULL;
44 struct btrfs_chunk_map *map __free(btrfs_free_chunk_map) = NULL;
45 struct zone_info AUTO_KFREE(zone_info);
46 unsigned long AUTO_KFREE(active);
47 int ret;
48
49 bg = btrfs_alloc_dummy_block_group(fs_info, test->bg_length);
50 if (!bg) {
51 test_std_err(TEST_ALLOC_BLOCK_GROUP);
52 return -ENOMEM;
53 }
54
55 map = btrfs_alloc_chunk_map(test->num_stripes, GFP_KERNEL);
56 if (!map) {
57 test_std_err(TEST_ALLOC_EXTENT_MAP);
58 return -ENOMEM;
59 }
60
61 zone_info = kzalloc_objs(*zone_info, test->num_stripes, GFP_KERNEL);
62 if (!zone_info) {
63 test_err("cannot allocate zone info");
64 return -ENOMEM;
65 }
66
67 active = bitmap_zalloc(test->num_stripes, GFP_KERNEL);
68 if (!zone_info) {
69 test_err("cannot allocate active bitmap");
70 return -ENOMEM;
71 }
72
73 map->type = test->raid_type;
74 map->num_stripes = test->num_stripes;
75 if (test->raid_type == BTRFS_BLOCK_GROUP_RAID10)
76 map->sub_stripes = 2;
77 for (int i = 0; i < test->num_stripes; i++) {
78 zone_info[i].physical = 0;
79 zone_info[i].alloc_offset = test->alloc_offsets[i];
80 zone_info[i].capacity = ZONE_SIZE;
81 if (zone_info[i].alloc_offset && zone_info[i].alloc_offset < ZONE_SIZE)
82 __set_bit(i, active);
83 }
84 if (test->degraded)
85 btrfs_set_opt(fs_info->mount_opt, DEGRADED);
86 else
87 btrfs_clear_opt(fs_info->mount_opt, DEGRADED);
88
89 ret = btrfs_load_block_group_by_raid_type(bg, map, zone_info, active,
90 test->last_alloc);
91
92 if (ret != test->expected_result) {
93 test_err("unexpected return value: ret %d expected %d", ret,
94 test->expected_result);
95 return -EINVAL;
96 }
97
98 if (!ret && bg->alloc_offset != test->expected_alloc_offset) {
99 test_err("unexpected alloc_offset: alloc_offset %llu expected %llu",
100 bg->alloc_offset, test->expected_alloc_offset);
101 return -EINVAL;
102 }
103
104 return 0;
105 }
106
107 static const struct load_zone_info_test_vector load_zone_info_tests[] = {
108 /* SINGLE */
109 {
110 .description = "SINGLE: load write pointer from sequential zone",
111 .raid_type = 0,
112 .num_stripes = 1,
113 .alloc_offsets = {
114 SZ_1M,
115 },
116 .expected_alloc_offset = SZ_1M,
117 },
118 /*
119 * SINGLE block group on a conventional zone sets last_alloc outside of
120 * btrfs_load_block_group_*(). Do not test that case.
121 */
122
123 /* DUP */
124 /* Normal case */
125 {
126 .description = "DUP: having matching write pointers",
127 .raid_type = BTRFS_BLOCK_GROUP_DUP,
128 .num_stripes = 2,
129 .alloc_offsets = {
130 SZ_1M, SZ_1M,
131 },
132 .expected_alloc_offset = SZ_1M,
133 },
134 /*
135 * One sequential zone and one conventional zone, having matching
136 * last_alloc.
137 */
138 {
139 .description = "DUP: seq zone and conv zone, matching last_alloc",
140 .raid_type = BTRFS_BLOCK_GROUP_DUP,
141 .num_stripes = 2,
142 .alloc_offsets = {
143 SZ_1M, WP_CONVENTIONAL,
144 },
145 .last_alloc = SZ_1M,
146 .expected_alloc_offset = SZ_1M,
147 },
148 /*
149 * One sequential and one conventional zone, but having smaller
150 * last_alloc than write pointer.
151 */
152 {
153 .description = "DUP: seq zone and conv zone, smaller last_alloc",
154 .raid_type = BTRFS_BLOCK_GROUP_DUP,
155 .num_stripes = 2,
156 .alloc_offsets = {
157 SZ_1M, WP_CONVENTIONAL,
158 },
159 .last_alloc = 0,
160 .expected_alloc_offset = SZ_1M,
161 },
162 /* Error case: having different write pointers. */
163 {
164 .description = "DUP: fail: different write pointers",
165 .raid_type = BTRFS_BLOCK_GROUP_DUP,
166 .num_stripes = 2,
167 .alloc_offsets = {
168 SZ_1M, SZ_2M,
169 },
170 .expected_result = -EIO,
171 },
172 /* Error case: partial missing device should not happen on DUP. */
173 {
174 .description = "DUP: fail: missing device",
175 .raid_type = BTRFS_BLOCK_GROUP_DUP,
176 .num_stripes = 2,
177 .alloc_offsets = {
178 SZ_1M, WP_MISSING_DEV,
179 },
180 .expected_result = -EIO,
181 },
182 /*
183 * Error case: one sequential and one conventional zone, but having larger
184 * last_alloc than write pointer.
185 */
186 {
187 .description = "DUP: fail: seq zone and conv zone, larger last_alloc",
188 .raid_type = BTRFS_BLOCK_GROUP_DUP,
189 .num_stripes = 2,
190 .alloc_offsets = {
191 SZ_1M, WP_CONVENTIONAL,
192 },
193 .last_alloc = SZ_2M,
194 .expected_result = -EIO,
195 },
196
197 /* RAID1 */
198 /* Normal case */
199 {
200 .description = "RAID1: having matching write pointers",
201 .raid_type = BTRFS_BLOCK_GROUP_RAID1,
202 .num_stripes = 2,
203 .alloc_offsets = {
204 SZ_1M, SZ_1M,
205 },
206 .expected_alloc_offset = SZ_1M,
207 },
208 /*
209 * One sequential zone and one conventional zone, having matching
210 * last_alloc.
211 */
212 {
213 .description = "RAID1: seq zone and conv zone, matching last_alloc",
214 .raid_type = BTRFS_BLOCK_GROUP_RAID1,
215 .num_stripes = 2,
216 .alloc_offsets = {
217 SZ_1M, WP_CONVENTIONAL,
218 },
219 .last_alloc = SZ_1M,
220 .expected_alloc_offset = SZ_1M,
221 },
222 /*
223 * One sequential and one conventional zone, but having smaller
224 * last_alloc than write pointer.
225 */
226 {
227 .description = "RAID1: seq zone and conv zone, smaller last_alloc",
228 .raid_type = BTRFS_BLOCK_GROUP_RAID1,
229 .num_stripes = 2,
230 .alloc_offsets = {
231 SZ_1M, WP_CONVENTIONAL,
232 },
233 .last_alloc = 0,
234 .expected_alloc_offset = SZ_1M,
235 },
236 /* Partial missing device should be recovered on DEGRADED mount */
237 {
238 .description = "RAID1: fail: missing device on DEGRADED",
239 .raid_type = BTRFS_BLOCK_GROUP_RAID1,
240 .num_stripes = 2,
241 .alloc_offsets = {
242 SZ_1M, WP_MISSING_DEV,
243 },
244 .degraded = true,
245 .expected_alloc_offset = SZ_1M,
246 },
247 /* Error case: having different write pointers. */
248 {
249 .description = "RAID1: fail: different write pointers",
250 .raid_type = BTRFS_BLOCK_GROUP_RAID1,
251 .num_stripes = 2,
252 .alloc_offsets = {
253 SZ_1M, SZ_2M,
254 },
255 .expected_result = -EIO,
256 },
257 /*
258 * Partial missing device is not allowed on non-DEGRADED mount never happen
259 * as it is rejected beforehand.
260 */
261 /*
262 * Error case: one sequential and one conventional zone, but having larger
263 * last_alloc than write pointer.
264 */
265 {
266 .description = "RAID1: fail: seq zone and conv zone, larger last_alloc",
267 .raid_type = BTRFS_BLOCK_GROUP_RAID1,
268 .num_stripes = 2,
269 .alloc_offsets = {
270 SZ_1M, WP_CONVENTIONAL,
271 },
272 .last_alloc = SZ_2M,
273 .expected_result = -EIO,
274 },
275
276 /* RAID0 */
277 /* Normal case */
278 {
279 .description = "RAID0: initial partial write",
280 .raid_type = BTRFS_BLOCK_GROUP_RAID0,
281 .num_stripes = 4,
282 .alloc_offsets = {
283 HALF_STRIPE_LEN, 0, 0, 0,
284 },
285 .expected_alloc_offset = HALF_STRIPE_LEN,
286 },
287 {
288 .description = "RAID0: while in second stripe",
289 .raid_type = BTRFS_BLOCK_GROUP_RAID0,
290 .num_stripes = 4,
291 .alloc_offsets = {
292 BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN + HALF_STRIPE_LEN,
293 BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
294 },
295 .expected_alloc_offset = BTRFS_STRIPE_LEN * 5 + HALF_STRIPE_LEN,
296 },
297 {
298 .description = "RAID0: one stripe advanced",
299 .raid_type = BTRFS_BLOCK_GROUP_RAID0,
300 .num_stripes = 2,
301 .alloc_offsets = {
302 SZ_1M + BTRFS_STRIPE_LEN, SZ_1M,
303 },
304 .expected_alloc_offset = SZ_2M + BTRFS_STRIPE_LEN,
305 },
306 /* Error case: having different write pointers. */
307 {
308 .description = "RAID0: fail: disordered stripes",
309 .raid_type = BTRFS_BLOCK_GROUP_RAID0,
310 .num_stripes = 4,
311 .alloc_offsets = {
312 BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN * 2,
313 BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
314 },
315 .expected_result = -EIO,
316 },
317 {
318 .description = "RAID0: fail: far distance",
319 .raid_type = BTRFS_BLOCK_GROUP_RAID0,
320 .num_stripes = 4,
321 .alloc_offsets = {
322 BTRFS_STRIPE_LEN * 3, BTRFS_STRIPE_LEN,
323 BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
324 },
325 .expected_result = -EIO,
326 },
327 {
328 .description = "RAID0: fail: too many partial write",
329 .raid_type = BTRFS_BLOCK_GROUP_RAID0,
330 .num_stripes = 4,
331 .alloc_offsets = {
332 HALF_STRIPE_LEN, HALF_STRIPE_LEN, 0, 0,
333 },
334 .expected_result = -EIO,
335 },
336 /*
337 * Error case: Partial missing device is not allowed even on non-DEGRADED
338 * mount.
339 */
340 {
341 .description = "RAID0: fail: missing device on DEGRADED",
342 .raid_type = BTRFS_BLOCK_GROUP_RAID0,
343 .num_stripes = 2,
344 .alloc_offsets = {
345 SZ_1M, WP_MISSING_DEV,
346 },
347 .degraded = true,
348 .expected_result = -EIO,
349 },
350
351 /*
352 * One sequential zone and one conventional zone, having matching
353 * last_alloc.
354 */
355 {
356 .description = "RAID0: seq zone and conv zone, partially written stripe",
357 .raid_type = BTRFS_BLOCK_GROUP_RAID0,
358 .num_stripes = 2,
359 .alloc_offsets = {
360 SZ_1M, WP_CONVENTIONAL,
361 },
362 .last_alloc = SZ_2M - SZ_4K,
363 .expected_alloc_offset = SZ_2M - SZ_4K,
364 },
365 {
366 .description = "RAID0: conv zone and seq zone, partially written stripe",
367 .raid_type = BTRFS_BLOCK_GROUP_RAID0,
368 .num_stripes = 2,
369 .alloc_offsets = {
370 WP_CONVENTIONAL, SZ_1M,
371 },
372 .last_alloc = SZ_2M + SZ_4K,
373 .expected_alloc_offset = SZ_2M + SZ_4K,
374 },
375 /*
376 * Error case: one sequential and one conventional zone, but having larger
377 * last_alloc than write pointer.
378 */
379 {
380 .description = "RAID0: fail: seq zone and conv zone, larger last_alloc",
381 .raid_type = BTRFS_BLOCK_GROUP_RAID0,
382 .num_stripes = 2,
383 .alloc_offsets = {
384 SZ_1M, WP_CONVENTIONAL,
385 },
386 .last_alloc = SZ_2M + BTRFS_STRIPE_LEN * 2,
387 .expected_result = -EIO,
388 },
389
390 /* RAID0, 4 stripes with seq zones and conv zones. */
391 {
392 .description = "RAID0: stripes [2, 2, ?, ?] last_alloc = 6",
393 .raid_type = BTRFS_BLOCK_GROUP_RAID0,
394 .num_stripes = 4,
395 .alloc_offsets = {
396 BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
397 WP_CONVENTIONAL, WP_CONVENTIONAL,
398 },
399 .last_alloc = BTRFS_STRIPE_LEN * 6,
400 .expected_alloc_offset = BTRFS_STRIPE_LEN * 6,
401 },
402 {
403 .description = "RAID0: stripes [2, 2, ?, ?] last_alloc = 7.5",
404 .raid_type = BTRFS_BLOCK_GROUP_RAID0,
405 .num_stripes = 4,
406 .alloc_offsets = {
407 BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
408 WP_CONVENTIONAL, WP_CONVENTIONAL,
409 },
410 .last_alloc = BTRFS_STRIPE_LEN * 7 + HALF_STRIPE_LEN,
411 .expected_alloc_offset = BTRFS_STRIPE_LEN * 7 + HALF_STRIPE_LEN,
412 },
413 {
414 .description = "RAID0: stripes [3, ?, ?, ?] last_alloc = 1",
415 .raid_type = BTRFS_BLOCK_GROUP_RAID0,
416 .num_stripes = 4,
417 .alloc_offsets = {
418 BTRFS_STRIPE_LEN * 3, WP_CONVENTIONAL,
419 WP_CONVENTIONAL, WP_CONVENTIONAL,
420 },
421 .last_alloc = BTRFS_STRIPE_LEN,
422 .expected_alloc_offset = BTRFS_STRIPE_LEN * 9,
423 },
424 {
425 .description = "RAID0: stripes [2, ?, 1, ?] last_alloc = 5",
426 .raid_type = BTRFS_BLOCK_GROUP_RAID0,
427 .num_stripes = 4,
428 .alloc_offsets = {
429 BTRFS_STRIPE_LEN * 2, WP_CONVENTIONAL,
430 BTRFS_STRIPE_LEN, WP_CONVENTIONAL,
431 },
432 .last_alloc = BTRFS_STRIPE_LEN * 5,
433 .expected_alloc_offset = BTRFS_STRIPE_LEN * 5,
434 },
435 {
436 .description = "RAID0: fail: stripes [2, ?, 1, ?] last_alloc = 7",
437 .raid_type = BTRFS_BLOCK_GROUP_RAID0,
438 .num_stripes = 4,
439 .alloc_offsets = {
440 BTRFS_STRIPE_LEN * 2, WP_CONVENTIONAL,
441 BTRFS_STRIPE_LEN, WP_CONVENTIONAL,
442 },
443 .last_alloc = BTRFS_STRIPE_LEN * 7,
444 .expected_result = -EIO,
445 },
446
447 /* RAID10 */
448 /* Normal case */
449 {
450 .description = "RAID10: initial partial write",
451 .raid_type = BTRFS_BLOCK_GROUP_RAID10,
452 .num_stripes = 4,
453 .alloc_offsets = {
454 HALF_STRIPE_LEN, HALF_STRIPE_LEN, 0, 0,
455 },
456 .expected_alloc_offset = HALF_STRIPE_LEN,
457 },
458 {
459 .description = "RAID10: while in second stripe",
460 .raid_type = BTRFS_BLOCK_GROUP_RAID10,
461 .num_stripes = 8,
462 .alloc_offsets = {
463 BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
464 BTRFS_STRIPE_LEN + HALF_STRIPE_LEN,
465 BTRFS_STRIPE_LEN + HALF_STRIPE_LEN,
466 BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
467 BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
468 },
469 .expected_alloc_offset = BTRFS_STRIPE_LEN * 5 + HALF_STRIPE_LEN,
470 },
471 {
472 .description = "RAID10: one stripe advanced",
473 .raid_type = BTRFS_BLOCK_GROUP_RAID10,
474 .num_stripes = 4,
475 .alloc_offsets = {
476 SZ_1M + BTRFS_STRIPE_LEN, SZ_1M + BTRFS_STRIPE_LEN,
477 SZ_1M, SZ_1M,
478 },
479 .expected_alloc_offset = SZ_2M + BTRFS_STRIPE_LEN,
480 },
481 {
482 .description = "RAID10: one stripe advanced, with conventional zone",
483 .raid_type = BTRFS_BLOCK_GROUP_RAID10,
484 .num_stripes = 4,
485 .alloc_offsets = {
486 SZ_1M + BTRFS_STRIPE_LEN, WP_CONVENTIONAL,
487 WP_CONVENTIONAL, SZ_1M,
488 },
489 .expected_alloc_offset = SZ_2M + BTRFS_STRIPE_LEN,
490 },
491 /* Error case: having different write pointers. */
492 {
493 .description = "RAID10: fail: disordered stripes",
494 .raid_type = BTRFS_BLOCK_GROUP_RAID10,
495 .num_stripes = 8,
496 .alloc_offsets = {
497 BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
498 BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
499 BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
500 BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
501 },
502 .expected_result = -EIO,
503 },
504 {
505 .description = "RAID10: fail: far distance",
506 .raid_type = BTRFS_BLOCK_GROUP_RAID10,
507 .num_stripes = 8,
508 .alloc_offsets = {
509 BTRFS_STRIPE_LEN * 3, BTRFS_STRIPE_LEN * 3,
510 BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
511 BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
512 BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
513 },
514 .expected_result = -EIO,
515 },
516 {
517 .description = "RAID10: fail: too many partial write",
518 .raid_type = BTRFS_BLOCK_GROUP_RAID10,
519 .num_stripes = 8,
520 .alloc_offsets = {
521 HALF_STRIPE_LEN, HALF_STRIPE_LEN,
522 HALF_STRIPE_LEN, HALF_STRIPE_LEN,
523 0, 0, 0, 0,
524 },
525 .expected_result = -EIO,
526 },
527 /*
528 * Error case: Partial missing device in RAID0 level is not allowed even on
529 * non-DEGRADED mount.
530 */
531 {
532 .description = "RAID10: fail: missing device on DEGRADED",
533 .raid_type = BTRFS_BLOCK_GROUP_RAID10,
534 .num_stripes = 4,
535 .alloc_offsets = {
536 SZ_1M, SZ_1M,
537 WP_MISSING_DEV, WP_MISSING_DEV,
538 },
539 .degraded = true,
540 .expected_result = -EIO,
541 },
542
543 /*
544 * One sequential zone and one conventional zone, having matching
545 * last_alloc.
546 */
547 {
548 .description = "RAID10: seq zone and conv zone, partially written stripe",
549 .raid_type = BTRFS_BLOCK_GROUP_RAID10,
550 .num_stripes = 4,
551 .alloc_offsets = {
552 SZ_1M, SZ_1M,
553 WP_CONVENTIONAL, WP_CONVENTIONAL,
554 },
555 .last_alloc = SZ_2M - SZ_4K,
556 .expected_alloc_offset = SZ_2M - SZ_4K,
557 },
558 {
559 .description = "RAID10: conv zone and seq zone, partially written stripe",
560 .raid_type = BTRFS_BLOCK_GROUP_RAID10,
561 .num_stripes = 4,
562 .alloc_offsets = {
563 WP_CONVENTIONAL, WP_CONVENTIONAL,
564 SZ_1M, SZ_1M,
565 },
566 .last_alloc = SZ_2M + SZ_4K,
567 .expected_alloc_offset = SZ_2M + SZ_4K,
568 },
569 /*
570 * Error case: one sequential and one conventional zone, but having larger
571 * last_alloc than write pointer.
572 */
573 {
574 .description = "RAID10: fail: seq zone and conv zone, larger last_alloc",
575 .raid_type = BTRFS_BLOCK_GROUP_RAID10,
576 .num_stripes = 4,
577 .alloc_offsets = {
578 SZ_1M, SZ_1M,
579 WP_CONVENTIONAL, WP_CONVENTIONAL,
580 },
581 .last_alloc = SZ_2M + BTRFS_STRIPE_LEN * 2,
582 .expected_result = -EIO,
583 },
584
585 /* RAID10, 4 stripes with seq zones and conv zones. */
586 {
587 .description = "RAID10: stripes [2, 2, ?, ?] last_alloc = 6",
588 .raid_type = BTRFS_BLOCK_GROUP_RAID10,
589 .num_stripes = 8,
590 .alloc_offsets = {
591 BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
592 BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
593 WP_CONVENTIONAL, WP_CONVENTIONAL,
594 WP_CONVENTIONAL, WP_CONVENTIONAL,
595 },
596 .last_alloc = BTRFS_STRIPE_LEN * 6,
597 .expected_alloc_offset = BTRFS_STRIPE_LEN * 6,
598 },
599 {
600 .description = "RAID10: stripes [2, 2, ?, ?] last_alloc = 7.5",
601 .raid_type = BTRFS_BLOCK_GROUP_RAID10,
602 .num_stripes = 8,
603 .alloc_offsets = {
604 BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
605 BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
606 WP_CONVENTIONAL, WP_CONVENTIONAL,
607 WP_CONVENTIONAL, WP_CONVENTIONAL,
608 },
609 .last_alloc = BTRFS_STRIPE_LEN * 7 + HALF_STRIPE_LEN,
610 .expected_alloc_offset = BTRFS_STRIPE_LEN * 7 + HALF_STRIPE_LEN,
611 },
612 {
613 .description = "RAID10: stripes [3, ?, ?, ?] last_alloc = 1",
614 .raid_type = BTRFS_BLOCK_GROUP_RAID10,
615 .num_stripes = 8,
616 .alloc_offsets = {
617 BTRFS_STRIPE_LEN * 3, BTRFS_STRIPE_LEN * 3,
618 WP_CONVENTIONAL, WP_CONVENTIONAL,
619 WP_CONVENTIONAL, WP_CONVENTIONAL,
620 WP_CONVENTIONAL, WP_CONVENTIONAL,
621 },
622 .last_alloc = BTRFS_STRIPE_LEN,
623 .expected_alloc_offset = BTRFS_STRIPE_LEN * 9,
624 },
625 {
626 .description = "RAID10: stripes [2, ?, 1, ?] last_alloc = 5",
627 .raid_type = BTRFS_BLOCK_GROUP_RAID10,
628 .num_stripes = 8,
629 .alloc_offsets = {
630 BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
631 WP_CONVENTIONAL, WP_CONVENTIONAL,
632 BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
633 WP_CONVENTIONAL, WP_CONVENTIONAL,
634 },
635 .last_alloc = BTRFS_STRIPE_LEN * 5,
636 .expected_alloc_offset = BTRFS_STRIPE_LEN * 5,
637 },
638 {
639 .description = "RAID10: fail: stripes [2, ?, 1, ?] last_alloc = 7",
640 .raid_type = BTRFS_BLOCK_GROUP_RAID10,
641 .num_stripes = 8,
642 .alloc_offsets = {
643 BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
644 WP_CONVENTIONAL, WP_CONVENTIONAL,
645 BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
646 WP_CONVENTIONAL, WP_CONVENTIONAL,
647 },
648 .last_alloc = BTRFS_STRIPE_LEN * 7,
649 .expected_result = -EIO,
650 },
651 };
652
btrfs_test_zoned(void)653 int btrfs_test_zoned(void)
654 {
655 struct btrfs_fs_info *fs_info __free(btrfs_free_dummy_fs_info) = NULL;
656 int ret;
657
658 test_msg("running zoned tests (error messages are expected)");
659
660 fs_info = btrfs_alloc_dummy_fs_info(PAGE_SIZE, PAGE_SIZE);
661 if (!fs_info) {
662 test_std_err(TEST_ALLOC_FS_INFO);
663 return -ENOMEM;
664 }
665
666 for (int i = 0; i < ARRAY_SIZE(load_zone_info_tests); i++) {
667 ret = test_load_zone_info(fs_info, &load_zone_info_tests[i]);
668 if (ret) {
669 test_err("test case \"%s\" failed", load_zone_info_tests[i].description);
670 return ret;
671 }
672 }
673
674 return 0;
675 }
676