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
xfs_validate_blk_zone_seq(struct xfs_mount * mp,struct blk_zone * zone,unsigned int zone_no,xfs_rgblock_t * write_pointer)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
xfs_validate_blk_zone_conv(struct xfs_mount * mp,struct blk_zone * zone,unsigned int zone_no)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
xfs_validate_blk_zone(struct xfs_mount * mp,struct blk_zone * zone,unsigned int zone_no,uint32_t expected_size,uint32_t expected_capacity,xfs_rgblock_t * write_pointer)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