1bdf28630SDarrick J. Wong /* 2bdf28630SDarrick J. Wong * Copyright (C) 2016 Oracle. All Rights Reserved. 3bdf28630SDarrick J. Wong * 4bdf28630SDarrick J. Wong * Author: Darrick J. Wong <darrick.wong@oracle.com> 5bdf28630SDarrick J. Wong * 6bdf28630SDarrick J. Wong * This program is free software; you can redistribute it and/or 7bdf28630SDarrick J. Wong * modify it under the terms of the GNU General Public License 8bdf28630SDarrick J. Wong * as published by the Free Software Foundation; either version 2 9bdf28630SDarrick J. Wong * of the License, or (at your option) any later version. 10bdf28630SDarrick J. Wong * 11bdf28630SDarrick J. Wong * This program is distributed in the hope that it would be useful, 12bdf28630SDarrick J. Wong * but WITHOUT ANY WARRANTY; without even the implied warranty of 13bdf28630SDarrick J. Wong * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14bdf28630SDarrick J. Wong * GNU General Public License for more details. 15bdf28630SDarrick J. Wong * 16bdf28630SDarrick J. Wong * You should have received a copy of the GNU General Public License 17bdf28630SDarrick J. Wong * along with this program; if not, write the Free Software Foundation, 18bdf28630SDarrick J. Wong * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 19bdf28630SDarrick J. Wong */ 20bdf28630SDarrick J. Wong #include "xfs.h" 21bdf28630SDarrick J. Wong #include "xfs_fs.h" 22bdf28630SDarrick J. Wong #include "xfs_shared.h" 23bdf28630SDarrick J. Wong #include "xfs_format.h" 24bdf28630SDarrick J. Wong #include "xfs_log_format.h" 25bdf28630SDarrick J. Wong #include "xfs_trans_resv.h" 26bdf28630SDarrick J. Wong #include "xfs_sb.h" 27bdf28630SDarrick J. Wong #include "xfs_mount.h" 28bdf28630SDarrick J. Wong #include "xfs_defer.h" 29bdf28630SDarrick J. Wong #include "xfs_btree.h" 30bdf28630SDarrick J. Wong #include "xfs_bmap.h" 31bdf28630SDarrick J. Wong #include "xfs_refcount_btree.h" 32bdf28630SDarrick J. Wong #include "xfs_alloc.h" 33bdf28630SDarrick J. Wong #include "xfs_error.h" 34bdf28630SDarrick J. Wong #include "xfs_trace.h" 35bdf28630SDarrick J. Wong #include "xfs_cksum.h" 36bdf28630SDarrick J. Wong #include "xfs_trans.h" 37bdf28630SDarrick J. Wong #include "xfs_bit.h" 38bdf28630SDarrick J. Wong #include "xfs_refcount.h" 39bdf28630SDarrick J. Wong 4031727258SDarrick J. Wong /* Allowable refcount adjustment amounts. */ 4131727258SDarrick J. Wong enum xfs_refc_adjust_op { 4231727258SDarrick J. Wong XFS_REFCOUNT_ADJUST_INCREASE = 1, 4331727258SDarrick J. Wong XFS_REFCOUNT_ADJUST_DECREASE = -1, 4431727258SDarrick J. Wong }; 4531727258SDarrick J. Wong 46bdf28630SDarrick J. Wong /* 47bdf28630SDarrick J. Wong * Look up the first record less than or equal to [bno, len] in the btree 48bdf28630SDarrick J. Wong * given by cur. 49bdf28630SDarrick J. Wong */ 50bdf28630SDarrick J. Wong int 51bdf28630SDarrick J. Wong xfs_refcount_lookup_le( 52bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 53bdf28630SDarrick J. Wong xfs_agblock_t bno, 54bdf28630SDarrick J. Wong int *stat) 55bdf28630SDarrick J. Wong { 56bdf28630SDarrick J. Wong trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_private.a.agno, bno, 57bdf28630SDarrick J. Wong XFS_LOOKUP_LE); 58bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_startblock = bno; 59bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_blockcount = 0; 60bdf28630SDarrick J. Wong return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat); 61bdf28630SDarrick J. Wong } 62bdf28630SDarrick J. Wong 63bdf28630SDarrick J. Wong /* 64bdf28630SDarrick J. Wong * Look up the first record greater than or equal to [bno, len] in the btree 65bdf28630SDarrick J. Wong * given by cur. 66bdf28630SDarrick J. Wong */ 67bdf28630SDarrick J. Wong int 68bdf28630SDarrick J. Wong xfs_refcount_lookup_ge( 69bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 70bdf28630SDarrick J. Wong xfs_agblock_t bno, 71bdf28630SDarrick J. Wong int *stat) 72bdf28630SDarrick J. Wong { 73bdf28630SDarrick J. Wong trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_private.a.agno, bno, 74bdf28630SDarrick J. Wong XFS_LOOKUP_GE); 75bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_startblock = bno; 76bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_blockcount = 0; 77bdf28630SDarrick J. Wong return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat); 78bdf28630SDarrick J. Wong } 79bdf28630SDarrick J. Wong 80bdf28630SDarrick J. Wong /* 81bdf28630SDarrick J. Wong * Get the data from the pointed-to record. 82bdf28630SDarrick J. Wong */ 83bdf28630SDarrick J. Wong int 84bdf28630SDarrick J. Wong xfs_refcount_get_rec( 85bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 86bdf28630SDarrick J. Wong struct xfs_refcount_irec *irec, 87bdf28630SDarrick J. Wong int *stat) 88bdf28630SDarrick J. Wong { 89bdf28630SDarrick J. Wong union xfs_btree_rec *rec; 90bdf28630SDarrick J. Wong int error; 91bdf28630SDarrick J. Wong 92bdf28630SDarrick J. Wong error = xfs_btree_get_rec(cur, &rec, stat); 93bdf28630SDarrick J. Wong if (!error && *stat == 1) { 94bdf28630SDarrick J. Wong irec->rc_startblock = be32_to_cpu(rec->refc.rc_startblock); 95bdf28630SDarrick J. Wong irec->rc_blockcount = be32_to_cpu(rec->refc.rc_blockcount); 96bdf28630SDarrick J. Wong irec->rc_refcount = be32_to_cpu(rec->refc.rc_refcount); 97bdf28630SDarrick J. Wong trace_xfs_refcount_get(cur->bc_mp, cur->bc_private.a.agno, 98bdf28630SDarrick J. Wong irec); 99bdf28630SDarrick J. Wong } 100bdf28630SDarrick J. Wong return error; 101bdf28630SDarrick J. Wong } 102bdf28630SDarrick J. Wong 103bdf28630SDarrick J. Wong /* 104bdf28630SDarrick J. Wong * Update the record referred to by cur to the value given 105bdf28630SDarrick J. Wong * by [bno, len, refcount]. 106bdf28630SDarrick J. Wong * This either works (return 0) or gets an EFSCORRUPTED error. 107bdf28630SDarrick J. Wong */ 108bdf28630SDarrick J. Wong STATIC int 109bdf28630SDarrick J. Wong xfs_refcount_update( 110bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 111bdf28630SDarrick J. Wong struct xfs_refcount_irec *irec) 112bdf28630SDarrick J. Wong { 113bdf28630SDarrick J. Wong union xfs_btree_rec rec; 114bdf28630SDarrick J. Wong int error; 115bdf28630SDarrick J. Wong 116bdf28630SDarrick J. Wong trace_xfs_refcount_update(cur->bc_mp, cur->bc_private.a.agno, irec); 117bdf28630SDarrick J. Wong rec.refc.rc_startblock = cpu_to_be32(irec->rc_startblock); 118bdf28630SDarrick J. Wong rec.refc.rc_blockcount = cpu_to_be32(irec->rc_blockcount); 119bdf28630SDarrick J. Wong rec.refc.rc_refcount = cpu_to_be32(irec->rc_refcount); 120bdf28630SDarrick J. Wong error = xfs_btree_update(cur, &rec); 121bdf28630SDarrick J. Wong if (error) 122bdf28630SDarrick J. Wong trace_xfs_refcount_update_error(cur->bc_mp, 123bdf28630SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 124bdf28630SDarrick J. Wong return error; 125bdf28630SDarrick J. Wong } 126bdf28630SDarrick J. Wong 127bdf28630SDarrick J. Wong /* 128bdf28630SDarrick J. Wong * Insert the record referred to by cur to the value given 129bdf28630SDarrick J. Wong * by [bno, len, refcount]. 130bdf28630SDarrick J. Wong * This either works (return 0) or gets an EFSCORRUPTED error. 131bdf28630SDarrick J. Wong */ 132bdf28630SDarrick J. Wong STATIC int 133bdf28630SDarrick J. Wong xfs_refcount_insert( 134bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 135bdf28630SDarrick J. Wong struct xfs_refcount_irec *irec, 136bdf28630SDarrick J. Wong int *i) 137bdf28630SDarrick J. Wong { 138bdf28630SDarrick J. Wong int error; 139bdf28630SDarrick J. Wong 140bdf28630SDarrick J. Wong trace_xfs_refcount_insert(cur->bc_mp, cur->bc_private.a.agno, irec); 141bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_startblock = irec->rc_startblock; 142bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_blockcount = irec->rc_blockcount; 143bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_refcount = irec->rc_refcount; 144bdf28630SDarrick J. Wong error = xfs_btree_insert(cur, i); 145bdf28630SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, *i == 1, out_error); 146bdf28630SDarrick J. Wong out_error: 147bdf28630SDarrick J. Wong if (error) 148bdf28630SDarrick J. Wong trace_xfs_refcount_insert_error(cur->bc_mp, 149bdf28630SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 150bdf28630SDarrick J. Wong return error; 151bdf28630SDarrick J. Wong } 152bdf28630SDarrick J. Wong 153bdf28630SDarrick J. Wong /* 154bdf28630SDarrick J. Wong * Remove the record referred to by cur, then set the pointer to the spot 155bdf28630SDarrick J. Wong * where the record could be re-inserted, in case we want to increment or 156bdf28630SDarrick J. Wong * decrement the cursor. 157bdf28630SDarrick J. Wong * This either works (return 0) or gets an EFSCORRUPTED error. 158bdf28630SDarrick J. Wong */ 159bdf28630SDarrick J. Wong STATIC int 160bdf28630SDarrick J. Wong xfs_refcount_delete( 161bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 162bdf28630SDarrick J. Wong int *i) 163bdf28630SDarrick J. Wong { 164bdf28630SDarrick J. Wong struct xfs_refcount_irec irec; 165bdf28630SDarrick J. Wong int found_rec; 166bdf28630SDarrick J. Wong int error; 167bdf28630SDarrick J. Wong 168bdf28630SDarrick J. Wong error = xfs_refcount_get_rec(cur, &irec, &found_rec); 169bdf28630SDarrick J. Wong if (error) 170bdf28630SDarrick J. Wong goto out_error; 171bdf28630SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 172bdf28630SDarrick J. Wong trace_xfs_refcount_delete(cur->bc_mp, cur->bc_private.a.agno, &irec); 173bdf28630SDarrick J. Wong error = xfs_btree_delete(cur, i); 174bdf28630SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, *i == 1, out_error); 175bdf28630SDarrick J. Wong if (error) 176bdf28630SDarrick J. Wong goto out_error; 177bdf28630SDarrick J. Wong error = xfs_refcount_lookup_ge(cur, irec.rc_startblock, &found_rec); 178bdf28630SDarrick J. Wong out_error: 179bdf28630SDarrick J. Wong if (error) 180bdf28630SDarrick J. Wong trace_xfs_refcount_delete_error(cur->bc_mp, 181bdf28630SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 182bdf28630SDarrick J. Wong return error; 183bdf28630SDarrick J. Wong } 18431727258SDarrick J. Wong 18531727258SDarrick J. Wong /* 18631727258SDarrick J. Wong * Adjusting the Reference Count 18731727258SDarrick J. Wong * 18831727258SDarrick J. Wong * As stated elsewhere, the reference count btree (refcbt) stores 18931727258SDarrick J. Wong * >1 reference counts for extents of physical blocks. In this 19031727258SDarrick J. Wong * operation, we're either raising or lowering the reference count of 19131727258SDarrick J. Wong * some subrange stored in the tree: 19231727258SDarrick J. Wong * 19331727258SDarrick J. Wong * <------ adjustment range ------> 19431727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+--------- 19531727258SDarrick J. Wong * 2 | | 3 | 4 | |17| 55 | 10 19631727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+--------- 19731727258SDarrick J. Wong * X axis is physical blocks number; 19831727258SDarrick J. Wong * reference counts are the numbers inside the rectangles 19931727258SDarrick J. Wong * 20031727258SDarrick J. Wong * The first thing we need to do is to ensure that there are no 20131727258SDarrick J. Wong * refcount extents crossing either boundary of the range to be 20231727258SDarrick J. Wong * adjusted. For any extent that does cross a boundary, split it into 20331727258SDarrick J. Wong * two extents so that we can increment the refcount of one of the 20431727258SDarrick J. Wong * pieces later: 20531727258SDarrick J. Wong * 20631727258SDarrick J. Wong * <------ adjustment range ------> 20731727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+----+---- 20831727258SDarrick J. Wong * 2 | | 3 | 2 | |17| 55 | 10 | 10 20931727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+----+---- 21031727258SDarrick J. Wong * 21131727258SDarrick J. Wong * For this next step, let's assume that all the physical blocks in 21231727258SDarrick J. Wong * the adjustment range are mapped to a file and are therefore in use 21331727258SDarrick J. Wong * at least once. Therefore, we can infer that any gap in the 21431727258SDarrick J. Wong * refcount tree within the adjustment range represents a physical 21531727258SDarrick J. Wong * extent with refcount == 1: 21631727258SDarrick J. Wong * 21731727258SDarrick J. Wong * <------ adjustment range ------> 21831727258SDarrick J. Wong * ----+---+---+-----+-+--+--------+----+---- 21931727258SDarrick J. Wong * 2 |"1"| 3 | 2 |1|17| 55 | 10 | 10 22031727258SDarrick J. Wong * ----+---+---+-----+-+--+--------+----+---- 22131727258SDarrick J. Wong * ^ 22231727258SDarrick J. Wong * 22331727258SDarrick J. Wong * For each extent that falls within the interval range, figure out 22431727258SDarrick J. Wong * which extent is to the left or the right of that extent. Now we 22531727258SDarrick J. Wong * have a left, current, and right extent. If the new reference count 22631727258SDarrick J. Wong * of the center extent enables us to merge left, center, and right 22731727258SDarrick J. Wong * into one record covering all three, do so. If the center extent is 22831727258SDarrick J. Wong * at the left end of the range, abuts the left extent, and its new 22931727258SDarrick J. Wong * reference count matches the left extent's record, then merge them. 23031727258SDarrick J. Wong * If the center extent is at the right end of the range, abuts the 23131727258SDarrick J. Wong * right extent, and the reference counts match, merge those. In the 23231727258SDarrick J. Wong * example, we can left merge (assuming an increment operation): 23331727258SDarrick J. Wong * 23431727258SDarrick J. Wong * <------ adjustment range ------> 23531727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 23631727258SDarrick J. Wong * 2 | 3 | 2 |1|17| 55 | 10 | 10 23731727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 23831727258SDarrick J. Wong * ^ 23931727258SDarrick J. Wong * 24031727258SDarrick J. Wong * For all other extents within the range, adjust the reference count 24131727258SDarrick J. Wong * or delete it if the refcount falls below 2. If we were 24231727258SDarrick J. Wong * incrementing, the end result looks like this: 24331727258SDarrick J. Wong * 24431727258SDarrick J. Wong * <------ adjustment range ------> 24531727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 24631727258SDarrick J. Wong * 2 | 4 | 3 |2|18| 56 | 11 | 10 24731727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 24831727258SDarrick J. Wong * 24931727258SDarrick J. Wong * The result of a decrement operation looks as such: 25031727258SDarrick J. Wong * 25131727258SDarrick J. Wong * <------ adjustment range ------> 25231727258SDarrick J. Wong * ----+ +---+ +--+--------+----+---- 25331727258SDarrick J. Wong * 2 | | 2 | |16| 54 | 9 | 10 25431727258SDarrick J. Wong * ----+ +---+ +--+--------+----+---- 25531727258SDarrick J. Wong * DDDD 111111DD 25631727258SDarrick J. Wong * 25731727258SDarrick J. Wong * The blocks marked "D" are freed; the blocks marked "1" are only 25831727258SDarrick J. Wong * referenced once and therefore the record is removed from the 25931727258SDarrick J. Wong * refcount btree. 26031727258SDarrick J. Wong */ 26131727258SDarrick J. Wong 26231727258SDarrick J. Wong /* Next block after this extent. */ 26331727258SDarrick J. Wong static inline xfs_agblock_t 26431727258SDarrick J. Wong xfs_refc_next( 26531727258SDarrick J. Wong struct xfs_refcount_irec *rc) 26631727258SDarrick J. Wong { 26731727258SDarrick J. Wong return rc->rc_startblock + rc->rc_blockcount; 26831727258SDarrick J. Wong } 26931727258SDarrick J. Wong 27031727258SDarrick J. Wong /* 27131727258SDarrick J. Wong * Split a refcount extent that crosses agbno. 27231727258SDarrick J. Wong */ 27331727258SDarrick J. Wong STATIC int 27431727258SDarrick J. Wong xfs_refcount_split_extent( 27531727258SDarrick J. Wong struct xfs_btree_cur *cur, 27631727258SDarrick J. Wong xfs_agblock_t agbno, 27731727258SDarrick J. Wong bool *shape_changed) 27831727258SDarrick J. Wong { 27931727258SDarrick J. Wong struct xfs_refcount_irec rcext, tmp; 28031727258SDarrick J. Wong int found_rec; 28131727258SDarrick J. Wong int error; 28231727258SDarrick J. Wong 28331727258SDarrick J. Wong *shape_changed = false; 28431727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, agbno, &found_rec); 28531727258SDarrick J. Wong if (error) 28631727258SDarrick J. Wong goto out_error; 28731727258SDarrick J. Wong if (!found_rec) 28831727258SDarrick J. Wong return 0; 28931727258SDarrick J. Wong 29031727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &rcext, &found_rec); 29131727258SDarrick J. Wong if (error) 29231727258SDarrick J. Wong goto out_error; 29331727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 29431727258SDarrick J. Wong if (rcext.rc_startblock == agbno || xfs_refc_next(&rcext) <= agbno) 29531727258SDarrick J. Wong return 0; 29631727258SDarrick J. Wong 29731727258SDarrick J. Wong *shape_changed = true; 29831727258SDarrick J. Wong trace_xfs_refcount_split_extent(cur->bc_mp, cur->bc_private.a.agno, 29931727258SDarrick J. Wong &rcext, agbno); 30031727258SDarrick J. Wong 30131727258SDarrick J. Wong /* Establish the right extent. */ 30231727258SDarrick J. Wong tmp = rcext; 30331727258SDarrick J. Wong tmp.rc_startblock = agbno; 30431727258SDarrick J. Wong tmp.rc_blockcount -= (agbno - rcext.rc_startblock); 30531727258SDarrick J. Wong error = xfs_refcount_update(cur, &tmp); 30631727258SDarrick J. Wong if (error) 30731727258SDarrick J. Wong goto out_error; 30831727258SDarrick J. Wong 30931727258SDarrick J. Wong /* Insert the left extent. */ 31031727258SDarrick J. Wong tmp = rcext; 31131727258SDarrick J. Wong tmp.rc_blockcount = agbno - rcext.rc_startblock; 31231727258SDarrick J. Wong error = xfs_refcount_insert(cur, &tmp, &found_rec); 31331727258SDarrick J. Wong if (error) 31431727258SDarrick J. Wong goto out_error; 31531727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 31631727258SDarrick J. Wong return error; 31731727258SDarrick J. Wong 31831727258SDarrick J. Wong out_error: 31931727258SDarrick J. Wong trace_xfs_refcount_split_extent_error(cur->bc_mp, 32031727258SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 32131727258SDarrick J. Wong return error; 32231727258SDarrick J. Wong } 32331727258SDarrick J. Wong 32431727258SDarrick J. Wong /* 32531727258SDarrick J. Wong * Merge the left, center, and right extents. 32631727258SDarrick J. Wong */ 32731727258SDarrick J. Wong STATIC int 32831727258SDarrick J. Wong xfs_refcount_merge_center_extents( 32931727258SDarrick J. Wong struct xfs_btree_cur *cur, 33031727258SDarrick J. Wong struct xfs_refcount_irec *left, 33131727258SDarrick J. Wong struct xfs_refcount_irec *center, 33231727258SDarrick J. Wong struct xfs_refcount_irec *right, 33331727258SDarrick J. Wong unsigned long long extlen, 33431727258SDarrick J. Wong xfs_agblock_t *agbno, 33531727258SDarrick J. Wong xfs_extlen_t *aglen) 33631727258SDarrick J. Wong { 33731727258SDarrick J. Wong int error; 33831727258SDarrick J. Wong int found_rec; 33931727258SDarrick J. Wong 34031727258SDarrick J. Wong trace_xfs_refcount_merge_center_extents(cur->bc_mp, 34131727258SDarrick J. Wong cur->bc_private.a.agno, left, center, right); 34231727258SDarrick J. Wong 34331727258SDarrick J. Wong /* 34431727258SDarrick J. Wong * Make sure the center and right extents are not in the btree. 34531727258SDarrick J. Wong * If the center extent was synthesized, the first delete call 34631727258SDarrick J. Wong * removes the right extent and we skip the second deletion. 34731727258SDarrick J. Wong * If center and right were in the btree, then the first delete 34831727258SDarrick J. Wong * call removes the center and the second one removes the right 34931727258SDarrick J. Wong * extent. 35031727258SDarrick J. Wong */ 35131727258SDarrick J. Wong error = xfs_refcount_lookup_ge(cur, center->rc_startblock, 35231727258SDarrick J. Wong &found_rec); 35331727258SDarrick J. Wong if (error) 35431727258SDarrick J. Wong goto out_error; 35531727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 35631727258SDarrick J. Wong 35731727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 35831727258SDarrick J. Wong if (error) 35931727258SDarrick J. Wong goto out_error; 36031727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 36131727258SDarrick J. Wong 36231727258SDarrick J. Wong if (center->rc_refcount > 1) { 36331727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 36431727258SDarrick J. Wong if (error) 36531727258SDarrick J. Wong goto out_error; 36631727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, 36731727258SDarrick J. Wong out_error); 36831727258SDarrick J. Wong } 36931727258SDarrick J. Wong 37031727258SDarrick J. Wong /* Enlarge the left extent. */ 37131727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, left->rc_startblock, 37231727258SDarrick J. Wong &found_rec); 37331727258SDarrick J. Wong if (error) 37431727258SDarrick J. Wong goto out_error; 37531727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 37631727258SDarrick J. Wong 37731727258SDarrick J. Wong left->rc_blockcount = extlen; 37831727258SDarrick J. Wong error = xfs_refcount_update(cur, left); 37931727258SDarrick J. Wong if (error) 38031727258SDarrick J. Wong goto out_error; 38131727258SDarrick J. Wong 38231727258SDarrick J. Wong *aglen = 0; 38331727258SDarrick J. Wong return error; 38431727258SDarrick J. Wong 38531727258SDarrick J. Wong out_error: 38631727258SDarrick J. Wong trace_xfs_refcount_merge_center_extents_error(cur->bc_mp, 38731727258SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 38831727258SDarrick J. Wong return error; 38931727258SDarrick J. Wong } 39031727258SDarrick J. Wong 39131727258SDarrick J. Wong /* 39231727258SDarrick J. Wong * Merge with the left extent. 39331727258SDarrick J. Wong */ 39431727258SDarrick J. Wong STATIC int 39531727258SDarrick J. Wong xfs_refcount_merge_left_extent( 39631727258SDarrick J. Wong struct xfs_btree_cur *cur, 39731727258SDarrick J. Wong struct xfs_refcount_irec *left, 39831727258SDarrick J. Wong struct xfs_refcount_irec *cleft, 39931727258SDarrick J. Wong xfs_agblock_t *agbno, 40031727258SDarrick J. Wong xfs_extlen_t *aglen) 40131727258SDarrick J. Wong { 40231727258SDarrick J. Wong int error; 40331727258SDarrick J. Wong int found_rec; 40431727258SDarrick J. Wong 40531727258SDarrick J. Wong trace_xfs_refcount_merge_left_extent(cur->bc_mp, 40631727258SDarrick J. Wong cur->bc_private.a.agno, left, cleft); 40731727258SDarrick J. Wong 40831727258SDarrick J. Wong /* If the extent at agbno (cleft) wasn't synthesized, remove it. */ 40931727258SDarrick J. Wong if (cleft->rc_refcount > 1) { 41031727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, cleft->rc_startblock, 41131727258SDarrick J. Wong &found_rec); 41231727258SDarrick J. Wong if (error) 41331727258SDarrick J. Wong goto out_error; 41431727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, 41531727258SDarrick J. Wong out_error); 41631727258SDarrick J. Wong 41731727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 41831727258SDarrick J. Wong if (error) 41931727258SDarrick J. Wong goto out_error; 42031727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, 42131727258SDarrick J. Wong out_error); 42231727258SDarrick J. Wong } 42331727258SDarrick J. Wong 42431727258SDarrick J. Wong /* Enlarge the left extent. */ 42531727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, left->rc_startblock, 42631727258SDarrick J. Wong &found_rec); 42731727258SDarrick J. Wong if (error) 42831727258SDarrick J. Wong goto out_error; 42931727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 43031727258SDarrick J. Wong 43131727258SDarrick J. Wong left->rc_blockcount += cleft->rc_blockcount; 43231727258SDarrick J. Wong error = xfs_refcount_update(cur, left); 43331727258SDarrick J. Wong if (error) 43431727258SDarrick J. Wong goto out_error; 43531727258SDarrick J. Wong 43631727258SDarrick J. Wong *agbno += cleft->rc_blockcount; 43731727258SDarrick J. Wong *aglen -= cleft->rc_blockcount; 43831727258SDarrick J. Wong return error; 43931727258SDarrick J. Wong 44031727258SDarrick J. Wong out_error: 44131727258SDarrick J. Wong trace_xfs_refcount_merge_left_extent_error(cur->bc_mp, 44231727258SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 44331727258SDarrick J. Wong return error; 44431727258SDarrick J. Wong } 44531727258SDarrick J. Wong 44631727258SDarrick J. Wong /* 44731727258SDarrick J. Wong * Merge with the right extent. 44831727258SDarrick J. Wong */ 44931727258SDarrick J. Wong STATIC int 45031727258SDarrick J. Wong xfs_refcount_merge_right_extent( 45131727258SDarrick J. Wong struct xfs_btree_cur *cur, 45231727258SDarrick J. Wong struct xfs_refcount_irec *right, 45331727258SDarrick J. Wong struct xfs_refcount_irec *cright, 45431727258SDarrick J. Wong xfs_agblock_t *agbno, 45531727258SDarrick J. Wong xfs_extlen_t *aglen) 45631727258SDarrick J. Wong { 45731727258SDarrick J. Wong int error; 45831727258SDarrick J. Wong int found_rec; 45931727258SDarrick J. Wong 46031727258SDarrick J. Wong trace_xfs_refcount_merge_right_extent(cur->bc_mp, 46131727258SDarrick J. Wong cur->bc_private.a.agno, cright, right); 46231727258SDarrick J. Wong 46331727258SDarrick J. Wong /* 46431727258SDarrick J. Wong * If the extent ending at agbno+aglen (cright) wasn't synthesized, 46531727258SDarrick J. Wong * remove it. 46631727258SDarrick J. Wong */ 46731727258SDarrick J. Wong if (cright->rc_refcount > 1) { 46831727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, cright->rc_startblock, 46931727258SDarrick J. Wong &found_rec); 47031727258SDarrick J. Wong if (error) 47131727258SDarrick J. Wong goto out_error; 47231727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, 47331727258SDarrick J. Wong out_error); 47431727258SDarrick J. Wong 47531727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 47631727258SDarrick J. Wong if (error) 47731727258SDarrick J. Wong goto out_error; 47831727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, 47931727258SDarrick J. Wong out_error); 48031727258SDarrick J. Wong } 48131727258SDarrick J. Wong 48231727258SDarrick J. Wong /* Enlarge the right extent. */ 48331727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, right->rc_startblock, 48431727258SDarrick J. Wong &found_rec); 48531727258SDarrick J. Wong if (error) 48631727258SDarrick J. Wong goto out_error; 48731727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 48831727258SDarrick J. Wong 48931727258SDarrick J. Wong right->rc_startblock -= cright->rc_blockcount; 49031727258SDarrick J. Wong right->rc_blockcount += cright->rc_blockcount; 49131727258SDarrick J. Wong error = xfs_refcount_update(cur, right); 49231727258SDarrick J. Wong if (error) 49331727258SDarrick J. Wong goto out_error; 49431727258SDarrick J. Wong 49531727258SDarrick J. Wong *aglen -= cright->rc_blockcount; 49631727258SDarrick J. Wong return error; 49731727258SDarrick J. Wong 49831727258SDarrick J. Wong out_error: 49931727258SDarrick J. Wong trace_xfs_refcount_merge_right_extent_error(cur->bc_mp, 50031727258SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 50131727258SDarrick J. Wong return error; 50231727258SDarrick J. Wong } 50331727258SDarrick J. Wong 50431727258SDarrick J. Wong /* 50531727258SDarrick J. Wong * Find the left extent and the one after it (cleft). This function assumes 50631727258SDarrick J. Wong * that we've already split any extent crossing agbno. 50731727258SDarrick J. Wong */ 50831727258SDarrick J. Wong STATIC int 50931727258SDarrick J. Wong xfs_refcount_find_left_extents( 51031727258SDarrick J. Wong struct xfs_btree_cur *cur, 51131727258SDarrick J. Wong struct xfs_refcount_irec *left, 51231727258SDarrick J. Wong struct xfs_refcount_irec *cleft, 51331727258SDarrick J. Wong xfs_agblock_t agbno, 51431727258SDarrick J. Wong xfs_extlen_t aglen) 51531727258SDarrick J. Wong { 51631727258SDarrick J. Wong struct xfs_refcount_irec tmp; 51731727258SDarrick J. Wong int error; 51831727258SDarrick J. Wong int found_rec; 51931727258SDarrick J. Wong 52031727258SDarrick J. Wong left->rc_startblock = cleft->rc_startblock = NULLAGBLOCK; 52131727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, agbno - 1, &found_rec); 52231727258SDarrick J. Wong if (error) 52331727258SDarrick J. Wong goto out_error; 52431727258SDarrick J. Wong if (!found_rec) 52531727258SDarrick J. Wong return 0; 52631727258SDarrick J. Wong 52731727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 52831727258SDarrick J. Wong if (error) 52931727258SDarrick J. Wong goto out_error; 53031727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 53131727258SDarrick J. Wong 53231727258SDarrick J. Wong if (xfs_refc_next(&tmp) != agbno) 53331727258SDarrick J. Wong return 0; 53431727258SDarrick J. Wong /* We have a left extent; retrieve (or invent) the next right one */ 53531727258SDarrick J. Wong *left = tmp; 53631727258SDarrick J. Wong 53731727258SDarrick J. Wong error = xfs_btree_increment(cur, 0, &found_rec); 53831727258SDarrick J. Wong if (error) 53931727258SDarrick J. Wong goto out_error; 54031727258SDarrick J. Wong if (found_rec) { 54131727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 54231727258SDarrick J. Wong if (error) 54331727258SDarrick J. Wong goto out_error; 54431727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, 54531727258SDarrick J. Wong out_error); 54631727258SDarrick J. Wong 54731727258SDarrick J. Wong /* if tmp starts at the end of our range, just use that */ 54831727258SDarrick J. Wong if (tmp.rc_startblock == agbno) 54931727258SDarrick J. Wong *cleft = tmp; 55031727258SDarrick J. Wong else { 55131727258SDarrick J. Wong /* 55231727258SDarrick J. Wong * There's a gap in the refcntbt at the start of the 55331727258SDarrick J. Wong * range we're interested in (refcount == 1) so 55431727258SDarrick J. Wong * synthesize the implied extent and pass it back. 55531727258SDarrick J. Wong * We assume here that the agbno/aglen range was 55631727258SDarrick J. Wong * passed in from a data fork extent mapping and 55731727258SDarrick J. Wong * therefore is allocated to exactly one owner. 55831727258SDarrick J. Wong */ 55931727258SDarrick J. Wong cleft->rc_startblock = agbno; 56031727258SDarrick J. Wong cleft->rc_blockcount = min(aglen, 56131727258SDarrick J. Wong tmp.rc_startblock - agbno); 56231727258SDarrick J. Wong cleft->rc_refcount = 1; 56331727258SDarrick J. Wong } 56431727258SDarrick J. Wong } else { 56531727258SDarrick J. Wong /* 56631727258SDarrick J. Wong * No extents, so pretend that there's one covering the whole 56731727258SDarrick J. Wong * range. 56831727258SDarrick J. Wong */ 56931727258SDarrick J. Wong cleft->rc_startblock = agbno; 57031727258SDarrick J. Wong cleft->rc_blockcount = aglen; 57131727258SDarrick J. Wong cleft->rc_refcount = 1; 57231727258SDarrick J. Wong } 57331727258SDarrick J. Wong trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_private.a.agno, 57431727258SDarrick J. Wong left, cleft, agbno); 57531727258SDarrick J. Wong return error; 57631727258SDarrick J. Wong 57731727258SDarrick J. Wong out_error: 57831727258SDarrick J. Wong trace_xfs_refcount_find_left_extent_error(cur->bc_mp, 57931727258SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 58031727258SDarrick J. Wong return error; 58131727258SDarrick J. Wong } 58231727258SDarrick J. Wong 58331727258SDarrick J. Wong /* 58431727258SDarrick J. Wong * Find the right extent and the one before it (cright). This function 58531727258SDarrick J. Wong * assumes that we've already split any extents crossing agbno + aglen. 58631727258SDarrick J. Wong */ 58731727258SDarrick J. Wong STATIC int 58831727258SDarrick J. Wong xfs_refcount_find_right_extents( 58931727258SDarrick J. Wong struct xfs_btree_cur *cur, 59031727258SDarrick J. Wong struct xfs_refcount_irec *right, 59131727258SDarrick J. Wong struct xfs_refcount_irec *cright, 59231727258SDarrick J. Wong xfs_agblock_t agbno, 59331727258SDarrick J. Wong xfs_extlen_t aglen) 59431727258SDarrick J. Wong { 59531727258SDarrick J. Wong struct xfs_refcount_irec tmp; 59631727258SDarrick J. Wong int error; 59731727258SDarrick J. Wong int found_rec; 59831727258SDarrick J. Wong 59931727258SDarrick J. Wong right->rc_startblock = cright->rc_startblock = NULLAGBLOCK; 60031727258SDarrick J. Wong error = xfs_refcount_lookup_ge(cur, agbno + aglen, &found_rec); 60131727258SDarrick J. Wong if (error) 60231727258SDarrick J. Wong goto out_error; 60331727258SDarrick J. Wong if (!found_rec) 60431727258SDarrick J. Wong return 0; 60531727258SDarrick J. Wong 60631727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 60731727258SDarrick J. Wong if (error) 60831727258SDarrick J. Wong goto out_error; 60931727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 61031727258SDarrick J. Wong 61131727258SDarrick J. Wong if (tmp.rc_startblock != agbno + aglen) 61231727258SDarrick J. Wong return 0; 61331727258SDarrick J. Wong /* We have a right extent; retrieve (or invent) the next left one */ 61431727258SDarrick J. Wong *right = tmp; 61531727258SDarrick J. Wong 61631727258SDarrick J. Wong error = xfs_btree_decrement(cur, 0, &found_rec); 61731727258SDarrick J. Wong if (error) 61831727258SDarrick J. Wong goto out_error; 61931727258SDarrick J. Wong if (found_rec) { 62031727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 62131727258SDarrick J. Wong if (error) 62231727258SDarrick J. Wong goto out_error; 62331727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, 62431727258SDarrick J. Wong out_error); 62531727258SDarrick J. Wong 62631727258SDarrick J. Wong /* if tmp ends at the end of our range, just use that */ 62731727258SDarrick J. Wong if (xfs_refc_next(&tmp) == agbno + aglen) 62831727258SDarrick J. Wong *cright = tmp; 62931727258SDarrick J. Wong else { 63031727258SDarrick J. Wong /* 63131727258SDarrick J. Wong * There's a gap in the refcntbt at the end of the 63231727258SDarrick J. Wong * range we're interested in (refcount == 1) so 63331727258SDarrick J. Wong * create the implied extent and pass it back. 63431727258SDarrick J. Wong * We assume here that the agbno/aglen range was 63531727258SDarrick J. Wong * passed in from a data fork extent mapping and 63631727258SDarrick J. Wong * therefore is allocated to exactly one owner. 63731727258SDarrick J. Wong */ 63831727258SDarrick J. Wong cright->rc_startblock = max(agbno, xfs_refc_next(&tmp)); 63931727258SDarrick J. Wong cright->rc_blockcount = right->rc_startblock - 64031727258SDarrick J. Wong cright->rc_startblock; 64131727258SDarrick J. Wong cright->rc_refcount = 1; 64231727258SDarrick J. Wong } 64331727258SDarrick J. Wong } else { 64431727258SDarrick J. Wong /* 64531727258SDarrick J. Wong * No extents, so pretend that there's one covering the whole 64631727258SDarrick J. Wong * range. 64731727258SDarrick J. Wong */ 64831727258SDarrick J. Wong cright->rc_startblock = agbno; 64931727258SDarrick J. Wong cright->rc_blockcount = aglen; 65031727258SDarrick J. Wong cright->rc_refcount = 1; 65131727258SDarrick J. Wong } 65231727258SDarrick J. Wong trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_private.a.agno, 65331727258SDarrick J. Wong cright, right, agbno + aglen); 65431727258SDarrick J. Wong return error; 65531727258SDarrick J. Wong 65631727258SDarrick J. Wong out_error: 65731727258SDarrick J. Wong trace_xfs_refcount_find_right_extent_error(cur->bc_mp, 65831727258SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 65931727258SDarrick J. Wong return error; 66031727258SDarrick J. Wong } 66131727258SDarrick J. Wong 66231727258SDarrick J. Wong /* Is this extent valid? */ 66331727258SDarrick J. Wong static inline bool 66431727258SDarrick J. Wong xfs_refc_valid( 66531727258SDarrick J. Wong struct xfs_refcount_irec *rc) 66631727258SDarrick J. Wong { 66731727258SDarrick J. Wong return rc->rc_startblock != NULLAGBLOCK; 66831727258SDarrick J. Wong } 66931727258SDarrick J. Wong 67031727258SDarrick J. Wong /* 67131727258SDarrick J. Wong * Try to merge with any extents on the boundaries of the adjustment range. 67231727258SDarrick J. Wong */ 67331727258SDarrick J. Wong STATIC int 67431727258SDarrick J. Wong xfs_refcount_merge_extents( 67531727258SDarrick J. Wong struct xfs_btree_cur *cur, 67631727258SDarrick J. Wong xfs_agblock_t *agbno, 67731727258SDarrick J. Wong xfs_extlen_t *aglen, 67831727258SDarrick J. Wong enum xfs_refc_adjust_op adjust, 67931727258SDarrick J. Wong bool *shape_changed) 68031727258SDarrick J. Wong { 68131727258SDarrick J. Wong struct xfs_refcount_irec left = {0}, cleft = {0}; 68231727258SDarrick J. Wong struct xfs_refcount_irec cright = {0}, right = {0}; 68331727258SDarrick J. Wong int error; 68431727258SDarrick J. Wong unsigned long long ulen; 68531727258SDarrick J. Wong bool cequal; 68631727258SDarrick J. Wong 68731727258SDarrick J. Wong *shape_changed = false; 68831727258SDarrick J. Wong /* 68931727258SDarrick J. Wong * Find the extent just below agbno [left], just above agbno [cleft], 69031727258SDarrick J. Wong * just below (agbno + aglen) [cright], and just above (agbno + aglen) 69131727258SDarrick J. Wong * [right]. 69231727258SDarrick J. Wong */ 69331727258SDarrick J. Wong error = xfs_refcount_find_left_extents(cur, &left, &cleft, *agbno, 69431727258SDarrick J. Wong *aglen); 69531727258SDarrick J. Wong if (error) 69631727258SDarrick J. Wong return error; 69731727258SDarrick J. Wong error = xfs_refcount_find_right_extents(cur, &right, &cright, *agbno, 69831727258SDarrick J. Wong *aglen); 69931727258SDarrick J. Wong if (error) 70031727258SDarrick J. Wong return error; 70131727258SDarrick J. Wong 70231727258SDarrick J. Wong /* No left or right extent to merge; exit. */ 70331727258SDarrick J. Wong if (!xfs_refc_valid(&left) && !xfs_refc_valid(&right)) 70431727258SDarrick J. Wong return 0; 70531727258SDarrick J. Wong 70631727258SDarrick J. Wong cequal = (cleft.rc_startblock == cright.rc_startblock) && 70731727258SDarrick J. Wong (cleft.rc_blockcount == cright.rc_blockcount); 70831727258SDarrick J. Wong 70931727258SDarrick J. Wong /* Try to merge left, cleft, and right. cleft must == cright. */ 71031727258SDarrick J. Wong ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount + 71131727258SDarrick J. Wong right.rc_blockcount; 71231727258SDarrick J. Wong if (xfs_refc_valid(&left) && xfs_refc_valid(&right) && 71331727258SDarrick J. Wong xfs_refc_valid(&cleft) && xfs_refc_valid(&cright) && cequal && 71431727258SDarrick J. Wong left.rc_refcount == cleft.rc_refcount + adjust && 71531727258SDarrick J. Wong right.rc_refcount == cleft.rc_refcount + adjust && 71631727258SDarrick J. Wong ulen < MAXREFCEXTLEN) { 71731727258SDarrick J. Wong *shape_changed = true; 71831727258SDarrick J. Wong return xfs_refcount_merge_center_extents(cur, &left, &cleft, 71931727258SDarrick J. Wong &right, ulen, agbno, aglen); 72031727258SDarrick J. Wong } 72131727258SDarrick J. Wong 72231727258SDarrick J. Wong /* Try to merge left and cleft. */ 72331727258SDarrick J. Wong ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount; 72431727258SDarrick J. Wong if (xfs_refc_valid(&left) && xfs_refc_valid(&cleft) && 72531727258SDarrick J. Wong left.rc_refcount == cleft.rc_refcount + adjust && 72631727258SDarrick J. Wong ulen < MAXREFCEXTLEN) { 72731727258SDarrick J. Wong *shape_changed = true; 72831727258SDarrick J. Wong error = xfs_refcount_merge_left_extent(cur, &left, &cleft, 72931727258SDarrick J. Wong agbno, aglen); 73031727258SDarrick J. Wong if (error) 73131727258SDarrick J. Wong return error; 73231727258SDarrick J. Wong 73331727258SDarrick J. Wong /* 73431727258SDarrick J. Wong * If we just merged left + cleft and cleft == cright, 73531727258SDarrick J. Wong * we no longer have a cright to merge with right. We're done. 73631727258SDarrick J. Wong */ 73731727258SDarrick J. Wong if (cequal) 73831727258SDarrick J. Wong return 0; 73931727258SDarrick J. Wong } 74031727258SDarrick J. Wong 74131727258SDarrick J. Wong /* Try to merge cright and right. */ 74231727258SDarrick J. Wong ulen = (unsigned long long)right.rc_blockcount + cright.rc_blockcount; 74331727258SDarrick J. Wong if (xfs_refc_valid(&right) && xfs_refc_valid(&cright) && 74431727258SDarrick J. Wong right.rc_refcount == cright.rc_refcount + adjust && 74531727258SDarrick J. Wong ulen < MAXREFCEXTLEN) { 74631727258SDarrick J. Wong *shape_changed = true; 74731727258SDarrick J. Wong return xfs_refcount_merge_right_extent(cur, &right, &cright, 74831727258SDarrick J. Wong agbno, aglen); 74931727258SDarrick J. Wong } 75031727258SDarrick J. Wong 75131727258SDarrick J. Wong return error; 75231727258SDarrick J. Wong } 75331727258SDarrick J. Wong 75431727258SDarrick J. Wong /* 75531727258SDarrick J. Wong * While we're adjusting the refcounts records of an extent, we have 75631727258SDarrick J. Wong * to keep an eye on the number of extents we're dirtying -- run too 75731727258SDarrick J. Wong * many in a single transaction and we'll exceed the transaction's 75831727258SDarrick J. Wong * reservation and crash the fs. Each record adds 12 bytes to the 75931727258SDarrick J. Wong * log (plus any key updates) so we'll conservatively assume 24 bytes 76031727258SDarrick J. Wong * per record. We must also leave space for btree splits on both ends 76131727258SDarrick J. Wong * of the range and space for the CUD and a new CUI. 76231727258SDarrick J. Wong * 76331727258SDarrick J. Wong * XXX: This is a pretty hand-wavy estimate. The penalty for guessing 76431727258SDarrick J. Wong * true incorrectly is a shutdown FS; the penalty for guessing false 76531727258SDarrick J. Wong * incorrectly is more transaction rolls than might be necessary. 76631727258SDarrick J. Wong * Be conservative here. 76731727258SDarrick J. Wong */ 76831727258SDarrick J. Wong static bool 76931727258SDarrick J. Wong xfs_refcount_still_have_space( 77031727258SDarrick J. Wong struct xfs_btree_cur *cur) 77131727258SDarrick J. Wong { 77231727258SDarrick J. Wong unsigned long overhead; 77331727258SDarrick J. Wong 77431727258SDarrick J. Wong overhead = cur->bc_private.a.priv.refc.shape_changes * 77531727258SDarrick J. Wong xfs_allocfree_log_count(cur->bc_mp, 1); 77631727258SDarrick J. Wong overhead *= cur->bc_mp->m_sb.sb_blocksize; 77731727258SDarrick J. Wong 77831727258SDarrick J. Wong /* 77931727258SDarrick J. Wong * Only allow 2 refcount extent updates per transaction if the 78031727258SDarrick J. Wong * refcount continue update "error" has been injected. 78131727258SDarrick J. Wong */ 78231727258SDarrick J. Wong if (cur->bc_private.a.priv.refc.nr_ops > 2 && 78331727258SDarrick J. Wong XFS_TEST_ERROR(false, cur->bc_mp, 78431727258SDarrick J. Wong XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE, 78531727258SDarrick J. Wong XFS_RANDOM_REFCOUNT_CONTINUE_UPDATE)) 78631727258SDarrick J. Wong return false; 78731727258SDarrick J. Wong 78831727258SDarrick J. Wong if (cur->bc_private.a.priv.refc.nr_ops == 0) 78931727258SDarrick J. Wong return true; 79031727258SDarrick J. Wong else if (overhead > cur->bc_tp->t_log_res) 79131727258SDarrick J. Wong return false; 79231727258SDarrick J. Wong return cur->bc_tp->t_log_res - overhead > 79331727258SDarrick J. Wong cur->bc_private.a.priv.refc.nr_ops * 32; 79431727258SDarrick J. Wong } 79531727258SDarrick J. Wong 79631727258SDarrick J. Wong /* 79731727258SDarrick J. Wong * Adjust the refcounts of middle extents. At this point we should have 79831727258SDarrick J. Wong * split extents that crossed the adjustment range; merged with adjacent 79931727258SDarrick J. Wong * extents; and updated agbno/aglen to reflect the merges. Therefore, 80031727258SDarrick J. Wong * all we have to do is update the extents inside [agbno, agbno + aglen]. 80131727258SDarrick J. Wong */ 80231727258SDarrick J. Wong STATIC int 80331727258SDarrick J. Wong xfs_refcount_adjust_extents( 80431727258SDarrick J. Wong struct xfs_btree_cur *cur, 80531727258SDarrick J. Wong xfs_agblock_t *agbno, 80631727258SDarrick J. Wong xfs_extlen_t *aglen, 80731727258SDarrick J. Wong enum xfs_refc_adjust_op adj, 80831727258SDarrick J. Wong struct xfs_defer_ops *dfops, 80931727258SDarrick J. Wong struct xfs_owner_info *oinfo) 81031727258SDarrick J. Wong { 81131727258SDarrick J. Wong struct xfs_refcount_irec ext, tmp; 81231727258SDarrick J. Wong int error; 81331727258SDarrick J. Wong int found_rec, found_tmp; 81431727258SDarrick J. Wong xfs_fsblock_t fsbno; 81531727258SDarrick J. Wong 81631727258SDarrick J. Wong /* Merging did all the work already. */ 81731727258SDarrick J. Wong if (*aglen == 0) 81831727258SDarrick J. Wong return 0; 81931727258SDarrick J. Wong 82031727258SDarrick J. Wong error = xfs_refcount_lookup_ge(cur, *agbno, &found_rec); 82131727258SDarrick J. Wong if (error) 82231727258SDarrick J. Wong goto out_error; 82331727258SDarrick J. Wong 82431727258SDarrick J. Wong while (*aglen > 0 && xfs_refcount_still_have_space(cur)) { 82531727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &ext, &found_rec); 82631727258SDarrick J. Wong if (error) 82731727258SDarrick J. Wong goto out_error; 82831727258SDarrick J. Wong if (!found_rec) { 82931727258SDarrick J. Wong ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks; 83031727258SDarrick J. Wong ext.rc_blockcount = 0; 83131727258SDarrick J. Wong ext.rc_refcount = 0; 83231727258SDarrick J. Wong } 83331727258SDarrick J. Wong 83431727258SDarrick J. Wong /* 83531727258SDarrick J. Wong * Deal with a hole in the refcount tree; if a file maps to 83631727258SDarrick J. Wong * these blocks and there's no refcountbt record, pretend that 83731727258SDarrick J. Wong * there is one with refcount == 1. 83831727258SDarrick J. Wong */ 83931727258SDarrick J. Wong if (ext.rc_startblock != *agbno) { 84031727258SDarrick J. Wong tmp.rc_startblock = *agbno; 84131727258SDarrick J. Wong tmp.rc_blockcount = min(*aglen, 84231727258SDarrick J. Wong ext.rc_startblock - *agbno); 84331727258SDarrick J. Wong tmp.rc_refcount = 1 + adj; 84431727258SDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 84531727258SDarrick J. Wong cur->bc_private.a.agno, &tmp); 84631727258SDarrick J. Wong 84731727258SDarrick J. Wong /* 84831727258SDarrick J. Wong * Either cover the hole (increment) or 84931727258SDarrick J. Wong * delete the range (decrement). 85031727258SDarrick J. Wong */ 85131727258SDarrick J. Wong if (tmp.rc_refcount) { 85231727258SDarrick J. Wong error = xfs_refcount_insert(cur, &tmp, 85331727258SDarrick J. Wong &found_tmp); 85431727258SDarrick J. Wong if (error) 85531727258SDarrick J. Wong goto out_error; 85631727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, 85731727258SDarrick J. Wong found_tmp == 1, out_error); 85831727258SDarrick J. Wong cur->bc_private.a.priv.refc.nr_ops++; 85931727258SDarrick J. Wong } else { 86031727258SDarrick J. Wong fsbno = XFS_AGB_TO_FSB(cur->bc_mp, 86131727258SDarrick J. Wong cur->bc_private.a.agno, 86231727258SDarrick J. Wong tmp.rc_startblock); 86331727258SDarrick J. Wong xfs_bmap_add_free(cur->bc_mp, dfops, fsbno, 86431727258SDarrick J. Wong tmp.rc_blockcount, oinfo); 86531727258SDarrick J. Wong } 86631727258SDarrick J. Wong 86731727258SDarrick J. Wong (*agbno) += tmp.rc_blockcount; 86831727258SDarrick J. Wong (*aglen) -= tmp.rc_blockcount; 86931727258SDarrick J. Wong 87031727258SDarrick J. Wong error = xfs_refcount_lookup_ge(cur, *agbno, 87131727258SDarrick J. Wong &found_rec); 87231727258SDarrick J. Wong if (error) 87331727258SDarrick J. Wong goto out_error; 87431727258SDarrick J. Wong } 87531727258SDarrick J. Wong 87631727258SDarrick J. Wong /* Stop if there's nothing left to modify */ 87731727258SDarrick J. Wong if (*aglen == 0 || !xfs_refcount_still_have_space(cur)) 87831727258SDarrick J. Wong break; 87931727258SDarrick J. Wong 88031727258SDarrick J. Wong /* 88131727258SDarrick J. Wong * Adjust the reference count and either update the tree 88231727258SDarrick J. Wong * (incr) or free the blocks (decr). 88331727258SDarrick J. Wong */ 88431727258SDarrick J. Wong if (ext.rc_refcount == MAXREFCOUNT) 88531727258SDarrick J. Wong goto skip; 88631727258SDarrick J. Wong ext.rc_refcount += adj; 88731727258SDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 88831727258SDarrick J. Wong cur->bc_private.a.agno, &ext); 88931727258SDarrick J. Wong if (ext.rc_refcount > 1) { 89031727258SDarrick J. Wong error = xfs_refcount_update(cur, &ext); 89131727258SDarrick J. Wong if (error) 89231727258SDarrick J. Wong goto out_error; 89331727258SDarrick J. Wong cur->bc_private.a.priv.refc.nr_ops++; 89431727258SDarrick J. Wong } else if (ext.rc_refcount == 1) { 89531727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 89631727258SDarrick J. Wong if (error) 89731727258SDarrick J. Wong goto out_error; 89831727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, 89931727258SDarrick J. Wong found_rec == 1, out_error); 90031727258SDarrick J. Wong cur->bc_private.a.priv.refc.nr_ops++; 90131727258SDarrick J. Wong goto advloop; 90231727258SDarrick J. Wong } else { 90331727258SDarrick J. Wong fsbno = XFS_AGB_TO_FSB(cur->bc_mp, 90431727258SDarrick J. Wong cur->bc_private.a.agno, 90531727258SDarrick J. Wong ext.rc_startblock); 90631727258SDarrick J. Wong xfs_bmap_add_free(cur->bc_mp, dfops, fsbno, 90731727258SDarrick J. Wong ext.rc_blockcount, oinfo); 90831727258SDarrick J. Wong } 90931727258SDarrick J. Wong 91031727258SDarrick J. Wong skip: 91131727258SDarrick J. Wong error = xfs_btree_increment(cur, 0, &found_rec); 91231727258SDarrick J. Wong if (error) 91331727258SDarrick J. Wong goto out_error; 91431727258SDarrick J. Wong 91531727258SDarrick J. Wong advloop: 91631727258SDarrick J. Wong (*agbno) += ext.rc_blockcount; 91731727258SDarrick J. Wong (*aglen) -= ext.rc_blockcount; 91831727258SDarrick J. Wong } 91931727258SDarrick J. Wong 92031727258SDarrick J. Wong return error; 92131727258SDarrick J. Wong out_error: 92231727258SDarrick J. Wong trace_xfs_refcount_modify_extent_error(cur->bc_mp, 92331727258SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 92431727258SDarrick J. Wong return error; 92531727258SDarrick J. Wong } 92631727258SDarrick J. Wong 92731727258SDarrick J. Wong /* Adjust the reference count of a range of AG blocks. */ 92831727258SDarrick J. Wong STATIC int 92931727258SDarrick J. Wong xfs_refcount_adjust( 93031727258SDarrick J. Wong struct xfs_btree_cur *cur, 93131727258SDarrick J. Wong xfs_agblock_t agbno, 93231727258SDarrick J. Wong xfs_extlen_t aglen, 93331727258SDarrick J. Wong xfs_agblock_t *new_agbno, 93431727258SDarrick J. Wong xfs_extlen_t *new_aglen, 93531727258SDarrick J. Wong enum xfs_refc_adjust_op adj, 93631727258SDarrick J. Wong struct xfs_defer_ops *dfops, 93731727258SDarrick J. Wong struct xfs_owner_info *oinfo) 93831727258SDarrick J. Wong { 93931727258SDarrick J. Wong bool shape_changed; 94031727258SDarrick J. Wong int shape_changes = 0; 94131727258SDarrick J. Wong int error; 94231727258SDarrick J. Wong 94331727258SDarrick J. Wong *new_agbno = agbno; 94431727258SDarrick J. Wong *new_aglen = aglen; 94531727258SDarrick J. Wong if (adj == XFS_REFCOUNT_ADJUST_INCREASE) 94631727258SDarrick J. Wong trace_xfs_refcount_increase(cur->bc_mp, cur->bc_private.a.agno, 94731727258SDarrick J. Wong agbno, aglen); 94831727258SDarrick J. Wong else 94931727258SDarrick J. Wong trace_xfs_refcount_decrease(cur->bc_mp, cur->bc_private.a.agno, 95031727258SDarrick J. Wong agbno, aglen); 95131727258SDarrick J. Wong 95231727258SDarrick J. Wong /* 95331727258SDarrick J. Wong * Ensure that no rcextents cross the boundary of the adjustment range. 95431727258SDarrick J. Wong */ 95531727258SDarrick J. Wong error = xfs_refcount_split_extent(cur, agbno, &shape_changed); 95631727258SDarrick J. Wong if (error) 95731727258SDarrick J. Wong goto out_error; 95831727258SDarrick J. Wong if (shape_changed) 95931727258SDarrick J. Wong shape_changes++; 96031727258SDarrick J. Wong 96131727258SDarrick J. Wong error = xfs_refcount_split_extent(cur, agbno + aglen, &shape_changed); 96231727258SDarrick J. Wong if (error) 96331727258SDarrick J. Wong goto out_error; 96431727258SDarrick J. Wong if (shape_changed) 96531727258SDarrick J. Wong shape_changes++; 96631727258SDarrick J. Wong 96731727258SDarrick J. Wong /* 96831727258SDarrick J. Wong * Try to merge with the left or right extents of the range. 96931727258SDarrick J. Wong */ 97031727258SDarrick J. Wong error = xfs_refcount_merge_extents(cur, new_agbno, new_aglen, adj, 97131727258SDarrick J. Wong &shape_changed); 97231727258SDarrick J. Wong if (error) 97331727258SDarrick J. Wong goto out_error; 97431727258SDarrick J. Wong if (shape_changed) 97531727258SDarrick J. Wong shape_changes++; 97631727258SDarrick J. Wong if (shape_changes) 97731727258SDarrick J. Wong cur->bc_private.a.priv.refc.shape_changes++; 97831727258SDarrick J. Wong 97931727258SDarrick J. Wong /* Now that we've taken care of the ends, adjust the middle extents */ 98031727258SDarrick J. Wong error = xfs_refcount_adjust_extents(cur, new_agbno, new_aglen, 98131727258SDarrick J. Wong adj, dfops, oinfo); 98231727258SDarrick J. Wong if (error) 98331727258SDarrick J. Wong goto out_error; 98431727258SDarrick J. Wong 98531727258SDarrick J. Wong return 0; 98631727258SDarrick J. Wong 98731727258SDarrick J. Wong out_error: 98831727258SDarrick J. Wong trace_xfs_refcount_adjust_error(cur->bc_mp, cur->bc_private.a.agno, 98931727258SDarrick J. Wong error, _RET_IP_); 99031727258SDarrick J. Wong return error; 99131727258SDarrick J. Wong } 992