diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.h | 5 | ||||
-rw-r--r-- | fs/btrfs/file.c | 44 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 87 | ||||
-rw-r--r-- | fs/btrfs/tree-log.c | 24 |
4 files changed, 114 insertions, 46 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 5be778e62a29..f52a60b9eba5 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -3772,7 +3772,10 @@ extern const struct file_operations btrfs_file_operations; | |||
3772 | int __btrfs_drop_extents(struct btrfs_trans_handle *trans, | 3772 | int __btrfs_drop_extents(struct btrfs_trans_handle *trans, |
3773 | struct btrfs_root *root, struct inode *inode, | 3773 | struct btrfs_root *root, struct inode *inode, |
3774 | struct btrfs_path *path, u64 start, u64 end, | 3774 | struct btrfs_path *path, u64 start, u64 end, |
3775 | u64 *drop_end, int drop_cache); | 3775 | u64 *drop_end, int drop_cache, |
3776 | int replace_extent, | ||
3777 | u32 extent_item_size, | ||
3778 | int *key_inserted); | ||
3776 | int btrfs_drop_extents(struct btrfs_trans_handle *trans, | 3779 | int btrfs_drop_extents(struct btrfs_trans_handle *trans, |
3777 | struct btrfs_root *root, struct inode *inode, u64 start, | 3780 | struct btrfs_root *root, struct inode *inode, u64 start, |
3778 | u64 end, int drop_cache); | 3781 | u64 end, int drop_cache); |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 35bf83876f3f..030012e1710c 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -692,7 +692,10 @@ next: | |||
692 | int __btrfs_drop_extents(struct btrfs_trans_handle *trans, | 692 | int __btrfs_drop_extents(struct btrfs_trans_handle *trans, |
693 | struct btrfs_root *root, struct inode *inode, | 693 | struct btrfs_root *root, struct inode *inode, |
694 | struct btrfs_path *path, u64 start, u64 end, | 694 | struct btrfs_path *path, u64 start, u64 end, |
695 | u64 *drop_end, int drop_cache) | 695 | u64 *drop_end, int drop_cache, |
696 | int replace_extent, | ||
697 | u32 extent_item_size, | ||
698 | int *key_inserted) | ||
696 | { | 699 | { |
697 | struct extent_buffer *leaf; | 700 | struct extent_buffer *leaf; |
698 | struct btrfs_file_extent_item *fi; | 701 | struct btrfs_file_extent_item *fi; |
@@ -712,6 +715,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, | |||
712 | int modify_tree = -1; | 715 | int modify_tree = -1; |
713 | int update_refs = (root->ref_cows || root == root->fs_info->tree_root); | 716 | int update_refs = (root->ref_cows || root == root->fs_info->tree_root); |
714 | int found = 0; | 717 | int found = 0; |
718 | int leafs_visited = 0; | ||
715 | 719 | ||
716 | if (drop_cache) | 720 | if (drop_cache) |
717 | btrfs_drop_extent_cache(inode, start, end - 1, 0); | 721 | btrfs_drop_extent_cache(inode, start, end - 1, 0); |
@@ -733,6 +737,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, | |||
733 | path->slots[0]--; | 737 | path->slots[0]--; |
734 | } | 738 | } |
735 | ret = 0; | 739 | ret = 0; |
740 | leafs_visited++; | ||
736 | next_slot: | 741 | next_slot: |
737 | leaf = path->nodes[0]; | 742 | leaf = path->nodes[0]; |
738 | if (path->slots[0] >= btrfs_header_nritems(leaf)) { | 743 | if (path->slots[0] >= btrfs_header_nritems(leaf)) { |
@@ -744,6 +749,7 @@ next_slot: | |||
744 | ret = 0; | 749 | ret = 0; |
745 | break; | 750 | break; |
746 | } | 751 | } |
752 | leafs_visited++; | ||
747 | leaf = path->nodes[0]; | 753 | leaf = path->nodes[0]; |
748 | recow = 1; | 754 | recow = 1; |
749 | } | 755 | } |
@@ -927,14 +933,44 @@ next_slot: | |||
927 | } | 933 | } |
928 | 934 | ||
929 | if (!ret && del_nr > 0) { | 935 | if (!ret && del_nr > 0) { |
936 | /* | ||
937 | * Set path->slots[0] to first slot, so that after the delete | ||
938 | * if items are move off from our leaf to its immediate left or | ||
939 | * right neighbor leafs, we end up with a correct and adjusted | ||
940 | * path->slots[0] for our insertion. | ||
941 | */ | ||
942 | path->slots[0] = del_slot; | ||
930 | ret = btrfs_del_items(trans, root, path, del_slot, del_nr); | 943 | ret = btrfs_del_items(trans, root, path, del_slot, del_nr); |
931 | if (ret) | 944 | if (ret) |
932 | btrfs_abort_transaction(trans, root, ret); | 945 | btrfs_abort_transaction(trans, root, ret); |
946 | |||
947 | leaf = path->nodes[0]; | ||
948 | /* | ||
949 | * leaf eb has flag EXTENT_BUFFER_STALE if it was deleted (that | ||
950 | * is, its contents got pushed to its neighbors), in which case | ||
951 | * it means path->locks[0] == 0 | ||
952 | */ | ||
953 | if (!ret && replace_extent && leafs_visited == 1 && | ||
954 | path->locks[0] && | ||
955 | btrfs_leaf_free_space(root, leaf) >= | ||
956 | sizeof(struct btrfs_item) + extent_item_size) { | ||
957 | |||
958 | key.objectid = ino; | ||
959 | key.type = BTRFS_EXTENT_DATA_KEY; | ||
960 | key.offset = start; | ||
961 | setup_items_for_insert(root, path, &key, | ||
962 | &extent_item_size, | ||
963 | extent_item_size, | ||
964 | sizeof(struct btrfs_item) + | ||
965 | extent_item_size, 1); | ||
966 | *key_inserted = 1; | ||
967 | } | ||
933 | } | 968 | } |
934 | 969 | ||
970 | if (!replace_extent || !(*key_inserted)) | ||
971 | btrfs_release_path(path); | ||
935 | if (drop_end) | 972 | if (drop_end) |
936 | *drop_end = found ? min(end, extent_end) : end; | 973 | *drop_end = found ? min(end, extent_end) : end; |
937 | btrfs_release_path(path); | ||
938 | return ret; | 974 | return ret; |
939 | } | 975 | } |
940 | 976 | ||
@@ -949,7 +985,7 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, | |||
949 | if (!path) | 985 | if (!path) |
950 | return -ENOMEM; | 986 | return -ENOMEM; |
951 | ret = __btrfs_drop_extents(trans, root, inode, path, start, end, NULL, | 987 | ret = __btrfs_drop_extents(trans, root, inode, path, start, end, NULL, |
952 | drop_cache); | 988 | drop_cache, 0, 0, NULL); |
953 | btrfs_free_path(path); | 989 | btrfs_free_path(path); |
954 | return ret; | 990 | return ret; |
955 | } | 991 | } |
@@ -2219,7 +2255,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) | |||
2219 | while (cur_offset < lockend) { | 2255 | while (cur_offset < lockend) { |
2220 | ret = __btrfs_drop_extents(trans, root, inode, path, | 2256 | ret = __btrfs_drop_extents(trans, root, inode, path, |
2221 | cur_offset, lockend + 1, | 2257 | cur_offset, lockend + 1, |
2222 | &drop_end, 1); | 2258 | &drop_end, 1, 0, 0, NULL); |
2223 | if (ret != -ENOSPC) | 2259 | if (ret != -ENOSPC) |
2224 | break; | 2260 | break; |
2225 | 2261 | ||
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index ffb23e506762..23f18eb5fb55 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -125,13 +125,12 @@ static int btrfs_init_inode_security(struct btrfs_trans_handle *trans, | |||
125 | * no overlapping inline items exist in the btree | 125 | * no overlapping inline items exist in the btree |
126 | */ | 126 | */ |
127 | static noinline int insert_inline_extent(struct btrfs_trans_handle *trans, | 127 | static noinline int insert_inline_extent(struct btrfs_trans_handle *trans, |
128 | struct btrfs_path *path, int extent_inserted, | ||
128 | struct btrfs_root *root, struct inode *inode, | 129 | struct btrfs_root *root, struct inode *inode, |
129 | u64 start, size_t size, size_t compressed_size, | 130 | u64 start, size_t size, size_t compressed_size, |
130 | int compress_type, | 131 | int compress_type, |
131 | struct page **compressed_pages) | 132 | struct page **compressed_pages) |
132 | { | 133 | { |
133 | struct btrfs_key key; | ||
134 | struct btrfs_path *path; | ||
135 | struct extent_buffer *leaf; | 134 | struct extent_buffer *leaf; |
136 | struct page *page = NULL; | 135 | struct page *page = NULL; |
137 | char *kaddr; | 136 | char *kaddr; |
@@ -140,29 +139,29 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans, | |||
140 | int err = 0; | 139 | int err = 0; |
141 | int ret; | 140 | int ret; |
142 | size_t cur_size = size; | 141 | size_t cur_size = size; |
143 | size_t datasize; | ||
144 | unsigned long offset; | 142 | unsigned long offset; |
145 | 143 | ||
146 | if (compressed_size && compressed_pages) | 144 | if (compressed_size && compressed_pages) |
147 | cur_size = compressed_size; | 145 | cur_size = compressed_size; |
148 | 146 | ||
149 | path = btrfs_alloc_path(); | 147 | inode_add_bytes(inode, size); |
150 | if (!path) | ||
151 | return -ENOMEM; | ||
152 | 148 | ||
153 | path->leave_spinning = 1; | 149 | if (!extent_inserted) { |
150 | struct btrfs_key key; | ||
151 | size_t datasize; | ||
154 | 152 | ||
155 | key.objectid = btrfs_ino(inode); | 153 | key.objectid = btrfs_ino(inode); |
156 | key.offset = start; | 154 | key.offset = start; |
157 | btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY); | 155 | btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY); |
158 | datasize = btrfs_file_extent_calc_inline_size(cur_size); | ||
159 | 156 | ||
160 | inode_add_bytes(inode, size); | 157 | datasize = btrfs_file_extent_calc_inline_size(cur_size); |
161 | ret = btrfs_insert_empty_item(trans, root, path, &key, | 158 | path->leave_spinning = 1; |
162 | datasize); | 159 | ret = btrfs_insert_empty_item(trans, root, path, &key, |
163 | if (ret) { | 160 | datasize); |
164 | err = ret; | 161 | if (ret) { |
165 | goto fail; | 162 | err = ret; |
163 | goto fail; | ||
164 | } | ||
166 | } | 165 | } |
167 | leaf = path->nodes[0]; | 166 | leaf = path->nodes[0]; |
168 | ei = btrfs_item_ptr(leaf, path->slots[0], | 167 | ei = btrfs_item_ptr(leaf, path->slots[0], |
@@ -203,7 +202,7 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans, | |||
203 | page_cache_release(page); | 202 | page_cache_release(page); |
204 | } | 203 | } |
205 | btrfs_mark_buffer_dirty(leaf); | 204 | btrfs_mark_buffer_dirty(leaf); |
206 | btrfs_free_path(path); | 205 | btrfs_release_path(path); |
207 | 206 | ||
208 | /* | 207 | /* |
209 | * we're an inline extent, so nobody can | 208 | * we're an inline extent, so nobody can |
@@ -219,7 +218,6 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans, | |||
219 | 218 | ||
220 | return ret; | 219 | return ret; |
221 | fail: | 220 | fail: |
222 | btrfs_free_path(path); | ||
223 | return err; | 221 | return err; |
224 | } | 222 | } |
225 | 223 | ||
@@ -242,6 +240,9 @@ static noinline int cow_file_range_inline(struct btrfs_root *root, | |||
242 | u64 aligned_end = ALIGN(end, root->sectorsize); | 240 | u64 aligned_end = ALIGN(end, root->sectorsize); |
243 | u64 data_len = inline_len; | 241 | u64 data_len = inline_len; |
244 | int ret; | 242 | int ret; |
243 | struct btrfs_path *path; | ||
244 | int extent_inserted = 0; | ||
245 | u32 extent_item_size; | ||
245 | 246 | ||
246 | if (compressed_size) | 247 | if (compressed_size) |
247 | data_len = compressed_size; | 248 | data_len = compressed_size; |
@@ -256,12 +257,27 @@ static noinline int cow_file_range_inline(struct btrfs_root *root, | |||
256 | return 1; | 257 | return 1; |
257 | } | 258 | } |
258 | 259 | ||
260 | path = btrfs_alloc_path(); | ||
261 | if (!path) | ||
262 | return -ENOMEM; | ||
263 | |||
259 | trans = btrfs_join_transaction(root); | 264 | trans = btrfs_join_transaction(root); |
260 | if (IS_ERR(trans)) | 265 | if (IS_ERR(trans)) { |
266 | btrfs_free_path(path); | ||
261 | return PTR_ERR(trans); | 267 | return PTR_ERR(trans); |
268 | } | ||
262 | trans->block_rsv = &root->fs_info->delalloc_block_rsv; | 269 | trans->block_rsv = &root->fs_info->delalloc_block_rsv; |
263 | 270 | ||
264 | ret = btrfs_drop_extents(trans, root, inode, start, aligned_end, 1); | 271 | if (compressed_size && compressed_pages) |
272 | extent_item_size = btrfs_file_extent_calc_inline_size( | ||
273 | compressed_size); | ||
274 | else | ||
275 | extent_item_size = btrfs_file_extent_calc_inline_size( | ||
276 | inline_len); | ||
277 | |||
278 | ret = __btrfs_drop_extents(trans, root, inode, path, | ||
279 | start, aligned_end, NULL, | ||
280 | 1, 1, extent_item_size, &extent_inserted); | ||
265 | if (ret) { | 281 | if (ret) { |
266 | btrfs_abort_transaction(trans, root, ret); | 282 | btrfs_abort_transaction(trans, root, ret); |
267 | goto out; | 283 | goto out; |
@@ -269,7 +285,8 @@ static noinline int cow_file_range_inline(struct btrfs_root *root, | |||
269 | 285 | ||
270 | if (isize > actual_end) | 286 | if (isize > actual_end) |
271 | inline_len = min_t(u64, isize, actual_end); | 287 | inline_len = min_t(u64, isize, actual_end); |
272 | ret = insert_inline_extent(trans, root, inode, start, | 288 | ret = insert_inline_extent(trans, path, extent_inserted, |
289 | root, inode, start, | ||
273 | inline_len, compressed_size, | 290 | inline_len, compressed_size, |
274 | compress_type, compressed_pages); | 291 | compress_type, compressed_pages); |
275 | if (ret && ret != -ENOSPC) { | 292 | if (ret && ret != -ENOSPC) { |
@@ -284,6 +301,7 @@ static noinline int cow_file_range_inline(struct btrfs_root *root, | |||
284 | btrfs_delalloc_release_metadata(inode, end + 1 - start); | 301 | btrfs_delalloc_release_metadata(inode, end + 1 - start); |
285 | btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0); | 302 | btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0); |
286 | out: | 303 | out: |
304 | btrfs_free_path(path); | ||
287 | btrfs_end_transaction(trans, root); | 305 | btrfs_end_transaction(trans, root); |
288 | return ret; | 306 | return ret; |
289 | } | 307 | } |
@@ -1841,14 +1859,13 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, | |||
1841 | struct btrfs_path *path; | 1859 | struct btrfs_path *path; |
1842 | struct extent_buffer *leaf; | 1860 | struct extent_buffer *leaf; |
1843 | struct btrfs_key ins; | 1861 | struct btrfs_key ins; |
1862 | int extent_inserted = 0; | ||
1844 | int ret; | 1863 | int ret; |
1845 | 1864 | ||
1846 | path = btrfs_alloc_path(); | 1865 | path = btrfs_alloc_path(); |
1847 | if (!path) | 1866 | if (!path) |
1848 | return -ENOMEM; | 1867 | return -ENOMEM; |
1849 | 1868 | ||
1850 | path->leave_spinning = 1; | ||
1851 | |||
1852 | /* | 1869 | /* |
1853 | * we may be replacing one extent in the tree with another. | 1870 | * we may be replacing one extent in the tree with another. |
1854 | * The new extent is pinned in the extent map, and we don't want | 1871 | * The new extent is pinned in the extent map, and we don't want |
@@ -1858,17 +1875,23 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, | |||
1858 | * the caller is expected to unpin it and allow it to be merged | 1875 | * the caller is expected to unpin it and allow it to be merged |
1859 | * with the others. | 1876 | * with the others. |
1860 | */ | 1877 | */ |
1861 | ret = btrfs_drop_extents(trans, root, inode, file_pos, | 1878 | ret = __btrfs_drop_extents(trans, root, inode, path, file_pos, |
1862 | file_pos + num_bytes, 0); | 1879 | file_pos + num_bytes, NULL, 0, |
1880 | 1, sizeof(*fi), &extent_inserted); | ||
1863 | if (ret) | 1881 | if (ret) |
1864 | goto out; | 1882 | goto out; |
1865 | 1883 | ||
1866 | ins.objectid = btrfs_ino(inode); | 1884 | if (!extent_inserted) { |
1867 | ins.offset = file_pos; | 1885 | ins.objectid = btrfs_ino(inode); |
1868 | ins.type = BTRFS_EXTENT_DATA_KEY; | 1886 | ins.offset = file_pos; |
1869 | ret = btrfs_insert_empty_item(trans, root, path, &ins, sizeof(*fi)); | 1887 | ins.type = BTRFS_EXTENT_DATA_KEY; |
1870 | if (ret) | 1888 | |
1871 | goto out; | 1889 | path->leave_spinning = 1; |
1890 | ret = btrfs_insert_empty_item(trans, root, path, &ins, | ||
1891 | sizeof(*fi)); | ||
1892 | if (ret) | ||
1893 | goto out; | ||
1894 | } | ||
1872 | leaf = path->nodes[0]; | 1895 | leaf = path->nodes[0]; |
1873 | fi = btrfs_item_ptr(leaf, path->slots[0], | 1896 | fi = btrfs_item_ptr(leaf, path->slots[0], |
1874 | struct btrfs_file_extent_item); | 1897 | struct btrfs_file_extent_item); |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index ba2f15109dac..b561e7a4007d 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -3495,21 +3495,27 @@ static int log_one_extent(struct btrfs_trans_handle *trans, | |||
3495 | int ret; | 3495 | int ret; |
3496 | int index = log->log_transid % 2; | 3496 | int index = log->log_transid % 2; |
3497 | bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | 3497 | bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; |
3498 | 3498 | int extent_inserted = 0; | |
3499 | ret = __btrfs_drop_extents(trans, log, inode, path, em->start, | ||
3500 | em->start + em->len, NULL, 0); | ||
3501 | if (ret) | ||
3502 | return ret; | ||
3503 | 3499 | ||
3504 | INIT_LIST_HEAD(&ordered_sums); | 3500 | INIT_LIST_HEAD(&ordered_sums); |
3505 | btrfs_init_map_token(&token); | 3501 | btrfs_init_map_token(&token); |
3506 | key.objectid = btrfs_ino(inode); | ||
3507 | key.type = BTRFS_EXTENT_DATA_KEY; | ||
3508 | key.offset = em->start; | ||
3509 | 3502 | ||
3510 | ret = btrfs_insert_empty_item(trans, log, path, &key, sizeof(*fi)); | 3503 | ret = __btrfs_drop_extents(trans, log, inode, path, em->start, |
3504 | em->start + em->len, NULL, 0, 1, | ||
3505 | sizeof(*fi), &extent_inserted); | ||
3511 | if (ret) | 3506 | if (ret) |
3512 | return ret; | 3507 | return ret; |
3508 | |||
3509 | if (!extent_inserted) { | ||
3510 | key.objectid = btrfs_ino(inode); | ||
3511 | key.type = BTRFS_EXTENT_DATA_KEY; | ||
3512 | key.offset = em->start; | ||
3513 | |||
3514 | ret = btrfs_insert_empty_item(trans, log, path, &key, | ||
3515 | sizeof(*fi)); | ||
3516 | if (ret) | ||
3517 | return ret; | ||
3518 | } | ||
3513 | leaf = path->nodes[0]; | 3519 | leaf = path->nodes[0]; |
3514 | fi = btrfs_item_ptr(leaf, path->slots[0], | 3520 | fi = btrfs_item_ptr(leaf, path->slots[0], |
3515 | struct btrfs_file_extent_item); | 3521 | struct btrfs_file_extent_item); |