aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
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/btrfs/inode.c
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/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c78
1 files changed, 48 insertions, 30 deletions
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);