diff options
Diffstat (limited to 'fs/xfs/xfs_btree.c')
-rw-r--r-- | fs/xfs/xfs_btree.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index 80576695fbe5..8de884c4dab7 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c | |||
@@ -2467,3 +2467,132 @@ error0: | |||
2467 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); | 2467 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); |
2468 | return error; | 2468 | return error; |
2469 | } | 2469 | } |
2470 | |||
2471 | /* | ||
2472 | * Allocate a new root block, fill it in. | ||
2473 | */ | ||
2474 | int /* error */ | ||
2475 | xfs_btree_new_root( | ||
2476 | struct xfs_btree_cur *cur, /* btree cursor */ | ||
2477 | int *stat) /* success/failure */ | ||
2478 | { | ||
2479 | struct xfs_btree_block *block; /* one half of the old root block */ | ||
2480 | struct xfs_buf *bp; /* buffer containing block */ | ||
2481 | int error; /* error return value */ | ||
2482 | struct xfs_buf *lbp; /* left buffer pointer */ | ||
2483 | struct xfs_btree_block *left; /* left btree block */ | ||
2484 | struct xfs_buf *nbp; /* new (root) buffer */ | ||
2485 | struct xfs_btree_block *new; /* new (root) btree block */ | ||
2486 | int nptr; /* new value for key index, 1 or 2 */ | ||
2487 | struct xfs_buf *rbp; /* right buffer pointer */ | ||
2488 | struct xfs_btree_block *right; /* right btree block */ | ||
2489 | union xfs_btree_ptr rptr; | ||
2490 | union xfs_btree_ptr lptr; | ||
2491 | |||
2492 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); | ||
2493 | XFS_BTREE_STATS_INC(cur, newroot); | ||
2494 | |||
2495 | /* initialise our start point from the cursor */ | ||
2496 | cur->bc_ops->init_ptr_from_cur(cur, &rptr); | ||
2497 | |||
2498 | /* Allocate the new block. If we can't do it, we're toast. Give up. */ | ||
2499 | error = cur->bc_ops->alloc_block(cur, &rptr, &lptr, 1, stat); | ||
2500 | if (error) | ||
2501 | goto error0; | ||
2502 | if (*stat == 0) | ||
2503 | goto out0; | ||
2504 | XFS_BTREE_STATS_INC(cur, alloc); | ||
2505 | |||
2506 | /* Set up the new block. */ | ||
2507 | error = xfs_btree_get_buf_block(cur, &lptr, 0, &new, &nbp); | ||
2508 | if (error) | ||
2509 | goto error0; | ||
2510 | |||
2511 | /* Set the root in the holding structure increasing the level by 1. */ | ||
2512 | cur->bc_ops->set_root(cur, &lptr, 1); | ||
2513 | |||
2514 | /* | ||
2515 | * At the previous root level there are now two blocks: the old root, | ||
2516 | * and the new block generated when it was split. We don't know which | ||
2517 | * one the cursor is pointing at, so we set up variables "left" and | ||
2518 | * "right" for each case. | ||
2519 | */ | ||
2520 | block = xfs_btree_get_block(cur, cur->bc_nlevels - 1, &bp); | ||
2521 | |||
2522 | #ifdef DEBUG | ||
2523 | error = xfs_btree_check_block(cur, block, cur->bc_nlevels - 1, bp); | ||
2524 | if (error) | ||
2525 | goto error0; | ||
2526 | #endif | ||
2527 | |||
2528 | xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB); | ||
2529 | if (!xfs_btree_ptr_is_null(cur, &rptr)) { | ||
2530 | /* Our block is left, pick up the right block. */ | ||
2531 | lbp = bp; | ||
2532 | xfs_btree_buf_to_ptr(cur, lbp, &lptr); | ||
2533 | left = block; | ||
2534 | error = xfs_btree_read_buf_block(cur, &rptr, | ||
2535 | cur->bc_nlevels - 1, 0, &right, &rbp); | ||
2536 | if (error) | ||
2537 | goto error0; | ||
2538 | bp = rbp; | ||
2539 | nptr = 1; | ||
2540 | } else { | ||
2541 | /* Our block is right, pick up the left block. */ | ||
2542 | rbp = bp; | ||
2543 | xfs_btree_buf_to_ptr(cur, rbp, &rptr); | ||
2544 | right = block; | ||
2545 | xfs_btree_get_sibling(cur, right, &lptr, XFS_BB_LEFTSIB); | ||
2546 | error = xfs_btree_read_buf_block(cur, &lptr, | ||
2547 | cur->bc_nlevels - 1, 0, &left, &lbp); | ||
2548 | if (error) | ||
2549 | goto error0; | ||
2550 | bp = lbp; | ||
2551 | nptr = 2; | ||
2552 | } | ||
2553 | /* Fill in the new block's btree header and log it. */ | ||
2554 | xfs_btree_init_block(cur, cur->bc_nlevels, 2, new); | ||
2555 | xfs_btree_log_block(cur, nbp, XFS_BB_ALL_BITS); | ||
2556 | ASSERT(!xfs_btree_ptr_is_null(cur, &lptr) && | ||
2557 | !xfs_btree_ptr_is_null(cur, &rptr)); | ||
2558 | |||
2559 | /* Fill in the key data in the new root. */ | ||
2560 | if (xfs_btree_get_level(left) > 0) { | ||
2561 | xfs_btree_copy_keys(cur, | ||
2562 | xfs_btree_key_addr(cur, 1, new), | ||
2563 | xfs_btree_key_addr(cur, 1, left), 1); | ||
2564 | xfs_btree_copy_keys(cur, | ||
2565 | xfs_btree_key_addr(cur, 2, new), | ||
2566 | xfs_btree_key_addr(cur, 1, right), 1); | ||
2567 | } else { | ||
2568 | cur->bc_ops->init_key_from_rec( | ||
2569 | xfs_btree_key_addr(cur, 1, new), | ||
2570 | xfs_btree_rec_addr(cur, 1, left)); | ||
2571 | cur->bc_ops->init_key_from_rec( | ||
2572 | xfs_btree_key_addr(cur, 2, new), | ||
2573 | xfs_btree_rec_addr(cur, 1, right)); | ||
2574 | } | ||
2575 | xfs_btree_log_keys(cur, nbp, 1, 2); | ||
2576 | |||
2577 | /* Fill in the pointer data in the new root. */ | ||
2578 | xfs_btree_copy_ptrs(cur, | ||
2579 | xfs_btree_ptr_addr(cur, 1, new), &lptr, 1); | ||
2580 | xfs_btree_copy_ptrs(cur, | ||
2581 | xfs_btree_ptr_addr(cur, 2, new), &rptr, 1); | ||
2582 | xfs_btree_log_ptrs(cur, nbp, 1, 2); | ||
2583 | |||
2584 | /* Fix up the cursor. */ | ||
2585 | xfs_btree_setbuf(cur, cur->bc_nlevels, nbp); | ||
2586 | cur->bc_ptrs[cur->bc_nlevels] = nptr; | ||
2587 | cur->bc_nlevels++; | ||
2588 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | ||
2589 | *stat = 1; | ||
2590 | return 0; | ||
2591 | error0: | ||
2592 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); | ||
2593 | return error; | ||
2594 | out0: | ||
2595 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | ||
2596 | *stat = 0; | ||
2597 | return 0; | ||
2598 | } | ||