aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_btree.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_btree.c')
-rw-r--r--fs/xfs/xfs_btree.c129
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 */
2474int /* error */
2475xfs_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;
2591error0:
2592 XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
2593 return error;
2594out0:
2595 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
2596 *stat = 0;
2597 return 0;
2598}