diff options
-rw-r--r-- | fs/btrfs/ctree.h | 2 | ||||
-rw-r--r-- | fs/btrfs/extent_map.c | 50 | ||||
-rw-r--r-- | fs/btrfs/extent_map.h | 1 | ||||
-rw-r--r-- | fs/btrfs/file.c | 8 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 25 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 5 | ||||
-rw-r--r-- | fs/btrfs/tree-log.c | 2 |
7 files changed, 80 insertions, 13 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 38eeb6c49c8a..1ceab8b4d6dc 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -2292,7 +2292,7 @@ extern struct file_operations btrfs_file_operations; | |||
2292 | int btrfs_drop_extents(struct btrfs_trans_handle *trans, | 2292 | int btrfs_drop_extents(struct btrfs_trans_handle *trans, |
2293 | struct btrfs_root *root, struct inode *inode, | 2293 | struct btrfs_root *root, struct inode *inode, |
2294 | u64 start, u64 end, u64 locked_end, | 2294 | u64 start, u64 end, u64 locked_end, |
2295 | u64 inline_limit, u64 *hint_block); | 2295 | u64 inline_limit, u64 *hint_block, int drop_cache); |
2296 | int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, | 2296 | int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, |
2297 | struct btrfs_root *root, | 2297 | struct btrfs_root *root, |
2298 | struct inode *inode, u64 start, u64 end); | 2298 | struct inode *inode, u64 start, u64 end); |
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 72e9fa3c31f5..5bc7a0d325e7 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
@@ -198,6 +198,56 @@ static int mergable_maps(struct extent_map *prev, struct extent_map *next) | |||
198 | return 0; | 198 | return 0; |
199 | } | 199 | } |
200 | 200 | ||
201 | int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len) | ||
202 | { | ||
203 | int ret = 0; | ||
204 | struct extent_map *merge = NULL; | ||
205 | struct rb_node *rb; | ||
206 | struct extent_map *em; | ||
207 | |||
208 | write_lock(&tree->lock); | ||
209 | em = lookup_extent_mapping(tree, start, len); | ||
210 | |||
211 | WARN_ON(em->start != start || !em); | ||
212 | |||
213 | if (!em) | ||
214 | goto out; | ||
215 | |||
216 | clear_bit(EXTENT_FLAG_PINNED, &em->flags); | ||
217 | |||
218 | if (em->start != 0) { | ||
219 | rb = rb_prev(&em->rb_node); | ||
220 | if (rb) | ||
221 | merge = rb_entry(rb, struct extent_map, rb_node); | ||
222 | if (rb && mergable_maps(merge, em)) { | ||
223 | em->start = merge->start; | ||
224 | em->len += merge->len; | ||
225 | em->block_len += merge->block_len; | ||
226 | em->block_start = merge->block_start; | ||
227 | merge->in_tree = 0; | ||
228 | rb_erase(&merge->rb_node, &tree->map); | ||
229 | free_extent_map(merge); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | rb = rb_next(&em->rb_node); | ||
234 | if (rb) | ||
235 | merge = rb_entry(rb, struct extent_map, rb_node); | ||
236 | if (rb && mergable_maps(em, merge)) { | ||
237 | em->len += merge->len; | ||
238 | em->block_len += merge->len; | ||
239 | rb_erase(&merge->rb_node, &tree->map); | ||
240 | merge->in_tree = 0; | ||
241 | free_extent_map(merge); | ||
242 | } | ||
243 | |||
244 | free_extent_map(em); | ||
245 | out: | ||
246 | write_unlock(&tree->lock); | ||
247 | return ret; | ||
248 | |||
249 | } | ||
250 | |||
201 | /** | 251 | /** |
202 | * add_extent_mapping - add new extent map to the extent tree | 252 | * add_extent_mapping - add new extent map to the extent tree |
203 | * @tree: tree to insert new map in | 253 | * @tree: tree to insert new map in |
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index 6216dfbcf9be..d3d442f4bbbd 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h | |||
@@ -59,4 +59,5 @@ struct extent_map *alloc_extent_map(gfp_t mask); | |||
59 | void free_extent_map(struct extent_map *em); | 59 | void free_extent_map(struct extent_map *em); |
60 | int __init extent_map_init(void); | 60 | int __init extent_map_init(void); |
61 | void extent_map_exit(void); | 61 | void extent_map_exit(void); |
62 | int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len); | ||
62 | #endif | 63 | #endif |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index ef66c3d989b9..4123db9d5141 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -177,10 +177,10 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, | |||
177 | } | 177 | } |
178 | flags = em->flags; | 178 | flags = em->flags; |
179 | if (skip_pinned && test_bit(EXTENT_FLAG_PINNED, &em->flags)) { | 179 | if (skip_pinned && test_bit(EXTENT_FLAG_PINNED, &em->flags)) { |
180 | write_unlock(&em_tree->lock); | ||
181 | if (em->start <= start && | 180 | if (em->start <= start && |
182 | (!testend || em->start + em->len >= start + len)) { | 181 | (!testend || em->start + em->len >= start + len)) { |
183 | free_extent_map(em); | 182 | free_extent_map(em); |
183 | write_unlock(&em_tree->lock); | ||
184 | break; | 184 | break; |
185 | } | 185 | } |
186 | if (start < em->start) { | 186 | if (start < em->start) { |
@@ -190,6 +190,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, | |||
190 | start = em->start + em->len; | 190 | start = em->start + em->len; |
191 | } | 191 | } |
192 | free_extent_map(em); | 192 | free_extent_map(em); |
193 | write_unlock(&em_tree->lock); | ||
193 | continue; | 194 | continue; |
194 | } | 195 | } |
195 | compressed = test_bit(EXTENT_FLAG_COMPRESSED, &em->flags); | 196 | compressed = test_bit(EXTENT_FLAG_COMPRESSED, &em->flags); |
@@ -269,7 +270,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, | |||
269 | noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans, | 270 | noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans, |
270 | struct btrfs_root *root, struct inode *inode, | 271 | struct btrfs_root *root, struct inode *inode, |
271 | u64 start, u64 end, u64 locked_end, | 272 | u64 start, u64 end, u64 locked_end, |
272 | u64 inline_limit, u64 *hint_byte) | 273 | u64 inline_limit, u64 *hint_byte, int drop_cache) |
273 | { | 274 | { |
274 | u64 extent_end = 0; | 275 | u64 extent_end = 0; |
275 | u64 search_start = start; | 276 | u64 search_start = start; |
@@ -294,7 +295,8 @@ noinline int btrfs_drop_extents(struct btrfs_trans_handle *trans, | |||
294 | int ret; | 295 | int ret; |
295 | 296 | ||
296 | inline_limit = 0; | 297 | inline_limit = 0; |
297 | btrfs_drop_extent_cache(inode, start, end - 1, 0); | 298 | if (drop_cache) |
299 | btrfs_drop_extent_cache(inode, start, end - 1, 0); | ||
298 | 300 | ||
299 | path = btrfs_alloc_path(); | 301 | path = btrfs_alloc_path(); |
300 | if (!path) | 302 | if (!path) |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 739a245e25d6..233fe6f26120 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -232,7 +232,8 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans, | |||
232 | } | 232 | } |
233 | 233 | ||
234 | ret = btrfs_drop_extents(trans, root, inode, start, | 234 | ret = btrfs_drop_extents(trans, root, inode, start, |
235 | aligned_end, aligned_end, start, &hint_byte); | 235 | aligned_end, aligned_end, start, |
236 | &hint_byte, 1); | ||
236 | BUG_ON(ret); | 237 | BUG_ON(ret); |
237 | 238 | ||
238 | if (isize > actual_end) | 239 | if (isize > actual_end) |
@@ -241,7 +242,7 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans, | |||
241 | inline_len, compressed_size, | 242 | inline_len, compressed_size, |
242 | compressed_pages); | 243 | compressed_pages); |
243 | BUG_ON(ret); | 244 | BUG_ON(ret); |
244 | btrfs_drop_extent_cache(inode, start, aligned_end, 0); | 245 | btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0); |
245 | return 0; | 246 | return 0; |
246 | } | 247 | } |
247 | 248 | ||
@@ -1455,9 +1456,19 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, | |||
1455 | BUG_ON(!path); | 1456 | BUG_ON(!path); |
1456 | 1457 | ||
1457 | path->leave_spinning = 1; | 1458 | path->leave_spinning = 1; |
1459 | |||
1460 | /* | ||
1461 | * we may be replacing one extent in the tree with another. | ||
1462 | * The new extent is pinned in the extent map, and we don't want | ||
1463 | * to drop it from the cache until it is completely in the btree. | ||
1464 | * | ||
1465 | * So, tell btrfs_drop_extents to leave this extent in the cache. | ||
1466 | * the caller is expected to unpin it and allow it to be merged | ||
1467 | * with the others. | ||
1468 | */ | ||
1458 | ret = btrfs_drop_extents(trans, root, inode, file_pos, | 1469 | ret = btrfs_drop_extents(trans, root, inode, file_pos, |
1459 | file_pos + num_bytes, locked_end, | 1470 | file_pos + num_bytes, locked_end, |
1460 | file_pos, &hint); | 1471 | file_pos, &hint, 0); |
1461 | BUG_ON(ret); | 1472 | BUG_ON(ret); |
1462 | 1473 | ||
1463 | ins.objectid = inode->i_ino; | 1474 | ins.objectid = inode->i_ino; |
@@ -1485,7 +1496,6 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, | |||
1485 | btrfs_mark_buffer_dirty(leaf); | 1496 | btrfs_mark_buffer_dirty(leaf); |
1486 | 1497 | ||
1487 | inode_add_bytes(inode, num_bytes); | 1498 | inode_add_bytes(inode, num_bytes); |
1488 | btrfs_drop_extent_cache(inode, file_pos, file_pos + num_bytes - 1, 0); | ||
1489 | 1499 | ||
1490 | ins.objectid = disk_bytenr; | 1500 | ins.objectid = disk_bytenr; |
1491 | ins.offset = disk_num_bytes; | 1501 | ins.offset = disk_num_bytes; |
@@ -1596,6 +1606,9 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
1596 | ordered_extent->len, | 1606 | ordered_extent->len, |
1597 | compressed, 0, 0, | 1607 | compressed, 0, 0, |
1598 | BTRFS_FILE_EXTENT_REG); | 1608 | BTRFS_FILE_EXTENT_REG); |
1609 | unpin_extent_cache(&BTRFS_I(inode)->extent_tree, | ||
1610 | ordered_extent->file_offset, | ||
1611 | ordered_extent->len); | ||
1599 | BUG_ON(ret); | 1612 | BUG_ON(ret); |
1600 | } | 1613 | } |
1601 | unlock_extent(io_tree, ordered_extent->file_offset, | 1614 | unlock_extent(io_tree, ordered_extent->file_offset, |
@@ -2940,7 +2953,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t size) | |||
2940 | cur_offset, | 2953 | cur_offset, |
2941 | cur_offset + hole_size, | 2954 | cur_offset + hole_size, |
2942 | block_end, | 2955 | block_end, |
2943 | cur_offset, &hint_byte); | 2956 | cur_offset, &hint_byte, 1); |
2944 | if (err) | 2957 | if (err) |
2945 | break; | 2958 | break; |
2946 | err = btrfs_insert_file_extent(trans, root, | 2959 | err = btrfs_insert_file_extent(trans, root, |
@@ -5086,6 +5099,8 @@ static int prealloc_file_range(struct btrfs_trans_handle *trans, | |||
5086 | 0, 0, 0, | 5099 | 0, 0, 0, |
5087 | BTRFS_FILE_EXTENT_PREALLOC); | 5100 | BTRFS_FILE_EXTENT_PREALLOC); |
5088 | BUG_ON(ret); | 5101 | BUG_ON(ret); |
5102 | btrfs_drop_extent_cache(inode, cur_offset, | ||
5103 | cur_offset + ins.offset -1, 0); | ||
5089 | num_bytes -= ins.offset; | 5104 | num_bytes -= ins.offset; |
5090 | cur_offset += ins.offset; | 5105 | cur_offset += ins.offset; |
5091 | alloc_hint = ins.objectid + ins.offset; | 5106 | alloc_hint = ins.objectid + ins.offset; |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 9f4db848db10..e2d8e90259b0 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -597,9 +597,8 @@ again: | |||
597 | clear_page_dirty_for_io(page); | 597 | clear_page_dirty_for_io(page); |
598 | 598 | ||
599 | btrfs_set_extent_delalloc(inode, page_start, page_end); | 599 | btrfs_set_extent_delalloc(inode, page_start, page_end); |
600 | |||
601 | unlock_extent(io_tree, page_start, page_end, GFP_NOFS); | ||
602 | set_page_dirty(page); | 600 | set_page_dirty(page); |
601 | unlock_extent(io_tree, page_start, page_end, GFP_NOFS); | ||
603 | unlock_page(page); | 602 | unlock_page(page); |
604 | page_cache_release(page); | 603 | page_cache_release(page); |
605 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1); | 604 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1); |
@@ -977,7 +976,7 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
977 | 976 | ||
978 | /* punch hole in destination first */ | 977 | /* punch hole in destination first */ |
979 | btrfs_drop_extents(trans, root, inode, off, off + len, | 978 | btrfs_drop_extents(trans, root, inode, off, off + len, |
980 | off + len, 0, &hint_byte); | 979 | off + len, 0, &hint_byte, 1); |
981 | 980 | ||
982 | /* clone data */ | 981 | /* clone data */ |
983 | key.objectid = src->i_ino; | 982 | key.objectid = src->i_ino; |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index d91b0de7c502..8661a7381b39 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -534,7 +534,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, | |||
534 | saved_nbytes = inode_get_bytes(inode); | 534 | saved_nbytes = inode_get_bytes(inode); |
535 | /* drop any overlapping extents */ | 535 | /* drop any overlapping extents */ |
536 | ret = btrfs_drop_extents(trans, root, inode, | 536 | ret = btrfs_drop_extents(trans, root, inode, |
537 | start, extent_end, extent_end, start, &alloc_hint); | 537 | start, extent_end, extent_end, start, &alloc_hint, 1); |
538 | BUG_ON(ret); | 538 | BUG_ON(ret); |
539 | 539 | ||
540 | if (found_type == BTRFS_FILE_EXTENT_REG || | 540 | if (found_type == BTRFS_FILE_EXTENT_REG || |