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" 33e9e899a2SDarrick J. Wong #include "xfs_errortag.h" 34bdf28630SDarrick J. Wong #include "xfs_error.h" 35bdf28630SDarrick J. Wong #include "xfs_trace.h" 36bdf28630SDarrick J. Wong #include "xfs_cksum.h" 37bdf28630SDarrick J. Wong #include "xfs_trans.h" 38bdf28630SDarrick J. Wong #include "xfs_bit.h" 39bdf28630SDarrick J. Wong #include "xfs_refcount.h" 40174edb0eSDarrick J. Wong #include "xfs_rmap.h" 41bdf28630SDarrick J. Wong 4231727258SDarrick J. Wong /* Allowable refcount adjustment amounts. */ 4331727258SDarrick J. Wong enum xfs_refc_adjust_op { 4431727258SDarrick J. Wong XFS_REFCOUNT_ADJUST_INCREASE = 1, 4531727258SDarrick J. Wong XFS_REFCOUNT_ADJUST_DECREASE = -1, 46174edb0eSDarrick J. Wong XFS_REFCOUNT_ADJUST_COW_ALLOC = 0, 47174edb0eSDarrick J. Wong XFS_REFCOUNT_ADJUST_COW_FREE = -1, 4831727258SDarrick J. Wong }; 4931727258SDarrick J. Wong 50174edb0eSDarrick J. Wong STATIC int __xfs_refcount_cow_alloc(struct xfs_btree_cur *rcur, 51174edb0eSDarrick J. Wong xfs_agblock_t agbno, xfs_extlen_t aglen, 52174edb0eSDarrick J. Wong struct xfs_defer_ops *dfops); 53174edb0eSDarrick J. Wong STATIC int __xfs_refcount_cow_free(struct xfs_btree_cur *rcur, 54174edb0eSDarrick J. Wong xfs_agblock_t agbno, xfs_extlen_t aglen, 55174edb0eSDarrick J. Wong struct xfs_defer_ops *dfops); 56174edb0eSDarrick J. Wong 57bdf28630SDarrick J. Wong /* 58bdf28630SDarrick J. Wong * Look up the first record less than or equal to [bno, len] in the btree 59bdf28630SDarrick J. Wong * given by cur. 60bdf28630SDarrick J. Wong */ 61bdf28630SDarrick J. Wong int 62bdf28630SDarrick J. Wong xfs_refcount_lookup_le( 63bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 64bdf28630SDarrick J. Wong xfs_agblock_t bno, 65bdf28630SDarrick J. Wong int *stat) 66bdf28630SDarrick J. Wong { 67bdf28630SDarrick J. Wong trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_private.a.agno, bno, 68bdf28630SDarrick J. Wong XFS_LOOKUP_LE); 69bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_startblock = bno; 70bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_blockcount = 0; 71bdf28630SDarrick J. Wong return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat); 72bdf28630SDarrick J. Wong } 73bdf28630SDarrick J. Wong 74bdf28630SDarrick J. Wong /* 75bdf28630SDarrick J. Wong * Look up the first record greater than or equal to [bno, len] in the btree 76bdf28630SDarrick J. Wong * given by cur. 77bdf28630SDarrick J. Wong */ 78bdf28630SDarrick J. Wong int 79bdf28630SDarrick J. Wong xfs_refcount_lookup_ge( 80bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 81bdf28630SDarrick J. Wong xfs_agblock_t bno, 82bdf28630SDarrick J. Wong int *stat) 83bdf28630SDarrick J. Wong { 84bdf28630SDarrick J. Wong trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_private.a.agno, bno, 85bdf28630SDarrick J. Wong XFS_LOOKUP_GE); 86bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_startblock = bno; 87bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_blockcount = 0; 88bdf28630SDarrick J. Wong return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat); 89bdf28630SDarrick J. Wong } 90bdf28630SDarrick J. Wong 91174edb0eSDarrick J. Wong /* Convert on-disk record to in-core format. */ 92174edb0eSDarrick J. Wong static inline void 93174edb0eSDarrick J. Wong xfs_refcount_btrec_to_irec( 94174edb0eSDarrick J. Wong union xfs_btree_rec *rec, 95174edb0eSDarrick J. Wong struct xfs_refcount_irec *irec) 96174edb0eSDarrick J. Wong { 97174edb0eSDarrick J. Wong irec->rc_startblock = be32_to_cpu(rec->refc.rc_startblock); 98174edb0eSDarrick J. Wong irec->rc_blockcount = be32_to_cpu(rec->refc.rc_blockcount); 99174edb0eSDarrick J. Wong irec->rc_refcount = be32_to_cpu(rec->refc.rc_refcount); 100174edb0eSDarrick J. Wong } 101174edb0eSDarrick J. Wong 102bdf28630SDarrick J. Wong /* 103bdf28630SDarrick J. Wong * Get the data from the pointed-to record. 104bdf28630SDarrick J. Wong */ 105bdf28630SDarrick J. Wong int 106bdf28630SDarrick J. Wong xfs_refcount_get_rec( 107bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 108bdf28630SDarrick J. Wong struct xfs_refcount_irec *irec, 109bdf28630SDarrick J. Wong int *stat) 110bdf28630SDarrick J. Wong { 111bdf28630SDarrick J. Wong union xfs_btree_rec *rec; 112bdf28630SDarrick J. Wong int error; 113bdf28630SDarrick J. Wong 114bdf28630SDarrick J. Wong error = xfs_btree_get_rec(cur, &rec, stat); 115bdf28630SDarrick J. Wong if (!error && *stat == 1) { 116174edb0eSDarrick J. Wong xfs_refcount_btrec_to_irec(rec, irec); 117bdf28630SDarrick J. Wong trace_xfs_refcount_get(cur->bc_mp, cur->bc_private.a.agno, 118bdf28630SDarrick J. Wong irec); 119bdf28630SDarrick J. Wong } 120bdf28630SDarrick J. Wong return error; 121bdf28630SDarrick J. Wong } 122bdf28630SDarrick J. Wong 123bdf28630SDarrick J. Wong /* 124bdf28630SDarrick J. Wong * Update the record referred to by cur to the value given 125bdf28630SDarrick J. Wong * by [bno, len, refcount]. 126bdf28630SDarrick J. Wong * This either works (return 0) or gets an EFSCORRUPTED error. 127bdf28630SDarrick J. Wong */ 128bdf28630SDarrick J. Wong STATIC int 129bdf28630SDarrick J. Wong xfs_refcount_update( 130bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 131bdf28630SDarrick J. Wong struct xfs_refcount_irec *irec) 132bdf28630SDarrick J. Wong { 133bdf28630SDarrick J. Wong union xfs_btree_rec rec; 134bdf28630SDarrick J. Wong int error; 135bdf28630SDarrick J. Wong 136bdf28630SDarrick J. Wong trace_xfs_refcount_update(cur->bc_mp, cur->bc_private.a.agno, irec); 137bdf28630SDarrick J. Wong rec.refc.rc_startblock = cpu_to_be32(irec->rc_startblock); 138bdf28630SDarrick J. Wong rec.refc.rc_blockcount = cpu_to_be32(irec->rc_blockcount); 139bdf28630SDarrick J. Wong rec.refc.rc_refcount = cpu_to_be32(irec->rc_refcount); 140bdf28630SDarrick J. Wong error = xfs_btree_update(cur, &rec); 141bdf28630SDarrick J. Wong if (error) 142bdf28630SDarrick J. Wong trace_xfs_refcount_update_error(cur->bc_mp, 143bdf28630SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 144bdf28630SDarrick J. Wong return error; 145bdf28630SDarrick J. Wong } 146bdf28630SDarrick J. Wong 147bdf28630SDarrick J. Wong /* 148bdf28630SDarrick J. Wong * Insert the record referred to by cur to the value given 149bdf28630SDarrick J. Wong * by [bno, len, refcount]. 150bdf28630SDarrick J. Wong * This either works (return 0) or gets an EFSCORRUPTED error. 151bdf28630SDarrick J. Wong */ 152bdf28630SDarrick J. Wong STATIC int 153bdf28630SDarrick J. Wong xfs_refcount_insert( 154bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 155bdf28630SDarrick J. Wong struct xfs_refcount_irec *irec, 156bdf28630SDarrick J. Wong int *i) 157bdf28630SDarrick J. Wong { 158bdf28630SDarrick J. Wong int error; 159bdf28630SDarrick J. Wong 160bdf28630SDarrick J. Wong trace_xfs_refcount_insert(cur->bc_mp, cur->bc_private.a.agno, irec); 161bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_startblock = irec->rc_startblock; 162bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_blockcount = irec->rc_blockcount; 163bdf28630SDarrick J. Wong cur->bc_rec.rc.rc_refcount = irec->rc_refcount; 164bdf28630SDarrick J. Wong error = xfs_btree_insert(cur, i); 165bdf28630SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, *i == 1, out_error); 166bdf28630SDarrick J. Wong out_error: 167bdf28630SDarrick J. Wong if (error) 168bdf28630SDarrick J. Wong trace_xfs_refcount_insert_error(cur->bc_mp, 169bdf28630SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 170bdf28630SDarrick J. Wong return error; 171bdf28630SDarrick J. Wong } 172bdf28630SDarrick J. Wong 173bdf28630SDarrick J. Wong /* 174bdf28630SDarrick J. Wong * Remove the record referred to by cur, then set the pointer to the spot 175bdf28630SDarrick J. Wong * where the record could be re-inserted, in case we want to increment or 176bdf28630SDarrick J. Wong * decrement the cursor. 177bdf28630SDarrick J. Wong * This either works (return 0) or gets an EFSCORRUPTED error. 178bdf28630SDarrick J. Wong */ 179bdf28630SDarrick J. Wong STATIC int 180bdf28630SDarrick J. Wong xfs_refcount_delete( 181bdf28630SDarrick J. Wong struct xfs_btree_cur *cur, 182bdf28630SDarrick J. Wong int *i) 183bdf28630SDarrick J. Wong { 184bdf28630SDarrick J. Wong struct xfs_refcount_irec irec; 185bdf28630SDarrick J. Wong int found_rec; 186bdf28630SDarrick J. Wong int error; 187bdf28630SDarrick J. Wong 188bdf28630SDarrick J. Wong error = xfs_refcount_get_rec(cur, &irec, &found_rec); 189bdf28630SDarrick J. Wong if (error) 190bdf28630SDarrick J. Wong goto out_error; 191bdf28630SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 192bdf28630SDarrick J. Wong trace_xfs_refcount_delete(cur->bc_mp, cur->bc_private.a.agno, &irec); 193bdf28630SDarrick J. Wong error = xfs_btree_delete(cur, i); 194bdf28630SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, *i == 1, out_error); 195bdf28630SDarrick J. Wong if (error) 196bdf28630SDarrick J. Wong goto out_error; 197bdf28630SDarrick J. Wong error = xfs_refcount_lookup_ge(cur, irec.rc_startblock, &found_rec); 198bdf28630SDarrick J. Wong out_error: 199bdf28630SDarrick J. Wong if (error) 200bdf28630SDarrick J. Wong trace_xfs_refcount_delete_error(cur->bc_mp, 201bdf28630SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 202bdf28630SDarrick J. Wong return error; 203bdf28630SDarrick J. Wong } 20431727258SDarrick J. Wong 20531727258SDarrick J. Wong /* 20631727258SDarrick J. Wong * Adjusting the Reference Count 20731727258SDarrick J. Wong * 20831727258SDarrick J. Wong * As stated elsewhere, the reference count btree (refcbt) stores 20931727258SDarrick J. Wong * >1 reference counts for extents of physical blocks. In this 21031727258SDarrick J. Wong * operation, we're either raising or lowering the reference count of 21131727258SDarrick J. Wong * some subrange stored in the tree: 21231727258SDarrick J. Wong * 21331727258SDarrick J. Wong * <------ adjustment range ------> 21431727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+--------- 21531727258SDarrick J. Wong * 2 | | 3 | 4 | |17| 55 | 10 21631727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+--------- 21731727258SDarrick J. Wong * X axis is physical blocks number; 21831727258SDarrick J. Wong * reference counts are the numbers inside the rectangles 21931727258SDarrick J. Wong * 22031727258SDarrick J. Wong * The first thing we need to do is to ensure that there are no 22131727258SDarrick J. Wong * refcount extents crossing either boundary of the range to be 22231727258SDarrick J. Wong * adjusted. For any extent that does cross a boundary, split it into 22331727258SDarrick J. Wong * two extents so that we can increment the refcount of one of the 22431727258SDarrick J. Wong * pieces later: 22531727258SDarrick J. Wong * 22631727258SDarrick J. Wong * <------ adjustment range ------> 22731727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+----+---- 22831727258SDarrick J. Wong * 2 | | 3 | 2 | |17| 55 | 10 | 10 22931727258SDarrick J. Wong * ----+ +---+-----+ +--+--------+----+---- 23031727258SDarrick J. Wong * 23131727258SDarrick J. Wong * For this next step, let's assume that all the physical blocks in 23231727258SDarrick J. Wong * the adjustment range are mapped to a file and are therefore in use 23331727258SDarrick J. Wong * at least once. Therefore, we can infer that any gap in the 23431727258SDarrick J. Wong * refcount tree within the adjustment range represents a physical 23531727258SDarrick J. Wong * extent with refcount == 1: 23631727258SDarrick J. Wong * 23731727258SDarrick J. Wong * <------ adjustment range ------> 23831727258SDarrick J. Wong * ----+---+---+-----+-+--+--------+----+---- 23931727258SDarrick J. Wong * 2 |"1"| 3 | 2 |1|17| 55 | 10 | 10 24031727258SDarrick J. Wong * ----+---+---+-----+-+--+--------+----+---- 24131727258SDarrick J. Wong * ^ 24231727258SDarrick J. Wong * 24331727258SDarrick J. Wong * For each extent that falls within the interval range, figure out 24431727258SDarrick J. Wong * which extent is to the left or the right of that extent. Now we 24531727258SDarrick J. Wong * have a left, current, and right extent. If the new reference count 24631727258SDarrick J. Wong * of the center extent enables us to merge left, center, and right 24731727258SDarrick J. Wong * into one record covering all three, do so. If the center extent is 24831727258SDarrick J. Wong * at the left end of the range, abuts the left extent, and its new 24931727258SDarrick J. Wong * reference count matches the left extent's record, then merge them. 25031727258SDarrick J. Wong * If the center extent is at the right end of the range, abuts the 25131727258SDarrick J. Wong * right extent, and the reference counts match, merge those. In the 25231727258SDarrick J. Wong * example, we can left merge (assuming an increment operation): 25331727258SDarrick J. Wong * 25431727258SDarrick J. Wong * <------ adjustment range ------> 25531727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 25631727258SDarrick J. Wong * 2 | 3 | 2 |1|17| 55 | 10 | 10 25731727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 25831727258SDarrick J. Wong * ^ 25931727258SDarrick J. Wong * 26031727258SDarrick J. Wong * For all other extents within the range, adjust the reference count 26131727258SDarrick J. Wong * or delete it if the refcount falls below 2. If we were 26231727258SDarrick J. Wong * incrementing, the end result looks like this: 26331727258SDarrick J. Wong * 26431727258SDarrick J. Wong * <------ adjustment range ------> 26531727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 26631727258SDarrick J. Wong * 2 | 4 | 3 |2|18| 56 | 11 | 10 26731727258SDarrick J. Wong * --------+---+-----+-+--+--------+----+---- 26831727258SDarrick J. Wong * 26931727258SDarrick J. Wong * The result of a decrement operation looks as such: 27031727258SDarrick J. Wong * 27131727258SDarrick J. Wong * <------ adjustment range ------> 27231727258SDarrick J. Wong * ----+ +---+ +--+--------+----+---- 27331727258SDarrick J. Wong * 2 | | 2 | |16| 54 | 9 | 10 27431727258SDarrick J. Wong * ----+ +---+ +--+--------+----+---- 27531727258SDarrick J. Wong * DDDD 111111DD 27631727258SDarrick J. Wong * 27731727258SDarrick J. Wong * The blocks marked "D" are freed; the blocks marked "1" are only 27831727258SDarrick J. Wong * referenced once and therefore the record is removed from the 27931727258SDarrick J. Wong * refcount btree. 28031727258SDarrick J. Wong */ 28131727258SDarrick J. Wong 28231727258SDarrick J. Wong /* Next block after this extent. */ 28331727258SDarrick J. Wong static inline xfs_agblock_t 28431727258SDarrick J. Wong xfs_refc_next( 28531727258SDarrick J. Wong struct xfs_refcount_irec *rc) 28631727258SDarrick J. Wong { 28731727258SDarrick J. Wong return rc->rc_startblock + rc->rc_blockcount; 28831727258SDarrick J. Wong } 28931727258SDarrick J. Wong 29031727258SDarrick J. Wong /* 29131727258SDarrick J. Wong * Split a refcount extent that crosses agbno. 29231727258SDarrick J. Wong */ 29331727258SDarrick J. Wong STATIC int 29431727258SDarrick J. Wong xfs_refcount_split_extent( 29531727258SDarrick J. Wong struct xfs_btree_cur *cur, 29631727258SDarrick J. Wong xfs_agblock_t agbno, 29731727258SDarrick J. Wong bool *shape_changed) 29831727258SDarrick J. Wong { 29931727258SDarrick J. Wong struct xfs_refcount_irec rcext, tmp; 30031727258SDarrick J. Wong int found_rec; 30131727258SDarrick J. Wong int error; 30231727258SDarrick J. Wong 30331727258SDarrick J. Wong *shape_changed = false; 30431727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, agbno, &found_rec); 30531727258SDarrick J. Wong if (error) 30631727258SDarrick J. Wong goto out_error; 30731727258SDarrick J. Wong if (!found_rec) 30831727258SDarrick J. Wong return 0; 30931727258SDarrick J. Wong 31031727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &rcext, &found_rec); 31131727258SDarrick J. Wong if (error) 31231727258SDarrick J. Wong goto out_error; 31331727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 31431727258SDarrick J. Wong if (rcext.rc_startblock == agbno || xfs_refc_next(&rcext) <= agbno) 31531727258SDarrick J. Wong return 0; 31631727258SDarrick J. Wong 31731727258SDarrick J. Wong *shape_changed = true; 31831727258SDarrick J. Wong trace_xfs_refcount_split_extent(cur->bc_mp, cur->bc_private.a.agno, 31931727258SDarrick J. Wong &rcext, agbno); 32031727258SDarrick J. Wong 32131727258SDarrick J. Wong /* Establish the right extent. */ 32231727258SDarrick J. Wong tmp = rcext; 32331727258SDarrick J. Wong tmp.rc_startblock = agbno; 32431727258SDarrick J. Wong tmp.rc_blockcount -= (agbno - rcext.rc_startblock); 32531727258SDarrick J. Wong error = xfs_refcount_update(cur, &tmp); 32631727258SDarrick J. Wong if (error) 32731727258SDarrick J. Wong goto out_error; 32831727258SDarrick J. Wong 32931727258SDarrick J. Wong /* Insert the left extent. */ 33031727258SDarrick J. Wong tmp = rcext; 33131727258SDarrick J. Wong tmp.rc_blockcount = agbno - rcext.rc_startblock; 33231727258SDarrick J. Wong error = xfs_refcount_insert(cur, &tmp, &found_rec); 33331727258SDarrick J. Wong if (error) 33431727258SDarrick J. Wong goto out_error; 33531727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 33631727258SDarrick J. Wong return error; 33731727258SDarrick J. Wong 33831727258SDarrick J. Wong out_error: 33931727258SDarrick J. Wong trace_xfs_refcount_split_extent_error(cur->bc_mp, 34031727258SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 34131727258SDarrick J. Wong return error; 34231727258SDarrick J. Wong } 34331727258SDarrick J. Wong 34431727258SDarrick J. Wong /* 34531727258SDarrick J. Wong * Merge the left, center, and right extents. 34631727258SDarrick J. Wong */ 34731727258SDarrick J. Wong STATIC int 34831727258SDarrick J. Wong xfs_refcount_merge_center_extents( 34931727258SDarrick J. Wong struct xfs_btree_cur *cur, 35031727258SDarrick J. Wong struct xfs_refcount_irec *left, 35131727258SDarrick J. Wong struct xfs_refcount_irec *center, 35231727258SDarrick J. Wong struct xfs_refcount_irec *right, 35331727258SDarrick J. Wong unsigned long long extlen, 35431727258SDarrick J. Wong xfs_agblock_t *agbno, 35531727258SDarrick J. Wong xfs_extlen_t *aglen) 35631727258SDarrick J. Wong { 35731727258SDarrick J. Wong int error; 35831727258SDarrick J. Wong int found_rec; 35931727258SDarrick J. Wong 36031727258SDarrick J. Wong trace_xfs_refcount_merge_center_extents(cur->bc_mp, 36131727258SDarrick J. Wong cur->bc_private.a.agno, left, center, right); 36231727258SDarrick J. Wong 36331727258SDarrick J. Wong /* 36431727258SDarrick J. Wong * Make sure the center and right extents are not in the btree. 36531727258SDarrick J. Wong * If the center extent was synthesized, the first delete call 36631727258SDarrick J. Wong * removes the right extent and we skip the second deletion. 36731727258SDarrick J. Wong * If center and right were in the btree, then the first delete 36831727258SDarrick J. Wong * call removes the center and the second one removes the right 36931727258SDarrick J. Wong * extent. 37031727258SDarrick J. Wong */ 37131727258SDarrick J. Wong error = xfs_refcount_lookup_ge(cur, center->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 error = xfs_refcount_delete(cur, &found_rec); 37831727258SDarrick J. Wong if (error) 37931727258SDarrick J. Wong goto out_error; 38031727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 38131727258SDarrick J. Wong 38231727258SDarrick J. Wong if (center->rc_refcount > 1) { 38331727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 38431727258SDarrick J. Wong if (error) 38531727258SDarrick J. Wong goto out_error; 38631727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, 38731727258SDarrick J. Wong out_error); 38831727258SDarrick J. Wong } 38931727258SDarrick J. Wong 39031727258SDarrick J. Wong /* Enlarge the left extent. */ 39131727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, left->rc_startblock, 39231727258SDarrick J. Wong &found_rec); 39331727258SDarrick J. Wong if (error) 39431727258SDarrick J. Wong goto out_error; 39531727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 39631727258SDarrick J. Wong 39731727258SDarrick J. Wong left->rc_blockcount = extlen; 39831727258SDarrick J. Wong error = xfs_refcount_update(cur, left); 39931727258SDarrick J. Wong if (error) 40031727258SDarrick J. Wong goto out_error; 40131727258SDarrick J. Wong 40231727258SDarrick J. Wong *aglen = 0; 40331727258SDarrick J. Wong return error; 40431727258SDarrick J. Wong 40531727258SDarrick J. Wong out_error: 40631727258SDarrick J. Wong trace_xfs_refcount_merge_center_extents_error(cur->bc_mp, 40731727258SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 40831727258SDarrick J. Wong return error; 40931727258SDarrick J. Wong } 41031727258SDarrick J. Wong 41131727258SDarrick J. Wong /* 41231727258SDarrick J. Wong * Merge with the left extent. 41331727258SDarrick J. Wong */ 41431727258SDarrick J. Wong STATIC int 41531727258SDarrick J. Wong xfs_refcount_merge_left_extent( 41631727258SDarrick J. Wong struct xfs_btree_cur *cur, 41731727258SDarrick J. Wong struct xfs_refcount_irec *left, 41831727258SDarrick J. Wong struct xfs_refcount_irec *cleft, 41931727258SDarrick J. Wong xfs_agblock_t *agbno, 42031727258SDarrick J. Wong xfs_extlen_t *aglen) 42131727258SDarrick J. Wong { 42231727258SDarrick J. Wong int error; 42331727258SDarrick J. Wong int found_rec; 42431727258SDarrick J. Wong 42531727258SDarrick J. Wong trace_xfs_refcount_merge_left_extent(cur->bc_mp, 42631727258SDarrick J. Wong cur->bc_private.a.agno, left, cleft); 42731727258SDarrick J. Wong 42831727258SDarrick J. Wong /* If the extent at agbno (cleft) wasn't synthesized, remove it. */ 42931727258SDarrick J. Wong if (cleft->rc_refcount > 1) { 43031727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, cleft->rc_startblock, 43131727258SDarrick J. Wong &found_rec); 43231727258SDarrick J. Wong if (error) 43331727258SDarrick J. Wong goto out_error; 43431727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, 43531727258SDarrick J. Wong out_error); 43631727258SDarrick J. Wong 43731727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 43831727258SDarrick J. Wong if (error) 43931727258SDarrick J. Wong goto out_error; 44031727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, 44131727258SDarrick J. Wong out_error); 44231727258SDarrick J. Wong } 44331727258SDarrick J. Wong 44431727258SDarrick J. Wong /* Enlarge the left extent. */ 44531727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, left->rc_startblock, 44631727258SDarrick J. Wong &found_rec); 44731727258SDarrick J. Wong if (error) 44831727258SDarrick J. Wong goto out_error; 44931727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 45031727258SDarrick J. Wong 45131727258SDarrick J. Wong left->rc_blockcount += cleft->rc_blockcount; 45231727258SDarrick J. Wong error = xfs_refcount_update(cur, left); 45331727258SDarrick J. Wong if (error) 45431727258SDarrick J. Wong goto out_error; 45531727258SDarrick J. Wong 45631727258SDarrick J. Wong *agbno += cleft->rc_blockcount; 45731727258SDarrick J. Wong *aglen -= cleft->rc_blockcount; 45831727258SDarrick J. Wong return error; 45931727258SDarrick J. Wong 46031727258SDarrick J. Wong out_error: 46131727258SDarrick J. Wong trace_xfs_refcount_merge_left_extent_error(cur->bc_mp, 46231727258SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 46331727258SDarrick J. Wong return error; 46431727258SDarrick J. Wong } 46531727258SDarrick J. Wong 46631727258SDarrick J. Wong /* 46731727258SDarrick J. Wong * Merge with the right extent. 46831727258SDarrick J. Wong */ 46931727258SDarrick J. Wong STATIC int 47031727258SDarrick J. Wong xfs_refcount_merge_right_extent( 47131727258SDarrick J. Wong struct xfs_btree_cur *cur, 47231727258SDarrick J. Wong struct xfs_refcount_irec *right, 47331727258SDarrick J. Wong struct xfs_refcount_irec *cright, 47431727258SDarrick J. Wong xfs_agblock_t *agbno, 47531727258SDarrick J. Wong xfs_extlen_t *aglen) 47631727258SDarrick J. Wong { 47731727258SDarrick J. Wong int error; 47831727258SDarrick J. Wong int found_rec; 47931727258SDarrick J. Wong 48031727258SDarrick J. Wong trace_xfs_refcount_merge_right_extent(cur->bc_mp, 48131727258SDarrick J. Wong cur->bc_private.a.agno, cright, right); 48231727258SDarrick J. Wong 48331727258SDarrick J. Wong /* 48431727258SDarrick J. Wong * If the extent ending at agbno+aglen (cright) wasn't synthesized, 48531727258SDarrick J. Wong * remove it. 48631727258SDarrick J. Wong */ 48731727258SDarrick J. Wong if (cright->rc_refcount > 1) { 48831727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, cright->rc_startblock, 48931727258SDarrick J. Wong &found_rec); 49031727258SDarrick J. Wong if (error) 49131727258SDarrick J. Wong goto out_error; 49231727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, 49331727258SDarrick J. Wong out_error); 49431727258SDarrick J. Wong 49531727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 49631727258SDarrick J. Wong if (error) 49731727258SDarrick J. Wong goto out_error; 49831727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, 49931727258SDarrick J. Wong out_error); 50031727258SDarrick J. Wong } 50131727258SDarrick J. Wong 50231727258SDarrick J. Wong /* Enlarge the right extent. */ 50331727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, right->rc_startblock, 50431727258SDarrick J. Wong &found_rec); 50531727258SDarrick J. Wong if (error) 50631727258SDarrick J. Wong goto out_error; 50731727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 50831727258SDarrick J. Wong 50931727258SDarrick J. Wong right->rc_startblock -= cright->rc_blockcount; 51031727258SDarrick J. Wong right->rc_blockcount += cright->rc_blockcount; 51131727258SDarrick J. Wong error = xfs_refcount_update(cur, right); 51231727258SDarrick J. Wong if (error) 51331727258SDarrick J. Wong goto out_error; 51431727258SDarrick J. Wong 51531727258SDarrick J. Wong *aglen -= cright->rc_blockcount; 51631727258SDarrick J. Wong return error; 51731727258SDarrick J. Wong 51831727258SDarrick J. Wong out_error: 51931727258SDarrick J. Wong trace_xfs_refcount_merge_right_extent_error(cur->bc_mp, 52031727258SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 52131727258SDarrick J. Wong return error; 52231727258SDarrick J. Wong } 52331727258SDarrick J. Wong 524174edb0eSDarrick J. Wong #define XFS_FIND_RCEXT_SHARED 1 525174edb0eSDarrick J. Wong #define XFS_FIND_RCEXT_COW 2 52631727258SDarrick J. Wong /* 52731727258SDarrick J. Wong * Find the left extent and the one after it (cleft). This function assumes 52831727258SDarrick J. Wong * that we've already split any extent crossing agbno. 52931727258SDarrick J. Wong */ 53031727258SDarrick J. Wong STATIC int 53131727258SDarrick J. Wong xfs_refcount_find_left_extents( 53231727258SDarrick J. Wong struct xfs_btree_cur *cur, 53331727258SDarrick J. Wong struct xfs_refcount_irec *left, 53431727258SDarrick J. Wong struct xfs_refcount_irec *cleft, 53531727258SDarrick J. Wong xfs_agblock_t agbno, 536174edb0eSDarrick J. Wong xfs_extlen_t aglen, 537174edb0eSDarrick J. Wong int flags) 53831727258SDarrick J. Wong { 53931727258SDarrick J. Wong struct xfs_refcount_irec tmp; 54031727258SDarrick J. Wong int error; 54131727258SDarrick J. Wong int found_rec; 54231727258SDarrick J. Wong 54331727258SDarrick J. Wong left->rc_startblock = cleft->rc_startblock = NULLAGBLOCK; 54431727258SDarrick J. Wong error = xfs_refcount_lookup_le(cur, agbno - 1, &found_rec); 54531727258SDarrick J. Wong if (error) 54631727258SDarrick J. Wong goto out_error; 54731727258SDarrick J. Wong if (!found_rec) 54831727258SDarrick J. Wong return 0; 54931727258SDarrick J. Wong 55031727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 55131727258SDarrick J. Wong if (error) 55231727258SDarrick J. Wong goto out_error; 55331727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 55431727258SDarrick J. Wong 55531727258SDarrick J. Wong if (xfs_refc_next(&tmp) != agbno) 55631727258SDarrick J. Wong return 0; 557174edb0eSDarrick J. Wong if ((flags & XFS_FIND_RCEXT_SHARED) && tmp.rc_refcount < 2) 558174edb0eSDarrick J. Wong return 0; 559174edb0eSDarrick J. Wong if ((flags & XFS_FIND_RCEXT_COW) && tmp.rc_refcount > 1) 560174edb0eSDarrick J. Wong return 0; 56131727258SDarrick J. Wong /* We have a left extent; retrieve (or invent) the next right one */ 56231727258SDarrick J. Wong *left = tmp; 56331727258SDarrick J. Wong 56431727258SDarrick J. Wong error = xfs_btree_increment(cur, 0, &found_rec); 56531727258SDarrick J. Wong if (error) 56631727258SDarrick J. Wong goto out_error; 56731727258SDarrick J. Wong if (found_rec) { 56831727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 56931727258SDarrick J. Wong if (error) 57031727258SDarrick J. Wong goto out_error; 57131727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, 57231727258SDarrick J. Wong out_error); 57331727258SDarrick J. Wong 57431727258SDarrick J. Wong /* if tmp starts at the end of our range, just use that */ 57531727258SDarrick J. Wong if (tmp.rc_startblock == agbno) 57631727258SDarrick J. Wong *cleft = tmp; 57731727258SDarrick J. Wong else { 57831727258SDarrick J. Wong /* 57931727258SDarrick J. Wong * There's a gap in the refcntbt at the start of the 58031727258SDarrick J. Wong * range we're interested in (refcount == 1) so 58131727258SDarrick J. Wong * synthesize the implied extent and pass it back. 58231727258SDarrick J. Wong * We assume here that the agbno/aglen range was 58331727258SDarrick J. Wong * passed in from a data fork extent mapping and 58431727258SDarrick J. Wong * therefore is allocated to exactly one owner. 58531727258SDarrick J. Wong */ 58631727258SDarrick J. Wong cleft->rc_startblock = agbno; 58731727258SDarrick J. Wong cleft->rc_blockcount = min(aglen, 58831727258SDarrick J. Wong tmp.rc_startblock - agbno); 58931727258SDarrick J. Wong cleft->rc_refcount = 1; 59031727258SDarrick J. Wong } 59131727258SDarrick J. Wong } else { 59231727258SDarrick J. Wong /* 59331727258SDarrick J. Wong * No extents, so pretend that there's one covering the whole 59431727258SDarrick J. Wong * range. 59531727258SDarrick J. Wong */ 59631727258SDarrick J. Wong cleft->rc_startblock = agbno; 59731727258SDarrick J. Wong cleft->rc_blockcount = aglen; 59831727258SDarrick J. Wong cleft->rc_refcount = 1; 59931727258SDarrick J. Wong } 60031727258SDarrick J. Wong trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_private.a.agno, 60131727258SDarrick J. Wong left, cleft, agbno); 60231727258SDarrick J. Wong return error; 60331727258SDarrick J. Wong 60431727258SDarrick J. Wong out_error: 60531727258SDarrick J. Wong trace_xfs_refcount_find_left_extent_error(cur->bc_mp, 60631727258SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 60731727258SDarrick J. Wong return error; 60831727258SDarrick J. Wong } 60931727258SDarrick J. Wong 61031727258SDarrick J. Wong /* 61131727258SDarrick J. Wong * Find the right extent and the one before it (cright). This function 61231727258SDarrick J. Wong * assumes that we've already split any extents crossing agbno + aglen. 61331727258SDarrick J. Wong */ 61431727258SDarrick J. Wong STATIC int 61531727258SDarrick J. Wong xfs_refcount_find_right_extents( 61631727258SDarrick J. Wong struct xfs_btree_cur *cur, 61731727258SDarrick J. Wong struct xfs_refcount_irec *right, 61831727258SDarrick J. Wong struct xfs_refcount_irec *cright, 61931727258SDarrick J. Wong xfs_agblock_t agbno, 620174edb0eSDarrick J. Wong xfs_extlen_t aglen, 621174edb0eSDarrick J. Wong int flags) 62231727258SDarrick J. Wong { 62331727258SDarrick J. Wong struct xfs_refcount_irec tmp; 62431727258SDarrick J. Wong int error; 62531727258SDarrick J. Wong int found_rec; 62631727258SDarrick J. Wong 62731727258SDarrick J. Wong right->rc_startblock = cright->rc_startblock = NULLAGBLOCK; 62831727258SDarrick J. Wong error = xfs_refcount_lookup_ge(cur, agbno + aglen, &found_rec); 62931727258SDarrick J. Wong if (error) 63031727258SDarrick J. Wong goto out_error; 63131727258SDarrick J. Wong if (!found_rec) 63231727258SDarrick J. Wong return 0; 63331727258SDarrick J. Wong 63431727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 63531727258SDarrick J. Wong if (error) 63631727258SDarrick J. Wong goto out_error; 63731727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); 63831727258SDarrick J. Wong 63931727258SDarrick J. Wong if (tmp.rc_startblock != agbno + aglen) 64031727258SDarrick J. Wong return 0; 641174edb0eSDarrick J. Wong if ((flags & XFS_FIND_RCEXT_SHARED) && tmp.rc_refcount < 2) 642174edb0eSDarrick J. Wong return 0; 643174edb0eSDarrick J. Wong if ((flags & XFS_FIND_RCEXT_COW) && tmp.rc_refcount > 1) 644174edb0eSDarrick J. Wong return 0; 64531727258SDarrick J. Wong /* We have a right extent; retrieve (or invent) the next left one */ 64631727258SDarrick J. Wong *right = tmp; 64731727258SDarrick J. Wong 64831727258SDarrick J. Wong error = xfs_btree_decrement(cur, 0, &found_rec); 64931727258SDarrick J. Wong if (error) 65031727258SDarrick J. Wong goto out_error; 65131727258SDarrick J. Wong if (found_rec) { 65231727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &found_rec); 65331727258SDarrick J. Wong if (error) 65431727258SDarrick J. Wong goto out_error; 65531727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, 65631727258SDarrick J. Wong out_error); 65731727258SDarrick J. Wong 65831727258SDarrick J. Wong /* if tmp ends at the end of our range, just use that */ 65931727258SDarrick J. Wong if (xfs_refc_next(&tmp) == agbno + aglen) 66031727258SDarrick J. Wong *cright = tmp; 66131727258SDarrick J. Wong else { 66231727258SDarrick J. Wong /* 66331727258SDarrick J. Wong * There's a gap in the refcntbt at the end of the 66431727258SDarrick J. Wong * range we're interested in (refcount == 1) so 66531727258SDarrick J. Wong * create 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 cright->rc_startblock = max(agbno, xfs_refc_next(&tmp)); 67131727258SDarrick J. Wong cright->rc_blockcount = right->rc_startblock - 67231727258SDarrick J. Wong cright->rc_startblock; 67331727258SDarrick J. Wong cright->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 cright->rc_startblock = agbno; 68131727258SDarrick J. Wong cright->rc_blockcount = aglen; 68231727258SDarrick J. Wong cright->rc_refcount = 1; 68331727258SDarrick J. Wong } 68431727258SDarrick J. Wong trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_private.a.agno, 68531727258SDarrick J. Wong cright, right, agbno + aglen); 68631727258SDarrick J. Wong return error; 68731727258SDarrick J. Wong 68831727258SDarrick J. Wong out_error: 68931727258SDarrick J. Wong trace_xfs_refcount_find_right_extent_error(cur->bc_mp, 69031727258SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 69131727258SDarrick J. Wong return error; 69231727258SDarrick J. Wong } 69331727258SDarrick J. Wong 69431727258SDarrick J. Wong /* Is this extent valid? */ 69531727258SDarrick J. Wong static inline bool 69631727258SDarrick J. Wong xfs_refc_valid( 69731727258SDarrick J. Wong struct xfs_refcount_irec *rc) 69831727258SDarrick J. Wong { 69931727258SDarrick J. Wong return rc->rc_startblock != NULLAGBLOCK; 70031727258SDarrick J. Wong } 70131727258SDarrick J. Wong 70231727258SDarrick J. Wong /* 70331727258SDarrick J. Wong * Try to merge with any extents on the boundaries of the adjustment range. 70431727258SDarrick J. Wong */ 70531727258SDarrick J. Wong STATIC int 70631727258SDarrick J. Wong xfs_refcount_merge_extents( 70731727258SDarrick J. Wong struct xfs_btree_cur *cur, 70831727258SDarrick J. Wong xfs_agblock_t *agbno, 70931727258SDarrick J. Wong xfs_extlen_t *aglen, 71031727258SDarrick J. Wong enum xfs_refc_adjust_op adjust, 711174edb0eSDarrick J. Wong int flags, 71231727258SDarrick J. Wong bool *shape_changed) 71331727258SDarrick J. Wong { 71431727258SDarrick J. Wong struct xfs_refcount_irec left = {0}, cleft = {0}; 71531727258SDarrick J. Wong struct xfs_refcount_irec cright = {0}, right = {0}; 71631727258SDarrick J. Wong int error; 71731727258SDarrick J. Wong unsigned long long ulen; 71831727258SDarrick J. Wong bool cequal; 71931727258SDarrick J. Wong 72031727258SDarrick J. Wong *shape_changed = false; 72131727258SDarrick J. Wong /* 72231727258SDarrick J. Wong * Find the extent just below agbno [left], just above agbno [cleft], 72331727258SDarrick J. Wong * just below (agbno + aglen) [cright], and just above (agbno + aglen) 72431727258SDarrick J. Wong * [right]. 72531727258SDarrick J. Wong */ 72631727258SDarrick J. Wong error = xfs_refcount_find_left_extents(cur, &left, &cleft, *agbno, 727174edb0eSDarrick J. Wong *aglen, flags); 72831727258SDarrick J. Wong if (error) 72931727258SDarrick J. Wong return error; 73031727258SDarrick J. Wong error = xfs_refcount_find_right_extents(cur, &right, &cright, *agbno, 731174edb0eSDarrick J. Wong *aglen, flags); 73231727258SDarrick J. Wong if (error) 73331727258SDarrick J. Wong return error; 73431727258SDarrick J. Wong 73531727258SDarrick J. Wong /* No left or right extent to merge; exit. */ 73631727258SDarrick J. Wong if (!xfs_refc_valid(&left) && !xfs_refc_valid(&right)) 73731727258SDarrick J. Wong return 0; 73831727258SDarrick J. Wong 73931727258SDarrick J. Wong cequal = (cleft.rc_startblock == cright.rc_startblock) && 74031727258SDarrick J. Wong (cleft.rc_blockcount == cright.rc_blockcount); 74131727258SDarrick J. Wong 74231727258SDarrick J. Wong /* Try to merge left, cleft, and right. cleft must == cright. */ 74331727258SDarrick J. Wong ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount + 74431727258SDarrick J. Wong right.rc_blockcount; 74531727258SDarrick J. Wong if (xfs_refc_valid(&left) && xfs_refc_valid(&right) && 74631727258SDarrick J. Wong xfs_refc_valid(&cleft) && xfs_refc_valid(&cright) && cequal && 74731727258SDarrick J. Wong left.rc_refcount == cleft.rc_refcount + adjust && 74831727258SDarrick J. Wong right.rc_refcount == cleft.rc_refcount + adjust && 74931727258SDarrick J. Wong ulen < MAXREFCEXTLEN) { 75031727258SDarrick J. Wong *shape_changed = true; 75131727258SDarrick J. Wong return xfs_refcount_merge_center_extents(cur, &left, &cleft, 75231727258SDarrick J. Wong &right, ulen, agbno, aglen); 75331727258SDarrick J. Wong } 75431727258SDarrick J. Wong 75531727258SDarrick J. Wong /* Try to merge left and cleft. */ 75631727258SDarrick J. Wong ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount; 75731727258SDarrick J. Wong if (xfs_refc_valid(&left) && xfs_refc_valid(&cleft) && 75831727258SDarrick J. Wong left.rc_refcount == cleft.rc_refcount + adjust && 75931727258SDarrick J. Wong ulen < MAXREFCEXTLEN) { 76031727258SDarrick J. Wong *shape_changed = true; 76131727258SDarrick J. Wong error = xfs_refcount_merge_left_extent(cur, &left, &cleft, 76231727258SDarrick J. Wong agbno, aglen); 76331727258SDarrick J. Wong if (error) 76431727258SDarrick J. Wong return error; 76531727258SDarrick J. Wong 76631727258SDarrick J. Wong /* 76731727258SDarrick J. Wong * If we just merged left + cleft and cleft == cright, 76831727258SDarrick J. Wong * we no longer have a cright to merge with right. We're done. 76931727258SDarrick J. Wong */ 77031727258SDarrick J. Wong if (cequal) 77131727258SDarrick J. Wong return 0; 77231727258SDarrick J. Wong } 77331727258SDarrick J. Wong 77431727258SDarrick J. Wong /* Try to merge cright and right. */ 77531727258SDarrick J. Wong ulen = (unsigned long long)right.rc_blockcount + cright.rc_blockcount; 77631727258SDarrick J. Wong if (xfs_refc_valid(&right) && xfs_refc_valid(&cright) && 77731727258SDarrick J. Wong right.rc_refcount == cright.rc_refcount + adjust && 77831727258SDarrick J. Wong ulen < MAXREFCEXTLEN) { 77931727258SDarrick J. Wong *shape_changed = true; 78031727258SDarrick J. Wong return xfs_refcount_merge_right_extent(cur, &right, &cright, 78131727258SDarrick J. Wong agbno, aglen); 78231727258SDarrick J. Wong } 78331727258SDarrick J. Wong 78431727258SDarrick J. Wong return error; 78531727258SDarrick J. Wong } 78631727258SDarrick J. Wong 78731727258SDarrick J. Wong /* 78831727258SDarrick J. Wong * XXX: This is a pretty hand-wavy estimate. The penalty for guessing 78931727258SDarrick J. Wong * true incorrectly is a shutdown FS; the penalty for guessing false 79031727258SDarrick J. Wong * incorrectly is more transaction rolls than might be necessary. 79131727258SDarrick J. Wong * Be conservative here. 79231727258SDarrick J. Wong */ 79331727258SDarrick J. Wong static bool 79431727258SDarrick J. Wong xfs_refcount_still_have_space( 79531727258SDarrick J. Wong struct xfs_btree_cur *cur) 79631727258SDarrick J. Wong { 79731727258SDarrick J. Wong unsigned long overhead; 79831727258SDarrick J. Wong 79931727258SDarrick J. Wong overhead = cur->bc_private.a.priv.refc.shape_changes * 80031727258SDarrick J. Wong xfs_allocfree_log_count(cur->bc_mp, 1); 80131727258SDarrick J. Wong overhead *= cur->bc_mp->m_sb.sb_blocksize; 80231727258SDarrick J. Wong 80331727258SDarrick J. Wong /* 80431727258SDarrick J. Wong * Only allow 2 refcount extent updates per transaction if the 80531727258SDarrick J. Wong * refcount continue update "error" has been injected. 80631727258SDarrick J. Wong */ 80731727258SDarrick J. Wong if (cur->bc_private.a.priv.refc.nr_ops > 2 && 80831727258SDarrick J. Wong XFS_TEST_ERROR(false, cur->bc_mp, 8099e24cfd0SDarrick J. Wong XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE)) 81031727258SDarrick J. Wong return false; 81131727258SDarrick J. Wong 81231727258SDarrick J. Wong if (cur->bc_private.a.priv.refc.nr_ops == 0) 81331727258SDarrick J. Wong return true; 81431727258SDarrick J. Wong else if (overhead > cur->bc_tp->t_log_res) 81531727258SDarrick J. Wong return false; 81631727258SDarrick J. Wong return cur->bc_tp->t_log_res - overhead > 817e1a4e37cSDarrick J. Wong cur->bc_private.a.priv.refc.nr_ops * XFS_REFCOUNT_ITEM_OVERHEAD; 81831727258SDarrick J. Wong } 81931727258SDarrick J. Wong 82031727258SDarrick J. Wong /* 82131727258SDarrick J. Wong * Adjust the refcounts of middle extents. At this point we should have 82231727258SDarrick J. Wong * split extents that crossed the adjustment range; merged with adjacent 82331727258SDarrick J. Wong * extents; and updated agbno/aglen to reflect the merges. Therefore, 82431727258SDarrick J. Wong * all we have to do is update the extents inside [agbno, agbno + aglen]. 82531727258SDarrick J. Wong */ 82631727258SDarrick J. Wong STATIC int 82731727258SDarrick J. Wong xfs_refcount_adjust_extents( 82831727258SDarrick J. Wong struct xfs_btree_cur *cur, 82931727258SDarrick J. Wong xfs_agblock_t *agbno, 83031727258SDarrick J. Wong xfs_extlen_t *aglen, 83131727258SDarrick J. Wong enum xfs_refc_adjust_op adj, 83231727258SDarrick J. Wong struct xfs_defer_ops *dfops, 83331727258SDarrick J. Wong struct xfs_owner_info *oinfo) 83431727258SDarrick J. Wong { 83531727258SDarrick J. Wong struct xfs_refcount_irec ext, tmp; 83631727258SDarrick J. Wong int error; 83731727258SDarrick J. Wong int found_rec, found_tmp; 83831727258SDarrick J. Wong xfs_fsblock_t fsbno; 83931727258SDarrick J. Wong 84031727258SDarrick J. Wong /* Merging did all the work already. */ 84131727258SDarrick J. Wong if (*aglen == 0) 84231727258SDarrick J. Wong return 0; 84331727258SDarrick J. Wong 84431727258SDarrick J. Wong error = xfs_refcount_lookup_ge(cur, *agbno, &found_rec); 84531727258SDarrick J. Wong if (error) 84631727258SDarrick J. Wong goto out_error; 84731727258SDarrick J. Wong 84831727258SDarrick J. Wong while (*aglen > 0 && xfs_refcount_still_have_space(cur)) { 84931727258SDarrick J. Wong error = xfs_refcount_get_rec(cur, &ext, &found_rec); 85031727258SDarrick J. Wong if (error) 85131727258SDarrick J. Wong goto out_error; 85231727258SDarrick J. Wong if (!found_rec) { 85331727258SDarrick J. Wong ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks; 85431727258SDarrick J. Wong ext.rc_blockcount = 0; 85531727258SDarrick J. Wong ext.rc_refcount = 0; 85631727258SDarrick J. Wong } 85731727258SDarrick J. Wong 85831727258SDarrick J. Wong /* 85931727258SDarrick J. Wong * Deal with a hole in the refcount tree; if a file maps to 86031727258SDarrick J. Wong * these blocks and there's no refcountbt record, pretend that 86131727258SDarrick J. Wong * there is one with refcount == 1. 86231727258SDarrick J. Wong */ 86331727258SDarrick J. Wong if (ext.rc_startblock != *agbno) { 86431727258SDarrick J. Wong tmp.rc_startblock = *agbno; 86531727258SDarrick J. Wong tmp.rc_blockcount = min(*aglen, 86631727258SDarrick J. Wong ext.rc_startblock - *agbno); 86731727258SDarrick J. Wong tmp.rc_refcount = 1 + adj; 86831727258SDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 86931727258SDarrick J. Wong cur->bc_private.a.agno, &tmp); 87031727258SDarrick J. Wong 87131727258SDarrick J. Wong /* 87231727258SDarrick J. Wong * Either cover the hole (increment) or 87331727258SDarrick J. Wong * delete the range (decrement). 87431727258SDarrick J. Wong */ 87531727258SDarrick J. Wong if (tmp.rc_refcount) { 87631727258SDarrick J. Wong error = xfs_refcount_insert(cur, &tmp, 87731727258SDarrick J. Wong &found_tmp); 87831727258SDarrick J. Wong if (error) 87931727258SDarrick J. Wong goto out_error; 88031727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, 88131727258SDarrick J. Wong found_tmp == 1, out_error); 88231727258SDarrick J. Wong cur->bc_private.a.priv.refc.nr_ops++; 88331727258SDarrick J. Wong } else { 88431727258SDarrick J. Wong fsbno = XFS_AGB_TO_FSB(cur->bc_mp, 88531727258SDarrick J. Wong cur->bc_private.a.agno, 88631727258SDarrick J. Wong tmp.rc_startblock); 88731727258SDarrick J. Wong xfs_bmap_add_free(cur->bc_mp, dfops, fsbno, 88831727258SDarrick J. Wong tmp.rc_blockcount, oinfo); 88931727258SDarrick J. Wong } 89031727258SDarrick J. Wong 89131727258SDarrick J. Wong (*agbno) += tmp.rc_blockcount; 89231727258SDarrick J. Wong (*aglen) -= tmp.rc_blockcount; 89331727258SDarrick J. Wong 89431727258SDarrick J. Wong error = xfs_refcount_lookup_ge(cur, *agbno, 89531727258SDarrick J. Wong &found_rec); 89631727258SDarrick J. Wong if (error) 89731727258SDarrick J. Wong goto out_error; 89831727258SDarrick J. Wong } 89931727258SDarrick J. Wong 90031727258SDarrick J. Wong /* Stop if there's nothing left to modify */ 90131727258SDarrick J. Wong if (*aglen == 0 || !xfs_refcount_still_have_space(cur)) 90231727258SDarrick J. Wong break; 90331727258SDarrick J. Wong 90431727258SDarrick J. Wong /* 90531727258SDarrick J. Wong * Adjust the reference count and either update the tree 90631727258SDarrick J. Wong * (incr) or free the blocks (decr). 90731727258SDarrick J. Wong */ 90831727258SDarrick J. Wong if (ext.rc_refcount == MAXREFCOUNT) 90931727258SDarrick J. Wong goto skip; 91031727258SDarrick J. Wong ext.rc_refcount += adj; 91131727258SDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 91231727258SDarrick J. Wong cur->bc_private.a.agno, &ext); 91331727258SDarrick J. Wong if (ext.rc_refcount > 1) { 91431727258SDarrick J. Wong error = xfs_refcount_update(cur, &ext); 91531727258SDarrick J. Wong if (error) 91631727258SDarrick J. Wong goto out_error; 91731727258SDarrick J. Wong cur->bc_private.a.priv.refc.nr_ops++; 91831727258SDarrick J. Wong } else if (ext.rc_refcount == 1) { 91931727258SDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 92031727258SDarrick J. Wong if (error) 92131727258SDarrick J. Wong goto out_error; 92231727258SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, 92331727258SDarrick J. Wong found_rec == 1, out_error); 92431727258SDarrick J. Wong cur->bc_private.a.priv.refc.nr_ops++; 92531727258SDarrick J. Wong goto advloop; 92631727258SDarrick J. Wong } else { 92731727258SDarrick J. Wong fsbno = XFS_AGB_TO_FSB(cur->bc_mp, 92831727258SDarrick J. Wong cur->bc_private.a.agno, 92931727258SDarrick J. Wong ext.rc_startblock); 93031727258SDarrick J. Wong xfs_bmap_add_free(cur->bc_mp, dfops, fsbno, 93131727258SDarrick J. Wong ext.rc_blockcount, oinfo); 93231727258SDarrick J. Wong } 93331727258SDarrick J. Wong 93431727258SDarrick J. Wong skip: 93531727258SDarrick J. Wong error = xfs_btree_increment(cur, 0, &found_rec); 93631727258SDarrick J. Wong if (error) 93731727258SDarrick J. Wong goto out_error; 93831727258SDarrick J. Wong 93931727258SDarrick J. Wong advloop: 94031727258SDarrick J. Wong (*agbno) += ext.rc_blockcount; 94131727258SDarrick J. Wong (*aglen) -= ext.rc_blockcount; 94231727258SDarrick J. Wong } 94331727258SDarrick J. Wong 94431727258SDarrick J. Wong return error; 94531727258SDarrick J. Wong out_error: 94631727258SDarrick J. Wong trace_xfs_refcount_modify_extent_error(cur->bc_mp, 94731727258SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 94831727258SDarrick J. Wong return error; 94931727258SDarrick J. Wong } 95031727258SDarrick J. Wong 95131727258SDarrick J. Wong /* Adjust the reference count of a range of AG blocks. */ 95231727258SDarrick J. Wong STATIC int 95331727258SDarrick J. Wong xfs_refcount_adjust( 95431727258SDarrick J. Wong struct xfs_btree_cur *cur, 95531727258SDarrick J. Wong xfs_agblock_t agbno, 95631727258SDarrick J. Wong xfs_extlen_t aglen, 95731727258SDarrick J. Wong xfs_agblock_t *new_agbno, 95831727258SDarrick J. Wong xfs_extlen_t *new_aglen, 95931727258SDarrick J. Wong enum xfs_refc_adjust_op adj, 96031727258SDarrick J. Wong struct xfs_defer_ops *dfops, 96131727258SDarrick J. Wong struct xfs_owner_info *oinfo) 96231727258SDarrick J. Wong { 96331727258SDarrick J. Wong bool shape_changed; 96431727258SDarrick J. Wong int shape_changes = 0; 96531727258SDarrick J. Wong int error; 96631727258SDarrick J. Wong 96731727258SDarrick J. Wong *new_agbno = agbno; 96831727258SDarrick J. Wong *new_aglen = aglen; 96931727258SDarrick J. Wong if (adj == XFS_REFCOUNT_ADJUST_INCREASE) 97031727258SDarrick J. Wong trace_xfs_refcount_increase(cur->bc_mp, cur->bc_private.a.agno, 97131727258SDarrick J. Wong agbno, aglen); 97231727258SDarrick J. Wong else 97331727258SDarrick J. Wong trace_xfs_refcount_decrease(cur->bc_mp, cur->bc_private.a.agno, 97431727258SDarrick J. Wong agbno, aglen); 97531727258SDarrick J. Wong 97631727258SDarrick J. Wong /* 97731727258SDarrick J. Wong * Ensure that no rcextents cross the boundary of the adjustment range. 97831727258SDarrick J. Wong */ 97931727258SDarrick J. Wong error = xfs_refcount_split_extent(cur, agbno, &shape_changed); 98031727258SDarrick J. Wong if (error) 98131727258SDarrick J. Wong goto out_error; 98231727258SDarrick J. Wong if (shape_changed) 98331727258SDarrick J. Wong shape_changes++; 98431727258SDarrick J. Wong 98531727258SDarrick J. Wong error = xfs_refcount_split_extent(cur, agbno + aglen, &shape_changed); 98631727258SDarrick J. Wong if (error) 98731727258SDarrick J. Wong goto out_error; 98831727258SDarrick J. Wong if (shape_changed) 98931727258SDarrick J. Wong shape_changes++; 99031727258SDarrick J. Wong 99131727258SDarrick J. Wong /* 99231727258SDarrick J. Wong * Try to merge with the left or right extents of the range. 99331727258SDarrick J. Wong */ 99431727258SDarrick J. Wong error = xfs_refcount_merge_extents(cur, new_agbno, new_aglen, adj, 995174edb0eSDarrick J. Wong XFS_FIND_RCEXT_SHARED, &shape_changed); 99631727258SDarrick J. Wong if (error) 99731727258SDarrick J. Wong goto out_error; 99831727258SDarrick J. Wong if (shape_changed) 99931727258SDarrick J. Wong shape_changes++; 100031727258SDarrick J. Wong if (shape_changes) 100131727258SDarrick J. Wong cur->bc_private.a.priv.refc.shape_changes++; 100231727258SDarrick J. Wong 100331727258SDarrick J. Wong /* Now that we've taken care of the ends, adjust the middle extents */ 100431727258SDarrick J. Wong error = xfs_refcount_adjust_extents(cur, new_agbno, new_aglen, 100531727258SDarrick J. Wong adj, dfops, oinfo); 100631727258SDarrick J. Wong if (error) 100731727258SDarrick J. Wong goto out_error; 100831727258SDarrick J. Wong 100931727258SDarrick J. Wong return 0; 101031727258SDarrick J. Wong 101131727258SDarrick J. Wong out_error: 101231727258SDarrick J. Wong trace_xfs_refcount_adjust_error(cur->bc_mp, cur->bc_private.a.agno, 101331727258SDarrick J. Wong error, _RET_IP_); 101431727258SDarrick J. Wong return error; 101531727258SDarrick J. Wong } 101633ba6129SDarrick J. Wong 101733ba6129SDarrick J. Wong /* Clean up after calling xfs_refcount_finish_one. */ 101833ba6129SDarrick J. Wong void 101933ba6129SDarrick J. Wong xfs_refcount_finish_one_cleanup( 102033ba6129SDarrick J. Wong struct xfs_trans *tp, 102133ba6129SDarrick J. Wong struct xfs_btree_cur *rcur, 102233ba6129SDarrick J. Wong int error) 102333ba6129SDarrick J. Wong { 102433ba6129SDarrick J. Wong struct xfs_buf *agbp; 102533ba6129SDarrick J. Wong 102633ba6129SDarrick J. Wong if (rcur == NULL) 102733ba6129SDarrick J. Wong return; 102833ba6129SDarrick J. Wong agbp = rcur->bc_private.a.agbp; 102933ba6129SDarrick J. Wong xfs_btree_del_cursor(rcur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); 103033ba6129SDarrick J. Wong if (error) 103133ba6129SDarrick J. Wong xfs_trans_brelse(tp, agbp); 103233ba6129SDarrick J. Wong } 103333ba6129SDarrick J. Wong 103433ba6129SDarrick J. Wong /* 103533ba6129SDarrick J. Wong * Process one of the deferred refcount operations. We pass back the 103633ba6129SDarrick J. Wong * btree cursor to maintain our lock on the btree between calls. 103733ba6129SDarrick J. Wong * This saves time and eliminates a buffer deadlock between the 103833ba6129SDarrick J. Wong * superblock and the AGF because we'll always grab them in the same 103933ba6129SDarrick J. Wong * order. 104033ba6129SDarrick J. Wong */ 104133ba6129SDarrick J. Wong int 104233ba6129SDarrick J. Wong xfs_refcount_finish_one( 104333ba6129SDarrick J. Wong struct xfs_trans *tp, 104433ba6129SDarrick J. Wong struct xfs_defer_ops *dfops, 104533ba6129SDarrick J. Wong enum xfs_refcount_intent_type type, 104633ba6129SDarrick J. Wong xfs_fsblock_t startblock, 104733ba6129SDarrick J. Wong xfs_extlen_t blockcount, 104833ba6129SDarrick J. Wong xfs_fsblock_t *new_fsb, 104933ba6129SDarrick J. Wong xfs_extlen_t *new_len, 105033ba6129SDarrick J. Wong struct xfs_btree_cur **pcur) 105133ba6129SDarrick J. Wong { 105233ba6129SDarrick J. Wong struct xfs_mount *mp = tp->t_mountp; 105333ba6129SDarrick J. Wong struct xfs_btree_cur *rcur; 105433ba6129SDarrick J. Wong struct xfs_buf *agbp = NULL; 105533ba6129SDarrick J. Wong int error = 0; 105633ba6129SDarrick J. Wong xfs_agnumber_t agno; 105733ba6129SDarrick J. Wong xfs_agblock_t bno; 105833ba6129SDarrick J. Wong xfs_agblock_t new_agbno; 105933ba6129SDarrick J. Wong unsigned long nr_ops = 0; 106033ba6129SDarrick J. Wong int shape_changes = 0; 106133ba6129SDarrick J. Wong 106233ba6129SDarrick J. Wong agno = XFS_FSB_TO_AGNO(mp, startblock); 106333ba6129SDarrick J. Wong ASSERT(agno != NULLAGNUMBER); 106433ba6129SDarrick J. Wong bno = XFS_FSB_TO_AGBNO(mp, startblock); 106533ba6129SDarrick J. Wong 106633ba6129SDarrick J. Wong trace_xfs_refcount_deferred(mp, XFS_FSB_TO_AGNO(mp, startblock), 106733ba6129SDarrick J. Wong type, XFS_FSB_TO_AGBNO(mp, startblock), 106833ba6129SDarrick J. Wong blockcount); 106933ba6129SDarrick J. Wong 107033ba6129SDarrick J. Wong if (XFS_TEST_ERROR(false, mp, 10719e24cfd0SDarrick J. Wong XFS_ERRTAG_REFCOUNT_FINISH_ONE)) 107233ba6129SDarrick J. Wong return -EIO; 107333ba6129SDarrick J. Wong 107433ba6129SDarrick J. Wong /* 107533ba6129SDarrick J. Wong * If we haven't gotten a cursor or the cursor AG doesn't match 107633ba6129SDarrick J. Wong * the startblock, get one now. 107733ba6129SDarrick J. Wong */ 107833ba6129SDarrick J. Wong rcur = *pcur; 107933ba6129SDarrick J. Wong if (rcur != NULL && rcur->bc_private.a.agno != agno) { 108033ba6129SDarrick J. Wong nr_ops = rcur->bc_private.a.priv.refc.nr_ops; 108133ba6129SDarrick J. Wong shape_changes = rcur->bc_private.a.priv.refc.shape_changes; 108233ba6129SDarrick J. Wong xfs_refcount_finish_one_cleanup(tp, rcur, 0); 108333ba6129SDarrick J. Wong rcur = NULL; 108433ba6129SDarrick J. Wong *pcur = NULL; 108533ba6129SDarrick J. Wong } 108633ba6129SDarrick J. Wong if (rcur == NULL) { 108733ba6129SDarrick J. Wong error = xfs_alloc_read_agf(tp->t_mountp, tp, agno, 108833ba6129SDarrick J. Wong XFS_ALLOC_FLAG_FREEING, &agbp); 108933ba6129SDarrick J. Wong if (error) 109033ba6129SDarrick J. Wong return error; 109133ba6129SDarrick J. Wong if (!agbp) 109233ba6129SDarrick J. Wong return -EFSCORRUPTED; 109333ba6129SDarrick J. Wong 109433ba6129SDarrick J. Wong rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, dfops); 109533ba6129SDarrick J. Wong if (!rcur) { 109633ba6129SDarrick J. Wong error = -ENOMEM; 109733ba6129SDarrick J. Wong goto out_cur; 109833ba6129SDarrick J. Wong } 109933ba6129SDarrick J. Wong rcur->bc_private.a.priv.refc.nr_ops = nr_ops; 110033ba6129SDarrick J. Wong rcur->bc_private.a.priv.refc.shape_changes = shape_changes; 110133ba6129SDarrick J. Wong } 110233ba6129SDarrick J. Wong *pcur = rcur; 110333ba6129SDarrick J. Wong 110433ba6129SDarrick J. Wong switch (type) { 110533ba6129SDarrick J. Wong case XFS_REFCOUNT_INCREASE: 110633ba6129SDarrick J. Wong error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno, 110733ba6129SDarrick J. Wong new_len, XFS_REFCOUNT_ADJUST_INCREASE, dfops, NULL); 110833ba6129SDarrick J. Wong *new_fsb = XFS_AGB_TO_FSB(mp, agno, new_agbno); 110933ba6129SDarrick J. Wong break; 111033ba6129SDarrick J. Wong case XFS_REFCOUNT_DECREASE: 111133ba6129SDarrick J. Wong error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno, 111233ba6129SDarrick J. Wong new_len, XFS_REFCOUNT_ADJUST_DECREASE, dfops, NULL); 111333ba6129SDarrick J. Wong *new_fsb = XFS_AGB_TO_FSB(mp, agno, new_agbno); 111433ba6129SDarrick J. Wong break; 1115174edb0eSDarrick J. Wong case XFS_REFCOUNT_ALLOC_COW: 1116174edb0eSDarrick J. Wong *new_fsb = startblock + blockcount; 1117174edb0eSDarrick J. Wong *new_len = 0; 1118174edb0eSDarrick J. Wong error = __xfs_refcount_cow_alloc(rcur, bno, blockcount, dfops); 1119174edb0eSDarrick J. Wong break; 1120174edb0eSDarrick J. Wong case XFS_REFCOUNT_FREE_COW: 1121174edb0eSDarrick J. Wong *new_fsb = startblock + blockcount; 1122174edb0eSDarrick J. Wong *new_len = 0; 1123174edb0eSDarrick J. Wong error = __xfs_refcount_cow_free(rcur, bno, blockcount, dfops); 1124174edb0eSDarrick J. Wong break; 112533ba6129SDarrick J. Wong default: 112633ba6129SDarrick J. Wong ASSERT(0); 112733ba6129SDarrick J. Wong error = -EFSCORRUPTED; 112833ba6129SDarrick J. Wong } 112933ba6129SDarrick J. Wong if (!error && *new_len > 0) 113033ba6129SDarrick J. Wong trace_xfs_refcount_finish_one_leftover(mp, agno, type, 113133ba6129SDarrick J. Wong bno, blockcount, new_agbno, *new_len); 113233ba6129SDarrick J. Wong return error; 113333ba6129SDarrick J. Wong 113433ba6129SDarrick J. Wong out_cur: 113533ba6129SDarrick J. Wong xfs_trans_brelse(tp, agbp); 113633ba6129SDarrick J. Wong 113733ba6129SDarrick J. Wong return error; 113833ba6129SDarrick J. Wong } 113933ba6129SDarrick J. Wong 114033ba6129SDarrick J. Wong /* 114133ba6129SDarrick J. Wong * Record a refcount intent for later processing. 114233ba6129SDarrick J. Wong */ 114333ba6129SDarrick J. Wong static int 114433ba6129SDarrick J. Wong __xfs_refcount_add( 114533ba6129SDarrick J. Wong struct xfs_mount *mp, 114633ba6129SDarrick J. Wong struct xfs_defer_ops *dfops, 114733ba6129SDarrick J. Wong enum xfs_refcount_intent_type type, 114833ba6129SDarrick J. Wong xfs_fsblock_t startblock, 114933ba6129SDarrick J. Wong xfs_extlen_t blockcount) 115033ba6129SDarrick J. Wong { 115133ba6129SDarrick J. Wong struct xfs_refcount_intent *ri; 115233ba6129SDarrick J. Wong 115333ba6129SDarrick J. Wong trace_xfs_refcount_defer(mp, XFS_FSB_TO_AGNO(mp, startblock), 115433ba6129SDarrick J. Wong type, XFS_FSB_TO_AGBNO(mp, startblock), 115533ba6129SDarrick J. Wong blockcount); 115633ba6129SDarrick J. Wong 115733ba6129SDarrick J. Wong ri = kmem_alloc(sizeof(struct xfs_refcount_intent), 115833ba6129SDarrick J. Wong KM_SLEEP | KM_NOFS); 115933ba6129SDarrick J. Wong INIT_LIST_HEAD(&ri->ri_list); 116033ba6129SDarrick J. Wong ri->ri_type = type; 116133ba6129SDarrick J. Wong ri->ri_startblock = startblock; 116233ba6129SDarrick J. Wong ri->ri_blockcount = blockcount; 116333ba6129SDarrick J. Wong 116433ba6129SDarrick J. Wong xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_REFCOUNT, &ri->ri_list); 116533ba6129SDarrick J. Wong return 0; 116633ba6129SDarrick J. Wong } 116733ba6129SDarrick J. Wong 116833ba6129SDarrick J. Wong /* 116933ba6129SDarrick J. Wong * Increase the reference count of the blocks backing a file's extent. 117033ba6129SDarrick J. Wong */ 117133ba6129SDarrick J. Wong int 117233ba6129SDarrick J. Wong xfs_refcount_increase_extent( 117333ba6129SDarrick J. Wong struct xfs_mount *mp, 117433ba6129SDarrick J. Wong struct xfs_defer_ops *dfops, 117533ba6129SDarrick J. Wong struct xfs_bmbt_irec *PREV) 117633ba6129SDarrick J. Wong { 117733ba6129SDarrick J. Wong if (!xfs_sb_version_hasreflink(&mp->m_sb)) 117833ba6129SDarrick J. Wong return 0; 117933ba6129SDarrick J. Wong 118033ba6129SDarrick J. Wong return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_INCREASE, 118133ba6129SDarrick J. Wong PREV->br_startblock, PREV->br_blockcount); 118233ba6129SDarrick J. Wong } 118333ba6129SDarrick J. Wong 118433ba6129SDarrick J. Wong /* 118533ba6129SDarrick J. Wong * Decrease the reference count of the blocks backing a file's extent. 118633ba6129SDarrick J. Wong */ 118733ba6129SDarrick J. Wong int 118833ba6129SDarrick J. Wong xfs_refcount_decrease_extent( 118933ba6129SDarrick J. Wong struct xfs_mount *mp, 119033ba6129SDarrick J. Wong struct xfs_defer_ops *dfops, 119133ba6129SDarrick J. Wong struct xfs_bmbt_irec *PREV) 119233ba6129SDarrick J. Wong { 119333ba6129SDarrick J. Wong if (!xfs_sb_version_hasreflink(&mp->m_sb)) 119433ba6129SDarrick J. Wong return 0; 119533ba6129SDarrick J. Wong 119633ba6129SDarrick J. Wong return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_DECREASE, 119733ba6129SDarrick J. Wong PREV->br_startblock, PREV->br_blockcount); 119833ba6129SDarrick J. Wong } 1199350a27a6SDarrick J. Wong 1200350a27a6SDarrick J. Wong /* 1201350a27a6SDarrick J. Wong * Given an AG extent, find the lowest-numbered run of shared blocks 1202350a27a6SDarrick J. Wong * within that range and return the range in fbno/flen. If 1203350a27a6SDarrick J. Wong * find_end_of_shared is set, return the longest contiguous extent of 1204350a27a6SDarrick J. Wong * shared blocks; if not, just return the first extent we find. If no 1205350a27a6SDarrick J. Wong * shared blocks are found, fbno and flen will be set to NULLAGBLOCK 1206350a27a6SDarrick J. Wong * and 0, respectively. 1207350a27a6SDarrick J. Wong */ 1208350a27a6SDarrick J. Wong int 1209350a27a6SDarrick J. Wong xfs_refcount_find_shared( 1210350a27a6SDarrick J. Wong struct xfs_btree_cur *cur, 1211350a27a6SDarrick J. Wong xfs_agblock_t agbno, 1212350a27a6SDarrick J. Wong xfs_extlen_t aglen, 1213350a27a6SDarrick J. Wong xfs_agblock_t *fbno, 1214350a27a6SDarrick J. Wong xfs_extlen_t *flen, 1215350a27a6SDarrick J. Wong bool find_end_of_shared) 1216350a27a6SDarrick J. Wong { 1217350a27a6SDarrick J. Wong struct xfs_refcount_irec tmp; 1218350a27a6SDarrick J. Wong int i; 1219350a27a6SDarrick J. Wong int have; 1220350a27a6SDarrick J. Wong int error; 1221350a27a6SDarrick J. Wong 1222350a27a6SDarrick J. Wong trace_xfs_refcount_find_shared(cur->bc_mp, cur->bc_private.a.agno, 1223350a27a6SDarrick J. Wong agbno, aglen); 1224350a27a6SDarrick J. Wong 1225350a27a6SDarrick J. Wong /* By default, skip the whole range */ 1226350a27a6SDarrick J. Wong *fbno = NULLAGBLOCK; 1227350a27a6SDarrick J. Wong *flen = 0; 1228350a27a6SDarrick J. Wong 1229350a27a6SDarrick J. Wong /* Try to find a refcount extent that crosses the start */ 1230350a27a6SDarrick J. Wong error = xfs_refcount_lookup_le(cur, agbno, &have); 1231350a27a6SDarrick J. Wong if (error) 1232350a27a6SDarrick J. Wong goto out_error; 1233350a27a6SDarrick J. Wong if (!have) { 1234350a27a6SDarrick J. Wong /* No left extent, look at the next one */ 1235350a27a6SDarrick J. Wong error = xfs_btree_increment(cur, 0, &have); 1236350a27a6SDarrick J. Wong if (error) 1237350a27a6SDarrick J. Wong goto out_error; 1238350a27a6SDarrick J. Wong if (!have) 1239350a27a6SDarrick J. Wong goto done; 1240350a27a6SDarrick J. Wong } 1241350a27a6SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &i); 1242350a27a6SDarrick J. Wong if (error) 1243350a27a6SDarrick J. Wong goto out_error; 1244350a27a6SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, out_error); 1245350a27a6SDarrick J. Wong 1246350a27a6SDarrick J. Wong /* If the extent ends before the start, look at the next one */ 1247350a27a6SDarrick J. Wong if (tmp.rc_startblock + tmp.rc_blockcount <= agbno) { 1248350a27a6SDarrick J. Wong error = xfs_btree_increment(cur, 0, &have); 1249350a27a6SDarrick J. Wong if (error) 1250350a27a6SDarrick J. Wong goto out_error; 1251350a27a6SDarrick J. Wong if (!have) 1252350a27a6SDarrick J. Wong goto done; 1253350a27a6SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &i); 1254350a27a6SDarrick J. Wong if (error) 1255350a27a6SDarrick J. Wong goto out_error; 1256350a27a6SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, out_error); 1257350a27a6SDarrick J. Wong } 1258350a27a6SDarrick J. Wong 1259350a27a6SDarrick J. Wong /* If the extent starts after the range we want, bail out */ 1260350a27a6SDarrick J. Wong if (tmp.rc_startblock >= agbno + aglen) 1261350a27a6SDarrick J. Wong goto done; 1262350a27a6SDarrick J. Wong 1263350a27a6SDarrick J. Wong /* We found the start of a shared extent! */ 1264350a27a6SDarrick J. Wong if (tmp.rc_startblock < agbno) { 1265350a27a6SDarrick J. Wong tmp.rc_blockcount -= (agbno - tmp.rc_startblock); 1266350a27a6SDarrick J. Wong tmp.rc_startblock = agbno; 1267350a27a6SDarrick J. Wong } 1268350a27a6SDarrick J. Wong 1269350a27a6SDarrick J. Wong *fbno = tmp.rc_startblock; 1270350a27a6SDarrick J. Wong *flen = min(tmp.rc_blockcount, agbno + aglen - *fbno); 1271350a27a6SDarrick J. Wong if (!find_end_of_shared) 1272350a27a6SDarrick J. Wong goto done; 1273350a27a6SDarrick J. Wong 1274350a27a6SDarrick J. Wong /* Otherwise, find the end of this shared extent */ 1275350a27a6SDarrick J. Wong while (*fbno + *flen < agbno + aglen) { 1276350a27a6SDarrick J. Wong error = xfs_btree_increment(cur, 0, &have); 1277350a27a6SDarrick J. Wong if (error) 1278350a27a6SDarrick J. Wong goto out_error; 1279350a27a6SDarrick J. Wong if (!have) 1280350a27a6SDarrick J. Wong break; 1281350a27a6SDarrick J. Wong error = xfs_refcount_get_rec(cur, &tmp, &i); 1282350a27a6SDarrick J. Wong if (error) 1283350a27a6SDarrick J. Wong goto out_error; 1284350a27a6SDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, out_error); 1285350a27a6SDarrick J. Wong if (tmp.rc_startblock >= agbno + aglen || 1286350a27a6SDarrick J. Wong tmp.rc_startblock != *fbno + *flen) 1287350a27a6SDarrick J. Wong break; 1288350a27a6SDarrick J. Wong *flen = min(*flen + tmp.rc_blockcount, agbno + aglen - *fbno); 1289350a27a6SDarrick J. Wong } 1290350a27a6SDarrick J. Wong 1291350a27a6SDarrick J. Wong done: 1292350a27a6SDarrick J. Wong trace_xfs_refcount_find_shared_result(cur->bc_mp, 1293350a27a6SDarrick J. Wong cur->bc_private.a.agno, *fbno, *flen); 1294350a27a6SDarrick J. Wong 1295350a27a6SDarrick J. Wong out_error: 1296350a27a6SDarrick J. Wong if (error) 1297350a27a6SDarrick J. Wong trace_xfs_refcount_find_shared_error(cur->bc_mp, 1298350a27a6SDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 1299350a27a6SDarrick J. Wong return error; 1300350a27a6SDarrick J. Wong } 1301174edb0eSDarrick J. Wong 1302174edb0eSDarrick J. Wong /* 1303174edb0eSDarrick J. Wong * Recovering CoW Blocks After a Crash 1304174edb0eSDarrick J. Wong * 1305174edb0eSDarrick J. Wong * Due to the way that the copy on write mechanism works, there's a window of 1306174edb0eSDarrick J. Wong * opportunity in which we can lose track of allocated blocks during a crash. 1307174edb0eSDarrick J. Wong * Because CoW uses delayed allocation in the in-core CoW fork, writeback 1308174edb0eSDarrick J. Wong * causes blocks to be allocated and stored in the CoW fork. The blocks are 1309174edb0eSDarrick J. Wong * no longer in the free space btree but are not otherwise recorded anywhere 1310174edb0eSDarrick J. Wong * until the write completes and the blocks are mapped into the file. A crash 1311174edb0eSDarrick J. Wong * in between allocation and remapping results in the replacement blocks being 1312174edb0eSDarrick J. Wong * lost. This situation is exacerbated by the CoW extent size hint because 1313174edb0eSDarrick J. Wong * allocations can hang around for long time. 1314174edb0eSDarrick J. Wong * 1315174edb0eSDarrick J. Wong * However, there is a place where we can record these allocations before they 1316174edb0eSDarrick J. Wong * become mappings -- the reference count btree. The btree does not record 1317174edb0eSDarrick J. Wong * extents with refcount == 1, so we can record allocations with a refcount of 1318174edb0eSDarrick J. Wong * 1. Blocks being used for CoW writeout cannot be shared, so there should be 1319174edb0eSDarrick J. Wong * no conflict with shared block records. These mappings should be created 1320174edb0eSDarrick J. Wong * when we allocate blocks to the CoW fork and deleted when they're removed 1321174edb0eSDarrick J. Wong * from the CoW fork. 1322174edb0eSDarrick J. Wong * 1323174edb0eSDarrick J. Wong * Minor nit: records for in-progress CoW allocations and records for shared 1324174edb0eSDarrick J. Wong * extents must never be merged, to preserve the property that (except for CoW 1325174edb0eSDarrick J. Wong * allocations) there are no refcount btree entries with refcount == 1. The 1326174edb0eSDarrick J. Wong * only time this could potentially happen is when unsharing a block that's 1327174edb0eSDarrick J. Wong * adjacent to CoW allocations, so we must be careful to avoid this. 1328174edb0eSDarrick J. Wong * 1329174edb0eSDarrick J. Wong * At mount time we recover lost CoW allocations by searching the refcount 1330174edb0eSDarrick J. Wong * btree for these refcount == 1 mappings. These represent CoW allocations 1331174edb0eSDarrick J. Wong * that were in progress at the time the filesystem went down, so we can free 1332174edb0eSDarrick J. Wong * them to get the space back. 1333174edb0eSDarrick J. Wong * 1334174edb0eSDarrick J. Wong * This mechanism is superior to creating EFIs for unmapped CoW extents for 1335174edb0eSDarrick J. Wong * several reasons -- first, EFIs pin the tail of the log and would have to be 1336174edb0eSDarrick J. Wong * periodically relogged to avoid filling up the log. Second, CoW completions 1337174edb0eSDarrick J. Wong * will have to file an EFD and create new EFIs for whatever remains in the 1338174edb0eSDarrick J. Wong * CoW fork; this partially takes care of (1) but extent-size reservations 1339174edb0eSDarrick J. Wong * will have to periodically relog even if there's no writeout in progress. 1340174edb0eSDarrick J. Wong * This can happen if the CoW extent size hint is set, which you really want. 1341174edb0eSDarrick J. Wong * Third, EFIs cannot currently be automatically relogged into newer 1342174edb0eSDarrick J. Wong * transactions to advance the log tail. Fourth, stuffing the log full of 1343174edb0eSDarrick J. Wong * EFIs places an upper bound on the number of CoW allocations that can be 1344174edb0eSDarrick J. Wong * held filesystem-wide at any given time. Recording them in the refcount 1345174edb0eSDarrick J. Wong * btree doesn't require us to maintain any state in memory and doesn't pin 1346174edb0eSDarrick J. Wong * the log. 1347174edb0eSDarrick J. Wong */ 1348174edb0eSDarrick J. Wong /* 1349174edb0eSDarrick J. Wong * Adjust the refcounts of CoW allocations. These allocations are "magic" 1350174edb0eSDarrick J. Wong * in that they're not referenced anywhere else in the filesystem, so we 1351174edb0eSDarrick J. Wong * stash them in the refcount btree with a refcount of 1 until either file 1352174edb0eSDarrick J. Wong * remapping (or CoW cancellation) happens. 1353174edb0eSDarrick J. Wong */ 1354174edb0eSDarrick J. Wong STATIC int 1355174edb0eSDarrick J. Wong xfs_refcount_adjust_cow_extents( 1356174edb0eSDarrick J. Wong struct xfs_btree_cur *cur, 1357174edb0eSDarrick J. Wong xfs_agblock_t agbno, 1358174edb0eSDarrick J. Wong xfs_extlen_t aglen, 1359174edb0eSDarrick J. Wong enum xfs_refc_adjust_op adj, 1360174edb0eSDarrick J. Wong struct xfs_defer_ops *dfops, 1361174edb0eSDarrick J. Wong struct xfs_owner_info *oinfo) 1362174edb0eSDarrick J. Wong { 1363174edb0eSDarrick J. Wong struct xfs_refcount_irec ext, tmp; 1364174edb0eSDarrick J. Wong int error; 1365174edb0eSDarrick J. Wong int found_rec, found_tmp; 1366174edb0eSDarrick J. Wong 1367174edb0eSDarrick J. Wong if (aglen == 0) 1368174edb0eSDarrick J. Wong return 0; 1369174edb0eSDarrick J. Wong 1370174edb0eSDarrick J. Wong /* Find any overlapping refcount records */ 1371174edb0eSDarrick J. Wong error = xfs_refcount_lookup_ge(cur, agbno, &found_rec); 1372174edb0eSDarrick J. Wong if (error) 1373174edb0eSDarrick J. Wong goto out_error; 1374174edb0eSDarrick J. Wong error = xfs_refcount_get_rec(cur, &ext, &found_rec); 1375174edb0eSDarrick J. Wong if (error) 1376174edb0eSDarrick J. Wong goto out_error; 1377174edb0eSDarrick J. Wong if (!found_rec) { 1378174edb0eSDarrick J. Wong ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks + 1379174edb0eSDarrick J. Wong XFS_REFC_COW_START; 1380174edb0eSDarrick J. Wong ext.rc_blockcount = 0; 1381174edb0eSDarrick J. Wong ext.rc_refcount = 0; 1382174edb0eSDarrick J. Wong } 1383174edb0eSDarrick J. Wong 1384174edb0eSDarrick J. Wong switch (adj) { 1385174edb0eSDarrick J. Wong case XFS_REFCOUNT_ADJUST_COW_ALLOC: 1386174edb0eSDarrick J. Wong /* Adding a CoW reservation, there should be nothing here. */ 1387174edb0eSDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, 1388174edb0eSDarrick J. Wong ext.rc_startblock >= agbno + aglen, out_error); 1389174edb0eSDarrick J. Wong 1390174edb0eSDarrick J. Wong tmp.rc_startblock = agbno; 1391174edb0eSDarrick J. Wong tmp.rc_blockcount = aglen; 1392174edb0eSDarrick J. Wong tmp.rc_refcount = 1; 1393174edb0eSDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 1394174edb0eSDarrick J. Wong cur->bc_private.a.agno, &tmp); 1395174edb0eSDarrick J. Wong 1396174edb0eSDarrick J. Wong error = xfs_refcount_insert(cur, &tmp, 1397174edb0eSDarrick J. Wong &found_tmp); 1398174edb0eSDarrick J. Wong if (error) 1399174edb0eSDarrick J. Wong goto out_error; 1400174edb0eSDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, 1401174edb0eSDarrick J. Wong found_tmp == 1, out_error); 1402174edb0eSDarrick J. Wong break; 1403174edb0eSDarrick J. Wong case XFS_REFCOUNT_ADJUST_COW_FREE: 1404174edb0eSDarrick J. Wong /* Removing a CoW reservation, there should be one extent. */ 1405174edb0eSDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, 1406174edb0eSDarrick J. Wong ext.rc_startblock == agbno, out_error); 1407174edb0eSDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, 1408174edb0eSDarrick J. Wong ext.rc_blockcount == aglen, out_error); 1409174edb0eSDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, 1410174edb0eSDarrick J. Wong ext.rc_refcount == 1, out_error); 1411174edb0eSDarrick J. Wong 1412174edb0eSDarrick J. Wong ext.rc_refcount = 0; 1413174edb0eSDarrick J. Wong trace_xfs_refcount_modify_extent(cur->bc_mp, 1414174edb0eSDarrick J. Wong cur->bc_private.a.agno, &ext); 1415174edb0eSDarrick J. Wong error = xfs_refcount_delete(cur, &found_rec); 1416174edb0eSDarrick J. Wong if (error) 1417174edb0eSDarrick J. Wong goto out_error; 1418174edb0eSDarrick J. Wong XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, 1419174edb0eSDarrick J. Wong found_rec == 1, out_error); 1420174edb0eSDarrick J. Wong break; 1421174edb0eSDarrick J. Wong default: 1422174edb0eSDarrick J. Wong ASSERT(0); 1423174edb0eSDarrick J. Wong } 1424174edb0eSDarrick J. Wong 1425174edb0eSDarrick J. Wong return error; 1426174edb0eSDarrick J. Wong out_error: 1427174edb0eSDarrick J. Wong trace_xfs_refcount_modify_extent_error(cur->bc_mp, 1428174edb0eSDarrick J. Wong cur->bc_private.a.agno, error, _RET_IP_); 1429174edb0eSDarrick J. Wong return error; 1430174edb0eSDarrick J. Wong } 1431174edb0eSDarrick J. Wong 1432174edb0eSDarrick J. Wong /* 1433174edb0eSDarrick J. Wong * Add or remove refcount btree entries for CoW reservations. 1434174edb0eSDarrick J. Wong */ 1435174edb0eSDarrick J. Wong STATIC int 1436174edb0eSDarrick J. Wong xfs_refcount_adjust_cow( 1437174edb0eSDarrick J. Wong struct xfs_btree_cur *cur, 1438174edb0eSDarrick J. Wong xfs_agblock_t agbno, 1439174edb0eSDarrick J. Wong xfs_extlen_t aglen, 1440174edb0eSDarrick J. Wong enum xfs_refc_adjust_op adj, 1441174edb0eSDarrick J. Wong struct xfs_defer_ops *dfops) 1442174edb0eSDarrick J. Wong { 1443174edb0eSDarrick J. Wong bool shape_changed; 1444174edb0eSDarrick J. Wong int error; 1445174edb0eSDarrick J. Wong 1446174edb0eSDarrick J. Wong agbno += XFS_REFC_COW_START; 1447174edb0eSDarrick J. Wong 1448174edb0eSDarrick J. Wong /* 1449174edb0eSDarrick J. Wong * Ensure that no rcextents cross the boundary of the adjustment range. 1450174edb0eSDarrick J. Wong */ 1451174edb0eSDarrick J. Wong error = xfs_refcount_split_extent(cur, agbno, &shape_changed); 1452174edb0eSDarrick J. Wong if (error) 1453174edb0eSDarrick J. Wong goto out_error; 1454174edb0eSDarrick J. Wong 1455174edb0eSDarrick J. Wong error = xfs_refcount_split_extent(cur, agbno + aglen, &shape_changed); 1456174edb0eSDarrick J. Wong if (error) 1457174edb0eSDarrick J. Wong goto out_error; 1458174edb0eSDarrick J. Wong 1459174edb0eSDarrick J. Wong /* 1460174edb0eSDarrick J. Wong * Try to merge with the left or right extents of the range. 1461174edb0eSDarrick J. Wong */ 1462174edb0eSDarrick J. Wong error = xfs_refcount_merge_extents(cur, &agbno, &aglen, adj, 1463174edb0eSDarrick J. Wong XFS_FIND_RCEXT_COW, &shape_changed); 1464174edb0eSDarrick J. Wong if (error) 1465174edb0eSDarrick J. Wong goto out_error; 1466174edb0eSDarrick J. Wong 1467174edb0eSDarrick J. Wong /* Now that we've taken care of the ends, adjust the middle extents */ 1468174edb0eSDarrick J. Wong error = xfs_refcount_adjust_cow_extents(cur, agbno, aglen, adj, 1469174edb0eSDarrick J. Wong dfops, NULL); 1470174edb0eSDarrick J. Wong if (error) 1471174edb0eSDarrick J. Wong goto out_error; 1472174edb0eSDarrick J. Wong 1473174edb0eSDarrick J. Wong return 0; 1474174edb0eSDarrick J. Wong 1475174edb0eSDarrick J. Wong out_error: 1476174edb0eSDarrick J. Wong trace_xfs_refcount_adjust_cow_error(cur->bc_mp, cur->bc_private.a.agno, 1477174edb0eSDarrick J. Wong error, _RET_IP_); 1478174edb0eSDarrick J. Wong return error; 1479174edb0eSDarrick J. Wong } 1480174edb0eSDarrick J. Wong 1481174edb0eSDarrick J. Wong /* 1482174edb0eSDarrick J. Wong * Record a CoW allocation in the refcount btree. 1483174edb0eSDarrick J. Wong */ 1484174edb0eSDarrick J. Wong STATIC int 1485174edb0eSDarrick J. Wong __xfs_refcount_cow_alloc( 1486174edb0eSDarrick J. Wong struct xfs_btree_cur *rcur, 1487174edb0eSDarrick J. Wong xfs_agblock_t agbno, 1488174edb0eSDarrick J. Wong xfs_extlen_t aglen, 1489174edb0eSDarrick J. Wong struct xfs_defer_ops *dfops) 1490174edb0eSDarrick J. Wong { 1491174edb0eSDarrick J. Wong int error; 1492174edb0eSDarrick J. Wong 1493174edb0eSDarrick J. Wong trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_private.a.agno, 1494174edb0eSDarrick J. Wong agbno, aglen); 1495174edb0eSDarrick J. Wong 1496174edb0eSDarrick J. Wong /* Add refcount btree reservation */ 1497174edb0eSDarrick J. Wong error = xfs_refcount_adjust_cow(rcur, agbno, aglen, 1498174edb0eSDarrick J. Wong XFS_REFCOUNT_ADJUST_COW_ALLOC, dfops); 1499174edb0eSDarrick J. Wong if (error) 1500174edb0eSDarrick J. Wong return error; 1501174edb0eSDarrick J. Wong 1502174edb0eSDarrick J. Wong /* Add rmap entry */ 1503174edb0eSDarrick J. Wong if (xfs_sb_version_hasrmapbt(&rcur->bc_mp->m_sb)) { 1504174edb0eSDarrick J. Wong error = xfs_rmap_alloc_extent(rcur->bc_mp, dfops, 1505174edb0eSDarrick J. Wong rcur->bc_private.a.agno, 1506174edb0eSDarrick J. Wong agbno, aglen, XFS_RMAP_OWN_COW); 1507174edb0eSDarrick J. Wong if (error) 1508174edb0eSDarrick J. Wong return error; 1509174edb0eSDarrick J. Wong } 1510174edb0eSDarrick J. Wong 1511174edb0eSDarrick J. Wong return error; 1512174edb0eSDarrick J. Wong } 1513174edb0eSDarrick J. Wong 1514174edb0eSDarrick J. Wong /* 1515174edb0eSDarrick J. Wong * Remove a CoW allocation from the refcount btree. 1516174edb0eSDarrick J. Wong */ 1517174edb0eSDarrick J. Wong STATIC int 1518174edb0eSDarrick J. Wong __xfs_refcount_cow_free( 1519174edb0eSDarrick J. Wong struct xfs_btree_cur *rcur, 1520174edb0eSDarrick J. Wong xfs_agblock_t agbno, 1521174edb0eSDarrick J. Wong xfs_extlen_t aglen, 1522174edb0eSDarrick J. Wong struct xfs_defer_ops *dfops) 1523174edb0eSDarrick J. Wong { 1524174edb0eSDarrick J. Wong int error; 1525174edb0eSDarrick J. Wong 1526174edb0eSDarrick J. Wong trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_private.a.agno, 1527174edb0eSDarrick J. Wong agbno, aglen); 1528174edb0eSDarrick J. Wong 1529174edb0eSDarrick J. Wong /* Remove refcount btree reservation */ 1530174edb0eSDarrick J. Wong error = xfs_refcount_adjust_cow(rcur, agbno, aglen, 1531174edb0eSDarrick J. Wong XFS_REFCOUNT_ADJUST_COW_FREE, dfops); 1532174edb0eSDarrick J. Wong if (error) 1533174edb0eSDarrick J. Wong return error; 1534174edb0eSDarrick J. Wong 1535174edb0eSDarrick J. Wong /* Remove rmap entry */ 1536174edb0eSDarrick J. Wong if (xfs_sb_version_hasrmapbt(&rcur->bc_mp->m_sb)) { 1537174edb0eSDarrick J. Wong error = xfs_rmap_free_extent(rcur->bc_mp, dfops, 1538174edb0eSDarrick J. Wong rcur->bc_private.a.agno, 1539174edb0eSDarrick J. Wong agbno, aglen, XFS_RMAP_OWN_COW); 1540174edb0eSDarrick J. Wong if (error) 1541174edb0eSDarrick J. Wong return error; 1542174edb0eSDarrick J. Wong } 1543174edb0eSDarrick J. Wong 1544174edb0eSDarrick J. Wong return error; 1545174edb0eSDarrick J. Wong } 1546174edb0eSDarrick J. Wong 1547174edb0eSDarrick J. Wong /* Record a CoW staging extent in the refcount btree. */ 1548174edb0eSDarrick J. Wong int 1549174edb0eSDarrick J. Wong xfs_refcount_alloc_cow_extent( 1550174edb0eSDarrick J. Wong struct xfs_mount *mp, 1551174edb0eSDarrick J. Wong struct xfs_defer_ops *dfops, 1552174edb0eSDarrick J. Wong xfs_fsblock_t fsb, 1553174edb0eSDarrick J. Wong xfs_extlen_t len) 1554174edb0eSDarrick J. Wong { 1555174edb0eSDarrick J. Wong if (!xfs_sb_version_hasreflink(&mp->m_sb)) 1556174edb0eSDarrick J. Wong return 0; 1557174edb0eSDarrick J. Wong 1558174edb0eSDarrick J. Wong return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_ALLOC_COW, 1559174edb0eSDarrick J. Wong fsb, len); 1560174edb0eSDarrick J. Wong } 1561174edb0eSDarrick J. Wong 1562174edb0eSDarrick J. Wong /* Forget a CoW staging event in the refcount btree. */ 1563174edb0eSDarrick J. Wong int 1564174edb0eSDarrick J. Wong xfs_refcount_free_cow_extent( 1565174edb0eSDarrick J. Wong struct xfs_mount *mp, 1566174edb0eSDarrick J. Wong struct xfs_defer_ops *dfops, 1567174edb0eSDarrick J. Wong xfs_fsblock_t fsb, 1568174edb0eSDarrick J. Wong xfs_extlen_t len) 1569174edb0eSDarrick J. Wong { 1570174edb0eSDarrick J. Wong if (!xfs_sb_version_hasreflink(&mp->m_sb)) 1571174edb0eSDarrick J. Wong return 0; 1572174edb0eSDarrick J. Wong 1573174edb0eSDarrick J. Wong return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_FREE_COW, 1574174edb0eSDarrick J. Wong fsb, len); 1575174edb0eSDarrick J. Wong } 1576174edb0eSDarrick J. Wong 1577174edb0eSDarrick J. Wong struct xfs_refcount_recovery { 1578174edb0eSDarrick J. Wong struct list_head rr_list; 1579174edb0eSDarrick J. Wong struct xfs_refcount_irec rr_rrec; 1580174edb0eSDarrick J. Wong }; 1581174edb0eSDarrick J. Wong 1582174edb0eSDarrick J. Wong /* Stuff an extent on the recovery list. */ 1583174edb0eSDarrick J. Wong STATIC int 1584174edb0eSDarrick J. Wong xfs_refcount_recover_extent( 1585174edb0eSDarrick J. Wong struct xfs_btree_cur *cur, 1586174edb0eSDarrick J. Wong union xfs_btree_rec *rec, 1587174edb0eSDarrick J. Wong void *priv) 1588174edb0eSDarrick J. Wong { 1589174edb0eSDarrick J. Wong struct list_head *debris = priv; 1590174edb0eSDarrick J. Wong struct xfs_refcount_recovery *rr; 1591174edb0eSDarrick J. Wong 1592174edb0eSDarrick J. Wong if (be32_to_cpu(rec->refc.rc_refcount) != 1) 1593174edb0eSDarrick J. Wong return -EFSCORRUPTED; 1594174edb0eSDarrick J. Wong 1595174edb0eSDarrick J. Wong rr = kmem_alloc(sizeof(struct xfs_refcount_recovery), KM_SLEEP); 1596174edb0eSDarrick J. Wong xfs_refcount_btrec_to_irec(rec, &rr->rr_rrec); 1597174edb0eSDarrick J. Wong list_add_tail(&rr->rr_list, debris); 1598174edb0eSDarrick J. Wong 1599174edb0eSDarrick J. Wong return 0; 1600174edb0eSDarrick J. Wong } 1601174edb0eSDarrick J. Wong 1602174edb0eSDarrick J. Wong /* Find and remove leftover CoW reservations. */ 1603174edb0eSDarrick J. Wong int 1604174edb0eSDarrick J. Wong xfs_refcount_recover_cow_leftovers( 1605174edb0eSDarrick J. Wong struct xfs_mount *mp, 1606174edb0eSDarrick J. Wong xfs_agnumber_t agno) 1607174edb0eSDarrick J. Wong { 1608174edb0eSDarrick J. Wong struct xfs_trans *tp; 1609174edb0eSDarrick J. Wong struct xfs_btree_cur *cur; 1610174edb0eSDarrick J. Wong struct xfs_buf *agbp; 1611174edb0eSDarrick J. Wong struct xfs_refcount_recovery *rr, *n; 1612174edb0eSDarrick J. Wong struct list_head debris; 1613174edb0eSDarrick J. Wong union xfs_btree_irec low; 1614174edb0eSDarrick J. Wong union xfs_btree_irec high; 1615174edb0eSDarrick J. Wong struct xfs_defer_ops dfops; 1616174edb0eSDarrick J. Wong xfs_fsblock_t fsb; 1617174edb0eSDarrick J. Wong xfs_agblock_t agbno; 1618174edb0eSDarrick J. Wong int error; 1619174edb0eSDarrick J. Wong 1620174edb0eSDarrick J. Wong if (mp->m_sb.sb_agblocks >= XFS_REFC_COW_START) 1621174edb0eSDarrick J. Wong return -EOPNOTSUPP; 1622174edb0eSDarrick J. Wong 16233ecb3ac7SDarrick J. Wong INIT_LIST_HEAD(&debris); 16243ecb3ac7SDarrick J. Wong 16253ecb3ac7SDarrick J. Wong /* 16263ecb3ac7SDarrick J. Wong * In this first part, we use an empty transaction to gather up 16273ecb3ac7SDarrick J. Wong * all the leftover CoW extents so that we can subsequently 16283ecb3ac7SDarrick J. Wong * delete them. The empty transaction is used to avoid 16293ecb3ac7SDarrick J. Wong * a buffer lock deadlock if there happens to be a loop in the 16303ecb3ac7SDarrick J. Wong * refcountbt because we're allowed to re-grab a buffer that is 16313ecb3ac7SDarrick J. Wong * already attached to our transaction. When we're done 16323ecb3ac7SDarrick J. Wong * recording the CoW debris we cancel the (empty) transaction 16333ecb3ac7SDarrick J. Wong * and everything goes away cleanly. 16343ecb3ac7SDarrick J. Wong */ 16353ecb3ac7SDarrick J. Wong error = xfs_trans_alloc_empty(mp, &tp); 1636174edb0eSDarrick J. Wong if (error) 1637174edb0eSDarrick J. Wong return error; 16383ecb3ac7SDarrick J. Wong 16393ecb3ac7SDarrick J. Wong error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); 16403ecb3ac7SDarrick J. Wong if (error) 16413ecb3ac7SDarrick J. Wong goto out_trans; 164210479e2dSDarrick J. Wong if (!agbp) { 164310479e2dSDarrick J. Wong error = -ENOMEM; 164410479e2dSDarrick J. Wong goto out_trans; 164510479e2dSDarrick J. Wong } 16463ecb3ac7SDarrick J. Wong cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL); 1647174edb0eSDarrick J. Wong 1648174edb0eSDarrick J. Wong /* Find all the leftover CoW staging extents. */ 1649174edb0eSDarrick J. Wong memset(&low, 0, sizeof(low)); 1650174edb0eSDarrick J. Wong memset(&high, 0, sizeof(high)); 1651174edb0eSDarrick J. Wong low.rc.rc_startblock = XFS_REFC_COW_START; 1652174edb0eSDarrick J. Wong high.rc.rc_startblock = -1U; 1653174edb0eSDarrick J. Wong error = xfs_btree_query_range(cur, &low, &high, 1654174edb0eSDarrick J. Wong xfs_refcount_recover_extent, &debris); 1655174edb0eSDarrick J. Wong if (error) 16566f97077fSDarrick J. Wong goto out_cursor; 1657174edb0eSDarrick J. Wong xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); 16583ecb3ac7SDarrick J. Wong xfs_trans_brelse(tp, agbp); 16593ecb3ac7SDarrick J. Wong xfs_trans_cancel(tp); 1660174edb0eSDarrick J. Wong 1661174edb0eSDarrick J. Wong /* Now iterate the list to free the leftovers */ 16623ecb3ac7SDarrick J. Wong list_for_each_entry_safe(rr, n, &debris, rr_list) { 1663174edb0eSDarrick J. Wong /* Set up transaction. */ 1664174edb0eSDarrick J. Wong error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, 0, 0, 0, &tp); 1665174edb0eSDarrick J. Wong if (error) 1666174edb0eSDarrick J. Wong goto out_free; 1667174edb0eSDarrick J. Wong 1668174edb0eSDarrick J. Wong trace_xfs_refcount_recover_extent(mp, agno, &rr->rr_rrec); 1669174edb0eSDarrick J. Wong 1670174edb0eSDarrick J. Wong /* Free the orphan record */ 1671174edb0eSDarrick J. Wong xfs_defer_init(&dfops, &fsb); 1672174edb0eSDarrick J. Wong agbno = rr->rr_rrec.rc_startblock - XFS_REFC_COW_START; 1673174edb0eSDarrick J. Wong fsb = XFS_AGB_TO_FSB(mp, agno, agbno); 1674174edb0eSDarrick J. Wong error = xfs_refcount_free_cow_extent(mp, &dfops, fsb, 1675174edb0eSDarrick J. Wong rr->rr_rrec.rc_blockcount); 1676174edb0eSDarrick J. Wong if (error) 1677174edb0eSDarrick J. Wong goto out_defer; 1678174edb0eSDarrick J. Wong 1679174edb0eSDarrick J. Wong /* Free the block. */ 1680174edb0eSDarrick J. Wong xfs_bmap_add_free(mp, &dfops, fsb, 1681174edb0eSDarrick J. Wong rr->rr_rrec.rc_blockcount, NULL); 1682174edb0eSDarrick J. Wong 16838ad7c629SChristoph Hellwig error = xfs_defer_finish(&tp, &dfops); 1684174edb0eSDarrick J. Wong if (error) 1685174edb0eSDarrick J. Wong goto out_defer; 1686174edb0eSDarrick J. Wong 1687174edb0eSDarrick J. Wong error = xfs_trans_commit(tp); 1688174edb0eSDarrick J. Wong if (error) 1689174edb0eSDarrick J. Wong goto out_free; 16903ecb3ac7SDarrick J. Wong 16913ecb3ac7SDarrick J. Wong list_del(&rr->rr_list); 16923ecb3ac7SDarrick J. Wong kmem_free(rr); 16936f97077fSDarrick J. Wong } 1694174edb0eSDarrick J. Wong 16953ecb3ac7SDarrick J. Wong return error; 16963ecb3ac7SDarrick J. Wong out_defer: 16973ecb3ac7SDarrick J. Wong xfs_defer_cancel(&dfops); 16983ecb3ac7SDarrick J. Wong out_trans: 16993ecb3ac7SDarrick J. Wong xfs_trans_cancel(tp); 1700174edb0eSDarrick J. Wong out_free: 1701174edb0eSDarrick J. Wong /* Free the leftover list */ 1702174edb0eSDarrick J. Wong list_for_each_entry_safe(rr, n, &debris, rr_list) { 1703174edb0eSDarrick J. Wong list_del(&rr->rr_list); 1704174edb0eSDarrick J. Wong kmem_free(rr); 1705174edb0eSDarrick J. Wong } 1706174edb0eSDarrick J. Wong return error; 1707174edb0eSDarrick J. Wong 17086f97077fSDarrick J. Wong out_cursor: 1709174edb0eSDarrick J. Wong xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); 17103ecb3ac7SDarrick J. Wong xfs_trans_brelse(tp, agbp); 17113ecb3ac7SDarrick J. Wong goto out_trans; 1712174edb0eSDarrick J. Wong } 1713