diff options
author | Josef Bacik <josef@redhat.com> | 2011-09-26 13:56:12 -0400 |
---|---|---|
committer | Josef Bacik <josef@redhat.com> | 2011-10-19 15:12:47 -0400 |
commit | 462d6fac8960a3ba797927adfcbd29d503eb16fd (patch) | |
tree | 82e72468a746b55d09246db8272823c2907633e1 /fs | |
parent | ef3be45722317f8c2fb0e861065df0c3830ff9ac (diff) |
Btrfs: introduce convert_extent_bit
If I have a range where I know a certain bit is and I want to set it to another
bit the only option I have is to call set and then clear bit, which will result
in 2 tree searches. This is inefficient, so introduce convert_extent_bit which
will go through and set the bit I want and clear the old bit I don't want.
Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/extent_io.c | 188 | ||||
-rw-r--r-- | fs/btrfs/extent_io.h | 2 |
2 files changed, 190 insertions, 0 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 7d5e55632809..0ada0b700b44 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -894,6 +894,194 @@ search_again: | |||
894 | goto again; | 894 | goto again; |
895 | } | 895 | } |
896 | 896 | ||
897 | /** | ||
898 | * convert_extent - convert all bits in a given range from one bit to another | ||
899 | * @tree: the io tree to search | ||
900 | * @start: the start offset in bytes | ||
901 | * @end: the end offset in bytes (inclusive) | ||
902 | * @bits: the bits to set in this range | ||
903 | * @clear_bits: the bits to clear in this range | ||
904 | * @mask: the allocation mask | ||
905 | * | ||
906 | * This will go through and set bits for the given range. If any states exist | ||
907 | * already in this range they are set with the given bit and cleared of the | ||
908 | * clear_bits. This is only meant to be used by things that are mergeable, ie | ||
909 | * converting from say DELALLOC to DIRTY. This is not meant to be used with | ||
910 | * boundary bits like LOCK. | ||
911 | */ | ||
912 | int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, | ||
913 | int bits, int clear_bits, gfp_t mask) | ||
914 | { | ||
915 | struct extent_state *state; | ||
916 | struct extent_state *prealloc = NULL; | ||
917 | struct rb_node *node; | ||
918 | int err = 0; | ||
919 | u64 last_start; | ||
920 | u64 last_end; | ||
921 | |||
922 | again: | ||
923 | if (!prealloc && (mask & __GFP_WAIT)) { | ||
924 | prealloc = alloc_extent_state(mask); | ||
925 | if (!prealloc) | ||
926 | return -ENOMEM; | ||
927 | } | ||
928 | |||
929 | spin_lock(&tree->lock); | ||
930 | /* | ||
931 | * this search will find all the extents that end after | ||
932 | * our range starts. | ||
933 | */ | ||
934 | node = tree_search(tree, start); | ||
935 | if (!node) { | ||
936 | prealloc = alloc_extent_state_atomic(prealloc); | ||
937 | if (!prealloc) | ||
938 | return -ENOMEM; | ||
939 | err = insert_state(tree, prealloc, start, end, &bits); | ||
940 | prealloc = NULL; | ||
941 | BUG_ON(err == -EEXIST); | ||
942 | goto out; | ||
943 | } | ||
944 | state = rb_entry(node, struct extent_state, rb_node); | ||
945 | hit_next: | ||
946 | last_start = state->start; | ||
947 | last_end = state->end; | ||
948 | |||
949 | /* | ||
950 | * | ---- desired range ---- | | ||
951 | * | state | | ||
952 | * | ||
953 | * Just lock what we found and keep going | ||
954 | */ | ||
955 | if (state->start == start && state->end <= end) { | ||
956 | struct rb_node *next_node; | ||
957 | |||
958 | set_state_bits(tree, state, &bits); | ||
959 | clear_state_bit(tree, state, &clear_bits, 0); | ||
960 | |||
961 | merge_state(tree, state); | ||
962 | if (last_end == (u64)-1) | ||
963 | goto out; | ||
964 | |||
965 | start = last_end + 1; | ||
966 | next_node = rb_next(&state->rb_node); | ||
967 | if (next_node && start < end && prealloc && !need_resched()) { | ||
968 | state = rb_entry(next_node, struct extent_state, | ||
969 | rb_node); | ||
970 | if (state->start == start) | ||
971 | goto hit_next; | ||
972 | } | ||
973 | goto search_again; | ||
974 | } | ||
975 | |||
976 | /* | ||
977 | * | ---- desired range ---- | | ||
978 | * | state | | ||
979 | * or | ||
980 | * | ------------- state -------------- | | ||
981 | * | ||
982 | * We need to split the extent we found, and may flip bits on | ||
983 | * second half. | ||
984 | * | ||
985 | * If the extent we found extends past our | ||
986 | * range, we just split and search again. It'll get split | ||
987 | * again the next time though. | ||
988 | * | ||
989 | * If the extent we found is inside our range, we set the | ||
990 | * desired bit on it. | ||
991 | */ | ||
992 | if (state->start < start) { | ||
993 | prealloc = alloc_extent_state_atomic(prealloc); | ||
994 | if (!prealloc) | ||
995 | return -ENOMEM; | ||
996 | err = split_state(tree, state, prealloc, start); | ||
997 | BUG_ON(err == -EEXIST); | ||
998 | prealloc = NULL; | ||
999 | if (err) | ||
1000 | goto out; | ||
1001 | if (state->end <= end) { | ||
1002 | set_state_bits(tree, state, &bits); | ||
1003 | clear_state_bit(tree, state, &clear_bits, 0); | ||
1004 | merge_state(tree, state); | ||
1005 | if (last_end == (u64)-1) | ||
1006 | goto out; | ||
1007 | start = last_end + 1; | ||
1008 | } | ||
1009 | goto search_again; | ||
1010 | } | ||
1011 | /* | ||
1012 | * | ---- desired range ---- | | ||
1013 | * | state | or | state | | ||
1014 | * | ||
1015 | * There's a hole, we need to insert something in it and | ||
1016 | * ignore the extent we found. | ||
1017 | */ | ||
1018 | if (state->start > start) { | ||
1019 | u64 this_end; | ||
1020 | if (end < last_start) | ||
1021 | this_end = end; | ||
1022 | else | ||
1023 | this_end = last_start - 1; | ||
1024 | |||
1025 | prealloc = alloc_extent_state_atomic(prealloc); | ||
1026 | if (!prealloc) | ||
1027 | return -ENOMEM; | ||
1028 | |||
1029 | /* | ||
1030 | * Avoid to free 'prealloc' if it can be merged with | ||
1031 | * the later extent. | ||
1032 | */ | ||
1033 | err = insert_state(tree, prealloc, start, this_end, | ||
1034 | &bits); | ||
1035 | BUG_ON(err == -EEXIST); | ||
1036 | if (err) { | ||
1037 | free_extent_state(prealloc); | ||
1038 | prealloc = NULL; | ||
1039 | goto out; | ||
1040 | } | ||
1041 | prealloc = NULL; | ||
1042 | start = this_end + 1; | ||
1043 | goto search_again; | ||
1044 | } | ||
1045 | /* | ||
1046 | * | ---- desired range ---- | | ||
1047 | * | state | | ||
1048 | * We need to split the extent, and set the bit | ||
1049 | * on the first half | ||
1050 | */ | ||
1051 | if (state->start <= end && state->end > end) { | ||
1052 | prealloc = alloc_extent_state_atomic(prealloc); | ||
1053 | if (!prealloc) | ||
1054 | return -ENOMEM; | ||
1055 | |||
1056 | err = split_state(tree, state, prealloc, end + 1); | ||
1057 | BUG_ON(err == -EEXIST); | ||
1058 | |||
1059 | set_state_bits(tree, prealloc, &bits); | ||
1060 | clear_state_bit(tree, prealloc, &clear_bits, 0); | ||
1061 | |||
1062 | merge_state(tree, prealloc); | ||
1063 | prealloc = NULL; | ||
1064 | goto out; | ||
1065 | } | ||
1066 | |||
1067 | goto search_again; | ||
1068 | |||
1069 | out: | ||
1070 | spin_unlock(&tree->lock); | ||
1071 | if (prealloc) | ||
1072 | free_extent_state(prealloc); | ||
1073 | |||
1074 | return err; | ||
1075 | |||
1076 | search_again: | ||
1077 | if (start > end) | ||
1078 | goto out; | ||
1079 | spin_unlock(&tree->lock); | ||
1080 | if (mask & __GFP_WAIT) | ||
1081 | cond_resched(); | ||
1082 | goto again; | ||
1083 | } | ||
1084 | |||
897 | /* wrappers around set/clear extent bit */ | 1085 | /* wrappers around set/clear extent bit */ |
898 | int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, | 1086 | int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, |
899 | gfp_t mask) | 1087 | gfp_t mask) |
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 7b2f0c3e7929..cea445dcd806 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h | |||
@@ -214,6 +214,8 @@ int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, | |||
214 | gfp_t mask); | 214 | gfp_t mask); |
215 | int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, | 215 | int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, |
216 | gfp_t mask); | 216 | gfp_t mask); |
217 | int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, | ||
218 | int bits, int clear_bits, gfp_t mask); | ||
217 | int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end, | 219 | int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end, |
218 | struct extent_state **cached_state, gfp_t mask); | 220 | struct extent_state **cached_state, gfp_t mask); |
219 | int find_first_extent_bit(struct extent_io_tree *tree, u64 start, | 221 | int find_first_extent_bit(struct extent_io_tree *tree, u64 start, |