10b61f8a4SDave Chinner // SPDX-License-Identifier: GPL-2.0+ 2bdf28630SDarrick J. Wong /* 3bdf28630SDarrick J. Wong * Copyright (C) 2016 Oracle. All Rights Reserved. 4bdf28630SDarrick J. Wong * Author: Darrick J. Wong <darrick.wong@oracle.com> 5bdf28630SDarrick J. Wong */ 6bdf28630SDarrick J. Wong #include "xfs.h" 7bdf28630SDarrick J. Wong #include "xfs_fs.h" 8bdf28630SDarrick J. Wong #include "xfs_shared.h" 9bdf28630SDarrick J. Wong #include "xfs_format.h" 10bdf28630SDarrick J. Wong #include "xfs_log_format.h" 11bdf28630SDarrick J. Wong #include "xfs_trans_resv.h" 12bdf28630SDarrick J. Wong #include "xfs_mount.h" 13bdf28630SDarrick J. Wong #include "xfs_defer.h" 14bdf28630SDarrick J. Wong #include "xfs_btree.h" 15bdf28630SDarrick J. Wong #include "xfs_bmap.h" 16bdf28630SDarrick J. Wong #include "xfs_refcount_btree.h" 17bdf28630SDarrick J. Wong #include "xfs_alloc.h" 18e9e899a2SDarrick J. Wong #include "xfs_errortag.h" 19bdf28630SDarrick J. Wong #include "xfs_error.h" 20bdf28630SDarrick J. Wong #include "xfs_trace.h" 21bdf28630SDarrick J. Wong #include "xfs_trans.h" 22bdf28630SDarrick J. Wong #include "xfs_bit.h" 23bdf28630SDarrick J. Wong #include "xfs_refcount.h" 24174edb0eSDarrick J. Wong #include "xfs_rmap.h" 25a81a0621SDave Chinner #include "xfs_ag.h" 26bdf28630SDarrick J. Wong 27f3c799c2SDarrick J. Wong struct kmem_cache *xfs_refcount_intent_cache; 28f3c799c2SDarrick J. Wong 2931727258SDarrick J. Wong /* Allowable refcount adjustment amounts. */ 3031727258SDarrick J. Wong enum xfs_refc_adjust_op { 3131727258SDarrick J. Wong XFS_REFCOUNT_ADJUST_INCREASE = 1, 3231727258SDarrick J. Wong XFS_REFCOUNT_ADJUST_DECREASE = -1, 33174edb0eSDarrick J. Wong XFS_REFCOUNT_ADJUST_COW_ALLOC = 0, 34174edb0eSDarrick J. Wong XFS_REFCOUNT_ADJUST_COW_FREE = -1, 3531727258SDarrick J. Wong }; 3631727258SDarrick J. Wong 37174edb0eSDarrick J. Wong STATIC int __xfs_refcount_cow_alloc(struct xfs_btree_cur *rcur, 380f37d178SBrian Foster xfs_agblock_t agbno, xfs_extlen_t aglen); 39174edb0eSDarrick J. Wong STATIC int __xfs_refcount_cow_free(struct xfs_btree_cur *rcur, 400f37d178SBrian Foster xfs_agblock_t agbno, xfs_extlen_t aglen); 41174edb0eSDarrick J. Wong 42bdf28630SDarrick J. Wong /* 43bdf28630SDarrick J. Wong * Look up the first record less than or equal to [bno, len] in the btree 44bdf28630SDarrick J. Wong * given by cur. 45bdf28630SDarrick J. Wong */ 46bdf28630SDarrick J. Wong int 47bdf28630SDarrick J. Wong xfs_refcount_lookup_le( 48bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 499a50ee4fSDarrick J. Wong enum xfs_refc_domain domain, 50bdf28630SDarrick J. Wong xfs_agblock_t bno, 51bdf28630SDarrick J. Wong int *stat) 52bdf28630SDarrick J. Wong { 539a50ee4fSDarrick J. Wong trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, 549a50ee4fSDarrick J. Wong xfs_refcount_encode_startblock(bno, domain), 55bdf28630SDarrick J. Wong XFS_LOOKUP_LE); 56bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_startblock = bno; 57bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_blockcount = 0; 589a50ee4fSDarrick J. Wong cur->bc_rec.rc.rc_domain = domain; 59bdf28630SDarrick J. Wong return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat); 60bdf28630SDarrick J. Wong } 61bdf28630SDarrick J. Wong 62bdf28630SDarrick J. Wong /* 63bdf28630SDarrick J. Wong * Look up the first record greater than or equal to [bno, len] in the btree 64bdf28630SDarrick J. Wong * given by cur. 65bdf28630SDarrick J. Wong */ 66bdf28630SDarrick J. Wong int 67bdf28630SDarrick J. Wong xfs_refcount_lookup_ge( 68bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 699a50ee4fSDarrick J. Wong enum xfs_refc_domain domain, 70bdf28630SDarrick J. Wong xfs_agblock_t bno, 71bdf28630SDarrick J. Wong int *stat) 72bdf28630SDarrick J. Wong { 739a50ee4fSDarrick J. Wong trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, 749a50ee4fSDarrick J. Wong xfs_refcount_encode_startblock(bno, domain), 75bdf28630SDarrick J. Wong XFS_LOOKUP_GE); 76bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_startblock = bno; 77bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_blockcount = 0; 789a50ee4fSDarrick J. Wong cur->bc_rec.rc.rc_domain = domain; 79bdf28630SDarrick J. Wong return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat); 80bdf28630SDarrick J. Wong } 81bdf28630SDarrick J. Wong 8208daa3ccSDarrick J. Wong /* 8308daa3ccSDarrick J. Wong * Look up the first record equal to [bno, len] in the btree 8408daa3ccSDarrick J. Wong * given by cur. 8508daa3ccSDarrick J. Wong */ 8608daa3ccSDarrick J. Wong int 8708daa3ccSDarrick J. Wong xfs_refcount_lookup_eq( 8808daa3ccSDarrick J. Wong struct xfs_btree_cur *cur, 899a50ee4fSDarrick J. Wong enum xfs_refc_domain domain, 9008daa3ccSDarrick J. Wong xfs_agblock_t bno, 9108daa3ccSDarrick J. Wong int *stat) 9208daa3ccSDarrick J. Wong { 939a50ee4fSDarrick J. Wong trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, 949a50ee4fSDarrick J. Wong xfs_refcount_encode_startblock(bno, domain), 9508daa3ccSDarrick J. Wong XFS_LOOKUP_LE); 9608daa3ccSDarrick J. Wong cur->bc_rec.rc.rc_startblock = bno; 9708daa3ccSDarrick J. Wong cur->bc_rec.rc.rc_blockcount = 0; 989a50ee4fSDarrick J. Wong cur->bc_rec.rc.rc_domain = domain; 9908daa3ccSDarrick J. Wong return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat); 10008daa3ccSDarrick J. Wong } 10108daa3ccSDarrick J. Wong 102174edb0eSDarrick J. Wong /* Convert on-disk record to in-core format. */ 1037f8f1313SDarrick J. Wong void 104174edb0eSDarrick J. Wong xfs_refcount_btrec_to_irec( 105159eb69dSDarrick J. Wong const union xfs_btree_rec *rec, 106174edb0eSDarrick J. Wong struct xfs_refcount_irec *irec) 107174edb0eSDarrick J. Wong { 1089a50ee4fSDarrick J. Wong uint32_t start; 1099a50ee4fSDarrick J. Wong 1109a50ee4fSDarrick J. Wong start = be32_to_cpu(rec->refc.rc_startblock); 1119a50ee4fSDarrick J. Wong if (start & XFS_REFC_COW_START) { 1129a50ee4fSDarrick J. Wong start &= ~XFS_REFC_COW_START; 1139a50ee4fSDarrick J. Wong irec->rc_domain = XFS_REFC_DOMAIN_COW; 1149a50ee4fSDarrick J. Wong } else { 1159a50ee4fSDarrick J. Wong irec->rc_domain = XFS_REFC_DOMAIN_SHARED; 1169a50ee4fSDarrick J. Wong } 1179a50ee4fSDarrick J. Wong 1189a50ee4fSDarrick J. Wong irec->rc_startblock = start; 119174edb0eSDarrick J. Wong irec->rc_blockcount = be32_to_cpu(rec->refc.rc_blockcount); 120174edb0eSDarrick J. Wong irec->rc_refcount = be32_to_cpu(rec->refc.rc_refcount); 121174edb0eSDarrick J. Wong } 122174edb0eSDarrick J. Wong 123bdf28630SDarrick J. Wong /* 124bdf28630SDarrick J. Wong * Get the data from the pointed-to record. 125bdf28630SDarrick J. Wong */ 126bdf28630SDarrick J. Wong int 127bdf28630SDarrick J. Wong xfs_refcount_get_rec( 128bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 129bdf28630SDarrick J. Wong struct xfs_refcount_irec *irec, 130bdf28630SDarrick J. Wong int *stat) 131bdf28630SDarrick J. Wong { 1329e6c08d4SDave Chinner struct xfs_mount *mp = cur->bc_mp; 1330800169eSDave Chinner struct xfs_perag *pag = cur->bc_ag.pag; 134bdf28630SDarrick J. Wong union xfs_btree_rec *rec; 135bdf28630SDarrick J. Wong int error; 136bdf28630SDarrick J. Wong 137bdf28630SDarrick J. Wong error = xfs_btree_get_rec(cur, &rec, stat); 1389e6c08d4SDave Chinner if (error || !*stat) 139bdf28630SDarrick J. Wong return error; 1409e6c08d4SDave Chinner 1419e6c08d4SDave Chinner xfs_refcount_btrec_to_irec(rec, irec); 1429e6c08d4SDave Chinner if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN) 1439e6c08d4SDave Chinner goto out_bad_rec; 1449e6c08d4SDave Chinner 145f492135dSDarrick J. Wong if (!xfs_refcount_check_domain(irec)) 1469e6c08d4SDave Chinner goto out_bad_rec; 1479e6c08d4SDave Chinner 1489e6c08d4SDave Chinner /* check for valid extent range, including overflow */ 1499a50ee4fSDarrick J. Wong if (!xfs_verify_agbext(pag, irec->rc_startblock, irec->rc_blockcount)) 1509e6c08d4SDave Chinner goto out_bad_rec; 1519e6c08d4SDave Chinner 1529e6c08d4SDave Chinner if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT) 1539e6c08d4SDave Chinner goto out_bad_rec; 1549e6c08d4SDave Chinner 1550800169eSDave Chinner trace_xfs_refcount_get(cur->bc_mp, pag->pag_agno, irec); 1569e6c08d4SDave Chinner return 0; 1579e6c08d4SDave Chinner 1589e6c08d4SDave Chinner out_bad_rec: 1599e6c08d4SDave Chinner xfs_warn(mp, 1600800169eSDave Chinner "Refcount BTree record corruption in AG %d detected!", 1610800169eSDave Chinner pag->pag_agno); 1629e6c08d4SDave Chinner xfs_warn(mp, 1639e6c08d4SDave Chinner "Start block 0x%x, block count 0x%x, references 0x%x", 1649e6c08d4SDave Chinner irec->rc_startblock, irec->rc_blockcount, irec->rc_refcount); 1659e6c08d4SDave Chinner return -EFSCORRUPTED; 166bdf28630SDarrick J. Wong } 167bdf28630SDarrick J. Wong 168bdf28630SDarrick J. Wong /* 169bdf28630SDarrick J. Wong * Update the record referred to by cur to the value given 170bdf28630SDarrick J. Wong * by [bno, len, refcount]. 171bdf28630SDarrick J. Wong * This either works (return 0) or gets an EFSCORRUPTED error. 172bdf28630SDarrick J. Wong */ 173bdf28630SDarrick J. Wong STATIC int 174bdf28630SDarrick J. Wong xfs_refcount_update( 175bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 176bdf28630SDarrick J. Wong struct xfs_refcount_irec *irec) 177bdf28630SDarrick J. Wong { 178bdf28630SDarrick J. Wong union xfs_btree_rec rec; 1799a50ee4fSDarrick J. Wong uint32_t start; 180bdf28630SDarrick J. Wong int error; 181bdf28630SDarrick J. Wong 18250f02fe3SDave Chinner trace_xfs_refcount_update(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec); 1839a50ee4fSDarrick J. Wong 1849a50ee4fSDarrick J. Wong start = xfs_refcount_encode_startblock(irec->rc_startblock, 1859a50ee4fSDarrick J. Wong irec->rc_domain); 1869a50ee4fSDarrick J. Wong rec.refc.rc_startblock = cpu_to_be32(start); 187bdf28630SDarrick J. Wong rec.refc.rc_blockcount = cpu_to_be32(irec->rc_blockcount); 188bdf28630SDarrick J. Wong rec.refc.rc_refcount = cpu_to_be32(irec->rc_refcount); 1899a50ee4fSDarrick J. Wong 190bdf28630SDarrick J. Wong error = xfs_btree_update(cur, &rec); 191bdf28630SDarrick J. Wong if (error) 192bdf28630SDarrick J. Wong trace_xfs_refcount_update_error(cur->bc_mp, 19350f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 194bdf28630SDarrick J. Wong return error; 195bdf28630SDarrick J. Wong } 196bdf28630SDarrick J. Wong 197bdf28630SDarrick J. Wong /* 198bdf28630SDarrick J. Wong * Insert the record referred to by cur to the value given 199bdf28630SDarrick J. Wong * by [bno, len, refcount]. 200bdf28630SDarrick J. Wong * This either works (return 0) or gets an EFSCORRUPTED error. 201bdf28630SDarrick J. Wong */ 2027f8f1313SDarrick J. Wong int 203bdf28630SDarrick J. Wong xfs_refcount_insert( 204bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 205bdf28630SDarrick J. Wong struct xfs_refcount_irec *irec, 206bdf28630SDarrick J. Wong int *i) 207bdf28630SDarrick J. Wong { 208bdf28630SDarrick J. Wong int error; 209bdf28630SDarrick J. Wong 21050f02fe3SDave Chinner trace_xfs_refcount_insert(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec); 2119a50ee4fSDarrick J. Wong 212bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_startblock = irec->rc_startblock; 213bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_blockcount = irec->rc_blockcount; 214bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_refcount = irec->rc_refcount; 2159a50ee4fSDarrick J. Wong cur->bc_rec.rc.rc_domain = irec->rc_domain; 2169a50ee4fSDarrick J. Wong 217bdf28630SDarrick J. Wong error = xfs_btree_insert(cur, i); 21816858f7cSDave Chinner if (error) 21916858f7cSDave Chinner goto out_error; 220f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, *i != 1)) { 221f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 222f9e03706SDarrick J. Wong goto out_error; 223f9e03706SDarrick J. Wong } 22416858f7cSDave Chinner 225bdf28630SDarrick J. Wong out_error: 226bdf28630SDarrick J. Wong if (error) 227bdf28630SDarrick J. Wong trace_xfs_refcount_insert_error(cur->bc_mp, 22850f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 229bdf28630SDarrick J. Wong return error; 230bdf28630SDarrick J. Wong } 231bdf28630SDarrick J. Wong 232bdf28630SDarrick J. Wong /* 233bdf28630SDarrick J. Wong * Remove the record referred to by cur, then set the pointer to the spot 234bdf28630SDarrick J. Wong * where the record could be re-inserted, in case we want to increment or 235bdf28630SDarrick J. Wong * decrement the cursor. 236bdf28630SDarrick J. Wong * This either works (return 0) or gets an EFSCORRUPTED error. 237bdf28630SDarrick J. Wong */ 238bdf28630SDarrick J. Wong STATIC int 239bdf28630SDarrick J. Wong xfs_refcount_delete( 240bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 241bdf28630SDarrick J. Wong int *i) 242bdf28630SDarrick J. Wong { 243bdf28630SDarrick J. Wong struct xfs_refcount_irec irec; 244bdf28630SDarrick J. Wong int found_rec; 245bdf28630SDarrick J. Wong int error; 246bdf28630SDarrick J. Wong 247bdf28630SDarrick J. Wong error = xfs_refcount_get_rec(cur, &irec, &found_rec); 248bdf28630SDarrick J. Wong if (error) 249bdf28630SDarrick J. Wong goto out_error; 250f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 251f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 252f9e03706SDarrick J. Wong goto out_error; 253f9e03706SDarrick J. Wong } 25450f02fe3SDave Chinner trace_xfs_refcount_delete(cur->bc_mp, cur->bc_ag.pag->pag_agno, &irec); 255bdf28630SDarrick J. Wong error = xfs_btree_delete(cur, i); 256f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, *i != 1)) { 257f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 258f9e03706SDarrick J. Wong goto out_error; 259f9e03706SDarrick J. Wong } 260bdf28630SDarrick J. Wong if (error) 261bdf28630SDarrick J. Wong goto out_error; 2629a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_ge(cur, irec.rc_domain, irec.rc_startblock, 2639a50ee4fSDarrick J. Wong &found_rec); 264bdf28630SDarrick J. Wong out_error: 265bdf28630SDarrick J. Wong if (error) 266bdf28630SDarrick J. Wong trace_xfs_refcount_delete_error(cur->bc_mp, 26750f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 268bdf28630SDarrick J. Wong return error; 269bdf28630SDarrick J. Wong } 27031727258SDarrick J. Wong 27131727258SDarrick J. Wong /* 27231727258SDarrick J. Wong * Adjusting the Reference Count 27331727258SDarrick J. Wong * 27431727258SDarrick J. Wong * As stated elsewhere, the reference count btree (refcbt) stores 27531727258SDarrick J. Wong * >1 reference counts for extents of physical blocks. In this 27631727258SDarrick J. Wong * operation, we're either raising or lowering the reference count of 27731727258SDarrick J. Wong * some subrange stored in the tree: 27831727258SDarrick J. Wong * 27931727258SDarrick J. Wong * <------ adjustment range ------> 28031727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+--------- 28131727258SDarrick J. Wong * 2 | | 3 | 4 | |17| 55 | 10 28231727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+--------- 28331727258SDarrick J. Wong * X axis is physical blocks number; 28431727258SDarrick J. Wong * reference counts are the numbers inside the rectangles 28531727258SDarrick J. Wong * 28631727258SDarrick J. Wong * The first thing we need to do is to ensure that there are no 28731727258SDarrick J. Wong * refcount extents crossing either boundary of the range to be 28831727258SDarrick J. Wong * adjusted. For any extent that does cross a boundary, split it into 28931727258SDarrick J. Wong * two extents so that we can increment the refcount of one of the 29031727258SDarrick J. Wong * pieces later: 29131727258SDarrick J. Wong * 29231727258SDarrick J. Wong * <------ adjustment range ------> 29331727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+----+---- 29431727258SDarrick J. Wong * 2 | | 3 | 2 | |17| 55 | 10 | 10 29531727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+----+---- 29631727258SDarrick J. Wong * 29731727258SDarrick J. Wong * For this next step, let's assume that all the physical blocks in 29831727258SDarrick J. Wong * the adjustment range are mapped to a file and are therefore in use 29931727258SDarrick J. Wong * at least once. Therefore, we can infer that any gap in the 30031727258SDarrick J. Wong * refcount tree within the adjustment range represents a physical 30131727258SDarrick J. Wong * extent with refcount == 1: 30231727258SDarrick J. Wong * 30331727258SDarrick J. Wong * <------ adjustment range ------> 30431727258SDarrick J. Wong * ----+---+---+-----+-+--+--------+----+---- 30531727258SDarrick J. Wong * 2 |"1"| 3 | 2 |1|17| 55 | 10 | 10 30631727258SDarrick J. Wong * ----+---+---+-----+-+--+--------+----+---- 30731727258SDarrick J. Wong * ^ 30831727258SDarrick J. Wong * 30931727258SDarrick J. Wong * For each extent that falls within the interval range, figure out 31031727258SDarrick J. Wong * which extent is to the left or the right of that extent. Now we 31131727258SDarrick J. Wong * have a left, current, and right extent. If the new reference count 31231727258SDarrick J. Wong * of the center extent enables us to merge left, center, and right 31331727258SDarrick J. Wong * into one record covering all three, do so. If the center extent is 31431727258SDarrick J. Wong * at the left end of the range, abuts the left extent, and its new 31531727258SDarrick J. Wong * reference count matches the left extent's record, then merge them. 31631727258SDarrick J. Wong * If the center extent is at the right end of the range, abuts the 31731727258SDarrick J. Wong * right extent, and the reference counts match, merge those. In the 31831727258SDarrick J. Wong * example, we can left merge (assuming an increment operation): 31931727258SDarrick J. Wong * 32031727258SDarrick J. Wong * <------ adjustment range ------> 32131727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 32231727258SDarrick J. Wong * 2 | 3 | 2 |1|17| 55 | 10 | 10 32331727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 32431727258SDarrick J. Wong * ^ 32531727258SDarrick J. Wong * 32631727258SDarrick J. Wong * For all other extents within the range, adjust the reference count 32731727258SDarrick J. Wong * or delete it if the refcount falls below 2. If we were 32831727258SDarrick J. Wong * incrementing, the end result looks like this: 32931727258SDarrick J. Wong * 33031727258SDarrick J. Wong * <------ adjustment range ------> 33131727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 33231727258SDarrick J. Wong * 2 | 4 | 3 |2|18| 56 | 11 | 10 33331727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 33431727258SDarrick J. Wong * 33531727258SDarrick J. Wong * The result of a decrement operation looks as such: 33631727258SDarrick J. Wong * 33731727258SDarrick J. Wong * <------ adjustment range ------> 33831727258SDarrick J. Wong * ----+ +---+ +--+--------+----+---- 33931727258SDarrick J. Wong * 2 | | 2 | |16| 54 | 9 | 10 34031727258SDarrick J. Wong * ----+ +---+ +--+--------+----+---- 34131727258SDarrick J. Wong * DDDD 111111DD 34231727258SDarrick J. Wong * 34331727258SDarrick J. Wong * The blocks marked "D" are freed; the blocks marked "1" are only 34431727258SDarrick J. Wong * referenced once and therefore the record is removed from the 34531727258SDarrick J. Wong * refcount btree. 34631727258SDarrick J. Wong */ 34731727258SDarrick J. Wong 34831727258SDarrick J. Wong /* Next block after this extent. */ 34931727258SDarrick J. Wong static inline xfs_agblock_t 35031727258SDarrick J. Wong xfs_refc_next( 35131727258SDarrick J. Wong struct xfs_refcount_irec *rc) 35231727258SDarrick J. Wong { 35331727258SDarrick J. Wong return rc->rc_startblock + rc->rc_blockcount; 35431727258SDarrick J. Wong } 35531727258SDarrick J. Wong 35631727258SDarrick J. Wong /* 35731727258SDarrick J. Wong * Split a refcount extent that crosses agbno. 35831727258SDarrick J. Wong */ 35931727258SDarrick J. Wong STATIC int 36031727258SDarrick J. Wong xfs_refcount_split_extent( 36131727258SDarrick J. Wong struct xfs_btree_cur *cur, 3629a50ee4fSDarrick J. Wong enum xfs_refc_domain domain, 36331727258SDarrick J. Wong xfs_agblock_t agbno, 36431727258SDarrick J. Wong bool *shape_changed) 36531727258SDarrick J. Wong { 36631727258SDarrick J. Wong struct xfs_refcount_irec rcext, tmp; 36731727258SDarrick J. Wong int found_rec; 36831727258SDarrick J. Wong int error; 36931727258SDarrick J. Wong 37031727258SDarrick J. Wong *shape_changed = false; 3719a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(cur, domain, agbno, &found_rec); 37231727258SDarrick J. Wong if (error) 37331727258SDarrick J. Wong goto out_error; 37431727258SDarrick J. Wong if (!found_rec) 37531727258SDarrick J. Wong return 0; 37631727258SDarrick J. Wong 37731727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &rcext, &found_rec); 37831727258SDarrick J. Wong if (error) 37931727258SDarrick J. Wong goto out_error; 380f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 381f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 382f9e03706SDarrick J. Wong goto out_error; 383f9e03706SDarrick J. Wong } 384f62ac3e0SDarrick J. Wong if (rcext.rc_domain != domain) 385f62ac3e0SDarrick J. Wong return 0; 38631727258SDarrick J. Wong if (rcext.rc_startblock == agbno || xfs_refc_next(&rcext) <= agbno) 38731727258SDarrick J. Wong return 0; 38831727258SDarrick J. Wong 38931727258SDarrick J. Wong *shape_changed = true; 39050f02fe3SDave Chinner trace_xfs_refcount_split_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno, 39131727258SDarrick J. Wong &rcext, agbno); 39231727258SDarrick J. Wong 39331727258SDarrick J. Wong /* Establish the right extent. */ 39431727258SDarrick J. Wong tmp = rcext; 39531727258SDarrick J. Wong tmp.rc_startblock = agbno; 39631727258SDarrick J. Wong tmp.rc_blockcount -= (agbno - rcext.rc_startblock); 39731727258SDarrick J. Wong error = xfs_refcount_update(cur, &tmp); 39831727258SDarrick J. Wong if (error) 39931727258SDarrick J. Wong goto out_error; 40031727258SDarrick J. Wong 40131727258SDarrick J. Wong /* Insert the left extent. */ 40231727258SDarrick J. Wong tmp = rcext; 40331727258SDarrick J. Wong tmp.rc_blockcount = agbno - rcext.rc_startblock; 40431727258SDarrick J. Wong error = xfs_refcount_insert(cur, &tmp, &found_rec); 40531727258SDarrick J. Wong if (error) 40631727258SDarrick J. Wong goto out_error; 407f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 408f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 409f9e03706SDarrick J. Wong goto out_error; 410f9e03706SDarrick J. Wong } 41131727258SDarrick J. Wong return error; 41231727258SDarrick J. Wong 41331727258SDarrick J. Wong out_error: 41431727258SDarrick J. Wong trace_xfs_refcount_split_extent_error(cur->bc_mp, 41550f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 41631727258SDarrick J. Wong return error; 41731727258SDarrick J. Wong } 41831727258SDarrick J. Wong 41931727258SDarrick J. Wong /* 42031727258SDarrick J. Wong * Merge the left, center, and right extents. 42131727258SDarrick J. Wong */ 42231727258SDarrick J. Wong STATIC int 42331727258SDarrick J. Wong xfs_refcount_merge_center_extents( 42431727258SDarrick J. Wong struct xfs_btree_cur *cur, 42531727258SDarrick J. Wong struct xfs_refcount_irec *left, 42631727258SDarrick J. Wong struct xfs_refcount_irec *center, 42731727258SDarrick J. Wong struct xfs_refcount_irec *right, 42831727258SDarrick J. Wong unsigned long long extlen, 42931727258SDarrick J. Wong xfs_extlen_t *aglen) 43031727258SDarrick J. Wong { 43131727258SDarrick J. Wong int error; 43231727258SDarrick J. Wong int found_rec; 43331727258SDarrick J. Wong 43431727258SDarrick J. Wong trace_xfs_refcount_merge_center_extents(cur->bc_mp, 43550f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, left, center, right); 43631727258SDarrick J. Wong 437f62ac3e0SDarrick J. Wong ASSERT(left->rc_domain == center->rc_domain); 438f62ac3e0SDarrick J. Wong ASSERT(right->rc_domain == center->rc_domain); 439f62ac3e0SDarrick J. Wong 44031727258SDarrick J. Wong /* 44131727258SDarrick J. Wong * Make sure the center and right extents are not in the btree. 44231727258SDarrick J. Wong * If the center extent was synthesized, the first delete call 44331727258SDarrick J. Wong * removes the right extent and we skip the second deletion. 44431727258SDarrick J. Wong * If center and right were in the btree, then the first delete 44531727258SDarrick J. Wong * call removes the center and the second one removes the right 44631727258SDarrick J. Wong * extent. 44731727258SDarrick J. Wong */ 4489a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_ge(cur, center->rc_domain, 4499a50ee4fSDarrick J. Wong center->rc_startblock, &found_rec); 45031727258SDarrick J. Wong if (error) 45131727258SDarrick J. Wong goto out_error; 452f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 453f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 454f9e03706SDarrick J. Wong goto out_error; 455f9e03706SDarrick J. Wong } 45631727258SDarrick J. Wong 45731727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 45831727258SDarrick J. Wong if (error) 45931727258SDarrick J. Wong goto out_error; 460f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 461f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 462f9e03706SDarrick J. Wong goto out_error; 463f9e03706SDarrick J. Wong } 46431727258SDarrick J. Wong 46531727258SDarrick J. Wong if (center->rc_refcount > 1) { 46631727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 46731727258SDarrick J. Wong if (error) 46831727258SDarrick J. Wong goto out_error; 469f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 470f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 471f9e03706SDarrick J. Wong goto out_error; 472f9e03706SDarrick J. Wong } 47331727258SDarrick J. Wong } 47431727258SDarrick J. Wong 47531727258SDarrick J. Wong /* Enlarge the left extent. */ 4769a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(cur, left->rc_domain, 4779a50ee4fSDarrick J. Wong left->rc_startblock, &found_rec); 47831727258SDarrick J. Wong if (error) 47931727258SDarrick J. Wong goto out_error; 480f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 481f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 482f9e03706SDarrick J. Wong goto out_error; 483f9e03706SDarrick J. Wong } 48431727258SDarrick J. Wong 48531727258SDarrick J. Wong left->rc_blockcount = extlen; 48631727258SDarrick J. Wong error = xfs_refcount_update(cur, left); 48731727258SDarrick J. Wong if (error) 48831727258SDarrick J. Wong goto out_error; 48931727258SDarrick J. Wong 49031727258SDarrick J. Wong *aglen = 0; 49131727258SDarrick J. Wong return error; 49231727258SDarrick J. Wong 49331727258SDarrick J. Wong out_error: 49431727258SDarrick J. Wong trace_xfs_refcount_merge_center_extents_error(cur->bc_mp, 49550f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 49631727258SDarrick J. Wong return error; 49731727258SDarrick J. Wong } 49831727258SDarrick J. Wong 49931727258SDarrick J. Wong /* 50031727258SDarrick J. Wong * Merge with the left extent. 50131727258SDarrick J. Wong */ 50231727258SDarrick J. Wong STATIC int 50331727258SDarrick J. Wong xfs_refcount_merge_left_extent( 50431727258SDarrick J. Wong struct xfs_btree_cur *cur, 50531727258SDarrick J. Wong struct xfs_refcount_irec *left, 50631727258SDarrick J. Wong struct xfs_refcount_irec *cleft, 50731727258SDarrick J. Wong xfs_agblock_t *agbno, 50831727258SDarrick J. Wong xfs_extlen_t *aglen) 50931727258SDarrick J. Wong { 51031727258SDarrick J. Wong int error; 51131727258SDarrick J. Wong int found_rec; 51231727258SDarrick J. Wong 51331727258SDarrick J. Wong trace_xfs_refcount_merge_left_extent(cur->bc_mp, 51450f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, left, cleft); 51531727258SDarrick J. Wong 516f62ac3e0SDarrick J. Wong ASSERT(left->rc_domain == cleft->rc_domain); 517f62ac3e0SDarrick J. Wong 51831727258SDarrick J. Wong /* If the extent at agbno (cleft) wasn't synthesized, remove it. */ 51931727258SDarrick J. Wong if (cleft->rc_refcount > 1) { 5209a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(cur, cleft->rc_domain, 5219a50ee4fSDarrick J. Wong cleft->rc_startblock, &found_rec); 52231727258SDarrick J. Wong if (error) 52331727258SDarrick J. Wong goto out_error; 524f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 525f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 526f9e03706SDarrick J. Wong goto out_error; 527f9e03706SDarrick J. Wong } 52831727258SDarrick J. Wong 52931727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 53031727258SDarrick J. Wong if (error) 53131727258SDarrick J. Wong goto out_error; 532f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 533f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 534f9e03706SDarrick J. Wong goto out_error; 535f9e03706SDarrick J. Wong } 53631727258SDarrick J. Wong } 53731727258SDarrick J. Wong 53831727258SDarrick J. Wong /* Enlarge the left extent. */ 5399a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(cur, left->rc_domain, 5409a50ee4fSDarrick J. Wong left->rc_startblock, &found_rec); 54131727258SDarrick J. Wong if (error) 54231727258SDarrick J. Wong goto out_error; 543f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 544f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 545f9e03706SDarrick J. Wong goto out_error; 546f9e03706SDarrick J. Wong } 54731727258SDarrick J. Wong 54831727258SDarrick J. Wong left->rc_blockcount += cleft->rc_blockcount; 54931727258SDarrick J. Wong error = xfs_refcount_update(cur, left); 55031727258SDarrick J. Wong if (error) 55131727258SDarrick J. Wong goto out_error; 55231727258SDarrick J. Wong 55331727258SDarrick J. Wong *agbno += cleft->rc_blockcount; 55431727258SDarrick J. Wong *aglen -= cleft->rc_blockcount; 55531727258SDarrick J. Wong return error; 55631727258SDarrick J. Wong 55731727258SDarrick J. Wong out_error: 55831727258SDarrick J. Wong trace_xfs_refcount_merge_left_extent_error(cur->bc_mp, 55950f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 56031727258SDarrick J. Wong return error; 56131727258SDarrick J. Wong } 56231727258SDarrick J. Wong 56331727258SDarrick J. Wong /* 56431727258SDarrick J. Wong * Merge with the right extent. 56531727258SDarrick J. Wong */ 56631727258SDarrick J. Wong STATIC int 56731727258SDarrick J. Wong xfs_refcount_merge_right_extent( 56831727258SDarrick J. Wong struct xfs_btree_cur *cur, 56931727258SDarrick J. Wong struct xfs_refcount_irec *right, 57031727258SDarrick J. Wong struct xfs_refcount_irec *cright, 57131727258SDarrick J. Wong xfs_extlen_t *aglen) 57231727258SDarrick J. Wong { 57331727258SDarrick J. Wong int error; 57431727258SDarrick J. Wong int found_rec; 57531727258SDarrick J. Wong 57631727258SDarrick J. Wong trace_xfs_refcount_merge_right_extent(cur->bc_mp, 57750f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, cright, right); 57831727258SDarrick J. Wong 579f62ac3e0SDarrick J. Wong ASSERT(right->rc_domain == cright->rc_domain); 580f62ac3e0SDarrick J. Wong 58131727258SDarrick J. Wong /* 58231727258SDarrick J. Wong * If the extent ending at agbno+aglen (cright) wasn't synthesized, 58331727258SDarrick J. Wong * remove it. 58431727258SDarrick J. Wong */ 58531727258SDarrick J. Wong if (cright->rc_refcount > 1) { 5869a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(cur, cright->rc_domain, 5879a50ee4fSDarrick J. Wong cright->rc_startblock, &found_rec); 58831727258SDarrick J. Wong if (error) 58931727258SDarrick J. Wong goto out_error; 590f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 591f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 592f9e03706SDarrick J. Wong goto out_error; 593f9e03706SDarrick J. Wong } 59431727258SDarrick J. Wong 59531727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 59631727258SDarrick J. Wong if (error) 59731727258SDarrick J. Wong goto out_error; 598f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 599f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 600f9e03706SDarrick J. Wong goto out_error; 601f9e03706SDarrick J. Wong } 60231727258SDarrick J. Wong } 60331727258SDarrick J. Wong 60431727258SDarrick J. Wong /* Enlarge the right extent. */ 6059a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(cur, right->rc_domain, 6069a50ee4fSDarrick J. Wong right->rc_startblock, &found_rec); 60731727258SDarrick J. Wong if (error) 60831727258SDarrick J. Wong goto out_error; 609f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 610f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 611f9e03706SDarrick J. Wong goto out_error; 612f9e03706SDarrick J. Wong } 61331727258SDarrick J. Wong 61431727258SDarrick J. Wong right->rc_startblock -= cright->rc_blockcount; 61531727258SDarrick J. Wong right->rc_blockcount += cright->rc_blockcount; 61631727258SDarrick J. Wong error = xfs_refcount_update(cur, right); 61731727258SDarrick J. Wong if (error) 61831727258SDarrick J. Wong goto out_error; 61931727258SDarrick J. Wong 62031727258SDarrick J. Wong *aglen -= cright->rc_blockcount; 62131727258SDarrick J. Wong return error; 62231727258SDarrick J. Wong 62331727258SDarrick J. Wong out_error: 62431727258SDarrick J. Wong trace_xfs_refcount_merge_right_extent_error(cur->bc_mp, 62550f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 62631727258SDarrick J. Wong return error; 62731727258SDarrick J. Wong } 62831727258SDarrick J. Wong 62931727258SDarrick J. Wong /* 63031727258SDarrick J. Wong * Find the left extent and the one after it (cleft). This function assumes 63131727258SDarrick J. Wong * that we've already split any extent crossing agbno. 63231727258SDarrick J. Wong */ 63331727258SDarrick J. Wong STATIC int 63431727258SDarrick J. Wong xfs_refcount_find_left_extents( 63531727258SDarrick J. Wong struct xfs_btree_cur *cur, 63631727258SDarrick J. Wong struct xfs_refcount_irec *left, 63731727258SDarrick J. Wong struct xfs_refcount_irec *cleft, 63868d0f389SDarrick J. Wong enum xfs_refc_domain domain, 63931727258SDarrick J. Wong xfs_agblock_t agbno, 64068d0f389SDarrick J. Wong xfs_extlen_t aglen) 64131727258SDarrick J. Wong { 64231727258SDarrick J. Wong struct xfs_refcount_irec tmp; 64331727258SDarrick J. Wong int error; 64431727258SDarrick J. Wong int found_rec; 64531727258SDarrick J. Wong 64631727258SDarrick J. Wong left->rc_startblock = cleft->rc_startblock = NULLAGBLOCK; 6479a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(cur, domain, agbno - 1, &found_rec); 64831727258SDarrick J. Wong if (error) 64931727258SDarrick J. Wong goto out_error; 65031727258SDarrick J. Wong if (!found_rec) 65131727258SDarrick J. Wong return 0; 65231727258SDarrick J. Wong 65331727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 65431727258SDarrick J. Wong if (error) 65531727258SDarrick J. Wong goto out_error; 656f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 657f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 658f9e03706SDarrick J. Wong goto out_error; 659f9e03706SDarrick J. Wong } 66031727258SDarrick J. Wong 661f62ac3e0SDarrick J. Wong if (tmp.rc_domain != domain) 662f62ac3e0SDarrick J. Wong return 0; 66331727258SDarrick J. Wong if (xfs_refc_next(&tmp) != agbno) 66431727258SDarrick J. Wong return 0; 66531727258SDarrick J. Wong /* We have a left extent; retrieve (or invent) the next right one */ 66631727258SDarrick J. Wong *left = tmp; 66731727258SDarrick J. Wong 66831727258SDarrick J. Wong error = xfs_btree_increment(cur, 0, &found_rec); 66931727258SDarrick J. Wong if (error) 67031727258SDarrick J. Wong goto out_error; 67131727258SDarrick J. Wong if (found_rec) { 67231727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 67331727258SDarrick J. Wong if (error) 67431727258SDarrick J. Wong goto out_error; 675f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 676f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 677f9e03706SDarrick J. Wong goto out_error; 678f9e03706SDarrick J. Wong } 67931727258SDarrick J. Wong 680f62ac3e0SDarrick J. Wong if (tmp.rc_domain != domain) 681f62ac3e0SDarrick J. Wong goto not_found; 682f62ac3e0SDarrick J. Wong 68331727258SDarrick J. Wong /* if tmp starts at the end of our range, just use that */ 68431727258SDarrick J. Wong if (tmp.rc_startblock == agbno) 68531727258SDarrick J. Wong *cleft = tmp; 68631727258SDarrick J. Wong else { 68731727258SDarrick J. Wong /* 68831727258SDarrick J. Wong * There's a gap in the refcntbt at the start of the 68931727258SDarrick J. Wong * range we're interested in (refcount == 1) so 69031727258SDarrick J. Wong * synthesize the implied extent and pass it back. 69131727258SDarrick J. Wong * We assume here that the agbno/aglen range was 69231727258SDarrick J. Wong * passed in from a data fork extent mapping and 69331727258SDarrick J. Wong * therefore is allocated to exactly one owner. 69431727258SDarrick J. Wong */ 69531727258SDarrick J. Wong cleft->rc_startblock = agbno; 69631727258SDarrick J. Wong cleft->rc_blockcount = min(aglen, 69731727258SDarrick J. Wong tmp.rc_startblock - agbno); 69831727258SDarrick J. Wong cleft->rc_refcount = 1; 6999a50ee4fSDarrick J. Wong cleft->rc_domain = domain; 70031727258SDarrick J. Wong } 70131727258SDarrick J. Wong } else { 702f62ac3e0SDarrick J. Wong not_found: 70331727258SDarrick J. Wong /* 70431727258SDarrick J. Wong * No extents, so pretend that there's one covering the whole 70531727258SDarrick J. Wong * range. 70631727258SDarrick J. Wong */ 70731727258SDarrick J. Wong cleft->rc_startblock = agbno; 70831727258SDarrick J. Wong cleft->rc_blockcount = aglen; 70931727258SDarrick J. Wong cleft->rc_refcount = 1; 7109a50ee4fSDarrick J. Wong cleft->rc_domain = domain; 71131727258SDarrick J. Wong } 71250f02fe3SDave Chinner trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno, 71331727258SDarrick J. Wong left, cleft, agbno); 71431727258SDarrick J. Wong return error; 71531727258SDarrick J. Wong 71631727258SDarrick J. Wong out_error: 71731727258SDarrick J. Wong trace_xfs_refcount_find_left_extent_error(cur->bc_mp, 71850f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 71931727258SDarrick J. Wong return error; 72031727258SDarrick J. Wong } 72131727258SDarrick J. Wong 72231727258SDarrick J. Wong /* 72331727258SDarrick J. Wong * Find the right extent and the one before it (cright). This function 72431727258SDarrick J. Wong * assumes that we've already split any extents crossing agbno + aglen. 72531727258SDarrick J. Wong */ 72631727258SDarrick J. Wong STATIC int 72731727258SDarrick J. Wong xfs_refcount_find_right_extents( 72831727258SDarrick J. Wong struct xfs_btree_cur *cur, 72931727258SDarrick J. Wong struct xfs_refcount_irec *right, 73031727258SDarrick J. Wong struct xfs_refcount_irec *cright, 73168d0f389SDarrick J. Wong enum xfs_refc_domain domain, 73231727258SDarrick J. Wong xfs_agblock_t agbno, 73368d0f389SDarrick J. Wong xfs_extlen_t aglen) 73431727258SDarrick J. Wong { 73531727258SDarrick J. Wong struct xfs_refcount_irec tmp; 73631727258SDarrick J. Wong int error; 73731727258SDarrick J. Wong int found_rec; 73831727258SDarrick J. Wong 73931727258SDarrick J. Wong right->rc_startblock = cright->rc_startblock = NULLAGBLOCK; 7409a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_ge(cur, domain, agbno + aglen, &found_rec); 74131727258SDarrick J. Wong if (error) 74231727258SDarrick J. Wong goto out_error; 74331727258SDarrick J. Wong if (!found_rec) 74431727258SDarrick J. Wong return 0; 74531727258SDarrick J. Wong 74631727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 74731727258SDarrick J. Wong if (error) 74831727258SDarrick J. Wong goto out_error; 749f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 750f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 751f9e03706SDarrick J. Wong goto out_error; 752f9e03706SDarrick J. Wong } 75331727258SDarrick J. Wong 754f62ac3e0SDarrick J. Wong if (tmp.rc_domain != domain) 755f62ac3e0SDarrick J. Wong return 0; 75631727258SDarrick J. Wong if (tmp.rc_startblock != agbno + aglen) 75731727258SDarrick J. Wong return 0; 75831727258SDarrick J. Wong /* We have a right extent; retrieve (or invent) the next left one */ 75931727258SDarrick J. Wong *right = tmp; 76031727258SDarrick J. Wong 76131727258SDarrick J. Wong error = xfs_btree_decrement(cur, 0, &found_rec); 76231727258SDarrick J. Wong if (error) 76331727258SDarrick J. Wong goto out_error; 76431727258SDarrick J. Wong if (found_rec) { 76531727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 76631727258SDarrick J. Wong if (error) 76731727258SDarrick J. Wong goto out_error; 768f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 769f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 770f9e03706SDarrick J. Wong goto out_error; 771f9e03706SDarrick J. Wong } 77231727258SDarrick J. Wong 773f62ac3e0SDarrick J. Wong if (tmp.rc_domain != domain) 774f62ac3e0SDarrick J. Wong goto not_found; 775f62ac3e0SDarrick J. Wong 77631727258SDarrick J. Wong /* if tmp ends at the end of our range, just use that */ 77731727258SDarrick J. Wong if (xfs_refc_next(&tmp) == agbno + aglen) 77831727258SDarrick J. Wong *cright = tmp; 77931727258SDarrick J. Wong else { 78031727258SDarrick J. Wong /* 78131727258SDarrick J. Wong * There's a gap in the refcntbt at the end of the 78231727258SDarrick J. Wong * range we're interested in (refcount == 1) so 78331727258SDarrick J. Wong * create the implied extent and pass it back. 78431727258SDarrick J. Wong * We assume here that the agbno/aglen range was 78531727258SDarrick J. Wong * passed in from a data fork extent mapping and 78631727258SDarrick J. Wong * therefore is allocated to exactly one owner. 78731727258SDarrick J. Wong */ 78831727258SDarrick J. Wong cright->rc_startblock = max(agbno, xfs_refc_next(&tmp)); 78931727258SDarrick J. Wong cright->rc_blockcount = right->rc_startblock - 79031727258SDarrick J. Wong cright->rc_startblock; 79131727258SDarrick J. Wong cright->rc_refcount = 1; 7929a50ee4fSDarrick J. Wong cright->rc_domain = domain; 79331727258SDarrick J. Wong } 79431727258SDarrick J. Wong } else { 795f62ac3e0SDarrick J. Wong not_found: 79631727258SDarrick J. Wong /* 79731727258SDarrick J. Wong * No extents, so pretend that there's one covering the whole 79831727258SDarrick J. Wong * range. 79931727258SDarrick J. Wong */ 80031727258SDarrick J. Wong cright->rc_startblock = agbno; 80131727258SDarrick J. Wong cright->rc_blockcount = aglen; 80231727258SDarrick J. Wong cright->rc_refcount = 1; 8039a50ee4fSDarrick J. Wong cright->rc_domain = domain; 80431727258SDarrick J. Wong } 80550f02fe3SDave Chinner trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno, 80631727258SDarrick J. Wong cright, right, agbno + aglen); 80731727258SDarrick J. Wong return error; 80831727258SDarrick J. Wong 80931727258SDarrick J. Wong out_error: 81031727258SDarrick J. Wong trace_xfs_refcount_find_right_extent_error(cur->bc_mp, 81150f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 81231727258SDarrick J. Wong return error; 81331727258SDarrick J. Wong } 81431727258SDarrick J. Wong 81531727258SDarrick J. Wong /* Is this extent valid? */ 81631727258SDarrick J. Wong static inline bool 81731727258SDarrick J. Wong xfs_refc_valid( 81831727258SDarrick J. Wong struct xfs_refcount_irec *rc) 81931727258SDarrick J. Wong { 82031727258SDarrick J. Wong return rc->rc_startblock != NULLAGBLOCK; 82131727258SDarrick J. Wong } 82231727258SDarrick J. Wong 82331727258SDarrick J. Wong /* 82431727258SDarrick J. Wong * Try to merge with any extents on the boundaries of the adjustment range. 82531727258SDarrick J. Wong */ 82631727258SDarrick J. Wong STATIC int 82731727258SDarrick J. Wong xfs_refcount_merge_extents( 82831727258SDarrick J. Wong struct xfs_btree_cur *cur, 82968d0f389SDarrick J. Wong enum xfs_refc_domain domain, 83031727258SDarrick J. Wong xfs_agblock_t *agbno, 83131727258SDarrick J. Wong xfs_extlen_t *aglen, 83231727258SDarrick J. Wong enum xfs_refc_adjust_op adjust, 83331727258SDarrick J. Wong bool *shape_changed) 83431727258SDarrick J. Wong { 83531727258SDarrick J. Wong struct xfs_refcount_irec left = {0}, cleft = {0}; 83631727258SDarrick J. Wong struct xfs_refcount_irec cright = {0}, right = {0}; 83731727258SDarrick J. Wong int error; 83831727258SDarrick J. Wong unsigned long long ulen; 83931727258SDarrick J. Wong bool cequal; 84031727258SDarrick J. Wong 84131727258SDarrick J. Wong *shape_changed = false; 84231727258SDarrick J. Wong /* 84331727258SDarrick J. Wong * Find the extent just below agbno [left], just above agbno [cleft], 84431727258SDarrick J. Wong * just below (agbno + aglen) [cright], and just above (agbno + aglen) 84531727258SDarrick J. Wong * [right]. 84631727258SDarrick J. Wong */ 84768d0f389SDarrick J. Wong error = xfs_refcount_find_left_extents(cur, &left, &cleft, domain, 84868d0f389SDarrick J. Wong *agbno, *aglen); 84931727258SDarrick J. Wong if (error) 85031727258SDarrick J. Wong return error; 85168d0f389SDarrick J. Wong error = xfs_refcount_find_right_extents(cur, &right, &cright, domain, 85268d0f389SDarrick J. Wong *agbno, *aglen); 85331727258SDarrick J. Wong if (error) 85431727258SDarrick J. Wong return error; 85531727258SDarrick J. Wong 85631727258SDarrick J. Wong /* No left or right extent to merge; exit. */ 85731727258SDarrick J. Wong if (!xfs_refc_valid(&left) && !xfs_refc_valid(&right)) 85831727258SDarrick J. Wong return 0; 85931727258SDarrick J. Wong 86031727258SDarrick J. Wong cequal = (cleft.rc_startblock == cright.rc_startblock) && 86131727258SDarrick J. Wong (cleft.rc_blockcount == cright.rc_blockcount); 86231727258SDarrick J. Wong 86331727258SDarrick J. Wong /* Try to merge left, cleft, and right. cleft must == cright. */ 86431727258SDarrick J. Wong ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount + 86531727258SDarrick J. Wong right.rc_blockcount; 86631727258SDarrick J. Wong if (xfs_refc_valid(&left) && xfs_refc_valid(&right) && 86731727258SDarrick J. Wong xfs_refc_valid(&cleft) && xfs_refc_valid(&cright) && cequal && 86831727258SDarrick J. Wong left.rc_refcount == cleft.rc_refcount + adjust && 86931727258SDarrick J. Wong right.rc_refcount == cleft.rc_refcount + adjust && 87031727258SDarrick J. Wong ulen < MAXREFCEXTLEN) { 87131727258SDarrick J. Wong *shape_changed = true; 87231727258SDarrick J. Wong return xfs_refcount_merge_center_extents(cur, &left, &cleft, 873a1f69417SEric Sandeen &right, ulen, aglen); 87431727258SDarrick J. Wong } 87531727258SDarrick J. Wong 87631727258SDarrick J. Wong /* Try to merge left and cleft. */ 87731727258SDarrick J. Wong ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount; 87831727258SDarrick J. Wong if (xfs_refc_valid(&left) && xfs_refc_valid(&cleft) && 87931727258SDarrick J. Wong left.rc_refcount == cleft.rc_refcount + adjust && 88031727258SDarrick J. Wong ulen < MAXREFCEXTLEN) { 88131727258SDarrick J. Wong *shape_changed = true; 88231727258SDarrick J. Wong error = xfs_refcount_merge_left_extent(cur, &left, &cleft, 88331727258SDarrick J. Wong agbno, aglen); 88431727258SDarrick J. Wong if (error) 88531727258SDarrick J. Wong return error; 88631727258SDarrick J. Wong 88731727258SDarrick J. Wong /* 88831727258SDarrick J. Wong * If we just merged left + cleft and cleft == cright, 88931727258SDarrick J. Wong * we no longer have a cright to merge with right. We're done. 89031727258SDarrick J. Wong */ 89131727258SDarrick J. Wong if (cequal) 89231727258SDarrick J. Wong return 0; 89331727258SDarrick J. Wong } 89431727258SDarrick J. Wong 89531727258SDarrick J. Wong /* Try to merge cright and right. */ 89631727258SDarrick J. Wong ulen = (unsigned long long)right.rc_blockcount + cright.rc_blockcount; 89731727258SDarrick J. Wong if (xfs_refc_valid(&right) && xfs_refc_valid(&cright) && 89831727258SDarrick J. Wong right.rc_refcount == cright.rc_refcount + adjust && 89931727258SDarrick J. Wong ulen < MAXREFCEXTLEN) { 90031727258SDarrick J. Wong *shape_changed = true; 90131727258SDarrick J. Wong return xfs_refcount_merge_right_extent(cur, &right, &cright, 902a1f69417SEric Sandeen aglen); 90331727258SDarrick J. Wong } 90431727258SDarrick J. Wong 905f62ac3e0SDarrick J. Wong return 0; 90631727258SDarrick J. Wong } 90731727258SDarrick J. Wong 90831727258SDarrick J. Wong /* 90931727258SDarrick J. Wong * XXX: This is a pretty hand-wavy estimate. The penalty for guessing 91031727258SDarrick J. Wong * true incorrectly is a shutdown FS; the penalty for guessing false 91131727258SDarrick J. Wong * incorrectly is more transaction rolls than might be necessary. 91231727258SDarrick J. Wong * Be conservative here. 91331727258SDarrick J. Wong */ 91431727258SDarrick J. Wong static bool 91531727258SDarrick J. Wong xfs_refcount_still_have_space( 91631727258SDarrick J. Wong struct xfs_btree_cur *cur) 91731727258SDarrick J. Wong { 91831727258SDarrick J. Wong unsigned long overhead; 91931727258SDarrick J. Wong 920b037c4eeSDarrick J. Wong /* 921b037c4eeSDarrick J. Wong * Worst case estimate: full splits of the free space and rmap btrees 922b037c4eeSDarrick J. Wong * to handle each of the shape changes to the refcount btree. 923b037c4eeSDarrick J. Wong */ 9246ed7e509SDarrick J. Wong overhead = xfs_allocfree_block_count(cur->bc_mp, 925b037c4eeSDarrick J. Wong cur->bc_ag.refc.shape_changes); 926b037c4eeSDarrick J. Wong overhead += cur->bc_mp->m_refc_maxlevels; 92731727258SDarrick J. Wong overhead *= cur->bc_mp->m_sb.sb_blocksize; 92831727258SDarrick J. Wong 92931727258SDarrick J. Wong /* 93031727258SDarrick J. Wong * Only allow 2 refcount extent updates per transaction if the 93131727258SDarrick J. Wong * refcount continue update "error" has been injected. 93231727258SDarrick J. Wong */ 933c4aa10d0SDave Chinner if (cur->bc_ag.refc.nr_ops > 2 && 93431727258SDarrick J. Wong XFS_TEST_ERROR(false, cur->bc_mp, 9359e24cfd0SDarrick J. Wong XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE)) 93631727258SDarrick J. Wong return false; 93731727258SDarrick J. Wong 938c4aa10d0SDave Chinner if (cur->bc_ag.refc.nr_ops == 0) 93931727258SDarrick J. Wong return true; 94031727258SDarrick J. Wong else if (overhead > cur->bc_tp->t_log_res) 94131727258SDarrick J. Wong return false; 94231727258SDarrick J. Wong return cur->bc_tp->t_log_res - overhead > 943c4aa10d0SDave Chinner cur->bc_ag.refc.nr_ops * XFS_REFCOUNT_ITEM_OVERHEAD; 94431727258SDarrick J. Wong } 94531727258SDarrick J. Wong 94631727258SDarrick J. Wong /* 94731727258SDarrick J. Wong * Adjust the refcounts of middle extents. At this point we should have 94831727258SDarrick J. Wong * split extents that crossed the adjustment range; merged with adjacent 94931727258SDarrick J. Wong * extents; and updated agbno/aglen to reflect the merges. Therefore, 95031727258SDarrick J. Wong * all we have to do is update the extents inside [agbno, agbno + aglen]. 95131727258SDarrick J. Wong */ 95231727258SDarrick J. Wong STATIC int 95331727258SDarrick J. Wong xfs_refcount_adjust_extents( 95431727258SDarrick J. Wong struct xfs_btree_cur *cur, 95531727258SDarrick J. Wong xfs_agblock_t *agbno, 95631727258SDarrick J. Wong xfs_extlen_t *aglen, 957c04c51c5SDarrick J. Wong enum xfs_refc_adjust_op adj) 95831727258SDarrick J. Wong { 95931727258SDarrick J. Wong struct xfs_refcount_irec ext, tmp; 96031727258SDarrick J. Wong int error; 96131727258SDarrick J. Wong int found_rec, found_tmp; 96231727258SDarrick J. Wong xfs_fsblock_t fsbno; 96331727258SDarrick J. Wong 96431727258SDarrick J. Wong /* Merging did all the work already. */ 96531727258SDarrick J. Wong if (*aglen == 0) 96631727258SDarrick J. Wong return 0; 96731727258SDarrick J. Wong 9689a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_ge(cur, XFS_REFC_DOMAIN_SHARED, *agbno, 9699a50ee4fSDarrick J. Wong &found_rec); 97031727258SDarrick J. Wong if (error) 97131727258SDarrick J. Wong goto out_error; 97231727258SDarrick J. Wong 97331727258SDarrick J. Wong while (*aglen > 0 && xfs_refcount_still_have_space(cur)) { 97431727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &ext, &found_rec); 97531727258SDarrick J. Wong if (error) 97631727258SDarrick J. Wong goto out_error; 977f62ac3e0SDarrick J. Wong if (!found_rec || ext.rc_domain != XFS_REFC_DOMAIN_SHARED) { 97831727258SDarrick J. Wong ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks; 97931727258SDarrick J. Wong ext.rc_blockcount = 0; 98031727258SDarrick J. Wong ext.rc_refcount = 0; 9819a50ee4fSDarrick J. Wong ext.rc_domain = XFS_REFC_DOMAIN_SHARED; 98231727258SDarrick J. Wong } 98331727258SDarrick J. Wong 98431727258SDarrick J. Wong /* 98531727258SDarrick J. Wong * Deal with a hole in the refcount tree; if a file maps to 98631727258SDarrick J. Wong * these blocks and there's no refcountbt record, pretend that 98731727258SDarrick J. Wong * there is one with refcount == 1. 98831727258SDarrick J. Wong */ 98931727258SDarrick J. Wong if (ext.rc_startblock != *agbno) { 99031727258SDarrick J. Wong tmp.rc_startblock = *agbno; 99131727258SDarrick J. Wong tmp.rc_blockcount = min(*aglen, 99231727258SDarrick J. Wong ext.rc_startblock - *agbno); 99331727258SDarrick J. Wong tmp.rc_refcount = 1 + adj; 9949a50ee4fSDarrick J. Wong tmp.rc_domain = XFS_REFC_DOMAIN_SHARED; 9959a50ee4fSDarrick J. Wong 99631727258SDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 99750f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, &tmp); 99831727258SDarrick J. Wong 99931727258SDarrick J. Wong /* 100031727258SDarrick J. Wong * Either cover the hole (increment) or 100131727258SDarrick J. Wong * delete the range (decrement). 100231727258SDarrick J. Wong */ 1003c47260d4SDarrick J. Wong cur->bc_ag.refc.nr_ops++; 100431727258SDarrick J. Wong if (tmp.rc_refcount) { 100531727258SDarrick J. Wong error = xfs_refcount_insert(cur, &tmp, 100631727258SDarrick J. Wong &found_tmp); 100731727258SDarrick J. Wong if (error) 100831727258SDarrick J. Wong goto out_error; 1009f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, 1010f9e03706SDarrick J. Wong found_tmp != 1)) { 1011f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1012f9e03706SDarrick J. Wong goto out_error; 1013f9e03706SDarrick J. Wong } 101431727258SDarrick J. Wong } else { 101531727258SDarrick J. Wong fsbno = XFS_AGB_TO_FSB(cur->bc_mp, 101650f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, 101731727258SDarrick J. Wong tmp.rc_startblock); 1018c201d9caSDarrick J. Wong xfs_free_extent_later(cur->bc_tp, fsbno, 1019c04c51c5SDarrick J. Wong tmp.rc_blockcount, NULL); 102031727258SDarrick J. Wong } 102131727258SDarrick J. Wong 102231727258SDarrick J. Wong (*agbno) += tmp.rc_blockcount; 102331727258SDarrick J. Wong (*aglen) -= tmp.rc_blockcount; 102431727258SDarrick J. Wong 1025f850995fSDarrick J. Wong /* Stop if there's nothing left to modify */ 1026f850995fSDarrick J. Wong if (*aglen == 0 || !xfs_refcount_still_have_space(cur)) 1027f850995fSDarrick J. Wong break; 1028f850995fSDarrick J. Wong 1029f850995fSDarrick J. Wong /* Move the cursor to the start of ext. */ 10309a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_ge(cur, 10319a50ee4fSDarrick J. Wong XFS_REFC_DOMAIN_SHARED, *agbno, 103231727258SDarrick J. Wong &found_rec); 103331727258SDarrick J. Wong if (error) 103431727258SDarrick J. Wong goto out_error; 103531727258SDarrick J. Wong } 103631727258SDarrick J. Wong 1037f850995fSDarrick J. Wong /* 1038f850995fSDarrick J. Wong * A previous step trimmed agbno/aglen such that the end of the 1039f850995fSDarrick J. Wong * range would not be in the middle of the record. If this is 1040f850995fSDarrick J. Wong * no longer the case, something is seriously wrong with the 1041f850995fSDarrick J. Wong * btree. Make sure we never feed the synthesized record into 1042f850995fSDarrick J. Wong * the processing loop below. 1043f850995fSDarrick J. Wong */ 1044f850995fSDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_blockcount == 0) || 1045f850995fSDarrick J. Wong XFS_IS_CORRUPT(cur->bc_mp, ext.rc_blockcount > *aglen)) { 1046f850995fSDarrick J. Wong error = -EFSCORRUPTED; 1047f850995fSDarrick J. Wong goto out_error; 1048f850995fSDarrick J. Wong } 104931727258SDarrick J. Wong 105031727258SDarrick J. Wong /* 105131727258SDarrick J. Wong * Adjust the reference count and either update the tree 105231727258SDarrick J. Wong * (incr) or free the blocks (decr). 105331727258SDarrick J. Wong */ 105431727258SDarrick J. Wong if (ext.rc_refcount == MAXREFCOUNT) 105531727258SDarrick J. Wong goto skip; 105631727258SDarrick J. Wong ext.rc_refcount += adj; 105731727258SDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 105850f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, &ext); 1059c47260d4SDarrick J. Wong cur->bc_ag.refc.nr_ops++; 106031727258SDarrick J. Wong if (ext.rc_refcount > 1) { 106131727258SDarrick J. Wong error = xfs_refcount_update(cur, &ext); 106231727258SDarrick J. Wong if (error) 106331727258SDarrick J. Wong goto out_error; 106431727258SDarrick J. Wong } else if (ext.rc_refcount == 1) { 106531727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 106631727258SDarrick J. Wong if (error) 106731727258SDarrick J. Wong goto out_error; 1068f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 1069f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1070f9e03706SDarrick J. Wong goto out_error; 1071f9e03706SDarrick J. Wong } 107231727258SDarrick J. Wong goto advloop; 107331727258SDarrick J. Wong } else { 107431727258SDarrick J. Wong fsbno = XFS_AGB_TO_FSB(cur->bc_mp, 107550f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, 107631727258SDarrick J. Wong ext.rc_startblock); 1077c04c51c5SDarrick J. Wong xfs_free_extent_later(cur->bc_tp, fsbno, 1078c04c51c5SDarrick J. Wong ext.rc_blockcount, NULL); 107931727258SDarrick J. Wong } 108031727258SDarrick J. Wong 108131727258SDarrick J. Wong skip: 108231727258SDarrick J. Wong error = xfs_btree_increment(cur, 0, &found_rec); 108331727258SDarrick J. Wong if (error) 108431727258SDarrick J. Wong goto out_error; 108531727258SDarrick J. Wong 108631727258SDarrick J. Wong advloop: 108731727258SDarrick J. Wong (*agbno) += ext.rc_blockcount; 108831727258SDarrick J. Wong (*aglen) -= ext.rc_blockcount; 108931727258SDarrick J. Wong } 109031727258SDarrick J. Wong 109131727258SDarrick J. Wong return error; 109231727258SDarrick J. Wong out_error: 109331727258SDarrick J. Wong trace_xfs_refcount_modify_extent_error(cur->bc_mp, 109450f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 109531727258SDarrick J. Wong return error; 109631727258SDarrick J. Wong } 109731727258SDarrick J. Wong 109831727258SDarrick J. Wong /* Adjust the reference count of a range of AG blocks. */ 109931727258SDarrick J. Wong STATIC int 110031727258SDarrick J. Wong xfs_refcount_adjust( 110131727258SDarrick J. Wong struct xfs_btree_cur *cur, 110231727258SDarrick J. Wong xfs_agblock_t agbno, 110331727258SDarrick J. Wong xfs_extlen_t aglen, 110431727258SDarrick J. Wong xfs_agblock_t *new_agbno, 110531727258SDarrick J. Wong xfs_extlen_t *new_aglen, 1106c04c51c5SDarrick J. Wong enum xfs_refc_adjust_op adj) 110731727258SDarrick J. Wong { 110831727258SDarrick J. Wong bool shape_changed; 110931727258SDarrick J. Wong int shape_changes = 0; 111031727258SDarrick J. Wong int error; 111131727258SDarrick J. Wong 111231727258SDarrick J. Wong *new_agbno = agbno; 111331727258SDarrick J. Wong *new_aglen = aglen; 111431727258SDarrick J. Wong if (adj == XFS_REFCOUNT_ADJUST_INCREASE) 111550f02fe3SDave Chinner trace_xfs_refcount_increase(cur->bc_mp, cur->bc_ag.pag->pag_agno, 111631727258SDarrick J. Wong agbno, aglen); 111731727258SDarrick J. Wong else 111850f02fe3SDave Chinner trace_xfs_refcount_decrease(cur->bc_mp, cur->bc_ag.pag->pag_agno, 111931727258SDarrick J. Wong agbno, aglen); 112031727258SDarrick J. Wong 112131727258SDarrick J. Wong /* 112231727258SDarrick J. Wong * Ensure that no rcextents cross the boundary of the adjustment range. 112331727258SDarrick J. Wong */ 11249a50ee4fSDarrick J. Wong error = xfs_refcount_split_extent(cur, XFS_REFC_DOMAIN_SHARED, 11259a50ee4fSDarrick J. Wong agbno, &shape_changed); 112631727258SDarrick J. Wong if (error) 112731727258SDarrick J. Wong goto out_error; 112831727258SDarrick J. Wong if (shape_changed) 112931727258SDarrick J. Wong shape_changes++; 113031727258SDarrick J. Wong 11319a50ee4fSDarrick J. Wong error = xfs_refcount_split_extent(cur, XFS_REFC_DOMAIN_SHARED, 11329a50ee4fSDarrick J. Wong agbno + aglen, &shape_changed); 113331727258SDarrick J. Wong if (error) 113431727258SDarrick J. Wong goto out_error; 113531727258SDarrick J. Wong if (shape_changed) 113631727258SDarrick J. Wong shape_changes++; 113731727258SDarrick J. Wong 113831727258SDarrick J. Wong /* 113931727258SDarrick J. Wong * Try to merge with the left or right extents of the range. 114031727258SDarrick J. Wong */ 114168d0f389SDarrick J. Wong error = xfs_refcount_merge_extents(cur, XFS_REFC_DOMAIN_SHARED, 114268d0f389SDarrick J. Wong new_agbno, new_aglen, adj, &shape_changed); 114331727258SDarrick J. Wong if (error) 114431727258SDarrick J. Wong goto out_error; 114531727258SDarrick J. Wong if (shape_changed) 114631727258SDarrick J. Wong shape_changes++; 114731727258SDarrick J. Wong if (shape_changes) 1148c4aa10d0SDave Chinner cur->bc_ag.refc.shape_changes++; 114931727258SDarrick J. Wong 115031727258SDarrick J. Wong /* Now that we've taken care of the ends, adjust the middle extents */ 1151c04c51c5SDarrick J. Wong error = xfs_refcount_adjust_extents(cur, new_agbno, new_aglen, adj); 115231727258SDarrick J. Wong if (error) 115331727258SDarrick J. Wong goto out_error; 115431727258SDarrick J. Wong 115531727258SDarrick J. Wong return 0; 115631727258SDarrick J. Wong 115731727258SDarrick J. Wong out_error: 115850f02fe3SDave Chinner trace_xfs_refcount_adjust_error(cur->bc_mp, cur->bc_ag.pag->pag_agno, 115931727258SDarrick J. Wong error, _RET_IP_); 116031727258SDarrick J. Wong return error; 116131727258SDarrick J. Wong } 116233ba6129SDarrick J. Wong 116333ba6129SDarrick J. Wong /* Clean up after calling xfs_refcount_finish_one. */ 116433ba6129SDarrick J. Wong void 116533ba6129SDarrick J. Wong xfs_refcount_finish_one_cleanup( 116633ba6129SDarrick J. Wong struct xfs_trans *tp, 116733ba6129SDarrick J. Wong struct xfs_btree_cur *rcur, 116833ba6129SDarrick J. Wong int error) 116933ba6129SDarrick J. Wong { 117033ba6129SDarrick J. Wong struct xfs_buf *agbp; 117133ba6129SDarrick J. Wong 117233ba6129SDarrick J. Wong if (rcur == NULL) 117333ba6129SDarrick J. Wong return; 1174576af732SDave Chinner agbp = rcur->bc_ag.agbp; 11750b04b6b8SDarrick J. Wong xfs_btree_del_cursor(rcur, error); 117633ba6129SDarrick J. Wong if (error) 117733ba6129SDarrick J. Wong xfs_trans_brelse(tp, agbp); 117833ba6129SDarrick J. Wong } 117933ba6129SDarrick J. Wong 118033ba6129SDarrick J. Wong /* 11818edbe0cfSDarrick J. Wong * Set up a continuation a deferred refcount operation by updating the intent. 11828edbe0cfSDarrick J. Wong * Checks to make sure we're not going to run off the end of the AG. 11838edbe0cfSDarrick J. Wong */ 11848edbe0cfSDarrick J. Wong static inline int 11858edbe0cfSDarrick J. Wong xfs_refcount_continue_op( 11868edbe0cfSDarrick J. Wong struct xfs_btree_cur *cur, 11878edbe0cfSDarrick J. Wong xfs_fsblock_t startblock, 11888edbe0cfSDarrick J. Wong xfs_agblock_t new_agbno, 11898edbe0cfSDarrick J. Wong xfs_extlen_t new_len, 11908edbe0cfSDarrick J. Wong xfs_fsblock_t *new_fsbno) 11918edbe0cfSDarrick J. Wong { 11928edbe0cfSDarrick J. Wong struct xfs_mount *mp = cur->bc_mp; 11938edbe0cfSDarrick J. Wong struct xfs_perag *pag = cur->bc_ag.pag; 11948edbe0cfSDarrick J. Wong 11958edbe0cfSDarrick J. Wong if (XFS_IS_CORRUPT(mp, !xfs_verify_agbext(pag, new_agbno, new_len))) 11968edbe0cfSDarrick J. Wong return -EFSCORRUPTED; 11978edbe0cfSDarrick J. Wong 11988edbe0cfSDarrick J. Wong *new_fsbno = XFS_AGB_TO_FSB(mp, pag->pag_agno, new_agbno); 11998edbe0cfSDarrick J. Wong 12008edbe0cfSDarrick J. Wong ASSERT(xfs_verify_fsbext(mp, *new_fsbno, new_len)); 12018edbe0cfSDarrick J. Wong ASSERT(pag->pag_agno == XFS_FSB_TO_AGNO(mp, *new_fsbno)); 12028edbe0cfSDarrick J. Wong 12038edbe0cfSDarrick J. Wong return 0; 12048edbe0cfSDarrick J. Wong } 12058edbe0cfSDarrick J. Wong 12068edbe0cfSDarrick J. Wong /* 120733ba6129SDarrick J. Wong * Process one of the deferred refcount operations. We pass back the 120833ba6129SDarrick J. Wong * btree cursor to maintain our lock on the btree between calls. 120933ba6129SDarrick J. Wong * This saves time and eliminates a buffer deadlock between the 121033ba6129SDarrick J. Wong * superblock and the AGF because we'll always grab them in the same 121133ba6129SDarrick J. Wong * order. 121233ba6129SDarrick J. Wong */ 121333ba6129SDarrick J. Wong int 121433ba6129SDarrick J. Wong xfs_refcount_finish_one( 121533ba6129SDarrick J. Wong struct xfs_trans *tp, 121633ba6129SDarrick J. Wong enum xfs_refcount_intent_type type, 121733ba6129SDarrick J. Wong xfs_fsblock_t startblock, 121833ba6129SDarrick J. Wong xfs_extlen_t blockcount, 121933ba6129SDarrick J. Wong xfs_fsblock_t *new_fsb, 122033ba6129SDarrick J. Wong xfs_extlen_t *new_len, 122133ba6129SDarrick J. Wong struct xfs_btree_cur **pcur) 122233ba6129SDarrick J. Wong { 122333ba6129SDarrick J. Wong struct xfs_mount *mp = tp->t_mountp; 122433ba6129SDarrick J. Wong struct xfs_btree_cur *rcur; 122533ba6129SDarrick J. Wong struct xfs_buf *agbp = NULL; 122633ba6129SDarrick J. Wong int error = 0; 122733ba6129SDarrick J. Wong xfs_agblock_t bno; 122833ba6129SDarrick J. Wong xfs_agblock_t new_agbno; 122933ba6129SDarrick J. Wong unsigned long nr_ops = 0; 123033ba6129SDarrick J. Wong int shape_changes = 0; 1231a81a0621SDave Chinner struct xfs_perag *pag; 123233ba6129SDarrick J. Wong 1233a81a0621SDave Chinner pag = xfs_perag_get(mp, XFS_FSB_TO_AGNO(mp, startblock)); 123433ba6129SDarrick J. Wong bno = XFS_FSB_TO_AGBNO(mp, startblock); 123533ba6129SDarrick J. Wong 123633ba6129SDarrick J. Wong trace_xfs_refcount_deferred(mp, XFS_FSB_TO_AGNO(mp, startblock), 123733ba6129SDarrick J. Wong type, XFS_FSB_TO_AGBNO(mp, startblock), 123833ba6129SDarrick J. Wong blockcount); 123933ba6129SDarrick J. Wong 1240a81a0621SDave Chinner if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_REFCOUNT_FINISH_ONE)) { 1241a81a0621SDave Chinner error = -EIO; 1242a81a0621SDave Chinner goto out_drop; 1243a81a0621SDave Chinner } 124433ba6129SDarrick J. Wong 124533ba6129SDarrick J. Wong /* 124633ba6129SDarrick J. Wong * If we haven't gotten a cursor or the cursor AG doesn't match 124733ba6129SDarrick J. Wong * the startblock, get one now. 124833ba6129SDarrick J. Wong */ 124933ba6129SDarrick J. Wong rcur = *pcur; 1250a81a0621SDave Chinner if (rcur != NULL && rcur->bc_ag.pag != pag) { 1251c4aa10d0SDave Chinner nr_ops = rcur->bc_ag.refc.nr_ops; 1252c4aa10d0SDave Chinner shape_changes = rcur->bc_ag.refc.shape_changes; 125333ba6129SDarrick J. Wong xfs_refcount_finish_one_cleanup(tp, rcur, 0); 125433ba6129SDarrick J. Wong rcur = NULL; 125533ba6129SDarrick J. Wong *pcur = NULL; 125633ba6129SDarrick J. Wong } 125733ba6129SDarrick J. Wong if (rcur == NULL) { 125808d3e84fSDave Chinner error = xfs_alloc_read_agf(pag, tp, XFS_ALLOC_FLAG_FREEING, 125908d3e84fSDave Chinner &agbp); 126033ba6129SDarrick J. Wong if (error) 1261a81a0621SDave Chinner goto out_drop; 126233ba6129SDarrick J. Wong 1263a81a0621SDave Chinner rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag); 1264c4aa10d0SDave Chinner rcur->bc_ag.refc.nr_ops = nr_ops; 1265c4aa10d0SDave Chinner rcur->bc_ag.refc.shape_changes = shape_changes; 126633ba6129SDarrick J. Wong } 126733ba6129SDarrick J. Wong *pcur = rcur; 126833ba6129SDarrick J. Wong 126933ba6129SDarrick J. Wong switch (type) { 127033ba6129SDarrick J. Wong case XFS_REFCOUNT_INCREASE: 127133ba6129SDarrick J. Wong error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno, 1272c04c51c5SDarrick J. Wong new_len, XFS_REFCOUNT_ADJUST_INCREASE); 12738edbe0cfSDarrick J. Wong if (error) 12748edbe0cfSDarrick J. Wong goto out_drop; 12758edbe0cfSDarrick J. Wong if (*new_len > 0) 12768edbe0cfSDarrick J. Wong error = xfs_refcount_continue_op(rcur, startblock, 12778edbe0cfSDarrick J. Wong new_agbno, *new_len, new_fsb); 127833ba6129SDarrick J. Wong break; 127933ba6129SDarrick J. Wong case XFS_REFCOUNT_DECREASE: 128033ba6129SDarrick J. Wong error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno, 1281c04c51c5SDarrick J. Wong new_len, XFS_REFCOUNT_ADJUST_DECREASE); 12828edbe0cfSDarrick J. Wong if (error) 12838edbe0cfSDarrick J. Wong goto out_drop; 12848edbe0cfSDarrick J. Wong if (*new_len > 0) 12858edbe0cfSDarrick J. Wong error = xfs_refcount_continue_op(rcur, startblock, 12868edbe0cfSDarrick J. Wong new_agbno, *new_len, new_fsb); 128733ba6129SDarrick J. Wong break; 1288174edb0eSDarrick J. Wong case XFS_REFCOUNT_ALLOC_COW: 1289174edb0eSDarrick J. Wong *new_fsb = startblock + blockcount; 1290174edb0eSDarrick J. Wong *new_len = 0; 12910f37d178SBrian Foster error = __xfs_refcount_cow_alloc(rcur, bno, blockcount); 1292174edb0eSDarrick J. Wong break; 1293174edb0eSDarrick J. Wong case XFS_REFCOUNT_FREE_COW: 1294174edb0eSDarrick J. Wong *new_fsb = startblock + blockcount; 1295174edb0eSDarrick J. Wong *new_len = 0; 12960f37d178SBrian Foster error = __xfs_refcount_cow_free(rcur, bno, blockcount); 1297174edb0eSDarrick J. Wong break; 129833ba6129SDarrick J. Wong default: 129933ba6129SDarrick J. Wong ASSERT(0); 130033ba6129SDarrick J. Wong error = -EFSCORRUPTED; 130133ba6129SDarrick J. Wong } 130233ba6129SDarrick J. Wong if (!error && *new_len > 0) 1303a81a0621SDave Chinner trace_xfs_refcount_finish_one_leftover(mp, pag->pag_agno, type, 130433ba6129SDarrick J. Wong bno, blockcount, new_agbno, *new_len); 1305a81a0621SDave Chinner out_drop: 1306a81a0621SDave Chinner xfs_perag_put(pag); 130733ba6129SDarrick J. Wong return error; 130833ba6129SDarrick J. Wong } 130933ba6129SDarrick J. Wong 131033ba6129SDarrick J. Wong /* 131133ba6129SDarrick J. Wong * Record a refcount intent for later processing. 131233ba6129SDarrick J. Wong */ 131374b4c5d4SDarrick J. Wong static void 131433ba6129SDarrick J. Wong __xfs_refcount_add( 13150f37d178SBrian Foster struct xfs_trans *tp, 131633ba6129SDarrick J. Wong enum xfs_refcount_intent_type type, 131733ba6129SDarrick J. Wong xfs_fsblock_t startblock, 131833ba6129SDarrick J. Wong xfs_extlen_t blockcount) 131933ba6129SDarrick J. Wong { 132033ba6129SDarrick J. Wong struct xfs_refcount_intent *ri; 132133ba6129SDarrick J. Wong 13220f37d178SBrian Foster trace_xfs_refcount_defer(tp->t_mountp, 13230f37d178SBrian Foster XFS_FSB_TO_AGNO(tp->t_mountp, startblock), 13240f37d178SBrian Foster type, XFS_FSB_TO_AGBNO(tp->t_mountp, startblock), 132533ba6129SDarrick J. Wong blockcount); 132633ba6129SDarrick J. Wong 1327f3c799c2SDarrick J. Wong ri = kmem_cache_alloc(xfs_refcount_intent_cache, 1328f3c799c2SDarrick J. Wong GFP_NOFS | __GFP_NOFAIL); 132933ba6129SDarrick J. Wong INIT_LIST_HEAD(&ri->ri_list); 133033ba6129SDarrick J. Wong ri->ri_type = type; 133133ba6129SDarrick J. Wong ri->ri_startblock = startblock; 133233ba6129SDarrick J. Wong ri->ri_blockcount = blockcount; 133333ba6129SDarrick J. Wong 13340f37d178SBrian Foster xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_REFCOUNT, &ri->ri_list); 133533ba6129SDarrick J. Wong } 133633ba6129SDarrick J. Wong 133733ba6129SDarrick J. Wong /* 133833ba6129SDarrick J. Wong * Increase the reference count of the blocks backing a file's extent. 133933ba6129SDarrick J. Wong */ 134074b4c5d4SDarrick J. Wong void 134133ba6129SDarrick J. Wong xfs_refcount_increase_extent( 13420f37d178SBrian Foster struct xfs_trans *tp, 134333ba6129SDarrick J. Wong struct xfs_bmbt_irec *PREV) 134433ba6129SDarrick J. Wong { 1345ebd9027dSDave Chinner if (!xfs_has_reflink(tp->t_mountp)) 134674b4c5d4SDarrick J. Wong return; 134733ba6129SDarrick J. Wong 134874b4c5d4SDarrick J. Wong __xfs_refcount_add(tp, XFS_REFCOUNT_INCREASE, PREV->br_startblock, 134974b4c5d4SDarrick J. Wong PREV->br_blockcount); 135033ba6129SDarrick J. Wong } 135133ba6129SDarrick J. Wong 135233ba6129SDarrick J. Wong /* 135333ba6129SDarrick J. Wong * Decrease the reference count of the blocks backing a file's extent. 135433ba6129SDarrick J. Wong */ 135574b4c5d4SDarrick J. Wong void 135633ba6129SDarrick J. Wong xfs_refcount_decrease_extent( 13570f37d178SBrian Foster struct xfs_trans *tp, 135833ba6129SDarrick J. Wong struct xfs_bmbt_irec *PREV) 135933ba6129SDarrick J. Wong { 1360ebd9027dSDave Chinner if (!xfs_has_reflink(tp->t_mountp)) 136174b4c5d4SDarrick J. Wong return; 136233ba6129SDarrick J. Wong 136374b4c5d4SDarrick J. Wong __xfs_refcount_add(tp, XFS_REFCOUNT_DECREASE, PREV->br_startblock, 136474b4c5d4SDarrick J. Wong PREV->br_blockcount); 136533ba6129SDarrick J. Wong } 1366350a27a6SDarrick J. Wong 1367350a27a6SDarrick J. Wong /* 1368350a27a6SDarrick J. Wong * Given an AG extent, find the lowest-numbered run of shared blocks 1369350a27a6SDarrick J. Wong * within that range and return the range in fbno/flen. If 1370350a27a6SDarrick J. Wong * find_end_of_shared is set, return the longest contiguous extent of 1371350a27a6SDarrick J. Wong * shared blocks; if not, just return the first extent we find. If no 1372350a27a6SDarrick J. Wong * shared blocks are found, fbno and flen will be set to NULLAGBLOCK 1373350a27a6SDarrick J. Wong * and 0, respectively. 1374350a27a6SDarrick J. Wong */ 1375350a27a6SDarrick J. Wong int 1376350a27a6SDarrick J. Wong xfs_refcount_find_shared( 1377350a27a6SDarrick J. Wong struct xfs_btree_cur *cur, 1378350a27a6SDarrick J. Wong xfs_agblock_t agbno, 1379350a27a6SDarrick J. Wong xfs_extlen_t aglen, 1380350a27a6SDarrick J. Wong xfs_agblock_t *fbno, 1381350a27a6SDarrick J. Wong xfs_extlen_t *flen, 1382350a27a6SDarrick J. Wong bool find_end_of_shared) 1383350a27a6SDarrick J. Wong { 1384350a27a6SDarrick J. Wong struct xfs_refcount_irec tmp; 1385350a27a6SDarrick J. Wong int i; 1386350a27a6SDarrick J. Wong int have; 1387350a27a6SDarrick J. Wong int error; 1388350a27a6SDarrick J. Wong 138950f02fe3SDave Chinner trace_xfs_refcount_find_shared(cur->bc_mp, cur->bc_ag.pag->pag_agno, 1390350a27a6SDarrick J. Wong agbno, aglen); 1391350a27a6SDarrick J. Wong 1392350a27a6SDarrick J. Wong /* By default, skip the whole range */ 1393350a27a6SDarrick J. Wong *fbno = NULLAGBLOCK; 1394350a27a6SDarrick J. Wong *flen = 0; 1395350a27a6SDarrick J. Wong 1396350a27a6SDarrick J. Wong /* Try to find a refcount extent that crosses the start */ 13979a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(cur, XFS_REFC_DOMAIN_SHARED, agbno, 13989a50ee4fSDarrick J. Wong &have); 1399350a27a6SDarrick J. Wong if (error) 1400350a27a6SDarrick J. Wong goto out_error; 1401350a27a6SDarrick J. Wong if (!have) { 1402350a27a6SDarrick J. Wong /* No left extent, look at the next one */ 1403350a27a6SDarrick J. Wong error = xfs_btree_increment(cur, 0, &have); 1404350a27a6SDarrick J. Wong if (error) 1405350a27a6SDarrick J. Wong goto out_error; 1406350a27a6SDarrick J. Wong if (!have) 1407350a27a6SDarrick J. Wong goto done; 1408350a27a6SDarrick J. Wong } 1409350a27a6SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &i); 1410350a27a6SDarrick J. Wong if (error) 1411350a27a6SDarrick J. Wong goto out_error; 1412f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) { 1413f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1414f9e03706SDarrick J. Wong goto out_error; 1415f9e03706SDarrick J. Wong } 1416f62ac3e0SDarrick J. Wong if (tmp.rc_domain != XFS_REFC_DOMAIN_SHARED) 1417f62ac3e0SDarrick J. Wong goto done; 1418350a27a6SDarrick J. Wong 1419350a27a6SDarrick J. Wong /* If the extent ends before the start, look at the next one */ 1420350a27a6SDarrick J. Wong if (tmp.rc_startblock + tmp.rc_blockcount <= agbno) { 1421350a27a6SDarrick J. Wong error = xfs_btree_increment(cur, 0, &have); 1422350a27a6SDarrick J. Wong if (error) 1423350a27a6SDarrick J. Wong goto out_error; 1424350a27a6SDarrick J. Wong if (!have) 1425350a27a6SDarrick J. Wong goto done; 1426350a27a6SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &i); 1427350a27a6SDarrick J. Wong if (error) 1428350a27a6SDarrick J. Wong goto out_error; 1429f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) { 1430f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1431f9e03706SDarrick J. Wong goto out_error; 1432f9e03706SDarrick J. Wong } 1433f62ac3e0SDarrick J. Wong if (tmp.rc_domain != XFS_REFC_DOMAIN_SHARED) 1434f62ac3e0SDarrick J. Wong goto done; 1435350a27a6SDarrick J. Wong } 1436350a27a6SDarrick J. Wong 1437350a27a6SDarrick J. Wong /* If the extent starts after the range we want, bail out */ 1438350a27a6SDarrick J. Wong if (tmp.rc_startblock >= agbno + aglen) 1439350a27a6SDarrick J. Wong goto done; 1440350a27a6SDarrick J. Wong 1441350a27a6SDarrick J. Wong /* We found the start of a shared extent! */ 1442350a27a6SDarrick J. Wong if (tmp.rc_startblock < agbno) { 1443350a27a6SDarrick J. Wong tmp.rc_blockcount -= (agbno - tmp.rc_startblock); 1444350a27a6SDarrick J. Wong tmp.rc_startblock = agbno; 1445350a27a6SDarrick J. Wong } 1446350a27a6SDarrick J. Wong 1447350a27a6SDarrick J. Wong *fbno = tmp.rc_startblock; 1448350a27a6SDarrick J. Wong *flen = min(tmp.rc_blockcount, agbno + aglen - *fbno); 1449350a27a6SDarrick J. Wong if (!find_end_of_shared) 1450350a27a6SDarrick J. Wong goto done; 1451350a27a6SDarrick J. Wong 1452350a27a6SDarrick J. Wong /* Otherwise, find the end of this shared extent */ 1453350a27a6SDarrick J. Wong while (*fbno + *flen < agbno + aglen) { 1454350a27a6SDarrick J. Wong error = xfs_btree_increment(cur, 0, &have); 1455350a27a6SDarrick J. Wong if (error) 1456350a27a6SDarrick J. Wong goto out_error; 1457350a27a6SDarrick J. Wong if (!have) 1458350a27a6SDarrick J. Wong break; 1459350a27a6SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &i); 1460350a27a6SDarrick J. Wong if (error) 1461350a27a6SDarrick J. Wong goto out_error; 1462f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) { 1463f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1464f9e03706SDarrick J. Wong goto out_error; 1465f9e03706SDarrick J. Wong } 1466f62ac3e0SDarrick J. Wong if (tmp.rc_domain != XFS_REFC_DOMAIN_SHARED || 1467f62ac3e0SDarrick J. Wong tmp.rc_startblock >= agbno + aglen || 1468350a27a6SDarrick J. Wong tmp.rc_startblock != *fbno + *flen) 1469350a27a6SDarrick J. Wong break; 1470350a27a6SDarrick J. Wong *flen = min(*flen + tmp.rc_blockcount, agbno + aglen - *fbno); 1471350a27a6SDarrick J. Wong } 1472350a27a6SDarrick J. Wong 1473350a27a6SDarrick J. Wong done: 1474350a27a6SDarrick J. Wong trace_xfs_refcount_find_shared_result(cur->bc_mp, 147550f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, *fbno, *flen); 1476350a27a6SDarrick J. Wong 1477350a27a6SDarrick J. Wong out_error: 1478350a27a6SDarrick J. Wong if (error) 1479350a27a6SDarrick J. Wong trace_xfs_refcount_find_shared_error(cur->bc_mp, 148050f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 1481350a27a6SDarrick J. Wong return error; 1482350a27a6SDarrick J. Wong } 1483174edb0eSDarrick J. Wong 1484174edb0eSDarrick J. Wong /* 1485174edb0eSDarrick J. Wong * Recovering CoW Blocks After a Crash 1486174edb0eSDarrick J. Wong * 1487174edb0eSDarrick J. Wong * Due to the way that the copy on write mechanism works, there's a window of 1488174edb0eSDarrick J. Wong * opportunity in which we can lose track of allocated blocks during a crash. 1489174edb0eSDarrick J. Wong * Because CoW uses delayed allocation in the in-core CoW fork, writeback 1490174edb0eSDarrick J. Wong * causes blocks to be allocated and stored in the CoW fork. The blocks are 1491174edb0eSDarrick J. Wong * no longer in the free space btree but are not otherwise recorded anywhere 1492174edb0eSDarrick J. Wong * until the write completes and the blocks are mapped into the file. A crash 1493174edb0eSDarrick J. Wong * in between allocation and remapping results in the replacement blocks being 1494174edb0eSDarrick J. Wong * lost. This situation is exacerbated by the CoW extent size hint because 1495174edb0eSDarrick J. Wong * allocations can hang around for long time. 1496174edb0eSDarrick J. Wong * 1497174edb0eSDarrick J. Wong * However, there is a place where we can record these allocations before they 1498174edb0eSDarrick J. Wong * become mappings -- the reference count btree. The btree does not record 1499174edb0eSDarrick J. Wong * extents with refcount == 1, so we can record allocations with a refcount of 1500174edb0eSDarrick J. Wong * 1. Blocks being used for CoW writeout cannot be shared, so there should be 1501174edb0eSDarrick J. Wong * no conflict with shared block records. These mappings should be created 1502174edb0eSDarrick J. Wong * when we allocate blocks to the CoW fork and deleted when they're removed 1503174edb0eSDarrick J. Wong * from the CoW fork. 1504174edb0eSDarrick J. Wong * 1505174edb0eSDarrick J. Wong * Minor nit: records for in-progress CoW allocations and records for shared 1506174edb0eSDarrick J. Wong * extents must never be merged, to preserve the property that (except for CoW 1507174edb0eSDarrick J. Wong * allocations) there are no refcount btree entries with refcount == 1. The 1508174edb0eSDarrick J. Wong * only time this could potentially happen is when unsharing a block that's 1509174edb0eSDarrick J. Wong * adjacent to CoW allocations, so we must be careful to avoid this. 1510174edb0eSDarrick J. Wong * 1511174edb0eSDarrick J. Wong * At mount time we recover lost CoW allocations by searching the refcount 1512174edb0eSDarrick J. Wong * btree for these refcount == 1 mappings. These represent CoW allocations 1513174edb0eSDarrick J. Wong * that were in progress at the time the filesystem went down, so we can free 1514174edb0eSDarrick J. Wong * them to get the space back. 1515174edb0eSDarrick J. Wong * 1516174edb0eSDarrick J. Wong * This mechanism is superior to creating EFIs for unmapped CoW extents for 1517174edb0eSDarrick J. Wong * several reasons -- first, EFIs pin the tail of the log and would have to be 1518174edb0eSDarrick J. Wong * periodically relogged to avoid filling up the log. Second, CoW completions 1519174edb0eSDarrick J. Wong * will have to file an EFD and create new EFIs for whatever remains in the 1520174edb0eSDarrick J. Wong * CoW fork; this partially takes care of (1) but extent-size reservations 1521174edb0eSDarrick J. Wong * will have to periodically relog even if there's no writeout in progress. 1522174edb0eSDarrick J. Wong * This can happen if the CoW extent size hint is set, which you really want. 1523174edb0eSDarrick J. Wong * Third, EFIs cannot currently be automatically relogged into newer 1524174edb0eSDarrick J. Wong * transactions to advance the log tail. Fourth, stuffing the log full of 1525174edb0eSDarrick J. Wong * EFIs places an upper bound on the number of CoW allocations that can be 1526174edb0eSDarrick J. Wong * held filesystem-wide at any given time. Recording them in the refcount 1527174edb0eSDarrick J. Wong * btree doesn't require us to maintain any state in memory and doesn't pin 1528174edb0eSDarrick J. Wong * the log. 1529174edb0eSDarrick J. Wong */ 1530174edb0eSDarrick J. Wong /* 1531174edb0eSDarrick J. Wong * Adjust the refcounts of CoW allocations. These allocations are "magic" 1532174edb0eSDarrick J. Wong * in that they're not referenced anywhere else in the filesystem, so we 1533174edb0eSDarrick J. Wong * stash them in the refcount btree with a refcount of 1 until either file 1534174edb0eSDarrick J. Wong * remapping (or CoW cancellation) happens. 1535174edb0eSDarrick J. Wong */ 1536174edb0eSDarrick J. Wong STATIC int 1537174edb0eSDarrick J. Wong xfs_refcount_adjust_cow_extents( 1538174edb0eSDarrick J. Wong struct xfs_btree_cur *cur, 1539174edb0eSDarrick J. Wong xfs_agblock_t agbno, 1540174edb0eSDarrick J. Wong xfs_extlen_t aglen, 1541a1f69417SEric Sandeen enum xfs_refc_adjust_op adj) 1542174edb0eSDarrick J. Wong { 1543174edb0eSDarrick J. Wong struct xfs_refcount_irec ext, tmp; 1544174edb0eSDarrick J. Wong int error; 1545174edb0eSDarrick J. Wong int found_rec, found_tmp; 1546174edb0eSDarrick J. Wong 1547174edb0eSDarrick J. Wong if (aglen == 0) 1548174edb0eSDarrick J. Wong return 0; 1549174edb0eSDarrick J. Wong 1550174edb0eSDarrick J. Wong /* Find any overlapping refcount records */ 15519a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_ge(cur, XFS_REFC_DOMAIN_COW, agbno, 15529a50ee4fSDarrick J. Wong &found_rec); 1553174edb0eSDarrick J. Wong if (error) 1554174edb0eSDarrick J. Wong goto out_error; 1555174edb0eSDarrick J. Wong error = xfs_refcount_get_rec(cur, &ext, &found_rec); 1556174edb0eSDarrick J. Wong if (error) 1557174edb0eSDarrick J. Wong goto out_error; 1558f62ac3e0SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec && 1559f62ac3e0SDarrick J. Wong ext.rc_domain != XFS_REFC_DOMAIN_COW)) { 1560f62ac3e0SDarrick J. Wong error = -EFSCORRUPTED; 1561f62ac3e0SDarrick J. Wong goto out_error; 1562f62ac3e0SDarrick J. Wong } 1563174edb0eSDarrick J. Wong if (!found_rec) { 15649a50ee4fSDarrick J. Wong ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks; 1565174edb0eSDarrick J. Wong ext.rc_blockcount = 0; 1566174edb0eSDarrick J. Wong ext.rc_refcount = 0; 15679a50ee4fSDarrick J. Wong ext.rc_domain = XFS_REFC_DOMAIN_COW; 1568174edb0eSDarrick J. Wong } 1569174edb0eSDarrick J. Wong 1570174edb0eSDarrick J. Wong switch (adj) { 1571174edb0eSDarrick J. Wong case XFS_REFCOUNT_ADJUST_COW_ALLOC: 1572174edb0eSDarrick J. Wong /* Adding a CoW reservation, there should be nothing here. */ 1573f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, 1574f9e03706SDarrick J. Wong agbno + aglen > ext.rc_startblock)) { 1575f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1576f9e03706SDarrick J. Wong goto out_error; 1577f9e03706SDarrick J. Wong } 1578174edb0eSDarrick J. Wong 1579174edb0eSDarrick J. Wong tmp.rc_startblock = agbno; 1580174edb0eSDarrick J. Wong tmp.rc_blockcount = aglen; 1581174edb0eSDarrick J. Wong tmp.rc_refcount = 1; 15829a50ee4fSDarrick J. Wong tmp.rc_domain = XFS_REFC_DOMAIN_COW; 15839a50ee4fSDarrick J. Wong 1584174edb0eSDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 158550f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, &tmp); 1586174edb0eSDarrick J. Wong 1587174edb0eSDarrick J. Wong error = xfs_refcount_insert(cur, &tmp, 1588174edb0eSDarrick J. Wong &found_tmp); 1589174edb0eSDarrick J. Wong if (error) 1590174edb0eSDarrick J. Wong goto out_error; 1591f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_tmp != 1)) { 1592f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1593f9e03706SDarrick J. Wong goto out_error; 1594f9e03706SDarrick J. Wong } 1595174edb0eSDarrick J. Wong break; 1596174edb0eSDarrick J. Wong case XFS_REFCOUNT_ADJUST_COW_FREE: 1597174edb0eSDarrick J. Wong /* Removing a CoW reservation, there should be one extent. */ 1598f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_startblock != agbno)) { 1599f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1600f9e03706SDarrick J. Wong goto out_error; 1601f9e03706SDarrick J. Wong } 1602f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_blockcount != aglen)) { 1603f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1604f9e03706SDarrick J. Wong goto out_error; 1605f9e03706SDarrick J. Wong } 1606f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_refcount != 1)) { 1607f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1608f9e03706SDarrick J. Wong goto out_error; 1609f9e03706SDarrick J. Wong } 1610174edb0eSDarrick J. Wong 1611174edb0eSDarrick J. Wong ext.rc_refcount = 0; 1612174edb0eSDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 161350f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, &ext); 1614174edb0eSDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 1615174edb0eSDarrick J. Wong if (error) 1616174edb0eSDarrick J. Wong goto out_error; 1617f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 1618f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1619f9e03706SDarrick J. Wong goto out_error; 1620f9e03706SDarrick J. Wong } 1621174edb0eSDarrick J. Wong break; 1622174edb0eSDarrick J. Wong default: 1623174edb0eSDarrick J. Wong ASSERT(0); 1624174edb0eSDarrick J. Wong } 1625174edb0eSDarrick J. Wong 1626174edb0eSDarrick J. Wong return error; 1627174edb0eSDarrick J. Wong out_error: 1628174edb0eSDarrick J. Wong trace_xfs_refcount_modify_extent_error(cur->bc_mp, 162950f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 1630174edb0eSDarrick J. Wong return error; 1631174edb0eSDarrick J. Wong } 1632174edb0eSDarrick J. Wong 1633174edb0eSDarrick J. Wong /* 1634174edb0eSDarrick J. Wong * Add or remove refcount btree entries for CoW reservations. 1635174edb0eSDarrick J. Wong */ 1636174edb0eSDarrick J. Wong STATIC int 1637174edb0eSDarrick J. Wong xfs_refcount_adjust_cow( 1638174edb0eSDarrick J. Wong struct xfs_btree_cur *cur, 1639174edb0eSDarrick J. Wong xfs_agblock_t agbno, 1640174edb0eSDarrick J. Wong xfs_extlen_t aglen, 1641a1f69417SEric Sandeen enum xfs_refc_adjust_op adj) 1642174edb0eSDarrick J. Wong { 1643174edb0eSDarrick J. Wong bool shape_changed; 1644174edb0eSDarrick J. Wong int error; 1645174edb0eSDarrick J. Wong 1646174edb0eSDarrick J. Wong /* 1647174edb0eSDarrick J. Wong * Ensure that no rcextents cross the boundary of the adjustment range. 1648174edb0eSDarrick J. Wong */ 16499a50ee4fSDarrick J. Wong error = xfs_refcount_split_extent(cur, XFS_REFC_DOMAIN_COW, 16509a50ee4fSDarrick J. Wong agbno, &shape_changed); 1651174edb0eSDarrick J. Wong if (error) 1652174edb0eSDarrick J. Wong goto out_error; 1653174edb0eSDarrick J. Wong 16549a50ee4fSDarrick J. Wong error = xfs_refcount_split_extent(cur, XFS_REFC_DOMAIN_COW, 16559a50ee4fSDarrick J. Wong agbno + aglen, &shape_changed); 1656174edb0eSDarrick J. Wong if (error) 1657174edb0eSDarrick J. Wong goto out_error; 1658174edb0eSDarrick J. Wong 1659174edb0eSDarrick J. Wong /* 1660174edb0eSDarrick J. Wong * Try to merge with the left or right extents of the range. 1661174edb0eSDarrick J. Wong */ 166268d0f389SDarrick J. Wong error = xfs_refcount_merge_extents(cur, XFS_REFC_DOMAIN_COW, &agbno, 166368d0f389SDarrick J. Wong &aglen, adj, &shape_changed); 1664174edb0eSDarrick J. Wong if (error) 1665174edb0eSDarrick J. Wong goto out_error; 1666174edb0eSDarrick J. Wong 1667174edb0eSDarrick J. Wong /* Now that we've taken care of the ends, adjust the middle extents */ 1668a1f69417SEric Sandeen error = xfs_refcount_adjust_cow_extents(cur, agbno, aglen, adj); 1669174edb0eSDarrick J. Wong if (error) 1670174edb0eSDarrick J. Wong goto out_error; 1671174edb0eSDarrick J. Wong 1672174edb0eSDarrick J. Wong return 0; 1673174edb0eSDarrick J. Wong 1674174edb0eSDarrick J. Wong out_error: 167550f02fe3SDave Chinner trace_xfs_refcount_adjust_cow_error(cur->bc_mp, cur->bc_ag.pag->pag_agno, 1676174edb0eSDarrick J. Wong error, _RET_IP_); 1677174edb0eSDarrick J. Wong return error; 1678174edb0eSDarrick J. Wong } 1679174edb0eSDarrick J. Wong 1680174edb0eSDarrick J. Wong /* 1681174edb0eSDarrick J. Wong * Record a CoW allocation in the refcount btree. 1682174edb0eSDarrick J. Wong */ 1683174edb0eSDarrick J. Wong STATIC int 1684174edb0eSDarrick J. Wong __xfs_refcount_cow_alloc( 1685174edb0eSDarrick J. Wong struct xfs_btree_cur *rcur, 1686174edb0eSDarrick J. Wong xfs_agblock_t agbno, 16870f37d178SBrian Foster xfs_extlen_t aglen) 1688174edb0eSDarrick J. Wong { 168950f02fe3SDave Chinner trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, 1690174edb0eSDarrick J. Wong agbno, aglen); 1691174edb0eSDarrick J. Wong 1692174edb0eSDarrick J. Wong /* Add refcount btree reservation */ 16930525e952SDarrick J. Wong return xfs_refcount_adjust_cow(rcur, agbno, aglen, 1694a1f69417SEric Sandeen XFS_REFCOUNT_ADJUST_COW_ALLOC); 1695174edb0eSDarrick J. Wong } 1696174edb0eSDarrick J. Wong 1697174edb0eSDarrick J. Wong /* 1698174edb0eSDarrick J. Wong * Remove a CoW allocation from the refcount btree. 1699174edb0eSDarrick J. Wong */ 1700174edb0eSDarrick J. Wong STATIC int 1701174edb0eSDarrick J. Wong __xfs_refcount_cow_free( 1702174edb0eSDarrick J. Wong struct xfs_btree_cur *rcur, 1703174edb0eSDarrick J. Wong xfs_agblock_t agbno, 17040f37d178SBrian Foster xfs_extlen_t aglen) 1705174edb0eSDarrick J. Wong { 170650f02fe3SDave Chinner trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, 1707174edb0eSDarrick J. Wong agbno, aglen); 1708174edb0eSDarrick J. Wong 1709174edb0eSDarrick J. Wong /* Remove refcount btree reservation */ 17100525e952SDarrick J. Wong return xfs_refcount_adjust_cow(rcur, agbno, aglen, 1711a1f69417SEric Sandeen XFS_REFCOUNT_ADJUST_COW_FREE); 1712174edb0eSDarrick J. Wong } 1713174edb0eSDarrick J. Wong 1714174edb0eSDarrick J. Wong /* Record a CoW staging extent in the refcount btree. */ 171574b4c5d4SDarrick J. Wong void 1716174edb0eSDarrick J. Wong xfs_refcount_alloc_cow_extent( 17170f37d178SBrian Foster struct xfs_trans *tp, 1718174edb0eSDarrick J. Wong xfs_fsblock_t fsb, 1719174edb0eSDarrick J. Wong xfs_extlen_t len) 1720174edb0eSDarrick J. Wong { 17210f37d178SBrian Foster struct xfs_mount *mp = tp->t_mountp; 17220525e952SDarrick J. Wong 1723ebd9027dSDave Chinner if (!xfs_has_reflink(mp)) 172474b4c5d4SDarrick J. Wong return; 1725174edb0eSDarrick J. Wong 172674b4c5d4SDarrick J. Wong __xfs_refcount_add(tp, XFS_REFCOUNT_ALLOC_COW, fsb, len); 17270525e952SDarrick J. Wong 17280525e952SDarrick J. Wong /* Add rmap entry */ 1729bc46ac64SDarrick J. Wong xfs_rmap_alloc_extent(tp, XFS_FSB_TO_AGNO(mp, fsb), 17300525e952SDarrick J. Wong XFS_FSB_TO_AGBNO(mp, fsb), len, XFS_RMAP_OWN_COW); 1731174edb0eSDarrick J. Wong } 1732174edb0eSDarrick J. Wong 1733174edb0eSDarrick J. Wong /* Forget a CoW staging event in the refcount btree. */ 173474b4c5d4SDarrick J. Wong void 1735174edb0eSDarrick J. Wong xfs_refcount_free_cow_extent( 17360f37d178SBrian Foster struct xfs_trans *tp, 1737174edb0eSDarrick J. Wong xfs_fsblock_t fsb, 1738174edb0eSDarrick J. Wong xfs_extlen_t len) 1739174edb0eSDarrick J. Wong { 17400f37d178SBrian Foster struct xfs_mount *mp = tp->t_mountp; 17410525e952SDarrick J. Wong 1742ebd9027dSDave Chinner if (!xfs_has_reflink(mp)) 174374b4c5d4SDarrick J. Wong return; 1744174edb0eSDarrick J. Wong 17450525e952SDarrick J. Wong /* Remove rmap entry */ 1746bc46ac64SDarrick J. Wong xfs_rmap_free_extent(tp, XFS_FSB_TO_AGNO(mp, fsb), 17470525e952SDarrick J. Wong XFS_FSB_TO_AGBNO(mp, fsb), len, XFS_RMAP_OWN_COW); 174874b4c5d4SDarrick J. Wong __xfs_refcount_add(tp, XFS_REFCOUNT_FREE_COW, fsb, len); 1749174edb0eSDarrick J. Wong } 1750174edb0eSDarrick J. Wong 1751174edb0eSDarrick J. Wong struct xfs_refcount_recovery { 1752174edb0eSDarrick J. Wong struct list_head rr_list; 1753174edb0eSDarrick J. Wong struct xfs_refcount_irec rr_rrec; 1754174edb0eSDarrick J. Wong }; 1755174edb0eSDarrick J. Wong 1756174edb0eSDarrick J. Wong /* Stuff an extent on the recovery list. */ 1757174edb0eSDarrick J. Wong STATIC int 1758174edb0eSDarrick J. Wong xfs_refcount_recover_extent( 1759174edb0eSDarrick J. Wong struct xfs_btree_cur *cur, 1760159eb69dSDarrick J. Wong const union xfs_btree_rec *rec, 1761174edb0eSDarrick J. Wong void *priv) 1762174edb0eSDarrick J. Wong { 1763174edb0eSDarrick J. Wong struct list_head *debris = priv; 1764174edb0eSDarrick J. Wong struct xfs_refcount_recovery *rr; 1765174edb0eSDarrick J. Wong 1766a71895c5SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, 1767a71895c5SDarrick J. Wong be32_to_cpu(rec->refc.rc_refcount) != 1)) 1768174edb0eSDarrick J. Wong return -EFSCORRUPTED; 1769174edb0eSDarrick J. Wong 1770*c1ccf967SDarrick J. Wong rr = kmalloc(sizeof(struct xfs_refcount_recovery), 1771*c1ccf967SDarrick J. Wong GFP_KERNEL | __GFP_NOFAIL); 1772*c1ccf967SDarrick J. Wong INIT_LIST_HEAD(&rr->rr_list); 1773174edb0eSDarrick J. Wong xfs_refcount_btrec_to_irec(rec, &rr->rr_rrec); 1774174edb0eSDarrick J. Wong 1775f62ac3e0SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, 1776f62ac3e0SDarrick J. Wong rr->rr_rrec.rc_domain != XFS_REFC_DOMAIN_COW)) { 1777*c1ccf967SDarrick J. Wong kfree(rr); 1778f62ac3e0SDarrick J. Wong return -EFSCORRUPTED; 1779f62ac3e0SDarrick J. Wong } 1780f62ac3e0SDarrick J. Wong 1781f62ac3e0SDarrick J. Wong list_add_tail(&rr->rr_list, debris); 1782174edb0eSDarrick J. Wong return 0; 1783174edb0eSDarrick J. Wong } 1784174edb0eSDarrick J. Wong 1785174edb0eSDarrick J. Wong /* Find and remove leftover CoW reservations. */ 1786174edb0eSDarrick J. Wong int 1787174edb0eSDarrick J. Wong xfs_refcount_recover_cow_leftovers( 1788174edb0eSDarrick J. Wong struct xfs_mount *mp, 1789a81a0621SDave Chinner struct xfs_perag *pag) 1790174edb0eSDarrick J. Wong { 1791174edb0eSDarrick J. Wong struct xfs_trans *tp; 1792174edb0eSDarrick J. Wong struct xfs_btree_cur *cur; 1793174edb0eSDarrick J. Wong struct xfs_buf *agbp; 1794174edb0eSDarrick J. Wong struct xfs_refcount_recovery *rr, *n; 1795174edb0eSDarrick J. Wong struct list_head debris; 1796174edb0eSDarrick J. Wong union xfs_btree_irec low; 1797174edb0eSDarrick J. Wong union xfs_btree_irec high; 1798174edb0eSDarrick J. Wong xfs_fsblock_t fsb; 1799174edb0eSDarrick J. Wong int error; 1800174edb0eSDarrick J. Wong 1801f1fdc820SDarrick J. Wong /* reflink filesystems mustn't have AGs larger than 2^31-1 blocks */ 1802f1fdc820SDarrick J. Wong BUILD_BUG_ON(XFS_MAX_CRC_AG_BLOCKS >= XFS_REFC_COW_START); 1803f1fdc820SDarrick J. Wong if (mp->m_sb.sb_agblocks > XFS_MAX_CRC_AG_BLOCKS) 1804174edb0eSDarrick J. Wong return -EOPNOTSUPP; 1805174edb0eSDarrick J. Wong 18063ecb3ac7SDarrick J. Wong INIT_LIST_HEAD(&debris); 18073ecb3ac7SDarrick J. Wong 18083ecb3ac7SDarrick J. Wong /* 18093ecb3ac7SDarrick J. Wong * In this first part, we use an empty transaction to gather up 18103ecb3ac7SDarrick J. Wong * all the leftover CoW extents so that we can subsequently 18113ecb3ac7SDarrick J. Wong * delete them. The empty transaction is used to avoid 18123ecb3ac7SDarrick J. Wong * a buffer lock deadlock if there happens to be a loop in the 18133ecb3ac7SDarrick J. Wong * refcountbt because we're allowed to re-grab a buffer that is 18143ecb3ac7SDarrick J. Wong * already attached to our transaction. When we're done 18153ecb3ac7SDarrick J. Wong * recording the CoW debris we cancel the (empty) transaction 18163ecb3ac7SDarrick J. Wong * and everything goes away cleanly. 18173ecb3ac7SDarrick J. Wong */ 18183ecb3ac7SDarrick J. Wong error = xfs_trans_alloc_empty(mp, &tp); 1819174edb0eSDarrick J. Wong if (error) 1820174edb0eSDarrick J. Wong return error; 18213ecb3ac7SDarrick J. Wong 182208d3e84fSDave Chinner error = xfs_alloc_read_agf(pag, tp, 0, &agbp); 18233ecb3ac7SDarrick J. Wong if (error) 18243ecb3ac7SDarrick J. Wong goto out_trans; 1825a81a0621SDave Chinner cur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag); 1826174edb0eSDarrick J. Wong 1827174edb0eSDarrick J. Wong /* Find all the leftover CoW staging extents. */ 1828174edb0eSDarrick J. Wong memset(&low, 0, sizeof(low)); 1829174edb0eSDarrick J. Wong memset(&high, 0, sizeof(high)); 18309a50ee4fSDarrick J. Wong low.rc.rc_domain = high.rc.rc_domain = XFS_REFC_DOMAIN_COW; 1831174edb0eSDarrick J. Wong high.rc.rc_startblock = -1U; 1832174edb0eSDarrick J. Wong error = xfs_btree_query_range(cur, &low, &high, 1833174edb0eSDarrick J. Wong xfs_refcount_recover_extent, &debris); 1834ef97ef26SDarrick J. Wong xfs_btree_del_cursor(cur, error); 18353ecb3ac7SDarrick J. Wong xfs_trans_brelse(tp, agbp); 18363ecb3ac7SDarrick J. Wong xfs_trans_cancel(tp); 1837ef97ef26SDarrick J. Wong if (error) 1838ef97ef26SDarrick J. Wong goto out_free; 1839174edb0eSDarrick J. Wong 1840174edb0eSDarrick J. Wong /* Now iterate the list to free the leftovers */ 18413ecb3ac7SDarrick J. Wong list_for_each_entry_safe(rr, n, &debris, rr_list) { 1842174edb0eSDarrick J. Wong /* Set up transaction. */ 1843174edb0eSDarrick J. Wong error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, 0, 0, 0, &tp); 1844174edb0eSDarrick J. Wong if (error) 1845174edb0eSDarrick J. Wong goto out_free; 1846174edb0eSDarrick J. Wong 1847a81a0621SDave Chinner trace_xfs_refcount_recover_extent(mp, pag->pag_agno, 1848a81a0621SDave Chinner &rr->rr_rrec); 1849174edb0eSDarrick J. Wong 1850174edb0eSDarrick J. Wong /* Free the orphan record */ 18519a50ee4fSDarrick J. Wong fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, 18529a50ee4fSDarrick J. Wong rr->rr_rrec.rc_startblock); 185374b4c5d4SDarrick J. Wong xfs_refcount_free_cow_extent(tp, fsb, 1854174edb0eSDarrick J. Wong rr->rr_rrec.rc_blockcount); 1855174edb0eSDarrick J. Wong 1856174edb0eSDarrick J. Wong /* Free the block. */ 1857c201d9caSDarrick J. Wong xfs_free_extent_later(tp, fsb, rr->rr_rrec.rc_blockcount, NULL); 1858174edb0eSDarrick J. Wong 1859174edb0eSDarrick J. Wong error = xfs_trans_commit(tp); 1860174edb0eSDarrick J. Wong if (error) 1861174edb0eSDarrick J. Wong goto out_free; 18623ecb3ac7SDarrick J. Wong 18633ecb3ac7SDarrick J. Wong list_del(&rr->rr_list); 1864*c1ccf967SDarrick J. Wong kfree(rr); 18656f97077fSDarrick J. Wong } 1866174edb0eSDarrick J. Wong 18673ecb3ac7SDarrick J. Wong return error; 18683ecb3ac7SDarrick J. Wong out_trans: 18693ecb3ac7SDarrick J. Wong xfs_trans_cancel(tp); 1870174edb0eSDarrick J. Wong out_free: 1871174edb0eSDarrick J. Wong /* Free the leftover list */ 1872174edb0eSDarrick J. Wong list_for_each_entry_safe(rr, n, &debris, rr_list) { 1873174edb0eSDarrick J. Wong list_del(&rr->rr_list); 1874*c1ccf967SDarrick J. Wong kfree(rr); 1875174edb0eSDarrick J. Wong } 1876174edb0eSDarrick J. Wong return error; 1877174edb0eSDarrick J. Wong } 187849db55ecSDarrick J. Wong 187949db55ecSDarrick J. Wong /* Is there a record covering a given extent? */ 188049db55ecSDarrick J. Wong int 188149db55ecSDarrick J. Wong xfs_refcount_has_record( 188249db55ecSDarrick J. Wong struct xfs_btree_cur *cur, 18839a50ee4fSDarrick J. Wong enum xfs_refc_domain domain, 188449db55ecSDarrick J. Wong xfs_agblock_t bno, 188549db55ecSDarrick J. Wong xfs_extlen_t len, 188649db55ecSDarrick J. Wong bool *exists) 188749db55ecSDarrick J. Wong { 188849db55ecSDarrick J. Wong union xfs_btree_irec low; 188949db55ecSDarrick J. Wong union xfs_btree_irec high; 189049db55ecSDarrick J. Wong 189149db55ecSDarrick J. Wong memset(&low, 0, sizeof(low)); 189249db55ecSDarrick J. Wong low.rc.rc_startblock = bno; 189349db55ecSDarrick J. Wong memset(&high, 0xFF, sizeof(high)); 189449db55ecSDarrick J. Wong high.rc.rc_startblock = bno + len - 1; 18959a50ee4fSDarrick J. Wong low.rc.rc_domain = high.rc.rc_domain = domain; 189649db55ecSDarrick J. Wong 189749db55ecSDarrick J. Wong return xfs_btree_has_record(cur, &low, &high, exists); 189849db55ecSDarrick J. Wong } 1899f3c799c2SDarrick J. Wong 1900f3c799c2SDarrick J. Wong int __init 1901f3c799c2SDarrick J. Wong xfs_refcount_intent_init_cache(void) 1902f3c799c2SDarrick J. Wong { 1903f3c799c2SDarrick J. Wong xfs_refcount_intent_cache = kmem_cache_create("xfs_refc_intent", 1904f3c799c2SDarrick J. Wong sizeof(struct xfs_refcount_intent), 1905f3c799c2SDarrick J. Wong 0, 0, NULL); 1906f3c799c2SDarrick J. Wong 1907f3c799c2SDarrick J. Wong return xfs_refcount_intent_cache != NULL ? 0 : -ENOMEM; 1908f3c799c2SDarrick J. Wong } 1909f3c799c2SDarrick J. Wong 1910f3c799c2SDarrick J. Wong void 1911f3c799c2SDarrick J. Wong xfs_refcount_intent_destroy_cache(void) 1912f3c799c2SDarrick J. Wong { 1913f3c799c2SDarrick J. Wong kmem_cache_destroy(xfs_refcount_intent_cache); 1914f3c799c2SDarrick J. Wong xfs_refcount_intent_cache = NULL; 1915f3c799c2SDarrick J. Wong } 1916