diff options
-rw-r--r-- | fs/btrfs/ctree.c | 3 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 5 | ||||
-rw-r--r-- | fs/btrfs/file.c | 13 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 78 | ||||
-rw-r--r-- | fs/btrfs/send.c | 158 | ||||
-rw-r--r-- | fs/btrfs/tree-log.c | 172 |
6 files changed, 373 insertions, 56 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 316136bd6dd7..bcd0bd85e3ed 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -41,7 +41,6 @@ static void del_ptr(struct btrfs_root *root, struct btrfs_path *path, | |||
41 | int level, int slot); | 41 | int level, int slot); |
42 | static void tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, | 42 | static void tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, |
43 | struct extent_buffer *eb); | 43 | struct extent_buffer *eb); |
44 | static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path); | ||
45 | 44 | ||
46 | struct btrfs_path *btrfs_alloc_path(void) | 45 | struct btrfs_path *btrfs_alloc_path(void) |
47 | { | 46 | { |
@@ -4817,7 +4816,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
4817 | * This may release the path, and so you may lose any locks held at the | 4816 | * This may release the path, and so you may lose any locks held at the |
4818 | * time you call it. | 4817 | * time you call it. |
4819 | */ | 4818 | */ |
4820 | static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path) | 4819 | int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path) |
4821 | { | 4820 | { |
4822 | struct btrfs_key key; | 4821 | struct btrfs_key key; |
4823 | struct btrfs_disk_key found_key; | 4822 | struct btrfs_disk_key found_key; |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 54ab86127f7a..8be78f7d57e1 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -521,6 +521,7 @@ struct btrfs_super_block { | |||
521 | #define BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF (1ULL << 6) | 521 | #define BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF (1ULL << 6) |
522 | #define BTRFS_FEATURE_INCOMPAT_RAID56 (1ULL << 7) | 522 | #define BTRFS_FEATURE_INCOMPAT_RAID56 (1ULL << 7) |
523 | #define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA (1ULL << 8) | 523 | #define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA (1ULL << 8) |
524 | #define BTRFS_FEATURE_INCOMPAT_NO_HOLES (1ULL << 9) | ||
524 | 525 | ||
525 | #define BTRFS_FEATURE_COMPAT_SUPP 0ULL | 526 | #define BTRFS_FEATURE_COMPAT_SUPP 0ULL |
526 | #define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL | 527 | #define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL |
@@ -532,7 +533,8 @@ struct btrfs_super_block { | |||
532 | BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \ | 533 | BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \ |
533 | BTRFS_FEATURE_INCOMPAT_RAID56 | \ | 534 | BTRFS_FEATURE_INCOMPAT_RAID56 | \ |
534 | BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF | \ | 535 | BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF | \ |
535 | BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA) | 536 | BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA | \ |
537 | BTRFS_FEATURE_INCOMPAT_NO_HOLES) | ||
536 | 538 | ||
537 | /* | 539 | /* |
538 | * A leaf is full of items. offset and size tell us where to find | 540 | * A leaf is full of items. offset and size tell us where to find |
@@ -3399,6 +3401,7 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, | |||
3399 | } | 3401 | } |
3400 | 3402 | ||
3401 | int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); | 3403 | int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); |
3404 | int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path); | ||
3402 | int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, | 3405 | int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, |
3403 | u64 time_seq); | 3406 | u64 time_seq); |
3404 | static inline int btrfs_next_old_item(struct btrfs_root *root, | 3407 | static inline int btrfs_next_old_item(struct btrfs_root *root, |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 82d0342763c5..c77da440146a 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -1963,11 +1963,13 @@ static int fill_holes(struct btrfs_trans_handle *trans, struct inode *inode, | |||
1963 | struct btrfs_key key; | 1963 | struct btrfs_key key; |
1964 | int ret; | 1964 | int ret; |
1965 | 1965 | ||
1966 | if (btrfs_fs_incompat(root->fs_info, NO_HOLES)) | ||
1967 | goto out; | ||
1968 | |||
1966 | key.objectid = btrfs_ino(inode); | 1969 | key.objectid = btrfs_ino(inode); |
1967 | key.type = BTRFS_EXTENT_DATA_KEY; | 1970 | key.type = BTRFS_EXTENT_DATA_KEY; |
1968 | key.offset = offset; | 1971 | key.offset = offset; |
1969 | 1972 | ||
1970 | |||
1971 | ret = btrfs_search_slot(trans, root, &key, path, 0, 1); | 1973 | ret = btrfs_search_slot(trans, root, &key, path, 0, 1); |
1972 | if (ret < 0) | 1974 | if (ret < 0) |
1973 | return ret; | 1975 | return ret; |
@@ -2064,8 +2066,10 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) | |||
2064 | u64 drop_end; | 2066 | u64 drop_end; |
2065 | int ret = 0; | 2067 | int ret = 0; |
2066 | int err = 0; | 2068 | int err = 0; |
2069 | int rsv_count; | ||
2067 | bool same_page = ((offset >> PAGE_CACHE_SHIFT) == | 2070 | bool same_page = ((offset >> PAGE_CACHE_SHIFT) == |
2068 | ((offset + len - 1) >> PAGE_CACHE_SHIFT)); | 2071 | ((offset + len - 1) >> PAGE_CACHE_SHIFT)); |
2072 | bool no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES); | ||
2069 | 2073 | ||
2070 | ret = btrfs_wait_ordered_range(inode, offset, len); | 2074 | ret = btrfs_wait_ordered_range(inode, offset, len); |
2071 | if (ret) | 2075 | if (ret) |
@@ -2163,9 +2167,10 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) | |||
2163 | /* | 2167 | /* |
2164 | * 1 - update the inode | 2168 | * 1 - update the inode |
2165 | * 1 - removing the extents in the range | 2169 | * 1 - removing the extents in the range |
2166 | * 1 - adding the hole extent | 2170 | * 1 - adding the hole extent if no_holes isn't set |
2167 | */ | 2171 | */ |
2168 | trans = btrfs_start_transaction(root, 3); | 2172 | rsv_count = no_holes ? 2 : 3; |
2173 | trans = btrfs_start_transaction(root, rsv_count); | ||
2169 | if (IS_ERR(trans)) { | 2174 | if (IS_ERR(trans)) { |
2170 | err = PTR_ERR(trans); | 2175 | err = PTR_ERR(trans); |
2171 | goto out_free; | 2176 | goto out_free; |
@@ -2202,7 +2207,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) | |||
2202 | btrfs_end_transaction(trans, root); | 2207 | btrfs_end_transaction(trans, root); |
2203 | btrfs_btree_balance_dirty(root); | 2208 | btrfs_btree_balance_dirty(root); |
2204 | 2209 | ||
2205 | trans = btrfs_start_transaction(root, 3); | 2210 | trans = btrfs_start_transaction(root, rsv_count); |
2206 | if (IS_ERR(trans)) { | 2211 | if (IS_ERR(trans)) { |
2207 | ret = PTR_ERR(trans); | 2212 | ret = PTR_ERR(trans); |
2208 | trans = NULL; | 2213 | trans = NULL; |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f1a77449d032..c0c0dc8f07fa 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -4203,6 +4203,49 @@ out: | |||
4203 | return ret; | 4203 | return ret; |
4204 | } | 4204 | } |
4205 | 4205 | ||
4206 | static int maybe_insert_hole(struct btrfs_root *root, struct inode *inode, | ||
4207 | u64 offset, u64 len) | ||
4208 | { | ||
4209 | struct btrfs_trans_handle *trans; | ||
4210 | int ret; | ||
4211 | |||
4212 | /* | ||
4213 | * Still need to make sure the inode looks like it's been updated so | ||
4214 | * that any holes get logged if we fsync. | ||
4215 | */ | ||
4216 | if (btrfs_fs_incompat(root->fs_info, NO_HOLES)) { | ||
4217 | BTRFS_I(inode)->last_trans = root->fs_info->generation; | ||
4218 | BTRFS_I(inode)->last_sub_trans = root->log_transid; | ||
4219 | BTRFS_I(inode)->last_log_commit = root->last_log_commit; | ||
4220 | return 0; | ||
4221 | } | ||
4222 | |||
4223 | /* | ||
4224 | * 1 - for the one we're dropping | ||
4225 | * 1 - for the one we're adding | ||
4226 | * 1 - for updating the inode. | ||
4227 | */ | ||
4228 | trans = btrfs_start_transaction(root, 3); | ||
4229 | if (IS_ERR(trans)) | ||
4230 | return PTR_ERR(trans); | ||
4231 | |||
4232 | ret = btrfs_drop_extents(trans, root, inode, offset, offset + len, 1); | ||
4233 | if (ret) { | ||
4234 | btrfs_abort_transaction(trans, root, ret); | ||
4235 | btrfs_end_transaction(trans, root); | ||
4236 | return ret; | ||
4237 | } | ||
4238 | |||
4239 | ret = btrfs_insert_file_extent(trans, root, btrfs_ino(inode), offset, | ||
4240 | 0, 0, len, 0, len, 0, 0, 0); | ||
4241 | if (ret) | ||
4242 | btrfs_abort_transaction(trans, root, ret); | ||
4243 | else | ||
4244 | btrfs_update_inode(trans, root, inode); | ||
4245 | btrfs_end_transaction(trans, root); | ||
4246 | return ret; | ||
4247 | } | ||
4248 | |||
4206 | /* | 4249 | /* |
4207 | * This function puts in dummy file extents for the area we're creating a hole | 4250 | * This function puts in dummy file extents for the area we're creating a hole |
4208 | * for. So if we are truncating this file to a larger size we need to insert | 4251 | * for. So if we are truncating this file to a larger size we need to insert |
@@ -4211,7 +4254,6 @@ out: | |||
4211 | */ | 4254 | */ |
4212 | int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size) | 4255 | int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size) |
4213 | { | 4256 | { |
4214 | struct btrfs_trans_handle *trans; | ||
4215 | struct btrfs_root *root = BTRFS_I(inode)->root; | 4257 | struct btrfs_root *root = BTRFS_I(inode)->root; |
4216 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | 4258 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; |
4217 | struct extent_map *em = NULL; | 4259 | struct extent_map *em = NULL; |
@@ -4266,31 +4308,10 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size) | |||
4266 | struct extent_map *hole_em; | 4308 | struct extent_map *hole_em; |
4267 | hole_size = last_byte - cur_offset; | 4309 | hole_size = last_byte - cur_offset; |
4268 | 4310 | ||
4269 | trans = btrfs_start_transaction(root, 3); | 4311 | err = maybe_insert_hole(root, inode, cur_offset, |
4270 | if (IS_ERR(trans)) { | 4312 | hole_size); |
4271 | err = PTR_ERR(trans); | 4313 | if (err) |
4272 | break; | ||
4273 | } | ||
4274 | |||
4275 | err = btrfs_drop_extents(trans, root, inode, | ||
4276 | cur_offset, | ||
4277 | cur_offset + hole_size, 1); | ||
4278 | if (err) { | ||
4279 | btrfs_abort_transaction(trans, root, err); | ||
4280 | btrfs_end_transaction(trans, root); | ||
4281 | break; | ||
4282 | } | ||
4283 | |||
4284 | err = btrfs_insert_file_extent(trans, root, | ||
4285 | btrfs_ino(inode), cur_offset, 0, | ||
4286 | 0, hole_size, 0, hole_size, | ||
4287 | 0, 0, 0); | ||
4288 | if (err) { | ||
4289 | btrfs_abort_transaction(trans, root, err); | ||
4290 | btrfs_end_transaction(trans, root); | ||
4291 | break; | 4314 | break; |
4292 | } | ||
4293 | |||
4294 | btrfs_drop_extent_cache(inode, cur_offset, | 4315 | btrfs_drop_extent_cache(inode, cur_offset, |
4295 | cur_offset + hole_size - 1, 0); | 4316 | cur_offset + hole_size - 1, 0); |
4296 | hole_em = alloc_extent_map(); | 4317 | hole_em = alloc_extent_map(); |
@@ -4309,7 +4330,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size) | |||
4309 | hole_em->ram_bytes = hole_size; | 4330 | hole_em->ram_bytes = hole_size; |
4310 | hole_em->bdev = root->fs_info->fs_devices->latest_bdev; | 4331 | hole_em->bdev = root->fs_info->fs_devices->latest_bdev; |
4311 | hole_em->compress_type = BTRFS_COMPRESS_NONE; | 4332 | hole_em->compress_type = BTRFS_COMPRESS_NONE; |
4312 | hole_em->generation = trans->transid; | 4333 | hole_em->generation = root->fs_info->generation; |
4313 | 4334 | ||
4314 | while (1) { | 4335 | while (1) { |
4315 | write_lock(&em_tree->lock); | 4336 | write_lock(&em_tree->lock); |
@@ -4322,17 +4343,14 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size) | |||
4322 | hole_size - 1, 0); | 4343 | hole_size - 1, 0); |
4323 | } | 4344 | } |
4324 | free_extent_map(hole_em); | 4345 | free_extent_map(hole_em); |
4325 | next: | ||
4326 | btrfs_update_inode(trans, root, inode); | ||
4327 | btrfs_end_transaction(trans, root); | ||
4328 | } | 4346 | } |
4347 | next: | ||
4329 | free_extent_map(em); | 4348 | free_extent_map(em); |
4330 | em = NULL; | 4349 | em = NULL; |
4331 | cur_offset = last_byte; | 4350 | cur_offset = last_byte; |
4332 | if (cur_offset >= block_end) | 4351 | if (cur_offset >= block_end) |
4333 | break; | 4352 | break; |
4334 | } | 4353 | } |
4335 | |||
4336 | free_extent_map(em); | 4354 | free_extent_map(em); |
4337 | unlock_extent_cached(io_tree, hole_start, block_end - 1, &cached_state, | 4355 | unlock_extent_cached(io_tree, hole_start, block_end - 1, &cached_state, |
4338 | GFP_NOFS); | 4356 | GFP_NOFS); |
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 945d1db98f26..29803b4129fc 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c | |||
@@ -111,6 +111,7 @@ struct send_ctx { | |||
111 | int cur_inode_deleted; | 111 | int cur_inode_deleted; |
112 | u64 cur_inode_size; | 112 | u64 cur_inode_size; |
113 | u64 cur_inode_mode; | 113 | u64 cur_inode_mode; |
114 | u64 cur_inode_last_extent; | ||
114 | 115 | ||
115 | u64 send_progress; | 116 | u64 send_progress; |
116 | 117 | ||
@@ -145,6 +146,13 @@ struct name_cache_entry { | |||
145 | char name[]; | 146 | char name[]; |
146 | }; | 147 | }; |
147 | 148 | ||
149 | static int need_send_hole(struct send_ctx *sctx) | ||
150 | { | ||
151 | return (sctx->parent_root && !sctx->cur_inode_new && | ||
152 | !sctx->cur_inode_new_gen && !sctx->cur_inode_deleted && | ||
153 | S_ISREG(sctx->cur_inode_mode)); | ||
154 | } | ||
155 | |||
148 | static void fs_path_reset(struct fs_path *p) | 156 | static void fs_path_reset(struct fs_path *p) |
149 | { | 157 | { |
150 | if (p->reversed) { | 158 | if (p->reversed) { |
@@ -3752,6 +3760,39 @@ out: | |||
3752 | return ret; | 3760 | return ret; |
3753 | } | 3761 | } |
3754 | 3762 | ||
3763 | static int send_hole(struct send_ctx *sctx, u64 end) | ||
3764 | { | ||
3765 | struct fs_path *p = NULL; | ||
3766 | u64 offset = sctx->cur_inode_last_extent; | ||
3767 | u64 len; | ||
3768 | int ret = 0; | ||
3769 | |||
3770 | p = fs_path_alloc(); | ||
3771 | if (!p) | ||
3772 | return -ENOMEM; | ||
3773 | memset(sctx->read_buf, 0, BTRFS_SEND_READ_SIZE); | ||
3774 | while (offset < end) { | ||
3775 | len = min_t(u64, end - offset, BTRFS_SEND_READ_SIZE); | ||
3776 | |||
3777 | ret = begin_cmd(sctx, BTRFS_SEND_C_WRITE); | ||
3778 | if (ret < 0) | ||
3779 | break; | ||
3780 | ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, p); | ||
3781 | if (ret < 0) | ||
3782 | break; | ||
3783 | TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p); | ||
3784 | TLV_PUT_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, offset); | ||
3785 | TLV_PUT(sctx, BTRFS_SEND_A_DATA, sctx->read_buf, len); | ||
3786 | ret = send_cmd(sctx); | ||
3787 | if (ret < 0) | ||
3788 | break; | ||
3789 | offset += len; | ||
3790 | } | ||
3791 | tlv_put_failure: | ||
3792 | fs_path_free(p); | ||
3793 | return ret; | ||
3794 | } | ||
3795 | |||
3755 | static int send_write_or_clone(struct send_ctx *sctx, | 3796 | static int send_write_or_clone(struct send_ctx *sctx, |
3756 | struct btrfs_path *path, | 3797 | struct btrfs_path *path, |
3757 | struct btrfs_key *key, | 3798 | struct btrfs_key *key, |
@@ -3979,6 +4020,84 @@ out: | |||
3979 | return ret; | 4020 | return ret; |
3980 | } | 4021 | } |
3981 | 4022 | ||
4023 | static int get_last_extent(struct send_ctx *sctx, u64 offset) | ||
4024 | { | ||
4025 | struct btrfs_path *path; | ||
4026 | struct btrfs_root *root = sctx->send_root; | ||
4027 | struct btrfs_file_extent_item *fi; | ||
4028 | struct btrfs_key key; | ||
4029 | u64 extent_end; | ||
4030 | u8 type; | ||
4031 | int ret; | ||
4032 | |||
4033 | path = alloc_path_for_send(); | ||
4034 | if (!path) | ||
4035 | return -ENOMEM; | ||
4036 | |||
4037 | sctx->cur_inode_last_extent = 0; | ||
4038 | |||
4039 | key.objectid = sctx->cur_ino; | ||
4040 | key.type = BTRFS_EXTENT_DATA_KEY; | ||
4041 | key.offset = offset; | ||
4042 | ret = btrfs_search_slot_for_read(root, &key, path, 0, 1); | ||
4043 | if (ret < 0) | ||
4044 | goto out; | ||
4045 | ret = 0; | ||
4046 | btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); | ||
4047 | if (key.objectid != sctx->cur_ino || key.type != BTRFS_EXTENT_DATA_KEY) | ||
4048 | goto out; | ||
4049 | |||
4050 | fi = btrfs_item_ptr(path->nodes[0], path->slots[0], | ||
4051 | struct btrfs_file_extent_item); | ||
4052 | type = btrfs_file_extent_type(path->nodes[0], fi); | ||
4053 | if (type == BTRFS_FILE_EXTENT_INLINE) { | ||
4054 | u64 size = btrfs_file_extent_inline_len(path->nodes[0], fi); | ||
4055 | extent_end = ALIGN(key.offset + size, | ||
4056 | sctx->send_root->sectorsize); | ||
4057 | } else { | ||
4058 | extent_end = key.offset + | ||
4059 | btrfs_file_extent_num_bytes(path->nodes[0], fi); | ||
4060 | } | ||
4061 | sctx->cur_inode_last_extent = extent_end; | ||
4062 | out: | ||
4063 | btrfs_free_path(path); | ||
4064 | return ret; | ||
4065 | } | ||
4066 | |||
4067 | static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path, | ||
4068 | struct btrfs_key *key) | ||
4069 | { | ||
4070 | struct btrfs_file_extent_item *fi; | ||
4071 | u64 extent_end; | ||
4072 | u8 type; | ||
4073 | int ret = 0; | ||
4074 | |||
4075 | if (sctx->cur_ino != key->objectid || !need_send_hole(sctx)) | ||
4076 | return 0; | ||
4077 | |||
4078 | if (sctx->cur_inode_last_extent == (u64)-1) { | ||
4079 | ret = get_last_extent(sctx, key->offset - 1); | ||
4080 | if (ret) | ||
4081 | return ret; | ||
4082 | } | ||
4083 | |||
4084 | fi = btrfs_item_ptr(path->nodes[0], path->slots[0], | ||
4085 | struct btrfs_file_extent_item); | ||
4086 | type = btrfs_file_extent_type(path->nodes[0], fi); | ||
4087 | if (type == BTRFS_FILE_EXTENT_INLINE) { | ||
4088 | u64 size = btrfs_file_extent_inline_len(path->nodes[0], fi); | ||
4089 | extent_end = ALIGN(key->offset + size, | ||
4090 | sctx->send_root->sectorsize); | ||
4091 | } else { | ||
4092 | extent_end = key->offset + | ||
4093 | btrfs_file_extent_num_bytes(path->nodes[0], fi); | ||
4094 | } | ||
4095 | if (sctx->cur_inode_last_extent < key->offset) | ||
4096 | ret = send_hole(sctx, key->offset); | ||
4097 | sctx->cur_inode_last_extent = extent_end; | ||
4098 | return ret; | ||
4099 | } | ||
4100 | |||
3982 | static int process_extent(struct send_ctx *sctx, | 4101 | static int process_extent(struct send_ctx *sctx, |
3983 | struct btrfs_path *path, | 4102 | struct btrfs_path *path, |
3984 | struct btrfs_key *key) | 4103 | struct btrfs_key *key) |
@@ -3995,7 +4114,7 @@ static int process_extent(struct send_ctx *sctx, | |||
3995 | goto out; | 4114 | goto out; |
3996 | if (ret) { | 4115 | if (ret) { |
3997 | ret = 0; | 4116 | ret = 0; |
3998 | goto out; | 4117 | goto out_hole; |
3999 | } | 4118 | } |
4000 | } else { | 4119 | } else { |
4001 | struct btrfs_file_extent_item *ei; | 4120 | struct btrfs_file_extent_item *ei; |
@@ -4031,7 +4150,10 @@ static int process_extent(struct send_ctx *sctx, | |||
4031 | goto out; | 4150 | goto out; |
4032 | 4151 | ||
4033 | ret = send_write_or_clone(sctx, path, key, found_clone); | 4152 | ret = send_write_or_clone(sctx, path, key, found_clone); |
4034 | 4153 | if (ret) | |
4154 | goto out; | ||
4155 | out_hole: | ||
4156 | ret = maybe_send_hole(sctx, path, key); | ||
4035 | out: | 4157 | out: |
4036 | return ret; | 4158 | return ret; |
4037 | } | 4159 | } |
@@ -4157,6 +4279,19 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end) | |||
4157 | } | 4279 | } |
4158 | 4280 | ||
4159 | if (S_ISREG(sctx->cur_inode_mode)) { | 4281 | if (S_ISREG(sctx->cur_inode_mode)) { |
4282 | if (need_send_hole(sctx)) { | ||
4283 | if (sctx->cur_inode_last_extent == (u64)-1) { | ||
4284 | ret = get_last_extent(sctx, (u64)-1); | ||
4285 | if (ret) | ||
4286 | goto out; | ||
4287 | } | ||
4288 | if (sctx->cur_inode_last_extent < | ||
4289 | sctx->cur_inode_size) { | ||
4290 | ret = send_hole(sctx, sctx->cur_inode_size); | ||
4291 | if (ret) | ||
4292 | goto out; | ||
4293 | } | ||
4294 | } | ||
4160 | ret = send_truncate(sctx, sctx->cur_ino, sctx->cur_inode_gen, | 4295 | ret = send_truncate(sctx, sctx->cur_ino, sctx->cur_inode_gen, |
4161 | sctx->cur_inode_size); | 4296 | sctx->cur_inode_size); |
4162 | if (ret < 0) | 4297 | if (ret < 0) |
@@ -4200,6 +4335,7 @@ static int changed_inode(struct send_ctx *sctx, | |||
4200 | 4335 | ||
4201 | sctx->cur_ino = key->objectid; | 4336 | sctx->cur_ino = key->objectid; |
4202 | sctx->cur_inode_new_gen = 0; | 4337 | sctx->cur_inode_new_gen = 0; |
4338 | sctx->cur_inode_last_extent = (u64)-1; | ||
4203 | 4339 | ||
4204 | /* | 4340 | /* |
4205 | * Set send_progress to current inode. This will tell all get_cur_xxx | 4341 | * Set send_progress to current inode. This will tell all get_cur_xxx |
@@ -4480,14 +4616,18 @@ static int changed_cb(struct btrfs_root *left_root, | |||
4480 | struct send_ctx *sctx = ctx; | 4616 | struct send_ctx *sctx = ctx; |
4481 | 4617 | ||
4482 | if (result == BTRFS_COMPARE_TREE_SAME) { | 4618 | if (result == BTRFS_COMPARE_TREE_SAME) { |
4483 | if (key->type != BTRFS_INODE_REF_KEY && | 4619 | if (key->type == BTRFS_INODE_REF_KEY || |
4484 | key->type != BTRFS_INODE_EXTREF_KEY) | 4620 | key->type == BTRFS_INODE_EXTREF_KEY) { |
4485 | return 0; | 4621 | ret = compare_refs(sctx, left_path, key); |
4486 | ret = compare_refs(sctx, left_path, key); | 4622 | if (!ret) |
4487 | if (!ret) | 4623 | return 0; |
4624 | if (ret < 0) | ||
4625 | return ret; | ||
4626 | } else if (key->type == BTRFS_EXTENT_DATA_KEY) { | ||
4627 | return maybe_send_hole(sctx, left_path, key); | ||
4628 | } else { | ||
4488 | return 0; | 4629 | return 0; |
4489 | if (ret < 0) | 4630 | } |
4490 | return ret; | ||
4491 | result = BTRFS_COMPARE_TREE_CHANGED; | 4631 | result = BTRFS_COMPARE_TREE_CHANGED; |
4492 | ret = 0; | 4632 | ret = 0; |
4493 | } | 4633 | } |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 9f7fc51ca334..e7d7a837512a 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -3194,7 +3194,7 @@ static int log_inode_item(struct btrfs_trans_handle *trans, | |||
3194 | static noinline int copy_items(struct btrfs_trans_handle *trans, | 3194 | static noinline int copy_items(struct btrfs_trans_handle *trans, |
3195 | struct inode *inode, | 3195 | struct inode *inode, |
3196 | struct btrfs_path *dst_path, | 3196 | struct btrfs_path *dst_path, |
3197 | struct extent_buffer *src, | 3197 | struct btrfs_path *src_path, u64 *last_extent, |
3198 | int start_slot, int nr, int inode_only) | 3198 | int start_slot, int nr, int inode_only) |
3199 | { | 3199 | { |
3200 | unsigned long src_offset; | 3200 | unsigned long src_offset; |
@@ -3202,6 +3202,8 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
3202 | struct btrfs_root *log = BTRFS_I(inode)->root->log_root; | 3202 | struct btrfs_root *log = BTRFS_I(inode)->root->log_root; |
3203 | struct btrfs_file_extent_item *extent; | 3203 | struct btrfs_file_extent_item *extent; |
3204 | struct btrfs_inode_item *inode_item; | 3204 | struct btrfs_inode_item *inode_item; |
3205 | struct extent_buffer *src = src_path->nodes[0]; | ||
3206 | struct btrfs_key first_key, last_key, key; | ||
3205 | int ret; | 3207 | int ret; |
3206 | struct btrfs_key *ins_keys; | 3208 | struct btrfs_key *ins_keys; |
3207 | u32 *ins_sizes; | 3209 | u32 *ins_sizes; |
@@ -3209,6 +3211,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
3209 | int i; | 3211 | int i; |
3210 | struct list_head ordered_sums; | 3212 | struct list_head ordered_sums; |
3211 | int skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | 3213 | int skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; |
3214 | bool has_extents = false; | ||
3215 | bool need_find_last_extent = (*last_extent == 0); | ||
3216 | bool done = false; | ||
3212 | 3217 | ||
3213 | INIT_LIST_HEAD(&ordered_sums); | 3218 | INIT_LIST_HEAD(&ordered_sums); |
3214 | 3219 | ||
@@ -3217,6 +3222,8 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
3217 | if (!ins_data) | 3222 | if (!ins_data) |
3218 | return -ENOMEM; | 3223 | return -ENOMEM; |
3219 | 3224 | ||
3225 | first_key.objectid = (u64)-1; | ||
3226 | |||
3220 | ins_sizes = (u32 *)ins_data; | 3227 | ins_sizes = (u32 *)ins_data; |
3221 | ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32)); | 3228 | ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32)); |
3222 | 3229 | ||
@@ -3237,6 +3244,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
3237 | 3244 | ||
3238 | src_offset = btrfs_item_ptr_offset(src, start_slot + i); | 3245 | src_offset = btrfs_item_ptr_offset(src, start_slot + i); |
3239 | 3246 | ||
3247 | if ((i == (nr - 1))) | ||
3248 | last_key = ins_keys[i]; | ||
3249 | |||
3240 | if (ins_keys[i].type == BTRFS_INODE_ITEM_KEY) { | 3250 | if (ins_keys[i].type == BTRFS_INODE_ITEM_KEY) { |
3241 | inode_item = btrfs_item_ptr(dst_path->nodes[0], | 3251 | inode_item = btrfs_item_ptr(dst_path->nodes[0], |
3242 | dst_path->slots[0], | 3252 | dst_path->slots[0], |
@@ -3248,6 +3258,21 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
3248 | src_offset, ins_sizes[i]); | 3258 | src_offset, ins_sizes[i]); |
3249 | } | 3259 | } |
3250 | 3260 | ||
3261 | /* | ||
3262 | * We set need_find_last_extent here in case we know we were | ||
3263 | * processing other items and then walk into the first extent in | ||
3264 | * the inode. If we don't hit an extent then nothing changes, | ||
3265 | * we'll do the last search the next time around. | ||
3266 | */ | ||
3267 | if (ins_keys[i].type == BTRFS_EXTENT_DATA_KEY) { | ||
3268 | has_extents = true; | ||
3269 | if (need_find_last_extent && | ||
3270 | first_key.objectid == (u64)-1) | ||
3271 | first_key = ins_keys[i]; | ||
3272 | } else { | ||
3273 | need_find_last_extent = false; | ||
3274 | } | ||
3275 | |||
3251 | /* take a reference on file data extents so that truncates | 3276 | /* take a reference on file data extents so that truncates |
3252 | * or deletes of this inode don't have to relog the inode | 3277 | * or deletes of this inode don't have to relog the inode |
3253 | * again | 3278 | * again |
@@ -3312,6 +3337,126 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
3312 | list_del(&sums->list); | 3337 | list_del(&sums->list); |
3313 | kfree(sums); | 3338 | kfree(sums); |
3314 | } | 3339 | } |
3340 | |||
3341 | if (!has_extents) | ||
3342 | return ret; | ||
3343 | |||
3344 | /* | ||
3345 | * Because we use btrfs_search_forward we could skip leaves that were | ||
3346 | * not modified and then assume *last_extent is valid when it really | ||
3347 | * isn't. So back up to the previous leaf and read the end of the last | ||
3348 | * extent before we go and fill in holes. | ||
3349 | */ | ||
3350 | if (need_find_last_extent) { | ||
3351 | u64 len; | ||
3352 | |||
3353 | ret = btrfs_prev_leaf(BTRFS_I(inode)->root, src_path); | ||
3354 | if (ret < 0) | ||
3355 | return ret; | ||
3356 | if (ret) | ||
3357 | goto fill_holes; | ||
3358 | if (src_path->slots[0]) | ||
3359 | src_path->slots[0]--; | ||
3360 | src = src_path->nodes[0]; | ||
3361 | btrfs_item_key_to_cpu(src, &key, src_path->slots[0]); | ||
3362 | if (key.objectid != btrfs_ino(inode) || | ||
3363 | key.type != BTRFS_EXTENT_DATA_KEY) | ||
3364 | goto fill_holes; | ||
3365 | extent = btrfs_item_ptr(src, src_path->slots[0], | ||
3366 | struct btrfs_file_extent_item); | ||
3367 | if (btrfs_file_extent_type(src, extent) == | ||
3368 | BTRFS_FILE_EXTENT_INLINE) { | ||
3369 | len = btrfs_file_extent_inline_len(src, extent); | ||
3370 | *last_extent = ALIGN(key.offset + len, | ||
3371 | log->sectorsize); | ||
3372 | } else { | ||
3373 | len = btrfs_file_extent_num_bytes(src, extent); | ||
3374 | *last_extent = key.offset + len; | ||
3375 | } | ||
3376 | } | ||
3377 | fill_holes: | ||
3378 | /* So we did prev_leaf, now we need to move to the next leaf, but a few | ||
3379 | * things could have happened | ||
3380 | * | ||
3381 | * 1) A merge could have happened, so we could currently be on a leaf | ||
3382 | * that holds what we were copying in the first place. | ||
3383 | * 2) A split could have happened, and now not all of the items we want | ||
3384 | * are on the same leaf. | ||
3385 | * | ||
3386 | * So we need to adjust how we search for holes, we need to drop the | ||
3387 | * path and re-search for the first extent key we found, and then walk | ||
3388 | * forward until we hit the last one we copied. | ||
3389 | */ | ||
3390 | if (need_find_last_extent) { | ||
3391 | /* btrfs_prev_leaf could return 1 without releasing the path */ | ||
3392 | btrfs_release_path(src_path); | ||
3393 | ret = btrfs_search_slot(NULL, BTRFS_I(inode)->root, &first_key, | ||
3394 | src_path, 0, 0); | ||
3395 | if (ret < 0) | ||
3396 | return ret; | ||
3397 | ASSERT(ret == 0); | ||
3398 | src = src_path->nodes[0]; | ||
3399 | i = src_path->slots[0]; | ||
3400 | } else { | ||
3401 | i = start_slot; | ||
3402 | } | ||
3403 | |||
3404 | /* | ||
3405 | * Ok so here we need to go through and fill in any holes we may have | ||
3406 | * to make sure that holes are punched for those areas in case they had | ||
3407 | * extents previously. | ||
3408 | */ | ||
3409 | while (!done) { | ||
3410 | u64 offset, len; | ||
3411 | u64 extent_end; | ||
3412 | |||
3413 | if (i >= btrfs_header_nritems(src_path->nodes[0])) { | ||
3414 | ret = btrfs_next_leaf(BTRFS_I(inode)->root, src_path); | ||
3415 | if (ret < 0) | ||
3416 | return ret; | ||
3417 | ASSERT(ret == 0); | ||
3418 | src = src_path->nodes[0]; | ||
3419 | i = 0; | ||
3420 | } | ||
3421 | |||
3422 | btrfs_item_key_to_cpu(src, &key, i); | ||
3423 | if (!btrfs_comp_cpu_keys(&key, &last_key)) | ||
3424 | done = true; | ||
3425 | if (key.objectid != btrfs_ino(inode) || | ||
3426 | key.type != BTRFS_EXTENT_DATA_KEY) { | ||
3427 | i++; | ||
3428 | continue; | ||
3429 | } | ||
3430 | extent = btrfs_item_ptr(src, i, struct btrfs_file_extent_item); | ||
3431 | if (btrfs_file_extent_type(src, extent) == | ||
3432 | BTRFS_FILE_EXTENT_INLINE) { | ||
3433 | len = btrfs_file_extent_inline_len(src, extent); | ||
3434 | extent_end = ALIGN(key.offset + len, log->sectorsize); | ||
3435 | } else { | ||
3436 | len = btrfs_file_extent_num_bytes(src, extent); | ||
3437 | extent_end = key.offset + len; | ||
3438 | } | ||
3439 | i++; | ||
3440 | |||
3441 | if (*last_extent == key.offset) { | ||
3442 | *last_extent = extent_end; | ||
3443 | continue; | ||
3444 | } | ||
3445 | offset = *last_extent; | ||
3446 | len = key.offset - *last_extent; | ||
3447 | ret = btrfs_insert_file_extent(trans, log, btrfs_ino(inode), | ||
3448 | offset, 0, 0, len, 0, len, 0, | ||
3449 | 0, 0); | ||
3450 | if (ret) | ||
3451 | break; | ||
3452 | *last_extent = offset + len; | ||
3453 | } | ||
3454 | /* | ||
3455 | * Need to let the callers know we dropped the path so they should | ||
3456 | * re-search. | ||
3457 | */ | ||
3458 | if (!ret && need_find_last_extent) | ||
3459 | ret = 1; | ||
3315 | return ret; | 3460 | return ret; |
3316 | } | 3461 | } |
3317 | 3462 | ||
@@ -3630,6 +3775,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
3630 | struct btrfs_key max_key; | 3775 | struct btrfs_key max_key; |
3631 | struct btrfs_root *log = root->log_root; | 3776 | struct btrfs_root *log = root->log_root; |
3632 | struct extent_buffer *src = NULL; | 3777 | struct extent_buffer *src = NULL; |
3778 | u64 last_extent = 0; | ||
3633 | int err = 0; | 3779 | int err = 0; |
3634 | int ret; | 3780 | int ret; |
3635 | int nritems; | 3781 | int nritems; |
@@ -3745,11 +3891,15 @@ again: | |||
3745 | goto next_slot; | 3891 | goto next_slot; |
3746 | } | 3892 | } |
3747 | 3893 | ||
3748 | ret = copy_items(trans, inode, dst_path, src, ins_start_slot, | 3894 | ret = copy_items(trans, inode, dst_path, path, &last_extent, |
3749 | ins_nr, inode_only); | 3895 | ins_start_slot, ins_nr, inode_only); |
3750 | if (ret) { | 3896 | if (ret < 0) { |
3751 | err = ret; | 3897 | err = ret; |
3752 | goto out_unlock; | 3898 | goto out_unlock; |
3899 | } if (ret) { | ||
3900 | ins_nr = 0; | ||
3901 | btrfs_release_path(path); | ||
3902 | continue; | ||
3753 | } | 3903 | } |
3754 | ins_nr = 1; | 3904 | ins_nr = 1; |
3755 | ins_start_slot = path->slots[0]; | 3905 | ins_start_slot = path->slots[0]; |
@@ -3763,13 +3913,14 @@ next_slot: | |||
3763 | goto again; | 3913 | goto again; |
3764 | } | 3914 | } |
3765 | if (ins_nr) { | 3915 | if (ins_nr) { |
3766 | ret = copy_items(trans, inode, dst_path, src, | 3916 | ret = copy_items(trans, inode, dst_path, path, |
3767 | ins_start_slot, | 3917 | &last_extent, ins_start_slot, |
3768 | ins_nr, inode_only); | 3918 | ins_nr, inode_only); |
3769 | if (ret) { | 3919 | if (ret < 0) { |
3770 | err = ret; | 3920 | err = ret; |
3771 | goto out_unlock; | 3921 | goto out_unlock; |
3772 | } | 3922 | } |
3923 | ret = 0; | ||
3773 | ins_nr = 0; | 3924 | ins_nr = 0; |
3774 | } | 3925 | } |
3775 | btrfs_release_path(path); | 3926 | btrfs_release_path(path); |
@@ -3784,12 +3935,13 @@ next_slot: | |||
3784 | } | 3935 | } |
3785 | } | 3936 | } |
3786 | if (ins_nr) { | 3937 | if (ins_nr) { |
3787 | ret = copy_items(trans, inode, dst_path, src, ins_start_slot, | 3938 | ret = copy_items(trans, inode, dst_path, path, &last_extent, |
3788 | ins_nr, inode_only); | 3939 | ins_start_slot, ins_nr, inode_only); |
3789 | if (ret) { | 3940 | if (ret < 0) { |
3790 | err = ret; | 3941 | err = ret; |
3791 | goto out_unlock; | 3942 | goto out_unlock; |
3792 | } | 3943 | } |
3944 | ret = 0; | ||
3793 | ins_nr = 0; | 3945 | ins_nr = 0; |
3794 | } | 3946 | } |
3795 | 3947 | ||