aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-03-01 11:47:21 -0500
committerJosef Bacik <jbacik@fusionio.com>2013-03-01 11:47:21 -0500
commit124fe663f93162d17b7e391705cac122101e93d8 (patch)
treee845b288ac0976e24b9a2264c6e21c0142b76237 /fs
parent83c8266acc1d19debbf353a16aabbd892ef99462 (diff)
Btrfs: delete inline extents when we find them during logging
Apparently when we do inline extents we allow the data to overlap the last chunk of the btrfs_file_extent_item, which means that we can possibly have a btrfs_file_extent_item that isn't actually as large as a btrfs_file_extent_item. This messes with us when we try to overwrite the extent when logging new extents since we expect for it to be the right size. To fix this just delete the item and try to do the insert again which will give us the proper sized btrfs_file_extent_item. This fixes a panic where map_private_extent_buffer would blow up because we're trying to write past the end of the leaf. Thanks, Cc: stable@vger.kernel.org Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/tree-log.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 8e85e0e4333d..c7ef569eb22a 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -3300,6 +3300,7 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
3300 int index = log->log_transid % 2; 3300 int index = log->log_transid % 2;
3301 bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; 3301 bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
3302 3302
3303insert:
3303 INIT_LIST_HEAD(&ordered_sums); 3304 INIT_LIST_HEAD(&ordered_sums);
3304 btrfs_init_map_token(&token); 3305 btrfs_init_map_token(&token);
3305 key.objectid = btrfs_ino(inode); 3306 key.objectid = btrfs_ino(inode);
@@ -3315,6 +3316,23 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
3315 leaf = path->nodes[0]; 3316 leaf = path->nodes[0];
3316 fi = btrfs_item_ptr(leaf, path->slots[0], 3317 fi = btrfs_item_ptr(leaf, path->slots[0],
3317 struct btrfs_file_extent_item); 3318 struct btrfs_file_extent_item);
3319
3320 /*
3321 * If we are overwriting an inline extent with a real one then we need
3322 * to just delete the inline extent as it may not be large enough to
3323 * have the entire file_extent_item.
3324 */
3325 if (ret && btrfs_token_file_extent_type(leaf, fi, &token) ==
3326 BTRFS_FILE_EXTENT_INLINE) {
3327 ret = btrfs_del_item(trans, log, path);
3328 btrfs_release_path(path);
3329 if (ret) {
3330 path->really_keep_locks = 0;
3331 return ret;
3332 }
3333 goto insert;
3334 }
3335
3318 btrfs_set_token_file_extent_generation(leaf, fi, em->generation, 3336 btrfs_set_token_file_extent_generation(leaf, fi, em->generation,
3319 &token); 3337 &token);
3320 if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) { 3338 if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {