diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 33 |
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. */ |