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 | |
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>
-rw-r--r-- | fs/xfs/xfs_alloc.c | 10 | ||||
-rw-r--r-- | fs/xfs/xfs_alloc_btree.c | 339 | ||||
-rw-r--r-- | fs/xfs/xfs_alloc_btree.h | 6 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap.c | 20 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap_btree.c | 308 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap_btree.h | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_btree.c | 362 | ||||
-rw-r--r-- | fs/xfs/xfs_btree.h | 11 | ||||
-rw-r--r-- | fs/xfs/xfs_ialloc.c | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_ialloc_btree.c | 302 | ||||
-rw-r--r-- | fs/xfs/xfs_ialloc_btree.h | 6 |
11 files changed, 494 insertions, 873 deletions
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 875e1bae1941..a983824c12be 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c | |||
@@ -408,7 +408,7 @@ xfs_alloc_fixup_trees( | |||
408 | if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno1, nflen1, &i))) | 408 | if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno1, nflen1, &i))) |
409 | return error; | 409 | return error; |
410 | XFS_WANT_CORRUPTED_RETURN(i == 0); | 410 | XFS_WANT_CORRUPTED_RETURN(i == 0); |
411 | if ((error = xfs_alloc_insert(cnt_cur, &i))) | 411 | if ((error = xfs_btree_insert(cnt_cur, &i))) |
412 | return error; | 412 | return error; |
413 | XFS_WANT_CORRUPTED_RETURN(i == 1); | 413 | XFS_WANT_CORRUPTED_RETURN(i == 1); |
414 | } | 414 | } |
@@ -416,7 +416,7 @@ xfs_alloc_fixup_trees( | |||
416 | if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno2, nflen2, &i))) | 416 | if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno2, nflen2, &i))) |
417 | return error; | 417 | return error; |
418 | XFS_WANT_CORRUPTED_RETURN(i == 0); | 418 | XFS_WANT_CORRUPTED_RETURN(i == 0); |
419 | if ((error = xfs_alloc_insert(cnt_cur, &i))) | 419 | if ((error = xfs_btree_insert(cnt_cur, &i))) |
420 | return error; | 420 | return error; |
421 | XFS_WANT_CORRUPTED_RETURN(i == 1); | 421 | XFS_WANT_CORRUPTED_RETURN(i == 1); |
422 | } | 422 | } |
@@ -444,7 +444,7 @@ xfs_alloc_fixup_trees( | |||
444 | if ((error = xfs_alloc_lookup_eq(bno_cur, nfbno2, nflen2, &i))) | 444 | if ((error = xfs_alloc_lookup_eq(bno_cur, nfbno2, nflen2, &i))) |
445 | return error; | 445 | return error; |
446 | XFS_WANT_CORRUPTED_RETURN(i == 0); | 446 | XFS_WANT_CORRUPTED_RETURN(i == 0); |
447 | if ((error = xfs_alloc_insert(bno_cur, &i))) | 447 | if ((error = xfs_btree_insert(bno_cur, &i))) |
448 | return error; | 448 | return error; |
449 | XFS_WANT_CORRUPTED_RETURN(i == 1); | 449 | XFS_WANT_CORRUPTED_RETURN(i == 1); |
450 | } | 450 | } |
@@ -1756,7 +1756,7 @@ xfs_free_ag_extent( | |||
1756 | else { | 1756 | else { |
1757 | nbno = bno; | 1757 | nbno = bno; |
1758 | nlen = len; | 1758 | nlen = len; |
1759 | if ((error = xfs_alloc_insert(bno_cur, &i))) | 1759 | if ((error = xfs_btree_insert(bno_cur, &i))) |
1760 | goto error0; | 1760 | goto error0; |
1761 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 1761 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
1762 | } | 1762 | } |
@@ -1768,7 +1768,7 @@ xfs_free_ag_extent( | |||
1768 | if ((error = xfs_alloc_lookup_eq(cnt_cur, nbno, nlen, &i))) | 1768 | if ((error = xfs_alloc_lookup_eq(cnt_cur, nbno, nlen, &i))) |
1769 | goto error0; | 1769 | goto error0; |
1770 | XFS_WANT_CORRUPTED_GOTO(i == 0, error0); | 1770 | XFS_WANT_CORRUPTED_GOTO(i == 0, error0); |
1771 | if ((error = xfs_alloc_insert(cnt_cur, &i))) | 1771 | if ((error = xfs_btree_insert(cnt_cur, &i))) |
1772 | goto error0; | 1772 | goto error0; |
1773 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 1773 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
1774 | xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); | 1774 | xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); |
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c index f21a3e9cc3db..818adca77fc6 100644 --- a/fs/xfs/xfs_alloc_btree.c +++ b/fs/xfs/xfs_alloc_btree.c | |||
@@ -583,256 +583,6 @@ error0: | |||
583 | } | 583 | } |
584 | 584 | ||
585 | /* | 585 | /* |
586 | * Insert one record/level. Return information to the caller | ||
587 | * allowing the next level up to proceed if necessary. | ||
588 | */ | ||
589 | STATIC int /* error */ | ||
590 | xfs_alloc_insrec( | ||
591 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
592 | int level, /* level to insert record at */ | ||
593 | xfs_agblock_t *bnop, /* i/o: block number inserted */ | ||
594 | xfs_alloc_rec_t *recp, /* i/o: record data inserted */ | ||
595 | xfs_btree_cur_t **curp, /* output: new cursor replacing cur */ | ||
596 | int *stat) /* output: success/failure */ | ||
597 | { | ||
598 | xfs_agf_t *agf; /* allocation group freelist header */ | ||
599 | xfs_alloc_block_t *block; /* btree block record/key lives in */ | ||
600 | xfs_buf_t *bp; /* buffer for block */ | ||
601 | int error; /* error return value */ | ||
602 | int i; /* loop index */ | ||
603 | xfs_alloc_key_t key; /* key value being inserted */ | ||
604 | xfs_alloc_key_t *kp; /* pointer to btree keys */ | ||
605 | xfs_agblock_t nbno; /* block number of allocated block */ | ||
606 | xfs_btree_cur_t *ncur; /* new cursor to be used at next lvl */ | ||
607 | xfs_alloc_key_t nkey; /* new key value, from split */ | ||
608 | xfs_alloc_rec_t nrec; /* new record value, for caller */ | ||
609 | int numrecs; | ||
610 | int optr; /* old ptr value */ | ||
611 | xfs_alloc_ptr_t *pp; /* pointer to btree addresses */ | ||
612 | int ptr; /* index in btree block for this rec */ | ||
613 | xfs_alloc_rec_t *rp; /* pointer to btree records */ | ||
614 | |||
615 | ASSERT(be32_to_cpu(recp->ar_blockcount) > 0); | ||
616 | |||
617 | /* | ||
618 | * GCC doesn't understand the (arguably complex) control flow in | ||
619 | * this function and complains about uninitialized structure fields | ||
620 | * without this. | ||
621 | */ | ||
622 | memset(&nrec, 0, sizeof(nrec)); | ||
623 | |||
624 | /* | ||
625 | * If we made it to the root level, allocate a new root block | ||
626 | * and we're done. | ||
627 | */ | ||
628 | if (level >= cur->bc_nlevels) { | ||
629 | XFS_STATS_INC(xs_abt_insrec); | ||
630 | if ((error = xfs_btree_new_root(cur, &i))) | ||
631 | return error; | ||
632 | *bnop = NULLAGBLOCK; | ||
633 | *stat = i; | ||
634 | return 0; | ||
635 | } | ||
636 | /* | ||
637 | * Make a key out of the record data to be inserted, and save it. | ||
638 | */ | ||
639 | key.ar_startblock = recp->ar_startblock; | ||
640 | key.ar_blockcount = recp->ar_blockcount; | ||
641 | optr = ptr = cur->bc_ptrs[level]; | ||
642 | /* | ||
643 | * If we're off the left edge, return failure. | ||
644 | */ | ||
645 | if (ptr == 0) { | ||
646 | *stat = 0; | ||
647 | return 0; | ||
648 | } | ||
649 | XFS_STATS_INC(xs_abt_insrec); | ||
650 | /* | ||
651 | * Get pointers to the btree buffer and block. | ||
652 | */ | ||
653 | bp = cur->bc_bufs[level]; | ||
654 | block = XFS_BUF_TO_ALLOC_BLOCK(bp); | ||
655 | numrecs = be16_to_cpu(block->bb_numrecs); | ||
656 | #ifdef DEBUG | ||
657 | if ((error = xfs_btree_check_sblock(cur, block, level, bp))) | ||
658 | return error; | ||
659 | /* | ||
660 | * Check that the new entry is being inserted in the right place. | ||
661 | */ | ||
662 | if (ptr <= numrecs) { | ||
663 | if (level == 0) { | ||
664 | rp = XFS_ALLOC_REC_ADDR(block, ptr, cur); | ||
665 | xfs_btree_check_rec(cur->bc_btnum, recp, rp); | ||
666 | } else { | ||
667 | kp = XFS_ALLOC_KEY_ADDR(block, ptr, cur); | ||
668 | xfs_btree_check_key(cur->bc_btnum, &key, kp); | ||
669 | } | ||
670 | } | ||
671 | #endif | ||
672 | nbno = NULLAGBLOCK; | ||
673 | ncur = NULL; | ||
674 | /* | ||
675 | * If the block is full, we can't insert the new entry until we | ||
676 | * make the block un-full. | ||
677 | */ | ||
678 | if (numrecs == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { | ||
679 | /* | ||
680 | * First, try shifting an entry to the right neighbor. | ||
681 | */ | ||
682 | if ((error = xfs_btree_rshift(cur, level, &i))) | ||
683 | return error; | ||
684 | if (i) { | ||
685 | /* nothing */ | ||
686 | } | ||
687 | /* | ||
688 | * Next, try shifting an entry to the left neighbor. | ||
689 | */ | ||
690 | else { | ||
691 | if ((error = xfs_btree_lshift(cur, level, &i))) | ||
692 | return error; | ||
693 | if (i) | ||
694 | optr = ptr = cur->bc_ptrs[level]; | ||
695 | else { | ||
696 | union xfs_btree_ptr bno = { .s = cpu_to_be32(nbno) }; | ||
697 | /* | ||
698 | * Next, try splitting the current block in | ||
699 | * half. If this works we have to re-set our | ||
700 | * variables because we could be in a | ||
701 | * different block now. | ||
702 | */ | ||
703 | if ((error = xfs_btree_split(cur, level, &bno, | ||
704 | (union xfs_btree_key *)&nkey, | ||
705 | &ncur, &i))) | ||
706 | return error; | ||
707 | nbno = be32_to_cpu(bno.s); | ||
708 | if (i) { | ||
709 | bp = cur->bc_bufs[level]; | ||
710 | block = XFS_BUF_TO_ALLOC_BLOCK(bp); | ||
711 | #ifdef DEBUG | ||
712 | if ((error = | ||
713 | xfs_btree_check_sblock(cur, | ||
714 | block, level, bp))) | ||
715 | return error; | ||
716 | #endif | ||
717 | ptr = cur->bc_ptrs[level]; | ||
718 | nrec.ar_startblock = nkey.ar_startblock; | ||
719 | nrec.ar_blockcount = nkey.ar_blockcount; | ||
720 | } | ||
721 | /* | ||
722 | * Otherwise the insert fails. | ||
723 | */ | ||
724 | else { | ||
725 | *stat = 0; | ||
726 | return 0; | ||
727 | } | ||
728 | } | ||
729 | } | ||
730 | } | ||
731 | /* | ||
732 | * At this point we know there's room for our new entry in the block | ||
733 | * we're pointing at. | ||
734 | */ | ||
735 | numrecs = be16_to_cpu(block->bb_numrecs); | ||
736 | if (level > 0) { | ||
737 | /* | ||
738 | * It's a non-leaf entry. Make a hole for the new data | ||
739 | * in the key and ptr regions of the block. | ||
740 | */ | ||
741 | kp = XFS_ALLOC_KEY_ADDR(block, 1, cur); | ||
742 | pp = XFS_ALLOC_PTR_ADDR(block, 1, cur); | ||
743 | #ifdef DEBUG | ||
744 | for (i = numrecs; i >= ptr; i--) { | ||
745 | if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(pp[i - 1]), level))) | ||
746 | return error; | ||
747 | } | ||
748 | #endif | ||
749 | memmove(&kp[ptr], &kp[ptr - 1], | ||
750 | (numrecs - ptr + 1) * sizeof(*kp)); | ||
751 | memmove(&pp[ptr], &pp[ptr - 1], | ||
752 | (numrecs - ptr + 1) * sizeof(*pp)); | ||
753 | #ifdef DEBUG | ||
754 | if ((error = xfs_btree_check_sptr(cur, *bnop, level))) | ||
755 | return error; | ||
756 | #endif | ||
757 | /* | ||
758 | * Now stuff the new data in, bump numrecs and log the new data. | ||
759 | */ | ||
760 | kp[ptr - 1] = key; | ||
761 | pp[ptr - 1] = cpu_to_be32(*bnop); | ||
762 | numrecs++; | ||
763 | block->bb_numrecs = cpu_to_be16(numrecs); | ||
764 | xfs_alloc_log_keys(cur, bp, ptr, numrecs); | ||
765 | xfs_alloc_log_ptrs(cur, bp, ptr, numrecs); | ||
766 | #ifdef DEBUG | ||
767 | if (ptr < numrecs) | ||
768 | xfs_btree_check_key(cur->bc_btnum, kp + ptr - 1, | ||
769 | kp + ptr); | ||
770 | #endif | ||
771 | } else { | ||
772 | /* | ||
773 | * It's a leaf entry. Make a hole for the new record. | ||
774 | */ | ||
775 | rp = XFS_ALLOC_REC_ADDR(block, 1, cur); | ||
776 | memmove(&rp[ptr], &rp[ptr - 1], | ||
777 | (numrecs - ptr + 1) * sizeof(*rp)); | ||
778 | /* | ||
779 | * Now stuff the new record in, bump numrecs | ||
780 | * and log the new data. | ||
781 | */ | ||
782 | rp[ptr - 1] = *recp; | ||
783 | numrecs++; | ||
784 | block->bb_numrecs = cpu_to_be16(numrecs); | ||
785 | xfs_alloc_log_recs(cur, bp, ptr, numrecs); | ||
786 | #ifdef DEBUG | ||
787 | if (ptr < numrecs) | ||
788 | xfs_btree_check_rec(cur->bc_btnum, rp + ptr - 1, | ||
789 | rp + ptr); | ||
790 | #endif | ||
791 | } | ||
792 | /* | ||
793 | * Log the new number of records in the btree header. | ||
794 | */ | ||
795 | xfs_alloc_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS); | ||
796 | /* | ||
797 | * If we inserted at the start of a block, update the parents' keys. | ||
798 | */ | ||
799 | if (optr == 1 && (error = xfs_btree_updkey(cur, (union xfs_btree_key *)&key, level + 1))) | ||
800 | return error; | ||
801 | /* | ||
802 | * Look to see if the longest extent in the allocation group | ||
803 | * needs to be updated. | ||
804 | */ | ||
805 | |||
806 | agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); | ||
807 | if (level == 0 && | ||
808 | cur->bc_btnum == XFS_BTNUM_CNT && | ||
809 | be32_to_cpu(block->bb_rightsib) == NULLAGBLOCK && | ||
810 | be32_to_cpu(recp->ar_blockcount) > be32_to_cpu(agf->agf_longest)) { | ||
811 | /* | ||
812 | * If this is a leaf in the by-size btree and there | ||
813 | * is no right sibling block and this block is bigger | ||
814 | * than the previous longest block, update it. | ||
815 | */ | ||
816 | agf->agf_longest = recp->ar_blockcount; | ||
817 | cur->bc_mp->m_perag[be32_to_cpu(agf->agf_seqno)].pagf_longest | ||
818 | = be32_to_cpu(recp->ar_blockcount); | ||
819 | xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, | ||
820 | XFS_AGF_LONGEST); | ||
821 | } | ||
822 | /* | ||
823 | * Return the new block number, if any. | ||
824 | * If there is one, give back a record value and a cursor too. | ||
825 | */ | ||
826 | *bnop = nbno; | ||
827 | if (nbno != NULLAGBLOCK) { | ||
828 | *recp = nrec; | ||
829 | *curp = ncur; | ||
830 | } | ||
831 | *stat = 1; | ||
832 | return 0; | ||
833 | } | ||
834 | |||
835 | /* | ||
836 | * Log header fields from a btree block. | 586 | * Log header fields from a btree block. |
837 | */ | 587 | */ |
838 | STATIC void | 588 | STATIC void |
@@ -1019,65 +769,6 @@ xfs_alloc_get_rec( | |||
1019 | return 0; | 769 | return 0; |
1020 | } | 770 | } |
1021 | 771 | ||
1022 | /* | ||
1023 | * Insert the current record at the point referenced by cur. | ||
1024 | * The cursor may be inconsistent on return if splits have been done. | ||
1025 | */ | ||
1026 | int /* error */ | ||
1027 | xfs_alloc_insert( | ||
1028 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
1029 | int *stat) /* success/failure */ | ||
1030 | { | ||
1031 | int error; /* error return value */ | ||
1032 | int i; /* result value, 0 for failure */ | ||
1033 | int level; /* current level number in btree */ | ||
1034 | xfs_agblock_t nbno; /* new block number (split result) */ | ||
1035 | xfs_btree_cur_t *ncur; /* new cursor (split result) */ | ||
1036 | xfs_alloc_rec_t nrec; /* record being inserted this level */ | ||
1037 | xfs_btree_cur_t *pcur; /* previous level's cursor */ | ||
1038 | |||
1039 | level = 0; | ||
1040 | nbno = NULLAGBLOCK; | ||
1041 | nrec.ar_startblock = cpu_to_be32(cur->bc_rec.a.ar_startblock); | ||
1042 | nrec.ar_blockcount = cpu_to_be32(cur->bc_rec.a.ar_blockcount); | ||
1043 | ncur = NULL; | ||
1044 | pcur = cur; | ||
1045 | /* | ||
1046 | * Loop going up the tree, starting at the leaf level. | ||
1047 | * Stop when we don't get a split block, that must mean that | ||
1048 | * the insert is finished with this level. | ||
1049 | */ | ||
1050 | do { | ||
1051 | /* | ||
1052 | * Insert nrec/nbno into this level of the tree. | ||
1053 | * Note if we fail, nbno will be null. | ||
1054 | */ | ||
1055 | if ((error = xfs_alloc_insrec(pcur, level++, &nbno, &nrec, &ncur, | ||
1056 | &i))) { | ||
1057 | if (pcur != cur) | ||
1058 | xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); | ||
1059 | return error; | ||
1060 | } | ||
1061 | /* | ||
1062 | * See if the cursor we just used is trash. | ||
1063 | * Can't trash the caller's cursor, but otherwise we should | ||
1064 | * if ncur is a new cursor or we're about to be done. | ||
1065 | */ | ||
1066 | if (pcur != cur && (ncur || nbno == NULLAGBLOCK)) { | ||
1067 | cur->bc_nlevels = pcur->bc_nlevels; | ||
1068 | xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); | ||
1069 | } | ||
1070 | /* | ||
1071 | * If we got a new cursor, switch to it. | ||
1072 | */ | ||
1073 | if (ncur) { | ||
1074 | pcur = ncur; | ||
1075 | ncur = NULL; | ||
1076 | } | ||
1077 | } while (nbno != NULLAGBLOCK); | ||
1078 | *stat = i; | ||
1079 | return 0; | ||
1080 | } | ||
1081 | 772 | ||
1082 | STATIC struct xfs_btree_cur * | 773 | STATIC struct xfs_btree_cur * |
1083 | xfs_allocbt_dup_cursor( | 774 | xfs_allocbt_dup_cursor( |
@@ -1170,6 +861,12 @@ xfs_allocbt_update_lastrec( | |||
1170 | return; | 861 | return; |
1171 | len = rec->alloc.ar_blockcount; | 862 | len = rec->alloc.ar_blockcount; |
1172 | break; | 863 | break; |
864 | case LASTREC_INSREC: | ||
865 | if (be32_to_cpu(rec->alloc.ar_blockcount) <= | ||
866 | be32_to_cpu(agf->agf_longest)) | ||
867 | return; | ||
868 | len = rec->alloc.ar_blockcount; | ||
869 | break; | ||
1173 | default: | 870 | default: |
1174 | ASSERT(0); | 871 | ASSERT(0); |
1175 | return; | 872 | return; |
@@ -1200,6 +897,28 @@ xfs_allocbt_init_key_from_rec( | |||
1200 | } | 897 | } |
1201 | 898 | ||
1202 | STATIC void | 899 | STATIC void |
900 | xfs_allocbt_init_rec_from_key( | ||
901 | union xfs_btree_key *key, | ||
902 | union xfs_btree_rec *rec) | ||
903 | { | ||
904 | ASSERT(key->alloc.ar_startblock != 0); | ||
905 | |||
906 | rec->alloc.ar_startblock = key->alloc.ar_startblock; | ||
907 | rec->alloc.ar_blockcount = key->alloc.ar_blockcount; | ||
908 | } | ||
909 | |||
910 | STATIC void | ||
911 | xfs_allocbt_init_rec_from_cur( | ||
912 | struct xfs_btree_cur *cur, | ||
913 | union xfs_btree_rec *rec) | ||
914 | { | ||
915 | ASSERT(cur->bc_rec.a.ar_startblock != 0); | ||
916 | |||
917 | rec->alloc.ar_startblock = cpu_to_be32(cur->bc_rec.a.ar_startblock); | ||
918 | rec->alloc.ar_blockcount = cpu_to_be32(cur->bc_rec.a.ar_blockcount); | ||
919 | } | ||
920 | |||
921 | STATIC void | ||
1203 | xfs_allocbt_init_ptr_from_cur( | 922 | xfs_allocbt_init_ptr_from_cur( |
1204 | struct xfs_btree_cur *cur, | 923 | struct xfs_btree_cur *cur, |
1205 | union xfs_btree_ptr *ptr) | 924 | union xfs_btree_ptr *ptr) |
@@ -1309,6 +1028,8 @@ static const struct xfs_btree_ops xfs_allocbt_ops = { | |||
1309 | .update_lastrec = xfs_allocbt_update_lastrec, | 1028 | .update_lastrec = xfs_allocbt_update_lastrec, |
1310 | .get_maxrecs = xfs_allocbt_get_maxrecs, | 1029 | .get_maxrecs = xfs_allocbt_get_maxrecs, |
1311 | .init_key_from_rec = xfs_allocbt_init_key_from_rec, | 1030 | .init_key_from_rec = xfs_allocbt_init_key_from_rec, |
1031 | .init_rec_from_key = xfs_allocbt_init_rec_from_key, | ||
1032 | .init_rec_from_cur = xfs_allocbt_init_rec_from_cur, | ||
1312 | .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, | 1033 | .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, |
1313 | .key_diff = xfs_allocbt_key_diff, | 1034 | .key_diff = xfs_allocbt_key_diff, |
1314 | 1035 | ||
diff --git a/fs/xfs/xfs_alloc_btree.h b/fs/xfs/xfs_alloc_btree.h index 81e2f3607819..2e340ef8025a 100644 --- a/fs/xfs/xfs_alloc_btree.h +++ b/fs/xfs/xfs_alloc_btree.h | |||
@@ -107,12 +107,6 @@ extern int xfs_alloc_delete(struct xfs_btree_cur *cur, int *stat); | |||
107 | extern int xfs_alloc_get_rec(struct xfs_btree_cur *cur, xfs_agblock_t *bno, | 107 | extern int xfs_alloc_get_rec(struct xfs_btree_cur *cur, xfs_agblock_t *bno, |
108 | xfs_extlen_t *len, int *stat); | 108 | xfs_extlen_t *len, int *stat); |
109 | 109 | ||
110 | /* | ||
111 | * Insert the current record at the point referenced by cur. | ||
112 | * The cursor may be inconsistent on return if splits have been done. | ||
113 | */ | ||
114 | extern int xfs_alloc_insert(struct xfs_btree_cur *cur, int *stat); | ||
115 | |||
116 | 110 | ||
117 | extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *, | 111 | extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *, |
118 | struct xfs_trans *, struct xfs_buf *, | 112 | struct xfs_trans *, struct xfs_buf *, |
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 315bc2912682..85e2e8b9cf41 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -977,7 +977,7 @@ xfs_bmap_add_extent_delay_real( | |||
977 | goto done; | 977 | goto done; |
978 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); | 978 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); |
979 | cur->bc_rec.b.br_state = XFS_EXT_NORM; | 979 | cur->bc_rec.b.br_state = XFS_EXT_NORM; |
980 | if ((error = xfs_bmbt_insert(cur, &i))) | 980 | if ((error = xfs_btree_insert(cur, &i))) |
981 | goto done; | 981 | goto done; |
982 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); | 982 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
983 | } | 983 | } |
@@ -1053,7 +1053,7 @@ xfs_bmap_add_extent_delay_real( | |||
1053 | goto done; | 1053 | goto done; |
1054 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); | 1054 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); |
1055 | cur->bc_rec.b.br_state = XFS_EXT_NORM; | 1055 | cur->bc_rec.b.br_state = XFS_EXT_NORM; |
1056 | if ((error = xfs_bmbt_insert(cur, &i))) | 1056 | if ((error = xfs_btree_insert(cur, &i))) |
1057 | goto done; | 1057 | goto done; |
1058 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); | 1058 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
1059 | } | 1059 | } |
@@ -1143,7 +1143,7 @@ xfs_bmap_add_extent_delay_real( | |||
1143 | goto done; | 1143 | goto done; |
1144 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); | 1144 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); |
1145 | cur->bc_rec.b.br_state = XFS_EXT_NORM; | 1145 | cur->bc_rec.b.br_state = XFS_EXT_NORM; |
1146 | if ((error = xfs_bmbt_insert(cur, &i))) | 1146 | if ((error = xfs_btree_insert(cur, &i))) |
1147 | goto done; | 1147 | goto done; |
1148 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); | 1148 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
1149 | } | 1149 | } |
@@ -1198,7 +1198,7 @@ xfs_bmap_add_extent_delay_real( | |||
1198 | goto done; | 1198 | goto done; |
1199 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); | 1199 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); |
1200 | cur->bc_rec.b.br_state = XFS_EXT_NORM; | 1200 | cur->bc_rec.b.br_state = XFS_EXT_NORM; |
1201 | if ((error = xfs_bmbt_insert(cur, &i))) | 1201 | if ((error = xfs_btree_insert(cur, &i))) |
1202 | goto done; | 1202 | goto done; |
1203 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); | 1203 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
1204 | } | 1204 | } |
@@ -1651,7 +1651,7 @@ xfs_bmap_add_extent_unwritten_real( | |||
1651 | oldext))) | 1651 | oldext))) |
1652 | goto done; | 1652 | goto done; |
1653 | cur->bc_rec.b = *new; | 1653 | cur->bc_rec.b = *new; |
1654 | if ((error = xfs_bmbt_insert(cur, &i))) | 1654 | if ((error = xfs_btree_insert(cur, &i))) |
1655 | goto done; | 1655 | goto done; |
1656 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); | 1656 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
1657 | } | 1657 | } |
@@ -1741,7 +1741,7 @@ xfs_bmap_add_extent_unwritten_real( | |||
1741 | goto done; | 1741 | goto done; |
1742 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); | 1742 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); |
1743 | cur->bc_rec.b.br_state = XFS_EXT_NORM; | 1743 | cur->bc_rec.b.br_state = XFS_EXT_NORM; |
1744 | if ((error = xfs_bmbt_insert(cur, &i))) | 1744 | if ((error = xfs_btree_insert(cur, &i))) |
1745 | goto done; | 1745 | goto done; |
1746 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); | 1746 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
1747 | } | 1747 | } |
@@ -1789,7 +1789,7 @@ xfs_bmap_add_extent_unwritten_real( | |||
1789 | cur->bc_rec.b = PREV; | 1789 | cur->bc_rec.b = PREV; |
1790 | cur->bc_rec.b.br_blockcount = | 1790 | cur->bc_rec.b.br_blockcount = |
1791 | new->br_startoff - PREV.br_startoff; | 1791 | new->br_startoff - PREV.br_startoff; |
1792 | if ((error = xfs_bmbt_insert(cur, &i))) | 1792 | if ((error = xfs_btree_insert(cur, &i))) |
1793 | goto done; | 1793 | goto done; |
1794 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); | 1794 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
1795 | /* | 1795 | /* |
@@ -1804,7 +1804,7 @@ xfs_bmap_add_extent_unwritten_real( | |||
1804 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); | 1804 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); |
1805 | /* new middle extent - newext */ | 1805 | /* new middle extent - newext */ |
1806 | cur->bc_rec.b.br_state = new->br_state; | 1806 | cur->bc_rec.b.br_state = new->br_state; |
1807 | if ((error = xfs_bmbt_insert(cur, &i))) | 1807 | if ((error = xfs_btree_insert(cur, &i))) |
1808 | goto done; | 1808 | goto done; |
1809 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); | 1809 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
1810 | } | 1810 | } |
@@ -2264,7 +2264,7 @@ xfs_bmap_add_extent_hole_real( | |||
2264 | goto done; | 2264 | goto done; |
2265 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); | 2265 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); |
2266 | cur->bc_rec.b.br_state = new->br_state; | 2266 | cur->bc_rec.b.br_state = new->br_state; |
2267 | if ((error = xfs_bmbt_insert(cur, &i))) | 2267 | if ((error = xfs_btree_insert(cur, &i))) |
2268 | goto done; | 2268 | goto done; |
2269 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); | 2269 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
2270 | } | 2270 | } |
@@ -3303,7 +3303,7 @@ xfs_bmap_del_extent( | |||
3303 | if ((error = xfs_btree_increment(cur, 0, &i))) | 3303 | if ((error = xfs_btree_increment(cur, 0, &i))) |
3304 | goto done; | 3304 | goto done; |
3305 | cur->bc_rec.b = new; | 3305 | cur->bc_rec.b = new; |
3306 | error = xfs_bmbt_insert(cur, &i); | 3306 | error = xfs_btree_insert(cur, &i); |
3307 | if (error && error != ENOSPC) | 3307 | if (error && error != ENOSPC) |
3308 | goto done; | 3308 | goto done; |
3309 | /* | 3309 | /* |
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 204f276aeaad..2b15df32b7d2 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c | |||
@@ -456,198 +456,6 @@ error0: | |||
456 | return error; | 456 | return error; |
457 | } | 457 | } |
458 | 458 | ||
459 | /* | ||
460 | * Insert one record/level. Return information to the caller | ||
461 | * allowing the next level up to proceed if necessary. | ||
462 | */ | ||
463 | STATIC int /* error */ | ||
464 | xfs_bmbt_insrec( | ||
465 | xfs_btree_cur_t *cur, | ||
466 | int level, | ||
467 | xfs_fsblock_t *bnop, | ||
468 | xfs_bmbt_rec_t *recp, | ||
469 | xfs_btree_cur_t **curp, | ||
470 | int *stat) /* no-go/done/continue */ | ||
471 | { | ||
472 | xfs_bmbt_block_t *block; /* bmap btree block */ | ||
473 | xfs_buf_t *bp; /* buffer for block */ | ||
474 | int error; /* error return value */ | ||
475 | int i; /* loop index */ | ||
476 | xfs_bmbt_key_t key; /* bmap btree key */ | ||
477 | xfs_bmbt_key_t *kp=NULL; /* pointer to bmap btree key */ | ||
478 | int logflags; /* inode logging flags */ | ||
479 | xfs_fsblock_t nbno; /* new block number */ | ||
480 | struct xfs_btree_cur *ncur; /* new btree cursor */ | ||
481 | __uint64_t startoff; /* new btree key value */ | ||
482 | xfs_bmbt_rec_t nrec; /* new record count */ | ||
483 | int optr; /* old key/record index */ | ||
484 | xfs_bmbt_ptr_t *pp; /* pointer to bmap block addr */ | ||
485 | int ptr; /* key/record index */ | ||
486 | xfs_bmbt_rec_t *rp=NULL; /* pointer to bmap btree rec */ | ||
487 | int numrecs; | ||
488 | |||
489 | ASSERT(level < cur->bc_nlevels); | ||
490 | XFS_BMBT_TRACE_CURSOR(cur, ENTRY); | ||
491 | XFS_BMBT_TRACE_ARGIFR(cur, level, *bnop, recp); | ||
492 | ncur = NULL; | ||
493 | key.br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(recp)); | ||
494 | optr = ptr = cur->bc_ptrs[level]; | ||
495 | if (ptr == 0) { | ||
496 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); | ||
497 | *stat = 0; | ||
498 | return 0; | ||
499 | } | ||
500 | XFS_STATS_INC(xs_bmbt_insrec); | ||
501 | block = xfs_bmbt_get_block(cur, level, &bp); | ||
502 | numrecs = be16_to_cpu(block->bb_numrecs); | ||
503 | #ifdef DEBUG | ||
504 | if ((error = xfs_btree_check_lblock(cur, block, level, bp))) { | ||
505 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | ||
506 | return error; | ||
507 | } | ||
508 | if (ptr <= numrecs) { | ||
509 | if (level == 0) { | ||
510 | rp = XFS_BMAP_REC_IADDR(block, ptr, cur); | ||
511 | xfs_btree_check_rec(XFS_BTNUM_BMAP, recp, rp); | ||
512 | } else { | ||
513 | kp = XFS_BMAP_KEY_IADDR(block, ptr, cur); | ||
514 | xfs_btree_check_key(XFS_BTNUM_BMAP, &key, kp); | ||
515 | } | ||
516 | } | ||
517 | #endif | ||
518 | nbno = NULLFSBLOCK; | ||
519 | if (numrecs == XFS_BMAP_BLOCK_IMAXRECS(level, cur)) { | ||
520 | if (numrecs < XFS_BMAP_BLOCK_DMAXRECS(level, cur)) { | ||
521 | /* | ||
522 | * A root block, that can be made bigger. | ||
523 | */ | ||
524 | xfs_iroot_realloc(cur->bc_private.b.ip, 1, | ||
525 | cur->bc_private.b.whichfork); | ||
526 | block = xfs_bmbt_get_block(cur, level, &bp); | ||
527 | } else if (level == cur->bc_nlevels - 1) { | ||
528 | if ((error = xfs_btree_new_iroot(cur, &logflags, stat)) || | ||
529 | *stat == 0) { | ||
530 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | ||
531 | return error; | ||
532 | } | ||
533 | xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, | ||
534 | logflags); | ||
535 | block = xfs_bmbt_get_block(cur, level, &bp); | ||
536 | } else { | ||
537 | if ((error = xfs_btree_rshift(cur, level, &i))) { | ||
538 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | ||
539 | return error; | ||
540 | } | ||
541 | if (i) { | ||
542 | /* nothing */ | ||
543 | } else { | ||
544 | if ((error = xfs_btree_lshift(cur, level, &i))) { | ||
545 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | ||
546 | return error; | ||
547 | } | ||
548 | if (i) { | ||
549 | optr = ptr = cur->bc_ptrs[level]; | ||
550 | } else { | ||
551 | union xfs_btree_ptr bno = { .l = cpu_to_be64(nbno) }; | ||
552 | union xfs_btree_key skey; | ||
553 | if ((error = xfs_btree_split(cur, level, | ||
554 | &bno, &skey, &ncur, | ||
555 | &i))) { | ||
556 | XFS_BMBT_TRACE_CURSOR(cur, | ||
557 | ERROR); | ||
558 | return error; | ||
559 | } | ||
560 | nbno = be64_to_cpu(bno.l); | ||
561 | startoff = be64_to_cpu(skey.bmbt.br_startoff); | ||
562 | if (i) { | ||
563 | block = xfs_bmbt_get_block( | ||
564 | cur, level, &bp); | ||
565 | #ifdef DEBUG | ||
566 | if ((error = | ||
567 | xfs_btree_check_lblock(cur, | ||
568 | block, level, bp))) { | ||
569 | XFS_BMBT_TRACE_CURSOR( | ||
570 | cur, ERROR); | ||
571 | return error; | ||
572 | } | ||
573 | #endif | ||
574 | ptr = cur->bc_ptrs[level]; | ||
575 | xfs_bmbt_disk_set_allf(&nrec, | ||
576 | startoff, 0, 0, | ||
577 | XFS_EXT_NORM); | ||
578 | } else { | ||
579 | XFS_BMBT_TRACE_CURSOR(cur, | ||
580 | EXIT); | ||
581 | *stat = 0; | ||
582 | return 0; | ||
583 | } | ||
584 | } | ||
585 | } | ||
586 | } | ||
587 | } | ||
588 | numrecs = be16_to_cpu(block->bb_numrecs); | ||
589 | if (level > 0) { | ||
590 | kp = XFS_BMAP_KEY_IADDR(block, 1, cur); | ||
591 | pp = XFS_BMAP_PTR_IADDR(block, 1, cur); | ||
592 | #ifdef DEBUG | ||
593 | for (i = numrecs; i >= ptr; i--) { | ||
594 | if ((error = xfs_btree_check_lptr_disk(cur, pp[i - 1], | ||
595 | level))) { | ||
596 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | ||
597 | return error; | ||
598 | } | ||
599 | } | ||
600 | #endif | ||
601 | memmove(&kp[ptr], &kp[ptr - 1], | ||
602 | (numrecs - ptr + 1) * sizeof(*kp)); | ||
603 | memmove(&pp[ptr], &pp[ptr - 1], | ||
604 | (numrecs - ptr + 1) * sizeof(*pp)); | ||
605 | #ifdef DEBUG | ||
606 | if ((error = xfs_btree_check_lptr(cur, *bnop, level))) { | ||
607 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | ||
608 | return error; | ||
609 | } | ||
610 | #endif | ||
611 | kp[ptr - 1] = key; | ||
612 | pp[ptr - 1] = cpu_to_be64(*bnop); | ||
613 | numrecs++; | ||
614 | block->bb_numrecs = cpu_to_be16(numrecs); | ||
615 | xfs_bmbt_log_keys(cur, bp, ptr, numrecs); | ||
616 | xfs_bmbt_log_ptrs(cur, bp, ptr, numrecs); | ||
617 | } else { | ||
618 | rp = XFS_BMAP_REC_IADDR(block, 1, cur); | ||
619 | memmove(&rp[ptr], &rp[ptr - 1], | ||
620 | (numrecs - ptr + 1) * sizeof(*rp)); | ||
621 | rp[ptr - 1] = *recp; | ||
622 | numrecs++; | ||
623 | block->bb_numrecs = cpu_to_be16(numrecs); | ||
624 | xfs_bmbt_log_recs(cur, bp, ptr, numrecs); | ||
625 | } | ||
626 | xfs_bmbt_log_block(cur, bp, XFS_BB_NUMRECS); | ||
627 | #ifdef DEBUG | ||
628 | if (ptr < numrecs) { | ||
629 | if (level == 0) | ||
630 | xfs_btree_check_rec(XFS_BTNUM_BMAP, rp + ptr - 1, | ||
631 | rp + ptr); | ||
632 | else | ||
633 | xfs_btree_check_key(XFS_BTNUM_BMAP, kp + ptr - 1, | ||
634 | kp + ptr); | ||
635 | } | ||
636 | #endif | ||
637 | if (optr == 1 && (error = xfs_btree_updkey(cur, (union xfs_btree_key *)&key, level + 1))) { | ||
638 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | ||
639 | return error; | ||
640 | } | ||
641 | *bnop = nbno; | ||
642 | if (nbno != NULLFSBLOCK) { | ||
643 | *recp = nrec; | ||
644 | *curp = ncur; | ||
645 | } | ||
646 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); | ||
647 | *stat = 1; | ||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | STATIC int | 459 | STATIC int |
652 | xfs_bmbt_killroot( | 460 | xfs_bmbt_killroot( |
653 | xfs_btree_cur_t *cur) | 461 | xfs_btree_cur_t *cur) |
@@ -1060,67 +868,6 @@ xfs_bmbt_disk_get_startoff( | |||
1060 | } | 868 | } |
1061 | 869 | ||
1062 | /* | 870 | /* |
1063 | * Insert the current record at the point referenced by cur. | ||
1064 | * | ||
1065 | * A multi-level split of the tree on insert will invalidate the original | ||
1066 | * cursor. All callers of this function should assume that the cursor is | ||
1067 | * no longer valid and revalidate it. | ||
1068 | */ | ||
1069 | int /* error */ | ||
1070 | xfs_bmbt_insert( | ||
1071 | xfs_btree_cur_t *cur, | ||
1072 | int *stat) /* success/failure */ | ||
1073 | { | ||
1074 | int error; /* error return value */ | ||
1075 | int i; | ||
1076 | int level; | ||
1077 | xfs_fsblock_t nbno; | ||
1078 | xfs_btree_cur_t *ncur; | ||
1079 | xfs_bmbt_rec_t nrec; | ||
1080 | xfs_btree_cur_t *pcur; | ||
1081 | |||
1082 | XFS_BMBT_TRACE_CURSOR(cur, ENTRY); | ||
1083 | level = 0; | ||
1084 | nbno = NULLFSBLOCK; | ||
1085 | xfs_bmbt_disk_set_all(&nrec, &cur->bc_rec.b); | ||
1086 | ncur = NULL; | ||
1087 | pcur = cur; | ||
1088 | do { | ||
1089 | if ((error = xfs_bmbt_insrec(pcur, level++, &nbno, &nrec, &ncur, | ||
1090 | &i))) { | ||
1091 | if (pcur != cur) | ||
1092 | xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); | ||
1093 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | ||
1094 | return error; | ||
1095 | } | ||
1096 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
1097 | if (pcur != cur && (ncur || nbno == NULLFSBLOCK)) { | ||
1098 | cur->bc_nlevels = pcur->bc_nlevels; | ||
1099 | cur->bc_private.b.allocated += | ||
1100 | pcur->bc_private.b.allocated; | ||
1101 | pcur->bc_private.b.allocated = 0; | ||
1102 | ASSERT((cur->bc_private.b.firstblock != NULLFSBLOCK) || | ||
1103 | XFS_IS_REALTIME_INODE(cur->bc_private.b.ip)); | ||
1104 | cur->bc_private.b.firstblock = | ||
1105 | pcur->bc_private.b.firstblock; | ||
1106 | ASSERT(cur->bc_private.b.flist == | ||
1107 | pcur->bc_private.b.flist); | ||
1108 | xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); | ||
1109 | } | ||
1110 | if (ncur) { | ||
1111 | pcur = ncur; | ||
1112 | ncur = NULL; | ||
1113 | } | ||
1114 | } while (nbno != NULLFSBLOCK); | ||
1115 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); | ||
1116 | *stat = i; | ||
1117 | return 0; | ||
1118 | error0: | ||
1119 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | ||
1120 | return error; | ||
1121 | } | ||
1122 | |||
1123 | /* | ||
1124 | * Log fields from the btree block header. | 871 | * Log fields from the btree block header. |
1125 | */ | 872 | */ |
1126 | void | 873 | void |
@@ -1450,6 +1197,21 @@ xfs_bmbt_dup_cursor( | |||
1450 | return new; | 1197 | return new; |
1451 | } | 1198 | } |
1452 | 1199 | ||
1200 | STATIC void | ||
1201 | xfs_bmbt_update_cursor( | ||
1202 | struct xfs_btree_cur *src, | ||
1203 | struct xfs_btree_cur *dst) | ||
1204 | { | ||
1205 | ASSERT((dst->bc_private.b.firstblock != NULLFSBLOCK) || | ||
1206 | (dst->bc_private.b.ip->i_d.di_flags & XFS_DIFLAG_REALTIME)); | ||
1207 | ASSERT(dst->bc_private.b.flist == src->bc_private.b.flist); | ||
1208 | |||
1209 | dst->bc_private.b.allocated += src->bc_private.b.allocated; | ||
1210 | dst->bc_private.b.firstblock = src->bc_private.b.firstblock; | ||
1211 | |||
1212 | src->bc_private.b.allocated = 0; | ||
1213 | } | ||
1214 | |||
1453 | STATIC int | 1215 | STATIC int |
1454 | xfs_bmbt_alloc_block( | 1216 | xfs_bmbt_alloc_block( |
1455 | struct xfs_btree_cur *cur, | 1217 | struct xfs_btree_cur *cur, |
@@ -1544,6 +1306,23 @@ xfs_bmbt_get_maxrecs( | |||
1544 | return XFS_BMAP_BLOCK_IMAXRECS(level, cur); | 1306 | return XFS_BMAP_BLOCK_IMAXRECS(level, cur); |
1545 | } | 1307 | } |
1546 | 1308 | ||
1309 | /* | ||
1310 | * Get the maximum records we could store in the on-disk format. | ||
1311 | * | ||
1312 | * For non-root nodes this is equivalent to xfs_bmbt_get_maxrecs, but | ||
1313 | * for the root node this checks the available space in the dinode fork | ||
1314 | * so that we can resize the in-memory buffer to match it. After a | ||
1315 | * resize to the maximum size this function returns the same value | ||
1316 | * as xfs_bmbt_get_maxrecs for the root node, too. | ||
1317 | */ | ||
1318 | STATIC int | ||
1319 | xfs_bmbt_get_dmaxrecs( | ||
1320 | struct xfs_btree_cur *cur, | ||
1321 | int level) | ||
1322 | { | ||
1323 | return XFS_BMAP_BLOCK_DMAXRECS(level, cur); | ||
1324 | } | ||
1325 | |||
1547 | STATIC void | 1326 | STATIC void |
1548 | xfs_bmbt_init_key_from_rec( | 1327 | xfs_bmbt_init_key_from_rec( |
1549 | union xfs_btree_key *key, | 1328 | union xfs_btree_key *key, |
@@ -1554,6 +1333,25 @@ xfs_bmbt_init_key_from_rec( | |||
1554 | } | 1333 | } |
1555 | 1334 | ||
1556 | STATIC void | 1335 | STATIC void |
1336 | xfs_bmbt_init_rec_from_key( | ||
1337 | union xfs_btree_key *key, | ||
1338 | union xfs_btree_rec *rec) | ||
1339 | { | ||
1340 | ASSERT(key->bmbt.br_startoff != 0); | ||
1341 | |||
1342 | xfs_bmbt_disk_set_allf(&rec->bmbt, be64_to_cpu(key->bmbt.br_startoff), | ||
1343 | 0, 0, XFS_EXT_NORM); | ||
1344 | } | ||
1345 | |||
1346 | STATIC void | ||
1347 | xfs_bmbt_init_rec_from_cur( | ||
1348 | struct xfs_btree_cur *cur, | ||
1349 | union xfs_btree_rec *rec) | ||
1350 | { | ||
1351 | xfs_bmbt_disk_set_all(&rec->bmbt, &cur->bc_rec.b); | ||
1352 | } | ||
1353 | |||
1354 | STATIC void | ||
1557 | xfs_bmbt_init_ptr_from_cur( | 1355 | xfs_bmbt_init_ptr_from_cur( |
1558 | struct xfs_btree_cur *cur, | 1356 | struct xfs_btree_cur *cur, |
1559 | union xfs_btree_ptr *ptr) | 1357 | union xfs_btree_ptr *ptr) |
@@ -1660,9 +1458,13 @@ static const struct xfs_btree_ops xfs_bmbt_ops = { | |||
1660 | .key_len = sizeof(xfs_bmbt_key_t), | 1458 | .key_len = sizeof(xfs_bmbt_key_t), |
1661 | 1459 | ||
1662 | .dup_cursor = xfs_bmbt_dup_cursor, | 1460 | .dup_cursor = xfs_bmbt_dup_cursor, |
1461 | .update_cursor = xfs_bmbt_update_cursor, | ||
1663 | .alloc_block = xfs_bmbt_alloc_block, | 1462 | .alloc_block = xfs_bmbt_alloc_block, |
1664 | .get_maxrecs = xfs_bmbt_get_maxrecs, | 1463 | .get_maxrecs = xfs_bmbt_get_maxrecs, |
1464 | .get_dmaxrecs = xfs_bmbt_get_dmaxrecs, | ||
1665 | .init_key_from_rec = xfs_bmbt_init_key_from_rec, | 1465 | .init_key_from_rec = xfs_bmbt_init_key_from_rec, |
1466 | .init_rec_from_key = xfs_bmbt_init_rec_from_key, | ||
1467 | .init_rec_from_cur = xfs_bmbt_init_rec_from_cur, | ||
1666 | .init_ptr_from_cur = xfs_bmbt_init_ptr_from_cur, | 1468 | .init_ptr_from_cur = xfs_bmbt_init_ptr_from_cur, |
1667 | .key_diff = xfs_bmbt_key_diff, | 1469 | .key_diff = xfs_bmbt_key_diff, |
1668 | 1470 | ||
diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h index 26fd8ace3e77..703fe2e34347 100644 --- a/fs/xfs/xfs_bmap_btree.h +++ b/fs/xfs/xfs_bmap_btree.h | |||
@@ -250,7 +250,6 @@ extern void xfs_bmbt_disk_get_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s); | |||
250 | extern xfs_filblks_t xfs_bmbt_disk_get_blockcount(xfs_bmbt_rec_t *r); | 250 | extern xfs_filblks_t xfs_bmbt_disk_get_blockcount(xfs_bmbt_rec_t *r); |
251 | extern xfs_fileoff_t xfs_bmbt_disk_get_startoff(xfs_bmbt_rec_t *r); | 251 | extern xfs_fileoff_t xfs_bmbt_disk_get_startoff(xfs_bmbt_rec_t *r); |
252 | 252 | ||
253 | extern int xfs_bmbt_insert(struct xfs_btree_cur *, int *); | ||
254 | extern void xfs_bmbt_log_block(struct xfs_btree_cur *, struct xfs_buf *, int); | 253 | extern void xfs_bmbt_log_block(struct xfs_btree_cur *, struct xfs_buf *, int); |
255 | extern void xfs_bmbt_log_recs(struct xfs_btree_cur *, struct xfs_buf *, int, | 254 | extern void xfs_bmbt_log_recs(struct xfs_btree_cur *, struct xfs_buf *, int, |
256 | int); | 255 | int); |
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index 3b6e01dea669..36477aae77df 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c | |||
@@ -963,6 +963,17 @@ xfs_btree_ptr_is_null( | |||
963 | return be32_to_cpu(ptr->s) == NULLAGBLOCK; | 963 | return be32_to_cpu(ptr->s) == NULLAGBLOCK; |
964 | } | 964 | } |
965 | 965 | ||
966 | STATIC void | ||
967 | xfs_btree_set_ptr_null( | ||
968 | struct xfs_btree_cur *cur, | ||
969 | union xfs_btree_ptr *ptr) | ||
970 | { | ||
971 | if (cur->bc_flags & XFS_BTREE_LONG_PTRS) | ||
972 | ptr->l = cpu_to_be64(NULLFSBLOCK); | ||
973 | else | ||
974 | ptr->s = cpu_to_be32(NULLAGBLOCK); | ||
975 | } | ||
976 | |||
966 | /* | 977 | /* |
967 | * Get/set/init sibling pointers | 978 | * Get/set/init sibling pointers |
968 | */ | 979 | */ |
@@ -2697,3 +2708,354 @@ out0: | |||
2697 | *stat = 0; | 2708 | *stat = 0; |
2698 | return 0; | 2709 | return 0; |
2699 | } | 2710 | } |
2711 | |||
2712 | STATIC int | ||
2713 | xfs_btree_make_block_unfull( | ||
2714 | struct xfs_btree_cur *cur, /* btree cursor */ | ||
2715 | int level, /* btree level */ | ||
2716 | int numrecs,/* # of recs in block */ | ||
2717 | int *oindex,/* old tree index */ | ||
2718 | int *index, /* new tree index */ | ||
2719 | union xfs_btree_ptr *nptr, /* new btree ptr */ | ||
2720 | struct xfs_btree_cur **ncur, /* new btree cursor */ | ||
2721 | union xfs_btree_rec *nrec, /* new record */ | ||
2722 | int *stat) | ||
2723 | { | ||
2724 | union xfs_btree_key key; /* new btree key value */ | ||
2725 | int error = 0; | ||
2726 | |||
2727 | if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && | ||
2728 | level == cur->bc_nlevels - 1) { | ||
2729 | struct xfs_inode *ip = cur->bc_private.b.ip; | ||
2730 | |||
2731 | if (numrecs < cur->bc_ops->get_dmaxrecs(cur, level)) { | ||
2732 | /* A root block that can be made bigger. */ | ||
2733 | |||
2734 | xfs_iroot_realloc(ip, 1, cur->bc_private.b.whichfork); | ||
2735 | } else { | ||
2736 | /* A root block that needs replacing */ | ||
2737 | int logflags = 0; | ||
2738 | |||
2739 | error = xfs_btree_new_iroot(cur, &logflags, stat); | ||
2740 | if (error || *stat == 0) | ||
2741 | return error; | ||
2742 | |||
2743 | xfs_trans_log_inode(cur->bc_tp, ip, logflags); | ||
2744 | } | ||
2745 | |||
2746 | return 0; | ||
2747 | } | ||
2748 | |||
2749 | /* First, try shifting an entry to the right neighbor. */ | ||
2750 | error = xfs_btree_rshift(cur, level, stat); | ||
2751 | if (error || *stat) | ||
2752 | return error; | ||
2753 | |||
2754 | /* Next, try shifting an entry to the left neighbor. */ | ||
2755 | error = xfs_btree_lshift(cur, level, stat); | ||
2756 | if (error) | ||
2757 | return error; | ||
2758 | |||
2759 | if (*stat) { | ||
2760 | *oindex = *index = cur->bc_ptrs[level]; | ||
2761 | return 0; | ||
2762 | } | ||
2763 | |||
2764 | /* | ||
2765 | * Next, try splitting the current block in half. | ||
2766 | * | ||
2767 | * If this works we have to re-set our variables because we | ||
2768 | * could be in a different block now. | ||
2769 | */ | ||
2770 | error = xfs_btree_split(cur, level, nptr, &key, ncur, stat); | ||
2771 | if (error || *stat == 0) | ||
2772 | return error; | ||
2773 | |||
2774 | |||
2775 | *index = cur->bc_ptrs[level]; | ||
2776 | cur->bc_ops->init_rec_from_key(&key, nrec); | ||
2777 | return 0; | ||
2778 | } | ||
2779 | |||
2780 | /* | ||
2781 | * Insert one record/level. Return information to the caller | ||
2782 | * allowing the next level up to proceed if necessary. | ||
2783 | */ | ||
2784 | STATIC int | ||
2785 | xfs_btree_insrec( | ||
2786 | struct xfs_btree_cur *cur, /* btree cursor */ | ||
2787 | int level, /* level to insert record at */ | ||
2788 | union xfs_btree_ptr *ptrp, /* i/o: block number inserted */ | ||
2789 | union xfs_btree_rec *recp, /* i/o: record data inserted */ | ||
2790 | struct xfs_btree_cur **curp, /* output: new cursor replacing cur */ | ||
2791 | int *stat) /* success/failure */ | ||
2792 | { | ||
2793 | struct xfs_btree_block *block; /* btree block */ | ||
2794 | struct xfs_buf *bp; /* buffer for block */ | ||
2795 | union xfs_btree_key key; /* btree key */ | ||
2796 | union xfs_btree_ptr nptr; /* new block ptr */ | ||
2797 | struct xfs_btree_cur *ncur; /* new btree cursor */ | ||
2798 | union xfs_btree_rec nrec; /* new record count */ | ||
2799 | int optr; /* old key/record index */ | ||
2800 | int ptr; /* key/record index */ | ||
2801 | int numrecs;/* number of records */ | ||
2802 | int error; /* error return value */ | ||
2803 | #ifdef DEBUG | ||
2804 | int i; | ||
2805 | #endif | ||
2806 | |||
2807 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); | ||
2808 | XFS_BTREE_TRACE_ARGIPR(cur, level, *ptrp, recp); | ||
2809 | |||
2810 | ncur = NULL; | ||
2811 | |||
2812 | /* | ||
2813 | * If we have an external root pointer, and we've made it to the | ||
2814 | * root level, allocate a new root block and we're done. | ||
2815 | */ | ||
2816 | if (!(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && | ||
2817 | (level >= cur->bc_nlevels)) { | ||
2818 | error = xfs_btree_new_root(cur, stat); | ||
2819 | xfs_btree_set_ptr_null(cur, ptrp); | ||
2820 | |||
2821 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | ||
2822 | return error; | ||
2823 | } | ||
2824 | |||
2825 | /* If we're off the left edge, return failure. */ | ||
2826 | ptr = cur->bc_ptrs[level]; | ||
2827 | if (ptr == 0) { | ||
2828 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | ||
2829 | *stat = 0; | ||
2830 | return 0; | ||
2831 | } | ||
2832 | |||
2833 | /* Make a key out of the record data to be inserted, and save it. */ | ||
2834 | cur->bc_ops->init_key_from_rec(&key, recp); | ||
2835 | |||
2836 | optr = ptr; | ||
2837 | |||
2838 | XFS_BTREE_STATS_INC(cur, insrec); | ||
2839 | |||
2840 | /* Get pointers to the btree buffer and block. */ | ||
2841 | block = xfs_btree_get_block(cur, level, &bp); | ||
2842 | numrecs = xfs_btree_get_numrecs(block); | ||
2843 | |||
2844 | #ifdef DEBUG | ||
2845 | error = xfs_btree_check_block(cur, block, level, bp); | ||
2846 | if (error) | ||
2847 | goto error0; | ||
2848 | |||
2849 | /* Check that the new entry is being inserted in the right place. */ | ||
2850 | if (ptr <= numrecs) { | ||
2851 | if (level == 0) { | ||
2852 | xfs_btree_check_rec(cur->bc_btnum, recp, | ||
2853 | xfs_btree_rec_addr(cur, ptr, block)); | ||
2854 | } else { | ||
2855 | xfs_btree_check_key(cur->bc_btnum, &key, | ||
2856 | xfs_btree_key_addr(cur, ptr, block)); | ||
2857 | } | ||
2858 | } | ||
2859 | #endif | ||
2860 | |||
2861 | /* | ||
2862 | * If the block is full, we can't insert the new entry until we | ||
2863 | * make the block un-full. | ||
2864 | */ | ||
2865 | xfs_btree_set_ptr_null(cur, &nptr); | ||
2866 | if (numrecs == cur->bc_ops->get_maxrecs(cur, level)) { | ||
2867 | error = xfs_btree_make_block_unfull(cur, level, numrecs, | ||
2868 | &optr, &ptr, &nptr, &ncur, &nrec, stat); | ||
2869 | if (error || *stat == 0) | ||
2870 | goto error0; | ||
2871 | } | ||
2872 | |||
2873 | /* | ||
2874 | * The current block may have changed if the block was | ||
2875 | * previously full and we have just made space in it. | ||
2876 | */ | ||
2877 | block = xfs_btree_get_block(cur, level, &bp); | ||
2878 | numrecs = xfs_btree_get_numrecs(block); | ||
2879 | |||
2880 | #ifdef DEBUG | ||
2881 | error = xfs_btree_check_block(cur, block, level, bp); | ||
2882 | if (error) | ||
2883 | return error; | ||
2884 | #endif | ||
2885 | |||
2886 | /* | ||
2887 | * At this point we know there's room for our new entry in the block | ||
2888 | * we're pointing at. | ||
2889 | */ | ||
2890 | XFS_BTREE_STATS_ADD(cur, moves, numrecs - ptr + 1); | ||
2891 | |||
2892 | if (level > 0) { | ||
2893 | /* It's a nonleaf. make a hole in the keys and ptrs */ | ||
2894 | union xfs_btree_key *kp; | ||
2895 | union xfs_btree_ptr *pp; | ||
2896 | |||
2897 | kp = xfs_btree_key_addr(cur, ptr, block); | ||
2898 | pp = xfs_btree_ptr_addr(cur, ptr, block); | ||
2899 | |||
2900 | #ifdef DEBUG | ||
2901 | for (i = numrecs - ptr; i >= 0; i--) { | ||
2902 | error = xfs_btree_check_ptr(cur, pp, i, level); | ||
2903 | if (error) | ||
2904 | return error; | ||
2905 | } | ||
2906 | #endif | ||
2907 | |||
2908 | xfs_btree_shift_keys(cur, kp, 1, numrecs - ptr + 1); | ||
2909 | xfs_btree_shift_ptrs(cur, pp, 1, numrecs - ptr + 1); | ||
2910 | |||
2911 | #ifdef DEBUG | ||
2912 | error = xfs_btree_check_ptr(cur, ptrp, 0, level); | ||
2913 | if (error) | ||
2914 | goto error0; | ||
2915 | #endif | ||
2916 | |||
2917 | /* Now put the new data in, bump numrecs and log it. */ | ||
2918 | xfs_btree_copy_keys(cur, kp, &key, 1); | ||
2919 | xfs_btree_copy_ptrs(cur, pp, ptrp, 1); | ||
2920 | numrecs++; | ||
2921 | xfs_btree_set_numrecs(block, numrecs); | ||
2922 | xfs_btree_log_ptrs(cur, bp, ptr, numrecs); | ||
2923 | xfs_btree_log_keys(cur, bp, ptr, numrecs); | ||
2924 | #ifdef DEBUG | ||
2925 | if (ptr < numrecs) { | ||
2926 | xfs_btree_check_key(cur->bc_btnum, kp, | ||
2927 | xfs_btree_key_addr(cur, ptr + 1, block)); | ||
2928 | } | ||
2929 | #endif | ||
2930 | } else { | ||
2931 | /* It's a leaf. make a hole in the records */ | ||
2932 | union xfs_btree_rec *rp; | ||
2933 | |||
2934 | rp = xfs_btree_rec_addr(cur, ptr, block); | ||
2935 | |||
2936 | xfs_btree_shift_recs(cur, rp, 1, numrecs - ptr + 1); | ||
2937 | |||
2938 | /* Now put the new data in, bump numrecs and log it. */ | ||
2939 | xfs_btree_copy_recs(cur, rp, recp, 1); | ||
2940 | xfs_btree_set_numrecs(block, ++numrecs); | ||
2941 | xfs_btree_log_recs(cur, bp, ptr, numrecs); | ||
2942 | #ifdef DEBUG | ||
2943 | if (ptr < numrecs) { | ||
2944 | xfs_btree_check_rec(cur->bc_btnum, rp, | ||
2945 | xfs_btree_rec_addr(cur, ptr + 1, block)); | ||
2946 | } | ||
2947 | #endif | ||
2948 | } | ||
2949 | |||
2950 | /* Log the new number of records in the btree header. */ | ||
2951 | xfs_btree_log_block(cur, bp, XFS_BB_NUMRECS); | ||
2952 | |||
2953 | /* If we inserted at the start of a block, update the parents' keys. */ | ||
2954 | if (optr == 1) { | ||
2955 | error = xfs_btree_updkey(cur, &key, level + 1); | ||
2956 | if (error) | ||
2957 | goto error0; | ||
2958 | } | ||
2959 | |||
2960 | /* | ||
2961 | * If we are tracking the last record in the tree and | ||
2962 | * we are at the far right edge of the tree, update it. | ||
2963 | */ | ||
2964 | if (xfs_btree_is_lastrec(cur, block, level)) { | ||
2965 | cur->bc_ops->update_lastrec(cur, block, recp, | ||
2966 | ptr, LASTREC_INSREC); | ||
2967 | } | ||
2968 | |||
2969 | /* | ||
2970 | * Return the new block number, if any. | ||
2971 | * If there is one, give back a record value and a cursor too. | ||
2972 | */ | ||
2973 | *ptrp = nptr; | ||
2974 | if (!xfs_btree_ptr_is_null(cur, &nptr)) { | ||
2975 | *recp = nrec; | ||
2976 | *curp = ncur; | ||
2977 | } | ||
2978 | |||
2979 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | ||
2980 | *stat = 1; | ||
2981 | return 0; | ||
2982 | |||
2983 | error0: | ||
2984 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); | ||
2985 | return error; | ||
2986 | } | ||
2987 | |||
2988 | /* | ||
2989 | * Insert the record at the point referenced by cur. | ||
2990 | * | ||
2991 | * A multi-level split of the tree on insert will invalidate the original | ||
2992 | * cursor. All callers of this function should assume that the cursor is | ||
2993 | * no longer valid and revalidate it. | ||
2994 | */ | ||
2995 | int | ||
2996 | xfs_btree_insert( | ||
2997 | struct xfs_btree_cur *cur, | ||
2998 | int *stat) | ||
2999 | { | ||
3000 | int error; /* error return value */ | ||
3001 | int i; /* result value, 0 for failure */ | ||
3002 | int level; /* current level number in btree */ | ||
3003 | union xfs_btree_ptr nptr; /* new block number (split result) */ | ||
3004 | struct xfs_btree_cur *ncur; /* new cursor (split result) */ | ||
3005 | struct xfs_btree_cur *pcur; /* previous level's cursor */ | ||
3006 | union xfs_btree_rec rec; /* record to insert */ | ||
3007 | |||
3008 | level = 0; | ||
3009 | ncur = NULL; | ||
3010 | pcur = cur; | ||
3011 | |||
3012 | xfs_btree_set_ptr_null(cur, &nptr); | ||
3013 | cur->bc_ops->init_rec_from_cur(cur, &rec); | ||
3014 | |||
3015 | /* | ||
3016 | * Loop going up the tree, starting at the leaf level. | ||
3017 | * Stop when we don't get a split block, that must mean that | ||
3018 | * the insert is finished with this level. | ||
3019 | */ | ||
3020 | do { | ||
3021 | /* | ||
3022 | * Insert nrec/nptr into this level of the tree. | ||
3023 | * Note if we fail, nptr will be null. | ||
3024 | */ | ||
3025 | error = xfs_btree_insrec(pcur, level, &nptr, &rec, &ncur, &i); | ||
3026 | if (error) { | ||
3027 | if (pcur != cur) | ||
3028 | xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); | ||
3029 | goto error0; | ||
3030 | } | ||
3031 | |||
3032 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
3033 | level++; | ||
3034 | |||
3035 | /* | ||
3036 | * See if the cursor we just used is trash. | ||
3037 | * Can't trash the caller's cursor, but otherwise we should | ||
3038 | * if ncur is a new cursor or we're about to be done. | ||
3039 | */ | ||
3040 | if (pcur != cur && | ||
3041 | (ncur || xfs_btree_ptr_is_null(cur, &nptr))) { | ||
3042 | /* Save the state from the cursor before we trash it */ | ||
3043 | if (cur->bc_ops->update_cursor) | ||
3044 | cur->bc_ops->update_cursor(pcur, cur); | ||
3045 | cur->bc_nlevels = pcur->bc_nlevels; | ||
3046 | xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); | ||
3047 | } | ||
3048 | /* If we got a new cursor, switch to it. */ | ||
3049 | if (ncur) { | ||
3050 | pcur = ncur; | ||
3051 | ncur = NULL; | ||
3052 | } | ||
3053 | } while (!xfs_btree_ptr_is_null(cur, &nptr)); | ||
3054 | |||
3055 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | ||
3056 | *stat = i; | ||
3057 | return 0; | ||
3058 | error0: | ||
3059 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); | ||
3060 | return error; | ||
3061 | } | ||
diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h index 21eec863f00f..6f03871f5995 100644 --- a/fs/xfs/xfs_btree.h +++ b/fs/xfs/xfs_btree.h | |||
@@ -186,6 +186,8 @@ struct xfs_btree_ops { | |||
186 | 186 | ||
187 | /* cursor operations */ | 187 | /* cursor operations */ |
188 | struct xfs_btree_cur *(*dup_cursor)(struct xfs_btree_cur *); | 188 | struct xfs_btree_cur *(*dup_cursor)(struct xfs_btree_cur *); |
189 | void (*update_cursor)(struct xfs_btree_cur *src, | ||
190 | struct xfs_btree_cur *dst); | ||
189 | 191 | ||
190 | /* update btree root pointer */ | 192 | /* update btree root pointer */ |
191 | void (*set_root)(struct xfs_btree_cur *cur, | 193 | void (*set_root)(struct xfs_btree_cur *cur, |
@@ -206,9 +208,16 @@ struct xfs_btree_ops { | |||
206 | /* records in block/level */ | 208 | /* records in block/level */ |
207 | int (*get_maxrecs)(struct xfs_btree_cur *cur, int level); | 209 | int (*get_maxrecs)(struct xfs_btree_cur *cur, int level); |
208 | 210 | ||
211 | /* records on disk. Matter for the root in inode case. */ | ||
212 | int (*get_dmaxrecs)(struct xfs_btree_cur *cur, int level); | ||
213 | |||
209 | /* init values of btree structures */ | 214 | /* init values of btree structures */ |
210 | void (*init_key_from_rec)(union xfs_btree_key *key, | 215 | void (*init_key_from_rec)(union xfs_btree_key *key, |
211 | union xfs_btree_rec *rec); | 216 | union xfs_btree_rec *rec); |
217 | void (*init_rec_from_key)(union xfs_btree_key *key, | ||
218 | union xfs_btree_rec *rec); | ||
219 | void (*init_rec_from_cur)(struct xfs_btree_cur *cur, | ||
220 | union xfs_btree_rec *rec); | ||
212 | void (*init_ptr_from_cur)(struct xfs_btree_cur *cur, | 221 | void (*init_ptr_from_cur)(struct xfs_btree_cur *cur, |
213 | union xfs_btree_ptr *ptr); | 222 | union xfs_btree_ptr *ptr); |
214 | 223 | ||
@@ -240,6 +249,7 @@ struct xfs_btree_ops { | |||
240 | * Reasons for the update_lastrec method to be called. | 249 | * Reasons for the update_lastrec method to be called. |
241 | */ | 250 | */ |
242 | #define LASTREC_UPDATE 0 | 251 | #define LASTREC_UPDATE 0 |
252 | #define LASTREC_INSREC 1 | ||
243 | 253 | ||
244 | 254 | ||
245 | /* | 255 | /* |
@@ -549,6 +559,7 @@ int xfs_btree_split(struct xfs_btree_cur *, int, union xfs_btree_ptr *, | |||
549 | union xfs_btree_key *, struct xfs_btree_cur **, int *); | 559 | union xfs_btree_key *, struct xfs_btree_cur **, int *); |
550 | int xfs_btree_new_root(struct xfs_btree_cur *, int *); | 560 | int xfs_btree_new_root(struct xfs_btree_cur *, int *); |
551 | int xfs_btree_new_iroot(struct xfs_btree_cur *, int *, int *); | 561 | int xfs_btree_new_iroot(struct xfs_btree_cur *, int *, int *); |
562 | int xfs_btree_insert(struct xfs_btree_cur *, int *); | ||
552 | 563 | ||
553 | /* | 564 | /* |
554 | * Helpers. | 565 | * Helpers. |
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index 138651afd44f..b68e73bb17cd 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c | |||
@@ -418,7 +418,7 @@ xfs_ialloc_ag_alloc( | |||
418 | return error; | 418 | return error; |
419 | } | 419 | } |
420 | ASSERT(i == 0); | 420 | ASSERT(i == 0); |
421 | if ((error = xfs_inobt_insert(cur, &i))) { | 421 | if ((error = xfs_btree_insert(cur, &i))) { |
422 | xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); | 422 | xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); |
423 | return error; | 423 | return error; |
424 | } | 424 | } |
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 | ||
diff --git a/fs/xfs/xfs_ialloc_btree.h b/fs/xfs/xfs_ialloc_btree.h index 7f77549e82a6..c9cbc4f2168d 100644 --- a/fs/xfs/xfs_ialloc_btree.h +++ b/fs/xfs/xfs_ialloc_btree.h | |||
@@ -129,12 +129,6 @@ extern int xfs_inobt_delete(struct xfs_btree_cur *cur, int *stat); | |||
129 | extern int xfs_inobt_get_rec(struct xfs_btree_cur *cur, xfs_agino_t *ino, | 129 | extern int xfs_inobt_get_rec(struct xfs_btree_cur *cur, xfs_agino_t *ino, |
130 | __int32_t *fcnt, xfs_inofree_t *free, int *stat); | 130 | __int32_t *fcnt, xfs_inofree_t *free, int *stat); |
131 | 131 | ||
132 | /* | ||
133 | * Insert the current record at the point referenced by cur. | ||
134 | * The cursor may be inconsistent on return if splits have been done. | ||
135 | */ | ||
136 | extern int xfs_inobt_insert(struct xfs_btree_cur *cur, int *stat); | ||
137 | |||
138 | 132 | ||
139 | extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *, | 133 | extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *, |
140 | struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t); | 134 | struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t); |