aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_btree.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2008-10-30 01:57:51 -0400
committerLachlan McIlroy <lachlan@sgi.com>2008-10-30 01:57:51 -0400
commitd4b3a4b7dd62f2e111d4d0afa9ef3f9b6cd955c0 (patch)
treecd0b5a46d81fa9d9b0253c489f64ad698e3a0fa9 /fs/xfs/xfs_btree.c
parent4b22a57188d87e873346b73c227607715be96399 (diff)
[XFS] move xfs_bmbt_killroot to common code
xfs_bmbt_killroot is a mostly generic implementation of moving from a real block based root to an inode based root. So move it to xfs_btree.c where it can use all the nice infrastructure there and make it pointer size agnostic The new name for it is xfs_btree_kill_iroot, following the old naming but making it clear we're dealing with the root in inode case here, and to avoid confusion with xfs_btree_new_root which is used for the not inode rooted case. I've also added a comment describing what it does and why it's named the way it is. SGI-PV: 985583 SGI-Modid: xfs-linux-melb:xfs-kern:32203a Signed-off-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com> Signed-off-by: Bill O'Donnell <billodo@sgi.com> Signed-off-by: David Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs/xfs_btree.c')
-rw-r--r--fs/xfs/xfs_btree.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c
index 36477aae77df..75a8a7b00dfb 100644
--- a/fs/xfs/xfs_btree.c
+++ b/fs/xfs/xfs_btree.c
@@ -3059,3 +3059,115 @@ error0:
3059 XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); 3059 XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
3060 return error; 3060 return error;
3061} 3061}
3062
3063/*
3064 * Try to merge a non-leaf block back into the inode root.
3065 *
3066 * Note: the killroot names comes from the fact that we're effectively
3067 * killing the old root block. But because we can't just delete the
3068 * inode we have to copy the single block it was pointing to into the
3069 * inode.
3070 */
3071int
3072xfs_btree_kill_iroot(
3073 struct xfs_btree_cur *cur)
3074{
3075 int whichfork = cur->bc_private.b.whichfork;
3076 struct xfs_inode *ip = cur->bc_private.b.ip;
3077 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
3078 struct xfs_btree_block *block;
3079 struct xfs_btree_block *cblock;
3080 union xfs_btree_key *kp;
3081 union xfs_btree_key *ckp;
3082 union xfs_btree_ptr *pp;
3083 union xfs_btree_ptr *cpp;
3084 struct xfs_buf *cbp;
3085 int level;
3086 int index;
3087 int numrecs;
3088#ifdef DEBUG
3089 union xfs_btree_ptr ptr;
3090 int i;
3091#endif
3092
3093 XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
3094
3095 ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
3096 ASSERT(cur->bc_nlevels > 1);
3097
3098 /*
3099 * Don't deal with the root block needs to be a leaf case.
3100 * We're just going to turn the thing back into extents anyway.
3101 */
3102 level = cur->bc_nlevels - 1;
3103 if (level == 1)
3104 goto out0;
3105
3106 /*
3107 * Give up if the root has multiple children.
3108 */
3109 block = xfs_btree_get_iroot(cur);
3110 if (xfs_btree_get_numrecs(block) != 1)
3111 goto out0;
3112
3113 cblock = xfs_btree_get_block(cur, level - 1, &cbp);
3114 numrecs = xfs_btree_get_numrecs(cblock);
3115
3116 /*
3117 * Only do this if the next level will fit.
3118 * Then the data must be copied up to the inode,
3119 * instead of freeing the root you free the next level.
3120 */
3121 if (numrecs > cur->bc_ops->get_dmaxrecs(cur, level))
3122 goto out0;
3123
3124 XFS_BTREE_STATS_INC(cur, killroot);
3125
3126#ifdef DEBUG
3127 xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_LEFTSIB);
3128 ASSERT(xfs_btree_ptr_is_null(cur, &ptr));
3129 xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB);
3130 ASSERT(xfs_btree_ptr_is_null(cur, &ptr));
3131#endif
3132
3133 index = numrecs - cur->bc_ops->get_maxrecs(cur, level);
3134 if (index) {
3135 xfs_iroot_realloc(cur->bc_private.b.ip, index,
3136 cur->bc_private.b.whichfork);
3137 block = (struct xfs_btree_block *)ifp->if_broot;
3138 }
3139
3140 be16_add_cpu(&block->bb_numrecs, index);
3141 ASSERT(block->bb_numrecs == cblock->bb_numrecs);
3142
3143 kp = xfs_btree_key_addr(cur, 1, block);
3144 ckp = xfs_btree_key_addr(cur, 1, cblock);
3145 xfs_btree_copy_keys(cur, kp, ckp, numrecs);
3146
3147 pp = xfs_btree_ptr_addr(cur, 1, block);
3148 cpp = xfs_btree_ptr_addr(cur, 1, cblock);
3149#ifdef DEBUG
3150 for (i = 0; i < numrecs; i++) {
3151 int error;
3152
3153 error = xfs_btree_check_ptr(cur, cpp, i, level - 1);
3154 if (error) {
3155 XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
3156 return error;
3157 }
3158 }
3159#endif
3160 xfs_btree_copy_ptrs(cur, pp, cpp, numrecs);
3161
3162 cur->bc_ops->free_block(cur, cbp);
3163 XFS_BTREE_STATS_INC(cur, free);
3164
3165 cur->bc_bufs[level - 1] = NULL;
3166 be16_add_cpu(&block->bb_level, -1);
3167 xfs_trans_log_inode(cur->bc_tp, ip,
3168 XFS_ILOG_CORE | XFS_ILOG_FBROOT(cur->bc_private.b.whichfork));
3169 cur->bc_nlevels--;
3170out0:
3171 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
3172 return 0;
3173}