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); 1118b972158SDarrick J. Wong if (start & XFS_REFC_COWFLAG) { 1128b972158SDarrick J. Wong start &= ~XFS_REFC_COWFLAG; 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 1232b30cc0bSDarrick J. Wong /* Simple checks for refcount records. */ 1242b30cc0bSDarrick J. Wong xfs_failaddr_t 1252b30cc0bSDarrick J. Wong xfs_refcount_check_irec( 1262b30cc0bSDarrick J. Wong struct xfs_btree_cur *cur, 1272b30cc0bSDarrick J. Wong const struct xfs_refcount_irec *irec) 1282b30cc0bSDarrick J. Wong { 1292b30cc0bSDarrick J. Wong struct xfs_perag *pag = cur->bc_ag.pag; 1302b30cc0bSDarrick J. Wong 1312b30cc0bSDarrick J. Wong if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN) 1322b30cc0bSDarrick J. Wong return __this_address; 1332b30cc0bSDarrick J. Wong 1342b30cc0bSDarrick J. Wong if (!xfs_refcount_check_domain(irec)) 1352b30cc0bSDarrick J. Wong return __this_address; 1362b30cc0bSDarrick J. Wong 1372b30cc0bSDarrick J. Wong /* check for valid extent range, including overflow */ 1382b30cc0bSDarrick J. Wong if (!xfs_verify_agbext(pag, irec->rc_startblock, irec->rc_blockcount)) 1392b30cc0bSDarrick J. Wong return __this_address; 1402b30cc0bSDarrick J. Wong 1412b30cc0bSDarrick J. Wong if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT) 1422b30cc0bSDarrick J. Wong return __this_address; 1432b30cc0bSDarrick J. Wong 1442b30cc0bSDarrick J. Wong return NULL; 1452b30cc0bSDarrick J. Wong } 1462b30cc0bSDarrick J. Wong 147ee12eaaaSDarrick J. Wong static inline int 148ee12eaaaSDarrick J. Wong xfs_refcount_complain_bad_rec( 149ee12eaaaSDarrick J. Wong struct xfs_btree_cur *cur, 150ee12eaaaSDarrick J. Wong xfs_failaddr_t fa, 151ee12eaaaSDarrick J. Wong const struct xfs_refcount_irec *irec) 152ee12eaaaSDarrick J. Wong { 153ee12eaaaSDarrick J. Wong struct xfs_mount *mp = cur->bc_mp; 154ee12eaaaSDarrick J. Wong 155ee12eaaaSDarrick J. Wong xfs_warn(mp, 156ee12eaaaSDarrick J. Wong "Refcount BTree record corruption in AG %d detected at %pS!", 157ee12eaaaSDarrick J. Wong cur->bc_ag.pag->pag_agno, fa); 158ee12eaaaSDarrick J. Wong xfs_warn(mp, 159ee12eaaaSDarrick J. Wong "Start block 0x%x, block count 0x%x, references 0x%x", 160ee12eaaaSDarrick J. Wong irec->rc_startblock, irec->rc_blockcount, irec->rc_refcount); 161ee12eaaaSDarrick J. Wong return -EFSCORRUPTED; 162ee12eaaaSDarrick J. Wong } 163ee12eaaaSDarrick J. Wong 164bdf28630SDarrick J. Wong /* 165bdf28630SDarrick J. Wong * Get the data from the pointed-to record. 166bdf28630SDarrick J. Wong */ 167bdf28630SDarrick J. Wong int 168bdf28630SDarrick J. Wong xfs_refcount_get_rec( 169bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 170bdf28630SDarrick J. Wong struct xfs_refcount_irec *irec, 171bdf28630SDarrick J. Wong int *stat) 172bdf28630SDarrick J. Wong { 173bdf28630SDarrick J. Wong union xfs_btree_rec *rec; 1742b30cc0bSDarrick J. Wong xfs_failaddr_t fa; 175bdf28630SDarrick J. Wong int error; 176bdf28630SDarrick J. Wong 177bdf28630SDarrick J. Wong error = xfs_btree_get_rec(cur, &rec, stat); 1789e6c08d4SDave Chinner if (error || !*stat) 179bdf28630SDarrick J. Wong return error; 1809e6c08d4SDave Chinner 1819e6c08d4SDave Chinner xfs_refcount_btrec_to_irec(rec, irec); 1822b30cc0bSDarrick J. Wong fa = xfs_refcount_check_irec(cur, irec); 1832b30cc0bSDarrick J. Wong if (fa) 184ee12eaaaSDarrick J. Wong return xfs_refcount_complain_bad_rec(cur, fa, irec); 1859e6c08d4SDave Chinner 186ee12eaaaSDarrick J. Wong trace_xfs_refcount_get(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec); 1879e6c08d4SDave Chinner return 0; 188bdf28630SDarrick J. Wong } 189bdf28630SDarrick J. Wong 190bdf28630SDarrick J. Wong /* 191bdf28630SDarrick J. Wong * Update the record referred to by cur to the value given 192bdf28630SDarrick J. Wong * by [bno, len, refcount]. 193bdf28630SDarrick J. Wong * This either works (return 0) or gets an EFSCORRUPTED error. 194bdf28630SDarrick J. Wong */ 195bdf28630SDarrick J. Wong STATIC int 196bdf28630SDarrick J. Wong xfs_refcount_update( 197bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 198bdf28630SDarrick J. Wong struct xfs_refcount_irec *irec) 199bdf28630SDarrick J. Wong { 200bdf28630SDarrick J. Wong union xfs_btree_rec rec; 2019a50ee4fSDarrick J. Wong uint32_t start; 202bdf28630SDarrick J. Wong int error; 203bdf28630SDarrick J. Wong 20450f02fe3SDave Chinner trace_xfs_refcount_update(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec); 2059a50ee4fSDarrick J. Wong 2069a50ee4fSDarrick J. Wong start = xfs_refcount_encode_startblock(irec->rc_startblock, 2079a50ee4fSDarrick J. Wong irec->rc_domain); 2089a50ee4fSDarrick J. Wong rec.refc.rc_startblock = cpu_to_be32(start); 209bdf28630SDarrick J. Wong rec.refc.rc_blockcount = cpu_to_be32(irec->rc_blockcount); 210bdf28630SDarrick J. Wong rec.refc.rc_refcount = cpu_to_be32(irec->rc_refcount); 2119a50ee4fSDarrick J. Wong 212bdf28630SDarrick J. Wong error = xfs_btree_update(cur, &rec); 213bdf28630SDarrick J. Wong if (error) 214bdf28630SDarrick J. Wong trace_xfs_refcount_update_error(cur->bc_mp, 21550f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 216bdf28630SDarrick J. Wong return error; 217bdf28630SDarrick J. Wong } 218bdf28630SDarrick J. Wong 219bdf28630SDarrick J. Wong /* 220bdf28630SDarrick J. Wong * Insert the record referred to by cur to the value given 221bdf28630SDarrick J. Wong * by [bno, len, refcount]. 222bdf28630SDarrick J. Wong * This either works (return 0) or gets an EFSCORRUPTED error. 223bdf28630SDarrick J. Wong */ 2247f8f1313SDarrick J. Wong int 225bdf28630SDarrick J. Wong xfs_refcount_insert( 226bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 227bdf28630SDarrick J. Wong struct xfs_refcount_irec *irec, 228bdf28630SDarrick J. Wong int *i) 229bdf28630SDarrick J. Wong { 230bdf28630SDarrick J. Wong int error; 231bdf28630SDarrick J. Wong 23250f02fe3SDave Chinner trace_xfs_refcount_insert(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec); 2339a50ee4fSDarrick J. Wong 234bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_startblock = irec->rc_startblock; 235bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_blockcount = irec->rc_blockcount; 236bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_refcount = irec->rc_refcount; 2379a50ee4fSDarrick J. Wong cur->bc_rec.rc.rc_domain = irec->rc_domain; 2389a50ee4fSDarrick J. Wong 239bdf28630SDarrick J. Wong error = xfs_btree_insert(cur, i); 24016858f7cSDave Chinner if (error) 24116858f7cSDave Chinner goto out_error; 242f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, *i != 1)) { 243f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 244f9e03706SDarrick J. Wong goto out_error; 245f9e03706SDarrick J. Wong } 24616858f7cSDave Chinner 247bdf28630SDarrick J. Wong out_error: 248bdf28630SDarrick J. Wong if (error) 249bdf28630SDarrick J. Wong trace_xfs_refcount_insert_error(cur->bc_mp, 25050f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 251bdf28630SDarrick J. Wong return error; 252bdf28630SDarrick J. Wong } 253bdf28630SDarrick J. Wong 254bdf28630SDarrick J. Wong /* 255bdf28630SDarrick J. Wong * Remove the record referred to by cur, then set the pointer to the spot 256bdf28630SDarrick J. Wong * where the record could be re-inserted, in case we want to increment or 257bdf28630SDarrick J. Wong * decrement the cursor. 258bdf28630SDarrick J. Wong * This either works (return 0) or gets an EFSCORRUPTED error. 259bdf28630SDarrick J. Wong */ 260bdf28630SDarrick J. Wong STATIC int 261bdf28630SDarrick J. Wong xfs_refcount_delete( 262bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 263bdf28630SDarrick J. Wong int *i) 264bdf28630SDarrick J. Wong { 265bdf28630SDarrick J. Wong struct xfs_refcount_irec irec; 266bdf28630SDarrick J. Wong int found_rec; 267bdf28630SDarrick J. Wong int error; 268bdf28630SDarrick J. Wong 269bdf28630SDarrick J. Wong error = xfs_refcount_get_rec(cur, &irec, &found_rec); 270bdf28630SDarrick J. Wong if (error) 271bdf28630SDarrick J. Wong goto out_error; 272f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 273f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 274f9e03706SDarrick J. Wong goto out_error; 275f9e03706SDarrick J. Wong } 27650f02fe3SDave Chinner trace_xfs_refcount_delete(cur->bc_mp, cur->bc_ag.pag->pag_agno, &irec); 277bdf28630SDarrick J. Wong error = xfs_btree_delete(cur, i); 278f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, *i != 1)) { 279f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 280f9e03706SDarrick J. Wong goto out_error; 281f9e03706SDarrick J. Wong } 282bdf28630SDarrick J. Wong if (error) 283bdf28630SDarrick J. Wong goto out_error; 2849a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_ge(cur, irec.rc_domain, irec.rc_startblock, 2859a50ee4fSDarrick J. Wong &found_rec); 286bdf28630SDarrick J. Wong out_error: 287bdf28630SDarrick J. Wong if (error) 288bdf28630SDarrick J. Wong trace_xfs_refcount_delete_error(cur->bc_mp, 28950f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 290bdf28630SDarrick J. Wong return error; 291bdf28630SDarrick J. Wong } 29231727258SDarrick J. Wong 29331727258SDarrick J. Wong /* 29431727258SDarrick J. Wong * Adjusting the Reference Count 29531727258SDarrick J. Wong * 29631727258SDarrick J. Wong * As stated elsewhere, the reference count btree (refcbt) stores 29731727258SDarrick J. Wong * >1 reference counts for extents of physical blocks. In this 29831727258SDarrick J. Wong * operation, we're either raising or lowering the reference count of 29931727258SDarrick J. Wong * some subrange stored in the tree: 30031727258SDarrick J. Wong * 30131727258SDarrick J. Wong * <------ adjustment range ------> 30231727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+--------- 30331727258SDarrick J. Wong * 2 | | 3 | 4 | |17| 55 | 10 30431727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+--------- 30531727258SDarrick J. Wong * X axis is physical blocks number; 30631727258SDarrick J. Wong * reference counts are the numbers inside the rectangles 30731727258SDarrick J. Wong * 30831727258SDarrick J. Wong * The first thing we need to do is to ensure that there are no 30931727258SDarrick J. Wong * refcount extents crossing either boundary of the range to be 31031727258SDarrick J. Wong * adjusted. For any extent that does cross a boundary, split it into 31131727258SDarrick J. Wong * two extents so that we can increment the refcount of one of the 31231727258SDarrick J. Wong * pieces later: 31331727258SDarrick J. Wong * 31431727258SDarrick J. Wong * <------ adjustment range ------> 31531727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+----+---- 31631727258SDarrick J. Wong * 2 | | 3 | 2 | |17| 55 | 10 | 10 31731727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+----+---- 31831727258SDarrick J. Wong * 31931727258SDarrick J. Wong * For this next step, let's assume that all the physical blocks in 32031727258SDarrick J. Wong * the adjustment range are mapped to a file and are therefore in use 32131727258SDarrick J. Wong * at least once. Therefore, we can infer that any gap in the 32231727258SDarrick J. Wong * refcount tree within the adjustment range represents a physical 32331727258SDarrick J. Wong * extent with refcount == 1: 32431727258SDarrick J. Wong * 32531727258SDarrick J. Wong * <------ adjustment range ------> 32631727258SDarrick J. Wong * ----+---+---+-----+-+--+--------+----+---- 32731727258SDarrick J. Wong * 2 |"1"| 3 | 2 |1|17| 55 | 10 | 10 32831727258SDarrick J. Wong * ----+---+---+-----+-+--+--------+----+---- 32931727258SDarrick J. Wong * ^ 33031727258SDarrick J. Wong * 33131727258SDarrick J. Wong * For each extent that falls within the interval range, figure out 33231727258SDarrick J. Wong * which extent is to the left or the right of that extent. Now we 33331727258SDarrick J. Wong * have a left, current, and right extent. If the new reference count 33431727258SDarrick J. Wong * of the center extent enables us to merge left, center, and right 33531727258SDarrick J. Wong * into one record covering all three, do so. If the center extent is 33631727258SDarrick J. Wong * at the left end of the range, abuts the left extent, and its new 33731727258SDarrick J. Wong * reference count matches the left extent's record, then merge them. 33831727258SDarrick J. Wong * If the center extent is at the right end of the range, abuts the 33931727258SDarrick J. Wong * right extent, and the reference counts match, merge those. In the 34031727258SDarrick J. Wong * example, we can left merge (assuming an increment operation): 34131727258SDarrick J. Wong * 34231727258SDarrick J. Wong * <------ adjustment range ------> 34331727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 34431727258SDarrick J. Wong * 2 | 3 | 2 |1|17| 55 | 10 | 10 34531727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 34631727258SDarrick J. Wong * ^ 34731727258SDarrick J. Wong * 34831727258SDarrick J. Wong * For all other extents within the range, adjust the reference count 34931727258SDarrick J. Wong * or delete it if the refcount falls below 2. If we were 35031727258SDarrick J. Wong * incrementing, the end result looks like this: 35131727258SDarrick J. Wong * 35231727258SDarrick J. Wong * <------ adjustment range ------> 35331727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 35431727258SDarrick J. Wong * 2 | 4 | 3 |2|18| 56 | 11 | 10 35531727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 35631727258SDarrick J. Wong * 35731727258SDarrick J. Wong * The result of a decrement operation looks as such: 35831727258SDarrick J. Wong * 35931727258SDarrick J. Wong * <------ adjustment range ------> 36031727258SDarrick J. Wong * ----+ +---+ +--+--------+----+---- 36131727258SDarrick J. Wong * 2 | | 2 | |16| 54 | 9 | 10 36231727258SDarrick J. Wong * ----+ +---+ +--+--------+----+---- 36331727258SDarrick J. Wong * DDDD 111111DD 36431727258SDarrick J. Wong * 36531727258SDarrick J. Wong * The blocks marked "D" are freed; the blocks marked "1" are only 36631727258SDarrick J. Wong * referenced once and therefore the record is removed from the 36731727258SDarrick J. Wong * refcount btree. 36831727258SDarrick J. Wong */ 36931727258SDarrick J. Wong 37031727258SDarrick J. Wong /* Next block after this extent. */ 37131727258SDarrick J. Wong static inline xfs_agblock_t 37231727258SDarrick J. Wong xfs_refc_next( 37331727258SDarrick J. Wong struct xfs_refcount_irec *rc) 37431727258SDarrick J. Wong { 37531727258SDarrick J. Wong return rc->rc_startblock + rc->rc_blockcount; 37631727258SDarrick J. Wong } 37731727258SDarrick J. Wong 37831727258SDarrick J. Wong /* 37931727258SDarrick J. Wong * Split a refcount extent that crosses agbno. 38031727258SDarrick J. Wong */ 38131727258SDarrick J. Wong STATIC int 38231727258SDarrick J. Wong xfs_refcount_split_extent( 38331727258SDarrick J. Wong struct xfs_btree_cur *cur, 3849a50ee4fSDarrick J. Wong enum xfs_refc_domain domain, 38531727258SDarrick J. Wong xfs_agblock_t agbno, 38631727258SDarrick J. Wong bool *shape_changed) 38731727258SDarrick J. Wong { 38831727258SDarrick J. Wong struct xfs_refcount_irec rcext, tmp; 38931727258SDarrick J. Wong int found_rec; 39031727258SDarrick J. Wong int error; 39131727258SDarrick J. Wong 39231727258SDarrick J. Wong *shape_changed = false; 3939a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(cur, domain, agbno, &found_rec); 39431727258SDarrick J. Wong if (error) 39531727258SDarrick J. Wong goto out_error; 39631727258SDarrick J. Wong if (!found_rec) 39731727258SDarrick J. Wong return 0; 39831727258SDarrick J. Wong 39931727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &rcext, &found_rec); 40031727258SDarrick J. Wong if (error) 40131727258SDarrick J. Wong goto out_error; 402f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 403f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 404f9e03706SDarrick J. Wong goto out_error; 405f9e03706SDarrick J. Wong } 406f62ac3e0SDarrick J. Wong if (rcext.rc_domain != domain) 407f62ac3e0SDarrick J. Wong return 0; 40831727258SDarrick J. Wong if (rcext.rc_startblock == agbno || xfs_refc_next(&rcext) <= agbno) 40931727258SDarrick J. Wong return 0; 41031727258SDarrick J. Wong 41131727258SDarrick J. Wong *shape_changed = true; 41250f02fe3SDave Chinner trace_xfs_refcount_split_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno, 41331727258SDarrick J. Wong &rcext, agbno); 41431727258SDarrick J. Wong 41531727258SDarrick J. Wong /* Establish the right extent. */ 41631727258SDarrick J. Wong tmp = rcext; 41731727258SDarrick J. Wong tmp.rc_startblock = agbno; 41831727258SDarrick J. Wong tmp.rc_blockcount -= (agbno - rcext.rc_startblock); 41931727258SDarrick J. Wong error = xfs_refcount_update(cur, &tmp); 42031727258SDarrick J. Wong if (error) 42131727258SDarrick J. Wong goto out_error; 42231727258SDarrick J. Wong 42331727258SDarrick J. Wong /* Insert the left extent. */ 42431727258SDarrick J. Wong tmp = rcext; 42531727258SDarrick J. Wong tmp.rc_blockcount = agbno - rcext.rc_startblock; 42631727258SDarrick J. Wong error = xfs_refcount_insert(cur, &tmp, &found_rec); 42731727258SDarrick J. Wong if (error) 42831727258SDarrick J. Wong goto out_error; 429f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 430f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 431f9e03706SDarrick J. Wong goto out_error; 432f9e03706SDarrick J. Wong } 43331727258SDarrick J. Wong return error; 43431727258SDarrick J. Wong 43531727258SDarrick J. Wong out_error: 43631727258SDarrick J. Wong trace_xfs_refcount_split_extent_error(cur->bc_mp, 43750f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 43831727258SDarrick J. Wong return error; 43931727258SDarrick J. Wong } 44031727258SDarrick J. Wong 44131727258SDarrick J. Wong /* 44231727258SDarrick J. Wong * Merge the left, center, and right extents. 44331727258SDarrick J. Wong */ 44431727258SDarrick J. Wong STATIC int 44531727258SDarrick J. Wong xfs_refcount_merge_center_extents( 44631727258SDarrick J. Wong struct xfs_btree_cur *cur, 44731727258SDarrick J. Wong struct xfs_refcount_irec *left, 44831727258SDarrick J. Wong struct xfs_refcount_irec *center, 44931727258SDarrick J. Wong struct xfs_refcount_irec *right, 45031727258SDarrick J. Wong unsigned long long extlen, 45131727258SDarrick J. Wong xfs_extlen_t *aglen) 45231727258SDarrick J. Wong { 45331727258SDarrick J. Wong int error; 45431727258SDarrick J. Wong int found_rec; 45531727258SDarrick J. Wong 45631727258SDarrick J. Wong trace_xfs_refcount_merge_center_extents(cur->bc_mp, 45750f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, left, center, right); 45831727258SDarrick J. Wong 459f62ac3e0SDarrick J. Wong ASSERT(left->rc_domain == center->rc_domain); 460f62ac3e0SDarrick J. Wong ASSERT(right->rc_domain == center->rc_domain); 461f62ac3e0SDarrick J. Wong 46231727258SDarrick J. Wong /* 46331727258SDarrick J. Wong * Make sure the center and right extents are not in the btree. 46431727258SDarrick J. Wong * If the center extent was synthesized, the first delete call 46531727258SDarrick J. Wong * removes the right extent and we skip the second deletion. 46631727258SDarrick J. Wong * If center and right were in the btree, then the first delete 46731727258SDarrick J. Wong * call removes the center and the second one removes the right 46831727258SDarrick J. Wong * extent. 46931727258SDarrick J. Wong */ 4709a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_ge(cur, center->rc_domain, 4719a50ee4fSDarrick J. Wong center->rc_startblock, &found_rec); 47231727258SDarrick J. Wong if (error) 47331727258SDarrick J. Wong goto out_error; 474f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 475f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 476f9e03706SDarrick J. Wong goto out_error; 477f9e03706SDarrick J. Wong } 47831727258SDarrick J. Wong 47931727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 48031727258SDarrick J. Wong if (error) 48131727258SDarrick J. Wong goto out_error; 482f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 483f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 484f9e03706SDarrick J. Wong goto out_error; 485f9e03706SDarrick J. Wong } 48631727258SDarrick J. Wong 48731727258SDarrick J. Wong if (center->rc_refcount > 1) { 48831727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 48931727258SDarrick J. Wong if (error) 49031727258SDarrick J. Wong goto out_error; 491f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 492f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 493f9e03706SDarrick J. Wong goto out_error; 494f9e03706SDarrick J. Wong } 49531727258SDarrick J. Wong } 49631727258SDarrick J. Wong 49731727258SDarrick J. Wong /* Enlarge the left extent. */ 4989a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(cur, left->rc_domain, 4999a50ee4fSDarrick J. Wong left->rc_startblock, &found_rec); 50031727258SDarrick J. Wong if (error) 50131727258SDarrick J. Wong goto out_error; 502f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 503f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 504f9e03706SDarrick J. Wong goto out_error; 505f9e03706SDarrick J. Wong } 50631727258SDarrick J. Wong 50731727258SDarrick J. Wong left->rc_blockcount = extlen; 50831727258SDarrick J. Wong error = xfs_refcount_update(cur, left); 50931727258SDarrick J. Wong if (error) 51031727258SDarrick J. Wong goto out_error; 51131727258SDarrick J. Wong 51231727258SDarrick J. Wong *aglen = 0; 51331727258SDarrick J. Wong return error; 51431727258SDarrick J. Wong 51531727258SDarrick J. Wong out_error: 51631727258SDarrick J. Wong trace_xfs_refcount_merge_center_extents_error(cur->bc_mp, 51750f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 51831727258SDarrick J. Wong return error; 51931727258SDarrick J. Wong } 52031727258SDarrick J. Wong 52131727258SDarrick J. Wong /* 52231727258SDarrick J. Wong * Merge with the left extent. 52331727258SDarrick J. Wong */ 52431727258SDarrick J. Wong STATIC int 52531727258SDarrick J. Wong xfs_refcount_merge_left_extent( 52631727258SDarrick J. Wong struct xfs_btree_cur *cur, 52731727258SDarrick J. Wong struct xfs_refcount_irec *left, 52831727258SDarrick J. Wong struct xfs_refcount_irec *cleft, 52931727258SDarrick J. Wong xfs_agblock_t *agbno, 53031727258SDarrick J. Wong xfs_extlen_t *aglen) 53131727258SDarrick J. Wong { 53231727258SDarrick J. Wong int error; 53331727258SDarrick J. Wong int found_rec; 53431727258SDarrick J. Wong 53531727258SDarrick J. Wong trace_xfs_refcount_merge_left_extent(cur->bc_mp, 53650f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, left, cleft); 53731727258SDarrick J. Wong 538f62ac3e0SDarrick J. Wong ASSERT(left->rc_domain == cleft->rc_domain); 539f62ac3e0SDarrick J. Wong 54031727258SDarrick J. Wong /* If the extent at agbno (cleft) wasn't synthesized, remove it. */ 54131727258SDarrick J. Wong if (cleft->rc_refcount > 1) { 5429a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(cur, cleft->rc_domain, 5439a50ee4fSDarrick J. Wong cleft->rc_startblock, &found_rec); 54431727258SDarrick J. Wong if (error) 54531727258SDarrick J. Wong goto out_error; 546f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 547f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 548f9e03706SDarrick J. Wong goto out_error; 549f9e03706SDarrick J. Wong } 55031727258SDarrick J. Wong 55131727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 55231727258SDarrick J. Wong if (error) 55331727258SDarrick J. Wong goto out_error; 554f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 555f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 556f9e03706SDarrick J. Wong goto out_error; 557f9e03706SDarrick J. Wong } 55831727258SDarrick J. Wong } 55931727258SDarrick J. Wong 56031727258SDarrick J. Wong /* Enlarge the left extent. */ 5619a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(cur, left->rc_domain, 5629a50ee4fSDarrick J. Wong left->rc_startblock, &found_rec); 56331727258SDarrick J. Wong if (error) 56431727258SDarrick J. Wong goto out_error; 565f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 566f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 567f9e03706SDarrick J. Wong goto out_error; 568f9e03706SDarrick J. Wong } 56931727258SDarrick J. Wong 57031727258SDarrick J. Wong left->rc_blockcount += cleft->rc_blockcount; 57131727258SDarrick J. Wong error = xfs_refcount_update(cur, left); 57231727258SDarrick J. Wong if (error) 57331727258SDarrick J. Wong goto out_error; 57431727258SDarrick J. Wong 57531727258SDarrick J. Wong *agbno += cleft->rc_blockcount; 57631727258SDarrick J. Wong *aglen -= cleft->rc_blockcount; 57731727258SDarrick J. Wong return error; 57831727258SDarrick J. Wong 57931727258SDarrick J. Wong out_error: 58031727258SDarrick J. Wong trace_xfs_refcount_merge_left_extent_error(cur->bc_mp, 58150f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 58231727258SDarrick J. Wong return error; 58331727258SDarrick J. Wong } 58431727258SDarrick J. Wong 58531727258SDarrick J. Wong /* 58631727258SDarrick J. Wong * Merge with the right extent. 58731727258SDarrick J. Wong */ 58831727258SDarrick J. Wong STATIC int 58931727258SDarrick J. Wong xfs_refcount_merge_right_extent( 59031727258SDarrick J. Wong struct xfs_btree_cur *cur, 59131727258SDarrick J. Wong struct xfs_refcount_irec *right, 59231727258SDarrick J. Wong struct xfs_refcount_irec *cright, 59331727258SDarrick J. Wong xfs_extlen_t *aglen) 59431727258SDarrick J. Wong { 59531727258SDarrick J. Wong int error; 59631727258SDarrick J. Wong int found_rec; 59731727258SDarrick J. Wong 59831727258SDarrick J. Wong trace_xfs_refcount_merge_right_extent(cur->bc_mp, 59950f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, cright, right); 60031727258SDarrick J. Wong 601f62ac3e0SDarrick J. Wong ASSERT(right->rc_domain == cright->rc_domain); 602f62ac3e0SDarrick J. Wong 60331727258SDarrick J. Wong /* 60431727258SDarrick J. Wong * If the extent ending at agbno+aglen (cright) wasn't synthesized, 60531727258SDarrick J. Wong * remove it. 60631727258SDarrick J. Wong */ 60731727258SDarrick J. Wong if (cright->rc_refcount > 1) { 6089a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(cur, cright->rc_domain, 6099a50ee4fSDarrick J. Wong cright->rc_startblock, &found_rec); 61031727258SDarrick J. Wong if (error) 61131727258SDarrick J. Wong goto out_error; 612f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 613f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 614f9e03706SDarrick J. Wong goto out_error; 615f9e03706SDarrick J. Wong } 61631727258SDarrick J. Wong 61731727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 61831727258SDarrick J. Wong if (error) 61931727258SDarrick J. Wong goto out_error; 620f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 621f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 622f9e03706SDarrick J. Wong goto out_error; 623f9e03706SDarrick J. Wong } 62431727258SDarrick J. Wong } 62531727258SDarrick J. Wong 62631727258SDarrick J. Wong /* Enlarge the right extent. */ 6279a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(cur, right->rc_domain, 6289a50ee4fSDarrick J. Wong right->rc_startblock, &found_rec); 62931727258SDarrick J. Wong if (error) 63031727258SDarrick J. Wong goto out_error; 631f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 632f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 633f9e03706SDarrick J. Wong goto out_error; 634f9e03706SDarrick J. Wong } 63531727258SDarrick J. Wong 63631727258SDarrick J. Wong right->rc_startblock -= cright->rc_blockcount; 63731727258SDarrick J. Wong right->rc_blockcount += cright->rc_blockcount; 63831727258SDarrick J. Wong error = xfs_refcount_update(cur, right); 63931727258SDarrick J. Wong if (error) 64031727258SDarrick J. Wong goto out_error; 64131727258SDarrick J. Wong 64231727258SDarrick J. Wong *aglen -= cright->rc_blockcount; 64331727258SDarrick J. Wong return error; 64431727258SDarrick J. Wong 64531727258SDarrick J. Wong out_error: 64631727258SDarrick J. Wong trace_xfs_refcount_merge_right_extent_error(cur->bc_mp, 64750f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 64831727258SDarrick J. Wong return error; 64931727258SDarrick J. Wong } 65031727258SDarrick J. Wong 65131727258SDarrick J. Wong /* 65231727258SDarrick J. Wong * Find the left extent and the one after it (cleft). This function assumes 65331727258SDarrick J. Wong * that we've already split any extent crossing agbno. 65431727258SDarrick J. Wong */ 65531727258SDarrick J. Wong STATIC int 65631727258SDarrick J. Wong xfs_refcount_find_left_extents( 65731727258SDarrick J. Wong struct xfs_btree_cur *cur, 65831727258SDarrick J. Wong struct xfs_refcount_irec *left, 65931727258SDarrick J. Wong struct xfs_refcount_irec *cleft, 66068d0f389SDarrick J. Wong enum xfs_refc_domain domain, 66131727258SDarrick J. Wong xfs_agblock_t agbno, 66268d0f389SDarrick J. Wong xfs_extlen_t aglen) 66331727258SDarrick J. Wong { 66431727258SDarrick J. Wong struct xfs_refcount_irec tmp; 66531727258SDarrick J. Wong int error; 66631727258SDarrick J. Wong int found_rec; 66731727258SDarrick J. Wong 66831727258SDarrick J. Wong left->rc_startblock = cleft->rc_startblock = NULLAGBLOCK; 6699a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(cur, domain, agbno - 1, &found_rec); 67031727258SDarrick J. Wong if (error) 67131727258SDarrick J. Wong goto out_error; 67231727258SDarrick J. Wong if (!found_rec) 67331727258SDarrick J. Wong return 0; 67431727258SDarrick J. Wong 67531727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 67631727258SDarrick J. Wong if (error) 67731727258SDarrick J. Wong goto out_error; 678f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 679f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 680f9e03706SDarrick J. Wong goto out_error; 681f9e03706SDarrick J. Wong } 68231727258SDarrick J. Wong 683f62ac3e0SDarrick J. Wong if (tmp.rc_domain != domain) 684f62ac3e0SDarrick J. Wong return 0; 68531727258SDarrick J. Wong if (xfs_refc_next(&tmp) != agbno) 68631727258SDarrick J. Wong return 0; 68731727258SDarrick J. Wong /* We have a left extent; retrieve (or invent) the next right one */ 68831727258SDarrick J. Wong *left = tmp; 68931727258SDarrick J. Wong 69031727258SDarrick J. Wong error = xfs_btree_increment(cur, 0, &found_rec); 69131727258SDarrick J. Wong if (error) 69231727258SDarrick J. Wong goto out_error; 69331727258SDarrick J. Wong if (found_rec) { 69431727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 69531727258SDarrick J. Wong if (error) 69631727258SDarrick J. Wong goto out_error; 697f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 698f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 699f9e03706SDarrick J. Wong goto out_error; 700f9e03706SDarrick J. Wong } 70131727258SDarrick J. Wong 702f62ac3e0SDarrick J. Wong if (tmp.rc_domain != domain) 703f62ac3e0SDarrick J. Wong goto not_found; 704f62ac3e0SDarrick J. Wong 70531727258SDarrick J. Wong /* if tmp starts at the end of our range, just use that */ 70631727258SDarrick J. Wong if (tmp.rc_startblock == agbno) 70731727258SDarrick J. Wong *cleft = tmp; 70831727258SDarrick J. Wong else { 70931727258SDarrick J. Wong /* 71031727258SDarrick J. Wong * There's a gap in the refcntbt at the start of the 71131727258SDarrick J. Wong * range we're interested in (refcount == 1) so 71231727258SDarrick J. Wong * synthesize the implied extent and pass it back. 71331727258SDarrick J. Wong * We assume here that the agbno/aglen range was 71431727258SDarrick J. Wong * passed in from a data fork extent mapping and 71531727258SDarrick J. Wong * therefore is allocated to exactly one owner. 71631727258SDarrick J. Wong */ 71731727258SDarrick J. Wong cleft->rc_startblock = agbno; 71831727258SDarrick J. Wong cleft->rc_blockcount = min(aglen, 71931727258SDarrick J. Wong tmp.rc_startblock - agbno); 72031727258SDarrick J. Wong cleft->rc_refcount = 1; 7219a50ee4fSDarrick J. Wong cleft->rc_domain = domain; 72231727258SDarrick J. Wong } 72331727258SDarrick J. Wong } else { 724f62ac3e0SDarrick J. Wong not_found: 72531727258SDarrick J. Wong /* 72631727258SDarrick J. Wong * No extents, so pretend that there's one covering the whole 72731727258SDarrick J. Wong * range. 72831727258SDarrick J. Wong */ 72931727258SDarrick J. Wong cleft->rc_startblock = agbno; 73031727258SDarrick J. Wong cleft->rc_blockcount = aglen; 73131727258SDarrick J. Wong cleft->rc_refcount = 1; 7329a50ee4fSDarrick J. Wong cleft->rc_domain = domain; 73331727258SDarrick J. Wong } 73450f02fe3SDave Chinner trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno, 73531727258SDarrick J. Wong left, cleft, agbno); 73631727258SDarrick J. Wong return error; 73731727258SDarrick J. Wong 73831727258SDarrick J. Wong out_error: 73931727258SDarrick J. Wong trace_xfs_refcount_find_left_extent_error(cur->bc_mp, 74050f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 74131727258SDarrick J. Wong return error; 74231727258SDarrick J. Wong } 74331727258SDarrick J. Wong 74431727258SDarrick J. Wong /* 74531727258SDarrick J. Wong * Find the right extent and the one before it (cright). This function 74631727258SDarrick J. Wong * assumes that we've already split any extents crossing agbno + aglen. 74731727258SDarrick J. Wong */ 74831727258SDarrick J. Wong STATIC int 74931727258SDarrick J. Wong xfs_refcount_find_right_extents( 75031727258SDarrick J. Wong struct xfs_btree_cur *cur, 75131727258SDarrick J. Wong struct xfs_refcount_irec *right, 75231727258SDarrick J. Wong struct xfs_refcount_irec *cright, 75368d0f389SDarrick J. Wong enum xfs_refc_domain domain, 75431727258SDarrick J. Wong xfs_agblock_t agbno, 75568d0f389SDarrick J. Wong xfs_extlen_t aglen) 75631727258SDarrick J. Wong { 75731727258SDarrick J. Wong struct xfs_refcount_irec tmp; 75831727258SDarrick J. Wong int error; 75931727258SDarrick J. Wong int found_rec; 76031727258SDarrick J. Wong 76131727258SDarrick J. Wong right->rc_startblock = cright->rc_startblock = NULLAGBLOCK; 7629a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_ge(cur, domain, agbno + aglen, &found_rec); 76331727258SDarrick J. Wong if (error) 76431727258SDarrick J. Wong goto out_error; 76531727258SDarrick J. Wong if (!found_rec) 76631727258SDarrick J. Wong return 0; 76731727258SDarrick J. Wong 76831727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 76931727258SDarrick J. Wong if (error) 77031727258SDarrick J. Wong goto out_error; 771f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 772f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 773f9e03706SDarrick J. Wong goto out_error; 774f9e03706SDarrick J. Wong } 77531727258SDarrick J. Wong 776f62ac3e0SDarrick J. Wong if (tmp.rc_domain != domain) 777f62ac3e0SDarrick J. Wong return 0; 77831727258SDarrick J. Wong if (tmp.rc_startblock != agbno + aglen) 77931727258SDarrick J. Wong return 0; 78031727258SDarrick J. Wong /* We have a right extent; retrieve (or invent) the next left one */ 78131727258SDarrick J. Wong *right = tmp; 78231727258SDarrick J. Wong 78331727258SDarrick J. Wong error = xfs_btree_decrement(cur, 0, &found_rec); 78431727258SDarrick J. Wong if (error) 78531727258SDarrick J. Wong goto out_error; 78631727258SDarrick J. Wong if (found_rec) { 78731727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 78831727258SDarrick J. Wong if (error) 78931727258SDarrick J. Wong goto out_error; 790f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 791f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 792f9e03706SDarrick J. Wong goto out_error; 793f9e03706SDarrick J. Wong } 79431727258SDarrick J. Wong 795f62ac3e0SDarrick J. Wong if (tmp.rc_domain != domain) 796f62ac3e0SDarrick J. Wong goto not_found; 797f62ac3e0SDarrick J. Wong 79831727258SDarrick J. Wong /* if tmp ends at the end of our range, just use that */ 79931727258SDarrick J. Wong if (xfs_refc_next(&tmp) == agbno + aglen) 80031727258SDarrick J. Wong *cright = tmp; 80131727258SDarrick J. Wong else { 80231727258SDarrick J. Wong /* 80331727258SDarrick J. Wong * There's a gap in the refcntbt at the end of the 80431727258SDarrick J. Wong * range we're interested in (refcount == 1) so 80531727258SDarrick J. Wong * create the implied extent and pass it back. 80631727258SDarrick J. Wong * We assume here that the agbno/aglen range was 80731727258SDarrick J. Wong * passed in from a data fork extent mapping and 80831727258SDarrick J. Wong * therefore is allocated to exactly one owner. 80931727258SDarrick J. Wong */ 81031727258SDarrick J. Wong cright->rc_startblock = max(agbno, xfs_refc_next(&tmp)); 81131727258SDarrick J. Wong cright->rc_blockcount = right->rc_startblock - 81231727258SDarrick J. Wong cright->rc_startblock; 81331727258SDarrick J. Wong cright->rc_refcount = 1; 8149a50ee4fSDarrick J. Wong cright->rc_domain = domain; 81531727258SDarrick J. Wong } 81631727258SDarrick J. Wong } else { 817f62ac3e0SDarrick J. Wong not_found: 81831727258SDarrick J. Wong /* 81931727258SDarrick J. Wong * No extents, so pretend that there's one covering the whole 82031727258SDarrick J. Wong * range. 82131727258SDarrick J. Wong */ 82231727258SDarrick J. Wong cright->rc_startblock = agbno; 82331727258SDarrick J. Wong cright->rc_blockcount = aglen; 82431727258SDarrick J. Wong cright->rc_refcount = 1; 8259a50ee4fSDarrick J. Wong cright->rc_domain = domain; 82631727258SDarrick J. Wong } 82750f02fe3SDave Chinner trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno, 82831727258SDarrick J. Wong cright, right, agbno + aglen); 82931727258SDarrick J. Wong return error; 83031727258SDarrick J. Wong 83131727258SDarrick J. Wong out_error: 83231727258SDarrick J. Wong trace_xfs_refcount_find_right_extent_error(cur->bc_mp, 83350f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 83431727258SDarrick J. Wong return error; 83531727258SDarrick J. Wong } 83631727258SDarrick J. Wong 83731727258SDarrick J. Wong /* Is this extent valid? */ 83831727258SDarrick J. Wong static inline bool 83931727258SDarrick J. Wong xfs_refc_valid( 8409d720a5aSDarrick J. Wong const struct xfs_refcount_irec *rc) 84131727258SDarrick J. Wong { 84231727258SDarrick J. Wong return rc->rc_startblock != NULLAGBLOCK; 84331727258SDarrick J. Wong } 84431727258SDarrick J. Wong 845b25d1984SDarrick J. Wong static inline xfs_nlink_t 846b25d1984SDarrick J. Wong xfs_refc_merge_refcount( 847b25d1984SDarrick J. Wong const struct xfs_refcount_irec *irec, 848b25d1984SDarrick J. Wong enum xfs_refc_adjust_op adjust) 849b25d1984SDarrick J. Wong { 850b25d1984SDarrick J. Wong /* Once a record hits MAXREFCOUNT, it is pinned there forever */ 851b25d1984SDarrick J. Wong if (irec->rc_refcount == MAXREFCOUNT) 852b25d1984SDarrick J. Wong return MAXREFCOUNT; 853b25d1984SDarrick J. Wong return irec->rc_refcount + adjust; 854b25d1984SDarrick J. Wong } 855b25d1984SDarrick J. Wong 8569d720a5aSDarrick J. Wong static inline bool 8579d720a5aSDarrick J. Wong xfs_refc_want_merge_center( 8589d720a5aSDarrick J. Wong const struct xfs_refcount_irec *left, 8599d720a5aSDarrick J. Wong const struct xfs_refcount_irec *cleft, 8609d720a5aSDarrick J. Wong const struct xfs_refcount_irec *cright, 8619d720a5aSDarrick J. Wong const struct xfs_refcount_irec *right, 8629d720a5aSDarrick J. Wong bool cleft_is_cright, 8639d720a5aSDarrick J. Wong enum xfs_refc_adjust_op adjust, 8649d720a5aSDarrick J. Wong unsigned long long *ulenp) 8659d720a5aSDarrick J. Wong { 8669d720a5aSDarrick J. Wong unsigned long long ulen = left->rc_blockcount; 867b25d1984SDarrick J. Wong xfs_nlink_t new_refcount; 8689d720a5aSDarrick J. Wong 8699d720a5aSDarrick J. Wong /* 8709d720a5aSDarrick J. Wong * To merge with a center record, both shoulder records must be 8719d720a5aSDarrick J. Wong * adjacent to the record we want to adjust. This is only true if 8729d720a5aSDarrick J. Wong * find_left and find_right made all four records valid. 8739d720a5aSDarrick J. Wong */ 8749d720a5aSDarrick J. Wong if (!xfs_refc_valid(left) || !xfs_refc_valid(right) || 8759d720a5aSDarrick J. Wong !xfs_refc_valid(cleft) || !xfs_refc_valid(cright)) 8769d720a5aSDarrick J. Wong return false; 8779d720a5aSDarrick J. Wong 8789d720a5aSDarrick J. Wong /* There must only be one record for the entire range. */ 8799d720a5aSDarrick J. Wong if (!cleft_is_cright) 8809d720a5aSDarrick J. Wong return false; 8819d720a5aSDarrick J. Wong 8829d720a5aSDarrick J. Wong /* The shoulder record refcounts must match the new refcount. */ 883b25d1984SDarrick J. Wong new_refcount = xfs_refc_merge_refcount(cleft, adjust); 884b25d1984SDarrick J. Wong if (left->rc_refcount != new_refcount) 8859d720a5aSDarrick J. Wong return false; 886b25d1984SDarrick J. Wong if (right->rc_refcount != new_refcount) 8879d720a5aSDarrick J. Wong return false; 8889d720a5aSDarrick J. Wong 8899d720a5aSDarrick J. Wong /* 8909d720a5aSDarrick J. Wong * The new record cannot exceed the max length. ulen is a ULL as the 8919d720a5aSDarrick J. Wong * individual record block counts can be up to (u32 - 1) in length 8929d720a5aSDarrick J. Wong * hence we need to catch u32 addition overflows here. 8939d720a5aSDarrick J. Wong */ 8949d720a5aSDarrick J. Wong ulen += cleft->rc_blockcount + right->rc_blockcount; 8959d720a5aSDarrick J. Wong if (ulen >= MAXREFCEXTLEN) 8969d720a5aSDarrick J. Wong return false; 8979d720a5aSDarrick J. Wong 8989d720a5aSDarrick J. Wong *ulenp = ulen; 8999d720a5aSDarrick J. Wong return true; 9009d720a5aSDarrick J. Wong } 9019d720a5aSDarrick J. Wong 9029d720a5aSDarrick J. Wong static inline bool 9039d720a5aSDarrick J. Wong xfs_refc_want_merge_left( 9049d720a5aSDarrick J. Wong const struct xfs_refcount_irec *left, 9059d720a5aSDarrick J. Wong const struct xfs_refcount_irec *cleft, 9069d720a5aSDarrick J. Wong enum xfs_refc_adjust_op adjust) 9079d720a5aSDarrick J. Wong { 9089d720a5aSDarrick J. Wong unsigned long long ulen = left->rc_blockcount; 909b25d1984SDarrick J. Wong xfs_nlink_t new_refcount; 9109d720a5aSDarrick J. Wong 9119d720a5aSDarrick J. Wong /* 9129d720a5aSDarrick J. Wong * For a left merge, the left shoulder record must be adjacent to the 9139d720a5aSDarrick J. Wong * start of the range. If this is true, find_left made left and cleft 9149d720a5aSDarrick J. Wong * contain valid contents. 9159d720a5aSDarrick J. Wong */ 9169d720a5aSDarrick J. Wong if (!xfs_refc_valid(left) || !xfs_refc_valid(cleft)) 9179d720a5aSDarrick J. Wong return false; 9189d720a5aSDarrick J. Wong 9199d720a5aSDarrick J. Wong /* Left shoulder record refcount must match the new refcount. */ 920b25d1984SDarrick J. Wong new_refcount = xfs_refc_merge_refcount(cleft, adjust); 921b25d1984SDarrick J. Wong if (left->rc_refcount != new_refcount) 9229d720a5aSDarrick J. Wong return false; 9239d720a5aSDarrick J. Wong 9249d720a5aSDarrick J. Wong /* 9259d720a5aSDarrick J. Wong * The new record cannot exceed the max length. ulen is a ULL as the 9269d720a5aSDarrick J. Wong * individual record block counts can be up to (u32 - 1) in length 9279d720a5aSDarrick J. Wong * hence we need to catch u32 addition overflows here. 9289d720a5aSDarrick J. Wong */ 9299d720a5aSDarrick J. Wong ulen += cleft->rc_blockcount; 9309d720a5aSDarrick J. Wong if (ulen >= MAXREFCEXTLEN) 9319d720a5aSDarrick J. Wong return false; 9329d720a5aSDarrick J. Wong 9339d720a5aSDarrick J. Wong return true; 9349d720a5aSDarrick J. Wong } 9359d720a5aSDarrick J. Wong 9369d720a5aSDarrick J. Wong static inline bool 9379d720a5aSDarrick J. Wong xfs_refc_want_merge_right( 9389d720a5aSDarrick J. Wong const struct xfs_refcount_irec *cright, 9399d720a5aSDarrick J. Wong const struct xfs_refcount_irec *right, 9409d720a5aSDarrick J. Wong enum xfs_refc_adjust_op adjust) 9419d720a5aSDarrick J. Wong { 9429d720a5aSDarrick J. Wong unsigned long long ulen = right->rc_blockcount; 943b25d1984SDarrick J. Wong xfs_nlink_t new_refcount; 9449d720a5aSDarrick J. Wong 9459d720a5aSDarrick J. Wong /* 9469d720a5aSDarrick J. Wong * For a right merge, the right shoulder record must be adjacent to the 9479d720a5aSDarrick J. Wong * end of the range. If this is true, find_right made cright and right 9489d720a5aSDarrick J. Wong * contain valid contents. 9499d720a5aSDarrick J. Wong */ 9509d720a5aSDarrick J. Wong if (!xfs_refc_valid(right) || !xfs_refc_valid(cright)) 9519d720a5aSDarrick J. Wong return false; 9529d720a5aSDarrick J. Wong 9539d720a5aSDarrick J. Wong /* Right shoulder record refcount must match the new refcount. */ 954b25d1984SDarrick J. Wong new_refcount = xfs_refc_merge_refcount(cright, adjust); 955b25d1984SDarrick J. Wong if (right->rc_refcount != new_refcount) 9569d720a5aSDarrick J. Wong return false; 9579d720a5aSDarrick J. Wong 9589d720a5aSDarrick J. Wong /* 9599d720a5aSDarrick J. Wong * The new record cannot exceed the max length. ulen is a ULL as the 9609d720a5aSDarrick J. Wong * individual record block counts can be up to (u32 - 1) in length 9619d720a5aSDarrick J. Wong * hence we need to catch u32 addition overflows here. 9629d720a5aSDarrick J. Wong */ 9639d720a5aSDarrick J. Wong ulen += cright->rc_blockcount; 9649d720a5aSDarrick J. Wong if (ulen >= MAXREFCEXTLEN) 9659d720a5aSDarrick J. Wong return false; 9669d720a5aSDarrick J. Wong 9679d720a5aSDarrick J. Wong return true; 9689d720a5aSDarrick J. Wong } 9699d720a5aSDarrick J. Wong 97031727258SDarrick J. Wong /* 97131727258SDarrick J. Wong * Try to merge with any extents on the boundaries of the adjustment range. 97231727258SDarrick J. Wong */ 97331727258SDarrick J. Wong STATIC int 97431727258SDarrick J. Wong xfs_refcount_merge_extents( 97531727258SDarrick J. Wong struct xfs_btree_cur *cur, 97668d0f389SDarrick J. Wong enum xfs_refc_domain domain, 97731727258SDarrick J. Wong xfs_agblock_t *agbno, 97831727258SDarrick J. Wong xfs_extlen_t *aglen, 97931727258SDarrick J. Wong enum xfs_refc_adjust_op adjust, 98031727258SDarrick J. Wong bool *shape_changed) 98131727258SDarrick J. Wong { 98231727258SDarrick J. Wong struct xfs_refcount_irec left = {0}, cleft = {0}; 98331727258SDarrick J. Wong struct xfs_refcount_irec cright = {0}, right = {0}; 98431727258SDarrick J. Wong int error; 98531727258SDarrick J. Wong unsigned long long ulen; 98631727258SDarrick J. Wong bool cequal; 98731727258SDarrick J. Wong 98831727258SDarrick J. Wong *shape_changed = false; 98931727258SDarrick J. Wong /* 99031727258SDarrick J. Wong * Find the extent just below agbno [left], just above agbno [cleft], 99131727258SDarrick J. Wong * just below (agbno + aglen) [cright], and just above (agbno + aglen) 99231727258SDarrick J. Wong * [right]. 99331727258SDarrick J. Wong */ 99468d0f389SDarrick J. Wong error = xfs_refcount_find_left_extents(cur, &left, &cleft, domain, 99568d0f389SDarrick J. Wong *agbno, *aglen); 99631727258SDarrick J. Wong if (error) 99731727258SDarrick J. Wong return error; 99868d0f389SDarrick J. Wong error = xfs_refcount_find_right_extents(cur, &right, &cright, domain, 99968d0f389SDarrick J. Wong *agbno, *aglen); 100031727258SDarrick J. Wong if (error) 100131727258SDarrick J. Wong return error; 100231727258SDarrick J. Wong 100331727258SDarrick J. Wong /* No left or right extent to merge; exit. */ 100431727258SDarrick J. Wong if (!xfs_refc_valid(&left) && !xfs_refc_valid(&right)) 100531727258SDarrick J. Wong return 0; 100631727258SDarrick J. Wong 100731727258SDarrick J. Wong cequal = (cleft.rc_startblock == cright.rc_startblock) && 100831727258SDarrick J. Wong (cleft.rc_blockcount == cright.rc_blockcount); 100931727258SDarrick J. Wong 101031727258SDarrick J. Wong /* Try to merge left, cleft, and right. cleft must == cright. */ 10119d720a5aSDarrick J. Wong if (xfs_refc_want_merge_center(&left, &cleft, &cright, &right, cequal, 10129d720a5aSDarrick J. Wong adjust, &ulen)) { 101331727258SDarrick J. Wong *shape_changed = true; 101431727258SDarrick J. Wong return xfs_refcount_merge_center_extents(cur, &left, &cleft, 1015a1f69417SEric Sandeen &right, ulen, aglen); 101631727258SDarrick J. Wong } 101731727258SDarrick J. Wong 101831727258SDarrick J. Wong /* Try to merge left and cleft. */ 10199d720a5aSDarrick J. Wong if (xfs_refc_want_merge_left(&left, &cleft, adjust)) { 102031727258SDarrick J. Wong *shape_changed = true; 102131727258SDarrick J. Wong error = xfs_refcount_merge_left_extent(cur, &left, &cleft, 102231727258SDarrick J. Wong agbno, aglen); 102331727258SDarrick J. Wong if (error) 102431727258SDarrick J. Wong return error; 102531727258SDarrick J. Wong 102631727258SDarrick J. Wong /* 102731727258SDarrick J. Wong * If we just merged left + cleft and cleft == cright, 102831727258SDarrick J. Wong * we no longer have a cright to merge with right. We're done. 102931727258SDarrick J. Wong */ 103031727258SDarrick J. Wong if (cequal) 103131727258SDarrick J. Wong return 0; 103231727258SDarrick J. Wong } 103331727258SDarrick J. Wong 103431727258SDarrick J. Wong /* Try to merge cright and right. */ 10359d720a5aSDarrick J. Wong if (xfs_refc_want_merge_right(&cright, &right, adjust)) { 103631727258SDarrick J. Wong *shape_changed = true; 103731727258SDarrick J. Wong return xfs_refcount_merge_right_extent(cur, &right, &cright, 1038a1f69417SEric Sandeen aglen); 103931727258SDarrick J. Wong } 104031727258SDarrick J. Wong 1041f62ac3e0SDarrick J. Wong return 0; 104231727258SDarrick J. Wong } 104331727258SDarrick J. Wong 104431727258SDarrick J. Wong /* 104531727258SDarrick J. Wong * XXX: This is a pretty hand-wavy estimate. The penalty for guessing 104631727258SDarrick J. Wong * true incorrectly is a shutdown FS; the penalty for guessing false 104731727258SDarrick J. Wong * incorrectly is more transaction rolls than might be necessary. 104831727258SDarrick J. Wong * Be conservative here. 104931727258SDarrick J. Wong */ 105031727258SDarrick J. Wong static bool 105131727258SDarrick J. Wong xfs_refcount_still_have_space( 105231727258SDarrick J. Wong struct xfs_btree_cur *cur) 105331727258SDarrick J. Wong { 105431727258SDarrick J. Wong unsigned long overhead; 105531727258SDarrick J. Wong 1056b037c4eeSDarrick J. Wong /* 1057b037c4eeSDarrick J. Wong * Worst case estimate: full splits of the free space and rmap btrees 1058b037c4eeSDarrick J. Wong * to handle each of the shape changes to the refcount btree. 1059b037c4eeSDarrick J. Wong */ 10606ed7e509SDarrick J. Wong overhead = xfs_allocfree_block_count(cur->bc_mp, 1061b037c4eeSDarrick J. Wong cur->bc_ag.refc.shape_changes); 1062b037c4eeSDarrick J. Wong overhead += cur->bc_mp->m_refc_maxlevels; 106331727258SDarrick J. Wong overhead *= cur->bc_mp->m_sb.sb_blocksize; 106431727258SDarrick J. Wong 106531727258SDarrick J. Wong /* 106631727258SDarrick J. Wong * Only allow 2 refcount extent updates per transaction if the 106731727258SDarrick J. Wong * refcount continue update "error" has been injected. 106831727258SDarrick J. Wong */ 1069c4aa10d0SDave Chinner if (cur->bc_ag.refc.nr_ops > 2 && 107031727258SDarrick J. Wong XFS_TEST_ERROR(false, cur->bc_mp, 10719e24cfd0SDarrick J. Wong XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE)) 107231727258SDarrick J. Wong return false; 107331727258SDarrick J. Wong 1074c4aa10d0SDave Chinner if (cur->bc_ag.refc.nr_ops == 0) 107531727258SDarrick J. Wong return true; 107631727258SDarrick J. Wong else if (overhead > cur->bc_tp->t_log_res) 107731727258SDarrick J. Wong return false; 107831727258SDarrick J. Wong return cur->bc_tp->t_log_res - overhead > 1079c4aa10d0SDave Chinner cur->bc_ag.refc.nr_ops * XFS_REFCOUNT_ITEM_OVERHEAD; 108031727258SDarrick J. Wong } 108131727258SDarrick J. Wong 108231727258SDarrick J. Wong /* 108331727258SDarrick J. Wong * Adjust the refcounts of middle extents. At this point we should have 108431727258SDarrick J. Wong * split extents that crossed the adjustment range; merged with adjacent 108531727258SDarrick J. Wong * extents; and updated agbno/aglen to reflect the merges. Therefore, 108631727258SDarrick J. Wong * all we have to do is update the extents inside [agbno, agbno + aglen]. 108731727258SDarrick J. Wong */ 108831727258SDarrick J. Wong STATIC int 108931727258SDarrick J. Wong xfs_refcount_adjust_extents( 109031727258SDarrick J. Wong struct xfs_btree_cur *cur, 109131727258SDarrick J. Wong xfs_agblock_t *agbno, 109231727258SDarrick J. Wong xfs_extlen_t *aglen, 1093c04c51c5SDarrick J. Wong enum xfs_refc_adjust_op adj) 109431727258SDarrick J. Wong { 109531727258SDarrick J. Wong struct xfs_refcount_irec ext, tmp; 109631727258SDarrick J. Wong int error; 109731727258SDarrick J. Wong int found_rec, found_tmp; 109831727258SDarrick J. Wong xfs_fsblock_t fsbno; 109931727258SDarrick J. Wong 110031727258SDarrick J. Wong /* Merging did all the work already. */ 110131727258SDarrick J. Wong if (*aglen == 0) 110231727258SDarrick J. Wong return 0; 110331727258SDarrick J. Wong 11049a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_ge(cur, XFS_REFC_DOMAIN_SHARED, *agbno, 11059a50ee4fSDarrick J. Wong &found_rec); 110631727258SDarrick J. Wong if (error) 110731727258SDarrick J. Wong goto out_error; 110831727258SDarrick J. Wong 110931727258SDarrick J. Wong while (*aglen > 0 && xfs_refcount_still_have_space(cur)) { 111031727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &ext, &found_rec); 111131727258SDarrick J. Wong if (error) 111231727258SDarrick J. Wong goto out_error; 1113f62ac3e0SDarrick J. Wong if (!found_rec || ext.rc_domain != XFS_REFC_DOMAIN_SHARED) { 111431727258SDarrick J. Wong ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks; 111531727258SDarrick J. Wong ext.rc_blockcount = 0; 111631727258SDarrick J. Wong ext.rc_refcount = 0; 11179a50ee4fSDarrick J. Wong ext.rc_domain = XFS_REFC_DOMAIN_SHARED; 111831727258SDarrick J. Wong } 111931727258SDarrick J. Wong 112031727258SDarrick J. Wong /* 112131727258SDarrick J. Wong * Deal with a hole in the refcount tree; if a file maps to 112231727258SDarrick J. Wong * these blocks and there's no refcountbt record, pretend that 112331727258SDarrick J. Wong * there is one with refcount == 1. 112431727258SDarrick J. Wong */ 112531727258SDarrick J. Wong if (ext.rc_startblock != *agbno) { 112631727258SDarrick J. Wong tmp.rc_startblock = *agbno; 112731727258SDarrick J. Wong tmp.rc_blockcount = min(*aglen, 112831727258SDarrick J. Wong ext.rc_startblock - *agbno); 112931727258SDarrick J. Wong tmp.rc_refcount = 1 + adj; 11309a50ee4fSDarrick J. Wong tmp.rc_domain = XFS_REFC_DOMAIN_SHARED; 11319a50ee4fSDarrick J. Wong 113231727258SDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 113350f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, &tmp); 113431727258SDarrick J. Wong 113531727258SDarrick J. Wong /* 113631727258SDarrick J. Wong * Either cover the hole (increment) or 113731727258SDarrick J. Wong * delete the range (decrement). 113831727258SDarrick J. Wong */ 1139c47260d4SDarrick J. Wong cur->bc_ag.refc.nr_ops++; 114031727258SDarrick J. Wong if (tmp.rc_refcount) { 114131727258SDarrick J. Wong error = xfs_refcount_insert(cur, &tmp, 114231727258SDarrick J. Wong &found_tmp); 114331727258SDarrick J. Wong if (error) 114431727258SDarrick J. Wong goto out_error; 1145f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, 1146f9e03706SDarrick J. Wong found_tmp != 1)) { 1147f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1148f9e03706SDarrick J. Wong goto out_error; 1149f9e03706SDarrick J. Wong } 115031727258SDarrick J. Wong } else { 115131727258SDarrick J. Wong fsbno = XFS_AGB_TO_FSB(cur->bc_mp, 115250f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, 115331727258SDarrick J. Wong tmp.rc_startblock); 1154c201d9caSDarrick J. Wong xfs_free_extent_later(cur->bc_tp, fsbno, 1155c04c51c5SDarrick J. Wong tmp.rc_blockcount, NULL); 115631727258SDarrick J. Wong } 115731727258SDarrick J. Wong 115831727258SDarrick J. Wong (*agbno) += tmp.rc_blockcount; 115931727258SDarrick J. Wong (*aglen) -= tmp.rc_blockcount; 116031727258SDarrick J. Wong 1161f850995fSDarrick J. Wong /* Stop if there's nothing left to modify */ 1162f850995fSDarrick J. Wong if (*aglen == 0 || !xfs_refcount_still_have_space(cur)) 1163f850995fSDarrick J. Wong break; 1164f850995fSDarrick J. Wong 1165f850995fSDarrick J. Wong /* Move the cursor to the start of ext. */ 11669a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_ge(cur, 11679a50ee4fSDarrick J. Wong XFS_REFC_DOMAIN_SHARED, *agbno, 116831727258SDarrick J. Wong &found_rec); 116931727258SDarrick J. Wong if (error) 117031727258SDarrick J. Wong goto out_error; 117131727258SDarrick J. Wong } 117231727258SDarrick J. Wong 1173f850995fSDarrick J. Wong /* 1174f850995fSDarrick J. Wong * A previous step trimmed agbno/aglen such that the end of the 1175f850995fSDarrick J. Wong * range would not be in the middle of the record. If this is 1176f850995fSDarrick J. Wong * no longer the case, something is seriously wrong with the 1177f850995fSDarrick J. Wong * btree. Make sure we never feed the synthesized record into 1178f850995fSDarrick J. Wong * the processing loop below. 1179f850995fSDarrick J. Wong */ 1180f850995fSDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_blockcount == 0) || 1181f850995fSDarrick J. Wong XFS_IS_CORRUPT(cur->bc_mp, ext.rc_blockcount > *aglen)) { 1182f850995fSDarrick J. Wong error = -EFSCORRUPTED; 1183f850995fSDarrick J. Wong goto out_error; 1184f850995fSDarrick J. Wong } 118531727258SDarrick J. Wong 118631727258SDarrick J. Wong /* 118731727258SDarrick J. Wong * Adjust the reference count and either update the tree 118831727258SDarrick J. Wong * (incr) or free the blocks (decr). 118931727258SDarrick J. Wong */ 119031727258SDarrick J. Wong if (ext.rc_refcount == MAXREFCOUNT) 119131727258SDarrick J. Wong goto skip; 119231727258SDarrick J. Wong ext.rc_refcount += adj; 119331727258SDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 119450f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, &ext); 1195c47260d4SDarrick J. Wong cur->bc_ag.refc.nr_ops++; 119631727258SDarrick J. Wong if (ext.rc_refcount > 1) { 119731727258SDarrick J. Wong error = xfs_refcount_update(cur, &ext); 119831727258SDarrick J. Wong if (error) 119931727258SDarrick J. Wong goto out_error; 120031727258SDarrick J. Wong } else if (ext.rc_refcount == 1) { 120131727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 120231727258SDarrick J. Wong if (error) 120331727258SDarrick J. Wong goto out_error; 1204f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 1205f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1206f9e03706SDarrick J. Wong goto out_error; 1207f9e03706SDarrick J. Wong } 120831727258SDarrick J. Wong goto advloop; 120931727258SDarrick J. Wong } else { 121031727258SDarrick J. Wong fsbno = XFS_AGB_TO_FSB(cur->bc_mp, 121150f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, 121231727258SDarrick J. Wong ext.rc_startblock); 1213c04c51c5SDarrick J. Wong xfs_free_extent_later(cur->bc_tp, fsbno, 1214c04c51c5SDarrick J. Wong ext.rc_blockcount, NULL); 121531727258SDarrick J. Wong } 121631727258SDarrick J. Wong 121731727258SDarrick J. Wong skip: 121831727258SDarrick J. Wong error = xfs_btree_increment(cur, 0, &found_rec); 121931727258SDarrick J. Wong if (error) 122031727258SDarrick J. Wong goto out_error; 122131727258SDarrick J. Wong 122231727258SDarrick J. Wong advloop: 122331727258SDarrick J. Wong (*agbno) += ext.rc_blockcount; 122431727258SDarrick J. Wong (*aglen) -= ext.rc_blockcount; 122531727258SDarrick J. Wong } 122631727258SDarrick J. Wong 122731727258SDarrick J. Wong return error; 122831727258SDarrick J. Wong out_error: 122931727258SDarrick J. Wong trace_xfs_refcount_modify_extent_error(cur->bc_mp, 123050f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 123131727258SDarrick J. Wong return error; 123231727258SDarrick J. Wong } 123331727258SDarrick J. Wong 123431727258SDarrick J. Wong /* Adjust the reference count of a range of AG blocks. */ 123531727258SDarrick J. Wong STATIC int 123631727258SDarrick J. Wong xfs_refcount_adjust( 123731727258SDarrick J. Wong struct xfs_btree_cur *cur, 12380b11553eSDarrick J. Wong xfs_agblock_t *agbno, 12390b11553eSDarrick J. Wong xfs_extlen_t *aglen, 1240c04c51c5SDarrick J. Wong enum xfs_refc_adjust_op adj) 124131727258SDarrick J. Wong { 124231727258SDarrick J. Wong bool shape_changed; 124331727258SDarrick J. Wong int shape_changes = 0; 124431727258SDarrick J. Wong int error; 124531727258SDarrick J. Wong 124631727258SDarrick J. Wong if (adj == XFS_REFCOUNT_ADJUST_INCREASE) 12470b11553eSDarrick J. Wong trace_xfs_refcount_increase(cur->bc_mp, 12480b11553eSDarrick J. Wong cur->bc_ag.pag->pag_agno, *agbno, *aglen); 124931727258SDarrick J. Wong else 12500b11553eSDarrick J. Wong trace_xfs_refcount_decrease(cur->bc_mp, 12510b11553eSDarrick J. Wong cur->bc_ag.pag->pag_agno, *agbno, *aglen); 125231727258SDarrick J. Wong 125331727258SDarrick J. Wong /* 125431727258SDarrick J. Wong * Ensure that no rcextents cross the boundary of the adjustment range. 125531727258SDarrick J. Wong */ 12569a50ee4fSDarrick J. Wong error = xfs_refcount_split_extent(cur, XFS_REFC_DOMAIN_SHARED, 12570b11553eSDarrick J. Wong *agbno, &shape_changed); 125831727258SDarrick J. Wong if (error) 125931727258SDarrick J. Wong goto out_error; 126031727258SDarrick J. Wong if (shape_changed) 126131727258SDarrick J. Wong shape_changes++; 126231727258SDarrick J. Wong 12639a50ee4fSDarrick J. Wong error = xfs_refcount_split_extent(cur, XFS_REFC_DOMAIN_SHARED, 12640b11553eSDarrick J. Wong *agbno + *aglen, &shape_changed); 126531727258SDarrick J. Wong if (error) 126631727258SDarrick J. Wong goto out_error; 126731727258SDarrick J. Wong if (shape_changed) 126831727258SDarrick J. Wong shape_changes++; 126931727258SDarrick J. Wong 127031727258SDarrick J. Wong /* 127131727258SDarrick J. Wong * Try to merge with the left or right extents of the range. 127231727258SDarrick J. Wong */ 127368d0f389SDarrick J. Wong error = xfs_refcount_merge_extents(cur, XFS_REFC_DOMAIN_SHARED, 12740b11553eSDarrick J. Wong agbno, aglen, adj, &shape_changed); 127531727258SDarrick J. Wong if (error) 127631727258SDarrick J. Wong goto out_error; 127731727258SDarrick J. Wong if (shape_changed) 127831727258SDarrick J. Wong shape_changes++; 127931727258SDarrick J. Wong if (shape_changes) 1280c4aa10d0SDave Chinner cur->bc_ag.refc.shape_changes++; 128131727258SDarrick J. Wong 128231727258SDarrick J. Wong /* Now that we've taken care of the ends, adjust the middle extents */ 12830b11553eSDarrick J. Wong error = xfs_refcount_adjust_extents(cur, agbno, aglen, adj); 128431727258SDarrick J. Wong if (error) 128531727258SDarrick J. Wong goto out_error; 128631727258SDarrick J. Wong 128731727258SDarrick J. Wong return 0; 128831727258SDarrick J. Wong 128931727258SDarrick J. Wong out_error: 129050f02fe3SDave Chinner trace_xfs_refcount_adjust_error(cur->bc_mp, cur->bc_ag.pag->pag_agno, 129131727258SDarrick J. Wong error, _RET_IP_); 129231727258SDarrick J. Wong return error; 129331727258SDarrick J. Wong } 129433ba6129SDarrick J. Wong 129533ba6129SDarrick J. Wong /* Clean up after calling xfs_refcount_finish_one. */ 129633ba6129SDarrick J. Wong void 129733ba6129SDarrick J. Wong xfs_refcount_finish_one_cleanup( 129833ba6129SDarrick J. Wong struct xfs_trans *tp, 129933ba6129SDarrick J. Wong struct xfs_btree_cur *rcur, 130033ba6129SDarrick J. Wong int error) 130133ba6129SDarrick J. Wong { 130233ba6129SDarrick J. Wong struct xfs_buf *agbp; 130333ba6129SDarrick J. Wong 130433ba6129SDarrick J. Wong if (rcur == NULL) 130533ba6129SDarrick J. Wong return; 1306576af732SDave Chinner agbp = rcur->bc_ag.agbp; 13070b04b6b8SDarrick J. Wong xfs_btree_del_cursor(rcur, error); 130833ba6129SDarrick J. Wong if (error) 130933ba6129SDarrick J. Wong xfs_trans_brelse(tp, agbp); 131033ba6129SDarrick J. Wong } 131133ba6129SDarrick J. Wong 131233ba6129SDarrick J. Wong /* 13138edbe0cfSDarrick J. Wong * Set up a continuation a deferred refcount operation by updating the intent. 13148edbe0cfSDarrick J. Wong * Checks to make sure we're not going to run off the end of the AG. 13158edbe0cfSDarrick J. Wong */ 13168edbe0cfSDarrick J. Wong static inline int 13178edbe0cfSDarrick J. Wong xfs_refcount_continue_op( 13188edbe0cfSDarrick J. Wong struct xfs_btree_cur *cur, 13190b11553eSDarrick J. Wong struct xfs_refcount_intent *ri, 13200b11553eSDarrick J. Wong xfs_agblock_t new_agbno) 13218edbe0cfSDarrick J. Wong { 13228edbe0cfSDarrick J. Wong struct xfs_mount *mp = cur->bc_mp; 13238edbe0cfSDarrick J. Wong struct xfs_perag *pag = cur->bc_ag.pag; 13248edbe0cfSDarrick J. Wong 13250b11553eSDarrick J. Wong if (XFS_IS_CORRUPT(mp, !xfs_verify_agbext(pag, new_agbno, 13260b11553eSDarrick J. Wong ri->ri_blockcount))) 13278edbe0cfSDarrick J. Wong return -EFSCORRUPTED; 13288edbe0cfSDarrick J. Wong 13290b11553eSDarrick J. Wong ri->ri_startblock = XFS_AGB_TO_FSB(mp, pag->pag_agno, new_agbno); 13308edbe0cfSDarrick J. Wong 13310b11553eSDarrick J. Wong ASSERT(xfs_verify_fsbext(mp, ri->ri_startblock, ri->ri_blockcount)); 13320b11553eSDarrick J. Wong ASSERT(pag->pag_agno == XFS_FSB_TO_AGNO(mp, ri->ri_startblock)); 13338edbe0cfSDarrick J. Wong 13348edbe0cfSDarrick J. Wong return 0; 13358edbe0cfSDarrick J. Wong } 13368edbe0cfSDarrick J. Wong 13378edbe0cfSDarrick J. Wong /* 133833ba6129SDarrick J. Wong * Process one of the deferred refcount operations. We pass back the 133933ba6129SDarrick J. Wong * btree cursor to maintain our lock on the btree between calls. 134033ba6129SDarrick J. Wong * This saves time and eliminates a buffer deadlock between the 134133ba6129SDarrick J. Wong * superblock and the AGF because we'll always grab them in the same 134233ba6129SDarrick J. Wong * order. 134333ba6129SDarrick J. Wong */ 134433ba6129SDarrick J. Wong int 134533ba6129SDarrick J. Wong xfs_refcount_finish_one( 134633ba6129SDarrick J. Wong struct xfs_trans *tp, 13470b11553eSDarrick J. Wong struct xfs_refcount_intent *ri, 134833ba6129SDarrick J. Wong struct xfs_btree_cur **pcur) 134933ba6129SDarrick J. Wong { 135033ba6129SDarrick J. Wong struct xfs_mount *mp = tp->t_mountp; 135133ba6129SDarrick J. Wong struct xfs_btree_cur *rcur; 135233ba6129SDarrick J. Wong struct xfs_buf *agbp = NULL; 135333ba6129SDarrick J. Wong int error = 0; 135433ba6129SDarrick J. Wong xfs_agblock_t bno; 135533ba6129SDarrick J. Wong unsigned long nr_ops = 0; 135633ba6129SDarrick J. Wong int shape_changes = 0; 135733ba6129SDarrick J. Wong 13580b11553eSDarrick J. Wong bno = XFS_FSB_TO_AGBNO(mp, ri->ri_startblock); 135933ba6129SDarrick J. Wong 13600b11553eSDarrick J. Wong trace_xfs_refcount_deferred(mp, XFS_FSB_TO_AGNO(mp, ri->ri_startblock), 13610b11553eSDarrick J. Wong ri->ri_type, XFS_FSB_TO_AGBNO(mp, ri->ri_startblock), 13620b11553eSDarrick J. Wong ri->ri_blockcount); 136333ba6129SDarrick J. Wong 136400e7b3baSDarrick J. Wong if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_REFCOUNT_FINISH_ONE)) 136500e7b3baSDarrick J. Wong return -EIO; 136633ba6129SDarrick J. Wong 136733ba6129SDarrick J. Wong /* 136833ba6129SDarrick J. Wong * If we haven't gotten a cursor or the cursor AG doesn't match 136933ba6129SDarrick J. Wong * the startblock, get one now. 137033ba6129SDarrick J. Wong */ 137133ba6129SDarrick J. Wong rcur = *pcur; 137200e7b3baSDarrick J. Wong if (rcur != NULL && rcur->bc_ag.pag != ri->ri_pag) { 1373c4aa10d0SDave Chinner nr_ops = rcur->bc_ag.refc.nr_ops; 1374c4aa10d0SDave Chinner shape_changes = rcur->bc_ag.refc.shape_changes; 137533ba6129SDarrick J. Wong xfs_refcount_finish_one_cleanup(tp, rcur, 0); 137633ba6129SDarrick J. Wong rcur = NULL; 137733ba6129SDarrick J. Wong *pcur = NULL; 137833ba6129SDarrick J. Wong } 137933ba6129SDarrick J. Wong if (rcur == NULL) { 138000e7b3baSDarrick J. Wong error = xfs_alloc_read_agf(ri->ri_pag, tp, 138100e7b3baSDarrick J. Wong XFS_ALLOC_FLAG_FREEING, &agbp); 138233ba6129SDarrick J. Wong if (error) 138300e7b3baSDarrick J. Wong return error; 138433ba6129SDarrick J. Wong 138500e7b3baSDarrick J. Wong rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, ri->ri_pag); 1386c4aa10d0SDave Chinner rcur->bc_ag.refc.nr_ops = nr_ops; 1387c4aa10d0SDave Chinner rcur->bc_ag.refc.shape_changes = shape_changes; 138833ba6129SDarrick J. Wong } 138933ba6129SDarrick J. Wong *pcur = rcur; 139033ba6129SDarrick J. Wong 13910b11553eSDarrick J. Wong switch (ri->ri_type) { 139233ba6129SDarrick J. Wong case XFS_REFCOUNT_INCREASE: 13930b11553eSDarrick J. Wong error = xfs_refcount_adjust(rcur, &bno, &ri->ri_blockcount, 13940b11553eSDarrick J. Wong XFS_REFCOUNT_ADJUST_INCREASE); 13958edbe0cfSDarrick J. Wong if (error) 139600e7b3baSDarrick J. Wong return error; 13970b11553eSDarrick J. Wong if (ri->ri_blockcount > 0) 13980b11553eSDarrick J. Wong error = xfs_refcount_continue_op(rcur, ri, bno); 139933ba6129SDarrick J. Wong break; 140033ba6129SDarrick J. Wong case XFS_REFCOUNT_DECREASE: 14010b11553eSDarrick J. Wong error = xfs_refcount_adjust(rcur, &bno, &ri->ri_blockcount, 14020b11553eSDarrick J. Wong XFS_REFCOUNT_ADJUST_DECREASE); 14038edbe0cfSDarrick J. Wong if (error) 140400e7b3baSDarrick J. Wong return error; 14050b11553eSDarrick J. Wong if (ri->ri_blockcount > 0) 14060b11553eSDarrick J. Wong error = xfs_refcount_continue_op(rcur, ri, bno); 140733ba6129SDarrick J. Wong break; 1408174edb0eSDarrick J. Wong case XFS_REFCOUNT_ALLOC_COW: 14090b11553eSDarrick J. Wong error = __xfs_refcount_cow_alloc(rcur, bno, ri->ri_blockcount); 14100b11553eSDarrick J. Wong if (error) 141100e7b3baSDarrick J. Wong return error; 14120b11553eSDarrick J. Wong ri->ri_blockcount = 0; 1413174edb0eSDarrick J. Wong break; 1414174edb0eSDarrick J. Wong case XFS_REFCOUNT_FREE_COW: 14150b11553eSDarrick J. Wong error = __xfs_refcount_cow_free(rcur, bno, ri->ri_blockcount); 14160b11553eSDarrick J. Wong if (error) 141700e7b3baSDarrick J. Wong return error; 14180b11553eSDarrick J. Wong ri->ri_blockcount = 0; 1419174edb0eSDarrick J. Wong break; 142033ba6129SDarrick J. Wong default: 142133ba6129SDarrick J. Wong ASSERT(0); 142200e7b3baSDarrick J. Wong return -EFSCORRUPTED; 142333ba6129SDarrick J. Wong } 14240b11553eSDarrick J. Wong if (!error && ri->ri_blockcount > 0) 142500e7b3baSDarrick J. Wong trace_xfs_refcount_finish_one_leftover(mp, ri->ri_pag->pag_agno, 14260b11553eSDarrick J. Wong ri->ri_type, bno, ri->ri_blockcount); 142733ba6129SDarrick J. Wong return error; 142833ba6129SDarrick J. Wong } 142933ba6129SDarrick J. Wong 143033ba6129SDarrick J. Wong /* 143133ba6129SDarrick J. Wong * Record a refcount intent for later processing. 143233ba6129SDarrick J. Wong */ 143374b4c5d4SDarrick J. Wong static void 143433ba6129SDarrick J. Wong __xfs_refcount_add( 14350f37d178SBrian Foster struct xfs_trans *tp, 143633ba6129SDarrick J. Wong enum xfs_refcount_intent_type type, 143733ba6129SDarrick J. Wong xfs_fsblock_t startblock, 143833ba6129SDarrick J. Wong xfs_extlen_t blockcount) 143933ba6129SDarrick J. Wong { 144033ba6129SDarrick J. Wong struct xfs_refcount_intent *ri; 144133ba6129SDarrick J. Wong 14420f37d178SBrian Foster trace_xfs_refcount_defer(tp->t_mountp, 14430f37d178SBrian Foster XFS_FSB_TO_AGNO(tp->t_mountp, startblock), 14440f37d178SBrian Foster type, XFS_FSB_TO_AGBNO(tp->t_mountp, startblock), 144533ba6129SDarrick J. Wong blockcount); 144633ba6129SDarrick J. Wong 1447f3c799c2SDarrick J. Wong ri = kmem_cache_alloc(xfs_refcount_intent_cache, 1448f3c799c2SDarrick J. Wong GFP_NOFS | __GFP_NOFAIL); 144933ba6129SDarrick J. Wong INIT_LIST_HEAD(&ri->ri_list); 145033ba6129SDarrick J. Wong ri->ri_type = type; 145133ba6129SDarrick J. Wong ri->ri_startblock = startblock; 145233ba6129SDarrick J. Wong ri->ri_blockcount = blockcount; 145333ba6129SDarrick J. Wong 145400e7b3baSDarrick J. Wong xfs_refcount_update_get_group(tp->t_mountp, ri); 14550f37d178SBrian Foster xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_REFCOUNT, &ri->ri_list); 145633ba6129SDarrick J. Wong } 145733ba6129SDarrick J. Wong 145833ba6129SDarrick J. Wong /* 145933ba6129SDarrick J. Wong * Increase the reference count of the blocks backing a file's extent. 146033ba6129SDarrick J. Wong */ 146174b4c5d4SDarrick J. Wong void 146233ba6129SDarrick J. Wong xfs_refcount_increase_extent( 14630f37d178SBrian Foster struct xfs_trans *tp, 146433ba6129SDarrick J. Wong struct xfs_bmbt_irec *PREV) 146533ba6129SDarrick J. Wong { 1466ebd9027dSDave Chinner if (!xfs_has_reflink(tp->t_mountp)) 146774b4c5d4SDarrick J. Wong return; 146833ba6129SDarrick J. Wong 146974b4c5d4SDarrick J. Wong __xfs_refcount_add(tp, XFS_REFCOUNT_INCREASE, PREV->br_startblock, 147074b4c5d4SDarrick J. Wong PREV->br_blockcount); 147133ba6129SDarrick J. Wong } 147233ba6129SDarrick J. Wong 147333ba6129SDarrick J. Wong /* 147433ba6129SDarrick J. Wong * Decrease the reference count of the blocks backing a file's extent. 147533ba6129SDarrick J. Wong */ 147674b4c5d4SDarrick J. Wong void 147733ba6129SDarrick J. Wong xfs_refcount_decrease_extent( 14780f37d178SBrian Foster struct xfs_trans *tp, 147933ba6129SDarrick J. Wong struct xfs_bmbt_irec *PREV) 148033ba6129SDarrick J. Wong { 1481ebd9027dSDave Chinner if (!xfs_has_reflink(tp->t_mountp)) 148274b4c5d4SDarrick J. Wong return; 148333ba6129SDarrick J. Wong 148474b4c5d4SDarrick J. Wong __xfs_refcount_add(tp, XFS_REFCOUNT_DECREASE, PREV->br_startblock, 148574b4c5d4SDarrick J. Wong PREV->br_blockcount); 148633ba6129SDarrick J. Wong } 1487350a27a6SDarrick J. Wong 1488350a27a6SDarrick J. Wong /* 1489350a27a6SDarrick J. Wong * Given an AG extent, find the lowest-numbered run of shared blocks 1490350a27a6SDarrick J. Wong * within that range and return the range in fbno/flen. If 1491350a27a6SDarrick J. Wong * find_end_of_shared is set, return the longest contiguous extent of 1492350a27a6SDarrick J. Wong * shared blocks; if not, just return the first extent we find. If no 1493350a27a6SDarrick J. Wong * shared blocks are found, fbno and flen will be set to NULLAGBLOCK 1494350a27a6SDarrick J. Wong * and 0, respectively. 1495350a27a6SDarrick J. Wong */ 1496350a27a6SDarrick J. Wong int 1497350a27a6SDarrick J. Wong xfs_refcount_find_shared( 1498350a27a6SDarrick J. Wong struct xfs_btree_cur *cur, 1499350a27a6SDarrick J. Wong xfs_agblock_t agbno, 1500350a27a6SDarrick J. Wong xfs_extlen_t aglen, 1501350a27a6SDarrick J. Wong xfs_agblock_t *fbno, 1502350a27a6SDarrick J. Wong xfs_extlen_t *flen, 1503350a27a6SDarrick J. Wong bool find_end_of_shared) 1504350a27a6SDarrick J. Wong { 1505350a27a6SDarrick J. Wong struct xfs_refcount_irec tmp; 1506350a27a6SDarrick J. Wong int i; 1507350a27a6SDarrick J. Wong int have; 1508350a27a6SDarrick J. Wong int error; 1509350a27a6SDarrick J. Wong 151050f02fe3SDave Chinner trace_xfs_refcount_find_shared(cur->bc_mp, cur->bc_ag.pag->pag_agno, 1511350a27a6SDarrick J. Wong agbno, aglen); 1512350a27a6SDarrick J. Wong 1513350a27a6SDarrick J. Wong /* By default, skip the whole range */ 1514350a27a6SDarrick J. Wong *fbno = NULLAGBLOCK; 1515350a27a6SDarrick J. Wong *flen = 0; 1516350a27a6SDarrick J. Wong 1517350a27a6SDarrick J. Wong /* Try to find a refcount extent that crosses the start */ 15189a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_le(cur, XFS_REFC_DOMAIN_SHARED, agbno, 15199a50ee4fSDarrick J. Wong &have); 1520350a27a6SDarrick J. Wong if (error) 1521350a27a6SDarrick J. Wong goto out_error; 1522350a27a6SDarrick J. Wong if (!have) { 1523350a27a6SDarrick J. Wong /* No left extent, look at the next one */ 1524350a27a6SDarrick J. Wong error = xfs_btree_increment(cur, 0, &have); 1525350a27a6SDarrick J. Wong if (error) 1526350a27a6SDarrick J. Wong goto out_error; 1527350a27a6SDarrick J. Wong if (!have) 1528350a27a6SDarrick J. Wong goto done; 1529350a27a6SDarrick J. Wong } 1530350a27a6SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &i); 1531350a27a6SDarrick J. Wong if (error) 1532350a27a6SDarrick J. Wong goto out_error; 1533f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) { 1534f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1535f9e03706SDarrick J. Wong goto out_error; 1536f9e03706SDarrick J. Wong } 1537f62ac3e0SDarrick J. Wong if (tmp.rc_domain != XFS_REFC_DOMAIN_SHARED) 1538f62ac3e0SDarrick J. Wong goto done; 1539350a27a6SDarrick J. Wong 1540350a27a6SDarrick J. Wong /* If the extent ends before the start, look at the next one */ 1541350a27a6SDarrick J. Wong if (tmp.rc_startblock + tmp.rc_blockcount <= agbno) { 1542350a27a6SDarrick J. Wong error = xfs_btree_increment(cur, 0, &have); 1543350a27a6SDarrick J. Wong if (error) 1544350a27a6SDarrick J. Wong goto out_error; 1545350a27a6SDarrick J. Wong if (!have) 1546350a27a6SDarrick J. Wong goto done; 1547350a27a6SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &i); 1548350a27a6SDarrick J. Wong if (error) 1549350a27a6SDarrick J. Wong goto out_error; 1550f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) { 1551f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1552f9e03706SDarrick J. Wong goto out_error; 1553f9e03706SDarrick J. Wong } 1554f62ac3e0SDarrick J. Wong if (tmp.rc_domain != XFS_REFC_DOMAIN_SHARED) 1555f62ac3e0SDarrick J. Wong goto done; 1556350a27a6SDarrick J. Wong } 1557350a27a6SDarrick J. Wong 1558350a27a6SDarrick J. Wong /* If the extent starts after the range we want, bail out */ 1559350a27a6SDarrick J. Wong if (tmp.rc_startblock >= agbno + aglen) 1560350a27a6SDarrick J. Wong goto done; 1561350a27a6SDarrick J. Wong 1562350a27a6SDarrick J. Wong /* We found the start of a shared extent! */ 1563350a27a6SDarrick J. Wong if (tmp.rc_startblock < agbno) { 1564350a27a6SDarrick J. Wong tmp.rc_blockcount -= (agbno - tmp.rc_startblock); 1565350a27a6SDarrick J. Wong tmp.rc_startblock = agbno; 1566350a27a6SDarrick J. Wong } 1567350a27a6SDarrick J. Wong 1568350a27a6SDarrick J. Wong *fbno = tmp.rc_startblock; 1569350a27a6SDarrick J. Wong *flen = min(tmp.rc_blockcount, agbno + aglen - *fbno); 1570350a27a6SDarrick J. Wong if (!find_end_of_shared) 1571350a27a6SDarrick J. Wong goto done; 1572350a27a6SDarrick J. Wong 1573350a27a6SDarrick J. Wong /* Otherwise, find the end of this shared extent */ 1574350a27a6SDarrick J. Wong while (*fbno + *flen < agbno + aglen) { 1575350a27a6SDarrick J. Wong error = xfs_btree_increment(cur, 0, &have); 1576350a27a6SDarrick J. Wong if (error) 1577350a27a6SDarrick J. Wong goto out_error; 1578350a27a6SDarrick J. Wong if (!have) 1579350a27a6SDarrick J. Wong break; 1580350a27a6SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &i); 1581350a27a6SDarrick J. Wong if (error) 1582350a27a6SDarrick J. Wong goto out_error; 1583f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) { 1584f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1585f9e03706SDarrick J. Wong goto out_error; 1586f9e03706SDarrick J. Wong } 1587f62ac3e0SDarrick J. Wong if (tmp.rc_domain != XFS_REFC_DOMAIN_SHARED || 1588f62ac3e0SDarrick J. Wong tmp.rc_startblock >= agbno + aglen || 1589350a27a6SDarrick J. Wong tmp.rc_startblock != *fbno + *flen) 1590350a27a6SDarrick J. Wong break; 1591350a27a6SDarrick J. Wong *flen = min(*flen + tmp.rc_blockcount, agbno + aglen - *fbno); 1592350a27a6SDarrick J. Wong } 1593350a27a6SDarrick J. Wong 1594350a27a6SDarrick J. Wong done: 1595350a27a6SDarrick J. Wong trace_xfs_refcount_find_shared_result(cur->bc_mp, 159650f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, *fbno, *flen); 1597350a27a6SDarrick J. Wong 1598350a27a6SDarrick J. Wong out_error: 1599350a27a6SDarrick J. Wong if (error) 1600350a27a6SDarrick J. Wong trace_xfs_refcount_find_shared_error(cur->bc_mp, 160150f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 1602350a27a6SDarrick J. Wong return error; 1603350a27a6SDarrick J. Wong } 1604174edb0eSDarrick J. Wong 1605174edb0eSDarrick J. Wong /* 1606174edb0eSDarrick J. Wong * Recovering CoW Blocks After a Crash 1607174edb0eSDarrick J. Wong * 1608174edb0eSDarrick J. Wong * Due to the way that the copy on write mechanism works, there's a window of 1609174edb0eSDarrick J. Wong * opportunity in which we can lose track of allocated blocks during a crash. 1610174edb0eSDarrick J. Wong * Because CoW uses delayed allocation in the in-core CoW fork, writeback 1611174edb0eSDarrick J. Wong * causes blocks to be allocated and stored in the CoW fork. The blocks are 1612174edb0eSDarrick J. Wong * no longer in the free space btree but are not otherwise recorded anywhere 1613174edb0eSDarrick J. Wong * until the write completes and the blocks are mapped into the file. A crash 1614174edb0eSDarrick J. Wong * in between allocation and remapping results in the replacement blocks being 1615174edb0eSDarrick J. Wong * lost. This situation is exacerbated by the CoW extent size hint because 1616174edb0eSDarrick J. Wong * allocations can hang around for long time. 1617174edb0eSDarrick J. Wong * 1618174edb0eSDarrick J. Wong * However, there is a place where we can record these allocations before they 1619174edb0eSDarrick J. Wong * become mappings -- the reference count btree. The btree does not record 1620174edb0eSDarrick J. Wong * extents with refcount == 1, so we can record allocations with a refcount of 1621174edb0eSDarrick J. Wong * 1. Blocks being used for CoW writeout cannot be shared, so there should be 1622174edb0eSDarrick J. Wong * no conflict with shared block records. These mappings should be created 1623174edb0eSDarrick J. Wong * when we allocate blocks to the CoW fork and deleted when they're removed 1624174edb0eSDarrick J. Wong * from the CoW fork. 1625174edb0eSDarrick J. Wong * 1626174edb0eSDarrick J. Wong * Minor nit: records for in-progress CoW allocations and records for shared 1627174edb0eSDarrick J. Wong * extents must never be merged, to preserve the property that (except for CoW 1628174edb0eSDarrick J. Wong * allocations) there are no refcount btree entries with refcount == 1. The 1629174edb0eSDarrick J. Wong * only time this could potentially happen is when unsharing a block that's 1630174edb0eSDarrick J. Wong * adjacent to CoW allocations, so we must be careful to avoid this. 1631174edb0eSDarrick J. Wong * 1632174edb0eSDarrick J. Wong * At mount time we recover lost CoW allocations by searching the refcount 1633174edb0eSDarrick J. Wong * btree for these refcount == 1 mappings. These represent CoW allocations 1634174edb0eSDarrick J. Wong * that were in progress at the time the filesystem went down, so we can free 1635174edb0eSDarrick J. Wong * them to get the space back. 1636174edb0eSDarrick J. Wong * 1637174edb0eSDarrick J. Wong * This mechanism is superior to creating EFIs for unmapped CoW extents for 1638174edb0eSDarrick J. Wong * several reasons -- first, EFIs pin the tail of the log and would have to be 1639174edb0eSDarrick J. Wong * periodically relogged to avoid filling up the log. Second, CoW completions 1640174edb0eSDarrick J. Wong * will have to file an EFD and create new EFIs for whatever remains in the 1641174edb0eSDarrick J. Wong * CoW fork; this partially takes care of (1) but extent-size reservations 1642174edb0eSDarrick J. Wong * will have to periodically relog even if there's no writeout in progress. 1643174edb0eSDarrick J. Wong * This can happen if the CoW extent size hint is set, which you really want. 1644174edb0eSDarrick J. Wong * Third, EFIs cannot currently be automatically relogged into newer 1645174edb0eSDarrick J. Wong * transactions to advance the log tail. Fourth, stuffing the log full of 1646174edb0eSDarrick J. Wong * EFIs places an upper bound on the number of CoW allocations that can be 1647174edb0eSDarrick J. Wong * held filesystem-wide at any given time. Recording them in the refcount 1648174edb0eSDarrick J. Wong * btree doesn't require us to maintain any state in memory and doesn't pin 1649174edb0eSDarrick J. Wong * the log. 1650174edb0eSDarrick J. Wong */ 1651174edb0eSDarrick J. Wong /* 1652174edb0eSDarrick J. Wong * Adjust the refcounts of CoW allocations. These allocations are "magic" 1653174edb0eSDarrick J. Wong * in that they're not referenced anywhere else in the filesystem, so we 1654174edb0eSDarrick J. Wong * stash them in the refcount btree with a refcount of 1 until either file 1655174edb0eSDarrick J. Wong * remapping (or CoW cancellation) happens. 1656174edb0eSDarrick J. Wong */ 1657174edb0eSDarrick J. Wong STATIC int 1658174edb0eSDarrick J. Wong xfs_refcount_adjust_cow_extents( 1659174edb0eSDarrick J. Wong struct xfs_btree_cur *cur, 1660174edb0eSDarrick J. Wong xfs_agblock_t agbno, 1661174edb0eSDarrick J. Wong xfs_extlen_t aglen, 1662a1f69417SEric Sandeen enum xfs_refc_adjust_op adj) 1663174edb0eSDarrick J. Wong { 1664174edb0eSDarrick J. Wong struct xfs_refcount_irec ext, tmp; 1665174edb0eSDarrick J. Wong int error; 1666174edb0eSDarrick J. Wong int found_rec, found_tmp; 1667174edb0eSDarrick J. Wong 1668174edb0eSDarrick J. Wong if (aglen == 0) 1669174edb0eSDarrick J. Wong return 0; 1670174edb0eSDarrick J. Wong 1671174edb0eSDarrick J. Wong /* Find any overlapping refcount records */ 16729a50ee4fSDarrick J. Wong error = xfs_refcount_lookup_ge(cur, XFS_REFC_DOMAIN_COW, agbno, 16739a50ee4fSDarrick J. Wong &found_rec); 1674174edb0eSDarrick J. Wong if (error) 1675174edb0eSDarrick J. Wong goto out_error; 1676174edb0eSDarrick J. Wong error = xfs_refcount_get_rec(cur, &ext, &found_rec); 1677174edb0eSDarrick J. Wong if (error) 1678174edb0eSDarrick J. Wong goto out_error; 1679f62ac3e0SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec && 1680f62ac3e0SDarrick J. Wong ext.rc_domain != XFS_REFC_DOMAIN_COW)) { 1681f62ac3e0SDarrick J. Wong error = -EFSCORRUPTED; 1682f62ac3e0SDarrick J. Wong goto out_error; 1683f62ac3e0SDarrick J. Wong } 1684174edb0eSDarrick J. Wong if (!found_rec) { 16859a50ee4fSDarrick J. Wong ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks; 1686174edb0eSDarrick J. Wong ext.rc_blockcount = 0; 1687174edb0eSDarrick J. Wong ext.rc_refcount = 0; 16889a50ee4fSDarrick J. Wong ext.rc_domain = XFS_REFC_DOMAIN_COW; 1689174edb0eSDarrick J. Wong } 1690174edb0eSDarrick J. Wong 1691174edb0eSDarrick J. Wong switch (adj) { 1692174edb0eSDarrick J. Wong case XFS_REFCOUNT_ADJUST_COW_ALLOC: 1693174edb0eSDarrick J. Wong /* Adding a CoW reservation, there should be nothing here. */ 1694f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, 1695f9e03706SDarrick J. Wong agbno + aglen > ext.rc_startblock)) { 1696f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1697f9e03706SDarrick J. Wong goto out_error; 1698f9e03706SDarrick J. Wong } 1699174edb0eSDarrick J. Wong 1700174edb0eSDarrick J. Wong tmp.rc_startblock = agbno; 1701174edb0eSDarrick J. Wong tmp.rc_blockcount = aglen; 1702174edb0eSDarrick J. Wong tmp.rc_refcount = 1; 17039a50ee4fSDarrick J. Wong tmp.rc_domain = XFS_REFC_DOMAIN_COW; 17049a50ee4fSDarrick J. Wong 1705174edb0eSDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 170650f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, &tmp); 1707174edb0eSDarrick J. Wong 1708174edb0eSDarrick J. Wong error = xfs_refcount_insert(cur, &tmp, 1709174edb0eSDarrick J. Wong &found_tmp); 1710174edb0eSDarrick J. Wong if (error) 1711174edb0eSDarrick J. Wong goto out_error; 1712f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_tmp != 1)) { 1713f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1714f9e03706SDarrick J. Wong goto out_error; 1715f9e03706SDarrick J. Wong } 1716174edb0eSDarrick J. Wong break; 1717174edb0eSDarrick J. Wong case XFS_REFCOUNT_ADJUST_COW_FREE: 1718174edb0eSDarrick J. Wong /* Removing a CoW reservation, there should be one extent. */ 1719f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_startblock != agbno)) { 1720f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1721f9e03706SDarrick J. Wong goto out_error; 1722f9e03706SDarrick J. Wong } 1723f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_blockcount != aglen)) { 1724f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1725f9e03706SDarrick J. Wong goto out_error; 1726f9e03706SDarrick J. Wong } 1727f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_refcount != 1)) { 1728f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1729f9e03706SDarrick J. Wong goto out_error; 1730f9e03706SDarrick J. Wong } 1731174edb0eSDarrick J. Wong 1732174edb0eSDarrick J. Wong ext.rc_refcount = 0; 1733174edb0eSDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 173450f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, &ext); 1735174edb0eSDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 1736174edb0eSDarrick J. Wong if (error) 1737174edb0eSDarrick J. Wong goto out_error; 1738f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 1739f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1740f9e03706SDarrick J. Wong goto out_error; 1741f9e03706SDarrick J. Wong } 1742174edb0eSDarrick J. Wong break; 1743174edb0eSDarrick J. Wong default: 1744174edb0eSDarrick J. Wong ASSERT(0); 1745174edb0eSDarrick J. Wong } 1746174edb0eSDarrick J. Wong 1747174edb0eSDarrick J. Wong return error; 1748174edb0eSDarrick J. Wong out_error: 1749174edb0eSDarrick J. Wong trace_xfs_refcount_modify_extent_error(cur->bc_mp, 175050f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 1751174edb0eSDarrick J. Wong return error; 1752174edb0eSDarrick J. Wong } 1753174edb0eSDarrick J. Wong 1754174edb0eSDarrick J. Wong /* 1755174edb0eSDarrick J. Wong * Add or remove refcount btree entries for CoW reservations. 1756174edb0eSDarrick J. Wong */ 1757174edb0eSDarrick J. Wong STATIC int 1758174edb0eSDarrick J. Wong xfs_refcount_adjust_cow( 1759174edb0eSDarrick J. Wong struct xfs_btree_cur *cur, 1760174edb0eSDarrick J. Wong xfs_agblock_t agbno, 1761174edb0eSDarrick J. Wong xfs_extlen_t aglen, 1762a1f69417SEric Sandeen enum xfs_refc_adjust_op adj) 1763174edb0eSDarrick J. Wong { 1764174edb0eSDarrick J. Wong bool shape_changed; 1765174edb0eSDarrick J. Wong int error; 1766174edb0eSDarrick J. Wong 1767174edb0eSDarrick J. Wong /* 1768174edb0eSDarrick J. Wong * Ensure that no rcextents cross the boundary of the adjustment range. 1769174edb0eSDarrick J. Wong */ 17709a50ee4fSDarrick J. Wong error = xfs_refcount_split_extent(cur, XFS_REFC_DOMAIN_COW, 17719a50ee4fSDarrick J. Wong agbno, &shape_changed); 1772174edb0eSDarrick J. Wong if (error) 1773174edb0eSDarrick J. Wong goto out_error; 1774174edb0eSDarrick J. Wong 17759a50ee4fSDarrick J. Wong error = xfs_refcount_split_extent(cur, XFS_REFC_DOMAIN_COW, 17769a50ee4fSDarrick J. Wong agbno + aglen, &shape_changed); 1777174edb0eSDarrick J. Wong if (error) 1778174edb0eSDarrick J. Wong goto out_error; 1779174edb0eSDarrick J. Wong 1780174edb0eSDarrick J. Wong /* 1781174edb0eSDarrick J. Wong * Try to merge with the left or right extents of the range. 1782174edb0eSDarrick J. Wong */ 178368d0f389SDarrick J. Wong error = xfs_refcount_merge_extents(cur, XFS_REFC_DOMAIN_COW, &agbno, 178468d0f389SDarrick J. Wong &aglen, adj, &shape_changed); 1785174edb0eSDarrick J. Wong if (error) 1786174edb0eSDarrick J. Wong goto out_error; 1787174edb0eSDarrick J. Wong 1788174edb0eSDarrick J. Wong /* Now that we've taken care of the ends, adjust the middle extents */ 1789a1f69417SEric Sandeen error = xfs_refcount_adjust_cow_extents(cur, agbno, aglen, adj); 1790174edb0eSDarrick J. Wong if (error) 1791174edb0eSDarrick J. Wong goto out_error; 1792174edb0eSDarrick J. Wong 1793174edb0eSDarrick J. Wong return 0; 1794174edb0eSDarrick J. Wong 1795174edb0eSDarrick J. Wong out_error: 179650f02fe3SDave Chinner trace_xfs_refcount_adjust_cow_error(cur->bc_mp, cur->bc_ag.pag->pag_agno, 1797174edb0eSDarrick J. Wong error, _RET_IP_); 1798174edb0eSDarrick J. Wong return error; 1799174edb0eSDarrick J. Wong } 1800174edb0eSDarrick J. Wong 1801174edb0eSDarrick J. Wong /* 1802174edb0eSDarrick J. Wong * Record a CoW allocation in the refcount btree. 1803174edb0eSDarrick J. Wong */ 1804174edb0eSDarrick J. Wong STATIC int 1805174edb0eSDarrick J. Wong __xfs_refcount_cow_alloc( 1806174edb0eSDarrick J. Wong struct xfs_btree_cur *rcur, 1807174edb0eSDarrick J. Wong xfs_agblock_t agbno, 18080f37d178SBrian Foster xfs_extlen_t aglen) 1809174edb0eSDarrick J. Wong { 181050f02fe3SDave Chinner trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, 1811174edb0eSDarrick J. Wong agbno, aglen); 1812174edb0eSDarrick J. Wong 1813174edb0eSDarrick J. Wong /* Add refcount btree reservation */ 18140525e952SDarrick J. Wong return xfs_refcount_adjust_cow(rcur, agbno, aglen, 1815a1f69417SEric Sandeen XFS_REFCOUNT_ADJUST_COW_ALLOC); 1816174edb0eSDarrick J. Wong } 1817174edb0eSDarrick J. Wong 1818174edb0eSDarrick J. Wong /* 1819174edb0eSDarrick J. Wong * Remove a CoW allocation from the refcount btree. 1820174edb0eSDarrick J. Wong */ 1821174edb0eSDarrick J. Wong STATIC int 1822174edb0eSDarrick J. Wong __xfs_refcount_cow_free( 1823174edb0eSDarrick J. Wong struct xfs_btree_cur *rcur, 1824174edb0eSDarrick J. Wong xfs_agblock_t agbno, 18250f37d178SBrian Foster xfs_extlen_t aglen) 1826174edb0eSDarrick J. Wong { 182750f02fe3SDave Chinner trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, 1828174edb0eSDarrick J. Wong agbno, aglen); 1829174edb0eSDarrick J. Wong 1830174edb0eSDarrick J. Wong /* Remove refcount btree reservation */ 18310525e952SDarrick J. Wong return xfs_refcount_adjust_cow(rcur, agbno, aglen, 1832a1f69417SEric Sandeen XFS_REFCOUNT_ADJUST_COW_FREE); 1833174edb0eSDarrick J. Wong } 1834174edb0eSDarrick J. Wong 1835174edb0eSDarrick J. Wong /* Record a CoW staging extent in the refcount btree. */ 183674b4c5d4SDarrick J. Wong void 1837174edb0eSDarrick J. Wong xfs_refcount_alloc_cow_extent( 18380f37d178SBrian Foster struct xfs_trans *tp, 1839174edb0eSDarrick J. Wong xfs_fsblock_t fsb, 1840174edb0eSDarrick J. Wong xfs_extlen_t len) 1841174edb0eSDarrick J. Wong { 18420f37d178SBrian Foster struct xfs_mount *mp = tp->t_mountp; 18430525e952SDarrick J. Wong 1844ebd9027dSDave Chinner if (!xfs_has_reflink(mp)) 184574b4c5d4SDarrick J. Wong return; 1846174edb0eSDarrick J. Wong 184774b4c5d4SDarrick J. Wong __xfs_refcount_add(tp, XFS_REFCOUNT_ALLOC_COW, fsb, len); 18480525e952SDarrick J. Wong 18490525e952SDarrick J. Wong /* Add rmap entry */ 1850bc46ac64SDarrick J. Wong xfs_rmap_alloc_extent(tp, XFS_FSB_TO_AGNO(mp, fsb), 18510525e952SDarrick J. Wong XFS_FSB_TO_AGBNO(mp, fsb), len, XFS_RMAP_OWN_COW); 1852174edb0eSDarrick J. Wong } 1853174edb0eSDarrick J. Wong 1854174edb0eSDarrick J. Wong /* Forget a CoW staging event in the refcount btree. */ 185574b4c5d4SDarrick J. Wong void 1856174edb0eSDarrick J. Wong xfs_refcount_free_cow_extent( 18570f37d178SBrian Foster struct xfs_trans *tp, 1858174edb0eSDarrick J. Wong xfs_fsblock_t fsb, 1859174edb0eSDarrick J. Wong xfs_extlen_t len) 1860174edb0eSDarrick J. Wong { 18610f37d178SBrian Foster struct xfs_mount *mp = tp->t_mountp; 18620525e952SDarrick J. Wong 1863ebd9027dSDave Chinner if (!xfs_has_reflink(mp)) 186474b4c5d4SDarrick J. Wong return; 1865174edb0eSDarrick J. Wong 18660525e952SDarrick J. Wong /* Remove rmap entry */ 1867bc46ac64SDarrick J. Wong xfs_rmap_free_extent(tp, XFS_FSB_TO_AGNO(mp, fsb), 18680525e952SDarrick J. Wong XFS_FSB_TO_AGBNO(mp, fsb), len, XFS_RMAP_OWN_COW); 186974b4c5d4SDarrick J. Wong __xfs_refcount_add(tp, XFS_REFCOUNT_FREE_COW, fsb, len); 1870174edb0eSDarrick J. Wong } 1871174edb0eSDarrick J. Wong 1872174edb0eSDarrick J. Wong struct xfs_refcount_recovery { 1873174edb0eSDarrick J. Wong struct list_head rr_list; 1874174edb0eSDarrick J. Wong struct xfs_refcount_irec rr_rrec; 1875174edb0eSDarrick J. Wong }; 1876174edb0eSDarrick J. Wong 1877174edb0eSDarrick J. Wong /* Stuff an extent on the recovery list. */ 1878174edb0eSDarrick J. Wong STATIC int 1879174edb0eSDarrick J. Wong xfs_refcount_recover_extent( 1880174edb0eSDarrick J. Wong struct xfs_btree_cur *cur, 1881159eb69dSDarrick J. Wong const union xfs_btree_rec *rec, 1882174edb0eSDarrick J. Wong void *priv) 1883174edb0eSDarrick J. Wong { 1884174edb0eSDarrick J. Wong struct list_head *debris = priv; 1885174edb0eSDarrick J. Wong struct xfs_refcount_recovery *rr; 1886174edb0eSDarrick J. Wong 1887a71895c5SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, 1888a71895c5SDarrick J. Wong be32_to_cpu(rec->refc.rc_refcount) != 1)) 1889174edb0eSDarrick J. Wong return -EFSCORRUPTED; 1890174edb0eSDarrick J. Wong 1891c1ccf967SDarrick J. Wong rr = kmalloc(sizeof(struct xfs_refcount_recovery), 1892c1ccf967SDarrick J. Wong GFP_KERNEL | __GFP_NOFAIL); 1893c1ccf967SDarrick J. Wong INIT_LIST_HEAD(&rr->rr_list); 1894174edb0eSDarrick J. Wong xfs_refcount_btrec_to_irec(rec, &rr->rr_rrec); 1895174edb0eSDarrick J. Wong 18962b30cc0bSDarrick J. Wong if (xfs_refcount_check_irec(cur, &rr->rr_rrec) != NULL || 18972b30cc0bSDarrick J. Wong XFS_IS_CORRUPT(cur->bc_mp, 1898f62ac3e0SDarrick J. Wong rr->rr_rrec.rc_domain != XFS_REFC_DOMAIN_COW)) { 1899c1ccf967SDarrick J. Wong kfree(rr); 1900f62ac3e0SDarrick J. Wong return -EFSCORRUPTED; 1901f62ac3e0SDarrick J. Wong } 1902f62ac3e0SDarrick J. Wong 1903f62ac3e0SDarrick J. Wong list_add_tail(&rr->rr_list, debris); 1904174edb0eSDarrick J. Wong return 0; 1905174edb0eSDarrick J. Wong } 1906174edb0eSDarrick J. Wong 1907174edb0eSDarrick J. Wong /* Find and remove leftover CoW reservations. */ 1908174edb0eSDarrick J. Wong int 1909174edb0eSDarrick J. Wong xfs_refcount_recover_cow_leftovers( 1910174edb0eSDarrick J. Wong struct xfs_mount *mp, 1911a81a0621SDave Chinner struct xfs_perag *pag) 1912174edb0eSDarrick J. Wong { 1913174edb0eSDarrick J. Wong struct xfs_trans *tp; 1914174edb0eSDarrick J. Wong struct xfs_btree_cur *cur; 1915174edb0eSDarrick J. Wong struct xfs_buf *agbp; 1916174edb0eSDarrick J. Wong struct xfs_refcount_recovery *rr, *n; 1917174edb0eSDarrick J. Wong struct list_head debris; 1918174edb0eSDarrick J. Wong union xfs_btree_irec low; 1919174edb0eSDarrick J. Wong union xfs_btree_irec high; 1920174edb0eSDarrick J. Wong xfs_fsblock_t fsb; 1921174edb0eSDarrick J. Wong int error; 1922174edb0eSDarrick J. Wong 1923f1fdc820SDarrick J. Wong /* reflink filesystems mustn't have AGs larger than 2^31-1 blocks */ 19248b972158SDarrick J. Wong BUILD_BUG_ON(XFS_MAX_CRC_AG_BLOCKS >= XFS_REFC_COWFLAG); 1925f1fdc820SDarrick J. Wong if (mp->m_sb.sb_agblocks > XFS_MAX_CRC_AG_BLOCKS) 1926174edb0eSDarrick J. Wong return -EOPNOTSUPP; 1927174edb0eSDarrick J. Wong 19283ecb3ac7SDarrick J. Wong INIT_LIST_HEAD(&debris); 19293ecb3ac7SDarrick J. Wong 19303ecb3ac7SDarrick J. Wong /* 19313ecb3ac7SDarrick J. Wong * In this first part, we use an empty transaction to gather up 19323ecb3ac7SDarrick J. Wong * all the leftover CoW extents so that we can subsequently 19333ecb3ac7SDarrick J. Wong * delete them. The empty transaction is used to avoid 19343ecb3ac7SDarrick J. Wong * a buffer lock deadlock if there happens to be a loop in the 19353ecb3ac7SDarrick J. Wong * refcountbt because we're allowed to re-grab a buffer that is 19363ecb3ac7SDarrick J. Wong * already attached to our transaction. When we're done 19373ecb3ac7SDarrick J. Wong * recording the CoW debris we cancel the (empty) transaction 19383ecb3ac7SDarrick J. Wong * and everything goes away cleanly. 19393ecb3ac7SDarrick J. Wong */ 19403ecb3ac7SDarrick J. Wong error = xfs_trans_alloc_empty(mp, &tp); 1941174edb0eSDarrick J. Wong if (error) 1942174edb0eSDarrick J. Wong return error; 19433ecb3ac7SDarrick J. Wong 194408d3e84fSDave Chinner error = xfs_alloc_read_agf(pag, tp, 0, &agbp); 19453ecb3ac7SDarrick J. Wong if (error) 19463ecb3ac7SDarrick J. Wong goto out_trans; 1947a81a0621SDave Chinner cur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag); 1948174edb0eSDarrick J. Wong 1949174edb0eSDarrick J. Wong /* Find all the leftover CoW staging extents. */ 1950174edb0eSDarrick J. Wong memset(&low, 0, sizeof(low)); 1951174edb0eSDarrick J. Wong memset(&high, 0, sizeof(high)); 19529a50ee4fSDarrick J. Wong low.rc.rc_domain = high.rc.rc_domain = XFS_REFC_DOMAIN_COW; 1953174edb0eSDarrick J. Wong high.rc.rc_startblock = -1U; 1954174edb0eSDarrick J. Wong error = xfs_btree_query_range(cur, &low, &high, 1955174edb0eSDarrick J. Wong xfs_refcount_recover_extent, &debris); 1956ef97ef26SDarrick J. Wong xfs_btree_del_cursor(cur, error); 19573ecb3ac7SDarrick J. Wong xfs_trans_brelse(tp, agbp); 19583ecb3ac7SDarrick J. Wong xfs_trans_cancel(tp); 1959ef97ef26SDarrick J. Wong if (error) 1960ef97ef26SDarrick J. Wong goto out_free; 1961174edb0eSDarrick J. Wong 1962174edb0eSDarrick J. Wong /* Now iterate the list to free the leftovers */ 19633ecb3ac7SDarrick J. Wong list_for_each_entry_safe(rr, n, &debris, rr_list) { 1964174edb0eSDarrick J. Wong /* Set up transaction. */ 1965174edb0eSDarrick J. Wong error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, 0, 0, 0, &tp); 1966174edb0eSDarrick J. Wong if (error) 1967174edb0eSDarrick J. Wong goto out_free; 1968174edb0eSDarrick J. Wong 1969a81a0621SDave Chinner trace_xfs_refcount_recover_extent(mp, pag->pag_agno, 1970a81a0621SDave Chinner &rr->rr_rrec); 1971174edb0eSDarrick J. Wong 1972174edb0eSDarrick J. Wong /* Free the orphan record */ 19739a50ee4fSDarrick J. Wong fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, 19749a50ee4fSDarrick J. Wong rr->rr_rrec.rc_startblock); 197574b4c5d4SDarrick J. Wong xfs_refcount_free_cow_extent(tp, fsb, 1976174edb0eSDarrick J. Wong rr->rr_rrec.rc_blockcount); 1977174edb0eSDarrick J. Wong 1978174edb0eSDarrick J. Wong /* Free the block. */ 1979c201d9caSDarrick J. Wong xfs_free_extent_later(tp, fsb, rr->rr_rrec.rc_blockcount, NULL); 1980174edb0eSDarrick J. Wong 1981174edb0eSDarrick J. Wong error = xfs_trans_commit(tp); 1982174edb0eSDarrick J. Wong if (error) 1983174edb0eSDarrick J. Wong goto out_free; 19843ecb3ac7SDarrick J. Wong 19853ecb3ac7SDarrick J. Wong list_del(&rr->rr_list); 1986c1ccf967SDarrick J. Wong kfree(rr); 19876f97077fSDarrick J. Wong } 1988174edb0eSDarrick J. Wong 19893ecb3ac7SDarrick J. Wong return error; 19903ecb3ac7SDarrick J. Wong out_trans: 19913ecb3ac7SDarrick J. Wong xfs_trans_cancel(tp); 1992174edb0eSDarrick J. Wong out_free: 1993174edb0eSDarrick J. Wong /* Free the leftover list */ 1994174edb0eSDarrick J. Wong list_for_each_entry_safe(rr, n, &debris, rr_list) { 1995174edb0eSDarrick J. Wong list_del(&rr->rr_list); 1996c1ccf967SDarrick J. Wong kfree(rr); 1997174edb0eSDarrick J. Wong } 1998174edb0eSDarrick J. Wong return error; 1999174edb0eSDarrick J. Wong } 200049db55ecSDarrick J. Wong 2001*6abc7aefSDarrick J. Wong /* 2002*6abc7aefSDarrick J. Wong * Scan part of the keyspace of the refcount records and tell us if the area 2003*6abc7aefSDarrick J. Wong * has no records, is fully mapped by records, or is partially filled. 2004*6abc7aefSDarrick J. Wong */ 200549db55ecSDarrick J. Wong int 2006*6abc7aefSDarrick J. Wong xfs_refcount_has_records( 200749db55ecSDarrick J. Wong struct xfs_btree_cur *cur, 20089a50ee4fSDarrick J. Wong enum xfs_refc_domain domain, 200949db55ecSDarrick J. Wong xfs_agblock_t bno, 201049db55ecSDarrick J. Wong xfs_extlen_t len, 2011*6abc7aefSDarrick J. Wong enum xbtree_recpacking *outcome) 201249db55ecSDarrick J. Wong { 201349db55ecSDarrick J. Wong union xfs_btree_irec low; 201449db55ecSDarrick J. Wong union xfs_btree_irec high; 201549db55ecSDarrick J. Wong 201649db55ecSDarrick J. Wong memset(&low, 0, sizeof(low)); 201749db55ecSDarrick J. Wong low.rc.rc_startblock = bno; 201849db55ecSDarrick J. Wong memset(&high, 0xFF, sizeof(high)); 201949db55ecSDarrick J. Wong high.rc.rc_startblock = bno + len - 1; 20209a50ee4fSDarrick J. Wong low.rc.rc_domain = high.rc.rc_domain = domain; 202149db55ecSDarrick J. Wong 2022*6abc7aefSDarrick J. Wong return xfs_btree_has_records(cur, &low, &high, outcome); 202349db55ecSDarrick J. Wong } 2024f3c799c2SDarrick J. Wong 2025f3c799c2SDarrick J. Wong int __init 2026f3c799c2SDarrick J. Wong xfs_refcount_intent_init_cache(void) 2027f3c799c2SDarrick J. Wong { 2028f3c799c2SDarrick J. Wong xfs_refcount_intent_cache = kmem_cache_create("xfs_refc_intent", 2029f3c799c2SDarrick J. Wong sizeof(struct xfs_refcount_intent), 2030f3c799c2SDarrick J. Wong 0, 0, NULL); 2031f3c799c2SDarrick J. Wong 2032f3c799c2SDarrick J. Wong return xfs_refcount_intent_cache != NULL ? 0 : -ENOMEM; 2033f3c799c2SDarrick J. Wong } 2034f3c799c2SDarrick J. Wong 2035f3c799c2SDarrick J. Wong void 2036f3c799c2SDarrick J. Wong xfs_refcount_intent_destroy_cache(void) 2037f3c799c2SDarrick J. Wong { 2038f3c799c2SDarrick J. Wong kmem_cache_destroy(xfs_refcount_intent_cache); 2039f3c799c2SDarrick J. Wong xfs_refcount_intent_cache = NULL; 2040f3c799c2SDarrick J. Wong } 2041