diff options
Diffstat (limited to 'fs/ext3/balloc.c')
| -rw-r--r-- | fs/ext3/balloc.c | 135 |
1 files changed, 63 insertions, 72 deletions
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index ccd632fcc6d8..e463dca008e4 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c | |||
| @@ -749,24 +749,24 @@ fail_access: | |||
| 749 | * to find a free region that is of my size and has not | 749 | * to find a free region that is of my size and has not |
| 750 | * been reserved. | 750 | * been reserved. |
| 751 | * | 751 | * |
| 752 | * on succeed, it returns the reservation window to be appended to. | ||
| 753 | * failed, return NULL. | ||
| 754 | */ | 752 | */ |
| 755 | static struct ext3_reserve_window_node *find_next_reservable_window( | 753 | static int find_next_reservable_window( |
| 756 | struct ext3_reserve_window_node *search_head, | 754 | struct ext3_reserve_window_node *search_head, |
| 757 | unsigned long size, int *start_block, | 755 | struct ext3_reserve_window_node *my_rsv, |
| 756 | struct super_block * sb, int start_block, | ||
| 758 | int last_block) | 757 | int last_block) |
| 759 | { | 758 | { |
| 760 | struct rb_node *next; | 759 | struct rb_node *next; |
| 761 | struct ext3_reserve_window_node *rsv, *prev; | 760 | struct ext3_reserve_window_node *rsv, *prev; |
| 762 | int cur; | 761 | int cur; |
| 762 | int size = my_rsv->rsv_goal_size; | ||
| 763 | 763 | ||
| 764 | /* TODO: make the start of the reservation window byte-aligned */ | 764 | /* TODO: make the start of the reservation window byte-aligned */ |
| 765 | /* cur = *start_block & ~7;*/ | 765 | /* cur = *start_block & ~7;*/ |
| 766 | cur = *start_block; | 766 | cur = start_block; |
| 767 | rsv = search_head; | 767 | rsv = search_head; |
| 768 | if (!rsv) | 768 | if (!rsv) |
| 769 | return NULL; | 769 | return -1; |
| 770 | 770 | ||
| 771 | while (1) { | 771 | while (1) { |
| 772 | if (cur <= rsv->rsv_end) | 772 | if (cur <= rsv->rsv_end) |
| @@ -782,11 +782,11 @@ static struct ext3_reserve_window_node *find_next_reservable_window( | |||
| 782 | * space with expected-size (or more)... | 782 | * space with expected-size (or more)... |
| 783 | */ | 783 | */ |
| 784 | if (cur > last_block) | 784 | if (cur > last_block) |
| 785 | return NULL; /* fail */ | 785 | return -1; /* fail */ |
| 786 | 786 | ||
| 787 | prev = rsv; | 787 | prev = rsv; |
| 788 | next = rb_next(&rsv->rsv_node); | 788 | next = rb_next(&rsv->rsv_node); |
| 789 | rsv = list_entry(next, struct ext3_reserve_window_node, rsv_node); | 789 | rsv = list_entry(next,struct ext3_reserve_window_node,rsv_node); |
| 790 | 790 | ||
| 791 | /* | 791 | /* |
| 792 | * Reached the last reservation, we can just append to the | 792 | * Reached the last reservation, we can just append to the |
| @@ -813,8 +813,25 @@ static struct ext3_reserve_window_node *find_next_reservable_window( | |||
| 813 | * return the reservation window that we could append to. | 813 | * return the reservation window that we could append to. |
| 814 | * succeed. | 814 | * succeed. |
| 815 | */ | 815 | */ |
| 816 | *start_block = cur; | 816 | |
| 817 | return prev; | 817 | if ((prev != my_rsv) && (!rsv_is_empty(&my_rsv->rsv_window))) |
| 818 | rsv_window_remove(sb, my_rsv); | ||
| 819 | |||
| 820 | /* | ||
| 821 | * Let's book the whole avaliable window for now. We will check the | ||
| 822 | * disk bitmap later and then, if there are free blocks then we adjust | ||
| 823 | * the window size if it's larger than requested. | ||
| 824 | * Otherwise, we will remove this node from the tree next time | ||
| 825 | * call find_next_reservable_window. | ||
| 826 | */ | ||
| 827 | my_rsv->rsv_start = cur; | ||
| 828 | my_rsv->rsv_end = cur + size - 1; | ||
| 829 | my_rsv->rsv_alloc_hit = 0; | ||
| 830 | |||
| 831 | if (prev != my_rsv) | ||
| 832 | ext3_rsv_window_add(sb, my_rsv); | ||
| 833 | |||
| 834 | return 0; | ||
| 818 | } | 835 | } |
| 819 | 836 | ||
| 820 | /** | 837 | /** |
| @@ -852,6 +869,7 @@ static struct ext3_reserve_window_node *find_next_reservable_window( | |||
| 852 | * @sb: the super block | 869 | * @sb: the super block |
| 853 | * @group: the group we are trying to allocate in | 870 | * @group: the group we are trying to allocate in |
| 854 | * @bitmap_bh: the block group block bitmap | 871 | * @bitmap_bh: the block group block bitmap |
| 872 | * | ||
| 855 | */ | 873 | */ |
| 856 | static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, | 874 | static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, |
| 857 | int goal, struct super_block *sb, | 875 | int goal, struct super_block *sb, |
| @@ -860,10 +878,10 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, | |||
| 860 | struct ext3_reserve_window_node *search_head; | 878 | struct ext3_reserve_window_node *search_head; |
| 861 | int group_first_block, group_end_block, start_block; | 879 | int group_first_block, group_end_block, start_block; |
| 862 | int first_free_block; | 880 | int first_free_block; |
| 863 | int reservable_space_start; | ||
| 864 | struct ext3_reserve_window_node *prev_rsv; | ||
| 865 | struct rb_root *fs_rsv_root = &EXT3_SB(sb)->s_rsv_window_root; | 881 | struct rb_root *fs_rsv_root = &EXT3_SB(sb)->s_rsv_window_root; |
| 866 | unsigned long size; | 882 | unsigned long size; |
| 883 | int ret; | ||
| 884 | spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock; | ||
| 867 | 885 | ||
| 868 | group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) + | 886 | group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) + |
| 869 | group * EXT3_BLOCKS_PER_GROUP(sb); | 887 | group * EXT3_BLOCKS_PER_GROUP(sb); |
| @@ -875,6 +893,7 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, | |||
| 875 | start_block = goal + group_first_block; | 893 | start_block = goal + group_first_block; |
| 876 | 894 | ||
| 877 | size = my_rsv->rsv_goal_size; | 895 | size = my_rsv->rsv_goal_size; |
| 896 | |||
| 878 | if (!rsv_is_empty(&my_rsv->rsv_window)) { | 897 | if (!rsv_is_empty(&my_rsv->rsv_window)) { |
| 879 | /* | 898 | /* |
| 880 | * if the old reservation is cross group boundary | 899 | * if the old reservation is cross group boundary |
| @@ -908,6 +927,8 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, | |||
| 908 | my_rsv->rsv_goal_size= size; | 927 | my_rsv->rsv_goal_size= size; |
| 909 | } | 928 | } |
| 910 | } | 929 | } |
| 930 | |||
| 931 | spin_lock(rsv_lock); | ||
| 911 | /* | 932 | /* |
| 912 | * shift the search start to the window near the goal block | 933 | * shift the search start to the window near the goal block |
| 913 | */ | 934 | */ |
| @@ -921,11 +942,16 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, | |||
| 921 | * need to check the bitmap after we found a reservable window. | 942 | * need to check the bitmap after we found a reservable window. |
| 922 | */ | 943 | */ |
| 923 | retry: | 944 | retry: |
| 924 | prev_rsv = find_next_reservable_window(search_head, size, | 945 | ret = find_next_reservable_window(search_head, my_rsv, sb, |
| 925 | &start_block, group_end_block); | 946 | start_block, group_end_block); |
| 926 | if (prev_rsv == NULL) | 947 | |
| 927 | goto failed; | 948 | if (ret == -1) { |
| 928 | reservable_space_start = start_block; | 949 | if (!rsv_is_empty(&my_rsv->rsv_window)) |
| 950 | rsv_window_remove(sb, my_rsv); | ||
| 951 | spin_unlock(rsv_lock); | ||
| 952 | return -1; | ||
| 953 | } | ||
| 954 | |||
| 929 | /* | 955 | /* |
| 930 | * On success, find_next_reservable_window() returns the | 956 | * On success, find_next_reservable_window() returns the |
| 931 | * reservation window where there is a reservable space after it. | 957 | * reservation window where there is a reservable space after it. |
| @@ -937,8 +963,9 @@ retry: | |||
| 937 | * block. Search start from the start block of the reservable space | 963 | * block. Search start from the start block of the reservable space |
| 938 | * we just found. | 964 | * we just found. |
| 939 | */ | 965 | */ |
| 966 | spin_unlock(rsv_lock); | ||
| 940 | first_free_block = bitmap_search_next_usable_block( | 967 | first_free_block = bitmap_search_next_usable_block( |
| 941 | reservable_space_start - group_first_block, | 968 | my_rsv->rsv_start - group_first_block, |
| 942 | bitmap_bh, group_end_block - group_first_block + 1); | 969 | bitmap_bh, group_end_block - group_first_block + 1); |
| 943 | 970 | ||
| 944 | if (first_free_block < 0) { | 971 | if (first_free_block < 0) { |
| @@ -946,54 +973,29 @@ retry: | |||
| 946 | * no free block left on the bitmap, no point | 973 | * no free block left on the bitmap, no point |
| 947 | * to reserve the space. return failed. | 974 | * to reserve the space. return failed. |
| 948 | */ | 975 | */ |
| 949 | goto failed; | 976 | spin_lock(rsv_lock); |
| 977 | if (!rsv_is_empty(&my_rsv->rsv_window)) | ||
| 978 | rsv_window_remove(sb, my_rsv); | ||
| 979 | spin_unlock(rsv_lock); | ||
| 980 | return -1; /* failed */ | ||
| 950 | } | 981 | } |
| 982 | |||
| 951 | start_block = first_free_block + group_first_block; | 983 | start_block = first_free_block + group_first_block; |
| 952 | /* | 984 | /* |
| 953 | * check if the first free block is within the | 985 | * check if the first free block is within the |
| 954 | * free space we just found | 986 | * free space we just reserved |
| 955 | */ | 987 | */ |
| 956 | if ((start_block >= reservable_space_start) && | 988 | if (start_block >= my_rsv->rsv_start && start_block < my_rsv->rsv_end) |
| 957 | (start_block < reservable_space_start + size)) | 989 | return 0; /* success */ |
| 958 | goto found_rsv_window; | ||
| 959 | /* | 990 | /* |
| 960 | * if the first free bit we found is out of the reservable space | 991 | * if the first free bit we found is out of the reservable space |
| 961 | * this means there is no free block on the reservable space | 992 | * continue search for next reservable space, |
| 962 | * we should continue search for next reservable space, | ||
| 963 | * start from where the free block is, | 993 | * start from where the free block is, |
| 964 | * we also shift the list head to where we stopped last time | 994 | * we also shift the list head to where we stopped last time |
| 965 | */ | 995 | */ |
| 966 | search_head = prev_rsv; | 996 | search_head = my_rsv; |
| 997 | spin_lock(rsv_lock); | ||
| 967 | goto retry; | 998 | goto retry; |
| 968 | |||
| 969 | found_rsv_window: | ||
| 970 | /* | ||
| 971 | * great! the reservable space contains some free blocks. | ||
| 972 | * if the search returns that we should add the new | ||
| 973 | * window just next to where the old window, we don't | ||
| 974 | * need to remove the old window first then add it to the | ||
| 975 | * same place, just update the new start and new end. | ||
| 976 | */ | ||
| 977 | if (my_rsv != prev_rsv) { | ||
| 978 | if (!rsv_is_empty(&my_rsv->rsv_window)) | ||
| 979 | rsv_window_remove(sb, my_rsv); | ||
| 980 | } | ||
| 981 | my_rsv->rsv_start = reservable_space_start; | ||
| 982 | my_rsv->rsv_end = my_rsv->rsv_start + size - 1; | ||
| 983 | my_rsv->rsv_alloc_hit = 0; | ||
| 984 | if (my_rsv != prev_rsv) { | ||
| 985 | ext3_rsv_window_add(sb, my_rsv); | ||
| 986 | } | ||
| 987 | return 0; /* succeed */ | ||
| 988 | failed: | ||
| 989 | /* | ||
| 990 | * failed to find a new reservation window in the current | ||
| 991 | * group, remove the current(stale) reservation window | ||
| 992 | * if there is any | ||
| 993 | */ | ||
| 994 | if (!rsv_is_empty(&my_rsv->rsv_window)) | ||
| 995 | rsv_window_remove(sb, my_rsv); | ||
| 996 | return -1; /* failed */ | ||
| 997 | } | 999 | } |
| 998 | 1000 | ||
| 999 | /* | 1001 | /* |
| @@ -1023,7 +1025,6 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, | |||
| 1023 | int goal, struct ext3_reserve_window_node * my_rsv, | 1025 | int goal, struct ext3_reserve_window_node * my_rsv, |
| 1024 | int *errp) | 1026 | int *errp) |
| 1025 | { | 1027 | { |
| 1026 | spinlock_t *rsv_lock; | ||
| 1027 | unsigned long group_first_block; | 1028 | unsigned long group_first_block; |
| 1028 | int ret = 0; | 1029 | int ret = 0; |
| 1029 | int fatal; | 1030 | int fatal; |
| @@ -1052,7 +1053,6 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, | |||
| 1052 | ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, NULL); | 1053 | ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, NULL); |
| 1053 | goto out; | 1054 | goto out; |
| 1054 | } | 1055 | } |
| 1055 | rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock; | ||
| 1056 | /* | 1056 | /* |
| 1057 | * goal is a group relative block number (if there is a goal) | 1057 | * goal is a group relative block number (if there is a goal) |
| 1058 | * 0 < goal < EXT3_BLOCKS_PER_GROUP(sb) | 1058 | * 0 < goal < EXT3_BLOCKS_PER_GROUP(sb) |
| @@ -1078,30 +1078,21 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, | |||
| 1078 | * then we could go to allocate from the reservation window directly. | 1078 | * then we could go to allocate from the reservation window directly. |
| 1079 | */ | 1079 | */ |
| 1080 | while (1) { | 1080 | while (1) { |
| 1081 | struct ext3_reserve_window rsv_copy; | 1081 | if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) || |
| 1082 | 1082 | !goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb)) { | |
| 1083 | rsv_copy._rsv_start = my_rsv->rsv_start; | ||
| 1084 | rsv_copy._rsv_end = my_rsv->rsv_end; | ||
| 1085 | |||
| 1086 | if (rsv_is_empty(&rsv_copy) || (ret < 0) || | ||
| 1087 | !goal_in_my_reservation(&rsv_copy, goal, group, sb)) { | ||
| 1088 | spin_lock(rsv_lock); | ||
| 1089 | ret = alloc_new_reservation(my_rsv, goal, sb, | 1083 | ret = alloc_new_reservation(my_rsv, goal, sb, |
| 1090 | group, bitmap_bh); | 1084 | group, bitmap_bh); |
| 1091 | rsv_copy._rsv_start = my_rsv->rsv_start; | ||
| 1092 | rsv_copy._rsv_end = my_rsv->rsv_end; | ||
| 1093 | spin_unlock(rsv_lock); | ||
| 1094 | if (ret < 0) | 1085 | if (ret < 0) |
| 1095 | break; /* failed */ | 1086 | break; /* failed */ |
| 1096 | 1087 | ||
| 1097 | if (!goal_in_my_reservation(&rsv_copy, goal, group, sb)) | 1088 | if (!goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb)) |
| 1098 | goal = -1; | 1089 | goal = -1; |
| 1099 | } | 1090 | } |
| 1100 | if ((rsv_copy._rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb)) | 1091 | if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb)) |
| 1101 | || (rsv_copy._rsv_end < group_first_block)) | 1092 | || (my_rsv->rsv_end < group_first_block)) |
| 1102 | BUG(); | 1093 | BUG(); |
| 1103 | ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, | 1094 | ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, |
| 1104 | &rsv_copy); | 1095 | &my_rsv->rsv_window); |
| 1105 | if (ret >= 0) { | 1096 | if (ret >= 0) { |
| 1106 | my_rsv->rsv_alloc_hit++; | 1097 | my_rsv->rsv_alloc_hit++; |
| 1107 | break; /* succeed */ | 1098 | break; /* succeed */ |
