diff options
author | Christoph Hellwig <hch@infradead.org> | 2008-10-30 01:57:40 -0400 |
---|---|---|
committer | Lachlan McIlroy <lachlan@sgi.com> | 2008-10-30 01:57:40 -0400 |
commit | 4b22a57188d87e873346b73c227607715be96399 (patch) | |
tree | 4cf2d0deede695968b7a32b098c0c64fac8610e5 /fs/xfs/xfs_ialloc_btree.c | |
parent | ea77b0a66e6c910ef265d9af522d6303ea6b3055 (diff) |
[XFS] implement generic xfs_btree_insert/insrec
Make the btree insert 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:32202a
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_ialloc_btree.c')
-rw-r--r-- | fs/xfs/xfs_ialloc_btree.c | 302 |
1 files changed, 20 insertions, 282 deletions
diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c index 7ba3c7bb3984..8f66e2720566 100644 --- a/fs/xfs/xfs_ialloc_btree.c +++ b/fs/xfs/xfs_ialloc_btree.c | |||
@@ -515,228 +515,6 @@ error0: | |||
515 | } | 515 | } |
516 | 516 | ||
517 | /* | 517 | /* |
518 | * Insert one record/level. Return information to the caller | ||
519 | * allowing the next level up to proceed if necessary. | ||
520 | */ | ||
521 | STATIC int /* error */ | ||
522 | xfs_inobt_insrec( | ||
523 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
524 | int level, /* level to insert record at */ | ||
525 | xfs_agblock_t *bnop, /* i/o: block number inserted */ | ||
526 | xfs_inobt_rec_t *recp, /* i/o: record data inserted */ | ||
527 | xfs_btree_cur_t **curp, /* output: new cursor replacing cur */ | ||
528 | int *stat) /* success/failure */ | ||
529 | { | ||
530 | xfs_inobt_block_t *block; /* btree block record/key lives in */ | ||
531 | xfs_buf_t *bp; /* buffer for block */ | ||
532 | int error; /* error return value */ | ||
533 | int i; /* loop index */ | ||
534 | xfs_inobt_key_t key; /* key value being inserted */ | ||
535 | xfs_inobt_key_t *kp=NULL; /* pointer to btree keys */ | ||
536 | xfs_agblock_t nbno; /* block number of allocated block */ | ||
537 | xfs_btree_cur_t *ncur; /* new cursor to be used at next lvl */ | ||
538 | xfs_inobt_key_t nkey; /* new key value, from split */ | ||
539 | xfs_inobt_rec_t nrec; /* new record value, for caller */ | ||
540 | int numrecs; | ||
541 | int optr; /* old ptr value */ | ||
542 | xfs_inobt_ptr_t *pp; /* pointer to btree addresses */ | ||
543 | int ptr; /* index in btree block for this rec */ | ||
544 | xfs_inobt_rec_t *rp=NULL; /* pointer to btree records */ | ||
545 | |||
546 | /* | ||
547 | * GCC doesn't understand the (arguably complex) control flow in | ||
548 | * this function and complains about uninitialized structure fields | ||
549 | * without this. | ||
550 | */ | ||
551 | memset(&nrec, 0, sizeof(nrec)); | ||
552 | |||
553 | /* | ||
554 | * If we made it to the root level, allocate a new root block | ||
555 | * and we're done. | ||
556 | */ | ||
557 | if (level >= cur->bc_nlevels) { | ||
558 | error = xfs_btree_new_root(cur, &i); | ||
559 | *bnop = NULLAGBLOCK; | ||
560 | *stat = i; | ||
561 | return error; | ||
562 | } | ||
563 | /* | ||
564 | * Make a key out of the record data to be inserted, and save it. | ||
565 | */ | ||
566 | key.ir_startino = recp->ir_startino; | ||
567 | optr = ptr = cur->bc_ptrs[level]; | ||
568 | /* | ||
569 | * If we're off the left edge, return failure. | ||
570 | */ | ||
571 | if (ptr == 0) { | ||
572 | *stat = 0; | ||
573 | return 0; | ||
574 | } | ||
575 | /* | ||
576 | * Get pointers to the btree buffer and block. | ||
577 | */ | ||
578 | bp = cur->bc_bufs[level]; | ||
579 | block = XFS_BUF_TO_INOBT_BLOCK(bp); | ||
580 | numrecs = be16_to_cpu(block->bb_numrecs); | ||
581 | #ifdef DEBUG | ||
582 | if ((error = xfs_btree_check_sblock(cur, block, level, bp))) | ||
583 | return error; | ||
584 | /* | ||
585 | * Check that the new entry is being inserted in the right place. | ||
586 | */ | ||
587 | if (ptr <= numrecs) { | ||
588 | if (level == 0) { | ||
589 | rp = XFS_INOBT_REC_ADDR(block, ptr, cur); | ||
590 | xfs_btree_check_rec(cur->bc_btnum, recp, rp); | ||
591 | } else { | ||
592 | kp = XFS_INOBT_KEY_ADDR(block, ptr, cur); | ||
593 | xfs_btree_check_key(cur->bc_btnum, &key, kp); | ||
594 | } | ||
595 | } | ||
596 | #endif | ||
597 | nbno = NULLAGBLOCK; | ||
598 | ncur = NULL; | ||
599 | /* | ||
600 | * If the block is full, we can't insert the new entry until we | ||
601 | * make the block un-full. | ||
602 | */ | ||
603 | if (numrecs == XFS_INOBT_BLOCK_MAXRECS(level, cur)) { | ||
604 | /* | ||
605 | * First, try shifting an entry to the right neighbor. | ||
606 | */ | ||
607 | if ((error = xfs_btree_rshift(cur, level, &i))) | ||
608 | return error; | ||
609 | if (i) { | ||
610 | /* nothing */ | ||
611 | } | ||
612 | /* | ||
613 | * Next, try shifting an entry to the left neighbor. | ||
614 | */ | ||
615 | else { | ||
616 | if ((error = xfs_btree_lshift(cur, level, &i))) | ||
617 | return error; | ||
618 | if (i) { | ||
619 | optr = ptr = cur->bc_ptrs[level]; | ||
620 | } else { | ||
621 | union xfs_btree_ptr bno = { .s = cpu_to_be32(nbno) }; | ||
622 | /* | ||
623 | * Next, try splitting the current block | ||
624 | * in half. If this works we have to | ||
625 | * re-set our variables because | ||
626 | * we could be in a different block now. | ||
627 | */ | ||
628 | if ((error = xfs_btree_split(cur, level, &bno, | ||
629 | (union xfs_btree_key *)&nkey, | ||
630 | &ncur, &i))) | ||
631 | return error; | ||
632 | nbno = be32_to_cpu(bno.s); | ||
633 | if (i) { | ||
634 | bp = cur->bc_bufs[level]; | ||
635 | block = XFS_BUF_TO_INOBT_BLOCK(bp); | ||
636 | #ifdef DEBUG | ||
637 | if ((error = xfs_btree_check_sblock(cur, | ||
638 | block, level, bp))) | ||
639 | return error; | ||
640 | #endif | ||
641 | ptr = cur->bc_ptrs[level]; | ||
642 | nrec.ir_startino = nkey.ir_startino; | ||
643 | } else { | ||
644 | /* | ||
645 | * Otherwise the insert fails. | ||
646 | */ | ||
647 | *stat = 0; | ||
648 | return 0; | ||
649 | } | ||
650 | } | ||
651 | } | ||
652 | } | ||
653 | /* | ||
654 | * At this point we know there's room for our new entry in the block | ||
655 | * we're pointing at. | ||
656 | */ | ||
657 | numrecs = be16_to_cpu(block->bb_numrecs); | ||
658 | if (level > 0) { | ||
659 | /* | ||
660 | * It's a non-leaf entry. Make a hole for the new data | ||
661 | * in the key and ptr regions of the block. | ||
662 | */ | ||
663 | kp = XFS_INOBT_KEY_ADDR(block, 1, cur); | ||
664 | pp = XFS_INOBT_PTR_ADDR(block, 1, cur); | ||
665 | #ifdef DEBUG | ||
666 | for (i = numrecs; i >= ptr; i--) { | ||
667 | if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(pp[i - 1]), level))) | ||
668 | return error; | ||
669 | } | ||
670 | #endif | ||
671 | memmove(&kp[ptr], &kp[ptr - 1], | ||
672 | (numrecs - ptr + 1) * sizeof(*kp)); | ||
673 | memmove(&pp[ptr], &pp[ptr - 1], | ||
674 | (numrecs - ptr + 1) * sizeof(*pp)); | ||
675 | /* | ||
676 | * Now stuff the new data in, bump numrecs and log the new data. | ||
677 | */ | ||
678 | #ifdef DEBUG | ||
679 | if ((error = xfs_btree_check_sptr(cur, *bnop, level))) | ||
680 | return error; | ||
681 | #endif | ||
682 | kp[ptr - 1] = key; | ||
683 | pp[ptr - 1] = cpu_to_be32(*bnop); | ||
684 | numrecs++; | ||
685 | block->bb_numrecs = cpu_to_be16(numrecs); | ||
686 | xfs_inobt_log_keys(cur, bp, ptr, numrecs); | ||
687 | xfs_inobt_log_ptrs(cur, bp, ptr, numrecs); | ||
688 | } else { | ||
689 | /* | ||
690 | * It's a leaf entry. Make a hole for the new record. | ||
691 | */ | ||
692 | rp = XFS_INOBT_REC_ADDR(block, 1, cur); | ||
693 | memmove(&rp[ptr], &rp[ptr - 1], | ||
694 | (numrecs - ptr + 1) * sizeof(*rp)); | ||
695 | /* | ||
696 | * Now stuff the new record in, bump numrecs | ||
697 | * and log the new data. | ||
698 | */ | ||
699 | rp[ptr - 1] = *recp; | ||
700 | numrecs++; | ||
701 | block->bb_numrecs = cpu_to_be16(numrecs); | ||
702 | xfs_inobt_log_recs(cur, bp, ptr, numrecs); | ||
703 | } | ||
704 | /* | ||
705 | * Log the new number of records in the btree header. | ||
706 | */ | ||
707 | xfs_inobt_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS); | ||
708 | #ifdef DEBUG | ||
709 | /* | ||
710 | * Check that the key/record is in the right place, now. | ||
711 | */ | ||
712 | if (ptr < numrecs) { | ||
713 | if (level == 0) | ||
714 | xfs_btree_check_rec(cur->bc_btnum, rp + ptr - 1, | ||
715 | rp + ptr); | ||
716 | else | ||
717 | xfs_btree_check_key(cur->bc_btnum, kp + ptr - 1, | ||
718 | kp + ptr); | ||
719 | } | ||
720 | #endif | ||
721 | /* | ||
722 | * If we inserted at the start of a block, update the parents' keys. | ||
723 | */ | ||
724 | if (optr == 1 && (error = xfs_btree_updkey(cur, (union xfs_btree_key *)&key, level + 1))) | ||
725 | return error; | ||
726 | /* | ||
727 | * Return the new block number, if any. | ||
728 | * If there is one, give back a record value and a cursor too. | ||
729 | */ | ||
730 | *bnop = nbno; | ||
731 | if (nbno != NULLAGBLOCK) { | ||
732 | *recp = nrec; | ||
733 | *curp = ncur; | ||
734 | } | ||
735 | *stat = 1; | ||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | /* | ||
740 | * Log header fields from a btree block. | 518 | * Log header fields from a btree block. |
741 | */ | 519 | */ |
742 | STATIC void | 520 | STATIC void |
@@ -912,66 +690,6 @@ xfs_inobt_get_rec( | |||
912 | return 0; | 690 | return 0; |
913 | } | 691 | } |
914 | 692 | ||
915 | /* | ||
916 | * Insert the current record at the point referenced by cur. | ||
917 | * The cursor may be inconsistent on return if splits have been done. | ||
918 | */ | ||
919 | int /* error */ | ||
920 | xfs_inobt_insert( | ||
921 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
922 | int *stat) /* success/failure */ | ||
923 | { | ||
924 | int error; /* error return value */ | ||
925 | int i; /* result value, 0 for failure */ | ||
926 | int level; /* current level number in btree */ | ||
927 | xfs_agblock_t nbno; /* new block number (split result) */ | ||
928 | xfs_btree_cur_t *ncur; /* new cursor (split result) */ | ||
929 | xfs_inobt_rec_t nrec; /* record being inserted this level */ | ||
930 | xfs_btree_cur_t *pcur; /* previous level's cursor */ | ||
931 | |||
932 | level = 0; | ||
933 | nbno = NULLAGBLOCK; | ||
934 | nrec.ir_startino = cpu_to_be32(cur->bc_rec.i.ir_startino); | ||
935 | nrec.ir_freecount = cpu_to_be32(cur->bc_rec.i.ir_freecount); | ||
936 | nrec.ir_free = cpu_to_be64(cur->bc_rec.i.ir_free); | ||
937 | ncur = NULL; | ||
938 | pcur = cur; | ||
939 | /* | ||
940 | * Loop going up the tree, starting at the leaf level. | ||
941 | * Stop when we don't get a split block, that must mean that | ||
942 | * the insert is finished with this level. | ||
943 | */ | ||
944 | do { | ||
945 | /* | ||
946 | * Insert nrec/nbno into this level of the tree. | ||
947 | * Note if we fail, nbno will be null. | ||
948 | */ | ||
949 | if ((error = xfs_inobt_insrec(pcur, level++, &nbno, &nrec, &ncur, | ||
950 | &i))) { | ||
951 | if (pcur != cur) | ||
952 | xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); | ||
953 | return error; | ||
954 | } | ||
955 | /* | ||
956 | * See if the cursor we just used is trash. | ||
957 | * Can't trash the caller's cursor, but otherwise we should | ||
958 | * if ncur is a new cursor or we're about to be done. | ||
959 | */ | ||
960 | if (pcur != cur && (ncur || nbno == NULLAGBLOCK)) { | ||
961 | cur->bc_nlevels = pcur->bc_nlevels; | ||
962 | xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); | ||
963 | } | ||
964 | /* | ||
965 | * If we got a new cursor, switch to it. | ||
966 | */ | ||
967 | if (ncur) { | ||
968 | pcur = ncur; | ||
969 | ncur = NULL; | ||
970 | } | ||
971 | } while (nbno != NULLAGBLOCK); | ||
972 | *stat = i; | ||
973 | return 0; | ||
974 | } | ||
975 | 693 | ||
976 | STATIC struct xfs_btree_cur * | 694 | STATIC struct xfs_btree_cur * |
977 | xfs_inobt_dup_cursor( | 695 | xfs_inobt_dup_cursor( |
@@ -1053,6 +771,24 @@ xfs_inobt_init_key_from_rec( | |||
1053 | key->inobt.ir_startino = rec->inobt.ir_startino; | 771 | key->inobt.ir_startino = rec->inobt.ir_startino; |
1054 | } | 772 | } |
1055 | 773 | ||
774 | STATIC void | ||
775 | xfs_inobt_init_rec_from_key( | ||
776 | union xfs_btree_key *key, | ||
777 | union xfs_btree_rec *rec) | ||
778 | { | ||
779 | rec->inobt.ir_startino = key->inobt.ir_startino; | ||
780 | } | ||
781 | |||
782 | STATIC void | ||
783 | xfs_inobt_init_rec_from_cur( | ||
784 | struct xfs_btree_cur *cur, | ||
785 | union xfs_btree_rec *rec) | ||
786 | { | ||
787 | rec->inobt.ir_startino = cpu_to_be32(cur->bc_rec.i.ir_startino); | ||
788 | rec->inobt.ir_freecount = cpu_to_be32(cur->bc_rec.i.ir_freecount); | ||
789 | rec->inobt.ir_free = cpu_to_be64(cur->bc_rec.i.ir_free); | ||
790 | } | ||
791 | |||
1056 | /* | 792 | /* |
1057 | * intial value of ptr for lookup | 793 | * intial value of ptr for lookup |
1058 | */ | 794 | */ |
@@ -1152,6 +888,8 @@ static const struct xfs_btree_ops xfs_inobt_ops = { | |||
1152 | .alloc_block = xfs_inobt_alloc_block, | 888 | .alloc_block = xfs_inobt_alloc_block, |
1153 | .get_maxrecs = xfs_inobt_get_maxrecs, | 889 | .get_maxrecs = xfs_inobt_get_maxrecs, |
1154 | .init_key_from_rec = xfs_inobt_init_key_from_rec, | 890 | .init_key_from_rec = xfs_inobt_init_key_from_rec, |
891 | .init_rec_from_key = xfs_inobt_init_rec_from_key, | ||
892 | .init_rec_from_cur = xfs_inobt_init_rec_from_cur, | ||
1155 | .init_ptr_from_cur = xfs_inobt_init_ptr_from_cur, | 893 | .init_ptr_from_cur = xfs_inobt_init_ptr_from_cur, |
1156 | .key_diff = xfs_inobt_key_diff, | 894 | .key_diff = xfs_inobt_key_diff, |
1157 | 895 | ||