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, 49bdf28630SDarrick J. Wong xfs_agblock_t bno, 50bdf28630SDarrick J. Wong int *stat) 51bdf28630SDarrick J. Wong { 5250f02fe3SDave Chinner trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, bno, 53bdf28630SDarrick J. Wong XFS_LOOKUP_LE); 54bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_startblock = bno; 55bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_blockcount = 0; 56bdf28630SDarrick J. Wong return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat); 57bdf28630SDarrick J. Wong } 58bdf28630SDarrick J. Wong 59bdf28630SDarrick J. Wong /* 60bdf28630SDarrick J. Wong * Look up the first record greater than or equal to [bno, len] in the btree 61bdf28630SDarrick J. Wong * given by cur. 62bdf28630SDarrick J. Wong */ 63bdf28630SDarrick J. Wong int 64bdf28630SDarrick J. Wong xfs_refcount_lookup_ge( 65bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 66bdf28630SDarrick J. Wong xfs_agblock_t bno, 67bdf28630SDarrick J. Wong int *stat) 68bdf28630SDarrick J. Wong { 6950f02fe3SDave Chinner trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, bno, 70bdf28630SDarrick J. Wong XFS_LOOKUP_GE); 71bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_startblock = bno; 72bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_blockcount = 0; 73bdf28630SDarrick J. Wong return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat); 74bdf28630SDarrick J. Wong } 75bdf28630SDarrick J. Wong 7608daa3ccSDarrick J. Wong /* 7708daa3ccSDarrick J. Wong * Look up the first record equal to [bno, len] in the btree 7808daa3ccSDarrick J. Wong * given by cur. 7908daa3ccSDarrick J. Wong */ 8008daa3ccSDarrick J. Wong int 8108daa3ccSDarrick J. Wong xfs_refcount_lookup_eq( 8208daa3ccSDarrick J. Wong struct xfs_btree_cur *cur, 8308daa3ccSDarrick J. Wong xfs_agblock_t bno, 8408daa3ccSDarrick J. Wong int *stat) 8508daa3ccSDarrick J. Wong { 8650f02fe3SDave Chinner trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, bno, 8708daa3ccSDarrick J. Wong XFS_LOOKUP_LE); 8808daa3ccSDarrick J. Wong cur->bc_rec.rc.rc_startblock = bno; 8908daa3ccSDarrick J. Wong cur->bc_rec.rc.rc_blockcount = 0; 9008daa3ccSDarrick J. Wong return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat); 9108daa3ccSDarrick J. Wong } 9208daa3ccSDarrick J. Wong 93174edb0eSDarrick J. Wong /* Convert on-disk record to in-core format. */ 947f8f1313SDarrick J. Wong void 95174edb0eSDarrick J. Wong xfs_refcount_btrec_to_irec( 96159eb69dSDarrick J. Wong const union xfs_btree_rec *rec, 97174edb0eSDarrick J. Wong struct xfs_refcount_irec *irec) 98174edb0eSDarrick J. Wong { 99174edb0eSDarrick J. Wong irec->rc_startblock = be32_to_cpu(rec->refc.rc_startblock); 100174edb0eSDarrick J. Wong irec->rc_blockcount = be32_to_cpu(rec->refc.rc_blockcount); 101174edb0eSDarrick J. Wong irec->rc_refcount = be32_to_cpu(rec->refc.rc_refcount); 102174edb0eSDarrick J. Wong } 103174edb0eSDarrick J. Wong 104bdf28630SDarrick J. Wong /* 105bdf28630SDarrick J. Wong * Get the data from the pointed-to record. 106bdf28630SDarrick J. Wong */ 107bdf28630SDarrick J. Wong int 108bdf28630SDarrick J. Wong xfs_refcount_get_rec( 109bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 110bdf28630SDarrick J. Wong struct xfs_refcount_irec *irec, 111bdf28630SDarrick J. Wong int *stat) 112bdf28630SDarrick J. Wong { 1139e6c08d4SDave Chinner struct xfs_mount *mp = cur->bc_mp; 1140800169eSDave Chinner struct xfs_perag *pag = cur->bc_ag.pag; 115bdf28630SDarrick J. Wong union xfs_btree_rec *rec; 116bdf28630SDarrick J. Wong int error; 1179e6c08d4SDave Chinner xfs_agblock_t realstart; 118bdf28630SDarrick J. Wong 119bdf28630SDarrick J. Wong error = xfs_btree_get_rec(cur, &rec, stat); 1209e6c08d4SDave Chinner if (error || !*stat) 121bdf28630SDarrick J. Wong return error; 1229e6c08d4SDave Chinner 1239e6c08d4SDave Chinner xfs_refcount_btrec_to_irec(rec, irec); 1249e6c08d4SDave Chinner if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN) 1259e6c08d4SDave Chinner goto out_bad_rec; 1269e6c08d4SDave Chinner 1279e6c08d4SDave Chinner /* handle special COW-staging state */ 1289e6c08d4SDave Chinner realstart = irec->rc_startblock; 1299e6c08d4SDave Chinner if (realstart & XFS_REFC_COW_START) { 1309e6c08d4SDave Chinner if (irec->rc_refcount != 1) 1319e6c08d4SDave Chinner goto out_bad_rec; 1329e6c08d4SDave Chinner realstart &= ~XFS_REFC_COW_START; 1339e6c08d4SDave Chinner } else if (irec->rc_refcount < 2) { 1349e6c08d4SDave Chinner goto out_bad_rec; 1359e6c08d4SDave Chinner } 1369e6c08d4SDave Chinner 1379e6c08d4SDave Chinner /* check for valid extent range, including overflow */ 1380800169eSDave Chinner if (!xfs_verify_agbno(pag, realstart)) 1399e6c08d4SDave Chinner goto out_bad_rec; 1409e6c08d4SDave Chinner if (realstart > realstart + irec->rc_blockcount) 1419e6c08d4SDave Chinner goto out_bad_rec; 1420800169eSDave Chinner if (!xfs_verify_agbno(pag, realstart + irec->rc_blockcount - 1)) 1439e6c08d4SDave Chinner goto out_bad_rec; 1449e6c08d4SDave Chinner 1459e6c08d4SDave Chinner if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT) 1469e6c08d4SDave Chinner goto out_bad_rec; 1479e6c08d4SDave Chinner 1480800169eSDave Chinner trace_xfs_refcount_get(cur->bc_mp, pag->pag_agno, irec); 1499e6c08d4SDave Chinner return 0; 1509e6c08d4SDave Chinner 1519e6c08d4SDave Chinner out_bad_rec: 1529e6c08d4SDave Chinner xfs_warn(mp, 1530800169eSDave Chinner "Refcount BTree record corruption in AG %d detected!", 1540800169eSDave Chinner pag->pag_agno); 1559e6c08d4SDave Chinner xfs_warn(mp, 1569e6c08d4SDave Chinner "Start block 0x%x, block count 0x%x, references 0x%x", 1579e6c08d4SDave Chinner irec->rc_startblock, irec->rc_blockcount, irec->rc_refcount); 1589e6c08d4SDave Chinner return -EFSCORRUPTED; 159bdf28630SDarrick J. Wong } 160bdf28630SDarrick J. Wong 161bdf28630SDarrick J. Wong /* 162bdf28630SDarrick J. Wong * Update the record referred to by cur to the value given 163bdf28630SDarrick J. Wong * by [bno, len, refcount]. 164bdf28630SDarrick J. Wong * This either works (return 0) or gets an EFSCORRUPTED error. 165bdf28630SDarrick J. Wong */ 166bdf28630SDarrick J. Wong STATIC int 167bdf28630SDarrick J. Wong xfs_refcount_update( 168bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 169bdf28630SDarrick J. Wong struct xfs_refcount_irec *irec) 170bdf28630SDarrick J. Wong { 171bdf28630SDarrick J. Wong union xfs_btree_rec rec; 172bdf28630SDarrick J. Wong int error; 173bdf28630SDarrick J. Wong 17450f02fe3SDave Chinner trace_xfs_refcount_update(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec); 175bdf28630SDarrick J. Wong rec.refc.rc_startblock = cpu_to_be32(irec->rc_startblock); 176bdf28630SDarrick J. Wong rec.refc.rc_blockcount = cpu_to_be32(irec->rc_blockcount); 177bdf28630SDarrick J. Wong rec.refc.rc_refcount = cpu_to_be32(irec->rc_refcount); 178bdf28630SDarrick J. Wong error = xfs_btree_update(cur, &rec); 179bdf28630SDarrick J. Wong if (error) 180bdf28630SDarrick J. Wong trace_xfs_refcount_update_error(cur->bc_mp, 18150f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 182bdf28630SDarrick J. Wong return error; 183bdf28630SDarrick J. Wong } 184bdf28630SDarrick J. Wong 185bdf28630SDarrick J. Wong /* 186bdf28630SDarrick J. Wong * Insert the record referred to by cur to the value given 187bdf28630SDarrick J. Wong * by [bno, len, refcount]. 188bdf28630SDarrick J. Wong * This either works (return 0) or gets an EFSCORRUPTED error. 189bdf28630SDarrick J. Wong */ 1907f8f1313SDarrick J. Wong int 191bdf28630SDarrick J. Wong xfs_refcount_insert( 192bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 193bdf28630SDarrick J. Wong struct xfs_refcount_irec *irec, 194bdf28630SDarrick J. Wong int *i) 195bdf28630SDarrick J. Wong { 196bdf28630SDarrick J. Wong int error; 197bdf28630SDarrick J. Wong 19850f02fe3SDave Chinner trace_xfs_refcount_insert(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec); 199bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_startblock = irec->rc_startblock; 200bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_blockcount = irec->rc_blockcount; 201bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_refcount = irec->rc_refcount; 202bdf28630SDarrick J. Wong error = xfs_btree_insert(cur, i); 20316858f7cSDave Chinner if (error) 20416858f7cSDave Chinner goto out_error; 205f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, *i != 1)) { 206f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 207f9e03706SDarrick J. Wong goto out_error; 208f9e03706SDarrick J. Wong } 20916858f7cSDave Chinner 210bdf28630SDarrick J. Wong out_error: 211bdf28630SDarrick J. Wong if (error) 212bdf28630SDarrick J. Wong trace_xfs_refcount_insert_error(cur->bc_mp, 21350f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 214bdf28630SDarrick J. Wong return error; 215bdf28630SDarrick J. Wong } 216bdf28630SDarrick J. Wong 217bdf28630SDarrick J. Wong /* 218bdf28630SDarrick J. Wong * Remove the record referred to by cur, then set the pointer to the spot 219bdf28630SDarrick J. Wong * where the record could be re-inserted, in case we want to increment or 220bdf28630SDarrick J. Wong * decrement the cursor. 221bdf28630SDarrick J. Wong * This either works (return 0) or gets an EFSCORRUPTED error. 222bdf28630SDarrick J. Wong */ 223bdf28630SDarrick J. Wong STATIC int 224bdf28630SDarrick J. Wong xfs_refcount_delete( 225bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 226bdf28630SDarrick J. Wong int *i) 227bdf28630SDarrick J. Wong { 228bdf28630SDarrick J. Wong struct xfs_refcount_irec irec; 229bdf28630SDarrick J. Wong int found_rec; 230bdf28630SDarrick J. Wong int error; 231bdf28630SDarrick J. Wong 232bdf28630SDarrick J. Wong error = xfs_refcount_get_rec(cur, &irec, &found_rec); 233bdf28630SDarrick J. Wong if (error) 234bdf28630SDarrick J. Wong goto out_error; 235f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 236f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 237f9e03706SDarrick J. Wong goto out_error; 238f9e03706SDarrick J. Wong } 23950f02fe3SDave Chinner trace_xfs_refcount_delete(cur->bc_mp, cur->bc_ag.pag->pag_agno, &irec); 240bdf28630SDarrick J. Wong error = xfs_btree_delete(cur, i); 241f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, *i != 1)) { 242f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 243f9e03706SDarrick J. Wong goto out_error; 244f9e03706SDarrick J. Wong } 245bdf28630SDarrick J. Wong if (error) 246bdf28630SDarrick J. Wong goto out_error; 247bdf28630SDarrick J. Wong error = xfs_refcount_lookup_ge(cur, irec.rc_startblock, &found_rec); 248bdf28630SDarrick J. Wong out_error: 249bdf28630SDarrick J. Wong if (error) 250bdf28630SDarrick J. Wong trace_xfs_refcount_delete_error(cur->bc_mp, 25150f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 252bdf28630SDarrick J. Wong return error; 253bdf28630SDarrick J. Wong } 25431727258SDarrick J. Wong 25531727258SDarrick J. Wong /* 25631727258SDarrick J. Wong * Adjusting the Reference Count 25731727258SDarrick J. Wong * 25831727258SDarrick J. Wong * As stated elsewhere, the reference count btree (refcbt) stores 25931727258SDarrick J. Wong * >1 reference counts for extents of physical blocks. In this 26031727258SDarrick J. Wong * operation, we're either raising or lowering the reference count of 26131727258SDarrick J. Wong * some subrange stored in the tree: 26231727258SDarrick J. Wong * 26331727258SDarrick J. Wong * <------ adjustment range ------> 26431727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+--------- 26531727258SDarrick J. Wong * 2 | | 3 | 4 | |17| 55 | 10 26631727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+--------- 26731727258SDarrick J. Wong * X axis is physical blocks number; 26831727258SDarrick J. Wong * reference counts are the numbers inside the rectangles 26931727258SDarrick J. Wong * 27031727258SDarrick J. Wong * The first thing we need to do is to ensure that there are no 27131727258SDarrick J. Wong * refcount extents crossing either boundary of the range to be 27231727258SDarrick J. Wong * adjusted. For any extent that does cross a boundary, split it into 27331727258SDarrick J. Wong * two extents so that we can increment the refcount of one of the 27431727258SDarrick J. Wong * pieces later: 27531727258SDarrick J. Wong * 27631727258SDarrick J. Wong * <------ adjustment range ------> 27731727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+----+---- 27831727258SDarrick J. Wong * 2 | | 3 | 2 | |17| 55 | 10 | 10 27931727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+----+---- 28031727258SDarrick J. Wong * 28131727258SDarrick J. Wong * For this next step, let's assume that all the physical blocks in 28231727258SDarrick J. Wong * the adjustment range are mapped to a file and are therefore in use 28331727258SDarrick J. Wong * at least once. Therefore, we can infer that any gap in the 28431727258SDarrick J. Wong * refcount tree within the adjustment range represents a physical 28531727258SDarrick J. Wong * extent with refcount == 1: 28631727258SDarrick J. Wong * 28731727258SDarrick J. Wong * <------ adjustment range ------> 28831727258SDarrick J. Wong * ----+---+---+-----+-+--+--------+----+---- 28931727258SDarrick J. Wong * 2 |"1"| 3 | 2 |1|17| 55 | 10 | 10 29031727258SDarrick J. Wong * ----+---+---+-----+-+--+--------+----+---- 29131727258SDarrick J. Wong * ^ 29231727258SDarrick J. Wong * 29331727258SDarrick J. Wong * For each extent that falls within the interval range, figure out 29431727258SDarrick J. Wong * which extent is to the left or the right of that extent. Now we 29531727258SDarrick J. Wong * have a left, current, and right extent. If the new reference count 29631727258SDarrick J. Wong * of the center extent enables us to merge left, center, and right 29731727258SDarrick J. Wong * into one record covering all three, do so. If the center extent is 29831727258SDarrick J. Wong * at the left end of the range, abuts the left extent, and its new 29931727258SDarrick J. Wong * reference count matches the left extent's record, then merge them. 30031727258SDarrick J. Wong * If the center extent is at the right end of the range, abuts the 30131727258SDarrick J. Wong * right extent, and the reference counts match, merge those. In the 30231727258SDarrick J. Wong * example, we can left merge (assuming an increment operation): 30331727258SDarrick J. Wong * 30431727258SDarrick J. Wong * <------ adjustment range ------> 30531727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 30631727258SDarrick J. Wong * 2 | 3 | 2 |1|17| 55 | 10 | 10 30731727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 30831727258SDarrick J. Wong * ^ 30931727258SDarrick J. Wong * 31031727258SDarrick J. Wong * For all other extents within the range, adjust the reference count 31131727258SDarrick J. Wong * or delete it if the refcount falls below 2. If we were 31231727258SDarrick J. Wong * incrementing, the end result looks like this: 31331727258SDarrick J. Wong * 31431727258SDarrick J. Wong * <------ adjustment range ------> 31531727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 31631727258SDarrick J. Wong * 2 | 4 | 3 |2|18| 56 | 11 | 10 31731727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 31831727258SDarrick J. Wong * 31931727258SDarrick J. Wong * The result of a decrement operation looks as such: 32031727258SDarrick J. Wong * 32131727258SDarrick J. Wong * <------ adjustment range ------> 32231727258SDarrick J. Wong * ----+ +---+ +--+--------+----+---- 32331727258SDarrick J. Wong * 2 | | 2 | |16| 54 | 9 | 10 32431727258SDarrick J. Wong * ----+ +---+ +--+--------+----+---- 32531727258SDarrick J. Wong * DDDD 111111DD 32631727258SDarrick J. Wong * 32731727258SDarrick J. Wong * The blocks marked "D" are freed; the blocks marked "1" are only 32831727258SDarrick J. Wong * referenced once and therefore the record is removed from the 32931727258SDarrick J. Wong * refcount btree. 33031727258SDarrick J. Wong */ 33131727258SDarrick J. Wong 33231727258SDarrick J. Wong /* Next block after this extent. */ 33331727258SDarrick J. Wong static inline xfs_agblock_t 33431727258SDarrick J. Wong xfs_refc_next( 33531727258SDarrick J. Wong struct xfs_refcount_irec *rc) 33631727258SDarrick J. Wong { 33731727258SDarrick J. Wong return rc->rc_startblock + rc->rc_blockcount; 33831727258SDarrick J. Wong } 33931727258SDarrick J. Wong 34031727258SDarrick J. Wong /* 34131727258SDarrick J. Wong * Split a refcount extent that crosses agbno. 34231727258SDarrick J. Wong */ 34331727258SDarrick J. Wong STATIC int 34431727258SDarrick J. Wong xfs_refcount_split_extent( 34531727258SDarrick J. Wong struct xfs_btree_cur *cur, 34631727258SDarrick J. Wong xfs_agblock_t agbno, 34731727258SDarrick J. Wong bool *shape_changed) 34831727258SDarrick J. Wong { 34931727258SDarrick J. Wong struct xfs_refcount_irec rcext, tmp; 35031727258SDarrick J. Wong int found_rec; 35131727258SDarrick J. Wong int error; 35231727258SDarrick J. Wong 35331727258SDarrick J. Wong *shape_changed = false; 35431727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, agbno, &found_rec); 35531727258SDarrick J. Wong if (error) 35631727258SDarrick J. Wong goto out_error; 35731727258SDarrick J. Wong if (!found_rec) 35831727258SDarrick J. Wong return 0; 35931727258SDarrick J. Wong 36031727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &rcext, &found_rec); 36131727258SDarrick J. Wong if (error) 36231727258SDarrick J. Wong goto out_error; 363f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 364f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 365f9e03706SDarrick J. Wong goto out_error; 366f9e03706SDarrick J. Wong } 36731727258SDarrick J. Wong if (rcext.rc_startblock == agbno || xfs_refc_next(&rcext) <= agbno) 36831727258SDarrick J. Wong return 0; 36931727258SDarrick J. Wong 37031727258SDarrick J. Wong *shape_changed = true; 37150f02fe3SDave Chinner trace_xfs_refcount_split_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno, 37231727258SDarrick J. Wong &rcext, agbno); 37331727258SDarrick J. Wong 37431727258SDarrick J. Wong /* Establish the right extent. */ 37531727258SDarrick J. Wong tmp = rcext; 37631727258SDarrick J. Wong tmp.rc_startblock = agbno; 37731727258SDarrick J. Wong tmp.rc_blockcount -= (agbno - rcext.rc_startblock); 37831727258SDarrick J. Wong error = xfs_refcount_update(cur, &tmp); 37931727258SDarrick J. Wong if (error) 38031727258SDarrick J. Wong goto out_error; 38131727258SDarrick J. Wong 38231727258SDarrick J. Wong /* Insert the left extent. */ 38331727258SDarrick J. Wong tmp = rcext; 38431727258SDarrick J. Wong tmp.rc_blockcount = agbno - rcext.rc_startblock; 38531727258SDarrick J. Wong error = xfs_refcount_insert(cur, &tmp, &found_rec); 38631727258SDarrick J. Wong if (error) 38731727258SDarrick J. Wong goto out_error; 388f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 389f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 390f9e03706SDarrick J. Wong goto out_error; 391f9e03706SDarrick J. Wong } 39231727258SDarrick J. Wong return error; 39331727258SDarrick J. Wong 39431727258SDarrick J. Wong out_error: 39531727258SDarrick J. Wong trace_xfs_refcount_split_extent_error(cur->bc_mp, 39650f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 39731727258SDarrick J. Wong return error; 39831727258SDarrick J. Wong } 39931727258SDarrick J. Wong 40031727258SDarrick J. Wong /* 40131727258SDarrick J. Wong * Merge the left, center, and right extents. 40231727258SDarrick J. Wong */ 40331727258SDarrick J. Wong STATIC int 40431727258SDarrick J. Wong xfs_refcount_merge_center_extents( 40531727258SDarrick J. Wong struct xfs_btree_cur *cur, 40631727258SDarrick J. Wong struct xfs_refcount_irec *left, 40731727258SDarrick J. Wong struct xfs_refcount_irec *center, 40831727258SDarrick J. Wong struct xfs_refcount_irec *right, 40931727258SDarrick J. Wong unsigned long long extlen, 41031727258SDarrick J. Wong xfs_extlen_t *aglen) 41131727258SDarrick J. Wong { 41231727258SDarrick J. Wong int error; 41331727258SDarrick J. Wong int found_rec; 41431727258SDarrick J. Wong 41531727258SDarrick J. Wong trace_xfs_refcount_merge_center_extents(cur->bc_mp, 41650f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, left, center, right); 41731727258SDarrick J. Wong 41831727258SDarrick J. Wong /* 41931727258SDarrick J. Wong * Make sure the center and right extents are not in the btree. 42031727258SDarrick J. Wong * If the center extent was synthesized, the first delete call 42131727258SDarrick J. Wong * removes the right extent and we skip the second deletion. 42231727258SDarrick J. Wong * If center and right were in the btree, then the first delete 42331727258SDarrick J. Wong * call removes the center and the second one removes the right 42431727258SDarrick J. Wong * extent. 42531727258SDarrick J. Wong */ 42631727258SDarrick J. Wong error = xfs_refcount_lookup_ge(cur, center->rc_startblock, 42731727258SDarrick J. Wong &found_rec); 42831727258SDarrick J. Wong if (error) 42931727258SDarrick J. Wong goto out_error; 430f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 431f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 432f9e03706SDarrick J. Wong goto out_error; 433f9e03706SDarrick J. Wong } 43431727258SDarrick J. Wong 43531727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 43631727258SDarrick J. Wong if (error) 43731727258SDarrick J. Wong goto out_error; 438f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 439f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 440f9e03706SDarrick J. Wong goto out_error; 441f9e03706SDarrick J. Wong } 44231727258SDarrick J. Wong 44331727258SDarrick J. Wong if (center->rc_refcount > 1) { 44431727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 44531727258SDarrick J. Wong if (error) 44631727258SDarrick J. Wong goto out_error; 447f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 448f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 449f9e03706SDarrick J. Wong goto out_error; 450f9e03706SDarrick J. Wong } 45131727258SDarrick J. Wong } 45231727258SDarrick J. Wong 45331727258SDarrick J. Wong /* Enlarge the left extent. */ 45431727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, left->rc_startblock, 45531727258SDarrick J. Wong &found_rec); 45631727258SDarrick J. Wong if (error) 45731727258SDarrick J. Wong goto out_error; 458f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 459f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 460f9e03706SDarrick J. Wong goto out_error; 461f9e03706SDarrick J. Wong } 46231727258SDarrick J. Wong 46331727258SDarrick J. Wong left->rc_blockcount = extlen; 46431727258SDarrick J. Wong error = xfs_refcount_update(cur, left); 46531727258SDarrick J. Wong if (error) 46631727258SDarrick J. Wong goto out_error; 46731727258SDarrick J. Wong 46831727258SDarrick J. Wong *aglen = 0; 46931727258SDarrick J. Wong return error; 47031727258SDarrick J. Wong 47131727258SDarrick J. Wong out_error: 47231727258SDarrick J. Wong trace_xfs_refcount_merge_center_extents_error(cur->bc_mp, 47350f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 47431727258SDarrick J. Wong return error; 47531727258SDarrick J. Wong } 47631727258SDarrick J. Wong 47731727258SDarrick J. Wong /* 47831727258SDarrick J. Wong * Merge with the left extent. 47931727258SDarrick J. Wong */ 48031727258SDarrick J. Wong STATIC int 48131727258SDarrick J. Wong xfs_refcount_merge_left_extent( 48231727258SDarrick J. Wong struct xfs_btree_cur *cur, 48331727258SDarrick J. Wong struct xfs_refcount_irec *left, 48431727258SDarrick J. Wong struct xfs_refcount_irec *cleft, 48531727258SDarrick J. Wong xfs_agblock_t *agbno, 48631727258SDarrick J. Wong xfs_extlen_t *aglen) 48731727258SDarrick J. Wong { 48831727258SDarrick J. Wong int error; 48931727258SDarrick J. Wong int found_rec; 49031727258SDarrick J. Wong 49131727258SDarrick J. Wong trace_xfs_refcount_merge_left_extent(cur->bc_mp, 49250f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, left, cleft); 49331727258SDarrick J. Wong 49431727258SDarrick J. Wong /* If the extent at agbno (cleft) wasn't synthesized, remove it. */ 49531727258SDarrick J. Wong if (cleft->rc_refcount > 1) { 49631727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, cleft->rc_startblock, 49731727258SDarrick J. Wong &found_rec); 49831727258SDarrick J. Wong if (error) 49931727258SDarrick J. Wong goto out_error; 500f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 501f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 502f9e03706SDarrick J. Wong goto out_error; 503f9e03706SDarrick J. Wong } 50431727258SDarrick J. Wong 50531727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 50631727258SDarrick J. Wong if (error) 50731727258SDarrick J. Wong goto out_error; 508f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 509f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 510f9e03706SDarrick J. Wong goto out_error; 511f9e03706SDarrick J. Wong } 51231727258SDarrick J. Wong } 51331727258SDarrick J. Wong 51431727258SDarrick J. Wong /* Enlarge the left extent. */ 51531727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, left->rc_startblock, 51631727258SDarrick J. Wong &found_rec); 51731727258SDarrick J. Wong if (error) 51831727258SDarrick J. Wong goto out_error; 519f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 520f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 521f9e03706SDarrick J. Wong goto out_error; 522f9e03706SDarrick J. Wong } 52331727258SDarrick J. Wong 52431727258SDarrick J. Wong left->rc_blockcount += cleft->rc_blockcount; 52531727258SDarrick J. Wong error = xfs_refcount_update(cur, left); 52631727258SDarrick J. Wong if (error) 52731727258SDarrick J. Wong goto out_error; 52831727258SDarrick J. Wong 52931727258SDarrick J. Wong *agbno += cleft->rc_blockcount; 53031727258SDarrick J. Wong *aglen -= cleft->rc_blockcount; 53131727258SDarrick J. Wong return error; 53231727258SDarrick J. Wong 53331727258SDarrick J. Wong out_error: 53431727258SDarrick J. Wong trace_xfs_refcount_merge_left_extent_error(cur->bc_mp, 53550f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 53631727258SDarrick J. Wong return error; 53731727258SDarrick J. Wong } 53831727258SDarrick J. Wong 53931727258SDarrick J. Wong /* 54031727258SDarrick J. Wong * Merge with the right extent. 54131727258SDarrick J. Wong */ 54231727258SDarrick J. Wong STATIC int 54331727258SDarrick J. Wong xfs_refcount_merge_right_extent( 54431727258SDarrick J. Wong struct xfs_btree_cur *cur, 54531727258SDarrick J. Wong struct xfs_refcount_irec *right, 54631727258SDarrick J. Wong struct xfs_refcount_irec *cright, 54731727258SDarrick J. Wong xfs_extlen_t *aglen) 54831727258SDarrick J. Wong { 54931727258SDarrick J. Wong int error; 55031727258SDarrick J. Wong int found_rec; 55131727258SDarrick J. Wong 55231727258SDarrick J. Wong trace_xfs_refcount_merge_right_extent(cur->bc_mp, 55350f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, cright, right); 55431727258SDarrick J. Wong 55531727258SDarrick J. Wong /* 55631727258SDarrick J. Wong * If the extent ending at agbno+aglen (cright) wasn't synthesized, 55731727258SDarrick J. Wong * remove it. 55831727258SDarrick J. Wong */ 55931727258SDarrick J. Wong if (cright->rc_refcount > 1) { 56031727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, cright->rc_startblock, 56131727258SDarrick J. Wong &found_rec); 56231727258SDarrick J. Wong if (error) 56331727258SDarrick J. Wong goto out_error; 564f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 565f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 566f9e03706SDarrick J. Wong goto out_error; 567f9e03706SDarrick J. Wong } 56831727258SDarrick J. Wong 56931727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 57031727258SDarrick J. Wong if (error) 57131727258SDarrick J. Wong goto out_error; 572f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 573f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 574f9e03706SDarrick J. Wong goto out_error; 575f9e03706SDarrick J. Wong } 57631727258SDarrick J. Wong } 57731727258SDarrick J. Wong 57831727258SDarrick J. Wong /* Enlarge the right extent. */ 57931727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, right->rc_startblock, 58031727258SDarrick J. Wong &found_rec); 58131727258SDarrick J. Wong if (error) 58231727258SDarrick J. Wong goto out_error; 583f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 584f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 585f9e03706SDarrick J. Wong goto out_error; 586f9e03706SDarrick J. Wong } 58731727258SDarrick J. Wong 58831727258SDarrick J. Wong right->rc_startblock -= cright->rc_blockcount; 58931727258SDarrick J. Wong right->rc_blockcount += cright->rc_blockcount; 59031727258SDarrick J. Wong error = xfs_refcount_update(cur, right); 59131727258SDarrick J. Wong if (error) 59231727258SDarrick J. Wong goto out_error; 59331727258SDarrick J. Wong 59431727258SDarrick J. Wong *aglen -= cright->rc_blockcount; 59531727258SDarrick J. Wong return error; 59631727258SDarrick J. Wong 59731727258SDarrick J. Wong out_error: 59831727258SDarrick J. Wong trace_xfs_refcount_merge_right_extent_error(cur->bc_mp, 59950f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 60031727258SDarrick J. Wong return error; 60131727258SDarrick J. Wong } 60231727258SDarrick J. Wong 603174edb0eSDarrick J. Wong #define XFS_FIND_RCEXT_SHARED 1 604174edb0eSDarrick J. Wong #define XFS_FIND_RCEXT_COW 2 60531727258SDarrick J. Wong /* 60631727258SDarrick J. Wong * Find the left extent and the one after it (cleft). This function assumes 60731727258SDarrick J. Wong * that we've already split any extent crossing agbno. 60831727258SDarrick J. Wong */ 60931727258SDarrick J. Wong STATIC int 61031727258SDarrick J. Wong xfs_refcount_find_left_extents( 61131727258SDarrick J. Wong struct xfs_btree_cur *cur, 61231727258SDarrick J. Wong struct xfs_refcount_irec *left, 61331727258SDarrick J. Wong struct xfs_refcount_irec *cleft, 61431727258SDarrick J. Wong xfs_agblock_t agbno, 615174edb0eSDarrick J. Wong xfs_extlen_t aglen, 616174edb0eSDarrick J. Wong int flags) 61731727258SDarrick J. Wong { 61831727258SDarrick J. Wong struct xfs_refcount_irec tmp; 61931727258SDarrick J. Wong int error; 62031727258SDarrick J. Wong int found_rec; 62131727258SDarrick J. Wong 62231727258SDarrick J. Wong left->rc_startblock = cleft->rc_startblock = NULLAGBLOCK; 62331727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, agbno - 1, &found_rec); 62431727258SDarrick J. Wong if (error) 62531727258SDarrick J. Wong goto out_error; 62631727258SDarrick J. Wong if (!found_rec) 62731727258SDarrick J. Wong return 0; 62831727258SDarrick J. Wong 62931727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 63031727258SDarrick J. Wong if (error) 63131727258SDarrick J. Wong goto out_error; 632f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 633f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 634f9e03706SDarrick J. Wong goto out_error; 635f9e03706SDarrick J. Wong } 63631727258SDarrick J. Wong 63731727258SDarrick J. Wong if (xfs_refc_next(&tmp) != agbno) 63831727258SDarrick J. Wong return 0; 639174edb0eSDarrick J. Wong if ((flags & XFS_FIND_RCEXT_SHARED) && tmp.rc_refcount < 2) 640174edb0eSDarrick J. Wong return 0; 641174edb0eSDarrick J. Wong if ((flags & XFS_FIND_RCEXT_COW) && tmp.rc_refcount > 1) 642174edb0eSDarrick J. Wong return 0; 64331727258SDarrick J. Wong /* We have a left extent; retrieve (or invent) the next right one */ 64431727258SDarrick J. Wong *left = tmp; 64531727258SDarrick J. Wong 64631727258SDarrick J. Wong error = xfs_btree_increment(cur, 0, &found_rec); 64731727258SDarrick J. Wong if (error) 64831727258SDarrick J. Wong goto out_error; 64931727258SDarrick J. Wong if (found_rec) { 65031727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 65131727258SDarrick J. Wong if (error) 65231727258SDarrick J. Wong goto out_error; 653f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 654f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 655f9e03706SDarrick J. Wong goto out_error; 656f9e03706SDarrick J. Wong } 65731727258SDarrick J. Wong 65831727258SDarrick J. Wong /* if tmp starts at the end of our range, just use that */ 65931727258SDarrick J. Wong if (tmp.rc_startblock == agbno) 66031727258SDarrick J. Wong *cleft = tmp; 66131727258SDarrick J. Wong else { 66231727258SDarrick J. Wong /* 66331727258SDarrick J. Wong * There's a gap in the refcntbt at the start of the 66431727258SDarrick J. Wong * range we're interested in (refcount == 1) so 66531727258SDarrick J. Wong * synthesize the implied extent and pass it back. 66631727258SDarrick J. Wong * We assume here that the agbno/aglen range was 66731727258SDarrick J. Wong * passed in from a data fork extent mapping and 66831727258SDarrick J. Wong * therefore is allocated to exactly one owner. 66931727258SDarrick J. Wong */ 67031727258SDarrick J. Wong cleft->rc_startblock = agbno; 67131727258SDarrick J. Wong cleft->rc_blockcount = min(aglen, 67231727258SDarrick J. Wong tmp.rc_startblock - agbno); 67331727258SDarrick J. Wong cleft->rc_refcount = 1; 67431727258SDarrick J. Wong } 67531727258SDarrick J. Wong } else { 67631727258SDarrick J. Wong /* 67731727258SDarrick J. Wong * No extents, so pretend that there's one covering the whole 67831727258SDarrick J. Wong * range. 67931727258SDarrick J. Wong */ 68031727258SDarrick J. Wong cleft->rc_startblock = agbno; 68131727258SDarrick J. Wong cleft->rc_blockcount = aglen; 68231727258SDarrick J. Wong cleft->rc_refcount = 1; 68331727258SDarrick J. Wong } 68450f02fe3SDave Chinner trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno, 68531727258SDarrick J. Wong left, cleft, agbno); 68631727258SDarrick J. Wong return error; 68731727258SDarrick J. Wong 68831727258SDarrick J. Wong out_error: 68931727258SDarrick J. Wong trace_xfs_refcount_find_left_extent_error(cur->bc_mp, 69050f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 69131727258SDarrick J. Wong return error; 69231727258SDarrick J. Wong } 69331727258SDarrick J. Wong 69431727258SDarrick J. Wong /* 69531727258SDarrick J. Wong * Find the right extent and the one before it (cright). This function 69631727258SDarrick J. Wong * assumes that we've already split any extents crossing agbno + aglen. 69731727258SDarrick J. Wong */ 69831727258SDarrick J. Wong STATIC int 69931727258SDarrick J. Wong xfs_refcount_find_right_extents( 70031727258SDarrick J. Wong struct xfs_btree_cur *cur, 70131727258SDarrick J. Wong struct xfs_refcount_irec *right, 70231727258SDarrick J. Wong struct xfs_refcount_irec *cright, 70331727258SDarrick J. Wong xfs_agblock_t agbno, 704174edb0eSDarrick J. Wong xfs_extlen_t aglen, 705174edb0eSDarrick J. Wong int flags) 70631727258SDarrick J. Wong { 70731727258SDarrick J. Wong struct xfs_refcount_irec tmp; 70831727258SDarrick J. Wong int error; 70931727258SDarrick J. Wong int found_rec; 71031727258SDarrick J. Wong 71131727258SDarrick J. Wong right->rc_startblock = cright->rc_startblock = NULLAGBLOCK; 71231727258SDarrick J. Wong error = xfs_refcount_lookup_ge(cur, agbno + aglen, &found_rec); 71331727258SDarrick J. Wong if (error) 71431727258SDarrick J. Wong goto out_error; 71531727258SDarrick J. Wong if (!found_rec) 71631727258SDarrick J. Wong return 0; 71731727258SDarrick J. Wong 71831727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 71931727258SDarrick J. Wong if (error) 72031727258SDarrick J. Wong goto out_error; 721f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 722f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 723f9e03706SDarrick J. Wong goto out_error; 724f9e03706SDarrick J. Wong } 72531727258SDarrick J. Wong 72631727258SDarrick J. Wong if (tmp.rc_startblock != agbno + aglen) 72731727258SDarrick J. Wong return 0; 728174edb0eSDarrick J. Wong if ((flags & XFS_FIND_RCEXT_SHARED) && tmp.rc_refcount < 2) 729174edb0eSDarrick J. Wong return 0; 730174edb0eSDarrick J. Wong if ((flags & XFS_FIND_RCEXT_COW) && tmp.rc_refcount > 1) 731174edb0eSDarrick J. Wong return 0; 73231727258SDarrick J. Wong /* We have a right extent; retrieve (or invent) the next left one */ 73331727258SDarrick J. Wong *right = tmp; 73431727258SDarrick J. Wong 73531727258SDarrick J. Wong error = xfs_btree_decrement(cur, 0, &found_rec); 73631727258SDarrick J. Wong if (error) 73731727258SDarrick J. Wong goto out_error; 73831727258SDarrick J. Wong if (found_rec) { 73931727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 74031727258SDarrick J. Wong if (error) 74131727258SDarrick J. Wong goto out_error; 742f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 743f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 744f9e03706SDarrick J. Wong goto out_error; 745f9e03706SDarrick J. Wong } 74631727258SDarrick J. Wong 74731727258SDarrick J. Wong /* if tmp ends at the end of our range, just use that */ 74831727258SDarrick J. Wong if (xfs_refc_next(&tmp) == agbno + aglen) 74931727258SDarrick J. Wong *cright = tmp; 75031727258SDarrick J. Wong else { 75131727258SDarrick J. Wong /* 75231727258SDarrick J. Wong * There's a gap in the refcntbt at the end of the 75331727258SDarrick J. Wong * range we're interested in (refcount == 1) so 75431727258SDarrick J. Wong * create the implied extent and pass it back. 75531727258SDarrick J. Wong * We assume here that the agbno/aglen range was 75631727258SDarrick J. Wong * passed in from a data fork extent mapping and 75731727258SDarrick J. Wong * therefore is allocated to exactly one owner. 75831727258SDarrick J. Wong */ 75931727258SDarrick J. Wong cright->rc_startblock = max(agbno, xfs_refc_next(&tmp)); 76031727258SDarrick J. Wong cright->rc_blockcount = right->rc_startblock - 76131727258SDarrick J. Wong cright->rc_startblock; 76231727258SDarrick J. Wong cright->rc_refcount = 1; 76331727258SDarrick J. Wong } 76431727258SDarrick J. Wong } else { 76531727258SDarrick J. Wong /* 76631727258SDarrick J. Wong * No extents, so pretend that there's one covering the whole 76731727258SDarrick J. Wong * range. 76831727258SDarrick J. Wong */ 76931727258SDarrick J. Wong cright->rc_startblock = agbno; 77031727258SDarrick J. Wong cright->rc_blockcount = aglen; 77131727258SDarrick J. Wong cright->rc_refcount = 1; 77231727258SDarrick J. Wong } 77350f02fe3SDave Chinner trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno, 77431727258SDarrick J. Wong cright, right, agbno + aglen); 77531727258SDarrick J. Wong return error; 77631727258SDarrick J. Wong 77731727258SDarrick J. Wong out_error: 77831727258SDarrick J. Wong trace_xfs_refcount_find_right_extent_error(cur->bc_mp, 77950f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 78031727258SDarrick J. Wong return error; 78131727258SDarrick J. Wong } 78231727258SDarrick J. Wong 78331727258SDarrick J. Wong /* Is this extent valid? */ 78431727258SDarrick J. Wong static inline bool 78531727258SDarrick J. Wong xfs_refc_valid( 78631727258SDarrick J. Wong struct xfs_refcount_irec *rc) 78731727258SDarrick J. Wong { 78831727258SDarrick J. Wong return rc->rc_startblock != NULLAGBLOCK; 78931727258SDarrick J. Wong } 79031727258SDarrick J. Wong 79131727258SDarrick J. Wong /* 79231727258SDarrick J. Wong * Try to merge with any extents on the boundaries of the adjustment range. 79331727258SDarrick J. Wong */ 79431727258SDarrick J. Wong STATIC int 79531727258SDarrick J. Wong xfs_refcount_merge_extents( 79631727258SDarrick J. Wong struct xfs_btree_cur *cur, 79731727258SDarrick J. Wong xfs_agblock_t *agbno, 79831727258SDarrick J. Wong xfs_extlen_t *aglen, 79931727258SDarrick J. Wong enum xfs_refc_adjust_op adjust, 800174edb0eSDarrick J. Wong int flags, 80131727258SDarrick J. Wong bool *shape_changed) 80231727258SDarrick J. Wong { 80331727258SDarrick J. Wong struct xfs_refcount_irec left = {0}, cleft = {0}; 80431727258SDarrick J. Wong struct xfs_refcount_irec cright = {0}, right = {0}; 80531727258SDarrick J. Wong int error; 80631727258SDarrick J. Wong unsigned long long ulen; 80731727258SDarrick J. Wong bool cequal; 80831727258SDarrick J. Wong 80931727258SDarrick J. Wong *shape_changed = false; 81031727258SDarrick J. Wong /* 81131727258SDarrick J. Wong * Find the extent just below agbno [left], just above agbno [cleft], 81231727258SDarrick J. Wong * just below (agbno + aglen) [cright], and just above (agbno + aglen) 81331727258SDarrick J. Wong * [right]. 81431727258SDarrick J. Wong */ 81531727258SDarrick J. Wong error = xfs_refcount_find_left_extents(cur, &left, &cleft, *agbno, 816174edb0eSDarrick J. Wong *aglen, flags); 81731727258SDarrick J. Wong if (error) 81831727258SDarrick J. Wong return error; 81931727258SDarrick J. Wong error = xfs_refcount_find_right_extents(cur, &right, &cright, *agbno, 820174edb0eSDarrick J. Wong *aglen, flags); 82131727258SDarrick J. Wong if (error) 82231727258SDarrick J. Wong return error; 82331727258SDarrick J. Wong 82431727258SDarrick J. Wong /* No left or right extent to merge; exit. */ 82531727258SDarrick J. Wong if (!xfs_refc_valid(&left) && !xfs_refc_valid(&right)) 82631727258SDarrick J. Wong return 0; 82731727258SDarrick J. Wong 82831727258SDarrick J. Wong cequal = (cleft.rc_startblock == cright.rc_startblock) && 82931727258SDarrick J. Wong (cleft.rc_blockcount == cright.rc_blockcount); 83031727258SDarrick J. Wong 83131727258SDarrick J. Wong /* Try to merge left, cleft, and right. cleft must == cright. */ 83231727258SDarrick J. Wong ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount + 83331727258SDarrick J. Wong right.rc_blockcount; 83431727258SDarrick J. Wong if (xfs_refc_valid(&left) && xfs_refc_valid(&right) && 83531727258SDarrick J. Wong xfs_refc_valid(&cleft) && xfs_refc_valid(&cright) && cequal && 83631727258SDarrick J. Wong left.rc_refcount == cleft.rc_refcount + adjust && 83731727258SDarrick J. Wong right.rc_refcount == cleft.rc_refcount + adjust && 83831727258SDarrick J. Wong ulen < MAXREFCEXTLEN) { 83931727258SDarrick J. Wong *shape_changed = true; 84031727258SDarrick J. Wong return xfs_refcount_merge_center_extents(cur, &left, &cleft, 841a1f69417SEric Sandeen &right, ulen, aglen); 84231727258SDarrick J. Wong } 84331727258SDarrick J. Wong 84431727258SDarrick J. Wong /* Try to merge left and cleft. */ 84531727258SDarrick J. Wong ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount; 84631727258SDarrick J. Wong if (xfs_refc_valid(&left) && xfs_refc_valid(&cleft) && 84731727258SDarrick J. Wong left.rc_refcount == cleft.rc_refcount + adjust && 84831727258SDarrick J. Wong ulen < MAXREFCEXTLEN) { 84931727258SDarrick J. Wong *shape_changed = true; 85031727258SDarrick J. Wong error = xfs_refcount_merge_left_extent(cur, &left, &cleft, 85131727258SDarrick J. Wong agbno, aglen); 85231727258SDarrick J. Wong if (error) 85331727258SDarrick J. Wong return error; 85431727258SDarrick J. Wong 85531727258SDarrick J. Wong /* 85631727258SDarrick J. Wong * If we just merged left + cleft and cleft == cright, 85731727258SDarrick J. Wong * we no longer have a cright to merge with right. We're done. 85831727258SDarrick J. Wong */ 85931727258SDarrick J. Wong if (cequal) 86031727258SDarrick J. Wong return 0; 86131727258SDarrick J. Wong } 86231727258SDarrick J. Wong 86331727258SDarrick J. Wong /* Try to merge cright and right. */ 86431727258SDarrick J. Wong ulen = (unsigned long long)right.rc_blockcount + cright.rc_blockcount; 86531727258SDarrick J. Wong if (xfs_refc_valid(&right) && xfs_refc_valid(&cright) && 86631727258SDarrick J. Wong right.rc_refcount == cright.rc_refcount + adjust && 86731727258SDarrick J. Wong ulen < MAXREFCEXTLEN) { 86831727258SDarrick J. Wong *shape_changed = true; 86931727258SDarrick J. Wong return xfs_refcount_merge_right_extent(cur, &right, &cright, 870a1f69417SEric Sandeen aglen); 87131727258SDarrick J. Wong } 87231727258SDarrick J. Wong 87331727258SDarrick J. Wong return error; 87431727258SDarrick J. Wong } 87531727258SDarrick J. Wong 87631727258SDarrick J. Wong /* 87731727258SDarrick J. Wong * XXX: This is a pretty hand-wavy estimate. The penalty for guessing 87831727258SDarrick J. Wong * true incorrectly is a shutdown FS; the penalty for guessing false 87931727258SDarrick J. Wong * incorrectly is more transaction rolls than might be necessary. 88031727258SDarrick J. Wong * Be conservative here. 88131727258SDarrick J. Wong */ 88231727258SDarrick J. Wong static bool 88331727258SDarrick J. Wong xfs_refcount_still_have_space( 88431727258SDarrick J. Wong struct xfs_btree_cur *cur) 88531727258SDarrick J. Wong { 88631727258SDarrick J. Wong unsigned long overhead; 88731727258SDarrick J. Wong 888b037c4eeSDarrick J. Wong /* 889b037c4eeSDarrick J. Wong * Worst case estimate: full splits of the free space and rmap btrees 890b037c4eeSDarrick J. Wong * to handle each of the shape changes to the refcount btree. 891b037c4eeSDarrick J. Wong */ 8926ed7e509SDarrick J. Wong overhead = xfs_allocfree_block_count(cur->bc_mp, 893b037c4eeSDarrick J. Wong cur->bc_ag.refc.shape_changes); 894b037c4eeSDarrick J. Wong overhead += cur->bc_mp->m_refc_maxlevels; 89531727258SDarrick J. Wong overhead *= cur->bc_mp->m_sb.sb_blocksize; 89631727258SDarrick J. Wong 89731727258SDarrick J. Wong /* 89831727258SDarrick J. Wong * Only allow 2 refcount extent updates per transaction if the 89931727258SDarrick J. Wong * refcount continue update "error" has been injected. 90031727258SDarrick J. Wong */ 901c4aa10d0SDave Chinner if (cur->bc_ag.refc.nr_ops > 2 && 90231727258SDarrick J. Wong XFS_TEST_ERROR(false, cur->bc_mp, 9039e24cfd0SDarrick J. Wong XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE)) 90431727258SDarrick J. Wong return false; 90531727258SDarrick J. Wong 906c4aa10d0SDave Chinner if (cur->bc_ag.refc.nr_ops == 0) 90731727258SDarrick J. Wong return true; 90831727258SDarrick J. Wong else if (overhead > cur->bc_tp->t_log_res) 90931727258SDarrick J. Wong return false; 91031727258SDarrick J. Wong return cur->bc_tp->t_log_res - overhead > 911c4aa10d0SDave Chinner cur->bc_ag.refc.nr_ops * XFS_REFCOUNT_ITEM_OVERHEAD; 91231727258SDarrick J. Wong } 91331727258SDarrick J. Wong 91431727258SDarrick J. Wong /* 91531727258SDarrick J. Wong * Adjust the refcounts of middle extents. At this point we should have 91631727258SDarrick J. Wong * split extents that crossed the adjustment range; merged with adjacent 91731727258SDarrick J. Wong * extents; and updated agbno/aglen to reflect the merges. Therefore, 91831727258SDarrick J. Wong * all we have to do is update the extents inside [agbno, agbno + aglen]. 91931727258SDarrick J. Wong */ 92031727258SDarrick J. Wong STATIC int 92131727258SDarrick J. Wong xfs_refcount_adjust_extents( 92231727258SDarrick J. Wong struct xfs_btree_cur *cur, 92331727258SDarrick J. Wong xfs_agblock_t *agbno, 92431727258SDarrick J. Wong xfs_extlen_t *aglen, 925c04c51c5SDarrick J. Wong enum xfs_refc_adjust_op adj) 92631727258SDarrick J. Wong { 92731727258SDarrick J. Wong struct xfs_refcount_irec ext, tmp; 92831727258SDarrick J. Wong int error; 92931727258SDarrick J. Wong int found_rec, found_tmp; 93031727258SDarrick J. Wong xfs_fsblock_t fsbno; 93131727258SDarrick J. Wong 93231727258SDarrick J. Wong /* Merging did all the work already. */ 93331727258SDarrick J. Wong if (*aglen == 0) 93431727258SDarrick J. Wong return 0; 93531727258SDarrick J. Wong 93631727258SDarrick J. Wong error = xfs_refcount_lookup_ge(cur, *agbno, &found_rec); 93731727258SDarrick J. Wong if (error) 93831727258SDarrick J. Wong goto out_error; 93931727258SDarrick J. Wong 94031727258SDarrick J. Wong while (*aglen > 0 && xfs_refcount_still_have_space(cur)) { 94131727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &ext, &found_rec); 94231727258SDarrick J. Wong if (error) 94331727258SDarrick J. Wong goto out_error; 94431727258SDarrick J. Wong if (!found_rec) { 94531727258SDarrick J. Wong ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks; 94631727258SDarrick J. Wong ext.rc_blockcount = 0; 94731727258SDarrick J. Wong ext.rc_refcount = 0; 94831727258SDarrick J. Wong } 94931727258SDarrick J. Wong 95031727258SDarrick J. Wong /* 95131727258SDarrick J. Wong * Deal with a hole in the refcount tree; if a file maps to 95231727258SDarrick J. Wong * these blocks and there's no refcountbt record, pretend that 95331727258SDarrick J. Wong * there is one with refcount == 1. 95431727258SDarrick J. Wong */ 95531727258SDarrick J. Wong if (ext.rc_startblock != *agbno) { 95631727258SDarrick J. Wong tmp.rc_startblock = *agbno; 95731727258SDarrick J. Wong tmp.rc_blockcount = min(*aglen, 95831727258SDarrick J. Wong ext.rc_startblock - *agbno); 95931727258SDarrick J. Wong tmp.rc_refcount = 1 + adj; 96031727258SDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 96150f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, &tmp); 96231727258SDarrick J. Wong 96331727258SDarrick J. Wong /* 96431727258SDarrick J. Wong * Either cover the hole (increment) or 96531727258SDarrick J. Wong * delete the range (decrement). 96631727258SDarrick J. Wong */ 967c47260d4SDarrick J. Wong cur->bc_ag.refc.nr_ops++; 96831727258SDarrick J. Wong if (tmp.rc_refcount) { 96931727258SDarrick J. Wong error = xfs_refcount_insert(cur, &tmp, 97031727258SDarrick J. Wong &found_tmp); 97131727258SDarrick J. Wong if (error) 97231727258SDarrick J. Wong goto out_error; 973f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, 974f9e03706SDarrick J. Wong found_tmp != 1)) { 975f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 976f9e03706SDarrick J. Wong goto out_error; 977f9e03706SDarrick J. Wong } 97831727258SDarrick J. Wong } else { 97931727258SDarrick J. Wong fsbno = XFS_AGB_TO_FSB(cur->bc_mp, 98050f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, 98131727258SDarrick J. Wong tmp.rc_startblock); 982c201d9caSDarrick J. Wong xfs_free_extent_later(cur->bc_tp, fsbno, 983c04c51c5SDarrick J. Wong tmp.rc_blockcount, NULL); 98431727258SDarrick J. Wong } 98531727258SDarrick J. Wong 98631727258SDarrick J. Wong (*agbno) += tmp.rc_blockcount; 98731727258SDarrick J. Wong (*aglen) -= tmp.rc_blockcount; 98831727258SDarrick J. Wong 989*f850995fSDarrick J. Wong /* Stop if there's nothing left to modify */ 990*f850995fSDarrick J. Wong if (*aglen == 0 || !xfs_refcount_still_have_space(cur)) 991*f850995fSDarrick J. Wong break; 992*f850995fSDarrick J. Wong 993*f850995fSDarrick J. Wong /* Move the cursor to the start of ext. */ 99431727258SDarrick J. Wong error = xfs_refcount_lookup_ge(cur, *agbno, 99531727258SDarrick J. Wong &found_rec); 99631727258SDarrick J. Wong if (error) 99731727258SDarrick J. Wong goto out_error; 99831727258SDarrick J. Wong } 99931727258SDarrick J. Wong 1000*f850995fSDarrick J. Wong /* 1001*f850995fSDarrick J. Wong * A previous step trimmed agbno/aglen such that the end of the 1002*f850995fSDarrick J. Wong * range would not be in the middle of the record. If this is 1003*f850995fSDarrick J. Wong * no longer the case, something is seriously wrong with the 1004*f850995fSDarrick J. Wong * btree. Make sure we never feed the synthesized record into 1005*f850995fSDarrick J. Wong * the processing loop below. 1006*f850995fSDarrick J. Wong */ 1007*f850995fSDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_blockcount == 0) || 1008*f850995fSDarrick J. Wong XFS_IS_CORRUPT(cur->bc_mp, ext.rc_blockcount > *aglen)) { 1009*f850995fSDarrick J. Wong error = -EFSCORRUPTED; 1010*f850995fSDarrick J. Wong goto out_error; 1011*f850995fSDarrick J. Wong } 101231727258SDarrick J. Wong 101331727258SDarrick J. Wong /* 101431727258SDarrick J. Wong * Adjust the reference count and either update the tree 101531727258SDarrick J. Wong * (incr) or free the blocks (decr). 101631727258SDarrick J. Wong */ 101731727258SDarrick J. Wong if (ext.rc_refcount == MAXREFCOUNT) 101831727258SDarrick J. Wong goto skip; 101931727258SDarrick J. Wong ext.rc_refcount += adj; 102031727258SDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 102150f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, &ext); 1022c47260d4SDarrick J. Wong cur->bc_ag.refc.nr_ops++; 102331727258SDarrick J. Wong if (ext.rc_refcount > 1) { 102431727258SDarrick J. Wong error = xfs_refcount_update(cur, &ext); 102531727258SDarrick J. Wong if (error) 102631727258SDarrick J. Wong goto out_error; 102731727258SDarrick J. Wong } else if (ext.rc_refcount == 1) { 102831727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 102931727258SDarrick J. Wong if (error) 103031727258SDarrick J. Wong goto out_error; 1031f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 1032f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1033f9e03706SDarrick J. Wong goto out_error; 1034f9e03706SDarrick J. Wong } 103531727258SDarrick J. Wong goto advloop; 103631727258SDarrick J. Wong } else { 103731727258SDarrick J. Wong fsbno = XFS_AGB_TO_FSB(cur->bc_mp, 103850f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, 103931727258SDarrick J. Wong ext.rc_startblock); 1040c04c51c5SDarrick J. Wong xfs_free_extent_later(cur->bc_tp, fsbno, 1041c04c51c5SDarrick J. Wong ext.rc_blockcount, NULL); 104231727258SDarrick J. Wong } 104331727258SDarrick J. Wong 104431727258SDarrick J. Wong skip: 104531727258SDarrick J. Wong error = xfs_btree_increment(cur, 0, &found_rec); 104631727258SDarrick J. Wong if (error) 104731727258SDarrick J. Wong goto out_error; 104831727258SDarrick J. Wong 104931727258SDarrick J. Wong advloop: 105031727258SDarrick J. Wong (*agbno) += ext.rc_blockcount; 105131727258SDarrick J. Wong (*aglen) -= ext.rc_blockcount; 105231727258SDarrick J. Wong } 105331727258SDarrick J. Wong 105431727258SDarrick J. Wong return error; 105531727258SDarrick J. Wong out_error: 105631727258SDarrick J. Wong trace_xfs_refcount_modify_extent_error(cur->bc_mp, 105750f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 105831727258SDarrick J. Wong return error; 105931727258SDarrick J. Wong } 106031727258SDarrick J. Wong 106131727258SDarrick J. Wong /* Adjust the reference count of a range of AG blocks. */ 106231727258SDarrick J. Wong STATIC int 106331727258SDarrick J. Wong xfs_refcount_adjust( 106431727258SDarrick J. Wong struct xfs_btree_cur *cur, 106531727258SDarrick J. Wong xfs_agblock_t agbno, 106631727258SDarrick J. Wong xfs_extlen_t aglen, 106731727258SDarrick J. Wong xfs_agblock_t *new_agbno, 106831727258SDarrick J. Wong xfs_extlen_t *new_aglen, 1069c04c51c5SDarrick J. Wong enum xfs_refc_adjust_op adj) 107031727258SDarrick J. Wong { 107131727258SDarrick J. Wong bool shape_changed; 107231727258SDarrick J. Wong int shape_changes = 0; 107331727258SDarrick J. Wong int error; 107431727258SDarrick J. Wong 107531727258SDarrick J. Wong *new_agbno = agbno; 107631727258SDarrick J. Wong *new_aglen = aglen; 107731727258SDarrick J. Wong if (adj == XFS_REFCOUNT_ADJUST_INCREASE) 107850f02fe3SDave Chinner trace_xfs_refcount_increase(cur->bc_mp, cur->bc_ag.pag->pag_agno, 107931727258SDarrick J. Wong agbno, aglen); 108031727258SDarrick J. Wong else 108150f02fe3SDave Chinner trace_xfs_refcount_decrease(cur->bc_mp, cur->bc_ag.pag->pag_agno, 108231727258SDarrick J. Wong agbno, aglen); 108331727258SDarrick J. Wong 108431727258SDarrick J. Wong /* 108531727258SDarrick J. Wong * Ensure that no rcextents cross the boundary of the adjustment range. 108631727258SDarrick J. Wong */ 108731727258SDarrick J. Wong error = xfs_refcount_split_extent(cur, agbno, &shape_changed); 108831727258SDarrick J. Wong if (error) 108931727258SDarrick J. Wong goto out_error; 109031727258SDarrick J. Wong if (shape_changed) 109131727258SDarrick J. Wong shape_changes++; 109231727258SDarrick J. Wong 109331727258SDarrick J. Wong error = xfs_refcount_split_extent(cur, agbno + aglen, &shape_changed); 109431727258SDarrick J. Wong if (error) 109531727258SDarrick J. Wong goto out_error; 109631727258SDarrick J. Wong if (shape_changed) 109731727258SDarrick J. Wong shape_changes++; 109831727258SDarrick J. Wong 109931727258SDarrick J. Wong /* 110031727258SDarrick J. Wong * Try to merge with the left or right extents of the range. 110131727258SDarrick J. Wong */ 110231727258SDarrick J. Wong error = xfs_refcount_merge_extents(cur, new_agbno, new_aglen, adj, 1103174edb0eSDarrick J. Wong XFS_FIND_RCEXT_SHARED, &shape_changed); 110431727258SDarrick J. Wong if (error) 110531727258SDarrick J. Wong goto out_error; 110631727258SDarrick J. Wong if (shape_changed) 110731727258SDarrick J. Wong shape_changes++; 110831727258SDarrick J. Wong if (shape_changes) 1109c4aa10d0SDave Chinner cur->bc_ag.refc.shape_changes++; 111031727258SDarrick J. Wong 111131727258SDarrick J. Wong /* Now that we've taken care of the ends, adjust the middle extents */ 1112c04c51c5SDarrick J. Wong error = xfs_refcount_adjust_extents(cur, new_agbno, new_aglen, adj); 111331727258SDarrick J. Wong if (error) 111431727258SDarrick J. Wong goto out_error; 111531727258SDarrick J. Wong 111631727258SDarrick J. Wong return 0; 111731727258SDarrick J. Wong 111831727258SDarrick J. Wong out_error: 111950f02fe3SDave Chinner trace_xfs_refcount_adjust_error(cur->bc_mp, cur->bc_ag.pag->pag_agno, 112031727258SDarrick J. Wong error, _RET_IP_); 112131727258SDarrick J. Wong return error; 112231727258SDarrick J. Wong } 112333ba6129SDarrick J. Wong 112433ba6129SDarrick J. Wong /* Clean up after calling xfs_refcount_finish_one. */ 112533ba6129SDarrick J. Wong void 112633ba6129SDarrick J. Wong xfs_refcount_finish_one_cleanup( 112733ba6129SDarrick J. Wong struct xfs_trans *tp, 112833ba6129SDarrick J. Wong struct xfs_btree_cur *rcur, 112933ba6129SDarrick J. Wong int error) 113033ba6129SDarrick J. Wong { 113133ba6129SDarrick J. Wong struct xfs_buf *agbp; 113233ba6129SDarrick J. Wong 113333ba6129SDarrick J. Wong if (rcur == NULL) 113433ba6129SDarrick J. Wong return; 1135576af732SDave Chinner agbp = rcur->bc_ag.agbp; 11360b04b6b8SDarrick J. Wong xfs_btree_del_cursor(rcur, error); 113733ba6129SDarrick J. Wong if (error) 113833ba6129SDarrick J. Wong xfs_trans_brelse(tp, agbp); 113933ba6129SDarrick J. Wong } 114033ba6129SDarrick J. Wong 114133ba6129SDarrick J. Wong /* 114233ba6129SDarrick J. Wong * Process one of the deferred refcount operations. We pass back the 114333ba6129SDarrick J. Wong * btree cursor to maintain our lock on the btree between calls. 114433ba6129SDarrick J. Wong * This saves time and eliminates a buffer deadlock between the 114533ba6129SDarrick J. Wong * superblock and the AGF because we'll always grab them in the same 114633ba6129SDarrick J. Wong * order. 114733ba6129SDarrick J. Wong */ 114833ba6129SDarrick J. Wong int 114933ba6129SDarrick J. Wong xfs_refcount_finish_one( 115033ba6129SDarrick J. Wong struct xfs_trans *tp, 115133ba6129SDarrick J. Wong enum xfs_refcount_intent_type type, 115233ba6129SDarrick J. Wong xfs_fsblock_t startblock, 115333ba6129SDarrick J. Wong xfs_extlen_t blockcount, 115433ba6129SDarrick J. Wong xfs_fsblock_t *new_fsb, 115533ba6129SDarrick J. Wong xfs_extlen_t *new_len, 115633ba6129SDarrick J. Wong struct xfs_btree_cur **pcur) 115733ba6129SDarrick J. Wong { 115833ba6129SDarrick J. Wong struct xfs_mount *mp = tp->t_mountp; 115933ba6129SDarrick J. Wong struct xfs_btree_cur *rcur; 116033ba6129SDarrick J. Wong struct xfs_buf *agbp = NULL; 116133ba6129SDarrick J. Wong int error = 0; 116233ba6129SDarrick J. Wong xfs_agblock_t bno; 116333ba6129SDarrick J. Wong xfs_agblock_t new_agbno; 116433ba6129SDarrick J. Wong unsigned long nr_ops = 0; 116533ba6129SDarrick J. Wong int shape_changes = 0; 1166a81a0621SDave Chinner struct xfs_perag *pag; 116733ba6129SDarrick J. Wong 1168a81a0621SDave Chinner pag = xfs_perag_get(mp, XFS_FSB_TO_AGNO(mp, startblock)); 116933ba6129SDarrick J. Wong bno = XFS_FSB_TO_AGBNO(mp, startblock); 117033ba6129SDarrick J. Wong 117133ba6129SDarrick J. Wong trace_xfs_refcount_deferred(mp, XFS_FSB_TO_AGNO(mp, startblock), 117233ba6129SDarrick J. Wong type, XFS_FSB_TO_AGBNO(mp, startblock), 117333ba6129SDarrick J. Wong blockcount); 117433ba6129SDarrick J. Wong 1175a81a0621SDave Chinner if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_REFCOUNT_FINISH_ONE)) { 1176a81a0621SDave Chinner error = -EIO; 1177a81a0621SDave Chinner goto out_drop; 1178a81a0621SDave Chinner } 117933ba6129SDarrick J. Wong 118033ba6129SDarrick J. Wong /* 118133ba6129SDarrick J. Wong * If we haven't gotten a cursor or the cursor AG doesn't match 118233ba6129SDarrick J. Wong * the startblock, get one now. 118333ba6129SDarrick J. Wong */ 118433ba6129SDarrick J. Wong rcur = *pcur; 1185a81a0621SDave Chinner if (rcur != NULL && rcur->bc_ag.pag != pag) { 1186c4aa10d0SDave Chinner nr_ops = rcur->bc_ag.refc.nr_ops; 1187c4aa10d0SDave Chinner shape_changes = rcur->bc_ag.refc.shape_changes; 118833ba6129SDarrick J. Wong xfs_refcount_finish_one_cleanup(tp, rcur, 0); 118933ba6129SDarrick J. Wong rcur = NULL; 119033ba6129SDarrick J. Wong *pcur = NULL; 119133ba6129SDarrick J. Wong } 119233ba6129SDarrick J. Wong if (rcur == NULL) { 119308d3e84fSDave Chinner error = xfs_alloc_read_agf(pag, tp, XFS_ALLOC_FLAG_FREEING, 119408d3e84fSDave Chinner &agbp); 119533ba6129SDarrick J. Wong if (error) 1196a81a0621SDave Chinner goto out_drop; 119733ba6129SDarrick J. Wong 1198a81a0621SDave Chinner rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag); 1199c4aa10d0SDave Chinner rcur->bc_ag.refc.nr_ops = nr_ops; 1200c4aa10d0SDave Chinner rcur->bc_ag.refc.shape_changes = shape_changes; 120133ba6129SDarrick J. Wong } 120233ba6129SDarrick J. Wong *pcur = rcur; 120333ba6129SDarrick J. Wong 120433ba6129SDarrick J. Wong switch (type) { 120533ba6129SDarrick J. Wong case XFS_REFCOUNT_INCREASE: 120633ba6129SDarrick J. Wong error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno, 1207c04c51c5SDarrick J. Wong new_len, XFS_REFCOUNT_ADJUST_INCREASE); 1208a81a0621SDave Chinner *new_fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, new_agbno); 120933ba6129SDarrick J. Wong break; 121033ba6129SDarrick J. Wong case XFS_REFCOUNT_DECREASE: 121133ba6129SDarrick J. Wong error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno, 1212c04c51c5SDarrick J. Wong new_len, XFS_REFCOUNT_ADJUST_DECREASE); 1213a81a0621SDave Chinner *new_fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, new_agbno); 121433ba6129SDarrick J. Wong break; 1215174edb0eSDarrick J. Wong case XFS_REFCOUNT_ALLOC_COW: 1216174edb0eSDarrick J. Wong *new_fsb = startblock + blockcount; 1217174edb0eSDarrick J. Wong *new_len = 0; 12180f37d178SBrian Foster error = __xfs_refcount_cow_alloc(rcur, bno, blockcount); 1219174edb0eSDarrick J. Wong break; 1220174edb0eSDarrick J. Wong case XFS_REFCOUNT_FREE_COW: 1221174edb0eSDarrick J. Wong *new_fsb = startblock + blockcount; 1222174edb0eSDarrick J. Wong *new_len = 0; 12230f37d178SBrian Foster error = __xfs_refcount_cow_free(rcur, bno, blockcount); 1224174edb0eSDarrick J. Wong break; 122533ba6129SDarrick J. Wong default: 122633ba6129SDarrick J. Wong ASSERT(0); 122733ba6129SDarrick J. Wong error = -EFSCORRUPTED; 122833ba6129SDarrick J. Wong } 122933ba6129SDarrick J. Wong if (!error && *new_len > 0) 1230a81a0621SDave Chinner trace_xfs_refcount_finish_one_leftover(mp, pag->pag_agno, type, 123133ba6129SDarrick J. Wong bno, blockcount, new_agbno, *new_len); 1232a81a0621SDave Chinner out_drop: 1233a81a0621SDave Chinner xfs_perag_put(pag); 123433ba6129SDarrick J. Wong return error; 123533ba6129SDarrick J. Wong } 123633ba6129SDarrick J. Wong 123733ba6129SDarrick J. Wong /* 123833ba6129SDarrick J. Wong * Record a refcount intent for later processing. 123933ba6129SDarrick J. Wong */ 124074b4c5d4SDarrick J. Wong static void 124133ba6129SDarrick J. Wong __xfs_refcount_add( 12420f37d178SBrian Foster struct xfs_trans *tp, 124333ba6129SDarrick J. Wong enum xfs_refcount_intent_type type, 124433ba6129SDarrick J. Wong xfs_fsblock_t startblock, 124533ba6129SDarrick J. Wong xfs_extlen_t blockcount) 124633ba6129SDarrick J. Wong { 124733ba6129SDarrick J. Wong struct xfs_refcount_intent *ri; 124833ba6129SDarrick J. Wong 12490f37d178SBrian Foster trace_xfs_refcount_defer(tp->t_mountp, 12500f37d178SBrian Foster XFS_FSB_TO_AGNO(tp->t_mountp, startblock), 12510f37d178SBrian Foster type, XFS_FSB_TO_AGBNO(tp->t_mountp, startblock), 125233ba6129SDarrick J. Wong blockcount); 125333ba6129SDarrick J. Wong 1254f3c799c2SDarrick J. Wong ri = kmem_cache_alloc(xfs_refcount_intent_cache, 1255f3c799c2SDarrick J. Wong GFP_NOFS | __GFP_NOFAIL); 125633ba6129SDarrick J. Wong INIT_LIST_HEAD(&ri->ri_list); 125733ba6129SDarrick J. Wong ri->ri_type = type; 125833ba6129SDarrick J. Wong ri->ri_startblock = startblock; 125933ba6129SDarrick J. Wong ri->ri_blockcount = blockcount; 126033ba6129SDarrick J. Wong 12610f37d178SBrian Foster xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_REFCOUNT, &ri->ri_list); 126233ba6129SDarrick J. Wong } 126333ba6129SDarrick J. Wong 126433ba6129SDarrick J. Wong /* 126533ba6129SDarrick J. Wong * Increase the reference count of the blocks backing a file's extent. 126633ba6129SDarrick J. Wong */ 126774b4c5d4SDarrick J. Wong void 126833ba6129SDarrick J. Wong xfs_refcount_increase_extent( 12690f37d178SBrian Foster struct xfs_trans *tp, 127033ba6129SDarrick J. Wong struct xfs_bmbt_irec *PREV) 127133ba6129SDarrick J. Wong { 1272ebd9027dSDave Chinner if (!xfs_has_reflink(tp->t_mountp)) 127374b4c5d4SDarrick J. Wong return; 127433ba6129SDarrick J. Wong 127574b4c5d4SDarrick J. Wong __xfs_refcount_add(tp, XFS_REFCOUNT_INCREASE, PREV->br_startblock, 127674b4c5d4SDarrick J. Wong PREV->br_blockcount); 127733ba6129SDarrick J. Wong } 127833ba6129SDarrick J. Wong 127933ba6129SDarrick J. Wong /* 128033ba6129SDarrick J. Wong * Decrease the reference count of the blocks backing a file's extent. 128133ba6129SDarrick J. Wong */ 128274b4c5d4SDarrick J. Wong void 128333ba6129SDarrick J. Wong xfs_refcount_decrease_extent( 12840f37d178SBrian Foster struct xfs_trans *tp, 128533ba6129SDarrick J. Wong struct xfs_bmbt_irec *PREV) 128633ba6129SDarrick J. Wong { 1287ebd9027dSDave Chinner if (!xfs_has_reflink(tp->t_mountp)) 128874b4c5d4SDarrick J. Wong return; 128933ba6129SDarrick J. Wong 129074b4c5d4SDarrick J. Wong __xfs_refcount_add(tp, XFS_REFCOUNT_DECREASE, PREV->br_startblock, 129174b4c5d4SDarrick J. Wong PREV->br_blockcount); 129233ba6129SDarrick J. Wong } 1293350a27a6SDarrick J. Wong 1294350a27a6SDarrick J. Wong /* 1295350a27a6SDarrick J. Wong * Given an AG extent, find the lowest-numbered run of shared blocks 1296350a27a6SDarrick J. Wong * within that range and return the range in fbno/flen. If 1297350a27a6SDarrick J. Wong * find_end_of_shared is set, return the longest contiguous extent of 1298350a27a6SDarrick J. Wong * shared blocks; if not, just return the first extent we find. If no 1299350a27a6SDarrick J. Wong * shared blocks are found, fbno and flen will be set to NULLAGBLOCK 1300350a27a6SDarrick J. Wong * and 0, respectively. 1301350a27a6SDarrick J. Wong */ 1302350a27a6SDarrick J. Wong int 1303350a27a6SDarrick J. Wong xfs_refcount_find_shared( 1304350a27a6SDarrick J. Wong struct xfs_btree_cur *cur, 1305350a27a6SDarrick J. Wong xfs_agblock_t agbno, 1306350a27a6SDarrick J. Wong xfs_extlen_t aglen, 1307350a27a6SDarrick J. Wong xfs_agblock_t *fbno, 1308350a27a6SDarrick J. Wong xfs_extlen_t *flen, 1309350a27a6SDarrick J. Wong bool find_end_of_shared) 1310350a27a6SDarrick J. Wong { 1311350a27a6SDarrick J. Wong struct xfs_refcount_irec tmp; 1312350a27a6SDarrick J. Wong int i; 1313350a27a6SDarrick J. Wong int have; 1314350a27a6SDarrick J. Wong int error; 1315350a27a6SDarrick J. Wong 131650f02fe3SDave Chinner trace_xfs_refcount_find_shared(cur->bc_mp, cur->bc_ag.pag->pag_agno, 1317350a27a6SDarrick J. Wong agbno, aglen); 1318350a27a6SDarrick J. Wong 1319350a27a6SDarrick J. Wong /* By default, skip the whole range */ 1320350a27a6SDarrick J. Wong *fbno = NULLAGBLOCK; 1321350a27a6SDarrick J. Wong *flen = 0; 1322350a27a6SDarrick J. Wong 1323350a27a6SDarrick J. Wong /* Try to find a refcount extent that crosses the start */ 1324350a27a6SDarrick J. Wong error = xfs_refcount_lookup_le(cur, agbno, &have); 1325350a27a6SDarrick J. Wong if (error) 1326350a27a6SDarrick J. Wong goto out_error; 1327350a27a6SDarrick J. Wong if (!have) { 1328350a27a6SDarrick J. Wong /* No left extent, look at the next one */ 1329350a27a6SDarrick J. Wong error = xfs_btree_increment(cur, 0, &have); 1330350a27a6SDarrick J. Wong if (error) 1331350a27a6SDarrick J. Wong goto out_error; 1332350a27a6SDarrick J. Wong if (!have) 1333350a27a6SDarrick J. Wong goto done; 1334350a27a6SDarrick J. Wong } 1335350a27a6SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &i); 1336350a27a6SDarrick J. Wong if (error) 1337350a27a6SDarrick J. Wong goto out_error; 1338f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) { 1339f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1340f9e03706SDarrick J. Wong goto out_error; 1341f9e03706SDarrick J. Wong } 1342350a27a6SDarrick J. Wong 1343350a27a6SDarrick J. Wong /* If the extent ends before the start, look at the next one */ 1344350a27a6SDarrick J. Wong if (tmp.rc_startblock + tmp.rc_blockcount <= agbno) { 1345350a27a6SDarrick J. Wong error = xfs_btree_increment(cur, 0, &have); 1346350a27a6SDarrick J. Wong if (error) 1347350a27a6SDarrick J. Wong goto out_error; 1348350a27a6SDarrick J. Wong if (!have) 1349350a27a6SDarrick J. Wong goto done; 1350350a27a6SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &i); 1351350a27a6SDarrick J. Wong if (error) 1352350a27a6SDarrick J. Wong goto out_error; 1353f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) { 1354f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1355f9e03706SDarrick J. Wong goto out_error; 1356f9e03706SDarrick J. Wong } 1357350a27a6SDarrick J. Wong } 1358350a27a6SDarrick J. Wong 1359350a27a6SDarrick J. Wong /* If the extent starts after the range we want, bail out */ 1360350a27a6SDarrick J. Wong if (tmp.rc_startblock >= agbno + aglen) 1361350a27a6SDarrick J. Wong goto done; 1362350a27a6SDarrick J. Wong 1363350a27a6SDarrick J. Wong /* We found the start of a shared extent! */ 1364350a27a6SDarrick J. Wong if (tmp.rc_startblock < agbno) { 1365350a27a6SDarrick J. Wong tmp.rc_blockcount -= (agbno - tmp.rc_startblock); 1366350a27a6SDarrick J. Wong tmp.rc_startblock = agbno; 1367350a27a6SDarrick J. Wong } 1368350a27a6SDarrick J. Wong 1369350a27a6SDarrick J. Wong *fbno = tmp.rc_startblock; 1370350a27a6SDarrick J. Wong *flen = min(tmp.rc_blockcount, agbno + aglen - *fbno); 1371350a27a6SDarrick J. Wong if (!find_end_of_shared) 1372350a27a6SDarrick J. Wong goto done; 1373350a27a6SDarrick J. Wong 1374350a27a6SDarrick J. Wong /* Otherwise, find the end of this shared extent */ 1375350a27a6SDarrick J. Wong while (*fbno + *flen < agbno + aglen) { 1376350a27a6SDarrick J. Wong error = xfs_btree_increment(cur, 0, &have); 1377350a27a6SDarrick J. Wong if (error) 1378350a27a6SDarrick J. Wong goto out_error; 1379350a27a6SDarrick J. Wong if (!have) 1380350a27a6SDarrick J. Wong break; 1381350a27a6SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &i); 1382350a27a6SDarrick J. Wong if (error) 1383350a27a6SDarrick J. Wong goto out_error; 1384f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) { 1385f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1386f9e03706SDarrick J. Wong goto out_error; 1387f9e03706SDarrick J. Wong } 1388350a27a6SDarrick J. Wong if (tmp.rc_startblock >= agbno + aglen || 1389350a27a6SDarrick J. Wong tmp.rc_startblock != *fbno + *flen) 1390350a27a6SDarrick J. Wong break; 1391350a27a6SDarrick J. Wong *flen = min(*flen + tmp.rc_blockcount, agbno + aglen - *fbno); 1392350a27a6SDarrick J. Wong } 1393350a27a6SDarrick J. Wong 1394350a27a6SDarrick J. Wong done: 1395350a27a6SDarrick J. Wong trace_xfs_refcount_find_shared_result(cur->bc_mp, 139650f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, *fbno, *flen); 1397350a27a6SDarrick J. Wong 1398350a27a6SDarrick J. Wong out_error: 1399350a27a6SDarrick J. Wong if (error) 1400350a27a6SDarrick J. Wong trace_xfs_refcount_find_shared_error(cur->bc_mp, 140150f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 1402350a27a6SDarrick J. Wong return error; 1403350a27a6SDarrick J. Wong } 1404174edb0eSDarrick J. Wong 1405174edb0eSDarrick J. Wong /* 1406174edb0eSDarrick J. Wong * Recovering CoW Blocks After a Crash 1407174edb0eSDarrick J. Wong * 1408174edb0eSDarrick J. Wong * Due to the way that the copy on write mechanism works, there's a window of 1409174edb0eSDarrick J. Wong * opportunity in which we can lose track of allocated blocks during a crash. 1410174edb0eSDarrick J. Wong * Because CoW uses delayed allocation in the in-core CoW fork, writeback 1411174edb0eSDarrick J. Wong * causes blocks to be allocated and stored in the CoW fork. The blocks are 1412174edb0eSDarrick J. Wong * no longer in the free space btree but are not otherwise recorded anywhere 1413174edb0eSDarrick J. Wong * until the write completes and the blocks are mapped into the file. A crash 1414174edb0eSDarrick J. Wong * in between allocation and remapping results in the replacement blocks being 1415174edb0eSDarrick J. Wong * lost. This situation is exacerbated by the CoW extent size hint because 1416174edb0eSDarrick J. Wong * allocations can hang around for long time. 1417174edb0eSDarrick J. Wong * 1418174edb0eSDarrick J. Wong * However, there is a place where we can record these allocations before they 1419174edb0eSDarrick J. Wong * become mappings -- the reference count btree. The btree does not record 1420174edb0eSDarrick J. Wong * extents with refcount == 1, so we can record allocations with a refcount of 1421174edb0eSDarrick J. Wong * 1. Blocks being used for CoW writeout cannot be shared, so there should be 1422174edb0eSDarrick J. Wong * no conflict with shared block records. These mappings should be created 1423174edb0eSDarrick J. Wong * when we allocate blocks to the CoW fork and deleted when they're removed 1424174edb0eSDarrick J. Wong * from the CoW fork. 1425174edb0eSDarrick J. Wong * 1426174edb0eSDarrick J. Wong * Minor nit: records for in-progress CoW allocations and records for shared 1427174edb0eSDarrick J. Wong * extents must never be merged, to preserve the property that (except for CoW 1428174edb0eSDarrick J. Wong * allocations) there are no refcount btree entries with refcount == 1. The 1429174edb0eSDarrick J. Wong * only time this could potentially happen is when unsharing a block that's 1430174edb0eSDarrick J. Wong * adjacent to CoW allocations, so we must be careful to avoid this. 1431174edb0eSDarrick J. Wong * 1432174edb0eSDarrick J. Wong * At mount time we recover lost CoW allocations by searching the refcount 1433174edb0eSDarrick J. Wong * btree for these refcount == 1 mappings. These represent CoW allocations 1434174edb0eSDarrick J. Wong * that were in progress at the time the filesystem went down, so we can free 1435174edb0eSDarrick J. Wong * them to get the space back. 1436174edb0eSDarrick J. Wong * 1437174edb0eSDarrick J. Wong * This mechanism is superior to creating EFIs for unmapped CoW extents for 1438174edb0eSDarrick J. Wong * several reasons -- first, EFIs pin the tail of the log and would have to be 1439174edb0eSDarrick J. Wong * periodically relogged to avoid filling up the log. Second, CoW completions 1440174edb0eSDarrick J. Wong * will have to file an EFD and create new EFIs for whatever remains in the 1441174edb0eSDarrick J. Wong * CoW fork; this partially takes care of (1) but extent-size reservations 1442174edb0eSDarrick J. Wong * will have to periodically relog even if there's no writeout in progress. 1443174edb0eSDarrick J. Wong * This can happen if the CoW extent size hint is set, which you really want. 1444174edb0eSDarrick J. Wong * Third, EFIs cannot currently be automatically relogged into newer 1445174edb0eSDarrick J. Wong * transactions to advance the log tail. Fourth, stuffing the log full of 1446174edb0eSDarrick J. Wong * EFIs places an upper bound on the number of CoW allocations that can be 1447174edb0eSDarrick J. Wong * held filesystem-wide at any given time. Recording them in the refcount 1448174edb0eSDarrick J. Wong * btree doesn't require us to maintain any state in memory and doesn't pin 1449174edb0eSDarrick J. Wong * the log. 1450174edb0eSDarrick J. Wong */ 1451174edb0eSDarrick J. Wong /* 1452174edb0eSDarrick J. Wong * Adjust the refcounts of CoW allocations. These allocations are "magic" 1453174edb0eSDarrick J. Wong * in that they're not referenced anywhere else in the filesystem, so we 1454174edb0eSDarrick J. Wong * stash them in the refcount btree with a refcount of 1 until either file 1455174edb0eSDarrick J. Wong * remapping (or CoW cancellation) happens. 1456174edb0eSDarrick J. Wong */ 1457174edb0eSDarrick J. Wong STATIC int 1458174edb0eSDarrick J. Wong xfs_refcount_adjust_cow_extents( 1459174edb0eSDarrick J. Wong struct xfs_btree_cur *cur, 1460174edb0eSDarrick J. Wong xfs_agblock_t agbno, 1461174edb0eSDarrick J. Wong xfs_extlen_t aglen, 1462a1f69417SEric Sandeen enum xfs_refc_adjust_op adj) 1463174edb0eSDarrick J. Wong { 1464174edb0eSDarrick J. Wong struct xfs_refcount_irec ext, tmp; 1465174edb0eSDarrick J. Wong int error; 1466174edb0eSDarrick J. Wong int found_rec, found_tmp; 1467174edb0eSDarrick J. Wong 1468174edb0eSDarrick J. Wong if (aglen == 0) 1469174edb0eSDarrick J. Wong return 0; 1470174edb0eSDarrick J. Wong 1471174edb0eSDarrick J. Wong /* Find any overlapping refcount records */ 1472174edb0eSDarrick J. Wong error = xfs_refcount_lookup_ge(cur, agbno, &found_rec); 1473174edb0eSDarrick J. Wong if (error) 1474174edb0eSDarrick J. Wong goto out_error; 1475174edb0eSDarrick J. Wong error = xfs_refcount_get_rec(cur, &ext, &found_rec); 1476174edb0eSDarrick J. Wong if (error) 1477174edb0eSDarrick J. Wong goto out_error; 1478174edb0eSDarrick J. Wong if (!found_rec) { 1479174edb0eSDarrick J. Wong ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks + 1480174edb0eSDarrick J. Wong XFS_REFC_COW_START; 1481174edb0eSDarrick J. Wong ext.rc_blockcount = 0; 1482174edb0eSDarrick J. Wong ext.rc_refcount = 0; 1483174edb0eSDarrick J. Wong } 1484174edb0eSDarrick J. Wong 1485174edb0eSDarrick J. Wong switch (adj) { 1486174edb0eSDarrick J. Wong case XFS_REFCOUNT_ADJUST_COW_ALLOC: 1487174edb0eSDarrick J. Wong /* Adding a CoW reservation, there should be nothing here. */ 1488f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, 1489f9e03706SDarrick J. Wong agbno + aglen > ext.rc_startblock)) { 1490f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1491f9e03706SDarrick J. Wong goto out_error; 1492f9e03706SDarrick J. Wong } 1493174edb0eSDarrick J. Wong 1494174edb0eSDarrick J. Wong tmp.rc_startblock = agbno; 1495174edb0eSDarrick J. Wong tmp.rc_blockcount = aglen; 1496174edb0eSDarrick J. Wong tmp.rc_refcount = 1; 1497174edb0eSDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 149850f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, &tmp); 1499174edb0eSDarrick J. Wong 1500174edb0eSDarrick J. Wong error = xfs_refcount_insert(cur, &tmp, 1501174edb0eSDarrick J. Wong &found_tmp); 1502174edb0eSDarrick J. Wong if (error) 1503174edb0eSDarrick J. Wong goto out_error; 1504f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_tmp != 1)) { 1505f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1506f9e03706SDarrick J. Wong goto out_error; 1507f9e03706SDarrick J. Wong } 1508174edb0eSDarrick J. Wong break; 1509174edb0eSDarrick J. Wong case XFS_REFCOUNT_ADJUST_COW_FREE: 1510174edb0eSDarrick J. Wong /* Removing a CoW reservation, there should be one extent. */ 1511f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_startblock != agbno)) { 1512f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1513f9e03706SDarrick J. Wong goto out_error; 1514f9e03706SDarrick J. Wong } 1515f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_blockcount != aglen)) { 1516f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1517f9e03706SDarrick J. Wong goto out_error; 1518f9e03706SDarrick J. Wong } 1519f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, ext.rc_refcount != 1)) { 1520f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1521f9e03706SDarrick J. Wong goto out_error; 1522f9e03706SDarrick J. Wong } 1523174edb0eSDarrick J. Wong 1524174edb0eSDarrick J. Wong ext.rc_refcount = 0; 1525174edb0eSDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 152650f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, &ext); 1527174edb0eSDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 1528174edb0eSDarrick J. Wong if (error) 1529174edb0eSDarrick J. Wong goto out_error; 1530f9e03706SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, found_rec != 1)) { 1531f9e03706SDarrick J. Wong error = -EFSCORRUPTED; 1532f9e03706SDarrick J. Wong goto out_error; 1533f9e03706SDarrick J. Wong } 1534174edb0eSDarrick J. Wong break; 1535174edb0eSDarrick J. Wong default: 1536174edb0eSDarrick J. Wong ASSERT(0); 1537174edb0eSDarrick J. Wong } 1538174edb0eSDarrick J. Wong 1539174edb0eSDarrick J. Wong return error; 1540174edb0eSDarrick J. Wong out_error: 1541174edb0eSDarrick J. Wong trace_xfs_refcount_modify_extent_error(cur->bc_mp, 154250f02fe3SDave Chinner cur->bc_ag.pag->pag_agno, error, _RET_IP_); 1543174edb0eSDarrick J. Wong return error; 1544174edb0eSDarrick J. Wong } 1545174edb0eSDarrick J. Wong 1546174edb0eSDarrick J. Wong /* 1547174edb0eSDarrick J. Wong * Add or remove refcount btree entries for CoW reservations. 1548174edb0eSDarrick J. Wong */ 1549174edb0eSDarrick J. Wong STATIC int 1550174edb0eSDarrick J. Wong xfs_refcount_adjust_cow( 1551174edb0eSDarrick J. Wong struct xfs_btree_cur *cur, 1552174edb0eSDarrick J. Wong xfs_agblock_t agbno, 1553174edb0eSDarrick J. Wong xfs_extlen_t aglen, 1554a1f69417SEric Sandeen enum xfs_refc_adjust_op adj) 1555174edb0eSDarrick J. Wong { 1556174edb0eSDarrick J. Wong bool shape_changed; 1557174edb0eSDarrick J. Wong int error; 1558174edb0eSDarrick J. Wong 1559174edb0eSDarrick J. Wong agbno += XFS_REFC_COW_START; 1560174edb0eSDarrick J. Wong 1561174edb0eSDarrick J. Wong /* 1562174edb0eSDarrick J. Wong * Ensure that no rcextents cross the boundary of the adjustment range. 1563174edb0eSDarrick J. Wong */ 1564174edb0eSDarrick J. Wong error = xfs_refcount_split_extent(cur, agbno, &shape_changed); 1565174edb0eSDarrick J. Wong if (error) 1566174edb0eSDarrick J. Wong goto out_error; 1567174edb0eSDarrick J. Wong 1568174edb0eSDarrick J. Wong error = xfs_refcount_split_extent(cur, agbno + aglen, &shape_changed); 1569174edb0eSDarrick J. Wong if (error) 1570174edb0eSDarrick J. Wong goto out_error; 1571174edb0eSDarrick J. Wong 1572174edb0eSDarrick J. Wong /* 1573174edb0eSDarrick J. Wong * Try to merge with the left or right extents of the range. 1574174edb0eSDarrick J. Wong */ 1575174edb0eSDarrick J. Wong error = xfs_refcount_merge_extents(cur, &agbno, &aglen, adj, 1576174edb0eSDarrick J. Wong XFS_FIND_RCEXT_COW, &shape_changed); 1577174edb0eSDarrick J. Wong if (error) 1578174edb0eSDarrick J. Wong goto out_error; 1579174edb0eSDarrick J. Wong 1580174edb0eSDarrick J. Wong /* Now that we've taken care of the ends, adjust the middle extents */ 1581a1f69417SEric Sandeen error = xfs_refcount_adjust_cow_extents(cur, agbno, aglen, adj); 1582174edb0eSDarrick J. Wong if (error) 1583174edb0eSDarrick J. Wong goto out_error; 1584174edb0eSDarrick J. Wong 1585174edb0eSDarrick J. Wong return 0; 1586174edb0eSDarrick J. Wong 1587174edb0eSDarrick J. Wong out_error: 158850f02fe3SDave Chinner trace_xfs_refcount_adjust_cow_error(cur->bc_mp, cur->bc_ag.pag->pag_agno, 1589174edb0eSDarrick J. Wong error, _RET_IP_); 1590174edb0eSDarrick J. Wong return error; 1591174edb0eSDarrick J. Wong } 1592174edb0eSDarrick J. Wong 1593174edb0eSDarrick J. Wong /* 1594174edb0eSDarrick J. Wong * Record a CoW allocation in the refcount btree. 1595174edb0eSDarrick J. Wong */ 1596174edb0eSDarrick J. Wong STATIC int 1597174edb0eSDarrick J. Wong __xfs_refcount_cow_alloc( 1598174edb0eSDarrick J. Wong struct xfs_btree_cur *rcur, 1599174edb0eSDarrick J. Wong xfs_agblock_t agbno, 16000f37d178SBrian Foster xfs_extlen_t aglen) 1601174edb0eSDarrick J. Wong { 160250f02fe3SDave Chinner trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, 1603174edb0eSDarrick J. Wong agbno, aglen); 1604174edb0eSDarrick J. Wong 1605174edb0eSDarrick J. Wong /* Add refcount btree reservation */ 16060525e952SDarrick J. Wong return xfs_refcount_adjust_cow(rcur, agbno, aglen, 1607a1f69417SEric Sandeen XFS_REFCOUNT_ADJUST_COW_ALLOC); 1608174edb0eSDarrick J. Wong } 1609174edb0eSDarrick J. Wong 1610174edb0eSDarrick J. Wong /* 1611174edb0eSDarrick J. Wong * Remove a CoW allocation from the refcount btree. 1612174edb0eSDarrick J. Wong */ 1613174edb0eSDarrick J. Wong STATIC int 1614174edb0eSDarrick J. Wong __xfs_refcount_cow_free( 1615174edb0eSDarrick J. Wong struct xfs_btree_cur *rcur, 1616174edb0eSDarrick J. Wong xfs_agblock_t agbno, 16170f37d178SBrian Foster xfs_extlen_t aglen) 1618174edb0eSDarrick J. Wong { 161950f02fe3SDave Chinner trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, 1620174edb0eSDarrick J. Wong agbno, aglen); 1621174edb0eSDarrick J. Wong 1622174edb0eSDarrick J. Wong /* Remove refcount btree reservation */ 16230525e952SDarrick J. Wong return xfs_refcount_adjust_cow(rcur, agbno, aglen, 1624a1f69417SEric Sandeen XFS_REFCOUNT_ADJUST_COW_FREE); 1625174edb0eSDarrick J. Wong } 1626174edb0eSDarrick J. Wong 1627174edb0eSDarrick J. Wong /* Record a CoW staging extent in the refcount btree. */ 162874b4c5d4SDarrick J. Wong void 1629174edb0eSDarrick J. Wong xfs_refcount_alloc_cow_extent( 16300f37d178SBrian Foster struct xfs_trans *tp, 1631174edb0eSDarrick J. Wong xfs_fsblock_t fsb, 1632174edb0eSDarrick J. Wong xfs_extlen_t len) 1633174edb0eSDarrick J. Wong { 16340f37d178SBrian Foster struct xfs_mount *mp = tp->t_mountp; 16350525e952SDarrick J. Wong 1636ebd9027dSDave Chinner if (!xfs_has_reflink(mp)) 163774b4c5d4SDarrick J. Wong return; 1638174edb0eSDarrick J. Wong 163974b4c5d4SDarrick J. Wong __xfs_refcount_add(tp, XFS_REFCOUNT_ALLOC_COW, fsb, len); 16400525e952SDarrick J. Wong 16410525e952SDarrick J. Wong /* Add rmap entry */ 1642bc46ac64SDarrick J. Wong xfs_rmap_alloc_extent(tp, XFS_FSB_TO_AGNO(mp, fsb), 16430525e952SDarrick J. Wong XFS_FSB_TO_AGBNO(mp, fsb), len, XFS_RMAP_OWN_COW); 1644174edb0eSDarrick J. Wong } 1645174edb0eSDarrick J. Wong 1646174edb0eSDarrick J. Wong /* Forget a CoW staging event in the refcount btree. */ 164774b4c5d4SDarrick J. Wong void 1648174edb0eSDarrick J. Wong xfs_refcount_free_cow_extent( 16490f37d178SBrian Foster struct xfs_trans *tp, 1650174edb0eSDarrick J. Wong xfs_fsblock_t fsb, 1651174edb0eSDarrick J. Wong xfs_extlen_t len) 1652174edb0eSDarrick J. Wong { 16530f37d178SBrian Foster struct xfs_mount *mp = tp->t_mountp; 16540525e952SDarrick J. Wong 1655ebd9027dSDave Chinner if (!xfs_has_reflink(mp)) 165674b4c5d4SDarrick J. Wong return; 1657174edb0eSDarrick J. Wong 16580525e952SDarrick J. Wong /* Remove rmap entry */ 1659bc46ac64SDarrick J. Wong xfs_rmap_free_extent(tp, XFS_FSB_TO_AGNO(mp, fsb), 16600525e952SDarrick J. Wong XFS_FSB_TO_AGBNO(mp, fsb), len, XFS_RMAP_OWN_COW); 166174b4c5d4SDarrick J. Wong __xfs_refcount_add(tp, XFS_REFCOUNT_FREE_COW, fsb, len); 1662174edb0eSDarrick J. Wong } 1663174edb0eSDarrick J. Wong 1664174edb0eSDarrick J. Wong struct xfs_refcount_recovery { 1665174edb0eSDarrick J. Wong struct list_head rr_list; 1666174edb0eSDarrick J. Wong struct xfs_refcount_irec rr_rrec; 1667174edb0eSDarrick J. Wong }; 1668174edb0eSDarrick J. Wong 1669174edb0eSDarrick J. Wong /* Stuff an extent on the recovery list. */ 1670174edb0eSDarrick J. Wong STATIC int 1671174edb0eSDarrick J. Wong xfs_refcount_recover_extent( 1672174edb0eSDarrick J. Wong struct xfs_btree_cur *cur, 1673159eb69dSDarrick J. Wong const union xfs_btree_rec *rec, 1674174edb0eSDarrick J. Wong void *priv) 1675174edb0eSDarrick J. Wong { 1676174edb0eSDarrick J. Wong struct list_head *debris = priv; 1677174edb0eSDarrick J. Wong struct xfs_refcount_recovery *rr; 1678174edb0eSDarrick J. Wong 1679a71895c5SDarrick J. Wong if (XFS_IS_CORRUPT(cur->bc_mp, 1680a71895c5SDarrick J. Wong be32_to_cpu(rec->refc.rc_refcount) != 1)) 1681174edb0eSDarrick J. Wong return -EFSCORRUPTED; 1682174edb0eSDarrick J. Wong 1683707e0ddaSTetsuo Handa rr = kmem_alloc(sizeof(struct xfs_refcount_recovery), 0); 1684174edb0eSDarrick J. Wong xfs_refcount_btrec_to_irec(rec, &rr->rr_rrec); 1685174edb0eSDarrick J. Wong list_add_tail(&rr->rr_list, debris); 1686174edb0eSDarrick J. Wong 1687174edb0eSDarrick J. Wong return 0; 1688174edb0eSDarrick J. Wong } 1689174edb0eSDarrick J. Wong 1690174edb0eSDarrick J. Wong /* Find and remove leftover CoW reservations. */ 1691174edb0eSDarrick J. Wong int 1692174edb0eSDarrick J. Wong xfs_refcount_recover_cow_leftovers( 1693174edb0eSDarrick J. Wong struct xfs_mount *mp, 1694a81a0621SDave Chinner struct xfs_perag *pag) 1695174edb0eSDarrick J. Wong { 1696174edb0eSDarrick J. Wong struct xfs_trans *tp; 1697174edb0eSDarrick J. Wong struct xfs_btree_cur *cur; 1698174edb0eSDarrick J. Wong struct xfs_buf *agbp; 1699174edb0eSDarrick J. Wong struct xfs_refcount_recovery *rr, *n; 1700174edb0eSDarrick J. Wong struct list_head debris; 1701174edb0eSDarrick J. Wong union xfs_btree_irec low; 1702174edb0eSDarrick J. Wong union xfs_btree_irec high; 1703174edb0eSDarrick J. Wong xfs_fsblock_t fsb; 1704174edb0eSDarrick J. Wong xfs_agblock_t agbno; 1705174edb0eSDarrick J. Wong int error; 1706174edb0eSDarrick J. Wong 1707174edb0eSDarrick J. Wong if (mp->m_sb.sb_agblocks >= XFS_REFC_COW_START) 1708174edb0eSDarrick J. Wong return -EOPNOTSUPP; 1709174edb0eSDarrick J. Wong 17103ecb3ac7SDarrick J. Wong INIT_LIST_HEAD(&debris); 17113ecb3ac7SDarrick J. Wong 17123ecb3ac7SDarrick J. Wong /* 17133ecb3ac7SDarrick J. Wong * In this first part, we use an empty transaction to gather up 17143ecb3ac7SDarrick J. Wong * all the leftover CoW extents so that we can subsequently 17153ecb3ac7SDarrick J. Wong * delete them. The empty transaction is used to avoid 17163ecb3ac7SDarrick J. Wong * a buffer lock deadlock if there happens to be a loop in the 17173ecb3ac7SDarrick J. Wong * refcountbt because we're allowed to re-grab a buffer that is 17183ecb3ac7SDarrick J. Wong * already attached to our transaction. When we're done 17193ecb3ac7SDarrick J. Wong * recording the CoW debris we cancel the (empty) transaction 17203ecb3ac7SDarrick J. Wong * and everything goes away cleanly. 17213ecb3ac7SDarrick J. Wong */ 17223ecb3ac7SDarrick J. Wong error = xfs_trans_alloc_empty(mp, &tp); 1723174edb0eSDarrick J. Wong if (error) 1724174edb0eSDarrick J. Wong return error; 17253ecb3ac7SDarrick J. Wong 172608d3e84fSDave Chinner error = xfs_alloc_read_agf(pag, tp, 0, &agbp); 17273ecb3ac7SDarrick J. Wong if (error) 17283ecb3ac7SDarrick J. Wong goto out_trans; 1729a81a0621SDave Chinner cur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag); 1730174edb0eSDarrick J. Wong 1731174edb0eSDarrick J. Wong /* Find all the leftover CoW staging extents. */ 1732174edb0eSDarrick J. Wong memset(&low, 0, sizeof(low)); 1733174edb0eSDarrick J. Wong memset(&high, 0, sizeof(high)); 1734174edb0eSDarrick J. Wong low.rc.rc_startblock = XFS_REFC_COW_START; 1735174edb0eSDarrick J. Wong high.rc.rc_startblock = -1U; 1736174edb0eSDarrick J. Wong error = xfs_btree_query_range(cur, &low, &high, 1737174edb0eSDarrick J. Wong xfs_refcount_recover_extent, &debris); 1738ef97ef26SDarrick J. Wong xfs_btree_del_cursor(cur, error); 17393ecb3ac7SDarrick J. Wong xfs_trans_brelse(tp, agbp); 17403ecb3ac7SDarrick J. Wong xfs_trans_cancel(tp); 1741ef97ef26SDarrick J. Wong if (error) 1742ef97ef26SDarrick J. Wong goto out_free; 1743174edb0eSDarrick J. Wong 1744174edb0eSDarrick J. Wong /* Now iterate the list to free the leftovers */ 17453ecb3ac7SDarrick J. Wong list_for_each_entry_safe(rr, n, &debris, rr_list) { 1746174edb0eSDarrick J. Wong /* Set up transaction. */ 1747174edb0eSDarrick J. Wong error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, 0, 0, 0, &tp); 1748174edb0eSDarrick J. Wong if (error) 1749174edb0eSDarrick J. Wong goto out_free; 1750174edb0eSDarrick J. Wong 1751a81a0621SDave Chinner trace_xfs_refcount_recover_extent(mp, pag->pag_agno, 1752a81a0621SDave Chinner &rr->rr_rrec); 1753174edb0eSDarrick J. Wong 1754174edb0eSDarrick J. Wong /* Free the orphan record */ 1755174edb0eSDarrick J. Wong agbno = rr->rr_rrec.rc_startblock - XFS_REFC_COW_START; 1756a81a0621SDave Chinner fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, agbno); 175774b4c5d4SDarrick J. Wong xfs_refcount_free_cow_extent(tp, fsb, 1758174edb0eSDarrick J. Wong rr->rr_rrec.rc_blockcount); 1759174edb0eSDarrick J. Wong 1760174edb0eSDarrick J. Wong /* Free the block. */ 1761c201d9caSDarrick J. Wong xfs_free_extent_later(tp, fsb, rr->rr_rrec.rc_blockcount, NULL); 1762174edb0eSDarrick J. Wong 1763174edb0eSDarrick J. Wong error = xfs_trans_commit(tp); 1764174edb0eSDarrick J. Wong if (error) 1765174edb0eSDarrick J. Wong goto out_free; 17663ecb3ac7SDarrick J. Wong 17673ecb3ac7SDarrick J. Wong list_del(&rr->rr_list); 17683ecb3ac7SDarrick J. Wong kmem_free(rr); 17696f97077fSDarrick J. Wong } 1770174edb0eSDarrick J. Wong 17713ecb3ac7SDarrick J. Wong return error; 17723ecb3ac7SDarrick J. Wong out_trans: 17733ecb3ac7SDarrick J. Wong xfs_trans_cancel(tp); 1774174edb0eSDarrick J. Wong out_free: 1775174edb0eSDarrick J. Wong /* Free the leftover list */ 1776174edb0eSDarrick J. Wong list_for_each_entry_safe(rr, n, &debris, rr_list) { 1777174edb0eSDarrick J. Wong list_del(&rr->rr_list); 1778174edb0eSDarrick J. Wong kmem_free(rr); 1779174edb0eSDarrick J. Wong } 1780174edb0eSDarrick J. Wong return error; 1781174edb0eSDarrick J. Wong } 178249db55ecSDarrick J. Wong 178349db55ecSDarrick J. Wong /* Is there a record covering a given extent? */ 178449db55ecSDarrick J. Wong int 178549db55ecSDarrick J. Wong xfs_refcount_has_record( 178649db55ecSDarrick J. Wong struct xfs_btree_cur *cur, 178749db55ecSDarrick J. Wong xfs_agblock_t bno, 178849db55ecSDarrick J. Wong xfs_extlen_t len, 178949db55ecSDarrick J. Wong bool *exists) 179049db55ecSDarrick J. Wong { 179149db55ecSDarrick J. Wong union xfs_btree_irec low; 179249db55ecSDarrick J. Wong union xfs_btree_irec high; 179349db55ecSDarrick J. Wong 179449db55ecSDarrick J. Wong memset(&low, 0, sizeof(low)); 179549db55ecSDarrick J. Wong low.rc.rc_startblock = bno; 179649db55ecSDarrick J. Wong memset(&high, 0xFF, sizeof(high)); 179749db55ecSDarrick J. Wong high.rc.rc_startblock = bno + len - 1; 179849db55ecSDarrick J. Wong 179949db55ecSDarrick J. Wong return xfs_btree_has_record(cur, &low, &high, exists); 180049db55ecSDarrick J. Wong } 1801f3c799c2SDarrick J. Wong 1802f3c799c2SDarrick J. Wong int __init 1803f3c799c2SDarrick J. Wong xfs_refcount_intent_init_cache(void) 1804f3c799c2SDarrick J. Wong { 1805f3c799c2SDarrick J. Wong xfs_refcount_intent_cache = kmem_cache_create("xfs_refc_intent", 1806f3c799c2SDarrick J. Wong sizeof(struct xfs_refcount_intent), 1807f3c799c2SDarrick J. Wong 0, 0, NULL); 1808f3c799c2SDarrick J. Wong 1809f3c799c2SDarrick J. Wong return xfs_refcount_intent_cache != NULL ? 0 : -ENOMEM; 1810f3c799c2SDarrick J. Wong } 1811f3c799c2SDarrick J. Wong 1812f3c799c2SDarrick J. Wong void 1813f3c799c2SDarrick J. Wong xfs_refcount_intent_destroy_cache(void) 1814f3c799c2SDarrick J. Wong { 1815f3c799c2SDarrick J. Wong kmem_cache_destroy(xfs_refcount_intent_cache); 1816f3c799c2SDarrick J. Wong xfs_refcount_intent_cache = NULL; 1817f3c799c2SDarrick J. Wong } 1818