diff options
author | Chris Mason <clm@fb.com> | 2014-05-19 23:47:56 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2014-06-09 20:20:55 -0400 |
commit | d4452bc526c431a882cc6ba854619e166cb7dfe4 (patch) | |
tree | 4cf699991791873af81041f3b40faca3d8155d8c /fs | |
parent | 2a10840945a86dfa2356bce526ae78cd4c1a356e (diff) |
Btrfs: break up __btrfs_write_out_cache to cut down stack usage
__btrfs_write_out_cache was one of our stack pigs. This breaks it
up into helper functions and slims it down to 194 bytes.
Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/free-space-cache.c | 308 |
1 files changed, 191 insertions, 117 deletions
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index a6bd654dcd47..372b05ff1943 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c | |||
@@ -851,90 +851,44 @@ out: | |||
851 | return ret; | 851 | return ret; |
852 | } | 852 | } |
853 | 853 | ||
854 | /** | 854 | static noinline_for_stack |
855 | * __btrfs_write_out_cache - write out cached info to an inode | 855 | int write_cache_extent_entries(struct io_ctl *io_ctl, |
856 | * @root - the root the inode belongs to | 856 | struct btrfs_free_space_ctl *ctl, |
857 | * @ctl - the free space cache we are going to write out | 857 | struct btrfs_block_group_cache *block_group, |
858 | * @block_group - the block_group for this cache if it belongs to a block_group | 858 | int *entries, int *bitmaps, |
859 | * @trans - the trans handle | 859 | struct list_head *bitmap_list) |
860 | * @path - the path to use | ||
861 | * @offset - the offset for the key we'll insert | ||
862 | * | ||
863 | * This function writes out a free space cache struct to disk for quick recovery | ||
864 | * on mount. This will return 0 if it was successfull in writing the cache out, | ||
865 | * and -1 if it was not. | ||
866 | */ | ||
867 | static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, | ||
868 | struct btrfs_free_space_ctl *ctl, | ||
869 | struct btrfs_block_group_cache *block_group, | ||
870 | struct btrfs_trans_handle *trans, | ||
871 | struct btrfs_path *path, u64 offset) | ||
872 | { | 860 | { |
873 | struct btrfs_free_space_header *header; | ||
874 | struct extent_buffer *leaf; | ||
875 | struct rb_node *node; | ||
876 | struct list_head *pos, *n; | ||
877 | struct extent_state *cached_state = NULL; | ||
878 | struct btrfs_free_cluster *cluster = NULL; | ||
879 | struct extent_io_tree *unpin = NULL; | ||
880 | struct io_ctl io_ctl; | ||
881 | struct list_head bitmap_list; | ||
882 | struct btrfs_key key; | ||
883 | u64 start, extent_start, extent_end, len; | ||
884 | int entries = 0; | ||
885 | int bitmaps = 0; | ||
886 | int ret; | 861 | int ret; |
887 | int err = -1; | 862 | struct btrfs_free_cluster *cluster = NULL; |
888 | 863 | struct rb_node *node = rb_first(&ctl->free_space_offset); | |
889 | INIT_LIST_HEAD(&bitmap_list); | ||
890 | |||
891 | if (!i_size_read(inode)) | ||
892 | return -1; | ||
893 | |||
894 | ret = io_ctl_init(&io_ctl, inode, root); | ||
895 | if (ret) | ||
896 | return -1; | ||
897 | 864 | ||
898 | /* Get the cluster for this block_group if it exists */ | 865 | /* Get the cluster for this block_group if it exists */ |
899 | if (block_group && !list_empty(&block_group->cluster_list)) | 866 | if (block_group && !list_empty(&block_group->cluster_list)) { |
900 | cluster = list_entry(block_group->cluster_list.next, | 867 | cluster = list_entry(block_group->cluster_list.next, |
901 | struct btrfs_free_cluster, | 868 | struct btrfs_free_cluster, |
902 | block_group_list); | 869 | block_group_list); |
870 | } | ||
903 | 871 | ||
904 | /* Lock all pages first so we can lock the extent safely. */ | ||
905 | io_ctl_prepare_pages(&io_ctl, inode, 0); | ||
906 | |||
907 | lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1, | ||
908 | 0, &cached_state); | ||
909 | |||
910 | node = rb_first(&ctl->free_space_offset); | ||
911 | if (!node && cluster) { | 872 | if (!node && cluster) { |
912 | node = rb_first(&cluster->root); | 873 | node = rb_first(&cluster->root); |
913 | cluster = NULL; | 874 | cluster = NULL; |
914 | } | 875 | } |
915 | 876 | ||
916 | /* Make sure we can fit our crcs into the first page */ | ||
917 | if (io_ctl.check_crcs && | ||
918 | (io_ctl.num_pages * sizeof(u32)) >= PAGE_CACHE_SIZE) | ||
919 | goto out_nospc; | ||
920 | |||
921 | io_ctl_set_generation(&io_ctl, trans->transid); | ||
922 | |||
923 | /* Write out the extent entries */ | 877 | /* Write out the extent entries */ |
924 | while (node) { | 878 | while (node) { |
925 | struct btrfs_free_space *e; | 879 | struct btrfs_free_space *e; |
926 | 880 | ||
927 | e = rb_entry(node, struct btrfs_free_space, offset_index); | 881 | e = rb_entry(node, struct btrfs_free_space, offset_index); |
928 | entries++; | 882 | *entries += 1; |
929 | 883 | ||
930 | ret = io_ctl_add_entry(&io_ctl, e->offset, e->bytes, | 884 | ret = io_ctl_add_entry(io_ctl, e->offset, e->bytes, |
931 | e->bitmap); | 885 | e->bitmap); |
932 | if (ret) | 886 | if (ret) |
933 | goto out_nospc; | 887 | goto fail; |
934 | 888 | ||
935 | if (e->bitmap) { | 889 | if (e->bitmap) { |
936 | list_add_tail(&e->list, &bitmap_list); | 890 | list_add_tail(&e->list, bitmap_list); |
937 | bitmaps++; | 891 | *bitmaps += 1; |
938 | } | 892 | } |
939 | node = rb_next(node); | 893 | node = rb_next(node); |
940 | if (!node && cluster) { | 894 | if (!node && cluster) { |
@@ -942,13 +896,84 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, | |||
942 | cluster = NULL; | 896 | cluster = NULL; |
943 | } | 897 | } |
944 | } | 898 | } |
899 | return 0; | ||
900 | fail: | ||
901 | return -ENOSPC; | ||
902 | } | ||
903 | |||
904 | static noinline_for_stack int | ||
905 | update_cache_item(struct btrfs_trans_handle *trans, | ||
906 | struct btrfs_root *root, | ||
907 | struct inode *inode, | ||
908 | struct btrfs_path *path, u64 offset, | ||
909 | int entries, int bitmaps) | ||
910 | { | ||
911 | struct btrfs_key key; | ||
912 | struct btrfs_free_space_header *header; | ||
913 | struct extent_buffer *leaf; | ||
914 | int ret; | ||
915 | |||
916 | key.objectid = BTRFS_FREE_SPACE_OBJECTID; | ||
917 | key.offset = offset; | ||
918 | key.type = 0; | ||
919 | |||
920 | ret = btrfs_search_slot(trans, root, &key, path, 0, 1); | ||
921 | if (ret < 0) { | ||
922 | clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1, | ||
923 | EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL, | ||
924 | GFP_NOFS); | ||
925 | goto fail; | ||
926 | } | ||
927 | leaf = path->nodes[0]; | ||
928 | if (ret > 0) { | ||
929 | struct btrfs_key found_key; | ||
930 | ASSERT(path->slots[0]); | ||
931 | path->slots[0]--; | ||
932 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | ||
933 | if (found_key.objectid != BTRFS_FREE_SPACE_OBJECTID || | ||
934 | found_key.offset != offset) { | ||
935 | clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, | ||
936 | inode->i_size - 1, | ||
937 | EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, | ||
938 | NULL, GFP_NOFS); | ||
939 | btrfs_release_path(path); | ||
940 | goto fail; | ||
941 | } | ||
942 | } | ||
943 | |||
944 | BTRFS_I(inode)->generation = trans->transid; | ||
945 | header = btrfs_item_ptr(leaf, path->slots[0], | ||
946 | struct btrfs_free_space_header); | ||
947 | btrfs_set_free_space_entries(leaf, header, entries); | ||
948 | btrfs_set_free_space_bitmaps(leaf, header, bitmaps); | ||
949 | btrfs_set_free_space_generation(leaf, header, trans->transid); | ||
950 | btrfs_mark_buffer_dirty(leaf); | ||
951 | btrfs_release_path(path); | ||
952 | |||
953 | return 0; | ||
954 | |||
955 | fail: | ||
956 | return -1; | ||
957 | } | ||
958 | |||
959 | static noinline_for_stack int | ||
960 | add_ioctl_entries(struct btrfs_root *root, | ||
961 | struct inode *inode, | ||
962 | struct btrfs_block_group_cache *block_group, | ||
963 | struct io_ctl *io_ctl, | ||
964 | struct extent_state **cached_state, | ||
965 | struct list_head *bitmap_list, | ||
966 | int *entries) | ||
967 | { | ||
968 | u64 start, extent_start, extent_end, len; | ||
969 | struct list_head *pos, *n; | ||
970 | struct extent_io_tree *unpin = NULL; | ||
971 | int ret; | ||
945 | 972 | ||
946 | /* | 973 | /* |
947 | * We want to add any pinned extents to our free space cache | 974 | * We want to add any pinned extents to our free space cache |
948 | * so we don't leak the space | 975 | * so we don't leak the space |
949 | */ | 976 | * |
950 | |||
951 | /* | ||
952 | * We shouldn't have switched the pinned extents yet so this is the | 977 | * We shouldn't have switched the pinned extents yet so this is the |
953 | * right one | 978 | * right one |
954 | */ | 979 | */ |
@@ -977,8 +1002,8 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, | |||
977 | block_group->key.offset, extent_end + 1); | 1002 | block_group->key.offset, extent_end + 1); |
978 | len = extent_end - extent_start; | 1003 | len = extent_end - extent_start; |
979 | 1004 | ||
980 | entries++; | 1005 | *entries += 1; |
981 | ret = io_ctl_add_entry(&io_ctl, extent_start, len, NULL); | 1006 | ret = io_ctl_add_entry(io_ctl, extent_start, len, NULL); |
982 | if (ret) | 1007 | if (ret) |
983 | goto out_nospc; | 1008 | goto out_nospc; |
984 | 1009 | ||
@@ -986,74 +1011,129 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, | |||
986 | } | 1011 | } |
987 | 1012 | ||
988 | /* Write out the bitmaps */ | 1013 | /* Write out the bitmaps */ |
989 | list_for_each_safe(pos, n, &bitmap_list) { | 1014 | list_for_each_safe(pos, n, bitmap_list) { |
990 | struct btrfs_free_space *entry = | 1015 | struct btrfs_free_space *entry = |
991 | list_entry(pos, struct btrfs_free_space, list); | 1016 | list_entry(pos, struct btrfs_free_space, list); |
992 | 1017 | ||
993 | ret = io_ctl_add_bitmap(&io_ctl, entry->bitmap); | 1018 | ret = io_ctl_add_bitmap(io_ctl, entry->bitmap); |
994 | if (ret) | 1019 | if (ret) |
995 | goto out_nospc; | 1020 | goto out_nospc; |
996 | list_del_init(&entry->list); | 1021 | list_del_init(&entry->list); |
997 | } | 1022 | } |
998 | 1023 | ||
999 | /* Zero out the rest of the pages just to make sure */ | 1024 | /* Zero out the rest of the pages just to make sure */ |
1000 | io_ctl_zero_remaining_pages(&io_ctl); | 1025 | io_ctl_zero_remaining_pages(io_ctl); |
1001 | 1026 | ||
1002 | ret = btrfs_dirty_pages(root, inode, io_ctl.pages, io_ctl.num_pages, | 1027 | ret = btrfs_dirty_pages(root, inode, io_ctl->pages, io_ctl->num_pages, |
1003 | 0, i_size_read(inode), &cached_state); | 1028 | 0, i_size_read(inode), cached_state); |
1004 | io_ctl_drop_pages(&io_ctl); | 1029 | io_ctl_drop_pages(io_ctl); |
1005 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0, | 1030 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0, |
1006 | i_size_read(inode) - 1, &cached_state, GFP_NOFS); | 1031 | i_size_read(inode) - 1, cached_state, GFP_NOFS); |
1007 | 1032 | ||
1008 | if (ret) | 1033 | if (ret) |
1009 | goto out; | 1034 | goto fail; |
1010 | 1035 | ||
1011 | ret = btrfs_wait_ordered_range(inode, 0, (u64)-1); | 1036 | ret = btrfs_wait_ordered_range(inode, 0, (u64)-1); |
1012 | if (ret) { | 1037 | if (ret) { |
1013 | clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1, | 1038 | clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1, |
1014 | EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL, | 1039 | EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL, |
1015 | GFP_NOFS); | 1040 | GFP_NOFS); |
1016 | goto out; | 1041 | goto fail; |
1017 | } | 1042 | } |
1043 | return 0; | ||
1018 | 1044 | ||
1019 | key.objectid = BTRFS_FREE_SPACE_OBJECTID; | 1045 | fail: |
1020 | key.offset = offset; | 1046 | return -1; |
1021 | key.type = 0; | ||
1022 | 1047 | ||
1023 | ret = btrfs_search_slot(trans, root, &key, path, 0, 1); | 1048 | out_nospc: |
1024 | if (ret < 0) { | 1049 | return -ENOSPC; |
1025 | clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1, | 1050 | } |
1026 | EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL, | 1051 | |
1027 | GFP_NOFS); | 1052 | static void noinline_for_stack |
1028 | goto out; | 1053 | cleanup_write_cache_enospc(struct inode *inode, |
1029 | } | 1054 | struct io_ctl *io_ctl, |
1030 | leaf = path->nodes[0]; | 1055 | struct extent_state **cached_state, |
1031 | if (ret > 0) { | 1056 | struct list_head *bitmap_list) |
1032 | struct btrfs_key found_key; | 1057 | { |
1033 | ASSERT(path->slots[0]); | 1058 | struct list_head *pos, *n; |
1034 | path->slots[0]--; | 1059 | list_for_each_safe(pos, n, bitmap_list) { |
1035 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | 1060 | struct btrfs_free_space *entry = |
1036 | if (found_key.objectid != BTRFS_FREE_SPACE_OBJECTID || | 1061 | list_entry(pos, struct btrfs_free_space, list); |
1037 | found_key.offset != offset) { | 1062 | list_del_init(&entry->list); |
1038 | clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, | ||
1039 | inode->i_size - 1, | ||
1040 | EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, | ||
1041 | NULL, GFP_NOFS); | ||
1042 | btrfs_release_path(path); | ||
1043 | goto out; | ||
1044 | } | ||
1045 | } | 1063 | } |
1064 | io_ctl_drop_pages(io_ctl); | ||
1065 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0, | ||
1066 | i_size_read(inode) - 1, cached_state, | ||
1067 | GFP_NOFS); | ||
1068 | } | ||
1046 | 1069 | ||
1047 | BTRFS_I(inode)->generation = trans->transid; | 1070 | /** |
1048 | header = btrfs_item_ptr(leaf, path->slots[0], | 1071 | * __btrfs_write_out_cache - write out cached info to an inode |
1049 | struct btrfs_free_space_header); | 1072 | * @root - the root the inode belongs to |
1050 | btrfs_set_free_space_entries(leaf, header, entries); | 1073 | * @ctl - the free space cache we are going to write out |
1051 | btrfs_set_free_space_bitmaps(leaf, header, bitmaps); | 1074 | * @block_group - the block_group for this cache if it belongs to a block_group |
1052 | btrfs_set_free_space_generation(leaf, header, trans->transid); | 1075 | * @trans - the trans handle |
1053 | btrfs_mark_buffer_dirty(leaf); | 1076 | * @path - the path to use |
1054 | btrfs_release_path(path); | 1077 | * @offset - the offset for the key we'll insert |
1078 | * | ||
1079 | * This function writes out a free space cache struct to disk for quick recovery | ||
1080 | * on mount. This will return 0 if it was successfull in writing the cache out, | ||
1081 | * and -1 if it was not. | ||
1082 | */ | ||
1083 | static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, | ||
1084 | struct btrfs_free_space_ctl *ctl, | ||
1085 | struct btrfs_block_group_cache *block_group, | ||
1086 | struct btrfs_trans_handle *trans, | ||
1087 | struct btrfs_path *path, u64 offset) | ||
1088 | { | ||
1089 | struct extent_state *cached_state = NULL; | ||
1090 | struct io_ctl io_ctl; | ||
1091 | struct list_head bitmap_list; | ||
1092 | int entries = 0; | ||
1093 | int bitmaps = 0; | ||
1094 | int ret; | ||
1095 | int err = -1; | ||
1096 | |||
1097 | INIT_LIST_HEAD(&bitmap_list); | ||
1098 | |||
1099 | if (!i_size_read(inode)) | ||
1100 | return -1; | ||
1101 | |||
1102 | ret = io_ctl_init(&io_ctl, inode, root); | ||
1103 | if (ret) | ||
1104 | return -1; | ||
1105 | |||
1106 | /* Lock all pages first so we can lock the extent safely. */ | ||
1107 | io_ctl_prepare_pages(&io_ctl, inode, 0); | ||
1108 | |||
1109 | lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1, | ||
1110 | 0, &cached_state); | ||
1111 | |||
1112 | |||
1113 | /* Make sure we can fit our crcs into the first page */ | ||
1114 | if (io_ctl.check_crcs && | ||
1115 | (io_ctl.num_pages * sizeof(u32)) >= PAGE_CACHE_SIZE) | ||
1116 | goto out_nospc; | ||
1117 | |||
1118 | io_ctl_set_generation(&io_ctl, trans->transid); | ||
1119 | |||
1120 | ret = write_cache_extent_entries(&io_ctl, ctl, | ||
1121 | block_group, &entries, &bitmaps, | ||
1122 | &bitmap_list); | ||
1123 | if (ret) | ||
1124 | goto out_nospc; | ||
1125 | |||
1126 | ret = add_ioctl_entries(root, inode, block_group, &io_ctl, | ||
1127 | &cached_state, &bitmap_list, &entries); | ||
1128 | |||
1129 | if (ret == -ENOSPC) | ||
1130 | goto out_nospc; | ||
1131 | else if (ret) | ||
1132 | goto out; | ||
1133 | |||
1134 | err = update_cache_item(trans, root, inode, path, offset, | ||
1135 | entries, bitmaps); | ||
1055 | 1136 | ||
1056 | err = 0; | ||
1057 | out: | 1137 | out: |
1058 | io_ctl_free(&io_ctl); | 1138 | io_ctl_free(&io_ctl); |
1059 | if (err) { | 1139 | if (err) { |
@@ -1064,14 +1144,8 @@ out: | |||
1064 | return err; | 1144 | return err; |
1065 | 1145 | ||
1066 | out_nospc: | 1146 | out_nospc: |
1067 | list_for_each_safe(pos, n, &bitmap_list) { | 1147 | |
1068 | struct btrfs_free_space *entry = | 1148 | cleanup_write_cache_enospc(inode, &io_ctl, &cached_state, &bitmap_list); |
1069 | list_entry(pos, struct btrfs_free_space, list); | ||
1070 | list_del_init(&entry->list); | ||
1071 | } | ||
1072 | io_ctl_drop_pages(&io_ctl); | ||
1073 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0, | ||
1074 | i_size_read(inode) - 1, &cached_state, GFP_NOFS); | ||
1075 | goto out; | 1149 | goto out; |
1076 | } | 1150 | } |
1077 | 1151 | ||