diff options
Diffstat (limited to 'fs/xfs')
-rw-r--r-- | fs/xfs/xfs_ialloc.c | 291 |
1 files changed, 138 insertions, 153 deletions
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index 18bf6eece54d..7679c1633053 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c | |||
@@ -589,6 +589,37 @@ nextag: | |||
589 | } | 589 | } |
590 | } | 590 | } |
591 | 591 | ||
592 | /* | ||
593 | * Try to retrieve the next record to the left/right from the current one. | ||
594 | */ | ||
595 | STATIC int | ||
596 | xfs_ialloc_next_rec( | ||
597 | struct xfs_btree_cur *cur, | ||
598 | xfs_inobt_rec_incore_t *rec, | ||
599 | int *done, | ||
600 | int left) | ||
601 | { | ||
602 | int error; | ||
603 | int i; | ||
604 | |||
605 | if (left) | ||
606 | error = xfs_btree_decrement(cur, 0, &i); | ||
607 | else | ||
608 | error = xfs_btree_increment(cur, 0, &i); | ||
609 | |||
610 | if (error) | ||
611 | return error; | ||
612 | *done = !i; | ||
613 | if (i) { | ||
614 | error = xfs_inobt_get_rec(cur, rec, &i); | ||
615 | if (error) | ||
616 | return error; | ||
617 | XFS_WANT_CORRUPTED_RETURN(i == 1); | ||
618 | } | ||
619 | |||
620 | return 0; | ||
621 | } | ||
622 | |||
592 | 623 | ||
593 | /* | 624 | /* |
594 | * Visible inode allocation functions. | 625 | * Visible inode allocation functions. |
@@ -644,8 +675,8 @@ xfs_dialloc( | |||
644 | int j; /* result code */ | 675 | int j; /* result code */ |
645 | xfs_mount_t *mp; /* file system mount structure */ | 676 | xfs_mount_t *mp; /* file system mount structure */ |
646 | int offset; /* index of inode in chunk */ | 677 | int offset; /* index of inode in chunk */ |
647 | xfs_agino_t pagino; /* parent's a.g. relative inode # */ | 678 | xfs_agino_t pagino; /* parent's AG relative inode # */ |
648 | xfs_agnumber_t pagno; /* parent's allocation group number */ | 679 | xfs_agnumber_t pagno; /* parent's AG number */ |
649 | xfs_inobt_rec_incore_t rec; /* inode allocation record */ | 680 | xfs_inobt_rec_incore_t rec; /* inode allocation record */ |
650 | xfs_agnumber_t tagno; /* testing allocation group number */ | 681 | xfs_agnumber_t tagno; /* testing allocation group number */ |
651 | xfs_btree_cur_t *tcur; /* temp cursor */ | 682 | xfs_btree_cur_t *tcur; /* temp cursor */ |
@@ -781,186 +812,140 @@ nextag: | |||
781 | goto error0; | 812 | goto error0; |
782 | 813 | ||
783 | /* | 814 | /* |
784 | * If in the same a.g. as the parent, try to get near the parent. | 815 | * If in the same AG as the parent, try to get near the parent. |
785 | */ | 816 | */ |
786 | if (pagno == agno) { | 817 | if (pagno == agno) { |
787 | if ((error = xfs_inobt_lookup_le(cur, pagino, 0, 0, &i))) | 818 | int doneleft; /* done, to the left */ |
819 | int doneright; /* done, to the right */ | ||
820 | |||
821 | error = xfs_inobt_lookup_le(cur, pagino, 0, 0, &i); | ||
822 | if (error) | ||
823 | goto error0; | ||
824 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
825 | |||
826 | error = xfs_inobt_get_rec(cur, &rec, &j); | ||
827 | if (error) | ||
788 | goto error0; | 828 | goto error0; |
789 | if (i != 0 && | 829 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
790 | (error = xfs_inobt_get_rec(cur, &rec, &j)) == 0 && | 830 | |
791 | j == 1 && | 831 | if (rec.ir_freecount > 0) { |
792 | rec.ir_freecount > 0) { | ||
793 | /* | 832 | /* |
794 | * Found a free inode in the same chunk | 833 | * Found a free inode in the same chunk |
795 | * as parent, done. | 834 | * as the parent, done. |
796 | */ | 835 | */ |
836 | goto alloc_inode; | ||
797 | } | 837 | } |
838 | |||
839 | |||
798 | /* | 840 | /* |
799 | * In the same a.g. as parent, but parent's chunk is full. | 841 | * In the same AG as parent, but parent's chunk is full. |
800 | */ | 842 | */ |
801 | else { | ||
802 | int doneleft; /* done, to the left */ | ||
803 | int doneright; /* done, to the right */ | ||
804 | 843 | ||
805 | if (error) | 844 | /* duplicate the cursor, search left & right simultaneously */ |
806 | goto error0; | 845 | error = xfs_btree_dup_cursor(cur, &tcur); |
807 | ASSERT(i == 1); | 846 | if (error) |
808 | ASSERT(j == 1); | 847 | goto error0; |
809 | /* | 848 | |
810 | * Duplicate the cursor, search left & right | 849 | /* search left with tcur, back up 1 record */ |
811 | * simultaneously. | 850 | error = xfs_ialloc_next_rec(tcur, &trec, &doneleft, 1); |
812 | */ | 851 | if (error) |
813 | if ((error = xfs_btree_dup_cursor(cur, &tcur))) | 852 | goto error1; |
814 | goto error0; | 853 | |
815 | /* | 854 | /* search right with cur, go forward 1 record. */ |
816 | * Search left with tcur, back up 1 record. | 855 | error = xfs_ialloc_next_rec(cur, &rec, &doneright, 0); |
817 | */ | 856 | if (error) |
818 | if ((error = xfs_btree_decrement(tcur, 0, &i))) | 857 | goto error1; |
819 | goto error1; | 858 | |
820 | doneleft = !i; | 859 | /* |
821 | if (!doneleft) { | 860 | * Loop until we find an inode chunk with a free inode. |
822 | error = xfs_inobt_get_rec(tcur, &trec, &i); | 861 | */ |
823 | if (error) | 862 | while (!doneleft || !doneright) { |
824 | goto error1; | 863 | int useleft; /* using left inode chunk this time */ |
825 | XFS_WANT_CORRUPTED_GOTO(i == 1, error1); | 864 | |
865 | /* figure out the closer block if both are valid. */ | ||
866 | if (!doneleft && !doneright) { | ||
867 | useleft = pagino - | ||
868 | (trec.ir_startino + XFS_INODES_PER_CHUNK - 1) < | ||
869 | rec.ir_startino - pagino; | ||
870 | } else { | ||
871 | useleft = !doneleft; | ||
826 | } | 872 | } |
827 | /* | 873 | |
828 | * Search right with cur, go forward 1 record. | 874 | /* free inodes to the left? */ |
829 | */ | 875 | if (useleft && trec.ir_freecount) { |
830 | if ((error = xfs_btree_increment(cur, 0, &i))) | 876 | rec = trec; |
831 | goto error1; | 877 | xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); |
832 | doneright = !i; | 878 | cur = tcur; |
833 | if (!doneright) { | 879 | goto alloc_inode; |
834 | error = xfs_inobt_get_rec(cur, &rec, &i); | ||
835 | if (error) | ||
836 | goto error1; | ||
837 | XFS_WANT_CORRUPTED_GOTO(i == 1, error1); | ||
838 | } | 880 | } |
839 | /* | ||
840 | * Loop until we find the closest inode chunk | ||
841 | * with a free one. | ||
842 | */ | ||
843 | while (!doneleft || !doneright) { | ||
844 | int useleft; /* using left inode | ||
845 | chunk this time */ | ||
846 | 881 | ||
847 | /* | 882 | /* free inodes to the right? */ |
848 | * Figure out which block is closer, | 883 | if (!useleft && rec.ir_freecount) { |
849 | * if both are valid. | 884 | xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); |
850 | */ | 885 | goto alloc_inode; |
851 | if (!doneleft && !doneright) | ||
852 | useleft = | ||
853 | pagino - | ||
854 | (trec.ir_startino + | ||
855 | XFS_INODES_PER_CHUNK - 1) < | ||
856 | rec.ir_startino - pagino; | ||
857 | else | ||
858 | useleft = !doneleft; | ||
859 | /* | ||
860 | * If checking the left, does it have | ||
861 | * free inodes? | ||
862 | */ | ||
863 | if (useleft && trec.ir_freecount) { | ||
864 | /* | ||
865 | * Yes, set it up as the chunk to use. | ||
866 | */ | ||
867 | rec = trec; | ||
868 | xfs_btree_del_cursor(cur, | ||
869 | XFS_BTREE_NOERROR); | ||
870 | cur = tcur; | ||
871 | break; | ||
872 | } | ||
873 | /* | ||
874 | * If checking the right, does it have | ||
875 | * free inodes? | ||
876 | */ | ||
877 | if (!useleft && rec.ir_freecount) { | ||
878 | /* | ||
879 | * Yes, it's already set up. | ||
880 | */ | ||
881 | xfs_btree_del_cursor(tcur, | ||
882 | XFS_BTREE_NOERROR); | ||
883 | break; | ||
884 | } | ||
885 | /* | ||
886 | * If used the left, get another one | ||
887 | * further left. | ||
888 | */ | ||
889 | if (useleft) { | ||
890 | if ((error = xfs_btree_decrement(tcur, 0, | ||
891 | &i))) | ||
892 | goto error1; | ||
893 | doneleft = !i; | ||
894 | if (!doneleft) { | ||
895 | error = xfs_inobt_get_rec( | ||
896 | tcur, &trec, &i); | ||
897 | if (error) | ||
898 | goto error1; | ||
899 | XFS_WANT_CORRUPTED_GOTO(i == 1, | ||
900 | error1); | ||
901 | } | ||
902 | } | ||
903 | /* | ||
904 | * If used the right, get another one | ||
905 | * further right. | ||
906 | */ | ||
907 | else { | ||
908 | if ((error = xfs_btree_increment(cur, 0, | ||
909 | &i))) | ||
910 | goto error1; | ||
911 | doneright = !i; | ||
912 | if (!doneright) { | ||
913 | error = xfs_inobt_get_rec( | ||
914 | cur, &rec, &i); | ||
915 | if (error) | ||
916 | goto error1; | ||
917 | XFS_WANT_CORRUPTED_GOTO(i == 1, | ||
918 | error1); | ||
919 | } | ||
920 | } | ||
921 | } | 886 | } |
922 | ASSERT(!doneleft || !doneright); | 887 | |
888 | /* get next record to check */ | ||
889 | if (useleft) { | ||
890 | error = xfs_ialloc_next_rec(tcur, &trec, | ||
891 | &doneleft, 1); | ||
892 | } else { | ||
893 | error = xfs_ialloc_next_rec(cur, &rec, | ||
894 | &doneright, 0); | ||
895 | } | ||
896 | if (error) | ||
897 | goto error1; | ||
923 | } | 898 | } |
899 | ASSERT(!doneleft || !doneright); | ||
924 | } | 900 | } |
901 | |||
925 | /* | 902 | /* |
926 | * In a different a.g. from the parent. | 903 | * In a different AG from the parent. |
927 | * See if the most recently allocated block has any free. | 904 | * See if the most recently allocated block has any free. |
928 | */ | 905 | */ |
929 | else if (be32_to_cpu(agi->agi_newino) != NULLAGINO) { | 906 | else if (be32_to_cpu(agi->agi_newino) != NULLAGINO) { |
930 | if ((error = xfs_inobt_lookup_eq(cur, | 907 | error = xfs_inobt_lookup_eq(cur, be32_to_cpu(agi->agi_newino), |
931 | be32_to_cpu(agi->agi_newino), 0, 0, &i))) | 908 | 0, 0, &i); |
909 | if (error) | ||
932 | goto error0; | 910 | goto error0; |
933 | if (i == 1 && | 911 | |
934 | (error = xfs_inobt_get_rec(cur, &rec, &j)) == 0 && | 912 | if (i == 1) { |
935 | j == 1 && | 913 | error = xfs_inobt_get_rec(cur, &rec, &j); |
936 | rec.ir_freecount > 0) { | 914 | if (error) |
937 | /* | 915 | goto error0; |
938 | * The last chunk allocated in the group still has | 916 | |
939 | * a free inode. | 917 | if (j == 1 && rec.ir_freecount > 0) { |
940 | */ | 918 | /* |
919 | * The last chunk allocated in the group | ||
920 | * still has a free inode. | ||
921 | */ | ||
922 | goto alloc_inode; | ||
923 | } | ||
941 | } | 924 | } |
925 | |||
942 | /* | 926 | /* |
943 | * None left in the last group, search the whole a.g. | 927 | * None left in the last group, search the whole AG |
944 | */ | 928 | */ |
945 | else { | 929 | error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i); |
930 | if (error) | ||
931 | goto error0; | ||
932 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
933 | |||
934 | for (;;) { | ||
935 | error = xfs_inobt_get_rec(cur, &rec, &i); | ||
946 | if (error) | 936 | if (error) |
947 | goto error0; | 937 | goto error0; |
948 | if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) | 938 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
939 | if (rec.ir_freecount > 0) | ||
940 | break; | ||
941 | error = xfs_btree_increment(cur, 0, &i); | ||
942 | if (error) | ||
949 | goto error0; | 943 | goto error0; |
950 | ASSERT(i == 1); | 944 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
951 | for (;;) { | ||
952 | error = xfs_inobt_get_rec(cur, &rec, &i); | ||
953 | if (error) | ||
954 | goto error0; | ||
955 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
956 | if (rec.ir_freecount > 0) | ||
957 | break; | ||
958 | if ((error = xfs_btree_increment(cur, 0, &i))) | ||
959 | goto error0; | ||
960 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
961 | } | ||
962 | } | 945 | } |
963 | } | 946 | } |
947 | |||
948 | alloc_inode: | ||
964 | offset = xfs_ialloc_find_free(&rec.ir_free); | 949 | offset = xfs_ialloc_find_free(&rec.ir_free); |
965 | ASSERT(offset >= 0); | 950 | ASSERT(offset >= 0); |
966 | ASSERT(offset < XFS_INODES_PER_CHUNK); | 951 | ASSERT(offset < XFS_INODES_PER_CHUNK); |