summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/tree-log.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r--fs/btrfs/tree-log.c33
1 files changed, 23 insertions, 10 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index f06454a55e00..561884f60d35 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -3578,9 +3578,16 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
3578 } 3578 }
3579 btrfs_release_path(path); 3579 btrfs_release_path(path);
3580 3580
3581 /* find the first key from this transaction again */ 3581 /*
3582 * Find the first key from this transaction again. See the note for
3583 * log_new_dir_dentries, if we're logging a directory recursively we
3584 * won't be holding its i_mutex, which means we can modify the directory
3585 * while we're logging it. If we remove an entry between our first
3586 * search and this search we'll not find the key again and can just
3587 * bail.
3588 */
3582 ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0); 3589 ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0);
3583 if (WARN_ON(ret != 0)) 3590 if (ret != 0)
3584 goto done; 3591 goto done;
3585 3592
3586 /* 3593 /*
@@ -4544,6 +4551,19 @@ static int logged_inode_size(struct btrfs_root *log, struct btrfs_inode *inode,
4544 item = btrfs_item_ptr(path->nodes[0], path->slots[0], 4551 item = btrfs_item_ptr(path->nodes[0], path->slots[0],
4545 struct btrfs_inode_item); 4552 struct btrfs_inode_item);
4546 *size_ret = btrfs_inode_size(path->nodes[0], item); 4553 *size_ret = btrfs_inode_size(path->nodes[0], item);
4554 /*
4555 * If the in-memory inode's i_size is smaller then the inode
4556 * size stored in the btree, return the inode's i_size, so
4557 * that we get a correct inode size after replaying the log
4558 * when before a power failure we had a shrinking truncate
4559 * followed by addition of a new name (rename / new hard link).
4560 * Otherwise return the inode size from the btree, to avoid
4561 * data loss when replaying a log due to previously doing a
4562 * write that expands the inode's size and logging a new name
4563 * immediately after.
4564 */
4565 if (*size_ret > inode->vfs_inode.i_size)
4566 *size_ret = inode->vfs_inode.i_size;
4547 } 4567 }
4548 4568
4549 btrfs_release_path(path); 4569 btrfs_release_path(path);
@@ -4705,15 +4725,8 @@ static int btrfs_log_trailing_hole(struct btrfs_trans_handle *trans,
4705 struct btrfs_file_extent_item); 4725 struct btrfs_file_extent_item);
4706 4726
4707 if (btrfs_file_extent_type(leaf, extent) == 4727 if (btrfs_file_extent_type(leaf, extent) ==
4708 BTRFS_FILE_EXTENT_INLINE) { 4728 BTRFS_FILE_EXTENT_INLINE)
4709 len = btrfs_file_extent_ram_bytes(leaf, extent);
4710 ASSERT(len == i_size ||
4711 (len == fs_info->sectorsize &&
4712 btrfs_file_extent_compression(leaf, extent) !=
4713 BTRFS_COMPRESS_NONE) ||
4714 (len < i_size && i_size < fs_info->sectorsize));
4715 return 0; 4729 return 0;
4716 }
4717 4730
4718 len = btrfs_file_extent_num_bytes(leaf, extent); 4731 len = btrfs_file_extent_num_bytes(leaf, extent);
4719 /* Last extent goes beyond i_size, no need to log a hole. */ 4732 /* Last extent goes beyond i_size, no need to log a hole. */