diff options
author | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-06-07 17:08:23 +0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-06-12 03:18:35 +0400 |
commit | 699489bbbea4fc3b9b735d69941cf4fca91ce1d5 (patch) | |
tree | 4b3d474252dfc93f0f4b55145d6d7193d0cbcd13 /fs/f2fs/dir.c | |
parent | 2d4d9fb591fe83d9f0559afaa9736ebc8edad0aa (diff) | |
download | linux-699489bbbea4fc3b9b735d69941cf4fca91ce1d5.tar.xz |
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.c | 9 |
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: static void update_parent_metadata(struct inode *dir, struct inode *inode, unsigned int current_depth) { - bool need_dir_update = false; - if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) { if (S_ISDIR(inode->i_mode)) { inc_nlink(dir); - need_dir_update = true; + set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); } clear_inode_flag(F2FS_I(inode), FI_NEW_INODE); } dir->i_mtime = dir->i_ctime = CURRENT_TIME; if (F2FS_I(dir)->i_current_depth != current_depth) { F2FS_I(dir)->i_current_depth = current_depth; - need_dir_update = true; + set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); } - if (need_dir_update) + if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) update_inode_page(dir); else mark_inode_dirty(dir); @@ -502,6 +500,7 @@ add_dentry: update_parent_metadata(dir, inode, current_depth); fail: + clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR); kunmap(dentry_page); f2fs_put_page(dentry_page, 1); return err; |