aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-10-22 12:18:51 -0400
committerChris Mason <clm@fb.com>2014-01-28 16:19:21 -0500
commit16e7549f045d33b0c5b0ebf19d08439e9221d40c (patch)
treea7f3c3bbe5fa0cf6bf821f3a26d8969647dfd20d /fs
parentd8ec26d7f8287f5788a494f56e8814210f0e64be (diff)
Btrfs: incompatible format change to remove hole extents
Btrfs has always had these filler extent data items for holes in inodes. This has made somethings very easy, like logging hole punches and sending hole punches. However for large holey files these extent data items are pure overhead. So add an incompatible feature to no longer add hole extents to reduce the amount of metadata used by these sort of files. This has a few changes for logging and send obviously since they will need to detect holes and log/send the holes if there are any. I've tested this thoroughly with xfstests and it doesn't cause any issues with and without the incompat format set. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ctree.c3
-rw-r--r--fs/btrfs/ctree.h5
-rw-r--r--fs/btrfs/file.c13
-rw-r--r--fs/btrfs/inode.c78
-rw-r--r--fs/btrfs/send.c158
-rw-r--r--fs/btrfs/tree-log.c172
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);
42static void tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, 42static void tree_mod_log_free_eb(struct btrfs_fs_info *fs_info,
43 struct extent_buffer *eb); 43 struct extent_buffer *eb);
44static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
45 44
46struct btrfs_path *btrfs_alloc_path(void) 45struct 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 */
4820static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path) 4819int 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
3401int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); 3403int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
3404int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
3402int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, 3405int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
3403 u64 time_seq); 3406 u64 time_seq);
3404static inline int btrfs_next_old_item(struct btrfs_root *root, 3407static 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
4206static 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 */
4212int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size) 4255int 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);
4325next:
4326 btrfs_update_inode(trans, root, inode);
4327 btrfs_end_transaction(trans, root);
4328 } 4346 }
4347next:
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
149static 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
148static void fs_path_reset(struct fs_path *p) 156static 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
3763static 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 }
3791tlv_put_failure:
3792 fs_path_free(p);
3793 return ret;
3794}
3795
3755static int send_write_or_clone(struct send_ctx *sctx, 3796static 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
4023static 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;
4062out:
4063 btrfs_free_path(path);
4064 return ret;
4065}
4066
4067static 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
3982static int process_extent(struct send_ctx *sctx, 4101static 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;
4155out_hole:
4156 ret = maybe_send_hole(sctx, path, key);
4035out: 4157out:
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,
3194static noinline int copy_items(struct btrfs_trans_handle *trans, 3194static 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 }
3377fill_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