diff options
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 78 |
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 | ||
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); |