1*4e4d5207SChristoph Hellwig // SPDX-License-Identifier: GPL-2.0 2*4e4d5207SChristoph Hellwig /* 3*4e4d5207SChristoph Hellwig * Copyright (c) 2023-2025 Christoph Hellwig. 4*4e4d5207SChristoph Hellwig * Copyright (c) 2024-2025, Western Digital Corporation or its affiliates. 5*4e4d5207SChristoph Hellwig */ 6*4e4d5207SChristoph Hellwig #include "xfs.h" 7*4e4d5207SChristoph Hellwig #include "xfs_shared.h" 8*4e4d5207SChristoph Hellwig #include "xfs_format.h" 9*4e4d5207SChristoph Hellwig #include "xfs_log_format.h" 10*4e4d5207SChristoph Hellwig #include "xfs_error.h" 11*4e4d5207SChristoph Hellwig #include "xfs_trans_resv.h" 12*4e4d5207SChristoph Hellwig #include "xfs_mount.h" 13*4e4d5207SChristoph Hellwig #include "xfs_inode.h" 14*4e4d5207SChristoph Hellwig #include "xfs_iomap.h" 15*4e4d5207SChristoph Hellwig #include "xfs_trans.h" 16*4e4d5207SChristoph Hellwig #include "xfs_alloc.h" 17*4e4d5207SChristoph Hellwig #include "xfs_bmap.h" 18*4e4d5207SChristoph Hellwig #include "xfs_bmap_btree.h" 19*4e4d5207SChristoph Hellwig #include "xfs_trans_space.h" 20*4e4d5207SChristoph Hellwig #include "xfs_refcount.h" 21*4e4d5207SChristoph Hellwig #include "xfs_rtbitmap.h" 22*4e4d5207SChristoph Hellwig #include "xfs_rtrmap_btree.h" 23*4e4d5207SChristoph Hellwig #include "xfs_zone_alloc.h" 24*4e4d5207SChristoph Hellwig #include "xfs_zone_priv.h" 25*4e4d5207SChristoph Hellwig #include "xfs_zones.h" 26*4e4d5207SChristoph Hellwig #include "xfs_trace.h" 27*4e4d5207SChristoph Hellwig 28*4e4d5207SChristoph Hellwig void 29*4e4d5207SChristoph Hellwig xfs_open_zone_put( 30*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz) 31*4e4d5207SChristoph Hellwig { 32*4e4d5207SChristoph Hellwig if (atomic_dec_and_test(&oz->oz_ref)) { 33*4e4d5207SChristoph Hellwig xfs_rtgroup_rele(oz->oz_rtg); 34*4e4d5207SChristoph Hellwig kfree(oz); 35*4e4d5207SChristoph Hellwig } 36*4e4d5207SChristoph Hellwig } 37*4e4d5207SChristoph Hellwig 38*4e4d5207SChristoph Hellwig static void 39*4e4d5207SChristoph Hellwig xfs_open_zone_mark_full( 40*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz) 41*4e4d5207SChristoph Hellwig { 42*4e4d5207SChristoph Hellwig struct xfs_rtgroup *rtg = oz->oz_rtg; 43*4e4d5207SChristoph Hellwig struct xfs_mount *mp = rtg_mount(rtg); 44*4e4d5207SChristoph Hellwig struct xfs_zone_info *zi = mp->m_zone_info; 45*4e4d5207SChristoph Hellwig 46*4e4d5207SChristoph Hellwig trace_xfs_zone_full(rtg); 47*4e4d5207SChristoph Hellwig 48*4e4d5207SChristoph Hellwig WRITE_ONCE(rtg->rtg_open_zone, NULL); 49*4e4d5207SChristoph Hellwig 50*4e4d5207SChristoph Hellwig spin_lock(&zi->zi_open_zones_lock); 51*4e4d5207SChristoph Hellwig if (oz->oz_is_gc) { 52*4e4d5207SChristoph Hellwig ASSERT(current == zi->zi_gc_thread); 53*4e4d5207SChristoph Hellwig zi->zi_open_gc_zone = NULL; 54*4e4d5207SChristoph Hellwig } else { 55*4e4d5207SChristoph Hellwig zi->zi_nr_open_zones--; 56*4e4d5207SChristoph Hellwig list_del_init(&oz->oz_entry); 57*4e4d5207SChristoph Hellwig } 58*4e4d5207SChristoph Hellwig spin_unlock(&zi->zi_open_zones_lock); 59*4e4d5207SChristoph Hellwig xfs_open_zone_put(oz); 60*4e4d5207SChristoph Hellwig 61*4e4d5207SChristoph Hellwig wake_up_all(&zi->zi_zone_wait); 62*4e4d5207SChristoph Hellwig } 63*4e4d5207SChristoph Hellwig 64*4e4d5207SChristoph Hellwig static void 65*4e4d5207SChristoph Hellwig xfs_zone_record_blocks( 66*4e4d5207SChristoph Hellwig struct xfs_trans *tp, 67*4e4d5207SChristoph Hellwig xfs_fsblock_t fsbno, 68*4e4d5207SChristoph Hellwig xfs_filblks_t len, 69*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz, 70*4e4d5207SChristoph Hellwig bool used) 71*4e4d5207SChristoph Hellwig { 72*4e4d5207SChristoph Hellwig struct xfs_mount *mp = tp->t_mountp; 73*4e4d5207SChristoph Hellwig struct xfs_rtgroup *rtg = oz->oz_rtg; 74*4e4d5207SChristoph Hellwig struct xfs_inode *rmapip = rtg_rmap(rtg); 75*4e4d5207SChristoph Hellwig 76*4e4d5207SChristoph Hellwig trace_xfs_zone_record_blocks(oz, xfs_rtb_to_rgbno(mp, fsbno), len); 77*4e4d5207SChristoph Hellwig 78*4e4d5207SChristoph Hellwig xfs_rtgroup_lock(rtg, XFS_RTGLOCK_RMAP); 79*4e4d5207SChristoph Hellwig xfs_rtgroup_trans_join(tp, rtg, XFS_RTGLOCK_RMAP); 80*4e4d5207SChristoph Hellwig if (used) { 81*4e4d5207SChristoph Hellwig rmapip->i_used_blocks += len; 82*4e4d5207SChristoph Hellwig ASSERT(rmapip->i_used_blocks <= rtg_blocks(rtg)); 83*4e4d5207SChristoph Hellwig } else { 84*4e4d5207SChristoph Hellwig xfs_add_frextents(mp, len); 85*4e4d5207SChristoph Hellwig } 86*4e4d5207SChristoph Hellwig oz->oz_written += len; 87*4e4d5207SChristoph Hellwig if (oz->oz_written == rtg_blocks(rtg)) 88*4e4d5207SChristoph Hellwig xfs_open_zone_mark_full(oz); 89*4e4d5207SChristoph Hellwig xfs_trans_log_inode(tp, rmapip, XFS_ILOG_CORE); 90*4e4d5207SChristoph Hellwig } 91*4e4d5207SChristoph Hellwig 92*4e4d5207SChristoph Hellwig static int 93*4e4d5207SChristoph Hellwig xfs_zoned_map_extent( 94*4e4d5207SChristoph Hellwig struct xfs_trans *tp, 95*4e4d5207SChristoph Hellwig struct xfs_inode *ip, 96*4e4d5207SChristoph Hellwig struct xfs_bmbt_irec *new, 97*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz, 98*4e4d5207SChristoph Hellwig xfs_fsblock_t old_startblock) 99*4e4d5207SChristoph Hellwig { 100*4e4d5207SChristoph Hellwig struct xfs_bmbt_irec data; 101*4e4d5207SChristoph Hellwig int nmaps = 1; 102*4e4d5207SChristoph Hellwig int error; 103*4e4d5207SChristoph Hellwig 104*4e4d5207SChristoph Hellwig /* Grab the corresponding mapping in the data fork. */ 105*4e4d5207SChristoph Hellwig error = xfs_bmapi_read(ip, new->br_startoff, new->br_blockcount, &data, 106*4e4d5207SChristoph Hellwig &nmaps, 0); 107*4e4d5207SChristoph Hellwig if (error) 108*4e4d5207SChristoph Hellwig return error; 109*4e4d5207SChristoph Hellwig 110*4e4d5207SChristoph Hellwig /* 111*4e4d5207SChristoph Hellwig * Cap the update to the existing extent in the data fork because we can 112*4e4d5207SChristoph Hellwig * only overwrite one extent at a time. 113*4e4d5207SChristoph Hellwig */ 114*4e4d5207SChristoph Hellwig ASSERT(new->br_blockcount >= data.br_blockcount); 115*4e4d5207SChristoph Hellwig new->br_blockcount = data.br_blockcount; 116*4e4d5207SChristoph Hellwig 117*4e4d5207SChristoph Hellwig /* 118*4e4d5207SChristoph Hellwig * If a data write raced with this GC write, keep the existing data in 119*4e4d5207SChristoph Hellwig * the data fork, mark our newly written GC extent as reclaimable, then 120*4e4d5207SChristoph Hellwig * move on to the next extent. 121*4e4d5207SChristoph Hellwig */ 122*4e4d5207SChristoph Hellwig if (old_startblock != NULLFSBLOCK && 123*4e4d5207SChristoph Hellwig old_startblock != data.br_startblock) 124*4e4d5207SChristoph Hellwig goto skip; 125*4e4d5207SChristoph Hellwig 126*4e4d5207SChristoph Hellwig trace_xfs_reflink_cow_remap_from(ip, new); 127*4e4d5207SChristoph Hellwig trace_xfs_reflink_cow_remap_to(ip, &data); 128*4e4d5207SChristoph Hellwig 129*4e4d5207SChristoph Hellwig error = xfs_iext_count_extend(tp, ip, XFS_DATA_FORK, 130*4e4d5207SChristoph Hellwig XFS_IEXT_REFLINK_END_COW_CNT); 131*4e4d5207SChristoph Hellwig if (error) 132*4e4d5207SChristoph Hellwig return error; 133*4e4d5207SChristoph Hellwig 134*4e4d5207SChristoph Hellwig if (data.br_startblock != HOLESTARTBLOCK) { 135*4e4d5207SChristoph Hellwig ASSERT(data.br_startblock != DELAYSTARTBLOCK); 136*4e4d5207SChristoph Hellwig ASSERT(!isnullstartblock(data.br_startblock)); 137*4e4d5207SChristoph Hellwig 138*4e4d5207SChristoph Hellwig xfs_bmap_unmap_extent(tp, ip, XFS_DATA_FORK, &data); 139*4e4d5207SChristoph Hellwig if (xfs_is_reflink_inode(ip)) { 140*4e4d5207SChristoph Hellwig xfs_refcount_decrease_extent(tp, true, &data); 141*4e4d5207SChristoph Hellwig } else { 142*4e4d5207SChristoph Hellwig error = xfs_free_extent_later(tp, data.br_startblock, 143*4e4d5207SChristoph Hellwig data.br_blockcount, NULL, 144*4e4d5207SChristoph Hellwig XFS_AG_RESV_NONE, 145*4e4d5207SChristoph Hellwig XFS_FREE_EXTENT_REALTIME); 146*4e4d5207SChristoph Hellwig if (error) 147*4e4d5207SChristoph Hellwig return error; 148*4e4d5207SChristoph Hellwig } 149*4e4d5207SChristoph Hellwig } 150*4e4d5207SChristoph Hellwig 151*4e4d5207SChristoph Hellwig xfs_zone_record_blocks(tp, new->br_startblock, new->br_blockcount, oz, 152*4e4d5207SChristoph Hellwig true); 153*4e4d5207SChristoph Hellwig 154*4e4d5207SChristoph Hellwig /* Map the new blocks into the data fork. */ 155*4e4d5207SChristoph Hellwig xfs_bmap_map_extent(tp, ip, XFS_DATA_FORK, new); 156*4e4d5207SChristoph Hellwig return 0; 157*4e4d5207SChristoph Hellwig 158*4e4d5207SChristoph Hellwig skip: 159*4e4d5207SChristoph Hellwig trace_xfs_reflink_cow_remap_skip(ip, new); 160*4e4d5207SChristoph Hellwig xfs_zone_record_blocks(tp, new->br_startblock, new->br_blockcount, oz, 161*4e4d5207SChristoph Hellwig false); 162*4e4d5207SChristoph Hellwig return 0; 163*4e4d5207SChristoph Hellwig } 164*4e4d5207SChristoph Hellwig 165*4e4d5207SChristoph Hellwig int 166*4e4d5207SChristoph Hellwig xfs_zoned_end_io( 167*4e4d5207SChristoph Hellwig struct xfs_inode *ip, 168*4e4d5207SChristoph Hellwig xfs_off_t offset, 169*4e4d5207SChristoph Hellwig xfs_off_t count, 170*4e4d5207SChristoph Hellwig xfs_daddr_t daddr, 171*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz, 172*4e4d5207SChristoph Hellwig xfs_fsblock_t old_startblock) 173*4e4d5207SChristoph Hellwig { 174*4e4d5207SChristoph Hellwig struct xfs_mount *mp = ip->i_mount; 175*4e4d5207SChristoph Hellwig xfs_fileoff_t end_fsb = XFS_B_TO_FSB(mp, offset + count); 176*4e4d5207SChristoph Hellwig struct xfs_bmbt_irec new = { 177*4e4d5207SChristoph Hellwig .br_startoff = XFS_B_TO_FSBT(mp, offset), 178*4e4d5207SChristoph Hellwig .br_startblock = xfs_daddr_to_rtb(mp, daddr), 179*4e4d5207SChristoph Hellwig .br_state = XFS_EXT_NORM, 180*4e4d5207SChristoph Hellwig }; 181*4e4d5207SChristoph Hellwig unsigned int resblks = 182*4e4d5207SChristoph Hellwig XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK); 183*4e4d5207SChristoph Hellwig struct xfs_trans *tp; 184*4e4d5207SChristoph Hellwig int error; 185*4e4d5207SChristoph Hellwig 186*4e4d5207SChristoph Hellwig if (xfs_is_shutdown(mp)) 187*4e4d5207SChristoph Hellwig return -EIO; 188*4e4d5207SChristoph Hellwig 189*4e4d5207SChristoph Hellwig while (new.br_startoff < end_fsb) { 190*4e4d5207SChristoph Hellwig new.br_blockcount = end_fsb - new.br_startoff; 191*4e4d5207SChristoph Hellwig 192*4e4d5207SChristoph Hellwig error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 193*4e4d5207SChristoph Hellwig XFS_TRANS_RESERVE | XFS_TRANS_RES_FDBLKS, &tp); 194*4e4d5207SChristoph Hellwig if (error) 195*4e4d5207SChristoph Hellwig return error; 196*4e4d5207SChristoph Hellwig xfs_ilock(ip, XFS_ILOCK_EXCL); 197*4e4d5207SChristoph Hellwig xfs_trans_ijoin(tp, ip, 0); 198*4e4d5207SChristoph Hellwig 199*4e4d5207SChristoph Hellwig error = xfs_zoned_map_extent(tp, ip, &new, oz, old_startblock); 200*4e4d5207SChristoph Hellwig if (error) 201*4e4d5207SChristoph Hellwig xfs_trans_cancel(tp); 202*4e4d5207SChristoph Hellwig else 203*4e4d5207SChristoph Hellwig error = xfs_trans_commit(tp); 204*4e4d5207SChristoph Hellwig xfs_iunlock(ip, XFS_ILOCK_EXCL); 205*4e4d5207SChristoph Hellwig if (error) 206*4e4d5207SChristoph Hellwig return error; 207*4e4d5207SChristoph Hellwig 208*4e4d5207SChristoph Hellwig new.br_startoff += new.br_blockcount; 209*4e4d5207SChristoph Hellwig new.br_startblock += new.br_blockcount; 210*4e4d5207SChristoph Hellwig if (old_startblock != NULLFSBLOCK) 211*4e4d5207SChristoph Hellwig old_startblock += new.br_blockcount; 212*4e4d5207SChristoph Hellwig } 213*4e4d5207SChristoph Hellwig 214*4e4d5207SChristoph Hellwig return 0; 215*4e4d5207SChristoph Hellwig } 216*4e4d5207SChristoph Hellwig 217*4e4d5207SChristoph Hellwig /* 218*4e4d5207SChristoph Hellwig * "Free" blocks allocated in a zone. 219*4e4d5207SChristoph Hellwig * 220*4e4d5207SChristoph Hellwig * Just decrement the used blocks counter and report the space as freed. 221*4e4d5207SChristoph Hellwig */ 222*4e4d5207SChristoph Hellwig int 223*4e4d5207SChristoph Hellwig xfs_zone_free_blocks( 224*4e4d5207SChristoph Hellwig struct xfs_trans *tp, 225*4e4d5207SChristoph Hellwig struct xfs_rtgroup *rtg, 226*4e4d5207SChristoph Hellwig xfs_fsblock_t fsbno, 227*4e4d5207SChristoph Hellwig xfs_filblks_t len) 228*4e4d5207SChristoph Hellwig { 229*4e4d5207SChristoph Hellwig struct xfs_mount *mp = tp->t_mountp; 230*4e4d5207SChristoph Hellwig struct xfs_inode *rmapip = rtg_rmap(rtg); 231*4e4d5207SChristoph Hellwig 232*4e4d5207SChristoph Hellwig xfs_assert_ilocked(rmapip, XFS_ILOCK_EXCL); 233*4e4d5207SChristoph Hellwig 234*4e4d5207SChristoph Hellwig if (len > rmapip->i_used_blocks) { 235*4e4d5207SChristoph Hellwig xfs_err(mp, 236*4e4d5207SChristoph Hellwig "trying to free more blocks (%lld) than used counter (%u).", 237*4e4d5207SChristoph Hellwig len, rmapip->i_used_blocks); 238*4e4d5207SChristoph Hellwig ASSERT(len <= rmapip->i_used_blocks); 239*4e4d5207SChristoph Hellwig xfs_rtginode_mark_sick(rtg, XFS_RTGI_RMAP); 240*4e4d5207SChristoph Hellwig xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); 241*4e4d5207SChristoph Hellwig return -EFSCORRUPTED; 242*4e4d5207SChristoph Hellwig } 243*4e4d5207SChristoph Hellwig 244*4e4d5207SChristoph Hellwig trace_xfs_zone_free_blocks(rtg, xfs_rtb_to_rgbno(mp, fsbno), len); 245*4e4d5207SChristoph Hellwig 246*4e4d5207SChristoph Hellwig rmapip->i_used_blocks -= len; 247*4e4d5207SChristoph Hellwig xfs_add_frextents(mp, len); 248*4e4d5207SChristoph Hellwig xfs_trans_log_inode(tp, rmapip, XFS_ILOG_CORE); 249*4e4d5207SChristoph Hellwig return 0; 250*4e4d5207SChristoph Hellwig } 251*4e4d5207SChristoph Hellwig 252*4e4d5207SChristoph Hellwig /* 253*4e4d5207SChristoph Hellwig * Check if the zone containing the data just before the offset we are 254*4e4d5207SChristoph Hellwig * writing to is still open and has space. 255*4e4d5207SChristoph Hellwig */ 256*4e4d5207SChristoph Hellwig static struct xfs_open_zone * 257*4e4d5207SChristoph Hellwig xfs_last_used_zone( 258*4e4d5207SChristoph Hellwig struct iomap_ioend *ioend) 259*4e4d5207SChristoph Hellwig { 260*4e4d5207SChristoph Hellwig struct xfs_inode *ip = XFS_I(ioend->io_inode); 261*4e4d5207SChristoph Hellwig struct xfs_mount *mp = ip->i_mount; 262*4e4d5207SChristoph Hellwig xfs_fileoff_t offset_fsb = XFS_B_TO_FSB(mp, ioend->io_offset); 263*4e4d5207SChristoph Hellwig struct xfs_rtgroup *rtg = NULL; 264*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz = NULL; 265*4e4d5207SChristoph Hellwig struct xfs_iext_cursor icur; 266*4e4d5207SChristoph Hellwig struct xfs_bmbt_irec got; 267*4e4d5207SChristoph Hellwig 268*4e4d5207SChristoph Hellwig xfs_ilock(ip, XFS_ILOCK_SHARED); 269*4e4d5207SChristoph Hellwig if (!xfs_iext_lookup_extent_before(ip, &ip->i_df, &offset_fsb, 270*4e4d5207SChristoph Hellwig &icur, &got)) { 271*4e4d5207SChristoph Hellwig xfs_iunlock(ip, XFS_ILOCK_SHARED); 272*4e4d5207SChristoph Hellwig return NULL; 273*4e4d5207SChristoph Hellwig } 274*4e4d5207SChristoph Hellwig xfs_iunlock(ip, XFS_ILOCK_SHARED); 275*4e4d5207SChristoph Hellwig 276*4e4d5207SChristoph Hellwig rtg = xfs_rtgroup_grab(mp, xfs_rtb_to_rgno(mp, got.br_startblock)); 277*4e4d5207SChristoph Hellwig if (!rtg) 278*4e4d5207SChristoph Hellwig return NULL; 279*4e4d5207SChristoph Hellwig 280*4e4d5207SChristoph Hellwig xfs_ilock(rtg_rmap(rtg), XFS_ILOCK_SHARED); 281*4e4d5207SChristoph Hellwig oz = READ_ONCE(rtg->rtg_open_zone); 282*4e4d5207SChristoph Hellwig if (oz && (oz->oz_is_gc || !atomic_inc_not_zero(&oz->oz_ref))) 283*4e4d5207SChristoph Hellwig oz = NULL; 284*4e4d5207SChristoph Hellwig xfs_iunlock(rtg_rmap(rtg), XFS_ILOCK_SHARED); 285*4e4d5207SChristoph Hellwig 286*4e4d5207SChristoph Hellwig xfs_rtgroup_rele(rtg); 287*4e4d5207SChristoph Hellwig return oz; 288*4e4d5207SChristoph Hellwig } 289*4e4d5207SChristoph Hellwig 290*4e4d5207SChristoph Hellwig static struct xfs_group * 291*4e4d5207SChristoph Hellwig xfs_find_free_zone( 292*4e4d5207SChristoph Hellwig struct xfs_mount *mp, 293*4e4d5207SChristoph Hellwig unsigned long start, 294*4e4d5207SChristoph Hellwig unsigned long end) 295*4e4d5207SChristoph Hellwig { 296*4e4d5207SChristoph Hellwig struct xfs_zone_info *zi = mp->m_zone_info; 297*4e4d5207SChristoph Hellwig XA_STATE (xas, &mp->m_groups[XG_TYPE_RTG].xa, start); 298*4e4d5207SChristoph Hellwig struct xfs_group *xg; 299*4e4d5207SChristoph Hellwig 300*4e4d5207SChristoph Hellwig xas_lock(&xas); 301*4e4d5207SChristoph Hellwig xas_for_each_marked(&xas, xg, end, XFS_RTG_FREE) 302*4e4d5207SChristoph Hellwig if (atomic_inc_not_zero(&xg->xg_active_ref)) 303*4e4d5207SChristoph Hellwig goto found; 304*4e4d5207SChristoph Hellwig xas_unlock(&xas); 305*4e4d5207SChristoph Hellwig return NULL; 306*4e4d5207SChristoph Hellwig 307*4e4d5207SChristoph Hellwig found: 308*4e4d5207SChristoph Hellwig xas_clear_mark(&xas, XFS_RTG_FREE); 309*4e4d5207SChristoph Hellwig atomic_dec(&zi->zi_nr_free_zones); 310*4e4d5207SChristoph Hellwig zi->zi_free_zone_cursor = xg->xg_gno; 311*4e4d5207SChristoph Hellwig xas_unlock(&xas); 312*4e4d5207SChristoph Hellwig return xg; 313*4e4d5207SChristoph Hellwig } 314*4e4d5207SChristoph Hellwig 315*4e4d5207SChristoph Hellwig static struct xfs_open_zone * 316*4e4d5207SChristoph Hellwig xfs_init_open_zone( 317*4e4d5207SChristoph Hellwig struct xfs_rtgroup *rtg, 318*4e4d5207SChristoph Hellwig xfs_rgblock_t write_pointer, 319*4e4d5207SChristoph Hellwig bool is_gc) 320*4e4d5207SChristoph Hellwig { 321*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz; 322*4e4d5207SChristoph Hellwig 323*4e4d5207SChristoph Hellwig oz = kzalloc(sizeof(*oz), GFP_NOFS | __GFP_NOFAIL); 324*4e4d5207SChristoph Hellwig spin_lock_init(&oz->oz_alloc_lock); 325*4e4d5207SChristoph Hellwig atomic_set(&oz->oz_ref, 1); 326*4e4d5207SChristoph Hellwig oz->oz_rtg = rtg; 327*4e4d5207SChristoph Hellwig oz->oz_write_pointer = write_pointer; 328*4e4d5207SChristoph Hellwig oz->oz_written = write_pointer; 329*4e4d5207SChristoph Hellwig oz->oz_is_gc = is_gc; 330*4e4d5207SChristoph Hellwig 331*4e4d5207SChristoph Hellwig /* 332*4e4d5207SChristoph Hellwig * All dereferences of rtg->rtg_open_zone hold the ILOCK for the rmap 333*4e4d5207SChristoph Hellwig * inode, but we don't really want to take that here because we are 334*4e4d5207SChristoph Hellwig * under the zone_list_lock. Ensure the pointer is only set for a fully 335*4e4d5207SChristoph Hellwig * initialized open zone structure so that a racy lookup finding it is 336*4e4d5207SChristoph Hellwig * fine. 337*4e4d5207SChristoph Hellwig */ 338*4e4d5207SChristoph Hellwig WRITE_ONCE(rtg->rtg_open_zone, oz); 339*4e4d5207SChristoph Hellwig return oz; 340*4e4d5207SChristoph Hellwig } 341*4e4d5207SChristoph Hellwig 342*4e4d5207SChristoph Hellwig /* 343*4e4d5207SChristoph Hellwig * Find a completely free zone, open it, and return a reference. 344*4e4d5207SChristoph Hellwig */ 345*4e4d5207SChristoph Hellwig struct xfs_open_zone * 346*4e4d5207SChristoph Hellwig xfs_open_zone( 347*4e4d5207SChristoph Hellwig struct xfs_mount *mp, 348*4e4d5207SChristoph Hellwig bool is_gc) 349*4e4d5207SChristoph Hellwig { 350*4e4d5207SChristoph Hellwig struct xfs_zone_info *zi = mp->m_zone_info; 351*4e4d5207SChristoph Hellwig struct xfs_group *xg; 352*4e4d5207SChristoph Hellwig 353*4e4d5207SChristoph Hellwig xg = xfs_find_free_zone(mp, zi->zi_free_zone_cursor, ULONG_MAX); 354*4e4d5207SChristoph Hellwig if (!xg) 355*4e4d5207SChristoph Hellwig xg = xfs_find_free_zone(mp, 0, zi->zi_free_zone_cursor); 356*4e4d5207SChristoph Hellwig if (!xg) 357*4e4d5207SChristoph Hellwig return NULL; 358*4e4d5207SChristoph Hellwig 359*4e4d5207SChristoph Hellwig set_current_state(TASK_RUNNING); 360*4e4d5207SChristoph Hellwig return xfs_init_open_zone(to_rtg(xg), 0, is_gc); 361*4e4d5207SChristoph Hellwig } 362*4e4d5207SChristoph Hellwig 363*4e4d5207SChristoph Hellwig static struct xfs_open_zone * 364*4e4d5207SChristoph Hellwig xfs_try_open_zone( 365*4e4d5207SChristoph Hellwig struct xfs_mount *mp) 366*4e4d5207SChristoph Hellwig { 367*4e4d5207SChristoph Hellwig struct xfs_zone_info *zi = mp->m_zone_info; 368*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz; 369*4e4d5207SChristoph Hellwig 370*4e4d5207SChristoph Hellwig if (zi->zi_nr_open_zones >= mp->m_max_open_zones - XFS_OPEN_GC_ZONES) 371*4e4d5207SChristoph Hellwig return NULL; 372*4e4d5207SChristoph Hellwig if (atomic_read(&zi->zi_nr_free_zones) < 373*4e4d5207SChristoph Hellwig XFS_GC_ZONES - XFS_OPEN_GC_ZONES) 374*4e4d5207SChristoph Hellwig return NULL; 375*4e4d5207SChristoph Hellwig 376*4e4d5207SChristoph Hellwig /* 377*4e4d5207SChristoph Hellwig * Increment the open zone count to reserve our slot before dropping 378*4e4d5207SChristoph Hellwig * zi_open_zones_lock. 379*4e4d5207SChristoph Hellwig */ 380*4e4d5207SChristoph Hellwig zi->zi_nr_open_zones++; 381*4e4d5207SChristoph Hellwig spin_unlock(&zi->zi_open_zones_lock); 382*4e4d5207SChristoph Hellwig oz = xfs_open_zone(mp, false); 383*4e4d5207SChristoph Hellwig spin_lock(&zi->zi_open_zones_lock); 384*4e4d5207SChristoph Hellwig if (!oz) { 385*4e4d5207SChristoph Hellwig zi->zi_nr_open_zones--; 386*4e4d5207SChristoph Hellwig return NULL; 387*4e4d5207SChristoph Hellwig } 388*4e4d5207SChristoph Hellwig 389*4e4d5207SChristoph Hellwig atomic_inc(&oz->oz_ref); 390*4e4d5207SChristoph Hellwig list_add_tail(&oz->oz_entry, &zi->zi_open_zones); 391*4e4d5207SChristoph Hellwig 392*4e4d5207SChristoph Hellwig /* 393*4e4d5207SChristoph Hellwig * If this was the last free zone, other waiters might be waiting 394*4e4d5207SChristoph Hellwig * on us to write to it as well. 395*4e4d5207SChristoph Hellwig */ 396*4e4d5207SChristoph Hellwig wake_up_all(&zi->zi_zone_wait); 397*4e4d5207SChristoph Hellwig 398*4e4d5207SChristoph Hellwig trace_xfs_zone_opened(oz->oz_rtg); 399*4e4d5207SChristoph Hellwig return oz; 400*4e4d5207SChristoph Hellwig } 401*4e4d5207SChristoph Hellwig 402*4e4d5207SChristoph Hellwig static bool 403*4e4d5207SChristoph Hellwig xfs_try_use_zone( 404*4e4d5207SChristoph Hellwig struct xfs_zone_info *zi, 405*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz) 406*4e4d5207SChristoph Hellwig { 407*4e4d5207SChristoph Hellwig if (oz->oz_write_pointer == rtg_blocks(oz->oz_rtg)) 408*4e4d5207SChristoph Hellwig return false; 409*4e4d5207SChristoph Hellwig if (!atomic_inc_not_zero(&oz->oz_ref)) 410*4e4d5207SChristoph Hellwig return false; 411*4e4d5207SChristoph Hellwig 412*4e4d5207SChristoph Hellwig /* 413*4e4d5207SChristoph Hellwig * If we couldn't match by inode or life time we just pick the first 414*4e4d5207SChristoph Hellwig * zone with enough space above. For that we want the least busy zone 415*4e4d5207SChristoph Hellwig * for some definition of "least" busy. For now this simple LRU 416*4e4d5207SChristoph Hellwig * algorithm that rotates every zone to the end of the list will do it, 417*4e4d5207SChristoph Hellwig * even if it isn't exactly cache friendly. 418*4e4d5207SChristoph Hellwig */ 419*4e4d5207SChristoph Hellwig if (!list_is_last(&oz->oz_entry, &zi->zi_open_zones)) 420*4e4d5207SChristoph Hellwig list_move_tail(&oz->oz_entry, &zi->zi_open_zones); 421*4e4d5207SChristoph Hellwig return true; 422*4e4d5207SChristoph Hellwig } 423*4e4d5207SChristoph Hellwig 424*4e4d5207SChristoph Hellwig static struct xfs_open_zone * 425*4e4d5207SChristoph Hellwig xfs_select_open_zone_lru( 426*4e4d5207SChristoph Hellwig struct xfs_zone_info *zi) 427*4e4d5207SChristoph Hellwig { 428*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz; 429*4e4d5207SChristoph Hellwig 430*4e4d5207SChristoph Hellwig lockdep_assert_held(&zi->zi_open_zones_lock); 431*4e4d5207SChristoph Hellwig 432*4e4d5207SChristoph Hellwig list_for_each_entry(oz, &zi->zi_open_zones, oz_entry) 433*4e4d5207SChristoph Hellwig if (xfs_try_use_zone(zi, oz)) 434*4e4d5207SChristoph Hellwig return oz; 435*4e4d5207SChristoph Hellwig 436*4e4d5207SChristoph Hellwig cond_resched_lock(&zi->zi_open_zones_lock); 437*4e4d5207SChristoph Hellwig return NULL; 438*4e4d5207SChristoph Hellwig } 439*4e4d5207SChristoph Hellwig 440*4e4d5207SChristoph Hellwig static struct xfs_open_zone * 441*4e4d5207SChristoph Hellwig xfs_select_open_zone_mru( 442*4e4d5207SChristoph Hellwig struct xfs_zone_info *zi) 443*4e4d5207SChristoph Hellwig { 444*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz; 445*4e4d5207SChristoph Hellwig 446*4e4d5207SChristoph Hellwig lockdep_assert_held(&zi->zi_open_zones_lock); 447*4e4d5207SChristoph Hellwig 448*4e4d5207SChristoph Hellwig list_for_each_entry_reverse(oz, &zi->zi_open_zones, oz_entry) 449*4e4d5207SChristoph Hellwig if (xfs_try_use_zone(zi, oz)) 450*4e4d5207SChristoph Hellwig return oz; 451*4e4d5207SChristoph Hellwig 452*4e4d5207SChristoph Hellwig cond_resched_lock(&zi->zi_open_zones_lock); 453*4e4d5207SChristoph Hellwig return NULL; 454*4e4d5207SChristoph Hellwig } 455*4e4d5207SChristoph Hellwig 456*4e4d5207SChristoph Hellwig /* 457*4e4d5207SChristoph Hellwig * Try to pack inodes that are written back after they were closed tight instead 458*4e4d5207SChristoph Hellwig * of trying to open new zones for them or spread them to the least recently 459*4e4d5207SChristoph Hellwig * used zone. This optimizes the data layout for workloads that untar or copy 460*4e4d5207SChristoph Hellwig * a lot of small files. Right now this does not separate multiple such 461*4e4d5207SChristoph Hellwig * streams. 462*4e4d5207SChristoph Hellwig */ 463*4e4d5207SChristoph Hellwig static inline bool xfs_zoned_pack_tight(struct xfs_inode *ip) 464*4e4d5207SChristoph Hellwig { 465*4e4d5207SChristoph Hellwig return !inode_is_open_for_write(VFS_I(ip)) && 466*4e4d5207SChristoph Hellwig !(ip->i_diflags & XFS_DIFLAG_APPEND); 467*4e4d5207SChristoph Hellwig } 468*4e4d5207SChristoph Hellwig 469*4e4d5207SChristoph Hellwig /* 470*4e4d5207SChristoph Hellwig * Pick a new zone for writes. 471*4e4d5207SChristoph Hellwig * 472*4e4d5207SChristoph Hellwig * If we aren't using up our budget of open zones just open a new one from the 473*4e4d5207SChristoph Hellwig * freelist. Else try to find one that matches the expected data lifetime. If 474*4e4d5207SChristoph Hellwig * we don't find one that is good pick any zone that is available. 475*4e4d5207SChristoph Hellwig */ 476*4e4d5207SChristoph Hellwig static struct xfs_open_zone * 477*4e4d5207SChristoph Hellwig xfs_select_zone_nowait( 478*4e4d5207SChristoph Hellwig struct xfs_mount *mp, 479*4e4d5207SChristoph Hellwig bool pack_tight) 480*4e4d5207SChristoph Hellwig { 481*4e4d5207SChristoph Hellwig struct xfs_zone_info *zi = mp->m_zone_info; 482*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz = NULL; 483*4e4d5207SChristoph Hellwig 484*4e4d5207SChristoph Hellwig if (xfs_is_shutdown(mp)) 485*4e4d5207SChristoph Hellwig return NULL; 486*4e4d5207SChristoph Hellwig 487*4e4d5207SChristoph Hellwig spin_lock(&zi->zi_open_zones_lock); 488*4e4d5207SChristoph Hellwig if (pack_tight) 489*4e4d5207SChristoph Hellwig oz = xfs_select_open_zone_mru(zi); 490*4e4d5207SChristoph Hellwig if (oz) 491*4e4d5207SChristoph Hellwig goto out_unlock; 492*4e4d5207SChristoph Hellwig 493*4e4d5207SChristoph Hellwig /* 494*4e4d5207SChristoph Hellwig * See if we can open a new zone and use that. 495*4e4d5207SChristoph Hellwig */ 496*4e4d5207SChristoph Hellwig oz = xfs_try_open_zone(mp); 497*4e4d5207SChristoph Hellwig if (oz) 498*4e4d5207SChristoph Hellwig goto out_unlock; 499*4e4d5207SChristoph Hellwig 500*4e4d5207SChristoph Hellwig oz = xfs_select_open_zone_lru(zi); 501*4e4d5207SChristoph Hellwig out_unlock: 502*4e4d5207SChristoph Hellwig spin_unlock(&zi->zi_open_zones_lock); 503*4e4d5207SChristoph Hellwig return oz; 504*4e4d5207SChristoph Hellwig } 505*4e4d5207SChristoph Hellwig 506*4e4d5207SChristoph Hellwig static struct xfs_open_zone * 507*4e4d5207SChristoph Hellwig xfs_select_zone( 508*4e4d5207SChristoph Hellwig struct xfs_mount *mp, 509*4e4d5207SChristoph Hellwig bool pack_tight) 510*4e4d5207SChristoph Hellwig { 511*4e4d5207SChristoph Hellwig struct xfs_zone_info *zi = mp->m_zone_info; 512*4e4d5207SChristoph Hellwig DEFINE_WAIT (wait); 513*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz; 514*4e4d5207SChristoph Hellwig 515*4e4d5207SChristoph Hellwig oz = xfs_select_zone_nowait(mp, pack_tight); 516*4e4d5207SChristoph Hellwig if (oz) 517*4e4d5207SChristoph Hellwig return oz; 518*4e4d5207SChristoph Hellwig 519*4e4d5207SChristoph Hellwig for (;;) { 520*4e4d5207SChristoph Hellwig prepare_to_wait(&zi->zi_zone_wait, &wait, TASK_UNINTERRUPTIBLE); 521*4e4d5207SChristoph Hellwig oz = xfs_select_zone_nowait(mp, pack_tight); 522*4e4d5207SChristoph Hellwig if (oz) 523*4e4d5207SChristoph Hellwig break; 524*4e4d5207SChristoph Hellwig schedule(); 525*4e4d5207SChristoph Hellwig } 526*4e4d5207SChristoph Hellwig finish_wait(&zi->zi_zone_wait, &wait); 527*4e4d5207SChristoph Hellwig return oz; 528*4e4d5207SChristoph Hellwig } 529*4e4d5207SChristoph Hellwig 530*4e4d5207SChristoph Hellwig static unsigned int 531*4e4d5207SChristoph Hellwig xfs_zone_alloc_blocks( 532*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz, 533*4e4d5207SChristoph Hellwig xfs_filblks_t count_fsb, 534*4e4d5207SChristoph Hellwig sector_t *sector, 535*4e4d5207SChristoph Hellwig bool *is_seq) 536*4e4d5207SChristoph Hellwig { 537*4e4d5207SChristoph Hellwig struct xfs_rtgroup *rtg = oz->oz_rtg; 538*4e4d5207SChristoph Hellwig struct xfs_mount *mp = rtg_mount(rtg); 539*4e4d5207SChristoph Hellwig xfs_rgblock_t rgbno; 540*4e4d5207SChristoph Hellwig 541*4e4d5207SChristoph Hellwig spin_lock(&oz->oz_alloc_lock); 542*4e4d5207SChristoph Hellwig count_fsb = min3(count_fsb, XFS_MAX_BMBT_EXTLEN, 543*4e4d5207SChristoph Hellwig (xfs_filblks_t)rtg_blocks(rtg) - oz->oz_write_pointer); 544*4e4d5207SChristoph Hellwig if (!count_fsb) { 545*4e4d5207SChristoph Hellwig spin_unlock(&oz->oz_alloc_lock); 546*4e4d5207SChristoph Hellwig return 0; 547*4e4d5207SChristoph Hellwig } 548*4e4d5207SChristoph Hellwig rgbno = oz->oz_write_pointer; 549*4e4d5207SChristoph Hellwig oz->oz_write_pointer += count_fsb; 550*4e4d5207SChristoph Hellwig spin_unlock(&oz->oz_alloc_lock); 551*4e4d5207SChristoph Hellwig 552*4e4d5207SChristoph Hellwig trace_xfs_zone_alloc_blocks(oz, rgbno, count_fsb); 553*4e4d5207SChristoph Hellwig 554*4e4d5207SChristoph Hellwig *sector = xfs_gbno_to_daddr(&rtg->rtg_group, 0); 555*4e4d5207SChristoph Hellwig *is_seq = bdev_zone_is_seq(mp->m_rtdev_targp->bt_bdev, *sector); 556*4e4d5207SChristoph Hellwig if (!*is_seq) 557*4e4d5207SChristoph Hellwig *sector += XFS_FSB_TO_BB(mp, rgbno); 558*4e4d5207SChristoph Hellwig return XFS_FSB_TO_B(mp, count_fsb); 559*4e4d5207SChristoph Hellwig } 560*4e4d5207SChristoph Hellwig 561*4e4d5207SChristoph Hellwig void 562*4e4d5207SChristoph Hellwig xfs_mark_rtg_boundary( 563*4e4d5207SChristoph Hellwig struct iomap_ioend *ioend) 564*4e4d5207SChristoph Hellwig { 565*4e4d5207SChristoph Hellwig struct xfs_mount *mp = XFS_I(ioend->io_inode)->i_mount; 566*4e4d5207SChristoph Hellwig sector_t sector = ioend->io_bio.bi_iter.bi_sector; 567*4e4d5207SChristoph Hellwig 568*4e4d5207SChristoph Hellwig if (xfs_rtb_to_rgbno(mp, xfs_daddr_to_rtb(mp, sector)) == 0) 569*4e4d5207SChristoph Hellwig ioend->io_flags |= IOMAP_IOEND_BOUNDARY; 570*4e4d5207SChristoph Hellwig } 571*4e4d5207SChristoph Hellwig 572*4e4d5207SChristoph Hellwig static void 573*4e4d5207SChristoph Hellwig xfs_submit_zoned_bio( 574*4e4d5207SChristoph Hellwig struct iomap_ioend *ioend, 575*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz, 576*4e4d5207SChristoph Hellwig bool is_seq) 577*4e4d5207SChristoph Hellwig { 578*4e4d5207SChristoph Hellwig ioend->io_bio.bi_iter.bi_sector = ioend->io_sector; 579*4e4d5207SChristoph Hellwig ioend->io_private = oz; 580*4e4d5207SChristoph Hellwig atomic_inc(&oz->oz_ref); /* for xfs_zoned_end_io */ 581*4e4d5207SChristoph Hellwig 582*4e4d5207SChristoph Hellwig if (is_seq) { 583*4e4d5207SChristoph Hellwig ioend->io_bio.bi_opf &= ~REQ_OP_WRITE; 584*4e4d5207SChristoph Hellwig ioend->io_bio.bi_opf |= REQ_OP_ZONE_APPEND; 585*4e4d5207SChristoph Hellwig } else { 586*4e4d5207SChristoph Hellwig xfs_mark_rtg_boundary(ioend); 587*4e4d5207SChristoph Hellwig } 588*4e4d5207SChristoph Hellwig 589*4e4d5207SChristoph Hellwig submit_bio(&ioend->io_bio); 590*4e4d5207SChristoph Hellwig } 591*4e4d5207SChristoph Hellwig 592*4e4d5207SChristoph Hellwig void 593*4e4d5207SChristoph Hellwig xfs_zone_alloc_and_submit( 594*4e4d5207SChristoph Hellwig struct iomap_ioend *ioend, 595*4e4d5207SChristoph Hellwig struct xfs_open_zone **oz) 596*4e4d5207SChristoph Hellwig { 597*4e4d5207SChristoph Hellwig struct xfs_inode *ip = XFS_I(ioend->io_inode); 598*4e4d5207SChristoph Hellwig struct xfs_mount *mp = ip->i_mount; 599*4e4d5207SChristoph Hellwig bool pack_tight = xfs_zoned_pack_tight(ip); 600*4e4d5207SChristoph Hellwig unsigned int alloc_len; 601*4e4d5207SChristoph Hellwig struct iomap_ioend *split; 602*4e4d5207SChristoph Hellwig bool is_seq; 603*4e4d5207SChristoph Hellwig 604*4e4d5207SChristoph Hellwig if (xfs_is_shutdown(mp)) 605*4e4d5207SChristoph Hellwig goto out_error; 606*4e4d5207SChristoph Hellwig 607*4e4d5207SChristoph Hellwig /* 608*4e4d5207SChristoph Hellwig * If we don't have a cached zone in this write context, see if the 609*4e4d5207SChristoph Hellwig * last extent before the one we are writing to points to an active 610*4e4d5207SChristoph Hellwig * zone. If so, just continue writing to it. 611*4e4d5207SChristoph Hellwig */ 612*4e4d5207SChristoph Hellwig if (!*oz && ioend->io_offset) 613*4e4d5207SChristoph Hellwig *oz = xfs_last_used_zone(ioend); 614*4e4d5207SChristoph Hellwig if (!*oz) { 615*4e4d5207SChristoph Hellwig select_zone: 616*4e4d5207SChristoph Hellwig *oz = xfs_select_zone(mp, pack_tight); 617*4e4d5207SChristoph Hellwig if (!*oz) 618*4e4d5207SChristoph Hellwig goto out_error; 619*4e4d5207SChristoph Hellwig } 620*4e4d5207SChristoph Hellwig 621*4e4d5207SChristoph Hellwig alloc_len = xfs_zone_alloc_blocks(*oz, XFS_B_TO_FSB(mp, ioend->io_size), 622*4e4d5207SChristoph Hellwig &ioend->io_sector, &is_seq); 623*4e4d5207SChristoph Hellwig if (!alloc_len) { 624*4e4d5207SChristoph Hellwig xfs_open_zone_put(*oz); 625*4e4d5207SChristoph Hellwig goto select_zone; 626*4e4d5207SChristoph Hellwig } 627*4e4d5207SChristoph Hellwig 628*4e4d5207SChristoph Hellwig while ((split = iomap_split_ioend(ioend, alloc_len, is_seq))) { 629*4e4d5207SChristoph Hellwig if (IS_ERR(split)) 630*4e4d5207SChristoph Hellwig goto out_split_error; 631*4e4d5207SChristoph Hellwig alloc_len -= split->io_bio.bi_iter.bi_size; 632*4e4d5207SChristoph Hellwig xfs_submit_zoned_bio(split, *oz, is_seq); 633*4e4d5207SChristoph Hellwig if (!alloc_len) { 634*4e4d5207SChristoph Hellwig xfs_open_zone_put(*oz); 635*4e4d5207SChristoph Hellwig goto select_zone; 636*4e4d5207SChristoph Hellwig } 637*4e4d5207SChristoph Hellwig } 638*4e4d5207SChristoph Hellwig 639*4e4d5207SChristoph Hellwig xfs_submit_zoned_bio(ioend, *oz, is_seq); 640*4e4d5207SChristoph Hellwig return; 641*4e4d5207SChristoph Hellwig 642*4e4d5207SChristoph Hellwig out_split_error: 643*4e4d5207SChristoph Hellwig ioend->io_bio.bi_status = errno_to_blk_status(PTR_ERR(split)); 644*4e4d5207SChristoph Hellwig out_error: 645*4e4d5207SChristoph Hellwig bio_io_error(&ioend->io_bio); 646*4e4d5207SChristoph Hellwig } 647*4e4d5207SChristoph Hellwig 648*4e4d5207SChristoph Hellwig void 649*4e4d5207SChristoph Hellwig xfs_zoned_wake_all( 650*4e4d5207SChristoph Hellwig struct xfs_mount *mp) 651*4e4d5207SChristoph Hellwig { 652*4e4d5207SChristoph Hellwig if (!(mp->m_super->s_flags & SB_ACTIVE)) 653*4e4d5207SChristoph Hellwig return; /* can happen during log recovery */ 654*4e4d5207SChristoph Hellwig wake_up_all(&mp->m_zone_info->zi_zone_wait); 655*4e4d5207SChristoph Hellwig } 656*4e4d5207SChristoph Hellwig 657*4e4d5207SChristoph Hellwig /* 658*4e4d5207SChristoph Hellwig * Check if @rgbno in @rgb is a potentially valid block. It might still be 659*4e4d5207SChristoph Hellwig * unused, but that information is only found in the rmap. 660*4e4d5207SChristoph Hellwig */ 661*4e4d5207SChristoph Hellwig bool 662*4e4d5207SChristoph Hellwig xfs_zone_rgbno_is_valid( 663*4e4d5207SChristoph Hellwig struct xfs_rtgroup *rtg, 664*4e4d5207SChristoph Hellwig xfs_rgnumber_t rgbno) 665*4e4d5207SChristoph Hellwig { 666*4e4d5207SChristoph Hellwig lockdep_assert_held(&rtg_rmap(rtg)->i_lock); 667*4e4d5207SChristoph Hellwig 668*4e4d5207SChristoph Hellwig if (rtg->rtg_open_zone) 669*4e4d5207SChristoph Hellwig return rgbno < rtg->rtg_open_zone->oz_write_pointer; 670*4e4d5207SChristoph Hellwig return !xa_get_mark(&rtg_mount(rtg)->m_groups[XG_TYPE_RTG].xa, 671*4e4d5207SChristoph Hellwig rtg_rgno(rtg), XFS_RTG_FREE); 672*4e4d5207SChristoph Hellwig } 673*4e4d5207SChristoph Hellwig 674*4e4d5207SChristoph Hellwig static void 675*4e4d5207SChristoph Hellwig xfs_free_open_zones( 676*4e4d5207SChristoph Hellwig struct xfs_zone_info *zi) 677*4e4d5207SChristoph Hellwig { 678*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz; 679*4e4d5207SChristoph Hellwig 680*4e4d5207SChristoph Hellwig spin_lock(&zi->zi_open_zones_lock); 681*4e4d5207SChristoph Hellwig while ((oz = list_first_entry_or_null(&zi->zi_open_zones, 682*4e4d5207SChristoph Hellwig struct xfs_open_zone, oz_entry))) { 683*4e4d5207SChristoph Hellwig list_del(&oz->oz_entry); 684*4e4d5207SChristoph Hellwig xfs_open_zone_put(oz); 685*4e4d5207SChristoph Hellwig } 686*4e4d5207SChristoph Hellwig spin_unlock(&zi->zi_open_zones_lock); 687*4e4d5207SChristoph Hellwig } 688*4e4d5207SChristoph Hellwig 689*4e4d5207SChristoph Hellwig struct xfs_init_zones { 690*4e4d5207SChristoph Hellwig struct xfs_mount *mp; 691*4e4d5207SChristoph Hellwig uint64_t available; 692*4e4d5207SChristoph Hellwig uint64_t reclaimable; 693*4e4d5207SChristoph Hellwig }; 694*4e4d5207SChristoph Hellwig 695*4e4d5207SChristoph Hellwig static int 696*4e4d5207SChristoph Hellwig xfs_init_zone( 697*4e4d5207SChristoph Hellwig struct xfs_init_zones *iz, 698*4e4d5207SChristoph Hellwig struct xfs_rtgroup *rtg, 699*4e4d5207SChristoph Hellwig struct blk_zone *zone) 700*4e4d5207SChristoph Hellwig { 701*4e4d5207SChristoph Hellwig struct xfs_mount *mp = rtg_mount(rtg); 702*4e4d5207SChristoph Hellwig struct xfs_zone_info *zi = mp->m_zone_info; 703*4e4d5207SChristoph Hellwig uint64_t used = rtg_rmap(rtg)->i_used_blocks; 704*4e4d5207SChristoph Hellwig xfs_rgblock_t write_pointer, highest_rgbno; 705*4e4d5207SChristoph Hellwig 706*4e4d5207SChristoph Hellwig if (zone && !xfs_zone_validate(zone, rtg, &write_pointer)) 707*4e4d5207SChristoph Hellwig return -EFSCORRUPTED; 708*4e4d5207SChristoph Hellwig 709*4e4d5207SChristoph Hellwig /* 710*4e4d5207SChristoph Hellwig * For sequential write required zones we retrieved the hardware write 711*4e4d5207SChristoph Hellwig * pointer above. 712*4e4d5207SChristoph Hellwig * 713*4e4d5207SChristoph Hellwig * For conventional zones or conventional devices we don't have that 714*4e4d5207SChristoph Hellwig * luxury. Instead query the rmap to find the highest recorded block 715*4e4d5207SChristoph Hellwig * and set the write pointer to the block after that. In case of a 716*4e4d5207SChristoph Hellwig * power loss this misses blocks where the data I/O has completed but 717*4e4d5207SChristoph Hellwig * not recorded in the rmap yet, and it also rewrites blocks if the most 718*4e4d5207SChristoph Hellwig * recently written ones got deleted again before unmount, but this is 719*4e4d5207SChristoph Hellwig * the best we can do without hardware support. 720*4e4d5207SChristoph Hellwig */ 721*4e4d5207SChristoph Hellwig if (!zone || zone->cond == BLK_ZONE_COND_NOT_WP) { 722*4e4d5207SChristoph Hellwig xfs_rtgroup_lock(rtg, XFS_RTGLOCK_RMAP); 723*4e4d5207SChristoph Hellwig highest_rgbno = xfs_rtrmap_highest_rgbno(rtg); 724*4e4d5207SChristoph Hellwig if (highest_rgbno == NULLRGBLOCK) 725*4e4d5207SChristoph Hellwig write_pointer = 0; 726*4e4d5207SChristoph Hellwig else 727*4e4d5207SChristoph Hellwig write_pointer = highest_rgbno + 1; 728*4e4d5207SChristoph Hellwig xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_RMAP); 729*4e4d5207SChristoph Hellwig } 730*4e4d5207SChristoph Hellwig 731*4e4d5207SChristoph Hellwig if (write_pointer == 0) { 732*4e4d5207SChristoph Hellwig /* zone is empty */ 733*4e4d5207SChristoph Hellwig atomic_inc(&zi->zi_nr_free_zones); 734*4e4d5207SChristoph Hellwig xfs_group_set_mark(&rtg->rtg_group, XFS_RTG_FREE); 735*4e4d5207SChristoph Hellwig iz->available += rtg_blocks(rtg); 736*4e4d5207SChristoph Hellwig } else if (write_pointer < rtg_blocks(rtg)) { 737*4e4d5207SChristoph Hellwig /* zone is open */ 738*4e4d5207SChristoph Hellwig struct xfs_open_zone *oz; 739*4e4d5207SChristoph Hellwig 740*4e4d5207SChristoph Hellwig atomic_inc(&rtg_group(rtg)->xg_active_ref); 741*4e4d5207SChristoph Hellwig oz = xfs_init_open_zone(rtg, write_pointer, false); 742*4e4d5207SChristoph Hellwig list_add_tail(&oz->oz_entry, &zi->zi_open_zones); 743*4e4d5207SChristoph Hellwig zi->zi_nr_open_zones++; 744*4e4d5207SChristoph Hellwig 745*4e4d5207SChristoph Hellwig iz->available += (rtg_blocks(rtg) - write_pointer); 746*4e4d5207SChristoph Hellwig iz->reclaimable += write_pointer - used; 747*4e4d5207SChristoph Hellwig } else if (used < rtg_blocks(rtg)) { 748*4e4d5207SChristoph Hellwig /* zone fully written, but has freed blocks */ 749*4e4d5207SChristoph Hellwig iz->reclaimable += (rtg_blocks(rtg) - used); 750*4e4d5207SChristoph Hellwig } 751*4e4d5207SChristoph Hellwig 752*4e4d5207SChristoph Hellwig return 0; 753*4e4d5207SChristoph Hellwig } 754*4e4d5207SChristoph Hellwig 755*4e4d5207SChristoph Hellwig static int 756*4e4d5207SChristoph Hellwig xfs_get_zone_info_cb( 757*4e4d5207SChristoph Hellwig struct blk_zone *zone, 758*4e4d5207SChristoph Hellwig unsigned int idx, 759*4e4d5207SChristoph Hellwig void *data) 760*4e4d5207SChristoph Hellwig { 761*4e4d5207SChristoph Hellwig struct xfs_init_zones *iz = data; 762*4e4d5207SChristoph Hellwig struct xfs_mount *mp = iz->mp; 763*4e4d5207SChristoph Hellwig xfs_fsblock_t zsbno = xfs_daddr_to_rtb(mp, zone->start); 764*4e4d5207SChristoph Hellwig xfs_rgnumber_t rgno; 765*4e4d5207SChristoph Hellwig struct xfs_rtgroup *rtg; 766*4e4d5207SChristoph Hellwig int error; 767*4e4d5207SChristoph Hellwig 768*4e4d5207SChristoph Hellwig if (xfs_rtb_to_rgbno(mp, zsbno) != 0) { 769*4e4d5207SChristoph Hellwig xfs_warn(mp, "mismatched zone start 0x%llx.", zsbno); 770*4e4d5207SChristoph Hellwig return -EFSCORRUPTED; 771*4e4d5207SChristoph Hellwig } 772*4e4d5207SChristoph Hellwig 773*4e4d5207SChristoph Hellwig rgno = xfs_rtb_to_rgno(mp, zsbno); 774*4e4d5207SChristoph Hellwig rtg = xfs_rtgroup_grab(mp, rgno); 775*4e4d5207SChristoph Hellwig if (!rtg) { 776*4e4d5207SChristoph Hellwig xfs_warn(mp, "realtime group not found for zone %u.", rgno); 777*4e4d5207SChristoph Hellwig return -EFSCORRUPTED; 778*4e4d5207SChristoph Hellwig } 779*4e4d5207SChristoph Hellwig error = xfs_init_zone(iz, rtg, zone); 780*4e4d5207SChristoph Hellwig xfs_rtgroup_rele(rtg); 781*4e4d5207SChristoph Hellwig return error; 782*4e4d5207SChristoph Hellwig } 783*4e4d5207SChristoph Hellwig 784*4e4d5207SChristoph Hellwig /* 785*4e4d5207SChristoph Hellwig * Calculate the max open zone limit based on the of number of 786*4e4d5207SChristoph Hellwig * backing zones available 787*4e4d5207SChristoph Hellwig */ 788*4e4d5207SChristoph Hellwig static inline uint32_t 789*4e4d5207SChristoph Hellwig xfs_max_open_zones( 790*4e4d5207SChristoph Hellwig struct xfs_mount *mp) 791*4e4d5207SChristoph Hellwig { 792*4e4d5207SChristoph Hellwig unsigned int max_open, max_open_data_zones; 793*4e4d5207SChristoph Hellwig /* 794*4e4d5207SChristoph Hellwig * We need two zones for every open data zone, 795*4e4d5207SChristoph Hellwig * one in reserve as we don't reclaim open zones. One data zone 796*4e4d5207SChristoph Hellwig * and its spare is included in XFS_MIN_ZONES. 797*4e4d5207SChristoph Hellwig */ 798*4e4d5207SChristoph Hellwig max_open_data_zones = (mp->m_sb.sb_rgcount - XFS_MIN_ZONES) / 2 + 1; 799*4e4d5207SChristoph Hellwig max_open = max_open_data_zones + XFS_OPEN_GC_ZONES; 800*4e4d5207SChristoph Hellwig 801*4e4d5207SChristoph Hellwig /* 802*4e4d5207SChristoph Hellwig * Cap the max open limit to 1/4 of available space 803*4e4d5207SChristoph Hellwig */ 804*4e4d5207SChristoph Hellwig max_open = min(max_open, mp->m_sb.sb_rgcount / 4); 805*4e4d5207SChristoph Hellwig 806*4e4d5207SChristoph Hellwig return max(XFS_MIN_OPEN_ZONES, max_open); 807*4e4d5207SChristoph Hellwig } 808*4e4d5207SChristoph Hellwig 809*4e4d5207SChristoph Hellwig /* 810*4e4d5207SChristoph Hellwig * Normally we use the open zone limit that the device reports. If there is 811*4e4d5207SChristoph Hellwig * none let the user pick one from the command line. 812*4e4d5207SChristoph Hellwig * 813*4e4d5207SChristoph Hellwig * If the device doesn't report an open zone limit and there is no override, 814*4e4d5207SChristoph Hellwig * allow to hold about a quarter of the zones open. In theory we could allow 815*4e4d5207SChristoph Hellwig * all to be open, but at that point we run into GC deadlocks because we can't 816*4e4d5207SChristoph Hellwig * reclaim open zones. 817*4e4d5207SChristoph Hellwig * 818*4e4d5207SChristoph Hellwig * When used on conventional SSDs a lower open limit is advisable as we'll 819*4e4d5207SChristoph Hellwig * otherwise overwhelm the FTL just as much as a conventional block allocator. 820*4e4d5207SChristoph Hellwig * 821*4e4d5207SChristoph Hellwig * Note: To debug the open zone management code, force max_open to 1 here. 822*4e4d5207SChristoph Hellwig */ 823*4e4d5207SChristoph Hellwig static int 824*4e4d5207SChristoph Hellwig xfs_calc_open_zones( 825*4e4d5207SChristoph Hellwig struct xfs_mount *mp) 826*4e4d5207SChristoph Hellwig { 827*4e4d5207SChristoph Hellwig struct block_device *bdev = mp->m_rtdev_targp->bt_bdev; 828*4e4d5207SChristoph Hellwig unsigned int bdev_open_zones = bdev_max_open_zones(bdev); 829*4e4d5207SChristoph Hellwig 830*4e4d5207SChristoph Hellwig if (!mp->m_max_open_zones) { 831*4e4d5207SChristoph Hellwig if (bdev_open_zones) 832*4e4d5207SChristoph Hellwig mp->m_max_open_zones = bdev_open_zones; 833*4e4d5207SChristoph Hellwig else 834*4e4d5207SChristoph Hellwig mp->m_max_open_zones = xfs_max_open_zones(mp); 835*4e4d5207SChristoph Hellwig } 836*4e4d5207SChristoph Hellwig 837*4e4d5207SChristoph Hellwig if (mp->m_max_open_zones < XFS_MIN_OPEN_ZONES) { 838*4e4d5207SChristoph Hellwig xfs_notice(mp, "need at least %u open zones.", 839*4e4d5207SChristoph Hellwig XFS_MIN_OPEN_ZONES); 840*4e4d5207SChristoph Hellwig return -EIO; 841*4e4d5207SChristoph Hellwig } 842*4e4d5207SChristoph Hellwig 843*4e4d5207SChristoph Hellwig if (bdev_open_zones && bdev_open_zones < mp->m_max_open_zones) { 844*4e4d5207SChristoph Hellwig mp->m_max_open_zones = bdev_open_zones; 845*4e4d5207SChristoph Hellwig xfs_info(mp, "limiting open zones to %u due to hardware limit.\n", 846*4e4d5207SChristoph Hellwig bdev_open_zones); 847*4e4d5207SChristoph Hellwig } 848*4e4d5207SChristoph Hellwig 849*4e4d5207SChristoph Hellwig if (mp->m_max_open_zones > xfs_max_open_zones(mp)) { 850*4e4d5207SChristoph Hellwig mp->m_max_open_zones = xfs_max_open_zones(mp); 851*4e4d5207SChristoph Hellwig xfs_info(mp, 852*4e4d5207SChristoph Hellwig "limiting open zones to %u due to total zone count (%u)", 853*4e4d5207SChristoph Hellwig mp->m_max_open_zones, mp->m_sb.sb_rgcount); 854*4e4d5207SChristoph Hellwig } 855*4e4d5207SChristoph Hellwig 856*4e4d5207SChristoph Hellwig return 0; 857*4e4d5207SChristoph Hellwig } 858*4e4d5207SChristoph Hellwig 859*4e4d5207SChristoph Hellwig static struct xfs_zone_info * 860*4e4d5207SChristoph Hellwig xfs_alloc_zone_info( 861*4e4d5207SChristoph Hellwig struct xfs_mount *mp) 862*4e4d5207SChristoph Hellwig { 863*4e4d5207SChristoph Hellwig struct xfs_zone_info *zi; 864*4e4d5207SChristoph Hellwig 865*4e4d5207SChristoph Hellwig zi = kzalloc(sizeof(*zi), GFP_KERNEL); 866*4e4d5207SChristoph Hellwig if (!zi) 867*4e4d5207SChristoph Hellwig return NULL; 868*4e4d5207SChristoph Hellwig INIT_LIST_HEAD(&zi->zi_open_zones); 869*4e4d5207SChristoph Hellwig INIT_LIST_HEAD(&zi->zi_reclaim_reservations); 870*4e4d5207SChristoph Hellwig spin_lock_init(&zi->zi_reset_list_lock); 871*4e4d5207SChristoph Hellwig spin_lock_init(&zi->zi_open_zones_lock); 872*4e4d5207SChristoph Hellwig spin_lock_init(&zi->zi_reservation_lock); 873*4e4d5207SChristoph Hellwig init_waitqueue_head(&zi->zi_zone_wait); 874*4e4d5207SChristoph Hellwig return zi; 875*4e4d5207SChristoph Hellwig } 876*4e4d5207SChristoph Hellwig 877*4e4d5207SChristoph Hellwig static void 878*4e4d5207SChristoph Hellwig xfs_free_zone_info( 879*4e4d5207SChristoph Hellwig struct xfs_zone_info *zi) 880*4e4d5207SChristoph Hellwig { 881*4e4d5207SChristoph Hellwig xfs_free_open_zones(zi); 882*4e4d5207SChristoph Hellwig kfree(zi); 883*4e4d5207SChristoph Hellwig } 884*4e4d5207SChristoph Hellwig 885*4e4d5207SChristoph Hellwig int 886*4e4d5207SChristoph Hellwig xfs_mount_zones( 887*4e4d5207SChristoph Hellwig struct xfs_mount *mp) 888*4e4d5207SChristoph Hellwig { 889*4e4d5207SChristoph Hellwig struct xfs_init_zones iz = { 890*4e4d5207SChristoph Hellwig .mp = mp, 891*4e4d5207SChristoph Hellwig }; 892*4e4d5207SChristoph Hellwig struct xfs_buftarg *bt = mp->m_rtdev_targp; 893*4e4d5207SChristoph Hellwig int error; 894*4e4d5207SChristoph Hellwig 895*4e4d5207SChristoph Hellwig if (!bt) { 896*4e4d5207SChristoph Hellwig xfs_notice(mp, "RT device missing."); 897*4e4d5207SChristoph Hellwig return -EINVAL; 898*4e4d5207SChristoph Hellwig } 899*4e4d5207SChristoph Hellwig 900*4e4d5207SChristoph Hellwig if (!xfs_has_rtgroups(mp) || !xfs_has_rmapbt(mp)) { 901*4e4d5207SChristoph Hellwig xfs_notice(mp, "invalid flag combination."); 902*4e4d5207SChristoph Hellwig return -EFSCORRUPTED; 903*4e4d5207SChristoph Hellwig } 904*4e4d5207SChristoph Hellwig if (mp->m_sb.sb_rextsize != 1) { 905*4e4d5207SChristoph Hellwig xfs_notice(mp, "zoned file systems do not support rextsize."); 906*4e4d5207SChristoph Hellwig return -EFSCORRUPTED; 907*4e4d5207SChristoph Hellwig } 908*4e4d5207SChristoph Hellwig if (mp->m_sb.sb_rgcount < XFS_MIN_ZONES) { 909*4e4d5207SChristoph Hellwig xfs_notice(mp, 910*4e4d5207SChristoph Hellwig "zoned file systems need to have at least %u zones.", XFS_MIN_ZONES); 911*4e4d5207SChristoph Hellwig return -EFSCORRUPTED; 912*4e4d5207SChristoph Hellwig } 913*4e4d5207SChristoph Hellwig 914*4e4d5207SChristoph Hellwig error = xfs_calc_open_zones(mp); 915*4e4d5207SChristoph Hellwig if (error) 916*4e4d5207SChristoph Hellwig return error; 917*4e4d5207SChristoph Hellwig 918*4e4d5207SChristoph Hellwig mp->m_zone_info = xfs_alloc_zone_info(mp); 919*4e4d5207SChristoph Hellwig if (!mp->m_zone_info) 920*4e4d5207SChristoph Hellwig return -ENOMEM; 921*4e4d5207SChristoph Hellwig 922*4e4d5207SChristoph Hellwig xfs_info(mp, "%u zones of %u blocks size (%u max open)", 923*4e4d5207SChristoph Hellwig mp->m_sb.sb_rgcount, mp->m_groups[XG_TYPE_RTG].blocks, 924*4e4d5207SChristoph Hellwig mp->m_max_open_zones); 925*4e4d5207SChristoph Hellwig 926*4e4d5207SChristoph Hellwig if (bdev_is_zoned(bt->bt_bdev)) { 927*4e4d5207SChristoph Hellwig error = blkdev_report_zones(bt->bt_bdev, 928*4e4d5207SChristoph Hellwig XFS_FSB_TO_BB(mp, mp->m_sb.sb_rtstart), 929*4e4d5207SChristoph Hellwig mp->m_sb.sb_rgcount, xfs_get_zone_info_cb, &iz); 930*4e4d5207SChristoph Hellwig if (error < 0) 931*4e4d5207SChristoph Hellwig goto out_free_zone_info; 932*4e4d5207SChristoph Hellwig } else { 933*4e4d5207SChristoph Hellwig struct xfs_rtgroup *rtg = NULL; 934*4e4d5207SChristoph Hellwig 935*4e4d5207SChristoph Hellwig while ((rtg = xfs_rtgroup_next(mp, rtg))) { 936*4e4d5207SChristoph Hellwig error = xfs_init_zone(&iz, rtg, NULL); 937*4e4d5207SChristoph Hellwig if (error) 938*4e4d5207SChristoph Hellwig goto out_free_zone_info; 939*4e4d5207SChristoph Hellwig } 940*4e4d5207SChristoph Hellwig } 941*4e4d5207SChristoph Hellwig 942*4e4d5207SChristoph Hellwig xfs_set_freecounter(mp, XC_FREE_RTEXTENTS, 943*4e4d5207SChristoph Hellwig iz.available + iz.reclaimable); 944*4e4d5207SChristoph Hellwig return 0; 945*4e4d5207SChristoph Hellwig 946*4e4d5207SChristoph Hellwig out_free_zone_info: 947*4e4d5207SChristoph Hellwig xfs_free_zone_info(mp->m_zone_info); 948*4e4d5207SChristoph Hellwig return error; 949*4e4d5207SChristoph Hellwig } 950*4e4d5207SChristoph Hellwig 951*4e4d5207SChristoph Hellwig void 952*4e4d5207SChristoph Hellwig xfs_unmount_zones( 953*4e4d5207SChristoph Hellwig struct xfs_mount *mp) 954*4e4d5207SChristoph Hellwig { 955*4e4d5207SChristoph Hellwig xfs_free_zone_info(mp->m_zone_info); 956*4e4d5207SChristoph Hellwig } 957