mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-29 20:58:57 -04:00
Commit2932ba8d9c("slab: Introduce kmalloc_obj() and family") introduced, among many others, the kzalloc_objs() helper, which has some benefits over kcalloc(). Namely, internal introspection of the allocated type now becomes possible, allowing for future alignment-aware choices to be made by the allocator and future hardening work that can be type sensitive. Dropping 'sizeof' comes also as a nice side-effect. Moreover, this also allows us to be in line with the recent tree-wide migration to the kmalloc_obj() and family of helpers. See commit69050f8d6d("treewide: Replace kmalloc with kmalloc_obj for non-scalar types"). Reviewed-by: Kees Cook <kees@kernel.org> Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
676 lines
17 KiB
C
676 lines
17 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2026 Western Digital. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/cleanup.h>
|
|
#include <linux/sizes.h>
|
|
|
|
#include "btrfs-tests.h"
|
|
#include "../space-info.h"
|
|
#include "../volumes.h"
|
|
#include "../zoned.h"
|
|
|
|
#define WP_MISSING_DEV ((u64)-1)
|
|
#define WP_CONVENTIONAL ((u64)-2)
|
|
#define ZONE_SIZE SZ_256M
|
|
|
|
#define HALF_STRIPE_LEN (BTRFS_STRIPE_LEN >> 1)
|
|
|
|
struct load_zone_info_test_vector {
|
|
u64 raid_type;
|
|
u64 num_stripes;
|
|
u64 alloc_offsets[8];
|
|
u64 last_alloc;
|
|
u64 bg_length;
|
|
bool degraded;
|
|
|
|
int expected_result;
|
|
u64 expected_alloc_offset;
|
|
|
|
const char *description;
|
|
};
|
|
|
|
struct zone_info {
|
|
u64 physical;
|
|
u64 capacity;
|
|
u64 alloc_offset;
|
|
};
|
|
|
|
static int test_load_zone_info(struct btrfs_fs_info *fs_info,
|
|
const struct load_zone_info_test_vector *test)
|
|
{
|
|
struct btrfs_block_group *bg __free(btrfs_free_dummy_block_group) = NULL;
|
|
struct btrfs_chunk_map *map __free(btrfs_free_chunk_map) = NULL;
|
|
struct zone_info AUTO_KFREE(zone_info);
|
|
unsigned long AUTO_KFREE(active);
|
|
int ret;
|
|
|
|
bg = btrfs_alloc_dummy_block_group(fs_info, test->bg_length);
|
|
if (!bg) {
|
|
test_std_err(TEST_ALLOC_BLOCK_GROUP);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
map = btrfs_alloc_chunk_map(test->num_stripes, GFP_KERNEL);
|
|
if (!map) {
|
|
test_std_err(TEST_ALLOC_EXTENT_MAP);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
zone_info = kzalloc_objs(*zone_info, test->num_stripes, GFP_KERNEL);
|
|
if (!zone_info) {
|
|
test_err("cannot allocate zone info");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
active = bitmap_zalloc(test->num_stripes, GFP_KERNEL);
|
|
if (!zone_info) {
|
|
test_err("cannot allocate active bitmap");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
map->type = test->raid_type;
|
|
map->num_stripes = test->num_stripes;
|
|
if (test->raid_type == BTRFS_BLOCK_GROUP_RAID10)
|
|
map->sub_stripes = 2;
|
|
for (int i = 0; i < test->num_stripes; i++) {
|
|
zone_info[i].physical = 0;
|
|
zone_info[i].alloc_offset = test->alloc_offsets[i];
|
|
zone_info[i].capacity = ZONE_SIZE;
|
|
if (zone_info[i].alloc_offset && zone_info[i].alloc_offset < ZONE_SIZE)
|
|
__set_bit(i, active);
|
|
}
|
|
if (test->degraded)
|
|
btrfs_set_opt(fs_info->mount_opt, DEGRADED);
|
|
else
|
|
btrfs_clear_opt(fs_info->mount_opt, DEGRADED);
|
|
|
|
ret = btrfs_load_block_group_by_raid_type(bg, map, zone_info, active,
|
|
test->last_alloc);
|
|
|
|
if (ret != test->expected_result) {
|
|
test_err("unexpected return value: ret %d expected %d", ret,
|
|
test->expected_result);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!ret && bg->alloc_offset != test->expected_alloc_offset) {
|
|
test_err("unexpected alloc_offset: alloc_offset %llu expected %llu",
|
|
bg->alloc_offset, test->expected_alloc_offset);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct load_zone_info_test_vector load_zone_info_tests[] = {
|
|
/* SINGLE */
|
|
{
|
|
.description = "SINGLE: load write pointer from sequential zone",
|
|
.raid_type = 0,
|
|
.num_stripes = 1,
|
|
.alloc_offsets = {
|
|
SZ_1M,
|
|
},
|
|
.expected_alloc_offset = SZ_1M,
|
|
},
|
|
/*
|
|
* SINGLE block group on a conventional zone sets last_alloc outside of
|
|
* btrfs_load_block_group_*(). Do not test that case.
|
|
*/
|
|
|
|
/* DUP */
|
|
/* Normal case */
|
|
{
|
|
.description = "DUP: having matching write pointers",
|
|
.raid_type = BTRFS_BLOCK_GROUP_DUP,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
SZ_1M, SZ_1M,
|
|
},
|
|
.expected_alloc_offset = SZ_1M,
|
|
},
|
|
/*
|
|
* One sequential zone and one conventional zone, having matching
|
|
* last_alloc.
|
|
*/
|
|
{
|
|
.description = "DUP: seq zone and conv zone, matching last_alloc",
|
|
.raid_type = BTRFS_BLOCK_GROUP_DUP,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
SZ_1M, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = SZ_1M,
|
|
.expected_alloc_offset = SZ_1M,
|
|
},
|
|
/*
|
|
* One sequential and one conventional zone, but having smaller
|
|
* last_alloc than write pointer.
|
|
*/
|
|
{
|
|
.description = "DUP: seq zone and conv zone, smaller last_alloc",
|
|
.raid_type = BTRFS_BLOCK_GROUP_DUP,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
SZ_1M, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = 0,
|
|
.expected_alloc_offset = SZ_1M,
|
|
},
|
|
/* Error case: having different write pointers. */
|
|
{
|
|
.description = "DUP: fail: different write pointers",
|
|
.raid_type = BTRFS_BLOCK_GROUP_DUP,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
SZ_1M, SZ_2M,
|
|
},
|
|
.expected_result = -EIO,
|
|
},
|
|
/* Error case: partial missing device should not happen on DUP. */
|
|
{
|
|
.description = "DUP: fail: missing device",
|
|
.raid_type = BTRFS_BLOCK_GROUP_DUP,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
SZ_1M, WP_MISSING_DEV,
|
|
},
|
|
.expected_result = -EIO,
|
|
},
|
|
/*
|
|
* Error case: one sequential and one conventional zone, but having larger
|
|
* last_alloc than write pointer.
|
|
*/
|
|
{
|
|
.description = "DUP: fail: seq zone and conv zone, larger last_alloc",
|
|
.raid_type = BTRFS_BLOCK_GROUP_DUP,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
SZ_1M, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = SZ_2M,
|
|
.expected_result = -EIO,
|
|
},
|
|
|
|
/* RAID1 */
|
|
/* Normal case */
|
|
{
|
|
.description = "RAID1: having matching write pointers",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID1,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
SZ_1M, SZ_1M,
|
|
},
|
|
.expected_alloc_offset = SZ_1M,
|
|
},
|
|
/*
|
|
* One sequential zone and one conventional zone, having matching
|
|
* last_alloc.
|
|
*/
|
|
{
|
|
.description = "RAID1: seq zone and conv zone, matching last_alloc",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID1,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
SZ_1M, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = SZ_1M,
|
|
.expected_alloc_offset = SZ_1M,
|
|
},
|
|
/*
|
|
* One sequential and one conventional zone, but having smaller
|
|
* last_alloc than write pointer.
|
|
*/
|
|
{
|
|
.description = "RAID1: seq zone and conv zone, smaller last_alloc",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID1,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
SZ_1M, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = 0,
|
|
.expected_alloc_offset = SZ_1M,
|
|
},
|
|
/* Partial missing device should be recovered on DEGRADED mount */
|
|
{
|
|
.description = "RAID1: fail: missing device on DEGRADED",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID1,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
SZ_1M, WP_MISSING_DEV,
|
|
},
|
|
.degraded = true,
|
|
.expected_alloc_offset = SZ_1M,
|
|
},
|
|
/* Error case: having different write pointers. */
|
|
{
|
|
.description = "RAID1: fail: different write pointers",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID1,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
SZ_1M, SZ_2M,
|
|
},
|
|
.expected_result = -EIO,
|
|
},
|
|
/*
|
|
* Partial missing device is not allowed on non-DEGRADED mount never happen
|
|
* as it is rejected beforehand.
|
|
*/
|
|
/*
|
|
* Error case: one sequential and one conventional zone, but having larger
|
|
* last_alloc than write pointer.
|
|
*/
|
|
{
|
|
.description = "RAID1: fail: seq zone and conv zone, larger last_alloc",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID1,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
SZ_1M, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = SZ_2M,
|
|
.expected_result = -EIO,
|
|
},
|
|
|
|
/* RAID0 */
|
|
/* Normal case */
|
|
{
|
|
.description = "RAID0: initial partial write",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID0,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
HALF_STRIPE_LEN, 0, 0, 0,
|
|
},
|
|
.expected_alloc_offset = HALF_STRIPE_LEN,
|
|
},
|
|
{
|
|
.description = "RAID0: while in second stripe",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID0,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN + HALF_STRIPE_LEN,
|
|
BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
|
|
},
|
|
.expected_alloc_offset = BTRFS_STRIPE_LEN * 5 + HALF_STRIPE_LEN,
|
|
},
|
|
{
|
|
.description = "RAID0: one stripe advanced",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID0,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
SZ_1M + BTRFS_STRIPE_LEN, SZ_1M,
|
|
},
|
|
.expected_alloc_offset = SZ_2M + BTRFS_STRIPE_LEN,
|
|
},
|
|
/* Error case: having different write pointers. */
|
|
{
|
|
.description = "RAID0: fail: disordered stripes",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID0,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN * 2,
|
|
BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
|
|
},
|
|
.expected_result = -EIO,
|
|
},
|
|
{
|
|
.description = "RAID0: fail: far distance",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID0,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
BTRFS_STRIPE_LEN * 3, BTRFS_STRIPE_LEN,
|
|
BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
|
|
},
|
|
.expected_result = -EIO,
|
|
},
|
|
{
|
|
.description = "RAID0: fail: too many partial write",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID0,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
HALF_STRIPE_LEN, HALF_STRIPE_LEN, 0, 0,
|
|
},
|
|
.expected_result = -EIO,
|
|
},
|
|
/*
|
|
* Error case: Partial missing device is not allowed even on non-DEGRADED
|
|
* mount.
|
|
*/
|
|
{
|
|
.description = "RAID0: fail: missing device on DEGRADED",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID0,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
SZ_1M, WP_MISSING_DEV,
|
|
},
|
|
.degraded = true,
|
|
.expected_result = -EIO,
|
|
},
|
|
|
|
/*
|
|
* One sequential zone and one conventional zone, having matching
|
|
* last_alloc.
|
|
*/
|
|
{
|
|
.description = "RAID0: seq zone and conv zone, partially written stripe",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID0,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
SZ_1M, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = SZ_2M - SZ_4K,
|
|
.expected_alloc_offset = SZ_2M - SZ_4K,
|
|
},
|
|
{
|
|
.description = "RAID0: conv zone and seq zone, partially written stripe",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID0,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
WP_CONVENTIONAL, SZ_1M,
|
|
},
|
|
.last_alloc = SZ_2M + SZ_4K,
|
|
.expected_alloc_offset = SZ_2M + SZ_4K,
|
|
},
|
|
/*
|
|
* Error case: one sequential and one conventional zone, but having larger
|
|
* last_alloc than write pointer.
|
|
*/
|
|
{
|
|
.description = "RAID0: fail: seq zone and conv zone, larger last_alloc",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID0,
|
|
.num_stripes = 2,
|
|
.alloc_offsets = {
|
|
SZ_1M, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = SZ_2M + BTRFS_STRIPE_LEN * 2,
|
|
.expected_result = -EIO,
|
|
},
|
|
|
|
/* RAID0, 4 stripes with seq zones and conv zones. */
|
|
{
|
|
.description = "RAID0: stripes [2, 2, ?, ?] last_alloc = 6",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID0,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = BTRFS_STRIPE_LEN * 6,
|
|
.expected_alloc_offset = BTRFS_STRIPE_LEN * 6,
|
|
},
|
|
{
|
|
.description = "RAID0: stripes [2, 2, ?, ?] last_alloc = 7.5",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID0,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = BTRFS_STRIPE_LEN * 7 + HALF_STRIPE_LEN,
|
|
.expected_alloc_offset = BTRFS_STRIPE_LEN * 7 + HALF_STRIPE_LEN,
|
|
},
|
|
{
|
|
.description = "RAID0: stripes [3, ?, ?, ?] last_alloc = 1",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID0,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
BTRFS_STRIPE_LEN * 3, WP_CONVENTIONAL,
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = BTRFS_STRIPE_LEN,
|
|
.expected_alloc_offset = BTRFS_STRIPE_LEN * 9,
|
|
},
|
|
{
|
|
.description = "RAID0: stripes [2, ?, 1, ?] last_alloc = 5",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID0,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
BTRFS_STRIPE_LEN * 2, WP_CONVENTIONAL,
|
|
BTRFS_STRIPE_LEN, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = BTRFS_STRIPE_LEN * 5,
|
|
.expected_alloc_offset = BTRFS_STRIPE_LEN * 5,
|
|
},
|
|
{
|
|
.description = "RAID0: fail: stripes [2, ?, 1, ?] last_alloc = 7",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID0,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
BTRFS_STRIPE_LEN * 2, WP_CONVENTIONAL,
|
|
BTRFS_STRIPE_LEN, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = BTRFS_STRIPE_LEN * 7,
|
|
.expected_result = -EIO,
|
|
},
|
|
|
|
/* RAID10 */
|
|
/* Normal case */
|
|
{
|
|
.description = "RAID10: initial partial write",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID10,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
HALF_STRIPE_LEN, HALF_STRIPE_LEN, 0, 0,
|
|
},
|
|
.expected_alloc_offset = HALF_STRIPE_LEN,
|
|
},
|
|
{
|
|
.description = "RAID10: while in second stripe",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID10,
|
|
.num_stripes = 8,
|
|
.alloc_offsets = {
|
|
BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
|
|
BTRFS_STRIPE_LEN + HALF_STRIPE_LEN,
|
|
BTRFS_STRIPE_LEN + HALF_STRIPE_LEN,
|
|
BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
|
|
BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
|
|
},
|
|
.expected_alloc_offset = BTRFS_STRIPE_LEN * 5 + HALF_STRIPE_LEN,
|
|
},
|
|
{
|
|
.description = "RAID10: one stripe advanced",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID10,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
SZ_1M + BTRFS_STRIPE_LEN, SZ_1M + BTRFS_STRIPE_LEN,
|
|
SZ_1M, SZ_1M,
|
|
},
|
|
.expected_alloc_offset = SZ_2M + BTRFS_STRIPE_LEN,
|
|
},
|
|
{
|
|
.description = "RAID10: one stripe advanced, with conventional zone",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID10,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
SZ_1M + BTRFS_STRIPE_LEN, WP_CONVENTIONAL,
|
|
WP_CONVENTIONAL, SZ_1M,
|
|
},
|
|
.expected_alloc_offset = SZ_2M + BTRFS_STRIPE_LEN,
|
|
},
|
|
/* Error case: having different write pointers. */
|
|
{
|
|
.description = "RAID10: fail: disordered stripes",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID10,
|
|
.num_stripes = 8,
|
|
.alloc_offsets = {
|
|
BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
|
|
BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
|
|
BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
|
|
BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
|
|
},
|
|
.expected_result = -EIO,
|
|
},
|
|
{
|
|
.description = "RAID10: fail: far distance",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID10,
|
|
.num_stripes = 8,
|
|
.alloc_offsets = {
|
|
BTRFS_STRIPE_LEN * 3, BTRFS_STRIPE_LEN * 3,
|
|
BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
|
|
BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
|
|
BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
|
|
},
|
|
.expected_result = -EIO,
|
|
},
|
|
{
|
|
.description = "RAID10: fail: too many partial write",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID10,
|
|
.num_stripes = 8,
|
|
.alloc_offsets = {
|
|
HALF_STRIPE_LEN, HALF_STRIPE_LEN,
|
|
HALF_STRIPE_LEN, HALF_STRIPE_LEN,
|
|
0, 0, 0, 0,
|
|
},
|
|
.expected_result = -EIO,
|
|
},
|
|
/*
|
|
* Error case: Partial missing device in RAID0 level is not allowed even on
|
|
* non-DEGRADED mount.
|
|
*/
|
|
{
|
|
.description = "RAID10: fail: missing device on DEGRADED",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID10,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
SZ_1M, SZ_1M,
|
|
WP_MISSING_DEV, WP_MISSING_DEV,
|
|
},
|
|
.degraded = true,
|
|
.expected_result = -EIO,
|
|
},
|
|
|
|
/*
|
|
* One sequential zone and one conventional zone, having matching
|
|
* last_alloc.
|
|
*/
|
|
{
|
|
.description = "RAID10: seq zone and conv zone, partially written stripe",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID10,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
SZ_1M, SZ_1M,
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = SZ_2M - SZ_4K,
|
|
.expected_alloc_offset = SZ_2M - SZ_4K,
|
|
},
|
|
{
|
|
.description = "RAID10: conv zone and seq zone, partially written stripe",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID10,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
SZ_1M, SZ_1M,
|
|
},
|
|
.last_alloc = SZ_2M + SZ_4K,
|
|
.expected_alloc_offset = SZ_2M + SZ_4K,
|
|
},
|
|
/*
|
|
* Error case: one sequential and one conventional zone, but having larger
|
|
* last_alloc than write pointer.
|
|
*/
|
|
{
|
|
.description = "RAID10: fail: seq zone and conv zone, larger last_alloc",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID10,
|
|
.num_stripes = 4,
|
|
.alloc_offsets = {
|
|
SZ_1M, SZ_1M,
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = SZ_2M + BTRFS_STRIPE_LEN * 2,
|
|
.expected_result = -EIO,
|
|
},
|
|
|
|
/* RAID10, 4 stripes with seq zones and conv zones. */
|
|
{
|
|
.description = "RAID10: stripes [2, 2, ?, ?] last_alloc = 6",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID10,
|
|
.num_stripes = 8,
|
|
.alloc_offsets = {
|
|
BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
|
|
BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = BTRFS_STRIPE_LEN * 6,
|
|
.expected_alloc_offset = BTRFS_STRIPE_LEN * 6,
|
|
},
|
|
{
|
|
.description = "RAID10: stripes [2, 2, ?, ?] last_alloc = 7.5",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID10,
|
|
.num_stripes = 8,
|
|
.alloc_offsets = {
|
|
BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
|
|
BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = BTRFS_STRIPE_LEN * 7 + HALF_STRIPE_LEN,
|
|
.expected_alloc_offset = BTRFS_STRIPE_LEN * 7 + HALF_STRIPE_LEN,
|
|
},
|
|
{
|
|
.description = "RAID10: stripes [3, ?, ?, ?] last_alloc = 1",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID10,
|
|
.num_stripes = 8,
|
|
.alloc_offsets = {
|
|
BTRFS_STRIPE_LEN * 3, BTRFS_STRIPE_LEN * 3,
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = BTRFS_STRIPE_LEN,
|
|
.expected_alloc_offset = BTRFS_STRIPE_LEN * 9,
|
|
},
|
|
{
|
|
.description = "RAID10: stripes [2, ?, 1, ?] last_alloc = 5",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID10,
|
|
.num_stripes = 8,
|
|
.alloc_offsets = {
|
|
BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = BTRFS_STRIPE_LEN * 5,
|
|
.expected_alloc_offset = BTRFS_STRIPE_LEN * 5,
|
|
},
|
|
{
|
|
.description = "RAID10: fail: stripes [2, ?, 1, ?] last_alloc = 7",
|
|
.raid_type = BTRFS_BLOCK_GROUP_RAID10,
|
|
.num_stripes = 8,
|
|
.alloc_offsets = {
|
|
BTRFS_STRIPE_LEN * 2, BTRFS_STRIPE_LEN * 2,
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
BTRFS_STRIPE_LEN, BTRFS_STRIPE_LEN,
|
|
WP_CONVENTIONAL, WP_CONVENTIONAL,
|
|
},
|
|
.last_alloc = BTRFS_STRIPE_LEN * 7,
|
|
.expected_result = -EIO,
|
|
},
|
|
};
|
|
|
|
int btrfs_test_zoned(void)
|
|
{
|
|
struct btrfs_fs_info *fs_info __free(btrfs_free_dummy_fs_info) = NULL;
|
|
int ret;
|
|
|
|
test_msg("running zoned tests (error messages are expected)");
|
|
|
|
fs_info = btrfs_alloc_dummy_fs_info(PAGE_SIZE, PAGE_SIZE);
|
|
if (!fs_info) {
|
|
test_std_err(TEST_ALLOC_FS_INFO);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(load_zone_info_tests); i++) {
|
|
ret = test_load_zone_info(fs_info, &load_zone_info_tests[i]);
|
|
if (ret) {
|
|
test_err("test case \"%s\" failed", load_zone_info_tests[i].description);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|