diff options
author | Christoph Hellwig <hch@infradead.org> | 2010-12-10 10:04:11 -0500 |
---|---|---|
committer | Alex Elder <aelder@sgi.com> | 2010-12-16 17:06:15 -0500 |
commit | 489a150f6454e2cd93d9e0ee6d7c5a361844f62a (patch) | |
tree | 18deded59797caaec9f01ef5a3eb66a765bef29f /fs/xfs/xfs_alloc.c | |
parent | 9f9baab38dacd11fe6095a1e59f3783a305f7020 (diff) |
xfs: factor duplicate code in xfs_alloc_ag_vextent_near into a helper
Add a new xfs_alloc_find_best_extent that does a forward/backward
search in the allocation btree. That code previously was existed
two times in xfs_alloc_ag_vextent_near, once for each search
direction.
Based on an earlier patch from Dave Chinner.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Alex Elder <aelder@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_alloc.c')
-rw-r--r-- | fs/xfs/xfs_alloc.c | 293 |
1 files changed, 113 insertions, 180 deletions
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index d9133f10d2b1..fa8723f5870a 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c | |||
@@ -665,6 +665,95 @@ error0: | |||
665 | } | 665 | } |
666 | 666 | ||
667 | /* | 667 | /* |
668 | * Search the btree in a given direction via the search cursor and compare | ||
669 | * the records found against the good extent we've already found. | ||
670 | */ | ||
671 | STATIC int | ||
672 | xfs_alloc_find_best_extent( | ||
673 | struct xfs_alloc_arg *args, /* allocation argument structure */ | ||
674 | struct xfs_btree_cur **gcur, /* good cursor */ | ||
675 | struct xfs_btree_cur **scur, /* searching cursor */ | ||
676 | xfs_agblock_t gdiff, /* difference for search comparison */ | ||
677 | xfs_agblock_t *sbno, /* extent found by search */ | ||
678 | xfs_extlen_t *slen, | ||
679 | xfs_extlen_t *slena, /* aligned length */ | ||
680 | int dir) /* 0 = search right, 1 = search left */ | ||
681 | { | ||
682 | xfs_agblock_t bno; | ||
683 | xfs_agblock_t new; | ||
684 | xfs_agblock_t sdiff; | ||
685 | int error; | ||
686 | int i; | ||
687 | |||
688 | /* The good extent is perfect, no need to search. */ | ||
689 | if (!gdiff) | ||
690 | goto out_use_good; | ||
691 | |||
692 | /* | ||
693 | * Look until we find a better one, run out of space or run off the end. | ||
694 | */ | ||
695 | do { | ||
696 | error = xfs_alloc_get_rec(*scur, sbno, slen, &i); | ||
697 | if (error) | ||
698 | goto error0; | ||
699 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
700 | xfs_alloc_compute_aligned(*sbno, *slen, args->alignment, | ||
701 | args->minlen, &bno, slena); | ||
702 | |||
703 | /* | ||
704 | * The good extent is closer than this one. | ||
705 | */ | ||
706 | if (!dir) { | ||
707 | if (bno >= args->agbno + gdiff) | ||
708 | goto out_use_good; | ||
709 | } else { | ||
710 | if (bno <= args->agbno - gdiff) | ||
711 | goto out_use_good; | ||
712 | } | ||
713 | |||
714 | /* | ||
715 | * Same distance, compare length and pick the best. | ||
716 | */ | ||
717 | if (*slena >= args->minlen) { | ||
718 | args->len = XFS_EXTLEN_MIN(*slena, args->maxlen); | ||
719 | xfs_alloc_fix_len(args); | ||
720 | |||
721 | sdiff = xfs_alloc_compute_diff(args->agbno, args->len, | ||
722 | args->alignment, *sbno, | ||
723 | *slen, &new); | ||
724 | |||
725 | /* | ||
726 | * Choose closer size and invalidate other cursor. | ||
727 | */ | ||
728 | if (sdiff < gdiff) | ||
729 | goto out_use_search; | ||
730 | goto out_use_good; | ||
731 | } | ||
732 | |||
733 | if (!dir) | ||
734 | error = xfs_btree_increment(*scur, 0, &i); | ||
735 | else | ||
736 | error = xfs_btree_decrement(*scur, 0, &i); | ||
737 | if (error) | ||
738 | goto error0; | ||
739 | } while (i); | ||
740 | |||
741 | out_use_good: | ||
742 | xfs_btree_del_cursor(*scur, XFS_BTREE_NOERROR); | ||
743 | *scur = NULL; | ||
744 | return 0; | ||
745 | |||
746 | out_use_search: | ||
747 | xfs_btree_del_cursor(*gcur, XFS_BTREE_NOERROR); | ||
748 | *gcur = NULL; | ||
749 | return 0; | ||
750 | |||
751 | error0: | ||
752 | /* caller invalidates cursors */ | ||
753 | return error; | ||
754 | } | ||
755 | |||
756 | /* | ||
668 | * Allocate a variable extent near bno in the allocation group agno. | 757 | * Allocate a variable extent near bno in the allocation group agno. |
669 | * Extent's length (returned in len) will be between minlen and maxlen, | 758 | * Extent's length (returned in len) will be between minlen and maxlen, |
670 | * and of the form k * prod + mod unless there's nothing that large. | 759 | * and of the form k * prod + mod unless there's nothing that large. |
@@ -931,203 +1020,45 @@ xfs_alloc_ag_vextent_near( | |||
931 | } | 1020 | } |
932 | } | 1021 | } |
933 | } while (bno_cur_lt || bno_cur_gt); | 1022 | } while (bno_cur_lt || bno_cur_gt); |
1023 | |||
934 | /* | 1024 | /* |
935 | * Got both cursors still active, need to find better entry. | 1025 | * Got both cursors still active, need to find better entry. |
936 | */ | 1026 | */ |
937 | if (bno_cur_lt && bno_cur_gt) { | 1027 | if (bno_cur_lt && bno_cur_gt) { |
938 | /* | ||
939 | * Left side is long enough, look for a right side entry. | ||
940 | */ | ||
941 | if (ltlena >= args->minlen) { | 1028 | if (ltlena >= args->minlen) { |
942 | /* | 1029 | /* |
943 | * Fix up the length. | 1030 | * Left side is good, look for a right side entry. |
944 | */ | 1031 | */ |
945 | args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); | 1032 | args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); |
946 | xfs_alloc_fix_len(args); | 1033 | xfs_alloc_fix_len(args); |
947 | rlen = args->len; | 1034 | ltdiff = xfs_alloc_compute_diff(args->agbno, args->len, |
948 | ltdiff = xfs_alloc_compute_diff(args->agbno, rlen, | ||
949 | args->alignment, ltbno, ltlen, <new); | 1035 | args->alignment, ltbno, ltlen, <new); |
1036 | |||
1037 | error = xfs_alloc_find_best_extent(args, | ||
1038 | &bno_cur_lt, &bno_cur_gt, | ||
1039 | ltdiff, >bno, >len, >lena, | ||
1040 | 0 /* search right */); | ||
1041 | } else { | ||
1042 | ASSERT(gtlena >= args->minlen); | ||
1043 | |||
950 | /* | 1044 | /* |
951 | * Not perfect. | 1045 | * Right side is good, look for a left side entry. |
952 | */ | ||
953 | if (ltdiff) { | ||
954 | /* | ||
955 | * Look until we find a better one, run out of | ||
956 | * space, or run off the end. | ||
957 | */ | ||
958 | while (bno_cur_lt && bno_cur_gt) { | ||
959 | if ((error = xfs_alloc_get_rec( | ||
960 | bno_cur_gt, >bno, | ||
961 | >len, &i))) | ||
962 | goto error0; | ||
963 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
964 | xfs_alloc_compute_aligned(gtbno, gtlen, | ||
965 | args->alignment, args->minlen, | ||
966 | >bnoa, >lena); | ||
967 | /* | ||
968 | * The left one is clearly better. | ||
969 | */ | ||
970 | if (gtbnoa >= args->agbno + ltdiff) { | ||
971 | xfs_btree_del_cursor( | ||
972 | bno_cur_gt, | ||
973 | XFS_BTREE_NOERROR); | ||
974 | bno_cur_gt = NULL; | ||
975 | break; | ||
976 | } | ||
977 | /* | ||
978 | * If we reach a big enough entry, | ||
979 | * compare the two and pick the best. | ||
980 | */ | ||
981 | if (gtlena >= args->minlen) { | ||
982 | args->len = | ||
983 | XFS_EXTLEN_MIN(gtlena, | ||
984 | args->maxlen); | ||
985 | xfs_alloc_fix_len(args); | ||
986 | rlen = args->len; | ||
987 | gtdiff = xfs_alloc_compute_diff( | ||
988 | args->agbno, rlen, | ||
989 | args->alignment, | ||
990 | gtbno, gtlen, >new); | ||
991 | /* | ||
992 | * Right side is better. | ||
993 | */ | ||
994 | if (gtdiff < ltdiff) { | ||
995 | xfs_btree_del_cursor( | ||
996 | bno_cur_lt, | ||
997 | XFS_BTREE_NOERROR); | ||
998 | bno_cur_lt = NULL; | ||
999 | } | ||
1000 | /* | ||
1001 | * Left side is better. | ||
1002 | */ | ||
1003 | else { | ||
1004 | xfs_btree_del_cursor( | ||
1005 | bno_cur_gt, | ||
1006 | XFS_BTREE_NOERROR); | ||
1007 | bno_cur_gt = NULL; | ||
1008 | } | ||
1009 | break; | ||
1010 | } | ||
1011 | /* | ||
1012 | * Fell off the right end. | ||
1013 | */ | ||
1014 | if ((error = xfs_btree_increment( | ||
1015 | bno_cur_gt, 0, &i))) | ||
1016 | goto error0; | ||
1017 | if (!i) { | ||
1018 | xfs_btree_del_cursor( | ||
1019 | bno_cur_gt, | ||
1020 | XFS_BTREE_NOERROR); | ||
1021 | bno_cur_gt = NULL; | ||
1022 | break; | ||
1023 | } | ||
1024 | } | ||
1025 | } | ||
1026 | /* | ||
1027 | * The left side is perfect, trash the right side. | ||
1028 | */ | ||
1029 | else { | ||
1030 | xfs_btree_del_cursor(bno_cur_gt, | ||
1031 | XFS_BTREE_NOERROR); | ||
1032 | bno_cur_gt = NULL; | ||
1033 | } | ||
1034 | } | ||
1035 | /* | ||
1036 | * It's the right side that was found first, look left. | ||
1037 | */ | ||
1038 | else { | ||
1039 | /* | ||
1040 | * Fix up the length. | ||
1041 | */ | 1046 | */ |
1042 | args->len = XFS_EXTLEN_MIN(gtlena, args->maxlen); | 1047 | args->len = XFS_EXTLEN_MIN(gtlena, args->maxlen); |
1043 | xfs_alloc_fix_len(args); | 1048 | xfs_alloc_fix_len(args); |
1044 | rlen = args->len; | 1049 | gtdiff = xfs_alloc_compute_diff(args->agbno, args->len, |
1045 | gtdiff = xfs_alloc_compute_diff(args->agbno, rlen, | ||
1046 | args->alignment, gtbno, gtlen, >new); | 1050 | args->alignment, gtbno, gtlen, >new); |
1047 | /* | 1051 | |
1048 | * Right side entry isn't perfect. | 1052 | error = xfs_alloc_find_best_extent(args, |
1049 | */ | 1053 | &bno_cur_gt, &bno_cur_lt, |
1050 | if (gtdiff) { | 1054 | gtdiff, <bno, <len, <lena, |
1051 | /* | 1055 | 1 /* search left */); |
1052 | * Look until we find a better one, run out of | ||
1053 | * space, or run off the end. | ||
1054 | */ | ||
1055 | while (bno_cur_lt && bno_cur_gt) { | ||
1056 | if ((error = xfs_alloc_get_rec( | ||
1057 | bno_cur_lt, <bno, | ||
1058 | <len, &i))) | ||
1059 | goto error0; | ||
1060 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
1061 | xfs_alloc_compute_aligned(ltbno, ltlen, | ||
1062 | args->alignment, args->minlen, | ||
1063 | <bnoa, <lena); | ||
1064 | /* | ||
1065 | * The right one is clearly better. | ||
1066 | */ | ||
1067 | if (ltbnoa <= args->agbno - gtdiff) { | ||
1068 | xfs_btree_del_cursor( | ||
1069 | bno_cur_lt, | ||
1070 | XFS_BTREE_NOERROR); | ||
1071 | bno_cur_lt = NULL; | ||
1072 | break; | ||
1073 | } | ||
1074 | /* | ||
1075 | * If we reach a big enough entry, | ||
1076 | * compare the two and pick the best. | ||
1077 | */ | ||
1078 | if (ltlena >= args->minlen) { | ||
1079 | args->len = XFS_EXTLEN_MIN( | ||
1080 | ltlena, args->maxlen); | ||
1081 | xfs_alloc_fix_len(args); | ||
1082 | rlen = args->len; | ||
1083 | ltdiff = xfs_alloc_compute_diff( | ||
1084 | args->agbno, rlen, | ||
1085 | args->alignment, | ||
1086 | ltbno, ltlen, <new); | ||
1087 | /* | ||
1088 | * Left side is better. | ||
1089 | */ | ||
1090 | if (ltdiff < gtdiff) { | ||
1091 | xfs_btree_del_cursor( | ||
1092 | bno_cur_gt, | ||
1093 | XFS_BTREE_NOERROR); | ||
1094 | bno_cur_gt = NULL; | ||
1095 | } | ||
1096 | /* | ||
1097 | * Right side is better. | ||
1098 | */ | ||
1099 | else { | ||
1100 | xfs_btree_del_cursor( | ||
1101 | bno_cur_lt, | ||
1102 | XFS_BTREE_NOERROR); | ||
1103 | bno_cur_lt = NULL; | ||
1104 | } | ||
1105 | break; | ||
1106 | } | ||
1107 | /* | ||
1108 | * Fell off the left end. | ||
1109 | */ | ||
1110 | if ((error = xfs_btree_decrement( | ||
1111 | bno_cur_lt, 0, &i))) | ||
1112 | goto error0; | ||
1113 | if (!i) { | ||
1114 | xfs_btree_del_cursor(bno_cur_lt, | ||
1115 | XFS_BTREE_NOERROR); | ||
1116 | bno_cur_lt = NULL; | ||
1117 | break; | ||
1118 | } | ||
1119 | } | ||
1120 | } | ||
1121 | /* | ||
1122 | * The right side is perfect, trash the left side. | ||
1123 | */ | ||
1124 | else { | ||
1125 | xfs_btree_del_cursor(bno_cur_lt, | ||
1126 | XFS_BTREE_NOERROR); | ||
1127 | bno_cur_lt = NULL; | ||
1128 | } | ||
1129 | } | 1056 | } |
1057 | |||
1058 | if (error) | ||
1059 | goto error0; | ||
1130 | } | 1060 | } |
1061 | |||
1131 | /* | 1062 | /* |
1132 | * If we couldn't get anything, give up. | 1063 | * If we couldn't get anything, give up. |
1133 | */ | 1064 | */ |
@@ -1136,6 +1067,7 @@ xfs_alloc_ag_vextent_near( | |||
1136 | args->agbno = NULLAGBLOCK; | 1067 | args->agbno = NULLAGBLOCK; |
1137 | return 0; | 1068 | return 0; |
1138 | } | 1069 | } |
1070 | |||
1139 | /* | 1071 | /* |
1140 | * At this point we have selected a freespace entry, either to the | 1072 | * At this point we have selected a freespace entry, either to the |
1141 | * left or to the right. If it's on the right, copy all the | 1073 | * left or to the right. If it's on the right, copy all the |
@@ -1152,6 +1084,7 @@ xfs_alloc_ag_vextent_near( | |||
1152 | j = 1; | 1084 | j = 1; |
1153 | } else | 1085 | } else |
1154 | j = 0; | 1086 | j = 0; |
1087 | |||
1155 | /* | 1088 | /* |
1156 | * Fix up the length and compute the useful address. | 1089 | * Fix up the length and compute the useful address. |
1157 | */ | 1090 | */ |