|
@@ -50,17 +50,22 @@
|
|
#include "xfs_trace.h"
|
|
#include "xfs_trace.h"
|
|
|
|
|
|
|
|
|
|
-#ifdef DEBUG
|
|
|
|
-STATIC void
|
|
|
|
-xfs_bmap_check_leaf_extents(xfs_btree_cur_t *cur, xfs_inode_t *ip, int whichfork);
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
kmem_zone_t *xfs_bmap_free_item_zone;
|
|
kmem_zone_t *xfs_bmap_free_item_zone;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Prototypes for internal bmap routines.
|
|
* Prototypes for internal bmap routines.
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
+#ifdef DEBUG
|
|
|
|
+STATIC void
|
|
|
|
+xfs_bmap_check_leaf_extents(
|
|
|
|
+ struct xfs_btree_cur *cur,
|
|
|
|
+ struct xfs_inode *ip,
|
|
|
|
+ int whichfork);
|
|
|
|
+#else
|
|
|
|
+#define xfs_bmap_check_leaf_extents(cur, ip, whichfork) do { } while (0)
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
|
|
/*
|
|
/*
|
|
* Called from xfs_bmap_add_attrfork to handle extents format files.
|
|
* Called from xfs_bmap_add_attrfork to handle extents format files.
|
|
@@ -84,47 +89,6 @@ xfs_bmap_add_attrfork_local(
|
|
xfs_bmap_free_t *flist, /* blocks to free at commit */
|
|
xfs_bmap_free_t *flist, /* blocks to free at commit */
|
|
int *flags); /* inode logging flags */
|
|
int *flags); /* inode logging flags */
|
|
|
|
|
|
-/*
|
|
|
|
- * Called by xfs_bmap_add_extent to handle cases converting a delayed
|
|
|
|
- * allocation to a real allocation.
|
|
|
|
- */
|
|
|
|
-STATIC int /* error */
|
|
|
|
-xfs_bmap_add_extent_delay_real(
|
|
|
|
- struct xfs_trans *tp, /* transaction pointer */
|
|
|
|
- xfs_inode_t *ip, /* incore inode pointer */
|
|
|
|
- xfs_extnum_t *idx, /* extent number to update/insert */
|
|
|
|
- xfs_btree_cur_t **curp, /* if *curp is null, not a btree */
|
|
|
|
- xfs_bmbt_irec_t *new, /* new data to add to file extents */
|
|
|
|
- xfs_filblks_t *dnew, /* new delayed-alloc indirect blocks */
|
|
|
|
- xfs_fsblock_t *first, /* pointer to firstblock variable */
|
|
|
|
- xfs_bmap_free_t *flist, /* list of extents to be freed */
|
|
|
|
- int *logflagsp); /* inode logging flags */
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
- * Called by xfs_bmap_add_extent to handle cases converting a hole
|
|
|
|
- * to a real allocation.
|
|
|
|
- */
|
|
|
|
-STATIC int /* error */
|
|
|
|
-xfs_bmap_add_extent_hole_real(
|
|
|
|
- xfs_inode_t *ip, /* incore inode pointer */
|
|
|
|
- xfs_extnum_t *idx, /* extent number to update/insert */
|
|
|
|
- xfs_btree_cur_t *cur, /* if null, not a btree */
|
|
|
|
- xfs_bmbt_irec_t *new, /* new data to add to file extents */
|
|
|
|
- int *logflagsp, /* inode logging flags */
|
|
|
|
- int whichfork); /* data or attr fork */
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
- * Called by xfs_bmap_add_extent to handle cases converting an unwritten
|
|
|
|
- * allocation to a real allocation or vice versa.
|
|
|
|
- */
|
|
|
|
-STATIC int /* error */
|
|
|
|
-xfs_bmap_add_extent_unwritten_real(
|
|
|
|
- xfs_inode_t *ip, /* incore inode pointer */
|
|
|
|
- xfs_extnum_t *idx, /* extent number to update/insert */
|
|
|
|
- xfs_btree_cur_t **curp, /* if *curp is null, not a btree */
|
|
|
|
- xfs_bmbt_irec_t *new, /* new data to add to file extents */
|
|
|
|
- int *logflagsp); /* inode logging flags */
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file.
|
|
* xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file.
|
|
* It figures out where to ask the underlying allocator to put the new extent.
|
|
* It figures out where to ask the underlying allocator to put the new extent.
|
|
@@ -407,147 +371,7 @@ xfs_bmap_add_attrfork_local(
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Update file extent records and the btree after allocating space.
|
|
|
|
- */
|
|
|
|
-STATIC int /* error */
|
|
|
|
-xfs_bmap_add_extent(
|
|
|
|
- struct xfs_trans *tp, /* transaction pointer */
|
|
|
|
- xfs_inode_t *ip, /* incore inode pointer */
|
|
|
|
- xfs_extnum_t *idx, /* extent number to update/insert */
|
|
|
|
- xfs_btree_cur_t **curp, /* if *curp is null, not a btree */
|
|
|
|
- xfs_bmbt_irec_t *new, /* new data to add to file extents */
|
|
|
|
- xfs_fsblock_t *first, /* pointer to firstblock variable */
|
|
|
|
- xfs_bmap_free_t *flist, /* list of extents to be freed */
|
|
|
|
- int *logflagsp, /* inode logging flags */
|
|
|
|
- int whichfork) /* data or attr fork */
|
|
|
|
-{
|
|
|
|
- xfs_btree_cur_t *cur; /* btree cursor or null */
|
|
|
|
- xfs_filblks_t da_new; /* new count del alloc blocks used */
|
|
|
|
- xfs_filblks_t da_old; /* old count del alloc blocks used */
|
|
|
|
- int error; /* error return value */
|
|
|
|
- xfs_ifork_t *ifp; /* inode fork ptr */
|
|
|
|
- int logflags; /* returned value */
|
|
|
|
- xfs_extnum_t nextents; /* number of extents in file now */
|
|
|
|
-
|
|
|
|
- XFS_STATS_INC(xs_add_exlist);
|
|
|
|
-
|
|
|
|
- cur = *curp;
|
|
|
|
- ifp = XFS_IFORK_PTR(ip, whichfork);
|
|
|
|
- nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
|
|
|
|
- da_old = da_new = 0;
|
|
|
|
- error = 0;
|
|
|
|
-
|
|
|
|
- ASSERT(*idx >= 0);
|
|
|
|
- ASSERT(*idx <= nextents);
|
|
|
|
- ASSERT(!isnullstartblock(new->br_startblock));
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Real allocation off the end of the file.
|
|
|
|
- */
|
|
|
|
- if (*idx == nextents) {
|
|
|
|
- if (cur)
|
|
|
|
- ASSERT((cur->bc_private.b.flags &
|
|
|
|
- XFS_BTCUR_BPRV_WASDEL) == 0);
|
|
|
|
- error = xfs_bmap_add_extent_hole_real(ip, idx, cur, new,
|
|
|
|
- &logflags, whichfork);
|
|
|
|
- } else {
|
|
|
|
- xfs_bmbt_irec_t prev; /* old extent at offset idx */
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Get the record referred to by idx.
|
|
|
|
- */
|
|
|
|
- xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx), &prev);
|
|
|
|
- /*
|
|
|
|
- * If it's a real allocation record, and the new allocation ends
|
|
|
|
- * after the start of the referred to record, then we're filling
|
|
|
|
- * in a delayed or unwritten allocation with a real one, or
|
|
|
|
- * converting real back to unwritten.
|
|
|
|
- */
|
|
|
|
- if (!isnullstartblock(new->br_startblock) &&
|
|
|
|
- new->br_startoff + new->br_blockcount > prev.br_startoff) {
|
|
|
|
- if (prev.br_state != XFS_EXT_UNWRITTEN &&
|
|
|
|
- isnullstartblock(prev.br_startblock)) {
|
|
|
|
- da_old = startblockval(prev.br_startblock);
|
|
|
|
- if (cur)
|
|
|
|
- ASSERT(cur->bc_private.b.flags &
|
|
|
|
- XFS_BTCUR_BPRV_WASDEL);
|
|
|
|
- error = xfs_bmap_add_extent_delay_real(tp, ip,
|
|
|
|
- idx, &cur, new, &da_new,
|
|
|
|
- first, flist, &logflags);
|
|
|
|
- } else {
|
|
|
|
- ASSERT(new->br_state == XFS_EXT_NORM ||
|
|
|
|
- new->br_state == XFS_EXT_UNWRITTEN);
|
|
|
|
-
|
|
|
|
- error = xfs_bmap_add_extent_unwritten_real(ip,
|
|
|
|
- idx, &cur, new, &logflags);
|
|
|
|
- if (error)
|
|
|
|
- goto done;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- /*
|
|
|
|
- * Otherwise we're filling in a hole with an allocation.
|
|
|
|
- */
|
|
|
|
- else {
|
|
|
|
- if (cur)
|
|
|
|
- ASSERT((cur->bc_private.b.flags &
|
|
|
|
- XFS_BTCUR_BPRV_WASDEL) == 0);
|
|
|
|
- error = xfs_bmap_add_extent_hole_real(ip, idx, cur,
|
|
|
|
- new, &logflags, whichfork);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (error)
|
|
|
|
- goto done;
|
|
|
|
- ASSERT(*curp == cur || *curp == NULL);
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Convert to a btree if necessary.
|
|
|
|
- */
|
|
|
|
- if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
|
|
|
|
- XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) {
|
|
|
|
- int tmp_logflags; /* partial log flag return val */
|
|
|
|
-
|
|
|
|
- ASSERT(cur == NULL);
|
|
|
|
- error = xfs_bmap_extents_to_btree(tp, ip, first,
|
|
|
|
- flist, &cur, da_old > 0, &tmp_logflags, whichfork);
|
|
|
|
- logflags |= tmp_logflags;
|
|
|
|
- if (error)
|
|
|
|
- goto done;
|
|
|
|
- }
|
|
|
|
- /*
|
|
|
|
- * Adjust for changes in reserved delayed indirect blocks.
|
|
|
|
- * Nothing to do for disk quotas here.
|
|
|
|
- */
|
|
|
|
- if (da_old || da_new) {
|
|
|
|
- xfs_filblks_t nblks;
|
|
|
|
-
|
|
|
|
- nblks = da_new;
|
|
|
|
- if (cur)
|
|
|
|
- nblks += cur->bc_private.b.allocated;
|
|
|
|
- ASSERT(nblks <= da_old);
|
|
|
|
- if (nblks < da_old)
|
|
|
|
- xfs_icsb_modify_counters(ip->i_mount, XFS_SBS_FDBLOCKS,
|
|
|
|
- (int64_t)(da_old - nblks), 0);
|
|
|
|
- }
|
|
|
|
- /*
|
|
|
|
- * Clear out the allocated field, done with it now in any case.
|
|
|
|
- */
|
|
|
|
- if (cur) {
|
|
|
|
- cur->bc_private.b.allocated = 0;
|
|
|
|
- *curp = cur;
|
|
|
|
- }
|
|
|
|
-done:
|
|
|
|
-#ifdef DEBUG
|
|
|
|
- if (!error)
|
|
|
|
- xfs_bmap_check_leaf_extents(*curp, ip, whichfork);
|
|
|
|
-#endif
|
|
|
|
- *logflagsp = logflags;
|
|
|
|
- return error;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
- * Called by xfs_bmap_add_extent to handle cases converting a delayed
|
|
|
|
- * allocation to a real allocation.
|
|
|
|
|
|
+ * Convert a delayed allocation to a real allocation.
|
|
*/
|
|
*/
|
|
STATIC int /* error */
|
|
STATIC int /* error */
|
|
xfs_bmap_add_extent_delay_real(
|
|
xfs_bmap_add_extent_delay_real(
|
|
@@ -556,7 +380,6 @@ xfs_bmap_add_extent_delay_real(
|
|
xfs_extnum_t *idx, /* extent number to update/insert */
|
|
xfs_extnum_t *idx, /* extent number to update/insert */
|
|
xfs_btree_cur_t **curp, /* if *curp is null, not a btree */
|
|
xfs_btree_cur_t **curp, /* if *curp is null, not a btree */
|
|
xfs_bmbt_irec_t *new, /* new data to add to file extents */
|
|
xfs_bmbt_irec_t *new, /* new data to add to file extents */
|
|
- xfs_filblks_t *dnew, /* new delayed-alloc indirect blocks */
|
|
|
|
xfs_fsblock_t *first, /* pointer to firstblock variable */
|
|
xfs_fsblock_t *first, /* pointer to firstblock variable */
|
|
xfs_bmap_free_t *flist, /* list of extents to be freed */
|
|
xfs_bmap_free_t *flist, /* list of extents to be freed */
|
|
int *logflagsp) /* inode logging flags */
|
|
int *logflagsp) /* inode logging flags */
|
|
@@ -572,10 +395,24 @@ xfs_bmap_add_extent_delay_real(
|
|
/* left is 0, right is 1, prev is 2 */
|
|
/* left is 0, right is 1, prev is 2 */
|
|
int rval=0; /* return value (logging flags) */
|
|
int rval=0; /* return value (logging flags) */
|
|
int state = 0;/* state bits, accessed thru macros */
|
|
int state = 0;/* state bits, accessed thru macros */
|
|
- xfs_filblks_t temp=0; /* value for dnew calculations */
|
|
|
|
- xfs_filblks_t temp2=0;/* value for dnew calculations */
|
|
|
|
|
|
+ xfs_filblks_t da_new; /* new count del alloc blocks used */
|
|
|
|
+ xfs_filblks_t da_old; /* old count del alloc blocks used */
|
|
|
|
+ xfs_filblks_t temp=0; /* value for da_new calculations */
|
|
|
|
+ xfs_filblks_t temp2=0;/* value for da_new calculations */
|
|
int tmp_rval; /* partial logging flags */
|
|
int tmp_rval; /* partial logging flags */
|
|
|
|
|
|
|
|
+ ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
|
|
|
|
+ cur = *curp;
|
|
|
|
+
|
|
|
|
+ ASSERT(*idx >= 0);
|
|
|
|
+ ASSERT(*idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
|
|
|
|
+ ASSERT(!isnullstartblock(new->br_startblock));
|
|
|
|
+ ASSERT(!cur || (cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL));
|
|
|
|
+
|
|
|
|
+ XFS_STATS_INC(xs_add_exlist);
|
|
|
|
+
|
|
|
|
+ *logflagsp = 0;
|
|
|
|
+
|
|
#define LEFT r[0]
|
|
#define LEFT r[0]
|
|
#define RIGHT r[1]
|
|
#define RIGHT r[1]
|
|
#define PREV r[2]
|
|
#define PREV r[2]
|
|
@@ -583,14 +420,15 @@ xfs_bmap_add_extent_delay_real(
|
|
/*
|
|
/*
|
|
* Set up a bunch of variables to make the tests simpler.
|
|
* Set up a bunch of variables to make the tests simpler.
|
|
*/
|
|
*/
|
|
- cur = *curp;
|
|
|
|
- ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
|
|
|
|
ep = xfs_iext_get_ext(ifp, *idx);
|
|
ep = xfs_iext_get_ext(ifp, *idx);
|
|
xfs_bmbt_get_all(ep, &PREV);
|
|
xfs_bmbt_get_all(ep, &PREV);
|
|
new_endoff = new->br_startoff + new->br_blockcount;
|
|
new_endoff = new->br_startoff + new->br_blockcount;
|
|
ASSERT(PREV.br_startoff <= new->br_startoff);
|
|
ASSERT(PREV.br_startoff <= new->br_startoff);
|
|
ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff);
|
|
ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff);
|
|
|
|
|
|
|
|
+ da_old = startblockval(PREV.br_startblock);
|
|
|
|
+ da_new = 0;
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Set flags determining what part of the previous delayed allocation
|
|
* Set flags determining what part of the previous delayed allocation
|
|
* extent is being replaced by a real allocation.
|
|
* extent is being replaced by a real allocation.
|
|
@@ -688,7 +526,6 @@ xfs_bmap_add_extent_delay_real(
|
|
RIGHT.br_blockcount, LEFT.br_state)))
|
|
RIGHT.br_blockcount, LEFT.br_state)))
|
|
goto done;
|
|
goto done;
|
|
}
|
|
}
|
|
- *dnew = 0;
|
|
|
|
break;
|
|
break;
|
|
|
|
|
|
case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG:
|
|
case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG:
|
|
@@ -719,7 +556,6 @@ xfs_bmap_add_extent_delay_real(
|
|
PREV.br_blockcount, LEFT.br_state)))
|
|
PREV.br_blockcount, LEFT.br_state)))
|
|
goto done;
|
|
goto done;
|
|
}
|
|
}
|
|
- *dnew = 0;
|
|
|
|
break;
|
|
break;
|
|
|
|
|
|
case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
|
|
case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
|
|
@@ -749,8 +585,6 @@ xfs_bmap_add_extent_delay_real(
|
|
RIGHT.br_blockcount, PREV.br_state)))
|
|
RIGHT.br_blockcount, PREV.br_state)))
|
|
goto done;
|
|
goto done;
|
|
}
|
|
}
|
|
-
|
|
|
|
- *dnew = 0;
|
|
|
|
break;
|
|
break;
|
|
|
|
|
|
case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING:
|
|
case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING:
|
|
@@ -778,8 +612,6 @@ xfs_bmap_add_extent_delay_real(
|
|
goto done;
|
|
goto done;
|
|
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
|
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
|
}
|
|
}
|
|
-
|
|
|
|
- *dnew = 0;
|
|
|
|
break;
|
|
break;
|
|
|
|
|
|
case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG:
|
|
case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG:
|
|
@@ -813,13 +645,12 @@ xfs_bmap_add_extent_delay_real(
|
|
LEFT.br_state)))
|
|
LEFT.br_state)))
|
|
goto done;
|
|
goto done;
|
|
}
|
|
}
|
|
- temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
|
|
|
|
|
|
+ da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
|
|
startblockval(PREV.br_startblock));
|
|
startblockval(PREV.br_startblock));
|
|
- xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
|
|
|
|
|
|
+ xfs_bmbt_set_startblock(ep, nullstartblock(da_new));
|
|
trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
|
|
trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
|
|
|
|
|
|
--*idx;
|
|
--*idx;
|
|
- *dnew = temp;
|
|
|
|
break;
|
|
break;
|
|
|
|
|
|
case BMAP_LEFT_FILLING:
|
|
case BMAP_LEFT_FILLING:
|
|
@@ -856,14 +687,12 @@ xfs_bmap_add_extent_delay_real(
|
|
if (error)
|
|
if (error)
|
|
goto done;
|
|
goto done;
|
|
}
|
|
}
|
|
- temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
|
|
|
|
|
|
+ da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
|
|
startblockval(PREV.br_startblock) -
|
|
startblockval(PREV.br_startblock) -
|
|
(cur ? cur->bc_private.b.allocated : 0));
|
|
(cur ? cur->bc_private.b.allocated : 0));
|
|
ep = xfs_iext_get_ext(ifp, *idx + 1);
|
|
ep = xfs_iext_get_ext(ifp, *idx + 1);
|
|
- xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
|
|
|
|
|
|
+ xfs_bmbt_set_startblock(ep, nullstartblock(da_new));
|
|
trace_xfs_bmap_post_update(ip, *idx + 1, state, _THIS_IP_);
|
|
trace_xfs_bmap_post_update(ip, *idx + 1, state, _THIS_IP_);
|
|
-
|
|
|
|
- *dnew = temp;
|
|
|
|
break;
|
|
break;
|
|
|
|
|
|
case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
|
|
case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG:
|
|
@@ -896,14 +725,13 @@ xfs_bmap_add_extent_delay_real(
|
|
goto done;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
|
|
- temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
|
|
|
|
|
|
+ da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
|
|
startblockval(PREV.br_startblock));
|
|
startblockval(PREV.br_startblock));
|
|
trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
|
|
trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
|
|
- xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
|
|
|
|
|
|
+ xfs_bmbt_set_startblock(ep, nullstartblock(da_new));
|
|
trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
|
|
trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
|
|
|
|
|
|
++*idx;
|
|
++*idx;
|
|
- *dnew = temp;
|
|
|
|
break;
|
|
break;
|
|
|
|
|
|
case BMAP_RIGHT_FILLING:
|
|
case BMAP_RIGHT_FILLING:
|
|
@@ -939,15 +767,14 @@ xfs_bmap_add_extent_delay_real(
|
|
if (error)
|
|
if (error)
|
|
goto done;
|
|
goto done;
|
|
}
|
|
}
|
|
- temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
|
|
|
|
|
|
+ da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
|
|
startblockval(PREV.br_startblock) -
|
|
startblockval(PREV.br_startblock) -
|
|
(cur ? cur->bc_private.b.allocated : 0));
|
|
(cur ? cur->bc_private.b.allocated : 0));
|
|
ep = xfs_iext_get_ext(ifp, *idx);
|
|
ep = xfs_iext_get_ext(ifp, *idx);
|
|
- xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
|
|
|
|
|
|
+ xfs_bmbt_set_startblock(ep, nullstartblock(da_new));
|
|
trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
|
|
trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
|
|
|
|
|
|
++*idx;
|
|
++*idx;
|
|
- *dnew = temp;
|
|
|
|
break;
|
|
break;
|
|
|
|
|
|
case 0:
|
|
case 0:
|
|
@@ -1029,7 +856,7 @@ xfs_bmap_add_extent_delay_real(
|
|
trace_xfs_bmap_post_update(ip, *idx + 2, state, _THIS_IP_);
|
|
trace_xfs_bmap_post_update(ip, *idx + 2, state, _THIS_IP_);
|
|
|
|
|
|
++*idx;
|
|
++*idx;
|
|
- *dnew = temp + temp2;
|
|
|
|
|
|
+ da_new = temp + temp2;
|
|
break;
|
|
break;
|
|
|
|
|
|
case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
|
|
case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
|
|
@@ -1044,9 +871,39 @@ xfs_bmap_add_extent_delay_real(
|
|
*/
|
|
*/
|
|
ASSERT(0);
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
- *curp = cur;
|
|
|
|
|
|
+
|
|
|
|
+ /* convert to a btree if necessary */
|
|
|
|
+ if (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_EXTENTS &&
|
|
|
|
+ XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) > ifp->if_ext_max) {
|
|
|
|
+ int tmp_logflags; /* partial log flag return val */
|
|
|
|
+
|
|
|
|
+ ASSERT(cur == NULL);
|
|
|
|
+ error = xfs_bmap_extents_to_btree(tp, ip, first, flist, &cur,
|
|
|
|
+ da_old > 0, &tmp_logflags, XFS_DATA_FORK);
|
|
|
|
+ *logflagsp |= tmp_logflags;
|
|
|
|
+ if (error)
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* adjust for changes in reserved delayed indirect blocks */
|
|
|
|
+ if (da_old || da_new) {
|
|
|
|
+ temp = da_new;
|
|
|
|
+ if (cur)
|
|
|
|
+ temp += cur->bc_private.b.allocated;
|
|
|
|
+ ASSERT(temp <= da_old);
|
|
|
|
+ if (temp < da_old)
|
|
|
|
+ xfs_icsb_modify_counters(ip->i_mount, XFS_SBS_FDBLOCKS,
|
|
|
|
+ (int64_t)(da_old - temp), 0);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* clear out the allocated field, done with it now in any case. */
|
|
|
|
+ if (cur) {
|
|
|
|
+ cur->bc_private.b.allocated = 0;
|
|
|
|
+ *curp = cur;
|
|
|
|
+ }
|
|
|
|
+ xfs_bmap_check_leaf_extents(cur, ip, XFS_DATA_FORK);
|
|
done:
|
|
done:
|
|
- *logflagsp = rval;
|
|
|
|
|
|
+ *logflagsp |= rval;
|
|
return error;
|
|
return error;
|
|
#undef LEFT
|
|
#undef LEFT
|
|
#undef RIGHT
|
|
#undef RIGHT
|
|
@@ -1054,15 +911,17 @@ done:
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Called by xfs_bmap_add_extent to handle cases converting an unwritten
|
|
|
|
- * allocation to a real allocation or vice versa.
|
|
|
|
|
|
+ * Convert an unwritten allocation to a real allocation or vice versa.
|
|
*/
|
|
*/
|
|
STATIC int /* error */
|
|
STATIC int /* error */
|
|
xfs_bmap_add_extent_unwritten_real(
|
|
xfs_bmap_add_extent_unwritten_real(
|
|
|
|
+ struct xfs_trans *tp,
|
|
xfs_inode_t *ip, /* incore inode pointer */
|
|
xfs_inode_t *ip, /* incore inode pointer */
|
|
xfs_extnum_t *idx, /* extent number to update/insert */
|
|
xfs_extnum_t *idx, /* extent number to update/insert */
|
|
xfs_btree_cur_t **curp, /* if *curp is null, not a btree */
|
|
xfs_btree_cur_t **curp, /* if *curp is null, not a btree */
|
|
xfs_bmbt_irec_t *new, /* new data to add to file extents */
|
|
xfs_bmbt_irec_t *new, /* new data to add to file extents */
|
|
|
|
+ xfs_fsblock_t *first, /* pointer to firstblock variable */
|
|
|
|
+ xfs_bmap_free_t *flist, /* list of extents to be freed */
|
|
int *logflagsp) /* inode logging flags */
|
|
int *logflagsp) /* inode logging flags */
|
|
{
|
|
{
|
|
xfs_btree_cur_t *cur; /* btree cursor */
|
|
xfs_btree_cur_t *cur; /* btree cursor */
|
|
@@ -1078,15 +937,25 @@ xfs_bmap_add_extent_unwritten_real(
|
|
int rval=0; /* return value (logging flags) */
|
|
int rval=0; /* return value (logging flags) */
|
|
int state = 0;/* state bits, accessed thru macros */
|
|
int state = 0;/* state bits, accessed thru macros */
|
|
|
|
|
|
|
|
+ *logflagsp = 0;
|
|
|
|
+
|
|
|
|
+ cur = *curp;
|
|
|
|
+ ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
|
|
|
|
+
|
|
|
|
+ ASSERT(*idx >= 0);
|
|
|
|
+ ASSERT(*idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
|
|
|
|
+ ASSERT(!isnullstartblock(new->br_startblock));
|
|
|
|
+
|
|
|
|
+ XFS_STATS_INC(xs_add_exlist);
|
|
|
|
+
|
|
#define LEFT r[0]
|
|
#define LEFT r[0]
|
|
#define RIGHT r[1]
|
|
#define RIGHT r[1]
|
|
#define PREV r[2]
|
|
#define PREV r[2]
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Set up a bunch of variables to make the tests simpler.
|
|
* Set up a bunch of variables to make the tests simpler.
|
|
*/
|
|
*/
|
|
error = 0;
|
|
error = 0;
|
|
- cur = *curp;
|
|
|
|
- ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
|
|
|
|
ep = xfs_iext_get_ext(ifp, *idx);
|
|
ep = xfs_iext_get_ext(ifp, *idx);
|
|
xfs_bmbt_get_all(ep, &PREV);
|
|
xfs_bmbt_get_all(ep, &PREV);
|
|
newext = new->br_state;
|
|
newext = new->br_state;
|
|
@@ -1537,9 +1406,29 @@ xfs_bmap_add_extent_unwritten_real(
|
|
*/
|
|
*/
|
|
ASSERT(0);
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
- *curp = cur;
|
|
|
|
|
|
+
|
|
|
|
+ /* convert to a btree if necessary */
|
|
|
|
+ if (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_EXTENTS &&
|
|
|
|
+ XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) > ifp->if_ext_max) {
|
|
|
|
+ int tmp_logflags; /* partial log flag return val */
|
|
|
|
+
|
|
|
|
+ ASSERT(cur == NULL);
|
|
|
|
+ error = xfs_bmap_extents_to_btree(tp, ip, first, flist, &cur,
|
|
|
|
+ 0, &tmp_logflags, XFS_DATA_FORK);
|
|
|
|
+ *logflagsp |= tmp_logflags;
|
|
|
|
+ if (error)
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* clear out the allocated field, done with it now in any case. */
|
|
|
|
+ if (cur) {
|
|
|
|
+ cur->bc_private.b.allocated = 0;
|
|
|
|
+ *curp = cur;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ xfs_bmap_check_leaf_extents(*curp, ip, XFS_DATA_FORK);
|
|
done:
|
|
done:
|
|
- *logflagsp = rval;
|
|
|
|
|
|
+ *logflagsp |= rval;
|
|
return error;
|
|
return error;
|
|
#undef LEFT
|
|
#undef LEFT
|
|
#undef RIGHT
|
|
#undef RIGHT
|
|
@@ -1691,30 +1580,42 @@ xfs_bmap_add_extent_hole_delay(
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Called by xfs_bmap_add_extent to handle cases converting a hole
|
|
|
|
- * to a real allocation.
|
|
|
|
|
|
+ * Convert a hole to a real allocation.
|
|
*/
|
|
*/
|
|
STATIC int /* error */
|
|
STATIC int /* error */
|
|
xfs_bmap_add_extent_hole_real(
|
|
xfs_bmap_add_extent_hole_real(
|
|
|
|
+ struct xfs_trans *tp,
|
|
xfs_inode_t *ip, /* incore inode pointer */
|
|
xfs_inode_t *ip, /* incore inode pointer */
|
|
xfs_extnum_t *idx, /* extent number to update/insert */
|
|
xfs_extnum_t *idx, /* extent number to update/insert */
|
|
- xfs_btree_cur_t *cur, /* if null, not a btree */
|
|
|
|
|
|
+ xfs_btree_cur_t **curp, /* if null, not a btree */
|
|
xfs_bmbt_irec_t *new, /* new data to add to file extents */
|
|
xfs_bmbt_irec_t *new, /* new data to add to file extents */
|
|
|
|
+ xfs_fsblock_t *first, /* pointer to firstblock variable */
|
|
|
|
+ xfs_bmap_free_t *flist, /* list of extents to be freed */
|
|
int *logflagsp, /* inode logging flags */
|
|
int *logflagsp, /* inode logging flags */
|
|
int whichfork) /* data or attr fork */
|
|
int whichfork) /* data or attr fork */
|
|
{
|
|
{
|
|
int error; /* error return value */
|
|
int error; /* error return value */
|
|
int i; /* temp state */
|
|
int i; /* temp state */
|
|
|
|
+ xfs_btree_cur_t *cur; /* if null, not a btree */
|
|
xfs_ifork_t *ifp; /* inode fork pointer */
|
|
xfs_ifork_t *ifp; /* inode fork pointer */
|
|
xfs_bmbt_irec_t left; /* left neighbor extent entry */
|
|
xfs_bmbt_irec_t left; /* left neighbor extent entry */
|
|
xfs_bmbt_irec_t right; /* right neighbor extent entry */
|
|
xfs_bmbt_irec_t right; /* right neighbor extent entry */
|
|
int rval=0; /* return value (logging flags) */
|
|
int rval=0; /* return value (logging flags) */
|
|
int state; /* state bits, accessed thru macros */
|
|
int state; /* state bits, accessed thru macros */
|
|
|
|
|
|
|
|
+ *logflagsp = 0;
|
|
|
|
+
|
|
ifp = XFS_IFORK_PTR(ip, whichfork);
|
|
ifp = XFS_IFORK_PTR(ip, whichfork);
|
|
- ASSERT(*idx <= ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t));
|
|
|
|
- state = 0;
|
|
|
|
|
|
+ cur = *curp;
|
|
|
|
+
|
|
|
|
+ ASSERT(*idx >= 0);
|
|
|
|
+ ASSERT(*idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
|
|
|
|
+ ASSERT(!isnullstartblock(new->br_startblock));
|
|
|
|
+ ASSERT(!cur || !(cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL));
|
|
|
|
+
|
|
|
|
+ XFS_STATS_INC(xs_add_exlist);
|
|
|
|
|
|
|
|
+ state = 0;
|
|
if (whichfork == XFS_ATTR_FORK)
|
|
if (whichfork == XFS_ATTR_FORK)
|
|
state |= BMAP_ATTRFORK;
|
|
state |= BMAP_ATTRFORK;
|
|
|
|
|
|
@@ -1897,8 +1798,28 @@ xfs_bmap_add_extent_hole_real(
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /* convert to a btree if necessary */
|
|
|
|
+ if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
|
|
|
|
+ XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) {
|
|
|
|
+ int tmp_logflags; /* partial log flag return val */
|
|
|
|
+
|
|
|
|
+ ASSERT(cur == NULL);
|
|
|
|
+ error = xfs_bmap_extents_to_btree(tp, ip, first,
|
|
|
|
+ flist, &cur, 0, &tmp_logflags, whichfork);
|
|
|
|
+ *logflagsp |= tmp_logflags;
|
|
|
|
+ if (error)
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* clear out the allocated field, done with it now in any case. */
|
|
|
|
+ if (cur) {
|
|
|
|
+ cur->bc_private.b.allocated = 0;
|
|
|
|
+ *curp = cur;
|
|
|
|
+ }
|
|
|
|
+ xfs_bmap_check_leaf_extents(cur, ip, whichfork);
|
|
done:
|
|
done:
|
|
- *logflagsp = rval;
|
|
|
|
|
|
+ *logflagsp |= rval;
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -4792,14 +4713,22 @@ xfs_bmapi_allocate(
|
|
xfs_sb_version_hasextflgbit(&mp->m_sb))
|
|
xfs_sb_version_hasextflgbit(&mp->m_sb))
|
|
bma->gotp->br_state = XFS_EXT_UNWRITTEN;
|
|
bma->gotp->br_state = XFS_EXT_UNWRITTEN;
|
|
|
|
|
|
- error = xfs_bmap_add_extent(bma->tp, bma->ip, lastx, cur, bma->gotp,
|
|
|
|
- firstblock, flist, logflags, whichfork);
|
|
|
|
|
|
+ if (bma->wasdel) {
|
|
|
|
+ error = xfs_bmap_add_extent_delay_real(bma->tp, bma->ip, lastx,
|
|
|
|
+ cur, bma->gotp, firstblock, flist, logflags);
|
|
|
|
+ } else {
|
|
|
|
+ error = xfs_bmap_add_extent_hole_real(bma->tp, bma->ip, lastx,
|
|
|
|
+ cur, bma->gotp, firstblock, flist, logflags,
|
|
|
|
+ whichfork);
|
|
|
|
+ }
|
|
|
|
+
|
|
if (error)
|
|
if (error)
|
|
return error;
|
|
return error;
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Update our extent pointer, given that xfs_bmap_add_extent might
|
|
|
|
- * have merged it into one of the neighbouring ones.
|
|
|
|
|
|
+ * Update our extent pointer, given that xfs_bmap_add_extent_delay_real
|
|
|
|
+ * or xfs_bmap_add_extent_hole_real might have merged it into one of
|
|
|
|
+ * the neighbouring ones.
|
|
*/
|
|
*/
|
|
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), bma->gotp);
|
|
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), bma->gotp);
|
|
|
|
|
|
@@ -4854,14 +4783,15 @@ xfs_bmapi_convert_unwritten(
|
|
mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN)
|
|
mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN)
|
|
? XFS_EXT_NORM : XFS_EXT_UNWRITTEN;
|
|
? XFS_EXT_NORM : XFS_EXT_UNWRITTEN;
|
|
|
|
|
|
- error = xfs_bmap_add_extent(bma->tp, bma->ip, lastx, cur, mval,
|
|
|
|
- firstblock, flist, logflags, whichfork);
|
|
|
|
|
|
+ error = xfs_bmap_add_extent_unwritten_real(bma->tp, bma->ip, lastx,
|
|
|
|
+ cur, mval, firstblock, flist, logflags);
|
|
if (error)
|
|
if (error)
|
|
return error;
|
|
return error;
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Update our extent pointer, given that xfs_bmap_add_extent might
|
|
|
|
- * have merged it into one of the neighbouring ones.
|
|
|
|
|
|
+ * Update our extent pointer, given that
|
|
|
|
+ * xfs_bmap_add_extent_unwritten_real might have merged it into one
|
|
|
|
+ * of the neighbouring ones.
|
|
*/
|
|
*/
|
|
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), bma->gotp);
|
|
xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), bma->gotp);
|
|
|
|
|
|
@@ -5287,9 +5217,9 @@ xfs_bunmapi(
|
|
del.br_blockcount = mod;
|
|
del.br_blockcount = mod;
|
|
}
|
|
}
|
|
del.br_state = XFS_EXT_UNWRITTEN;
|
|
del.br_state = XFS_EXT_UNWRITTEN;
|
|
- error = xfs_bmap_add_extent(tp, ip, &lastx, &cur, &del,
|
|
|
|
- firstblock, flist, &logflags,
|
|
|
|
- XFS_DATA_FORK);
|
|
|
|
|
|
+ error = xfs_bmap_add_extent_unwritten_real(tp, ip,
|
|
|
|
+ &lastx, &cur, &del, firstblock, flist,
|
|
|
|
+ &logflags);
|
|
if (error)
|
|
if (error)
|
|
goto error0;
|
|
goto error0;
|
|
goto nodelete;
|
|
goto nodelete;
|
|
@@ -5345,18 +5275,18 @@ xfs_bunmapi(
|
|
}
|
|
}
|
|
prev.br_state = XFS_EXT_UNWRITTEN;
|
|
prev.br_state = XFS_EXT_UNWRITTEN;
|
|
lastx--;
|
|
lastx--;
|
|
- error = xfs_bmap_add_extent(tp, ip, &lastx,
|
|
|
|
- &cur, &prev, firstblock, flist,
|
|
|
|
- &logflags, XFS_DATA_FORK);
|
|
|
|
|
|
+ error = xfs_bmap_add_extent_unwritten_real(tp,
|
|
|
|
+ ip, &lastx, &cur, &prev,
|
|
|
|
+ firstblock, flist, &logflags);
|
|
if (error)
|
|
if (error)
|
|
goto error0;
|
|
goto error0;
|
|
goto nodelete;
|
|
goto nodelete;
|
|
} else {
|
|
} else {
|
|
ASSERT(del.br_state == XFS_EXT_NORM);
|
|
ASSERT(del.br_state == XFS_EXT_NORM);
|
|
del.br_state = XFS_EXT_UNWRITTEN;
|
|
del.br_state = XFS_EXT_UNWRITTEN;
|
|
- error = xfs_bmap_add_extent(tp, ip, &lastx,
|
|
|
|
- &cur, &del, firstblock, flist,
|
|
|
|
- &logflags, XFS_DATA_FORK);
|
|
|
|
|
|
+ error = xfs_bmap_add_extent_unwritten_real(tp,
|
|
|
|
+ ip, &lastx, &cur, &del,
|
|
|
|
+ firstblock, flist, &logflags);
|
|
if (error)
|
|
if (error)
|
|
goto error0;
|
|
goto error0;
|
|
goto nodelete;
|
|
goto nodelete;
|