xref: /linux/fs/xfs/libxfs/xfs_zones.c (revision 6f7e6393d1ce636bb7ec77a7fe7b77458fddf701)
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_platform.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 
17 static bool
18 xfs_validate_blk_zone_seq(
19 	struct xfs_mount	*mp,
20 	struct blk_zone		*zone,
21 	unsigned int		zone_no,
22 	xfs_rgblock_t		*write_pointer)
23 {
24 	switch (zone->cond) {
25 	case BLK_ZONE_COND_EMPTY:
26 		*write_pointer = 0;
27 		return true;
28 	case BLK_ZONE_COND_IMP_OPEN:
29 	case BLK_ZONE_COND_EXP_OPEN:
30 	case BLK_ZONE_COND_CLOSED:
31 	case BLK_ZONE_COND_ACTIVE:
32 		if (zone->wp < zone->start ||
33 		    zone->wp >= zone->start + zone->capacity) {
34 			xfs_warn(mp,
35 	"zone %u write pointer (%llu) outside of zone.",
36 				zone_no, zone->wp);
37 			return false;
38 		}
39 
40 		*write_pointer = XFS_BB_TO_FSB(mp, zone->wp - zone->start);
41 		return true;
42 	case BLK_ZONE_COND_FULL:
43 		*write_pointer = XFS_BB_TO_FSB(mp, zone->capacity);
44 		return true;
45 	case BLK_ZONE_COND_NOT_WP:
46 	case BLK_ZONE_COND_OFFLINE:
47 	case BLK_ZONE_COND_READONLY:
48 		xfs_warn(mp, "zone %u has unsupported zone condition 0x%x.",
49 			zone_no, zone->cond);
50 		return false;
51 	default:
52 		xfs_warn(mp, "zone %u has unknown zone condition 0x%x.",
53 			zone_no, zone->cond);
54 		return false;
55 	}
56 }
57 
58 static bool
59 xfs_validate_blk_zone_conv(
60 	struct xfs_mount	*mp,
61 	struct blk_zone		*zone,
62 	unsigned int		zone_no)
63 {
64 	switch (zone->cond) {
65 	case BLK_ZONE_COND_NOT_WP:
66 		return true;
67 	default:
68 		xfs_warn(mp,
69 "conventional zone %u has unsupported zone condition 0x%x.",
70 			 zone_no, zone->cond);
71 		return false;
72 	}
73 }
74 
75 bool
76 xfs_validate_blk_zone(
77 	struct xfs_mount	*mp,
78 	struct blk_zone		*zone,
79 	unsigned int		zone_no,
80 	uint32_t		expected_size,
81 	uint32_t		expected_capacity,
82 	xfs_rgblock_t		*write_pointer)
83 {
84 	/*
85 	 * Check that the zone capacity matches the rtgroup size stored in the
86 	 * superblock.  Note that all zones including the last one must have a
87 	 * uniform capacity.
88 	 */
89 	if (XFS_BB_TO_FSB(mp, zone->capacity) != expected_capacity) {
90 		xfs_warn(mp,
91 "zone %u capacity (%llu) does not match RT group size (%u).",
92 			zone_no, XFS_BB_TO_FSB(mp, zone->capacity),
93 			expected_capacity);
94 		return false;
95 	}
96 
97 	if (XFS_BB_TO_FSB(mp, zone->len) != expected_size) {
98 		xfs_warn(mp,
99 "zone %u length (%llu) does not match geometry (%u).",
100 			zone_no, XFS_BB_TO_FSB(mp, zone->len),
101 			expected_size);
102 		return false;
103 	}
104 
105 	switch (zone->type) {
106 	case BLK_ZONE_TYPE_CONVENTIONAL:
107 		return xfs_validate_blk_zone_conv(mp, zone, zone_no);
108 	case BLK_ZONE_TYPE_SEQWRITE_REQ:
109 		return xfs_validate_blk_zone_seq(mp, zone, zone_no,
110 				write_pointer);
111 	default:
112 		xfs_warn(mp, "zoned %u has unsupported type 0x%x.",
113 			zone_no, zone->type);
114 		return false;
115 	}
116 }
117