diff options
author | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-06-07 09:08:23 -0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-06-11 19:18:35 -0400 |
commit | 699489bbbea4fc3b9b735d69941cf4fca91ce1d5 (patch) | |
tree | 4b3d474252dfc93f0f4b55145d6d7193d0cbcd13 /fs/f2fs | |
parent | 2d4d9fb591fe83d9f0559afaa9736ebc8edad0aa (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')
-rw-r--r-- | fs/f2fs/data.c | 2 | ||||
-rw-r--r-- | fs/f2fs/dir.c | 9 | ||||
-rw-r--r-- | fs/f2fs/f2fs.h | 1 |
3 files changed, 7 insertions, 5 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 93917e31dbdf..5b145fcc2864 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c | |||
@@ -339,6 +339,8 @@ repeat: | |||
339 | if (new_i_size && | 339 | if (new_i_size && |
340 | i_size_read(inode) < ((index + 1) << PAGE_CACHE_SHIFT)) { | 340 | i_size_read(inode) < ((index + 1) << PAGE_CACHE_SHIFT)) { |
341 | i_size_write(inode, ((index + 1) << PAGE_CACHE_SHIFT)); | 341 | i_size_write(inode, ((index + 1) << PAGE_CACHE_SHIFT)); |
342 | /* Only the directory inode sets new_i_size */ | ||
343 | set_inode_flag(F2FS_I(inode), FI_UPDATE_DIR); | ||
342 | mark_inode_dirty_sync(inode); | 344 | mark_inode_dirty_sync(inode); |
343 | } | 345 | } |
344 | return page; | 346 | return page; |
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: | |||
370 | static void update_parent_metadata(struct inode *dir, struct inode *inode, | 370 | static 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); |
504 | fail: | 502 | fail: |
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; |
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index c344a4d640cb..27edf59ac12c 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h | |||
@@ -859,6 +859,7 @@ enum { | |||
859 | FI_INC_LINK, /* need to increment i_nlink */ | 859 | FI_INC_LINK, /* need to increment i_nlink */ |
860 | FI_ACL_MODE, /* indicate acl mode */ | 860 | FI_ACL_MODE, /* indicate acl mode */ |
861 | FI_NO_ALLOC, /* should not allocate any blocks */ | 861 | FI_NO_ALLOC, /* should not allocate any blocks */ |
862 | FI_UPDATE_DIR, /* should update inode block for consistency */ | ||
862 | FI_DELAY_IPUT, /* used for the recovery */ | 863 | FI_DELAY_IPUT, /* used for the recovery */ |
863 | }; | 864 | }; |
864 | 865 | ||