diff options
author | Christoph Hellwig <hch@infradead.org> | 2008-10-30 01:57:51 -0400 |
---|---|---|
committer | Lachlan McIlroy <lachlan@sgi.com> | 2008-10-30 01:57:51 -0400 |
commit | d4b3a4b7dd62f2e111d4d0afa9ef3f9b6cd955c0 (patch) | |
tree | cd0b5a46d81fa9d9b0253c489f64ad698e3a0fa9 /fs/xfs/xfs_btree.c | |
parent | 4b22a57188d87e873346b73c227607715be96399 (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.c | 112 |
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 | */ | ||
3071 | int | ||
3072 | xfs_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--; | ||
3170 | out0: | ||
3171 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | ||
3172 | return 0; | ||
3173 | } | ||