diff options
Diffstat (limited to 'fs/xfs/xfs_alloc.c')
-rw-r--r-- | fs/xfs/xfs_alloc.c | 351 |
1 files changed, 145 insertions, 206 deletions
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 112abc439ca5..fa8723f5870a 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c | |||
@@ -577,61 +577,58 @@ xfs_alloc_ag_vextent_exact( | |||
577 | xfs_extlen_t rlen; /* length of returned extent */ | 577 | xfs_extlen_t rlen; /* length of returned extent */ |
578 | 578 | ||
579 | ASSERT(args->alignment == 1); | 579 | ASSERT(args->alignment == 1); |
580 | |||
580 | /* | 581 | /* |
581 | * Allocate/initialize a cursor for the by-number freespace btree. | 582 | * Allocate/initialize a cursor for the by-number freespace btree. |
582 | */ | 583 | */ |
583 | bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, | 584 | bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, |
584 | args->agno, XFS_BTNUM_BNO); | 585 | args->agno, XFS_BTNUM_BNO); |
586 | |||
585 | /* | 587 | /* |
586 | * Lookup bno and minlen in the btree (minlen is irrelevant, really). | 588 | * Lookup bno and minlen in the btree (minlen is irrelevant, really). |
587 | * Look for the closest free block <= bno, it must contain bno | 589 | * Look for the closest free block <= bno, it must contain bno |
588 | * if any free block does. | 590 | * if any free block does. |
589 | */ | 591 | */ |
590 | if ((error = xfs_alloc_lookup_le(bno_cur, args->agbno, args->minlen, &i))) | 592 | error = xfs_alloc_lookup_le(bno_cur, args->agbno, args->minlen, &i); |
593 | if (error) | ||
591 | goto error0; | 594 | goto error0; |
592 | if (!i) { | 595 | if (!i) |
593 | /* | 596 | goto not_found; |
594 | * Didn't find it, return null. | 597 | |
595 | */ | ||
596 | xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); | ||
597 | args->agbno = NULLAGBLOCK; | ||
598 | return 0; | ||
599 | } | ||
600 | /* | 598 | /* |
601 | * Grab the freespace record. | 599 | * Grab the freespace record. |
602 | */ | 600 | */ |
603 | if ((error = xfs_alloc_get_rec(bno_cur, &fbno, &flen, &i))) | 601 | error = xfs_alloc_get_rec(bno_cur, &fbno, &flen, &i); |
602 | if (error) | ||
604 | goto error0; | 603 | goto error0; |
605 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 604 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
606 | ASSERT(fbno <= args->agbno); | 605 | ASSERT(fbno <= args->agbno); |
607 | minend = args->agbno + args->minlen; | 606 | minend = args->agbno + args->minlen; |
608 | maxend = args->agbno + args->maxlen; | 607 | maxend = args->agbno + args->maxlen; |
609 | fend = fbno + flen; | 608 | fend = fbno + flen; |
609 | |||
610 | /* | 610 | /* |
611 | * Give up if the freespace isn't long enough for the minimum request. | 611 | * Give up if the freespace isn't long enough for the minimum request. |
612 | */ | 612 | */ |
613 | if (fend < minend) { | 613 | if (fend < minend) |
614 | xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); | 614 | goto not_found; |
615 | args->agbno = NULLAGBLOCK; | 615 | |
616 | return 0; | ||
617 | } | ||
618 | /* | 616 | /* |
619 | * End of extent will be smaller of the freespace end and the | 617 | * End of extent will be smaller of the freespace end and the |
620 | * maximal requested end. | 618 | * maximal requested end. |
621 | */ | 619 | * |
622 | end = XFS_AGBLOCK_MIN(fend, maxend); | ||
623 | /* | ||
624 | * Fix the length according to mod and prod if given. | 620 | * Fix the length according to mod and prod if given. |
625 | */ | 621 | */ |
622 | end = XFS_AGBLOCK_MIN(fend, maxend); | ||
626 | args->len = end - args->agbno; | 623 | args->len = end - args->agbno; |
627 | xfs_alloc_fix_len(args); | 624 | xfs_alloc_fix_len(args); |
628 | if (!xfs_alloc_fix_minleft(args)) { | 625 | if (!xfs_alloc_fix_minleft(args)) |
629 | xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); | 626 | goto not_found; |
630 | return 0; | 627 | |
631 | } | ||
632 | rlen = args->len; | 628 | rlen = args->len; |
633 | ASSERT(args->agbno + rlen <= fend); | 629 | ASSERT(args->agbno + rlen <= fend); |
634 | end = args->agbno + rlen; | 630 | end = args->agbno + rlen; |
631 | |||
635 | /* | 632 | /* |
636 | * We are allocating agbno for rlen [agbno .. end] | 633 | * We are allocating agbno for rlen [agbno .. end] |
637 | * Allocate/initialize a cursor for the by-size btree. | 634 | * Allocate/initialize a cursor for the by-size btree. |
@@ -640,16 +637,25 @@ xfs_alloc_ag_vextent_exact( | |||
640 | args->agno, XFS_BTNUM_CNT); | 637 | args->agno, XFS_BTNUM_CNT); |
641 | ASSERT(args->agbno + args->len <= | 638 | ASSERT(args->agbno + args->len <= |
642 | be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length)); | 639 | be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length)); |
643 | if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, | 640 | error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, args->agbno, |
644 | args->agbno, args->len, XFSA_FIXUP_BNO_OK))) { | 641 | args->len, XFSA_FIXUP_BNO_OK); |
642 | if (error) { | ||
645 | xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); | 643 | xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); |
646 | goto error0; | 644 | goto error0; |
647 | } | 645 | } |
646 | |||
648 | xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); | 647 | xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); |
649 | xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); | 648 | xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); |
650 | 649 | ||
651 | trace_xfs_alloc_exact_done(args); | ||
652 | args->wasfromfl = 0; | 650 | args->wasfromfl = 0; |
651 | trace_xfs_alloc_exact_done(args); | ||
652 | return 0; | ||
653 | |||
654 | not_found: | ||
655 | /* Didn't find it, return null. */ | ||
656 | xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); | ||
657 | args->agbno = NULLAGBLOCK; | ||
658 | trace_xfs_alloc_exact_notfound(args); | ||
653 | return 0; | 659 | return 0; |
654 | 660 | ||
655 | error0: | 661 | error0: |
@@ -659,6 +665,95 @@ error0: | |||
659 | } | 665 | } |
660 | 666 | ||
661 | /* | 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 | /* | ||
662 | * Allocate a variable extent near bno in the allocation group agno. | 757 | * Allocate a variable extent near bno in the allocation group agno. |
663 | * 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, |
664 | * 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. |
@@ -925,203 +1020,45 @@ xfs_alloc_ag_vextent_near( | |||
925 | } | 1020 | } |
926 | } | 1021 | } |
927 | } while (bno_cur_lt || bno_cur_gt); | 1022 | } while (bno_cur_lt || bno_cur_gt); |
1023 | |||
928 | /* | 1024 | /* |
929 | * Got both cursors still active, need to find better entry. | 1025 | * Got both cursors still active, need to find better entry. |
930 | */ | 1026 | */ |
931 | if (bno_cur_lt && bno_cur_gt) { | 1027 | if (bno_cur_lt && bno_cur_gt) { |
932 | /* | ||
933 | * Left side is long enough, look for a right side entry. | ||
934 | */ | ||
935 | if (ltlena >= args->minlen) { | 1028 | if (ltlena >= args->minlen) { |
936 | /* | 1029 | /* |
937 | * Fix up the length. | 1030 | * Left side is good, look for a right side entry. |
938 | */ | 1031 | */ |
939 | args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); | 1032 | args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); |
940 | xfs_alloc_fix_len(args); | 1033 | xfs_alloc_fix_len(args); |
941 | rlen = args->len; | 1034 | ltdiff = xfs_alloc_compute_diff(args->agbno, args->len, |
942 | ltdiff = xfs_alloc_compute_diff(args->agbno, rlen, | ||
943 | 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 | |||
944 | /* | 1044 | /* |
945 | * Not perfect. | 1045 | * Right side is good, look for a left side entry. |
946 | */ | ||
947 | if (ltdiff) { | ||
948 | /* | ||
949 | * Look until we find a better one, run out of | ||
950 | * space, or run off the end. | ||
951 | */ | ||
952 | while (bno_cur_lt && bno_cur_gt) { | ||
953 | if ((error = xfs_alloc_get_rec( | ||
954 | bno_cur_gt, >bno, | ||
955 | >len, &i))) | ||
956 | goto error0; | ||
957 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
958 | xfs_alloc_compute_aligned(gtbno, gtlen, | ||
959 | args->alignment, args->minlen, | ||
960 | >bnoa, >lena); | ||
961 | /* | ||
962 | * The left one is clearly better. | ||
963 | */ | ||
964 | if (gtbnoa >= args->agbno + ltdiff) { | ||
965 | xfs_btree_del_cursor( | ||
966 | bno_cur_gt, | ||
967 | XFS_BTREE_NOERROR); | ||
968 | bno_cur_gt = NULL; | ||
969 | break; | ||
970 | } | ||
971 | /* | ||
972 | * If we reach a big enough entry, | ||
973 | * compare the two and pick the best. | ||
974 | */ | ||
975 | if (gtlena >= args->minlen) { | ||
976 | args->len = | ||
977 | XFS_EXTLEN_MIN(gtlena, | ||
978 | args->maxlen); | ||
979 | xfs_alloc_fix_len(args); | ||
980 | rlen = args->len; | ||
981 | gtdiff = xfs_alloc_compute_diff( | ||
982 | args->agbno, rlen, | ||
983 | args->alignment, | ||
984 | gtbno, gtlen, >new); | ||
985 | /* | ||
986 | * Right side is better. | ||
987 | */ | ||
988 | if (gtdiff < ltdiff) { | ||
989 | xfs_btree_del_cursor( | ||
990 | bno_cur_lt, | ||
991 | XFS_BTREE_NOERROR); | ||
992 | bno_cur_lt = NULL; | ||
993 | } | ||
994 | /* | ||
995 | * Left side is better. | ||
996 | */ | ||
997 | else { | ||
998 | xfs_btree_del_cursor( | ||
999 | bno_cur_gt, | ||
1000 | XFS_BTREE_NOERROR); | ||
1001 | bno_cur_gt = NULL; | ||
1002 | } | ||
1003 | break; | ||
1004 | } | ||
1005 | /* | ||
1006 | * Fell off the right end. | ||
1007 | */ | ||
1008 | if ((error = xfs_btree_increment( | ||
1009 | bno_cur_gt, 0, &i))) | ||
1010 | goto error0; | ||
1011 | if (!i) { | ||
1012 | xfs_btree_del_cursor( | ||
1013 | bno_cur_gt, | ||
1014 | XFS_BTREE_NOERROR); | ||
1015 | bno_cur_gt = NULL; | ||
1016 | break; | ||
1017 | } | ||
1018 | } | ||
1019 | } | ||
1020 | /* | ||
1021 | * The left side is perfect, trash the right side. | ||
1022 | */ | ||
1023 | else { | ||
1024 | xfs_btree_del_cursor(bno_cur_gt, | ||
1025 | XFS_BTREE_NOERROR); | ||
1026 | bno_cur_gt = NULL; | ||
1027 | } | ||
1028 | } | ||
1029 | /* | ||
1030 | * It's the right side that was found first, look left. | ||
1031 | */ | ||
1032 | else { | ||
1033 | /* | ||
1034 | * Fix up the length. | ||
1035 | */ | 1046 | */ |
1036 | args->len = XFS_EXTLEN_MIN(gtlena, args->maxlen); | 1047 | args->len = XFS_EXTLEN_MIN(gtlena, args->maxlen); |
1037 | xfs_alloc_fix_len(args); | 1048 | xfs_alloc_fix_len(args); |
1038 | rlen = args->len; | 1049 | gtdiff = xfs_alloc_compute_diff(args->agbno, args->len, |
1039 | gtdiff = xfs_alloc_compute_diff(args->agbno, rlen, | ||
1040 | args->alignment, gtbno, gtlen, >new); | 1050 | args->alignment, gtbno, gtlen, >new); |
1041 | /* | 1051 | |
1042 | * Right side entry isn't perfect. | 1052 | error = xfs_alloc_find_best_extent(args, |
1043 | */ | 1053 | &bno_cur_gt, &bno_cur_lt, |
1044 | if (gtdiff) { | 1054 | gtdiff, <bno, <len, <lena, |
1045 | /* | 1055 | 1 /* search left */); |
1046 | * Look until we find a better one, run out of | ||
1047 | * space, or run off the end. | ||
1048 | */ | ||
1049 | while (bno_cur_lt && bno_cur_gt) { | ||
1050 | if ((error = xfs_alloc_get_rec( | ||
1051 | bno_cur_lt, <bno, | ||
1052 | <len, &i))) | ||
1053 | goto error0; | ||
1054 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | ||
1055 | xfs_alloc_compute_aligned(ltbno, ltlen, | ||
1056 | args->alignment, args->minlen, | ||
1057 | <bnoa, <lena); | ||
1058 | /* | ||
1059 | * The right one is clearly better. | ||
1060 | */ | ||
1061 | if (ltbnoa <= args->agbno - gtdiff) { | ||
1062 | xfs_btree_del_cursor( | ||
1063 | bno_cur_lt, | ||
1064 | XFS_BTREE_NOERROR); | ||
1065 | bno_cur_lt = NULL; | ||
1066 | break; | ||
1067 | } | ||
1068 | /* | ||
1069 | * If we reach a big enough entry, | ||
1070 | * compare the two and pick the best. | ||
1071 | */ | ||
1072 | if (ltlena >= args->minlen) { | ||
1073 | args->len = XFS_EXTLEN_MIN( | ||
1074 | ltlena, args->maxlen); | ||
1075 | xfs_alloc_fix_len(args); | ||
1076 | rlen = args->len; | ||
1077 | ltdiff = xfs_alloc_compute_diff( | ||
1078 | args->agbno, rlen, | ||
1079 | args->alignment, | ||
1080 | ltbno, ltlen, <new); | ||
1081 | /* | ||
1082 | * Left side is better. | ||
1083 | */ | ||
1084 | if (ltdiff < gtdiff) { | ||
1085 | xfs_btree_del_cursor( | ||
1086 | bno_cur_gt, | ||
1087 | XFS_BTREE_NOERROR); | ||
1088 | bno_cur_gt = NULL; | ||
1089 | } | ||
1090 | /* | ||
1091 | * Right side is better. | ||
1092 | */ | ||
1093 | else { | ||
1094 | xfs_btree_del_cursor( | ||
1095 | bno_cur_lt, | ||
1096 | XFS_BTREE_NOERROR); | ||
1097 | bno_cur_lt = NULL; | ||
1098 | } | ||
1099 | break; | ||
1100 | } | ||
1101 | /* | ||
1102 | * Fell off the left end. | ||
1103 | */ | ||
1104 | if ((error = xfs_btree_decrement( | ||
1105 | bno_cur_lt, 0, &i))) | ||
1106 | goto error0; | ||
1107 | if (!i) { | ||
1108 | xfs_btree_del_cursor(bno_cur_lt, | ||
1109 | XFS_BTREE_NOERROR); | ||
1110 | bno_cur_lt = NULL; | ||
1111 | break; | ||
1112 | } | ||
1113 | } | ||
1114 | } | ||
1115 | /* | ||
1116 | * The right side is perfect, trash the left side. | ||
1117 | */ | ||
1118 | else { | ||
1119 | xfs_btree_del_cursor(bno_cur_lt, | ||
1120 | XFS_BTREE_NOERROR); | ||
1121 | bno_cur_lt = NULL; | ||
1122 | } | ||
1123 | } | 1056 | } |
1057 | |||
1058 | if (error) | ||
1059 | goto error0; | ||
1124 | } | 1060 | } |
1061 | |||
1125 | /* | 1062 | /* |
1126 | * If we couldn't get anything, give up. | 1063 | * If we couldn't get anything, give up. |
1127 | */ | 1064 | */ |
@@ -1130,6 +1067,7 @@ xfs_alloc_ag_vextent_near( | |||
1130 | args->agbno = NULLAGBLOCK; | 1067 | args->agbno = NULLAGBLOCK; |
1131 | return 0; | 1068 | return 0; |
1132 | } | 1069 | } |
1070 | |||
1133 | /* | 1071 | /* |
1134 | * 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 |
1135 | * 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 |
@@ -1146,6 +1084,7 @@ xfs_alloc_ag_vextent_near( | |||
1146 | j = 1; | 1084 | j = 1; |
1147 | } else | 1085 | } else |
1148 | j = 0; | 1086 | j = 0; |
1087 | |||
1149 | /* | 1088 | /* |
1150 | * Fix up the length and compute the useful address. | 1089 | * Fix up the length and compute the useful address. |
1151 | */ | 1090 | */ |