Skip to content

Commit 1e85aa9

Browse files
naotakdave
authored andcommitted
btrfs-progs: zoned: fix alloc_offset calculation for partly conventional block groups
When one of two zones composing a DUP block group is a conventional zone, we have the zone_info[i]->alloc_offset = WP_CONVENTIONAL. That will, of course, not match the write pointer of the other zone, and fails that block group. This commit solves that issue by properly recovering the emulated write pointer from the last allocated extent. The offset for the SINGLE, DUP, and RAID1 are straight-forward: it is same as the end of last allocated extent. The RAID0 and RAID10 are a bit tricky that we need to do the math of striping. Reviewed-by: Johannes Thumshirn <[email protected]> Signed-off-by: Naohiro Aota <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 5042af1 commit 1e85aa9

File tree

1 file changed

+51
-14
lines changed

1 file changed

+51
-14
lines changed

kernel-shared/zoned.c

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,7 @@ static int btrfs_load_block_group_dup(struct btrfs_fs_info *fs_info,
981981
struct btrfs_block_group *bg,
982982
struct map_lookup *map,
983983
struct zone_info *zone_info,
984-
unsigned long *active)
984+
unsigned long *active, u64 last_alloc)
985985
{
986986
if ((map->type & BTRFS_BLOCK_GROUP_DATA) && !fs_info->stripe_root) {
987987
btrfs_err(fs_info, "zoned: data DUP profile needs raid-stripe-tree");
@@ -1002,6 +1002,12 @@ static int btrfs_load_block_group_dup(struct btrfs_fs_info *fs_info,
10021002
zone_info[1].physical);
10031003
return -EIO;
10041004
}
1005+
1006+
if (zone_info[0].alloc_offset == WP_CONVENTIONAL)
1007+
zone_info[0].alloc_offset = last_alloc;
1008+
if (zone_info[1].alloc_offset == WP_CONVENTIONAL)
1009+
zone_info[1].alloc_offset = last_alloc;
1010+
10051011
if (zone_info[0].alloc_offset != zone_info[1].alloc_offset) {
10061012
btrfs_err(fs_info,
10071013
"zoned: write pointer offset mismatch of zones in DUP profile");
@@ -1022,7 +1028,7 @@ static int btrfs_load_block_group_raid1(struct btrfs_fs_info *fs_info,
10221028
struct btrfs_block_group *bg,
10231029
struct map_lookup *map,
10241030
struct zone_info *zone_info,
1025-
unsigned long *active)
1031+
unsigned long *active, u64 last_alloc)
10261032
{
10271033
int i;
10281034

@@ -1036,9 +1042,10 @@ static int btrfs_load_block_group_raid1(struct btrfs_fs_info *fs_info,
10361042
bg->zone_capacity = min_not_zero(zone_info[0].capacity, zone_info[1].capacity);
10371043

10381044
for (i = 0; i < map->num_stripes; i++) {
1039-
if (zone_info[i].alloc_offset == WP_MISSING_DEV ||
1040-
zone_info[i].alloc_offset == WP_CONVENTIONAL)
1045+
if (zone_info[i].alloc_offset == WP_MISSING_DEV)
10411046
continue;
1047+
if (zone_info[i].alloc_offset == WP_CONVENTIONAL)
1048+
zone_info[i].alloc_offset = last_alloc;
10421049

10431050
if (zone_info[0].alloc_offset != zone_info[i].alloc_offset) {
10441051
btrfs_err(fs_info,
@@ -1066,7 +1073,7 @@ static int btrfs_load_block_group_raid0(struct btrfs_fs_info *fs_info,
10661073
struct btrfs_block_group *bg,
10671074
struct map_lookup *map,
10681075
struct zone_info *zone_info,
1069-
unsigned long *active)
1076+
unsigned long *active, u64 last_alloc)
10701077
{
10711078
if ((map->type & BTRFS_BLOCK_GROUP_DATA) && !fs_info->stripe_root) {
10721079
btrfs_err(fs_info, "zoned: data %s needs raid-stripe-tree",
@@ -1075,9 +1082,24 @@ static int btrfs_load_block_group_raid0(struct btrfs_fs_info *fs_info,
10751082
}
10761083

10771084
for (int i = 0; i < map->num_stripes; i++) {
1078-
if (zone_info[i].alloc_offset == WP_MISSING_DEV ||
1079-
zone_info[i].alloc_offset == WP_CONVENTIONAL)
1085+
if (zone_info[i].alloc_offset == WP_MISSING_DEV)
10801086
continue;
1087+
if (zone_info[i].alloc_offset == WP_CONVENTIONAL) {
1088+
u64 stripe_nr, full_stripe_nr;
1089+
u64 stripe_offset;
1090+
int stripe_index;
1091+
1092+
stripe_nr = last_alloc / map->stripe_len;
1093+
stripe_offset = stripe_nr * map->stripe_len;
1094+
full_stripe_nr = stripe_nr / map->num_stripes;
1095+
stripe_index = stripe_nr % map->num_stripes;
1096+
1097+
zone_info[i].alloc_offset = full_stripe_nr * map->stripe_len;
1098+
if (stripe_index > i)
1099+
zone_info[i].alloc_offset += map->stripe_len;
1100+
else if (stripe_index == i)
1101+
zone_info[i].alloc_offset += (last_alloc - stripe_offset);
1102+
}
10811103

10821104
if (test_bit(0, active) != test_bit(i, active)) {
10831105
return -EIO;
@@ -1096,7 +1118,7 @@ static int btrfs_load_block_group_raid10(struct btrfs_fs_info *fs_info,
10961118
struct btrfs_block_group *bg,
10971119
struct map_lookup *map,
10981120
struct zone_info *zone_info,
1099-
unsigned long *active)
1121+
unsigned long *active, u64 last_alloc)
11001122
{
11011123
if ((map->type & BTRFS_BLOCK_GROUP_DATA) && !fs_info->stripe_root) {
11021124
btrfs_err(fs_info, "zoned: data %s needs raid-stripe-tree",
@@ -1105,9 +1127,24 @@ static int btrfs_load_block_group_raid10(struct btrfs_fs_info *fs_info,
11051127
}
11061128

11071129
for (int i = 0; i < map->num_stripes; i++) {
1108-
if (zone_info[i].alloc_offset == WP_MISSING_DEV ||
1109-
zone_info[i].alloc_offset == WP_CONVENTIONAL)
1130+
if (zone_info[i].alloc_offset == WP_MISSING_DEV)
11101131
continue;
1132+
if (zone_info[i].alloc_offset == WP_CONVENTIONAL) {
1133+
u64 stripe_nr, full_stripe_nr;
1134+
u64 stripe_offset;
1135+
int stripe_index;
1136+
1137+
stripe_nr = last_alloc / map->stripe_len;
1138+
stripe_offset = stripe_nr * map->stripe_len;
1139+
full_stripe_nr = stripe_nr / (map->num_stripes / map->sub_stripes);
1140+
stripe_index = stripe_nr % (map->num_stripes / map->sub_stripes);
1141+
1142+
zone_info[i].alloc_offset = full_stripe_nr * map->stripe_len;
1143+
if (stripe_index > (i / map->sub_stripes))
1144+
zone_info[i].alloc_offset += map->stripe_len;
1145+
else if (stripe_index == (i / map->sub_stripes))
1146+
zone_info[i].alloc_offset += (last_alloc - stripe_offset);
1147+
}
11111148

11121149
if (test_bit(0, active) != test_bit(i, active)) {
11131150
return -EIO;
@@ -1214,18 +1251,18 @@ int btrfs_load_block_group_zone_info(struct btrfs_fs_info *fs_info,
12141251
ret = btrfs_load_block_group_single(fs_info, cache, &zone_info[0], active);
12151252
break;
12161253
case BTRFS_BLOCK_GROUP_DUP:
1217-
ret = btrfs_load_block_group_dup(fs_info, cache, map, zone_info, active);
1254+
ret = btrfs_load_block_group_dup(fs_info, cache, map, zone_info, active, last_alloc);
12181255
break;
12191256
case BTRFS_BLOCK_GROUP_RAID1:
12201257
case BTRFS_BLOCK_GROUP_RAID1C3:
12211258
case BTRFS_BLOCK_GROUP_RAID1C4:
1222-
ret = btrfs_load_block_group_raid1(fs_info, cache, map, zone_info, active);
1259+
ret = btrfs_load_block_group_raid1(fs_info, cache, map, zone_info, active, last_alloc);
12231260
break;
12241261
case BTRFS_BLOCK_GROUP_RAID0:
1225-
ret = btrfs_load_block_group_raid0(fs_info, cache, map, zone_info, active);
1262+
ret = btrfs_load_block_group_raid0(fs_info, cache, map, zone_info, active, last_alloc);
12261263
break;
12271264
case BTRFS_BLOCK_GROUP_RAID10:
1228-
ret = btrfs_load_block_group_raid10(fs_info, cache, map, zone_info, active);
1265+
ret = btrfs_load_block_group_raid10(fs_info, cache, map, zone_info, active, last_alloc);
12291266
break;
12301267
case BTRFS_BLOCK_GROUP_RAID5:
12311268
case BTRFS_BLOCK_GROUP_RAID6:

0 commit comments

Comments
 (0)