aboutsummaryrefslogtreecommitdiffstats
path: root/fs/f2fs/dir.c
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk.kim@samsung.com>2013-06-07 09:08:23 -0400
committerJaegeuk Kim <jaegeuk.kim@samsung.com>2013-06-11 19:18:35 -0400
commit699489bbbea4fc3b9b735d69941cf4fca91ce1d5 (patch)
tree4b3d474252dfc93f0f4b55145d6d7193d0cbcd13 /fs/f2fs/dir.c
parent2d4d9fb591fe83d9f0559afaa9736ebc8edad0aa (diff)
f2fs: sync dir->i_size with its block allocation
If new dentry block is allocated and its i_size is updated, we should update its inode block together in order to sync i_size and its block allocation. Otherwise, we can loose additional dentry block due to the unconsistent i_size. Errorneous Scenario ------------------- In the recovery routine, - recovery_dentry | - __f2fs_add_link | | - get_new_data_page | | | - i_size_write(new_i_size) | | | - mark_inode_dirty_sync(dir) | | - update_parent_metadata | | | - mark_inode_dirty(dir) | - write_checkpoint - sync_dirty_dir_inodes - filemap_flush(dentry_blocks) - f2fs_write_data_page - skip to write the last dentry block due to index < i_size In the above flow, new_i_size is not updated to its inode block so that the last dentry block will be lost accordingly. Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs/f2fs/dir.c')
-rw-r--r--fs/f2fs/dir.c9
1 files changed, 4 insertions, 5 deletions
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index eaea5b50d9c1..69ca049b5168 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -370,22 +370,20 @@ error:
370static void update_parent_metadata(struct inode *dir, struct inode *inode, 370static void update_parent_metadata(struct inode *dir, struct inode *inode,
371 unsigned int current_depth) 371 unsigned int current_depth)
372{ 372{
373 bool need_dir_update = false;
374
375 if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { 373 if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) {
376 if (S_ISDIR(inode->i_mode)) { 374 if (S_ISDIR(inode->i_mode)) {
377 inc_nlink(dir); 375 inc_nlink(dir);
378 need_dir_update = true; 376 set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
379 } 377 }
380 clear_inode_flag(F2FS_I(inode), FI_NEW_INODE); 378 clear_inode_flag(F2FS_I(inode), FI_NEW_INODE);
381 } 379 }
382 dir->i_mtime = dir->i_ctime = CURRENT_TIME; 380 dir->i_mtime = dir->i_ctime = CURRENT_TIME;
383 if (F2FS_I(dir)->i_current_depth != current_depth) { 381 if (F2FS_I(dir)->i_current_depth != current_depth) {
384 F2FS_I(dir)->i_current_depth = current_depth; 382 F2FS_I(dir)->i_current_depth = current_depth;
385 need_dir_update = true; 383 set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
386 } 384 }
387 385
388 if (need_dir_update) 386 if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR))
389 update_inode_page(dir); 387 update_inode_page(dir);
390 else 388 else
391 mark_inode_dirty(dir); 389 mark_inode_dirty(dir);
@@ -502,6 +500,7 @@ add_dentry:
502 500
503 update_parent_metadata(dir, inode, current_depth); 501 update_parent_metadata(dir, inode, current_depth);
504fail: 502fail:
503 clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
505 kunmap(dentry_page); 504 kunmap(dentry_page);
506 f2fs_put_page(dentry_page, 1); 505 f2fs_put_page(dentry_page, 1);
507 return err; 506 return err;