aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLiu Hui <onlyflyer@gmail.com>2009-01-05 15:57:51 -0500
committerChris Mason <chris.mason@oracle.com>2009-01-05 15:57:51 -0500
commit1f3c79a28c8837e8572b98f6d14142d9a6133c56 (patch)
tree09c7a7c46186806ec1ecd34f03780ef15e397245 /fs
parentec051c0f929afe5c42c24bb07abf577c616c208c (diff)
Btrfs: Fix free block discard calls down to the block layer
This is a patch to fix discard semantic to make Btrfs work with FTL and SSD. We can improve FTL's performance by telling it which sectors are freed by file system. But if we don't tell FTL the information of free sectors in proper time, the transaction mechanism of Btrfs will be destroyed and Btrfs could not roll back the previous transaction under the power loss condition. There are some problems in the old implementation: 1, In __free_extent(), the pinned down extents should not be discarded. 2, In free_extents(), the free extents are all pinned, so they need to be discarded in transaction committing time instead of free_extents(). 3, The reserved extent used by log tree should be discard too. This patch change discard behavior as follows: 1, For the extents which need to be free at once, we discard them in update_block_group(). 2, Delay discarding the pinned extent in btrfs_finish_extent_commit() when committing transaction. 3, Remove discarding from free_extents() and __free_extent() 4, Add discard interface into btrfs_free_reserved_extent() 5, Discard sectors before updating the free space cache, otherwise, FTL will destroy file system data.
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/extent-tree.c99
1 files changed, 48 insertions, 51 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index fe0e59ab33cc..780c1eeb8299 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -876,6 +876,38 @@ static void btrfs_issue_discard(struct block_device *bdev,
876} 876}
877#endif 877#endif
878 878
879static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
880 u64 num_bytes)
881{
882#ifdef BIO_RW_DISCARD
883 int ret;
884 u64 map_length = num_bytes;
885 struct btrfs_multi_bio *multi = NULL;
886
887 /* Tell the block device(s) that the sectors can be discarded */
888 ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
889 bytenr, &map_length, &multi, 0);
890 if (!ret) {
891 struct btrfs_bio_stripe *stripe = multi->stripes;
892 int i;
893
894 if (map_length > num_bytes)
895 map_length = num_bytes;
896
897 for (i = 0; i < multi->num_stripes; i++, stripe++) {
898 btrfs_issue_discard(stripe->dev->bdev,
899 stripe->physical,
900 map_length);
901 }
902 kfree(multi);
903 }
904
905 return ret;
906#else
907 return 0;
908#endif
909}
910
879static int noinline free_extents(struct btrfs_trans_handle *trans, 911static int noinline free_extents(struct btrfs_trans_handle *trans,
880 struct btrfs_root *extent_root, 912 struct btrfs_root *extent_root,
881 struct list_head *del_list) 913 struct list_head *del_list)
@@ -1069,10 +1101,6 @@ search:
1069 for (pos = cur, n = pos->next; pos != end; 1101 for (pos = cur, n = pos->next; pos != end;
1070 pos = n, n = pos->next) { 1102 pos = n, n = pos->next) {
1071 struct pending_extent_op *tmp; 1103 struct pending_extent_op *tmp;
1072#ifdef BIO_RW_DISCARD
1073 u64 map_length;
1074 struct btrfs_multi_bio *multi = NULL;
1075#endif
1076 tmp = list_entry(pos, struct pending_extent_op, list); 1104 tmp = list_entry(pos, struct pending_extent_op, list);
1077 1105
1078 /* 1106 /*
@@ -1084,28 +1112,6 @@ search:
1084 tmp->del); 1112 tmp->del);
1085 BUG_ON(ret); 1113 BUG_ON(ret);
1086 1114
1087#ifdef BIO_RW_DISCARD
1088 map_length = tmp->num_bytes;
1089 ret = btrfs_map_block(&info->mapping_tree, READ,
1090 tmp->bytenr, &map_length, &multi,
1091 0);
1092 if (!ret) {
1093 struct btrfs_bio_stripe *stripe;
1094 int i;
1095
1096 stripe = multi->stripes;
1097
1098 if (map_length > tmp->num_bytes)
1099 map_length = tmp->num_bytes;
1100
1101 for (i = 0; i < multi->num_stripes;
1102 i++, stripe++)
1103 btrfs_issue_discard(stripe->dev->bdev,
1104 stripe->physical,
1105 map_length);
1106 kfree(multi);
1107 }
1108#endif
1109 list_del_init(&tmp->list); 1115 list_del_init(&tmp->list);
1110 unlock_extent(&info->extent_ins, tmp->bytenr, 1116 unlock_extent(&info->extent_ins, tmp->bytenr,
1111 tmp->bytenr + tmp->num_bytes - 1, 1117 tmp->bytenr + tmp->num_bytes - 1,
@@ -1965,6 +1971,11 @@ static int update_block_group(struct btrfs_trans_handle *trans,
1965 spin_unlock(&cache->space_info->lock); 1971 spin_unlock(&cache->space_info->lock);
1966 if (mark_free) { 1972 if (mark_free) {
1967 int ret; 1973 int ret;
1974
1975 ret = btrfs_discard_extent(root, bytenr,
1976 num_bytes);
1977 WARN_ON(ret);
1978
1968 ret = btrfs_add_free_space(cache, bytenr, 1979 ret = btrfs_add_free_space(cache, bytenr,
1969 num_bytes); 1980 num_bytes);
1970 WARN_ON(ret); 1981 WARN_ON(ret);
@@ -2104,8 +2115,12 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
2104 EXTENT_DIRTY); 2115 EXTENT_DIRTY);
2105 if (ret) 2116 if (ret)
2106 break; 2117 break;
2118
2119 ret = btrfs_discard_extent(root, start, end + 1 - start);
2120
2107 btrfs_update_pinned_extents(root, start, end + 1 - start, 0); 2121 btrfs_update_pinned_extents(root, start, end + 1 - start, 0);
2108 clear_extent_dirty(unpin, start, end, GFP_NOFS); 2122 clear_extent_dirty(unpin, start, end, GFP_NOFS);
2123
2109 if (need_resched()) { 2124 if (need_resched()) {
2110 mutex_unlock(&root->fs_info->pinned_mutex); 2125 mutex_unlock(&root->fs_info->pinned_mutex);
2111 cond_resched(); 2126 cond_resched();
@@ -2113,7 +2128,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
2113 } 2128 }
2114 } 2129 }
2115 mutex_unlock(&root->fs_info->pinned_mutex); 2130 mutex_unlock(&root->fs_info->pinned_mutex);
2116 return 0; 2131 return ret;
2117} 2132}
2118 2133
2119static int finish_current_insert(struct btrfs_trans_handle *trans, 2134static int finish_current_insert(struct btrfs_trans_handle *trans,
@@ -2458,10 +2473,6 @@ static int __free_extent(struct btrfs_trans_handle *trans,
2458 if (refs == 0) { 2473 if (refs == 0) {
2459 u64 super_used; 2474 u64 super_used;
2460 u64 root_used; 2475 u64 root_used;
2461#ifdef BIO_RW_DISCARD
2462 u64 map_length = num_bytes;
2463 struct btrfs_multi_bio *multi = NULL;
2464#endif
2465 2476
2466 if (pin) { 2477 if (pin) {
2467 mutex_lock(&root->fs_info->pinned_mutex); 2478 mutex_lock(&root->fs_info->pinned_mutex);
@@ -2496,25 +2507,6 @@ static int __free_extent(struct btrfs_trans_handle *trans,
2496 ret = update_block_group(trans, root, bytenr, num_bytes, 0, 2507 ret = update_block_group(trans, root, bytenr, num_bytes, 0,
2497 mark_free); 2508 mark_free);
2498 BUG_ON(ret); 2509 BUG_ON(ret);
2499#ifdef BIO_RW_DISCARD
2500 /* Tell the block device(s) that the sectors can be discarded */
2501 ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
2502 bytenr, &map_length, &multi, 0);
2503 if (!ret) {
2504 struct btrfs_bio_stripe *stripe = multi->stripes;
2505 int i;
2506
2507 if (map_length > num_bytes)
2508 map_length = num_bytes;
2509
2510 for (i = 0; i < multi->num_stripes; i++, stripe++) {
2511 btrfs_issue_discard(stripe->dev->bdev,
2512 stripe->physical,
2513 map_length);
2514 }
2515 kfree(multi);
2516 }
2517#endif
2518 } 2510 }
2519 btrfs_free_path(path); 2511 btrfs_free_path(path);
2520 finish_current_insert(trans, extent_root, 0); 2512 finish_current_insert(trans, extent_root, 0);
@@ -3112,16 +3104,21 @@ again:
3112int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len) 3104int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len)
3113{ 3105{
3114 struct btrfs_block_group_cache *cache; 3106 struct btrfs_block_group_cache *cache;
3107 int ret = 0;
3115 3108
3116 cache = btrfs_lookup_block_group(root->fs_info, start); 3109 cache = btrfs_lookup_block_group(root->fs_info, start);
3117 if (!cache) { 3110 if (!cache) {
3118 printk(KERN_ERR "Unable to find block group for %Lu\n", start); 3111 printk(KERN_ERR "Unable to find block group for %Lu\n", start);
3119 return -ENOSPC; 3112 return -ENOSPC;
3120 } 3113 }
3114
3115 ret = btrfs_discard_extent(root, start, len);
3116
3121 btrfs_add_free_space(cache, start, len); 3117 btrfs_add_free_space(cache, start, len);
3122 put_block_group(cache); 3118 put_block_group(cache);
3123 update_reserved_extents(root, start, len, 0); 3119 update_reserved_extents(root, start, len, 0);
3124 return 0; 3120
3121 return ret;
3125} 3122}
3126 3123
3127int btrfs_reserve_extent(struct btrfs_trans_handle *trans, 3124int btrfs_reserve_extent(struct btrfs_trans_handle *trans,