diff options
author | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2014-02-05 11:16:39 +0900 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2014-02-17 14:58:52 +0900 |
commit | bd859c6598dd2b73c517b3a36ecc5dd387eb1eb2 (patch) | |
tree | 95b05b3981be310d97340d9b2c23564793646d10 /fs/f2fs | |
parent | f6517cfc84246b2606fd631730846c648ee0d455 (diff) | |
download | op-kernel-dev-bd859c6598dd2b73c517b3a36ecc5dd387eb1eb2.zip op-kernel-dev-bd859c6598dd2b73c517b3a36ecc5dd387eb1eb2.tar.gz |
f2fs: fix to truncate dentry pages in the error case
When a new directory is allocated, if an error is occurred, we should truncate
preallocated dentry pages too.
This bug was reported by Andrey Tsyvarev after a while as follows.
mkdir()->
f2fs_add_link()->
init_inode_metadata()->
f2fs_init_acl()->
f2fs_get_acl()->
f2fs_getxattr()->
read_all_xattrs() fails.
Also there was a BUG_ON triggered after the fault in
mkdir()->
f2fs_add_link()->
init_inode_metadata()->
remove_inode_page() ->
f2fs_bug_on(inode->i_blocks != 0 && inode->i_blocks != 1);
But, previous patch wasn't perfect to resolve that bug, so the following bug
report was also submitted.
kernel BUG at fs/f2fs/inode.c:274!
Call Trace:
[<ffffffff811fde03>] evict+0xa3/0x1a0
[<ffffffff811fe615>] iput+0xf5/0x180
[<ffffffffa01c7f63>] f2fs_mkdir+0xf3/0x150 [f2fs]
[<ffffffff811f2a77>] vfs_mkdir+0xb7/0x160
[<ffffffff811f36bf>] SyS_mkdir+0x5f/0xc0
[<ffffffff81680769>] system_call_fastpath+0x16/0x1b
Finally, this patch resolves all the issues like below.
If an error is occurred after make_empty_dir(),
1. truncate_inode_pages()
The make_bad_inode() prior to iput() will change i_mode to S_IFREG, which
means that f2fs will not decrement fi->dirty_dents during f2fs_evict_inode.
But, by calling it here, we can do that.
2. truncate_blocks()
Preallocated dentry pages are trucated here to sync i_blocks.
3. remove_dirty_dir_inode()
Remove this directory inode from the list.
Reported-and-Tested-by: Andrey Tsyvarev <tsyvarev@ispras.ru>
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs/f2fs')
-rw-r--r-- | fs/f2fs/dir.c | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index bfcb4ae..5bbf94c 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -372,6 +372,10 @@ static struct page *init_inode_metadata(struct inode *inode, put_error: f2fs_put_page(page, 1); + /* once the failed inode becomes a bad inode, i_mode is S_IFREG */ + truncate_inode_pages(&inode->i_data, 0); + truncate_blocks(inode, 0); + remove_dirty_dir_inode(inode); error: remove_inode_page(inode); return ERR_PTR(err); |