diff options
author | Christoph Hellwig <hch@infradead.org> | 2008-10-30 01:56:43 -0400 |
---|---|---|
committer | Lachlan McIlroy <lachlan@sgi.com> | 2008-10-30 01:56:43 -0400 |
commit | 9eaead51bed957af0070a277d945744a76df0c8b (patch) | |
tree | 7b0679186c06f366c7aed30873e3395bd414953e /fs/xfs/xfs_alloc_btree.c | |
parent | 278d0ca14e889c3932a05d1a68675252a12b3466 (diff) |
[XFS] implement generic xfs_btree_rshift
Make the btree right shift 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:32196a
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 | 136 |
1 files changed, 2 insertions, 134 deletions
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c index c5c32999b810..31e42891fc9a 100644 --- a/fs/xfs/xfs_alloc_btree.c +++ b/fs/xfs/xfs_alloc_btree.c | |||
@@ -49,7 +49,6 @@ 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); | 49 | STATIC void xfs_alloc_log_recs(xfs_btree_cur_t *, xfs_buf_t *, int, int); |
50 | STATIC int xfs_alloc_lshift(xfs_btree_cur_t *, int, int *); | 50 | STATIC int xfs_alloc_lshift(xfs_btree_cur_t *, int, int *); |
51 | STATIC int xfs_alloc_newroot(xfs_btree_cur_t *, int *); | 51 | STATIC int xfs_alloc_newroot(xfs_btree_cur_t *, int *); |
52 | STATIC int xfs_alloc_rshift(xfs_btree_cur_t *, int, int *); | ||
53 | STATIC int xfs_alloc_split(xfs_btree_cur_t *, int, xfs_agblock_t *, | 52 | STATIC int xfs_alloc_split(xfs_btree_cur_t *, int, xfs_agblock_t *, |
54 | xfs_alloc_key_t *, xfs_btree_cur_t **, int *); | 53 | xfs_alloc_key_t *, xfs_btree_cur_t **, int *); |
55 | 54 | ||
@@ -391,7 +390,7 @@ xfs_alloc_delrec( | |||
391 | */ | 390 | */ |
392 | if (be16_to_cpu(left->bb_numrecs) - 1 >= | 391 | if (be16_to_cpu(left->bb_numrecs) - 1 >= |
393 | XFS_ALLOC_BLOCK_MINRECS(level, cur)) { | 392 | XFS_ALLOC_BLOCK_MINRECS(level, cur)) { |
394 | if ((error = xfs_alloc_rshift(tcur, level, &i))) | 393 | if ((error = xfs_btree_rshift(tcur, level, &i))) |
395 | goto error0; | 394 | goto error0; |
396 | if (i) { | 395 | if (i) { |
397 | ASSERT(be16_to_cpu(block->bb_numrecs) >= | 396 | ASSERT(be16_to_cpu(block->bb_numrecs) >= |
@@ -683,7 +682,7 @@ xfs_alloc_insrec( | |||
683 | /* | 682 | /* |
684 | * First, try shifting an entry to the right neighbor. | 683 | * First, try shifting an entry to the right neighbor. |
685 | */ | 684 | */ |
686 | if ((error = xfs_alloc_rshift(cur, level, &i))) | 685 | if ((error = xfs_btree_rshift(cur, level, &i))) |
687 | return error; | 686 | return error; |
688 | if (i) { | 687 | if (i) { |
689 | /* nothing */ | 688 | /* nothing */ |
@@ -1233,137 +1232,6 @@ xfs_alloc_newroot( | |||
1233 | } | 1232 | } |
1234 | 1233 | ||
1235 | /* | 1234 | /* |
1236 | * Move 1 record right from cur/level if possible. | ||
1237 | * Update cur to reflect the new path. | ||
1238 | */ | ||
1239 | STATIC int /* error */ | ||
1240 | xfs_alloc_rshift( | ||
1241 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
1242 | int level, /* level to shift record on */ | ||
1243 | int *stat) /* success/failure */ | ||
1244 | { | ||
1245 | int error; /* error return value */ | ||
1246 | int i; /* loop index */ | ||
1247 | xfs_alloc_key_t key; /* key value for leaf level upward */ | ||
1248 | xfs_buf_t *lbp; /* buffer for left (current) block */ | ||
1249 | xfs_alloc_block_t *left; /* left (current) btree block */ | ||
1250 | xfs_buf_t *rbp; /* buffer for right neighbor block */ | ||
1251 | xfs_alloc_block_t *right; /* right neighbor btree block */ | ||
1252 | xfs_alloc_key_t *rkp; /* key pointer for right block */ | ||
1253 | xfs_btree_cur_t *tcur; /* temporary cursor */ | ||
1254 | |||
1255 | /* | ||
1256 | * Set up variables for this block as "left". | ||
1257 | */ | ||
1258 | lbp = cur->bc_bufs[level]; | ||
1259 | left = XFS_BUF_TO_ALLOC_BLOCK(lbp); | ||
1260 | #ifdef DEBUG | ||
1261 | if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) | ||
1262 | return error; | ||
1263 | #endif | ||
1264 | /* | ||
1265 | * If we've got no right sibling then we can't shift an entry right. | ||
1266 | */ | ||
1267 | if (be32_to_cpu(left->bb_rightsib) == NULLAGBLOCK) { | ||
1268 | *stat = 0; | ||
1269 | return 0; | ||
1270 | } | ||
1271 | /* | ||
1272 | * If the cursor entry is the one that would be moved, don't | ||
1273 | * do it... it's too complicated. | ||
1274 | */ | ||
1275 | if (cur->bc_ptrs[level] >= be16_to_cpu(left->bb_numrecs)) { | ||
1276 | *stat = 0; | ||
1277 | return 0; | ||
1278 | } | ||
1279 | /* | ||
1280 | * Set up the right neighbor as "right". | ||
1281 | */ | ||
1282 | if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, | ||
1283 | cur->bc_private.a.agno, be32_to_cpu(left->bb_rightsib), | ||
1284 | 0, &rbp, XFS_ALLOC_BTREE_REF))) | ||
1285 | return error; | ||
1286 | right = XFS_BUF_TO_ALLOC_BLOCK(rbp); | ||
1287 | if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) | ||
1288 | return error; | ||
1289 | /* | ||
1290 | * If it's full, it can't take another entry. | ||
1291 | */ | ||
1292 | if (be16_to_cpu(right->bb_numrecs) == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { | ||
1293 | *stat = 0; | ||
1294 | return 0; | ||
1295 | } | ||
1296 | /* | ||
1297 | * Make a hole at the start of the right neighbor block, then | ||
1298 | * copy the last left block entry to the hole. | ||
1299 | */ | ||
1300 | if (level > 0) { | ||
1301 | xfs_alloc_key_t *lkp; /* key pointer for left block */ | ||
1302 | xfs_alloc_ptr_t *lpp; /* address pointer for left block */ | ||
1303 | xfs_alloc_ptr_t *rpp; /* address pointer for right block */ | ||
1304 | |||
1305 | lkp = XFS_ALLOC_KEY_ADDR(left, be16_to_cpu(left->bb_numrecs), cur); | ||
1306 | lpp = XFS_ALLOC_PTR_ADDR(left, be16_to_cpu(left->bb_numrecs), cur); | ||
1307 | rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur); | ||
1308 | rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur); | ||
1309 | #ifdef DEBUG | ||
1310 | for (i = be16_to_cpu(right->bb_numrecs) - 1; i >= 0; i--) { | ||
1311 | if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(rpp[i]), level))) | ||
1312 | return error; | ||
1313 | } | ||
1314 | #endif | ||
1315 | memmove(rkp + 1, rkp, be16_to_cpu(right->bb_numrecs) * sizeof(*rkp)); | ||
1316 | memmove(rpp + 1, rpp, be16_to_cpu(right->bb_numrecs) * sizeof(*rpp)); | ||
1317 | #ifdef DEBUG | ||
1318 | if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(*lpp), level))) | ||
1319 | return error; | ||
1320 | #endif | ||
1321 | *rkp = *lkp; | ||
1322 | *rpp = *lpp; | ||
1323 | xfs_alloc_log_keys(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1); | ||
1324 | xfs_alloc_log_ptrs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1); | ||
1325 | xfs_btree_check_key(cur->bc_btnum, rkp, rkp + 1); | ||
1326 | } else { | ||
1327 | xfs_alloc_rec_t *lrp; /* record pointer for left block */ | ||
1328 | xfs_alloc_rec_t *rrp; /* record pointer for right block */ | ||
1329 | |||
1330 | lrp = XFS_ALLOC_REC_ADDR(left, be16_to_cpu(left->bb_numrecs), cur); | ||
1331 | rrp = XFS_ALLOC_REC_ADDR(right, 1, cur); | ||
1332 | memmove(rrp + 1, rrp, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp)); | ||
1333 | *rrp = *lrp; | ||
1334 | xfs_alloc_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1); | ||
1335 | key.ar_startblock = rrp->ar_startblock; | ||
1336 | key.ar_blockcount = rrp->ar_blockcount; | ||
1337 | rkp = &key; | ||
1338 | xfs_btree_check_rec(cur->bc_btnum, rrp, rrp + 1); | ||
1339 | } | ||
1340 | /* | ||
1341 | * Decrement and log left's numrecs, bump and log right's numrecs. | ||
1342 | */ | ||
1343 | be16_add_cpu(&left->bb_numrecs, -1); | ||
1344 | xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); | ||
1345 | be16_add_cpu(&right->bb_numrecs, 1); | ||
1346 | xfs_alloc_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); | ||
1347 | /* | ||
1348 | * Using a temporary cursor, update the parent key values of the | ||
1349 | * block on the right. | ||
1350 | */ | ||
1351 | if ((error = xfs_btree_dup_cursor(cur, &tcur))) | ||
1352 | return error; | ||
1353 | i = xfs_btree_lastrec(tcur, level); | ||
1354 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
1355 | if ((error = xfs_btree_increment(tcur, level, &i)) || | ||
1356 | (error = xfs_btree_updkey(tcur, (union xfs_btree_key *)rkp, level + 1))) | ||
1357 | goto error0; | ||
1358 | xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); | ||
1359 | *stat = 1; | ||
1360 | return 0; | ||
1361 | error0: | ||
1362 | xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); | ||
1363 | return error; | ||
1364 | } | ||
1365 | |||
1366 | /* | ||
1367 | * Split cur/level block in half. | 1235 | * Split cur/level block in half. |
1368 | * Return new block number and its first record (to be inserted into parent). | 1236 | * Return new block number and its first record (to be inserted into parent). |
1369 | */ | 1237 | */ |