diff options
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 82 |
1 files changed, 73 insertions, 9 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 7870bdba26b7..5f649bb32bec 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -490,8 +490,20 @@ insert: | |||
490 | src_item = (struct btrfs_inode_item *)src_ptr; | 490 | src_item = (struct btrfs_inode_item *)src_ptr; |
491 | dst_item = (struct btrfs_inode_item *)dst_ptr; | 491 | dst_item = (struct btrfs_inode_item *)dst_ptr; |
492 | 492 | ||
493 | if (btrfs_inode_generation(eb, src_item) == 0) | 493 | if (btrfs_inode_generation(eb, src_item) == 0) { |
494 | struct extent_buffer *dst_eb = path->nodes[0]; | ||
495 | |||
496 | if (S_ISREG(btrfs_inode_mode(eb, src_item)) && | ||
497 | S_ISREG(btrfs_inode_mode(dst_eb, dst_item))) { | ||
498 | struct btrfs_map_token token; | ||
499 | u64 ino_size = btrfs_inode_size(eb, src_item); | ||
500 | |||
501 | btrfs_init_map_token(&token); | ||
502 | btrfs_set_token_inode_size(dst_eb, dst_item, | ||
503 | ino_size, &token); | ||
504 | } | ||
494 | goto no_copy; | 505 | goto no_copy; |
506 | } | ||
495 | 507 | ||
496 | if (overwrite_root && | 508 | if (overwrite_root && |
497 | S_ISDIR(btrfs_inode_mode(eb, src_item)) && | 509 | S_ISDIR(btrfs_inode_mode(eb, src_item)) && |
@@ -3250,7 +3262,8 @@ static int drop_objectid_items(struct btrfs_trans_handle *trans, | |||
3250 | static void fill_inode_item(struct btrfs_trans_handle *trans, | 3262 | static void fill_inode_item(struct btrfs_trans_handle *trans, |
3251 | struct extent_buffer *leaf, | 3263 | struct extent_buffer *leaf, |
3252 | struct btrfs_inode_item *item, | 3264 | struct btrfs_inode_item *item, |
3253 | struct inode *inode, int log_inode_only) | 3265 | struct inode *inode, int log_inode_only, |
3266 | u64 logged_isize) | ||
3254 | { | 3267 | { |
3255 | struct btrfs_map_token token; | 3268 | struct btrfs_map_token token; |
3256 | 3269 | ||
@@ -3263,7 +3276,7 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, | |||
3263 | * to say 'update this inode with these values' | 3276 | * to say 'update this inode with these values' |
3264 | */ | 3277 | */ |
3265 | btrfs_set_token_inode_generation(leaf, item, 0, &token); | 3278 | btrfs_set_token_inode_generation(leaf, item, 0, &token); |
3266 | btrfs_set_token_inode_size(leaf, item, 0, &token); | 3279 | btrfs_set_token_inode_size(leaf, item, logged_isize, &token); |
3267 | } else { | 3280 | } else { |
3268 | btrfs_set_token_inode_generation(leaf, item, | 3281 | btrfs_set_token_inode_generation(leaf, item, |
3269 | BTRFS_I(inode)->generation, | 3282 | BTRFS_I(inode)->generation, |
@@ -3315,7 +3328,7 @@ static int log_inode_item(struct btrfs_trans_handle *trans, | |||
3315 | return ret; | 3328 | return ret; |
3316 | inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0], | 3329 | inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0], |
3317 | struct btrfs_inode_item); | 3330 | struct btrfs_inode_item); |
3318 | fill_inode_item(trans, path->nodes[0], inode_item, inode, 0); | 3331 | fill_inode_item(trans, path->nodes[0], inode_item, inode, 0, 0); |
3319 | btrfs_release_path(path); | 3332 | btrfs_release_path(path); |
3320 | return 0; | 3333 | return 0; |
3321 | } | 3334 | } |
@@ -3324,7 +3337,8 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
3324 | struct inode *inode, | 3337 | struct inode *inode, |
3325 | struct btrfs_path *dst_path, | 3338 | struct btrfs_path *dst_path, |
3326 | struct btrfs_path *src_path, u64 *last_extent, | 3339 | struct btrfs_path *src_path, u64 *last_extent, |
3327 | int start_slot, int nr, int inode_only) | 3340 | int start_slot, int nr, int inode_only, |
3341 | u64 logged_isize) | ||
3328 | { | 3342 | { |
3329 | unsigned long src_offset; | 3343 | unsigned long src_offset; |
3330 | unsigned long dst_offset; | 3344 | unsigned long dst_offset; |
@@ -3381,7 +3395,8 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
3381 | dst_path->slots[0], | 3395 | dst_path->slots[0], |
3382 | struct btrfs_inode_item); | 3396 | struct btrfs_inode_item); |
3383 | fill_inode_item(trans, dst_path->nodes[0], inode_item, | 3397 | fill_inode_item(trans, dst_path->nodes[0], inode_item, |
3384 | inode, inode_only == LOG_INODE_EXISTS); | 3398 | inode, inode_only == LOG_INODE_EXISTS, |
3399 | logged_isize); | ||
3385 | } else { | 3400 | } else { |
3386 | copy_extent_buffer(dst_path->nodes[0], src, dst_offset, | 3401 | copy_extent_buffer(dst_path->nodes[0], src, dst_offset, |
3387 | src_offset, ins_sizes[i]); | 3402 | src_offset, ins_sizes[i]); |
@@ -3933,6 +3948,33 @@ process: | |||
3933 | return ret; | 3948 | return ret; |
3934 | } | 3949 | } |
3935 | 3950 | ||
3951 | static int logged_inode_size(struct btrfs_root *log, struct inode *inode, | ||
3952 | struct btrfs_path *path, u64 *size_ret) | ||
3953 | { | ||
3954 | struct btrfs_key key; | ||
3955 | int ret; | ||
3956 | |||
3957 | key.objectid = btrfs_ino(inode); | ||
3958 | key.type = BTRFS_INODE_ITEM_KEY; | ||
3959 | key.offset = 0; | ||
3960 | |||
3961 | ret = btrfs_search_slot(NULL, log, &key, path, 0, 0); | ||
3962 | if (ret < 0) { | ||
3963 | return ret; | ||
3964 | } else if (ret > 0) { | ||
3965 | *size_ret = i_size_read(inode); | ||
3966 | } else { | ||
3967 | struct btrfs_inode_item *item; | ||
3968 | |||
3969 | item = btrfs_item_ptr(path->nodes[0], path->slots[0], | ||
3970 | struct btrfs_inode_item); | ||
3971 | *size_ret = btrfs_inode_size(path->nodes[0], item); | ||
3972 | } | ||
3973 | |||
3974 | btrfs_release_path(path); | ||
3975 | return 0; | ||
3976 | } | ||
3977 | |||
3936 | /* log a single inode in the tree log. | 3978 | /* log a single inode in the tree log. |
3937 | * At least one parent directory for this inode must exist in the tree | 3979 | * At least one parent directory for this inode must exist in the tree |
3938 | * or be logged already. | 3980 | * or be logged already. |
@@ -3970,6 +4012,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
3970 | bool fast_search = false; | 4012 | bool fast_search = false; |
3971 | u64 ino = btrfs_ino(inode); | 4013 | u64 ino = btrfs_ino(inode); |
3972 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | 4014 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; |
4015 | u64 logged_isize = 0; | ||
3973 | 4016 | ||
3974 | path = btrfs_alloc_path(); | 4017 | path = btrfs_alloc_path(); |
3975 | if (!path) | 4018 | if (!path) |
@@ -4030,6 +4073,25 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
4030 | max_key_type = BTRFS_XATTR_ITEM_KEY; | 4073 | max_key_type = BTRFS_XATTR_ITEM_KEY; |
4031 | ret = drop_objectid_items(trans, log, path, ino, max_key_type); | 4074 | ret = drop_objectid_items(trans, log, path, ino, max_key_type); |
4032 | } else { | 4075 | } else { |
4076 | if (inode_only == LOG_INODE_EXISTS) { | ||
4077 | /* | ||
4078 | * Make sure the new inode item we write to the log has | ||
4079 | * the same isize as the current one (if it exists). | ||
4080 | * This is necessary to prevent data loss after log | ||
4081 | * replay, and also to prevent doing a wrong expanding | ||
4082 | * truncate - for e.g. create file, write 4K into offset | ||
4083 | * 0, fsync, write 4K into offset 4096, add hard link, | ||
4084 | * fsync some other file (to sync log), power fail - if | ||
4085 | * we use the inode's current i_size, after log replay | ||
4086 | * we get a 8Kb file, with the last 4Kb extent as a hole | ||
4087 | * (zeroes), as if an expanding truncate happened, | ||
4088 | * instead of getting a file of 4Kb only. | ||
4089 | */ | ||
4090 | err = logged_inode_size(log, inode, path, | ||
4091 | &logged_isize); | ||
4092 | if (err) | ||
4093 | goto out_unlock; | ||
4094 | } | ||
4033 | if (test_and_clear_bit(BTRFS_INODE_NEEDS_FULL_SYNC, | 4095 | if (test_and_clear_bit(BTRFS_INODE_NEEDS_FULL_SYNC, |
4034 | &BTRFS_I(inode)->runtime_flags)) { | 4096 | &BTRFS_I(inode)->runtime_flags)) { |
4035 | clear_bit(BTRFS_INODE_COPY_EVERYTHING, | 4097 | clear_bit(BTRFS_INODE_COPY_EVERYTHING, |
@@ -4085,7 +4147,8 @@ again: | |||
4085 | } | 4147 | } |
4086 | 4148 | ||
4087 | ret = copy_items(trans, inode, dst_path, path, &last_extent, | 4149 | ret = copy_items(trans, inode, dst_path, path, &last_extent, |
4088 | ins_start_slot, ins_nr, inode_only); | 4150 | ins_start_slot, ins_nr, inode_only, |
4151 | logged_isize); | ||
4089 | if (ret < 0) { | 4152 | if (ret < 0) { |
4090 | err = ret; | 4153 | err = ret; |
4091 | goto out_unlock; | 4154 | goto out_unlock; |
@@ -4109,7 +4172,7 @@ next_slot: | |||
4109 | if (ins_nr) { | 4172 | if (ins_nr) { |
4110 | ret = copy_items(trans, inode, dst_path, path, | 4173 | ret = copy_items(trans, inode, dst_path, path, |
4111 | &last_extent, ins_start_slot, | 4174 | &last_extent, ins_start_slot, |
4112 | ins_nr, inode_only); | 4175 | ins_nr, inode_only, logged_isize); |
4113 | if (ret < 0) { | 4176 | if (ret < 0) { |
4114 | err = ret; | 4177 | err = ret; |
4115 | goto out_unlock; | 4178 | goto out_unlock; |
@@ -4130,7 +4193,8 @@ next_slot: | |||
4130 | } | 4193 | } |
4131 | if (ins_nr) { | 4194 | if (ins_nr) { |
4132 | ret = copy_items(trans, inode, dst_path, path, &last_extent, | 4195 | ret = copy_items(trans, inode, dst_path, path, &last_extent, |
4133 | ins_start_slot, ins_nr, inode_only); | 4196 | ins_start_slot, ins_nr, inode_only, |
4197 | logged_isize); | ||
4134 | if (ret < 0) { | 4198 | if (ret < 0) { |
4135 | err = ret; | 4199 | err = ret; |
4136 | goto out_unlock; | 4200 | goto out_unlock; |