xref: /linux/fs/btrfs/tests/zoned-tests.c (revision c92b4d3dd59f9f71ac34b42d4603d2323a499ab0)
11ba19a6eSNaohiro Aota // SPDX-License-Identifier: GPL-2.0
21ba19a6eSNaohiro Aota /*
31ba19a6eSNaohiro Aota  * Copyright (C) 2026 Western Digital.  All rights reserved.
41ba19a6eSNaohiro Aota  */
51ba19a6eSNaohiro Aota 
61ba19a6eSNaohiro Aota #include <linux/cleanup.h>
71ba19a6eSNaohiro Aota #include <linux/sizes.h>
81ba19a6eSNaohiro Aota 
91ba19a6eSNaohiro Aota #include "btrfs-tests.h"
101ba19a6eSNaohiro Aota #include "../space-info.h"
111ba19a6eSNaohiro Aota #include "../volumes.h"
121ba19a6eSNaohiro Aota #include "../zoned.h"
131ba19a6eSNaohiro Aota 
141ba19a6eSNaohiro Aota #define WP_MISSING_DEV				((u64)-1)
151ba19a6eSNaohiro Aota #define WP_CONVENTIONAL				((u64)-2)
161ba19a6eSNaohiro Aota #define ZONE_SIZE				SZ_256M
171ba19a6eSNaohiro Aota 
181ba19a6eSNaohiro Aota #define HALF_STRIPE_LEN				(BTRFS_STRIPE_LEN >> 1)
191ba19a6eSNaohiro Aota 
201ba19a6eSNaohiro Aota struct load_zone_info_test_vector {
211ba19a6eSNaohiro Aota 	u64 raid_type;
221ba19a6eSNaohiro Aota 	u64 num_stripes;
231ba19a6eSNaohiro Aota 	u64 alloc_offsets[8];
241ba19a6eSNaohiro Aota 	u64 last_alloc;
251ba19a6eSNaohiro Aota 	u64 bg_length;
261ba19a6eSNaohiro Aota 	bool degraded;
271ba19a6eSNaohiro Aota 
281ba19a6eSNaohiro Aota 	int expected_result;
291ba19a6eSNaohiro Aota 	u64 expected_alloc_offset;
301ba19a6eSNaohiro Aota 
311ba19a6eSNaohiro Aota 	const char *description;
321ba19a6eSNaohiro Aota };
331ba19a6eSNaohiro Aota 
341ba19a6eSNaohiro Aota struct zone_info {
351ba19a6eSNaohiro Aota 	u64 physical;
361ba19a6eSNaohiro Aota 	u64 capacity;
371ba19a6eSNaohiro Aota 	u64 alloc_offset;
381ba19a6eSNaohiro Aota };
391ba19a6eSNaohiro Aota 
401ba19a6eSNaohiro Aota static int test_load_zone_info(struct btrfs_fs_info *fs_info,
411ba19a6eSNaohiro Aota 			       const struct load_zone_info_test_vector *test)
421ba19a6eSNaohiro Aota {
431ba19a6eSNaohiro Aota 	struct btrfs_block_group *bg __free(btrfs_free_dummy_block_group) = NULL;
441ba19a6eSNaohiro Aota 	struct btrfs_chunk_map *map __free(btrfs_free_chunk_map) = NULL;
451ba19a6eSNaohiro Aota 	struct zone_info AUTO_KFREE(zone_info);
461ba19a6eSNaohiro Aota 	unsigned long AUTO_KFREE(active);
471ba19a6eSNaohiro Aota 	int ret;
481ba19a6eSNaohiro Aota 
491ba19a6eSNaohiro Aota 	bg = btrfs_alloc_dummy_block_group(fs_info, test->bg_length);
501ba19a6eSNaohiro Aota 	if (!bg) {
511ba19a6eSNaohiro Aota 		test_std_err(TEST_ALLOC_BLOCK_GROUP);
521ba19a6eSNaohiro Aota 		return -ENOMEM;
531ba19a6eSNaohiro Aota 	}
541ba19a6eSNaohiro Aota 
551ba19a6eSNaohiro Aota 	map = btrfs_alloc_chunk_map(test->num_stripes, GFP_KERNEL);
561ba19a6eSNaohiro Aota 	if (!map) {
571ba19a6eSNaohiro Aota 		test_std_err(TEST_ALLOC_EXTENT_MAP);
581ba19a6eSNaohiro Aota 		return -ENOMEM;
591ba19a6eSNaohiro Aota 	}
601ba19a6eSNaohiro Aota 
61*2d2b5507SMiquel Sabaté Solà 	zone_info = kzalloc_objs(*zone_info, test->num_stripes, GFP_KERNEL);
621ba19a6eSNaohiro Aota 	if (!zone_info) {
631ba19a6eSNaohiro Aota 		test_err("cannot allocate zone info");
641ba19a6eSNaohiro Aota 		return -ENOMEM;
651ba19a6eSNaohiro Aota 	}
661ba19a6eSNaohiro Aota 
671ba19a6eSNaohiro Aota 	active = bitmap_zalloc(test->num_stripes, GFP_KERNEL);
681ba19a6eSNaohiro Aota 	if (!zone_info) {
691ba19a6eSNaohiro Aota 		test_err("cannot allocate active bitmap");
701ba19a6eSNaohiro Aota 		return -ENOMEM;
711ba19a6eSNaohiro Aota 	}
721ba19a6eSNaohiro Aota 
731ba19a6eSNaohiro Aota 	map->type = test->raid_type;
741ba19a6eSNaohiro Aota 	map->num_stripes = test->num_stripes;
751ba19a6eSNaohiro Aota 	if (test->raid_type == BTRFS_BLOCK_GROUP_RAID10)
761ba19a6eSNaohiro Aota 		map->sub_stripes = 2;
771ba19a6eSNaohiro Aota 	for (int i = 0; i < test->num_stripes; i++) {
781ba19a6eSNaohiro Aota 		zone_info[i].physical = 0;
791ba19a6eSNaohiro Aota 		zone_info[i].alloc_offset = test->alloc_offsets[i];
801ba19a6eSNaohiro Aota 		zone_info[i].capacity = ZONE_SIZE;
811ba19a6eSNaohiro Aota 		if (zone_info[i].alloc_offset && zone_info[i].alloc_offset < ZONE_SIZE)
821ba19a6eSNaohiro Aota 			__set_bit(i, active);
831ba19a6eSNaohiro Aota 	}
841ba19a6eSNaohiro Aota 	if (test->degraded)
851ba19a6eSNaohiro Aota 		btrfs_set_opt(fs_info->mount_opt, DEGRADED);
861ba19a6eSNaohiro Aota 	else
871ba19a6eSNaohiro Aota 		btrfs_clear_opt(fs_info->mount_opt, DEGRADED);
881ba19a6eSNaohiro Aota 
891ba19a6eSNaohiro Aota 	ret = btrfs_load_block_group_by_raid_type(bg, map, zone_info, active,
901ba19a6eSNaohiro Aota 						  test->last_alloc);
911ba19a6eSNaohiro Aota 
921ba19a6eSNaohiro Aota 	if (ret != test->expected_result) {
931ba19a6eSNaohiro Aota 		test_err("unexpected return value: ret %d expected %d", ret,
941ba19a6eSNaohiro Aota 			 test->expected_result);
951ba19a6eSNaohiro Aota 		return -EINVAL;
961ba19a6eSNaohiro Aota 	}
971ba19a6eSNaohiro Aota 
981ba19a6eSNaohiro Aota 	if (!ret && bg->alloc_offset != test->expected_alloc_offset) {
991ba19a6eSNaohiro Aota 		test_err("unexpected alloc_offset: alloc_offset %llu expected %llu",
1001ba19a6eSNaohiro Aota 			 bg->alloc_offset, test->expected_alloc_offset);
1011ba19a6eSNaohiro Aota 		return -EINVAL;
1021ba19a6eSNaohiro Aota 	}
1031ba19a6eSNaohiro Aota 
1041ba19a6eSNaohiro Aota 	return 0;
1051ba19a6eSNaohiro Aota }
1061ba19a6eSNaohiro Aota 
1071ba19a6eSNaohiro Aota static const struct load_zone_info_test_vector load_zone_info_tests[] = {
1081ba19a6eSNaohiro Aota 	/* SINGLE */
1091ba19a6eSNaohiro Aota 	{
1101ba19a6eSNaohiro Aota 		.description = "SINGLE: load write pointer from sequential zone",
1111ba19a6eSNaohiro Aota 		.raid_type = 0,
1121ba19a6eSNaohiro Aota 		.num_stripes = 1,
1131ba19a6eSNaohiro Aota 		.alloc_offsets = {
1141ba19a6eSNaohiro Aota 			SZ_1M,
1151ba19a6eSNaohiro Aota 		},
1161ba19a6eSNaohiro Aota 		.expected_alloc_offset = SZ_1M,
1171ba19a6eSNaohiro Aota 	},
1181ba19a6eSNaohiro Aota 	/*
1191ba19a6eSNaohiro Aota 	 * SINGLE block group on a conventional zone sets last_alloc outside of
1201ba19a6eSNaohiro Aota 	 * btrfs_load_block_group_*(). Do not test that case.
1211ba19a6eSNaohiro Aota 	 */
1221ba19a6eSNaohiro Aota 
1231ba19a6eSNaohiro Aota 	/* DUP */
1241ba19a6eSNaohiro Aota 	/* Normal case */
1251ba19a6eSNaohiro Aota 	{
1261ba19a6eSNaohiro Aota 		.description = "DUP: having matching write pointers",
1271ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_DUP,
1281ba19a6eSNaohiro Aota 		.num_stripes = 2,
1291ba19a6eSNaohiro Aota 		.alloc_offsets = {
1301ba19a6eSNaohiro Aota 			SZ_1M, SZ_1M,
1311ba19a6eSNaohiro Aota 		},
1321ba19a6eSNaohiro Aota 		.expected_alloc_offset = SZ_1M,
1331ba19a6eSNaohiro Aota 	},
1341ba19a6eSNaohiro Aota 	/*
1351ba19a6eSNaohiro Aota 	 * One sequential zone and one conventional zone, having matching
1361ba19a6eSNaohiro Aota 	 * last_alloc.
1371ba19a6eSNaohiro Aota 	 */
1381ba19a6eSNaohiro Aota 	{
1391ba19a6eSNaohiro Aota 		.description = "DUP: seq zone and conv zone, matching last_alloc",
1401ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_DUP,
1411ba19a6eSNaohiro Aota 		.num_stripes = 2,
1421ba19a6eSNaohiro Aota 		.alloc_offsets = {
1431ba19a6eSNaohiro Aota 			SZ_1M, WP_CONVENTIONAL,
1441ba19a6eSNaohiro Aota 		},
1451ba19a6eSNaohiro Aota 		.last_alloc = SZ_1M,
1461ba19a6eSNaohiro Aota 		.expected_alloc_offset = SZ_1M,
1471ba19a6eSNaohiro Aota 	},
1481ba19a6eSNaohiro Aota 	/*
1491ba19a6eSNaohiro Aota 	 * One sequential and one conventional zone, but having smaller
1501ba19a6eSNaohiro Aota 	 * last_alloc than write pointer.
1511ba19a6eSNaohiro Aota 	 */
1521ba19a6eSNaohiro Aota 	{
1531ba19a6eSNaohiro Aota 		.description = "DUP: seq zone and conv zone, smaller last_alloc",
1541ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_DUP,
1551ba19a6eSNaohiro Aota 		.num_stripes = 2,
1561ba19a6eSNaohiro Aota 		.alloc_offsets = {
1571ba19a6eSNaohiro Aota 			SZ_1M, WP_CONVENTIONAL,
1581ba19a6eSNaohiro Aota 		},
1591ba19a6eSNaohiro Aota 		.last_alloc = 0,
1601ba19a6eSNaohiro Aota 		.expected_alloc_offset = SZ_1M,
1611ba19a6eSNaohiro Aota 	},
1621ba19a6eSNaohiro Aota 	/* Error case: having different write pointers. */
1631ba19a6eSNaohiro Aota 	{
1641ba19a6eSNaohiro Aota 		.description = "DUP: fail: different write pointers",
1651ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_DUP,
1661ba19a6eSNaohiro Aota 		.num_stripes = 2,
1671ba19a6eSNaohiro Aota 		.alloc_offsets = {
1681ba19a6eSNaohiro Aota 			SZ_1M, SZ_2M,
1691ba19a6eSNaohiro Aota 		},
1701ba19a6eSNaohiro Aota 		.expected_result = -EIO,
1711ba19a6eSNaohiro Aota 	},
1721ba19a6eSNaohiro Aota 	/* Error case: partial missing device should not happen on DUP. */
1731ba19a6eSNaohiro Aota 	{
1741ba19a6eSNaohiro Aota 		.description = "DUP: fail: missing device",
1751ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_DUP,
1761ba19a6eSNaohiro Aota 		.num_stripes = 2,
1771ba19a6eSNaohiro Aota 		.alloc_offsets = {
1781ba19a6eSNaohiro Aota 			SZ_1M, WP_MISSING_DEV,
1791ba19a6eSNaohiro Aota 		},
1801ba19a6eSNaohiro Aota 		.expected_result = -EIO,
1811ba19a6eSNaohiro Aota 	},
1821ba19a6eSNaohiro Aota 	/*
1831ba19a6eSNaohiro Aota 	 * Error case: one sequential and one conventional zone, but having larger
1841ba19a6eSNaohiro Aota 	 * last_alloc than write pointer.
1851ba19a6eSNaohiro Aota 	 */
1861ba19a6eSNaohiro Aota 	{
1871ba19a6eSNaohiro Aota 		.description = "DUP: fail: seq zone and conv zone, larger last_alloc",
1881ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_DUP,
1891ba19a6eSNaohiro Aota 		.num_stripes = 2,
1901ba19a6eSNaohiro Aota 		.alloc_offsets = {
1911ba19a6eSNaohiro Aota 			SZ_1M, WP_CONVENTIONAL,
1921ba19a6eSNaohiro Aota 		},
1931ba19a6eSNaohiro Aota 		.last_alloc = SZ_2M,
1941ba19a6eSNaohiro Aota 		.expected_result = -EIO,
1951ba19a6eSNaohiro Aota 	},
1961ba19a6eSNaohiro Aota 
1971ba19a6eSNaohiro Aota 	/* RAID1 */
1981ba19a6eSNaohiro Aota 	/* Normal case */
1991ba19a6eSNaohiro Aota 	{
2001ba19a6eSNaohiro Aota 		.description = "RAID1: having matching write pointers",
2011ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID1,
2021ba19a6eSNaohiro Aota 		.num_stripes = 2,
2031ba19a6eSNaohiro Aota 		.alloc_offsets = {
2041ba19a6eSNaohiro Aota 			SZ_1M, SZ_1M,
2051ba19a6eSNaohiro Aota 		},
2061ba19a6eSNaohiro Aota 		.expected_alloc_offset = SZ_1M,
2071ba19a6eSNaohiro Aota 	},
2081ba19a6eSNaohiro Aota 	/*
2091ba19a6eSNaohiro Aota 	 * One sequential zone and one conventional zone, having matching
2101ba19a6eSNaohiro Aota 	 * last_alloc.
2111ba19a6eSNaohiro Aota 	 */
2121ba19a6eSNaohiro Aota 	{
2131ba19a6eSNaohiro Aota 		.description = "RAID1: seq zone and conv zone, matching last_alloc",
2141ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID1,
2151ba19a6eSNaohiro Aota 		.num_stripes = 2,
2161ba19a6eSNaohiro Aota 		.alloc_offsets = {
2171ba19a6eSNaohiro Aota 			SZ_1M, WP_CONVENTIONAL,
2181ba19a6eSNaohiro Aota 		},
2191ba19a6eSNaohiro Aota 		.last_alloc = SZ_1M,
2201ba19a6eSNaohiro Aota 		.expected_alloc_offset = SZ_1M,
2211ba19a6eSNaohiro Aota 	},
2221ba19a6eSNaohiro Aota 	/*
2231ba19a6eSNaohiro Aota 	 * One sequential and one conventional zone, but having smaller
2241ba19a6eSNaohiro Aota 	 * last_alloc than write pointer.
2251ba19a6eSNaohiro Aota 	 */
2261ba19a6eSNaohiro Aota 	{
2271ba19a6eSNaohiro Aota 		.description = "RAID1: seq zone and conv zone, smaller last_alloc",
2281ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID1,
2291ba19a6eSNaohiro Aota 		.num_stripes = 2,
2301ba19a6eSNaohiro Aota 		.alloc_offsets = {
2311ba19a6eSNaohiro Aota 			SZ_1M, WP_CONVENTIONAL,
2321ba19a6eSNaohiro Aota 		},
2331ba19a6eSNaohiro Aota 		.last_alloc = 0,
2341ba19a6eSNaohiro Aota 		.expected_alloc_offset = SZ_1M,
2351ba19a6eSNaohiro Aota 	},
2361ba19a6eSNaohiro Aota 	/* Partial missing device should be recovered on DEGRADED mount */
2371ba19a6eSNaohiro Aota 	{
2381ba19a6eSNaohiro Aota 		.description = "RAID1: fail: missing device on DEGRADED",
2391ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID1,
2401ba19a6eSNaohiro Aota 		.num_stripes = 2,
2411ba19a6eSNaohiro Aota 		.alloc_offsets = {
2421ba19a6eSNaohiro Aota 			SZ_1M, WP_MISSING_DEV,
2431ba19a6eSNaohiro Aota 		},
2441ba19a6eSNaohiro Aota 		.degraded = true,
2451ba19a6eSNaohiro Aota 		.expected_alloc_offset = SZ_1M,
2461ba19a6eSNaohiro Aota 	},
2471ba19a6eSNaohiro Aota 	/* Error case: having different write pointers. */
2481ba19a6eSNaohiro Aota 	{
2491ba19a6eSNaohiro Aota 		.description = "RAID1: fail: different write pointers",
2501ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID1,
2511ba19a6eSNaohiro Aota 		.num_stripes = 2,
2521ba19a6eSNaohiro Aota 		.alloc_offsets = {
2531ba19a6eSNaohiro Aota 			SZ_1M, SZ_2M,
2541ba19a6eSNaohiro Aota 		},
2551ba19a6eSNaohiro Aota 		.expected_result = -EIO,
2561ba19a6eSNaohiro Aota 	},
2571ba19a6eSNaohiro Aota 	/*
2581ba19a6eSNaohiro Aota 	 * Partial missing device is not allowed on non-DEGRADED mount never happen
2591ba19a6eSNaohiro Aota 	 * as it is rejected beforehand.
2601ba19a6eSNaohiro Aota 	 */
2611ba19a6eSNaohiro Aota 	/*
2621ba19a6eSNaohiro Aota 	 * Error case: one sequential and one conventional zone, but having larger
2631ba19a6eSNaohiro Aota 	 * last_alloc than write pointer.
2641ba19a6eSNaohiro Aota 	 */
2651ba19a6eSNaohiro Aota 	{
2661ba19a6eSNaohiro Aota 		.description = "RAID1: fail: seq zone and conv zone, larger last_alloc",
2671ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID1,
2681ba19a6eSNaohiro Aota 		.num_stripes = 2,
2691ba19a6eSNaohiro Aota 		.alloc_offsets = {
2701ba19a6eSNaohiro Aota 			SZ_1M, WP_CONVENTIONAL,
2711ba19a6eSNaohiro Aota 		},
2721ba19a6eSNaohiro Aota 		.last_alloc = SZ_2M,
2731ba19a6eSNaohiro Aota 		.expected_result = -EIO,
2741ba19a6eSNaohiro Aota 	},
2751ba19a6eSNaohiro Aota 
2761ba19a6eSNaohiro Aota 	/* RAID0 */
2771ba19a6eSNaohiro Aota 	/* Normal case */
2781ba19a6eSNaohiro Aota 	{
2791ba19a6eSNaohiro Aota 		.description = "RAID0: initial partial write",
2801ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID0,
2811ba19a6eSNaohiro Aota 		.num_stripes = 4,
2821ba19a6eSNaohiro Aota 		.alloc_offsets = {
2831ba19a6eSNaohiro Aota 			HALF_STRIPE_LEN, 0, 0, 0,
2841ba19a6eSNaohiro Aota 		},
2851ba19a6eSNaohiro Aota 		.expected_alloc_offset = HALF_STRIPE_LEN,
2861ba19a6eSNaohiro Aota 	},
2871ba19a6eSNaohiro Aota 	{
2881ba19a6eSNaohiro Aota 		.description = "RAID0: while in second stripe",
2891ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID0,
2901ba19a6eSNaohiro Aota 		.num_stripes = 4,
2911ba19a6eSNaohiro Aota 		.alloc_offsets = {
2921ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN + HALF_STRIPE_LEN,
2931ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
2941ba19a6eSNaohiro Aota 		},
2951ba19a6eSNaohiro Aota 		.expected_alloc_offset = BTRFS_STRIPE_LEN * 5 + HALF_STRIPE_LEN,
2961ba19a6eSNaohiro Aota 	},
2971ba19a6eSNaohiro Aota 	{
2981ba19a6eSNaohiro Aota 		.description = "RAID0: one stripe advanced",
2991ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID0,
3001ba19a6eSNaohiro Aota 		.num_stripes = 2,
3011ba19a6eSNaohiro Aota 		.alloc_offsets = {
3021ba19a6eSNaohiro Aota 			SZ_1M + BTRFS_STRIPE_LEN, SZ_1M,
3031ba19a6eSNaohiro Aota 		},
3041ba19a6eSNaohiro Aota 		.expected_alloc_offset = SZ_2M + BTRFS_STRIPE_LEN,
3051ba19a6eSNaohiro Aota 	},
3061ba19a6eSNaohiro Aota 	/* Error case: having different write pointers. */
3071ba19a6eSNaohiro Aota 	{
3081ba19a6eSNaohiro Aota 		.description = "RAID0: fail: disordered stripes",
3091ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID0,
3101ba19a6eSNaohiro Aota 		.num_stripes = 4,
3111ba19a6eSNaohiro Aota 		.alloc_offsets = {
3121ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN * 2,
3131ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
3141ba19a6eSNaohiro Aota 		},
3151ba19a6eSNaohiro Aota 		.expected_result = -EIO,
3161ba19a6eSNaohiro Aota 	},
3171ba19a6eSNaohiro Aota 	{
3181ba19a6eSNaohiro Aota 		.description = "RAID0: fail: far distance",
3191ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID0,
3201ba19a6eSNaohiro Aota 		.num_stripes = 4,
3211ba19a6eSNaohiro Aota 		.alloc_offsets = {
3221ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 3, BTRFS_STRIPE_LEN,
3231ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
3241ba19a6eSNaohiro Aota 		},
3251ba19a6eSNaohiro Aota 		.expected_result = -EIO,
3261ba19a6eSNaohiro Aota 	},
3271ba19a6eSNaohiro Aota 	{
3281ba19a6eSNaohiro Aota 		.description = "RAID0: fail: too many partial write",
3291ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID0,
3301ba19a6eSNaohiro Aota 		.num_stripes = 4,
3311ba19a6eSNaohiro Aota 		.alloc_offsets = {
3321ba19a6eSNaohiro Aota 			HALF_STRIPE_LEN, HALF_STRIPE_LEN, 0, 0,
3331ba19a6eSNaohiro Aota 		},
3341ba19a6eSNaohiro Aota 		.expected_result = -EIO,
3351ba19a6eSNaohiro Aota 	},
3361ba19a6eSNaohiro Aota 	/*
3371ba19a6eSNaohiro Aota 	 * Error case: Partial missing device is not allowed even on non-DEGRADED
3381ba19a6eSNaohiro Aota 	 * mount.
3391ba19a6eSNaohiro Aota 	 */
3401ba19a6eSNaohiro Aota 	{
3411ba19a6eSNaohiro Aota 		.description = "RAID0: fail: missing device on DEGRADED",
3421ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID0,
3431ba19a6eSNaohiro Aota 		.num_stripes = 2,
3441ba19a6eSNaohiro Aota 		.alloc_offsets = {
3451ba19a6eSNaohiro Aota 			SZ_1M, WP_MISSING_DEV,
3461ba19a6eSNaohiro Aota 		},
3471ba19a6eSNaohiro Aota 		.degraded = true,
3481ba19a6eSNaohiro Aota 		.expected_result = -EIO,
3491ba19a6eSNaohiro Aota 	},
3501ba19a6eSNaohiro Aota 
3511ba19a6eSNaohiro Aota 	/*
3521ba19a6eSNaohiro Aota 	 * One sequential zone and one conventional zone, having matching
3531ba19a6eSNaohiro Aota 	 * last_alloc.
3541ba19a6eSNaohiro Aota 	 */
3551ba19a6eSNaohiro Aota 	{
3561ba19a6eSNaohiro Aota 		.description = "RAID0: seq zone and conv zone, partially written stripe",
3571ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID0,
3581ba19a6eSNaohiro Aota 		.num_stripes = 2,
3591ba19a6eSNaohiro Aota 		.alloc_offsets = {
3601ba19a6eSNaohiro Aota 			SZ_1M, WP_CONVENTIONAL,
3611ba19a6eSNaohiro Aota 		},
3621ba19a6eSNaohiro Aota 		.last_alloc = SZ_2M - SZ_4K,
3631ba19a6eSNaohiro Aota 		.expected_alloc_offset = SZ_2M - SZ_4K,
3641ba19a6eSNaohiro Aota 	},
3651ba19a6eSNaohiro Aota 	{
3661ba19a6eSNaohiro Aota 		.description = "RAID0: conv zone and seq zone, partially written stripe",
3671ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID0,
3681ba19a6eSNaohiro Aota 		.num_stripes = 2,
3691ba19a6eSNaohiro Aota 		.alloc_offsets = {
3701ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, SZ_1M,
3711ba19a6eSNaohiro Aota 		},
3721ba19a6eSNaohiro Aota 		.last_alloc = SZ_2M + SZ_4K,
3731ba19a6eSNaohiro Aota 		.expected_alloc_offset = SZ_2M + SZ_4K,
3741ba19a6eSNaohiro Aota 	},
3751ba19a6eSNaohiro Aota 	/*
3761ba19a6eSNaohiro Aota 	 * Error case: one sequential and one conventional zone, but having larger
3771ba19a6eSNaohiro Aota 	 * last_alloc than write pointer.
3781ba19a6eSNaohiro Aota 	 */
3791ba19a6eSNaohiro Aota 	{
3801ba19a6eSNaohiro Aota 		.description = "RAID0: fail: seq zone and conv zone, larger last_alloc",
3811ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID0,
3821ba19a6eSNaohiro Aota 		.num_stripes = 2,
3831ba19a6eSNaohiro Aota 		.alloc_offsets = {
3841ba19a6eSNaohiro Aota 			SZ_1M, WP_CONVENTIONAL,
3851ba19a6eSNaohiro Aota 		},
3861ba19a6eSNaohiro Aota 		.last_alloc = SZ_2M + BTRFS_STRIPE_LEN * 2,
3871ba19a6eSNaohiro Aota 		.expected_result = -EIO,
3881ba19a6eSNaohiro Aota 	},
3891ba19a6eSNaohiro Aota 
3901ba19a6eSNaohiro Aota 	/* RAID0, 4 stripes with seq zones and conv zones. */
3911ba19a6eSNaohiro Aota 	{
3921ba19a6eSNaohiro Aota 		.description = "RAID0: stripes [2, 2, ?, ?] last_alloc = 6",
3931ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID0,
3941ba19a6eSNaohiro Aota 		.num_stripes = 4,
3951ba19a6eSNaohiro Aota 		.alloc_offsets = {
3961ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
3971ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
3981ba19a6eSNaohiro Aota 		},
3991ba19a6eSNaohiro Aota 		.last_alloc = BTRFS_STRIPE_LEN * 6,
4001ba19a6eSNaohiro Aota 		.expected_alloc_offset = BTRFS_STRIPE_LEN * 6,
4011ba19a6eSNaohiro Aota 	},
4021ba19a6eSNaohiro Aota 	{
4031ba19a6eSNaohiro Aota 		.description = "RAID0: stripes [2, 2, ?, ?] last_alloc = 7.5",
4041ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID0,
4051ba19a6eSNaohiro Aota 		.num_stripes = 4,
4061ba19a6eSNaohiro Aota 		.alloc_offsets = {
4071ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
4081ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
4091ba19a6eSNaohiro Aota 		},
4101ba19a6eSNaohiro Aota 		.last_alloc = BTRFS_STRIPE_LEN * 7 + HALF_STRIPE_LEN,
4111ba19a6eSNaohiro Aota 		.expected_alloc_offset = BTRFS_STRIPE_LEN * 7 + HALF_STRIPE_LEN,
4121ba19a6eSNaohiro Aota 	},
4131ba19a6eSNaohiro Aota 	{
4141ba19a6eSNaohiro Aota 		.description = "RAID0: stripes [3, ?, ?, ?] last_alloc = 1",
4151ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID0,
4161ba19a6eSNaohiro Aota 		.num_stripes = 4,
4171ba19a6eSNaohiro Aota 		.alloc_offsets = {
4181ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 3, WP_CONVENTIONAL,
4191ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
4201ba19a6eSNaohiro Aota 		},
4211ba19a6eSNaohiro Aota 		.last_alloc = BTRFS_STRIPE_LEN,
4221ba19a6eSNaohiro Aota 		.expected_alloc_offset = BTRFS_STRIPE_LEN * 9,
4231ba19a6eSNaohiro Aota 	},
4241ba19a6eSNaohiro Aota 	{
4251ba19a6eSNaohiro Aota 		.description = "RAID0: stripes [2, ?, 1, ?] last_alloc = 5",
4261ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID0,
4271ba19a6eSNaohiro Aota 		.num_stripes = 4,
4281ba19a6eSNaohiro Aota 		.alloc_offsets = {
4291ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 2, WP_CONVENTIONAL,
4301ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN, WP_CONVENTIONAL,
4311ba19a6eSNaohiro Aota 		},
4321ba19a6eSNaohiro Aota 		.last_alloc = BTRFS_STRIPE_LEN * 5,
4331ba19a6eSNaohiro Aota 		.expected_alloc_offset = BTRFS_STRIPE_LEN * 5,
4341ba19a6eSNaohiro Aota 	},
4351ba19a6eSNaohiro Aota 	{
4361ba19a6eSNaohiro Aota 		.description = "RAID0: fail: stripes [2, ?, 1, ?] last_alloc = 7",
4371ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID0,
4381ba19a6eSNaohiro Aota 		.num_stripes = 4,
4391ba19a6eSNaohiro Aota 		.alloc_offsets = {
4401ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 2, WP_CONVENTIONAL,
4411ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN, WP_CONVENTIONAL,
4421ba19a6eSNaohiro Aota 		},
4431ba19a6eSNaohiro Aota 		.last_alloc = BTRFS_STRIPE_LEN * 7,
4441ba19a6eSNaohiro Aota 		.expected_result = -EIO,
4451ba19a6eSNaohiro Aota 	},
4461ba19a6eSNaohiro Aota 
4471ba19a6eSNaohiro Aota 	/* RAID10 */
4481ba19a6eSNaohiro Aota 	/* Normal case */
4491ba19a6eSNaohiro Aota 	{
4501ba19a6eSNaohiro Aota 		.description = "RAID10: initial partial write",
4511ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID10,
4521ba19a6eSNaohiro Aota 		.num_stripes = 4,
4531ba19a6eSNaohiro Aota 		.alloc_offsets = {
4541ba19a6eSNaohiro Aota 			HALF_STRIPE_LEN, HALF_STRIPE_LEN, 0, 0,
4551ba19a6eSNaohiro Aota 		},
4561ba19a6eSNaohiro Aota 		.expected_alloc_offset = HALF_STRIPE_LEN,
4571ba19a6eSNaohiro Aota 	},
4581ba19a6eSNaohiro Aota 	{
4591ba19a6eSNaohiro Aota 		.description = "RAID10: while in second stripe",
4601ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID10,
4611ba19a6eSNaohiro Aota 		.num_stripes = 8,
4621ba19a6eSNaohiro Aota 		.alloc_offsets = {
4631ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
4641ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN + HALF_STRIPE_LEN,
4651ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN + HALF_STRIPE_LEN,
4661ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
4671ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
4681ba19a6eSNaohiro Aota 		},
4691ba19a6eSNaohiro Aota 		.expected_alloc_offset = BTRFS_STRIPE_LEN * 5 + HALF_STRIPE_LEN,
4701ba19a6eSNaohiro Aota 	},
4711ba19a6eSNaohiro Aota 	{
4721ba19a6eSNaohiro Aota 		.description = "RAID10: one stripe advanced",
4731ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID10,
4741ba19a6eSNaohiro Aota 		.num_stripes = 4,
4751ba19a6eSNaohiro Aota 		.alloc_offsets = {
4761ba19a6eSNaohiro Aota 			SZ_1M + BTRFS_STRIPE_LEN, SZ_1M + BTRFS_STRIPE_LEN,
4771ba19a6eSNaohiro Aota 			SZ_1M, SZ_1M,
4781ba19a6eSNaohiro Aota 		},
4791ba19a6eSNaohiro Aota 		.expected_alloc_offset = SZ_2M + BTRFS_STRIPE_LEN,
4801ba19a6eSNaohiro Aota 	},
4811ba19a6eSNaohiro Aota 	{
4821ba19a6eSNaohiro Aota 		.description = "RAID10: one stripe advanced, with conventional zone",
4831ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID10,
4841ba19a6eSNaohiro Aota 		.num_stripes = 4,
4851ba19a6eSNaohiro Aota 		.alloc_offsets = {
4861ba19a6eSNaohiro Aota 			SZ_1M + BTRFS_STRIPE_LEN, WP_CONVENTIONAL,
4871ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, SZ_1M,
4881ba19a6eSNaohiro Aota 		},
4891ba19a6eSNaohiro Aota 		.expected_alloc_offset = SZ_2M + BTRFS_STRIPE_LEN,
4901ba19a6eSNaohiro Aota 	},
4911ba19a6eSNaohiro Aota 	/* Error case: having different write pointers. */
4921ba19a6eSNaohiro Aota 	{
4931ba19a6eSNaohiro Aota 		.description = "RAID10: fail: disordered stripes",
4941ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID10,
4951ba19a6eSNaohiro Aota 		.num_stripes = 8,
4961ba19a6eSNaohiro Aota 		.alloc_offsets = {
4971ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
4981ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
4991ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
5001ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
5011ba19a6eSNaohiro Aota 		},
5021ba19a6eSNaohiro Aota 		.expected_result = -EIO,
5031ba19a6eSNaohiro Aota 	},
5041ba19a6eSNaohiro Aota 	{
5051ba19a6eSNaohiro Aota 		.description = "RAID10: fail: far distance",
5061ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID10,
5071ba19a6eSNaohiro Aota 		.num_stripes = 8,
5081ba19a6eSNaohiro Aota 		.alloc_offsets = {
5091ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 3, BTRFS_STRIPE_LEN * 3,
5101ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
5111ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
5121ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
5131ba19a6eSNaohiro Aota 		},
5141ba19a6eSNaohiro Aota 		.expected_result = -EIO,
5151ba19a6eSNaohiro Aota 	},
5161ba19a6eSNaohiro Aota 	{
5171ba19a6eSNaohiro Aota 		.description = "RAID10: fail: too many partial write",
5181ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID10,
5191ba19a6eSNaohiro Aota 		.num_stripes = 8,
5201ba19a6eSNaohiro Aota 		.alloc_offsets = {
5211ba19a6eSNaohiro Aota 			HALF_STRIPE_LEN, HALF_STRIPE_LEN,
5221ba19a6eSNaohiro Aota 			HALF_STRIPE_LEN, HALF_STRIPE_LEN,
5231ba19a6eSNaohiro Aota 			0, 0, 0, 0,
5241ba19a6eSNaohiro Aota 		},
5251ba19a6eSNaohiro Aota 		.expected_result = -EIO,
5261ba19a6eSNaohiro Aota 	},
5271ba19a6eSNaohiro Aota 	/*
5281ba19a6eSNaohiro Aota 	 * Error case: Partial missing device in RAID0 level is not allowed even on
5291ba19a6eSNaohiro Aota 	 * non-DEGRADED mount.
5301ba19a6eSNaohiro Aota 	 */
5311ba19a6eSNaohiro Aota 	{
5321ba19a6eSNaohiro Aota 		.description = "RAID10: fail: missing device on DEGRADED",
5331ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID10,
5341ba19a6eSNaohiro Aota 		.num_stripes = 4,
5351ba19a6eSNaohiro Aota 		.alloc_offsets = {
5361ba19a6eSNaohiro Aota 			SZ_1M, SZ_1M,
5371ba19a6eSNaohiro Aota 			WP_MISSING_DEV, WP_MISSING_DEV,
5381ba19a6eSNaohiro Aota 		},
5391ba19a6eSNaohiro Aota 		.degraded = true,
5401ba19a6eSNaohiro Aota 		.expected_result = -EIO,
5411ba19a6eSNaohiro Aota 	},
5421ba19a6eSNaohiro Aota 
5431ba19a6eSNaohiro Aota 	/*
5441ba19a6eSNaohiro Aota 	 * One sequential zone and one conventional zone, having matching
5451ba19a6eSNaohiro Aota 	 * last_alloc.
5461ba19a6eSNaohiro Aota 	 */
5471ba19a6eSNaohiro Aota 	{
5481ba19a6eSNaohiro Aota 		.description = "RAID10: seq zone and conv zone, partially written stripe",
5491ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID10,
5501ba19a6eSNaohiro Aota 		.num_stripes = 4,
5511ba19a6eSNaohiro Aota 		.alloc_offsets = {
5521ba19a6eSNaohiro Aota 			SZ_1M, SZ_1M,
5531ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
5541ba19a6eSNaohiro Aota 		},
5551ba19a6eSNaohiro Aota 		.last_alloc = SZ_2M - SZ_4K,
5561ba19a6eSNaohiro Aota 		.expected_alloc_offset = SZ_2M - SZ_4K,
5571ba19a6eSNaohiro Aota 	},
5581ba19a6eSNaohiro Aota 	{
5591ba19a6eSNaohiro Aota 		.description = "RAID10: conv zone and seq zone, partially written stripe",
5601ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID10,
5611ba19a6eSNaohiro Aota 		.num_stripes = 4,
5621ba19a6eSNaohiro Aota 		.alloc_offsets = {
5631ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
5641ba19a6eSNaohiro Aota 			SZ_1M, SZ_1M,
5651ba19a6eSNaohiro Aota 		},
5661ba19a6eSNaohiro Aota 		.last_alloc = SZ_2M + SZ_4K,
5671ba19a6eSNaohiro Aota 		.expected_alloc_offset = SZ_2M + SZ_4K,
5681ba19a6eSNaohiro Aota 	},
5691ba19a6eSNaohiro Aota 	/*
5701ba19a6eSNaohiro Aota 	 * Error case: one sequential and one conventional zone, but having larger
5711ba19a6eSNaohiro Aota 	 * last_alloc than write pointer.
5721ba19a6eSNaohiro Aota 	 */
5731ba19a6eSNaohiro Aota 	{
5741ba19a6eSNaohiro Aota 		.description = "RAID10: fail: seq zone and conv zone, larger last_alloc",
5751ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID10,
5761ba19a6eSNaohiro Aota 		.num_stripes = 4,
5771ba19a6eSNaohiro Aota 		.alloc_offsets = {
5781ba19a6eSNaohiro Aota 			SZ_1M, SZ_1M,
5791ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
5801ba19a6eSNaohiro Aota 		},
5811ba19a6eSNaohiro Aota 		.last_alloc = SZ_2M + BTRFS_STRIPE_LEN * 2,
5821ba19a6eSNaohiro Aota 		.expected_result = -EIO,
5831ba19a6eSNaohiro Aota 	},
5841ba19a6eSNaohiro Aota 
5851ba19a6eSNaohiro Aota 	/* RAID10, 4 stripes with seq zones and conv zones. */
5861ba19a6eSNaohiro Aota 	{
5871ba19a6eSNaohiro Aota 		.description = "RAID10: stripes [2, 2, ?, ?] last_alloc = 6",
5881ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID10,
5891ba19a6eSNaohiro Aota 		.num_stripes = 8,
5901ba19a6eSNaohiro Aota 		.alloc_offsets = {
5911ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
5921ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
5931ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
5941ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
5951ba19a6eSNaohiro Aota 		},
5961ba19a6eSNaohiro Aota 		.last_alloc = BTRFS_STRIPE_LEN * 6,
5971ba19a6eSNaohiro Aota 		.expected_alloc_offset = BTRFS_STRIPE_LEN * 6,
5981ba19a6eSNaohiro Aota 	},
5991ba19a6eSNaohiro Aota 	{
6001ba19a6eSNaohiro Aota 		.description = "RAID10: stripes [2, 2, ?, ?] last_alloc = 7.5",
6011ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID10,
6021ba19a6eSNaohiro Aota 		.num_stripes = 8,
6031ba19a6eSNaohiro Aota 		.alloc_offsets = {
6041ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
6051ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
6061ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
6071ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
6081ba19a6eSNaohiro Aota 		},
6091ba19a6eSNaohiro Aota 		.last_alloc = BTRFS_STRIPE_LEN * 7 + HALF_STRIPE_LEN,
6101ba19a6eSNaohiro Aota 		.expected_alloc_offset = BTRFS_STRIPE_LEN * 7 + HALF_STRIPE_LEN,
6111ba19a6eSNaohiro Aota 	},
6121ba19a6eSNaohiro Aota 	{
6131ba19a6eSNaohiro Aota 		.description = "RAID10: stripes [3, ?, ?, ?] last_alloc = 1",
6141ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID10,
6151ba19a6eSNaohiro Aota 		.num_stripes = 8,
6161ba19a6eSNaohiro Aota 		.alloc_offsets = {
6171ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 3, BTRFS_STRIPE_LEN * 3,
6181ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
6191ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
6201ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
6211ba19a6eSNaohiro Aota 		},
6221ba19a6eSNaohiro Aota 		.last_alloc = BTRFS_STRIPE_LEN,
6231ba19a6eSNaohiro Aota 		.expected_alloc_offset = BTRFS_STRIPE_LEN * 9,
6241ba19a6eSNaohiro Aota 	},
6251ba19a6eSNaohiro Aota 	{
6261ba19a6eSNaohiro Aota 		.description = "RAID10: stripes [2, ?, 1, ?] last_alloc = 5",
6271ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID10,
6281ba19a6eSNaohiro Aota 		.num_stripes = 8,
6291ba19a6eSNaohiro Aota 		.alloc_offsets = {
6301ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
6311ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
6321ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
6331ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
6341ba19a6eSNaohiro Aota 		},
6351ba19a6eSNaohiro Aota 		.last_alloc = BTRFS_STRIPE_LEN * 5,
6361ba19a6eSNaohiro Aota 		.expected_alloc_offset = BTRFS_STRIPE_LEN * 5,
6371ba19a6eSNaohiro Aota 	},
6381ba19a6eSNaohiro Aota 	{
6391ba19a6eSNaohiro Aota 		.description = "RAID10: fail: stripes [2, ?, 1, ?] last_alloc = 7",
6401ba19a6eSNaohiro Aota 		.raid_type = BTRFS_BLOCK_GROUP_RAID10,
6411ba19a6eSNaohiro Aota 		.num_stripes = 8,
6421ba19a6eSNaohiro Aota 		.alloc_offsets = {
6431ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
6441ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
6451ba19a6eSNaohiro Aota 			BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
6461ba19a6eSNaohiro Aota 			WP_CONVENTIONAL, WP_CONVENTIONAL,
6471ba19a6eSNaohiro Aota 		},
6481ba19a6eSNaohiro Aota 		.last_alloc = BTRFS_STRIPE_LEN * 7,
6491ba19a6eSNaohiro Aota 		.expected_result = -EIO,
6501ba19a6eSNaohiro Aota 	},
6511ba19a6eSNaohiro Aota };
6521ba19a6eSNaohiro Aota 
6531ba19a6eSNaohiro Aota int btrfs_test_zoned(void)
6541ba19a6eSNaohiro Aota {
6551ba19a6eSNaohiro Aota 	struct btrfs_fs_info *fs_info __free(btrfs_free_dummy_fs_info) = NULL;
6561ba19a6eSNaohiro Aota 	int ret;
6571ba19a6eSNaohiro Aota 
6581ba19a6eSNaohiro Aota 	test_msg("running zoned tests (error messages are expected)");
6591ba19a6eSNaohiro Aota 
6601ba19a6eSNaohiro Aota 	fs_info = btrfs_alloc_dummy_fs_info(PAGE_SIZE, PAGE_SIZE);
6611ba19a6eSNaohiro Aota 	if (!fs_info) {
6621ba19a6eSNaohiro Aota 		test_std_err(TEST_ALLOC_FS_INFO);
6631ba19a6eSNaohiro Aota 		return -ENOMEM;
6641ba19a6eSNaohiro Aota 	}
6651ba19a6eSNaohiro Aota 
6661ba19a6eSNaohiro Aota 	for (int i = 0; i < ARRAY_SIZE(load_zone_info_tests); i++) {
6671ba19a6eSNaohiro Aota 		ret = test_load_zone_info(fs_info, &load_zone_info_tests[i]);
6681ba19a6eSNaohiro Aota 		if (ret) {
6691ba19a6eSNaohiro Aota 			test_err("test case \"%s\" failed", load_zone_info_tests[i].description);
6701ba19a6eSNaohiro Aota 			return ret;
6711ba19a6eSNaohiro Aota 		}
6721ba19a6eSNaohiro Aota 	}
6731ba19a6eSNaohiro Aota 
6741ba19a6eSNaohiro Aota 	return 0;
6751ba19a6eSNaohiro Aota }
676