diff options
| -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; |
