summaryrefslogtreecommitdiff
path: root/fs/xfs/libxfs/xfs_alloc_btree.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/libxfs/xfs_alloc_btree.c')
-rw-r--r--fs/xfs/libxfs/xfs_alloc_btree.c89
1 files changed, 79 insertions, 10 deletions
diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c
index 2a94543857a1..c71318216931 100644
--- a/fs/xfs/libxfs/xfs_alloc_btree.c
+++ b/fs/xfs/libxfs/xfs_alloc_btree.c
@@ -24,6 +24,10 @@ STATIC struct xfs_btree_cur *
xfs_allocbt_dup_cursor(
struct xfs_btree_cur *cur)
{
+ if (cur->bc_flags & XFS_BTREE_STAGING)
+ return xfs_allocbt_stage_cursor(cur->bc_mp, cur->bc_tp,
+ cur->bc_private.a.afake,
+ cur->bc_private.a.agno, cur->bc_btnum);
return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp,
cur->bc_private.a.agbp, cur->bc_private.a.agno,
cur->bc_btnum);
@@ -474,15 +478,13 @@ static const struct xfs_btree_ops xfs_cntbt_ops = {
/*
* Allocate a new allocation btree cursor.
*/
-struct xfs_btree_cur * /* new alloc btree cursor */
-xfs_allocbt_init_cursor(
+STATIC struct xfs_btree_cur * /* new alloc btree cursor */
+xfs_allocbt_init_common(
struct xfs_mount *mp, /* file system mount point */
struct xfs_trans *tp, /* transaction pointer */
- struct xfs_buf *agbp, /* buffer for agf structure */
xfs_agnumber_t agno, /* allocation group number */
xfs_btnum_t btnum) /* btree identifier */
{
- struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp);
struct xfs_btree_cur *cur;
ASSERT(btnum == XFS_BTNUM_BNO || btnum == XFS_BTNUM_CNT);
@@ -493,28 +495,95 @@ xfs_allocbt_init_cursor(
cur->bc_mp = mp;
cur->bc_btnum = btnum;
cur->bc_blocklog = mp->m_sb.sb_blocklog;
+ cur->bc_private.a.agno = agno;
- if (btnum == XFS_BTNUM_CNT) {
+ if (btnum == XFS_BTNUM_CNT)
cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtc_2);
+ else
+ cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtb_2);
+
+ if (xfs_sb_version_hascrc(&mp->m_sb))
+ cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
+
+ return cur;
+}
+
+/*
+ * Allocate a new allocation btree cursor.
+ */
+struct xfs_btree_cur * /* new alloc btree cursor */
+xfs_allocbt_init_cursor(
+ struct xfs_mount *mp, /* file system mount point */
+ struct xfs_trans *tp, /* transaction pointer */
+ struct xfs_buf *agbp, /* buffer for agf structure */
+ xfs_agnumber_t agno, /* allocation group number */
+ xfs_btnum_t btnum) /* btree identifier */
+{
+ struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp);
+ struct xfs_btree_cur *cur;
+
+ cur = xfs_allocbt_init_common(mp, tp, agno, btnum);
+ if (btnum == XFS_BTNUM_CNT) {
cur->bc_ops = &xfs_cntbt_ops;
cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]);
- cur->bc_flags = XFS_BTREE_LASTREC_UPDATE;
+ cur->bc_flags |= XFS_BTREE_LASTREC_UPDATE;
} else {
- cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtb_2);
cur->bc_ops = &xfs_bnobt_ops;
cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]);
}
cur->bc_private.a.agbp = agbp;
- cur->bc_private.a.agno = agno;
- if (xfs_sb_version_hascrc(&mp->m_sb))
- cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
+ return cur;
+}
+/* Create a free space btree cursor with a fake root for staging. */
+struct xfs_btree_cur *
+xfs_allocbt_stage_cursor(
+ struct xfs_mount *mp,
+ struct xfs_trans *tp,
+ struct xbtree_afakeroot *afake,
+ xfs_agnumber_t agno,
+ xfs_btnum_t btnum)
+{
+ struct xfs_btree_cur *cur;
+ struct xfs_btree_ops *ops;
+
+ cur = xfs_allocbt_init_common(mp, tp, agno, btnum);
+ if (btnum == XFS_BTNUM_BNO)
+ xfs_btree_stage_afakeroot(cur, afake, &xfs_bnobt_ops, &ops);
+ else
+ xfs_btree_stage_afakeroot(cur, afake, &xfs_cntbt_ops, &ops);
+ ops->set_root = xbtree_afakeroot_set_root;
+ ops->init_ptr_from_cur = xbtree_afakeroot_init_ptr_from_cur;
return cur;
}
/*
+ * Install a new inobt btree root. Caller is responsible for invalidating
+ * and freeing the old btree blocks.
+ */
+void
+xfs_allocbt_commit_staged_btree(
+ struct xfs_btree_cur *cur,
+ struct xfs_buf *agbp)
+{
+ struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp);
+ struct xbtree_afakeroot *afake = cur->bc_private.a.afake;
+
+ ASSERT(cur->bc_flags & XFS_BTREE_STAGING);
+
+ agf->agf_roots[cur->bc_btnum] = cpu_to_be32(afake->af_root);
+ agf->agf_levels[cur->bc_btnum] = cpu_to_be32(afake->af_levels);
+ xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS);
+
+ if (cur->bc_btnum == XFS_BTNUM_BNO)
+ xfs_btree_commit_afakeroot(cur, agbp, &xfs_bnobt_ops);
+ else
+ xfs_btree_commit_afakeroot(cur, agbp, &xfs_cntbt_ops);
+}
+
+/*
* Calculate number of records in an alloc btree block.
*/
int