xref: /linux/fs/xfs/libxfs/xfs_zones.c (revision c148bc7535650fbfa95a1f571b9ffa2ab478ea33)
1720c2d58SChristoph Hellwig // SPDX-License-Identifier: GPL-2.0
2720c2d58SChristoph Hellwig /*
3720c2d58SChristoph Hellwig  * Copyright (c) 2023-2025 Christoph Hellwig.
4720c2d58SChristoph Hellwig  * Copyright (c) 2024-2025, Western Digital Corporation or its affiliates.
5720c2d58SChristoph Hellwig  */
6720c2d58SChristoph Hellwig #include "xfs.h"
7720c2d58SChristoph Hellwig #include "xfs_fs.h"
8720c2d58SChristoph Hellwig #include "xfs_shared.h"
9720c2d58SChristoph Hellwig #include "xfs_format.h"
10720c2d58SChristoph Hellwig #include "xfs_log_format.h"
11720c2d58SChristoph Hellwig #include "xfs_trans_resv.h"
12720c2d58SChristoph Hellwig #include "xfs_mount.h"
13720c2d58SChristoph Hellwig #include "xfs_inode.h"
14720c2d58SChristoph Hellwig #include "xfs_rtgroup.h"
15720c2d58SChristoph Hellwig #include "xfs_zones.h"
16720c2d58SChristoph Hellwig 
17720c2d58SChristoph Hellwig static bool
xfs_zone_validate_empty(struct blk_zone * zone,struct xfs_rtgroup * rtg,xfs_rgblock_t * write_pointer)18720c2d58SChristoph Hellwig xfs_zone_validate_empty(
19720c2d58SChristoph Hellwig 	struct blk_zone		*zone,
20720c2d58SChristoph Hellwig 	struct xfs_rtgroup	*rtg,
21720c2d58SChristoph Hellwig 	xfs_rgblock_t		*write_pointer)
22720c2d58SChristoph Hellwig {
23720c2d58SChristoph Hellwig 	struct xfs_mount	*mp = rtg_mount(rtg);
24720c2d58SChristoph Hellwig 
25720c2d58SChristoph Hellwig 	if (rtg_rmap(rtg)->i_used_blocks > 0) {
26720c2d58SChristoph Hellwig 		xfs_warn(mp, "empty zone %u has non-zero used counter (0x%x).",
27720c2d58SChristoph Hellwig 			 rtg_rgno(rtg), rtg_rmap(rtg)->i_used_blocks);
28720c2d58SChristoph Hellwig 		return false;
29720c2d58SChristoph Hellwig 	}
30720c2d58SChristoph Hellwig 
31720c2d58SChristoph Hellwig 	*write_pointer = 0;
32720c2d58SChristoph Hellwig 	return true;
33720c2d58SChristoph Hellwig }
34720c2d58SChristoph Hellwig 
35720c2d58SChristoph Hellwig static bool
xfs_zone_validate_wp(struct blk_zone * zone,struct xfs_rtgroup * rtg,xfs_rgblock_t * write_pointer)36720c2d58SChristoph Hellwig xfs_zone_validate_wp(
37720c2d58SChristoph Hellwig 	struct blk_zone		*zone,
38720c2d58SChristoph Hellwig 	struct xfs_rtgroup	*rtg,
39720c2d58SChristoph Hellwig 	xfs_rgblock_t		*write_pointer)
40720c2d58SChristoph Hellwig {
41720c2d58SChristoph Hellwig 	struct xfs_mount	*mp = rtg_mount(rtg);
42720c2d58SChristoph Hellwig 	xfs_rtblock_t		wp_fsb = xfs_daddr_to_rtb(mp, zone->wp);
43720c2d58SChristoph Hellwig 
44720c2d58SChristoph Hellwig 	if (rtg_rmap(rtg)->i_used_blocks > rtg->rtg_extents) {
45720c2d58SChristoph Hellwig 		xfs_warn(mp, "zone %u has too large used counter (0x%x).",
46720c2d58SChristoph Hellwig 			 rtg_rgno(rtg), rtg_rmap(rtg)->i_used_blocks);
47720c2d58SChristoph Hellwig 		return false;
48720c2d58SChristoph Hellwig 	}
49720c2d58SChristoph Hellwig 
50720c2d58SChristoph Hellwig 	if (xfs_rtb_to_rgno(mp, wp_fsb) != rtg_rgno(rtg)) {
51720c2d58SChristoph Hellwig 		xfs_warn(mp, "zone %u write pointer (0x%llx) outside of zone.",
52720c2d58SChristoph Hellwig 			 rtg_rgno(rtg), wp_fsb);
53720c2d58SChristoph Hellwig 		return false;
54720c2d58SChristoph Hellwig 	}
55720c2d58SChristoph Hellwig 
56720c2d58SChristoph Hellwig 	*write_pointer = xfs_rtb_to_rgbno(mp, wp_fsb);
57720c2d58SChristoph Hellwig 	if (*write_pointer >= rtg->rtg_extents) {
58720c2d58SChristoph Hellwig 		xfs_warn(mp, "zone %u has invalid write pointer (0x%x).",
59720c2d58SChristoph Hellwig 			 rtg_rgno(rtg), *write_pointer);
60720c2d58SChristoph Hellwig 		return false;
61720c2d58SChristoph Hellwig 	}
62720c2d58SChristoph Hellwig 
63720c2d58SChristoph Hellwig 	return true;
64720c2d58SChristoph Hellwig }
65720c2d58SChristoph Hellwig 
66720c2d58SChristoph Hellwig static bool
xfs_zone_validate_full(struct blk_zone * zone,struct xfs_rtgroup * rtg,xfs_rgblock_t * write_pointer)67720c2d58SChristoph Hellwig xfs_zone_validate_full(
68720c2d58SChristoph Hellwig 	struct blk_zone		*zone,
69720c2d58SChristoph Hellwig 	struct xfs_rtgroup	*rtg,
70720c2d58SChristoph Hellwig 	xfs_rgblock_t		*write_pointer)
71720c2d58SChristoph Hellwig {
72720c2d58SChristoph Hellwig 	struct xfs_mount	*mp = rtg_mount(rtg);
73720c2d58SChristoph Hellwig 
74720c2d58SChristoph Hellwig 	if (rtg_rmap(rtg)->i_used_blocks > rtg->rtg_extents) {
75720c2d58SChristoph Hellwig 		xfs_warn(mp, "zone %u has too large used counter (0x%x).",
76720c2d58SChristoph Hellwig 			 rtg_rgno(rtg), rtg_rmap(rtg)->i_used_blocks);
77720c2d58SChristoph Hellwig 		return false;
78720c2d58SChristoph Hellwig 	}
79720c2d58SChristoph Hellwig 
80720c2d58SChristoph Hellwig 	*write_pointer = rtg->rtg_extents;
81720c2d58SChristoph Hellwig 	return true;
82720c2d58SChristoph Hellwig }
83720c2d58SChristoph Hellwig 
84720c2d58SChristoph Hellwig static bool
xfs_zone_validate_seq(struct blk_zone * zone,struct xfs_rtgroup * rtg,xfs_rgblock_t * write_pointer)85720c2d58SChristoph Hellwig xfs_zone_validate_seq(
86720c2d58SChristoph Hellwig 	struct blk_zone		*zone,
87720c2d58SChristoph Hellwig 	struct xfs_rtgroup	*rtg,
88720c2d58SChristoph Hellwig 	xfs_rgblock_t		*write_pointer)
89720c2d58SChristoph Hellwig {
90720c2d58SChristoph Hellwig 	struct xfs_mount	*mp = rtg_mount(rtg);
91720c2d58SChristoph Hellwig 
92720c2d58SChristoph Hellwig 	switch (zone->cond) {
93720c2d58SChristoph Hellwig 	case BLK_ZONE_COND_EMPTY:
94720c2d58SChristoph Hellwig 		return xfs_zone_validate_empty(zone, rtg, write_pointer);
95720c2d58SChristoph Hellwig 	case BLK_ZONE_COND_IMP_OPEN:
96720c2d58SChristoph Hellwig 	case BLK_ZONE_COND_EXP_OPEN:
97720c2d58SChristoph Hellwig 	case BLK_ZONE_COND_CLOSED:
98720c2d58SChristoph Hellwig 		return xfs_zone_validate_wp(zone, rtg, write_pointer);
99720c2d58SChristoph Hellwig 	case BLK_ZONE_COND_FULL:
100720c2d58SChristoph Hellwig 		return xfs_zone_validate_full(zone, rtg, write_pointer);
101720c2d58SChristoph Hellwig 	case BLK_ZONE_COND_NOT_WP:
102720c2d58SChristoph Hellwig 	case BLK_ZONE_COND_OFFLINE:
103720c2d58SChristoph Hellwig 	case BLK_ZONE_COND_READONLY:
104720c2d58SChristoph Hellwig 		xfs_warn(mp, "zone %u has unsupported zone condition 0x%x.",
105720c2d58SChristoph Hellwig 			rtg_rgno(rtg), zone->cond);
106720c2d58SChristoph Hellwig 		return false;
107720c2d58SChristoph Hellwig 	default:
108720c2d58SChristoph Hellwig 		xfs_warn(mp, "zone %u has unknown zone condition 0x%x.",
109720c2d58SChristoph Hellwig 			rtg_rgno(rtg), zone->cond);
110720c2d58SChristoph Hellwig 		return false;
111720c2d58SChristoph Hellwig 	}
112720c2d58SChristoph Hellwig }
113720c2d58SChristoph Hellwig 
114720c2d58SChristoph Hellwig static bool
xfs_zone_validate_conv(struct blk_zone * zone,struct xfs_rtgroup * rtg)115720c2d58SChristoph Hellwig xfs_zone_validate_conv(
116720c2d58SChristoph Hellwig 	struct blk_zone		*zone,
117720c2d58SChristoph Hellwig 	struct xfs_rtgroup	*rtg)
118720c2d58SChristoph Hellwig {
119720c2d58SChristoph Hellwig 	struct xfs_mount	*mp = rtg_mount(rtg);
120720c2d58SChristoph Hellwig 
121720c2d58SChristoph Hellwig 	switch (zone->cond) {
122720c2d58SChristoph Hellwig 	case BLK_ZONE_COND_NOT_WP:
123720c2d58SChristoph Hellwig 		return true;
124720c2d58SChristoph Hellwig 	default:
125720c2d58SChristoph Hellwig 		xfs_warn(mp,
126720c2d58SChristoph Hellwig "conventional zone %u has unsupported zone condition 0x%x.",
127720c2d58SChristoph Hellwig 			 rtg_rgno(rtg), zone->cond);
128720c2d58SChristoph Hellwig 		return false;
129720c2d58SChristoph Hellwig 	}
130720c2d58SChristoph Hellwig }
131720c2d58SChristoph Hellwig 
132720c2d58SChristoph Hellwig bool
xfs_zone_validate(struct blk_zone * zone,struct xfs_rtgroup * rtg,xfs_rgblock_t * write_pointer)133720c2d58SChristoph Hellwig xfs_zone_validate(
134720c2d58SChristoph Hellwig 	struct blk_zone		*zone,
135720c2d58SChristoph Hellwig 	struct xfs_rtgroup	*rtg,
136720c2d58SChristoph Hellwig 	xfs_rgblock_t		*write_pointer)
137720c2d58SChristoph Hellwig {
138720c2d58SChristoph Hellwig 	struct xfs_mount	*mp = rtg_mount(rtg);
139720c2d58SChristoph Hellwig 	struct xfs_groups	*g = &mp->m_groups[XG_TYPE_RTG];
140*97c69ba1SChristoph Hellwig 	uint32_t		expected_size;
141720c2d58SChristoph Hellwig 
142720c2d58SChristoph Hellwig 	/*
143720c2d58SChristoph Hellwig 	 * Check that the zone capacity matches the rtgroup size stored in the
144720c2d58SChristoph Hellwig 	 * superblock.  Note that all zones including the last one must have a
145720c2d58SChristoph Hellwig 	 * uniform capacity.
146720c2d58SChristoph Hellwig 	 */
147720c2d58SChristoph Hellwig 	if (XFS_BB_TO_FSB(mp, zone->capacity) != g->blocks) {
148720c2d58SChristoph Hellwig 		xfs_warn(mp,
149720c2d58SChristoph Hellwig "zone %u capacity (0x%llx) does not match RT group size (0x%x).",
150720c2d58SChristoph Hellwig 			rtg_rgno(rtg), XFS_BB_TO_FSB(mp, zone->capacity),
151720c2d58SChristoph Hellwig 			g->blocks);
152720c2d58SChristoph Hellwig 		return false;
153720c2d58SChristoph Hellwig 	}
154720c2d58SChristoph Hellwig 
155*97c69ba1SChristoph Hellwig 	if (g->has_daddr_gaps) {
156*97c69ba1SChristoph Hellwig 		expected_size = 1 << g->blklog;
157*97c69ba1SChristoph Hellwig 	} else {
158*97c69ba1SChristoph Hellwig 		if (zone->len != zone->capacity) {
159*97c69ba1SChristoph Hellwig 			xfs_warn(mp,
160*97c69ba1SChristoph Hellwig "zone %u has capacity != size ((0x%llx vs 0x%llx)",
161*97c69ba1SChristoph Hellwig 				rtg_rgno(rtg),
162*97c69ba1SChristoph Hellwig 				XFS_BB_TO_FSB(mp, zone->len),
163*97c69ba1SChristoph Hellwig 				XFS_BB_TO_FSB(mp, zone->capacity));
164*97c69ba1SChristoph Hellwig 			return false;
165*97c69ba1SChristoph Hellwig 		}
166*97c69ba1SChristoph Hellwig 		expected_size = g->blocks;
167*97c69ba1SChristoph Hellwig 	}
168*97c69ba1SChristoph Hellwig 
169*97c69ba1SChristoph Hellwig 	if (XFS_BB_TO_FSB(mp, zone->len) != expected_size) {
170720c2d58SChristoph Hellwig 		xfs_warn(mp,
171720c2d58SChristoph Hellwig "zone %u length (0x%llx) does match geometry (0x%x).",
172720c2d58SChristoph Hellwig 			rtg_rgno(rtg), XFS_BB_TO_FSB(mp, zone->len),
173*97c69ba1SChristoph Hellwig 			expected_size);
174720c2d58SChristoph Hellwig 	}
175720c2d58SChristoph Hellwig 
176720c2d58SChristoph Hellwig 	switch (zone->type) {
177720c2d58SChristoph Hellwig 	case BLK_ZONE_TYPE_CONVENTIONAL:
178720c2d58SChristoph Hellwig 		return xfs_zone_validate_conv(zone, rtg);
179720c2d58SChristoph Hellwig 	case BLK_ZONE_TYPE_SEQWRITE_REQ:
180720c2d58SChristoph Hellwig 		return xfs_zone_validate_seq(zone, rtg, write_pointer);
181720c2d58SChristoph Hellwig 	default:
182720c2d58SChristoph Hellwig 		xfs_warn(mp, "zoned %u has unsupported type 0x%x.",
183720c2d58SChristoph Hellwig 			rtg_rgno(rtg), zone->type);
184720c2d58SChristoph Hellwig 		return false;
185720c2d58SChristoph Hellwig 	}
186720c2d58SChristoph Hellwig }
187