diff options
author | Christoph Hellwig <hch@infradead.org> | 2008-10-30 01:57:03 -0400 |
---|---|---|
committer | Lachlan McIlroy <lachlan@sgi.com> | 2008-10-30 01:57:03 -0400 |
commit | f5eb8e7ca58bc1e92436614444006120d21668ba (patch) | |
tree | 94825b885653224f74c6087956cb4e1930380467 /fs/xfs/xfs_alloc_btree.c | |
parent | 687b890a184fef263ebb773926e1f4aa69240d01 (diff) |
[XFS] implement generic xfs_btree_split
Make the btree split code generic. Based on a patch from David Chinner
with lots of changes to follow the original btree implementations more
closely. While this loses some of the generic helper routines for
inserting/moving/removing records it also solves some of the one off bugs
in the original code and makes it easier to verify.
SGI-PV: 985583
SGI-Modid: xfs-linux-melb:xfs-kern:32198a
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_alloc_btree.c')
-rw-r--r-- | fs/xfs/xfs_alloc_btree.c | 200 |
1 files changed, 42 insertions, 158 deletions
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c index 974a412ebc8a..8a8d1aeec52a 100644 --- a/fs/xfs/xfs_alloc_btree.c +++ b/fs/xfs/xfs_alloc_btree.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
36 | #include "xfs_inode.h" | 36 | #include "xfs_inode.h" |
37 | #include "xfs_btree.h" | 37 | #include "xfs_btree.h" |
38 | #include "xfs_btree_trace.h" | ||
38 | #include "xfs_ialloc.h" | 39 | #include "xfs_ialloc.h" |
39 | #include "xfs_alloc.h" | 40 | #include "xfs_alloc.h" |
40 | #include "xfs_error.h" | 41 | #include "xfs_error.h" |
@@ -48,8 +49,6 @@ STATIC void xfs_alloc_log_keys(xfs_btree_cur_t *, xfs_buf_t *, int, int); | |||
48 | STATIC void xfs_alloc_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int); | 49 | STATIC void xfs_alloc_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int); |
49 | STATIC void xfs_alloc_log_recs(xfs_btree_cur_t *, xfs_buf_t *, int, int); | 50 | STATIC void xfs_alloc_log_recs(xfs_btree_cur_t *, xfs_buf_t *, int, int); |
50 | STATIC int xfs_alloc_newroot(xfs_btree_cur_t *, int *); | 51 | STATIC int xfs_alloc_newroot(xfs_btree_cur_t *, int *); |
51 | STATIC int xfs_alloc_split(xfs_btree_cur_t *, int, xfs_agblock_t *, | ||
52 | xfs_alloc_key_t *, xfs_btree_cur_t **, int *); | ||
53 | 52 | ||
54 | /* | 53 | /* |
55 | * Internal functions. | 54 | * Internal functions. |
@@ -695,15 +694,18 @@ xfs_alloc_insrec( | |||
695 | if (i) | 694 | if (i) |
696 | optr = ptr = cur->bc_ptrs[level]; | 695 | optr = ptr = cur->bc_ptrs[level]; |
697 | else { | 696 | else { |
697 | union xfs_btree_ptr bno = { .s = cpu_to_be32(nbno) }; | ||
698 | /* | 698 | /* |
699 | * Next, try splitting the current block in | 699 | * Next, try splitting the current block in |
700 | * half. If this works we have to re-set our | 700 | * half. If this works we have to re-set our |
701 | * variables because we could be in a | 701 | * variables because we could be in a |
702 | * different block now. | 702 | * different block now. |
703 | */ | 703 | */ |
704 | if ((error = xfs_alloc_split(cur, level, &nbno, | 704 | if ((error = xfs_btree_split(cur, level, &bno, |
705 | &nkey, &ncur, &i))) | 705 | (union xfs_btree_key *)&nkey, |
706 | &ncur, &i))) | ||
706 | return error; | 707 | return error; |
708 | nbno = be32_to_cpu(bno.s); | ||
707 | if (i) { | 709 | if (i) { |
708 | bp = cur->bc_bufs[level]; | 710 | bp = cur->bc_bufs[level]; |
709 | block = XFS_BUF_TO_ALLOC_BLOCK(bp); | 711 | block = XFS_BUF_TO_ALLOC_BLOCK(bp); |
@@ -1089,160 +1091,6 @@ xfs_alloc_newroot( | |||
1089 | return 0; | 1091 | return 0; |
1090 | } | 1092 | } |
1091 | 1093 | ||
1092 | /* | ||
1093 | * Split cur/level block in half. | ||
1094 | * Return new block number and its first record (to be inserted into parent). | ||
1095 | */ | ||
1096 | STATIC int /* error */ | ||
1097 | xfs_alloc_split( | ||
1098 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
1099 | int level, /* level to split */ | ||
1100 | xfs_agblock_t *bnop, /* output: block number allocated */ | ||
1101 | xfs_alloc_key_t *keyp, /* output: first key of new block */ | ||
1102 | xfs_btree_cur_t **curp, /* output: new cursor */ | ||
1103 | int *stat) /* success/failure */ | ||
1104 | { | ||
1105 | int error; /* error return value */ | ||
1106 | int i; /* loop index/record number */ | ||
1107 | xfs_agblock_t lbno; /* left (current) block number */ | ||
1108 | xfs_buf_t *lbp; /* buffer for left block */ | ||
1109 | xfs_alloc_block_t *left; /* left (current) btree block */ | ||
1110 | xfs_agblock_t rbno; /* right (new) block number */ | ||
1111 | xfs_buf_t *rbp; /* buffer for right block */ | ||
1112 | xfs_alloc_block_t *right; /* right (new) btree block */ | ||
1113 | |||
1114 | /* | ||
1115 | * Allocate the new block from the freelist. | ||
1116 | * If we can't do it, we're toast. Give up. | ||
1117 | */ | ||
1118 | error = xfs_alloc_get_freelist(cur->bc_tp, | ||
1119 | cur->bc_private.a.agbp, &rbno, 1); | ||
1120 | if (error) | ||
1121 | return error; | ||
1122 | if (rbno == NULLAGBLOCK) { | ||
1123 | *stat = 0; | ||
1124 | return 0; | ||
1125 | } | ||
1126 | xfs_trans_agbtree_delta(cur->bc_tp, 1); | ||
1127 | rbp = xfs_btree_get_bufs(cur->bc_mp, cur->bc_tp, cur->bc_private.a.agno, | ||
1128 | rbno, 0); | ||
1129 | /* | ||
1130 | * Set up the new block as "right". | ||
1131 | */ | ||
1132 | right = XFS_BUF_TO_ALLOC_BLOCK(rbp); | ||
1133 | /* | ||
1134 | * "Left" is the current (according to the cursor) block. | ||
1135 | */ | ||
1136 | lbp = cur->bc_bufs[level]; | ||
1137 | left = XFS_BUF_TO_ALLOC_BLOCK(lbp); | ||
1138 | #ifdef DEBUG | ||
1139 | if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) | ||
1140 | return error; | ||
1141 | #endif | ||
1142 | /* | ||
1143 | * Fill in the btree header for the new block. | ||
1144 | */ | ||
1145 | right->bb_magic = cpu_to_be32(xfs_magics[cur->bc_btnum]); | ||
1146 | right->bb_level = left->bb_level; | ||
1147 | right->bb_numrecs = cpu_to_be16(be16_to_cpu(left->bb_numrecs) / 2); | ||
1148 | /* | ||
1149 | * Make sure that if there's an odd number of entries now, that | ||
1150 | * each new block will have the same number of entries. | ||
1151 | */ | ||
1152 | if ((be16_to_cpu(left->bb_numrecs) & 1) && | ||
1153 | cur->bc_ptrs[level] <= be16_to_cpu(right->bb_numrecs) + 1) | ||
1154 | be16_add_cpu(&right->bb_numrecs, 1); | ||
1155 | i = be16_to_cpu(left->bb_numrecs) - be16_to_cpu(right->bb_numrecs) + 1; | ||
1156 | /* | ||
1157 | * For non-leaf blocks, copy keys and addresses over to the new block. | ||
1158 | */ | ||
1159 | if (level > 0) { | ||
1160 | xfs_alloc_key_t *lkp; /* left btree key pointer */ | ||
1161 | xfs_alloc_ptr_t *lpp; /* left btree address pointer */ | ||
1162 | xfs_alloc_key_t *rkp; /* right btree key pointer */ | ||
1163 | xfs_alloc_ptr_t *rpp; /* right btree address pointer */ | ||
1164 | |||
1165 | lkp = XFS_ALLOC_KEY_ADDR(left, i, cur); | ||
1166 | lpp = XFS_ALLOC_PTR_ADDR(left, i, cur); | ||
1167 | rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur); | ||
1168 | rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur); | ||
1169 | #ifdef DEBUG | ||
1170 | for (i = 0; i < be16_to_cpu(right->bb_numrecs); i++) { | ||
1171 | if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(lpp[i]), level))) | ||
1172 | return error; | ||
1173 | } | ||
1174 | #endif | ||
1175 | memcpy(rkp, lkp, be16_to_cpu(right->bb_numrecs) * sizeof(*rkp)); | ||
1176 | memcpy(rpp, lpp, be16_to_cpu(right->bb_numrecs) * sizeof(*rpp)); | ||
1177 | xfs_alloc_log_keys(cur, rbp, 1, be16_to_cpu(right->bb_numrecs)); | ||
1178 | xfs_alloc_log_ptrs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs)); | ||
1179 | *keyp = *rkp; | ||
1180 | } | ||
1181 | /* | ||
1182 | * For leaf blocks, copy records over to the new block. | ||
1183 | */ | ||
1184 | else { | ||
1185 | xfs_alloc_rec_t *lrp; /* left btree record pointer */ | ||
1186 | xfs_alloc_rec_t *rrp; /* right btree record pointer */ | ||
1187 | |||
1188 | lrp = XFS_ALLOC_REC_ADDR(left, i, cur); | ||
1189 | rrp = XFS_ALLOC_REC_ADDR(right, 1, cur); | ||
1190 | memcpy(rrp, lrp, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp)); | ||
1191 | xfs_alloc_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs)); | ||
1192 | keyp->ar_startblock = rrp->ar_startblock; | ||
1193 | keyp->ar_blockcount = rrp->ar_blockcount; | ||
1194 | } | ||
1195 | /* | ||
1196 | * Find the left block number by looking in the buffer. | ||
1197 | * Adjust numrecs, sibling pointers. | ||
1198 | */ | ||
1199 | lbno = XFS_DADDR_TO_AGBNO(cur->bc_mp, XFS_BUF_ADDR(lbp)); | ||
1200 | be16_add_cpu(&left->bb_numrecs, -(be16_to_cpu(right->bb_numrecs))); | ||
1201 | right->bb_rightsib = left->bb_rightsib; | ||
1202 | left->bb_rightsib = cpu_to_be32(rbno); | ||
1203 | right->bb_leftsib = cpu_to_be32(lbno); | ||
1204 | xfs_alloc_log_block(cur->bc_tp, rbp, XFS_BB_ALL_BITS); | ||
1205 | xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); | ||
1206 | /* | ||
1207 | * If there's a block to the new block's right, make that block | ||
1208 | * point back to right instead of to left. | ||
1209 | */ | ||
1210 | if (be32_to_cpu(right->bb_rightsib) != NULLAGBLOCK) { | ||
1211 | xfs_alloc_block_t *rrblock; /* rr btree block */ | ||
1212 | xfs_buf_t *rrbp; /* buffer for rrblock */ | ||
1213 | |||
1214 | if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, | ||
1215 | cur->bc_private.a.agno, be32_to_cpu(right->bb_rightsib), 0, | ||
1216 | &rrbp, XFS_ALLOC_BTREE_REF))) | ||
1217 | return error; | ||
1218 | rrblock = XFS_BUF_TO_ALLOC_BLOCK(rrbp); | ||
1219 | if ((error = xfs_btree_check_sblock(cur, rrblock, level, rrbp))) | ||
1220 | return error; | ||
1221 | rrblock->bb_leftsib = cpu_to_be32(rbno); | ||
1222 | xfs_alloc_log_block(cur->bc_tp, rrbp, XFS_BB_LEFTSIB); | ||
1223 | } | ||
1224 | /* | ||
1225 | * If the cursor is really in the right block, move it there. | ||
1226 | * If it's just pointing past the last entry in left, then we'll | ||
1227 | * insert there, so don't change anything in that case. | ||
1228 | */ | ||
1229 | if (cur->bc_ptrs[level] > be16_to_cpu(left->bb_numrecs) + 1) { | ||
1230 | xfs_btree_setbuf(cur, level, rbp); | ||
1231 | cur->bc_ptrs[level] -= be16_to_cpu(left->bb_numrecs); | ||
1232 | } | ||
1233 | /* | ||
1234 | * If there are more levels, we'll need another cursor which refers to | ||
1235 | * the right block, no matter where this cursor was. | ||
1236 | */ | ||
1237 | if (level + 1 < cur->bc_nlevels) { | ||
1238 | if ((error = xfs_btree_dup_cursor(cur, curp))) | ||
1239 | return error; | ||
1240 | (*curp)->bc_ptrs[level + 1]++; | ||
1241 | } | ||
1242 | *bnop = rbno; | ||
1243 | *stat = 1; | ||
1244 | return 0; | ||
1245 | } | ||
1246 | 1094 | ||
1247 | /* | 1095 | /* |
1248 | * Externally visible routines. | 1096 | * Externally visible routines. |
@@ -1396,6 +1244,41 @@ xfs_allocbt_dup_cursor( | |||
1396 | cur->bc_btnum); | 1244 | cur->bc_btnum); |
1397 | } | 1245 | } |
1398 | 1246 | ||
1247 | STATIC int | ||
1248 | xfs_allocbt_alloc_block( | ||
1249 | struct xfs_btree_cur *cur, | ||
1250 | union xfs_btree_ptr *start, | ||
1251 | union xfs_btree_ptr *new, | ||
1252 | int length, | ||
1253 | int *stat) | ||
1254 | { | ||
1255 | int error; | ||
1256 | xfs_agblock_t bno; | ||
1257 | |||
1258 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); | ||
1259 | |||
1260 | /* Allocate the new block from the freelist. If we can't, give up. */ | ||
1261 | error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp, | ||
1262 | &bno, 1); | ||
1263 | if (error) { | ||
1264 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); | ||
1265 | return error; | ||
1266 | } | ||
1267 | |||
1268 | if (bno == NULLAGBLOCK) { | ||
1269 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | ||
1270 | *stat = 0; | ||
1271 | return 0; | ||
1272 | } | ||
1273 | |||
1274 | xfs_trans_agbtree_delta(cur->bc_tp, 1); | ||
1275 | new->s = cpu_to_be32(bno); | ||
1276 | |||
1277 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | ||
1278 | *stat = 1; | ||
1279 | return 0; | ||
1280 | } | ||
1281 | |||
1399 | /* | 1282 | /* |
1400 | * Update the longest extent in the AGF | 1283 | * Update the longest extent in the AGF |
1401 | */ | 1284 | */ |
@@ -1557,6 +1440,7 @@ static const struct xfs_btree_ops xfs_allocbt_ops = { | |||
1557 | .key_len = sizeof(xfs_alloc_key_t), | 1440 | .key_len = sizeof(xfs_alloc_key_t), |
1558 | 1441 | ||
1559 | .dup_cursor = xfs_allocbt_dup_cursor, | 1442 | .dup_cursor = xfs_allocbt_dup_cursor, |
1443 | .alloc_block = xfs_allocbt_alloc_block, | ||
1560 | .update_lastrec = xfs_allocbt_update_lastrec, | 1444 | .update_lastrec = xfs_allocbt_update_lastrec, |
1561 | .get_maxrecs = xfs_allocbt_get_maxrecs, | 1445 | .get_maxrecs = xfs_allocbt_get_maxrecs, |
1562 | .init_key_from_rec = xfs_allocbt_init_key_from_rec, | 1446 | .init_key_from_rec = xfs_allocbt_init_key_from_rec, |