xref: /linux/fs/btrfs/tests/zoned-tests.c (revision c92b4d3dd59f9f71ac34b42d4603d2323a499ab0)
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