File Index
Files and directories
Sign in
FILE

xfs_zones.c

File preview with syntax highlighting.

linux-6.19.14/fs/xfs/libxfs/xfs_zones.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2023-2025 Christoph Hellwig.
  4 * Copyright (c) 2024-2025, Western Digital Corporation or its affiliates.
  5 */
  6#include "xfs.h"
  7#include "xfs_fs.h"
  8#include "xfs_shared.h"
  9#include "xfs_format.h"
 10#include "xfs_log_format.h"
 11#include "xfs_trans_resv.h"
 12#include "xfs_mount.h"
 13#include "xfs_inode.h"
 14#include "xfs_rtgroup.h"
 15#include "xfs_zones.h"
 16
 17static bool
 18xfs_zone_validate_empty(
 19	struct blk_zone		*zone,
 20	struct xfs_rtgroup	*rtg,
 21	xfs_rgblock_t		*write_pointer)
 22{
 23	struct xfs_mount	*mp = rtg_mount(rtg);
 24
 25	if (rtg_rmap(rtg)->i_used_blocks > 0) {
 26		xfs_warn(mp, "empty zone %u has non-zero used counter (0x%x).",
 27			 rtg_rgno(rtg), rtg_rmap(rtg)->i_used_blocks);
 28		return false;
 29	}
 30
 31	*write_pointer = 0;
 32	return true;
 33}
 34
 35static bool
 36xfs_zone_validate_wp(
 37	struct blk_zone		*zone,
 38	struct xfs_rtgroup	*rtg,
 39	xfs_rgblock_t		*write_pointer)
 40{
 41	struct xfs_mount	*mp = rtg_mount(rtg);
 42	xfs_rtblock_t		wp_fsb = xfs_daddr_to_rtb(mp, zone->wp);
 43
 44	if (rtg_rmap(rtg)->i_used_blocks > rtg->rtg_extents) {
 45		xfs_warn(mp, "zone %u has too large used counter (0x%x).",
 46			 rtg_rgno(rtg), rtg_rmap(rtg)->i_used_blocks);
 47		return false;
 48	}
 49
 50	if (xfs_rtb_to_rgno(mp, wp_fsb) != rtg_rgno(rtg)) {
 51		xfs_warn(mp, "zone %u write pointer (0x%llx) outside of zone.",
 52			 rtg_rgno(rtg), wp_fsb);
 53		return false;
 54	}
 55
 56	*write_pointer = xfs_rtb_to_rgbno(mp, wp_fsb);
 57	if (*write_pointer >= rtg->rtg_extents) {
 58		xfs_warn(mp, "zone %u has invalid write pointer (0x%x).",
 59			 rtg_rgno(rtg), *write_pointer);
 60		return false;
 61	}
 62
 63	return true;
 64}
 65
 66static bool
 67xfs_zone_validate_full(
 68	struct blk_zone		*zone,
 69	struct xfs_rtgroup	*rtg,
 70	xfs_rgblock_t		*write_pointer)
 71{
 72	struct xfs_mount	*mp = rtg_mount(rtg);
 73
 74	if (rtg_rmap(rtg)->i_used_blocks > rtg->rtg_extents) {
 75		xfs_warn(mp, "zone %u has too large used counter (0x%x).",
 76			 rtg_rgno(rtg), rtg_rmap(rtg)->i_used_blocks);
 77		return false;
 78	}
 79
 80	*write_pointer = rtg->rtg_extents;
 81	return true;
 82}
 83
 84static bool
 85xfs_zone_validate_seq(
 86	struct blk_zone		*zone,
 87	struct xfs_rtgroup	*rtg,
 88	xfs_rgblock_t		*write_pointer)
 89{
 90	struct xfs_mount	*mp = rtg_mount(rtg);
 91
 92	switch (zone->cond) {
 93	case BLK_ZONE_COND_EMPTY:
 94		return xfs_zone_validate_empty(zone, rtg, write_pointer);
 95	case BLK_ZONE_COND_IMP_OPEN:
 96	case BLK_ZONE_COND_EXP_OPEN:
 97	case BLK_ZONE_COND_CLOSED:
 98	case BLK_ZONE_COND_ACTIVE:
 99		return xfs_zone_validate_wp(zone, rtg, write_pointer);
100	case BLK_ZONE_COND_FULL:
101		return xfs_zone_validate_full(zone, rtg, write_pointer);
102	case BLK_ZONE_COND_NOT_WP:
103	case BLK_ZONE_COND_OFFLINE:
104	case BLK_ZONE_COND_READONLY:
105		xfs_warn(mp, "zone %u has unsupported zone condition 0x%x.",
106			rtg_rgno(rtg), zone->cond);
107		return false;
108	default:
109		xfs_warn(mp, "zone %u has unknown zone condition 0x%x.",
110			rtg_rgno(rtg), zone->cond);
111		return false;
112	}
113}
114
115static bool
116xfs_zone_validate_conv(
117	struct blk_zone		*zone,
118	struct xfs_rtgroup	*rtg)
119{
120	struct xfs_mount	*mp = rtg_mount(rtg);
121
122	switch (zone->cond) {
123	case BLK_ZONE_COND_NOT_WP:
124		return true;
125	default:
126		xfs_warn(mp,
127"conventional zone %u has unsupported zone condition 0x%x.",
128			 rtg_rgno(rtg), zone->cond);
129		return false;
130	}
131}
132
133bool
134xfs_zone_validate(
135	struct blk_zone		*zone,
136	struct xfs_rtgroup	*rtg,
137	xfs_rgblock_t		*write_pointer)
138{
139	struct xfs_mount	*mp = rtg_mount(rtg);
140	struct xfs_groups	*g = &mp->m_groups[XG_TYPE_RTG];
141	uint32_t		expected_size;
142
143	/*
144	 * Check that the zone capacity matches the rtgroup size stored in the
145	 * superblock.  Note that all zones including the last one must have a
146	 * uniform capacity.
147	 */
148	if (XFS_BB_TO_FSB(mp, zone->capacity) != g->blocks) {
149		xfs_warn(mp,
150"zone %u capacity (0x%llx) does not match RT group size (0x%x).",
151			rtg_rgno(rtg), XFS_BB_TO_FSB(mp, zone->capacity),
152			g->blocks);
153		return false;
154	}
155
156	if (g->has_daddr_gaps) {
157		expected_size = 1 << g->blklog;
158	} else {
159		if (zone->len != zone->capacity) {
160			xfs_warn(mp,
161"zone %u has capacity != size ((0x%llx vs 0x%llx)",
162				rtg_rgno(rtg),
163				XFS_BB_TO_FSB(mp, zone->len),
164				XFS_BB_TO_FSB(mp, zone->capacity));
165			return false;
166		}
167		expected_size = g->blocks;
168	}
169
170	if (XFS_BB_TO_FSB(mp, zone->len) != expected_size) {
171		xfs_warn(mp,
172"zone %u length (0x%llx) does match geometry (0x%x).",
173			rtg_rgno(rtg), XFS_BB_TO_FSB(mp, zone->len),
174			expected_size);
175	}
176
177	switch (zone->type) {
178	case BLK_ZONE_TYPE_CONVENTIONAL:
179		return xfs_zone_validate_conv(zone, rtg);
180	case BLK_ZONE_TYPE_SEQWRITE_REQ:
181		return xfs_zone_validate_seq(zone, rtg, write_pointer);
182	default:
183		xfs_warn(mp, "zoned %u has unsupported type 0x%x.",
184			rtg_rgno(rtg), zone->type);
185		return false;
186	}
187}
~/ Read-only file preview.