aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_ialloc.c291
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 */
595STATIC int
596xfs_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
948alloc_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);