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