f2fs: revisit error handling flows
This patch fixes a couple of bugs regarding to orphan inodes when handling errors. This tries to - call alloc_nid_done with add_orphan_inode in handle_failed_inode - let truncate blocks in f2fs_evict_inode - not make a bad inode due to i_mode change Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
Родитель
cb78942b82
Коммит
221149c00e
|
@ -391,9 +391,14 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
|
||||||
return page;
|
return page;
|
||||||
|
|
||||||
if (S_ISDIR(inode->i_mode)) {
|
if (S_ISDIR(inode->i_mode)) {
|
||||||
|
/* in order to handle error case */
|
||||||
|
get_page(page);
|
||||||
err = make_empty_dir(inode, dir, page);
|
err = make_empty_dir(inode, dir, page);
|
||||||
if (err)
|
if (err) {
|
||||||
goto error;
|
lock_page(page);
|
||||||
|
goto put_error;
|
||||||
|
}
|
||||||
|
put_page(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = f2fs_init_acl(inode, dir, page, dpage);
|
err = f2fs_init_acl(inode, dir, page, dpage);
|
||||||
|
@ -437,13 +442,12 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
|
||||||
return page;
|
return page;
|
||||||
|
|
||||||
put_error:
|
put_error:
|
||||||
f2fs_put_page(page, 1);
|
/* truncate empty dir pages */
|
||||||
error:
|
|
||||||
/* once the failed inode becomes a bad inode, i_mode is S_IFREG */
|
|
||||||
truncate_inode_pages(&inode->i_data, 0);
|
truncate_inode_pages(&inode->i_data, 0);
|
||||||
truncate_blocks(inode, 0, false);
|
|
||||||
remove_dirty_inode(inode);
|
clear_nlink(inode);
|
||||||
remove_inode_page(inode);
|
update_inode(inode, page);
|
||||||
|
f2fs_put_page(page, 1);
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -368,9 +368,6 @@ no_delete:
|
||||||
if (is_inode_flag_set(fi, FI_UPDATE_WRITE))
|
if (is_inode_flag_set(fi, FI_UPDATE_WRITE))
|
||||||
add_ino_entry(sbi, inode->i_ino, UPDATE_INO);
|
add_ino_entry(sbi, inode->i_ino, UPDATE_INO);
|
||||||
if (is_inode_flag_set(fi, FI_FREE_NID)) {
|
if (is_inode_flag_set(fi, FI_FREE_NID)) {
|
||||||
if (err && err != -ENOENT)
|
|
||||||
alloc_nid_done(sbi, inode->i_ino);
|
|
||||||
else
|
|
||||||
alloc_nid_failed(sbi, inode->i_ino);
|
alloc_nid_failed(sbi, inode->i_ino);
|
||||||
clear_inode_flag(fi, FI_FREE_NID);
|
clear_inode_flag(fi, FI_FREE_NID);
|
||||||
}
|
}
|
||||||
|
@ -397,37 +394,32 @@ out_clear:
|
||||||
void handle_failed_inode(struct inode *inode)
|
void handle_failed_inode(struct inode *inode)
|
||||||
{
|
{
|
||||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||||
int err = 0;
|
struct node_info ni;
|
||||||
|
|
||||||
clear_nlink(inode);
|
/* don't make bad inode, since it becomes a regular file. */
|
||||||
make_bad_inode(inode);
|
|
||||||
unlock_new_inode(inode);
|
unlock_new_inode(inode);
|
||||||
|
|
||||||
i_size_write(inode, 0);
|
|
||||||
if (F2FS_HAS_BLOCKS(inode))
|
|
||||||
err = f2fs_truncate(inode, false);
|
|
||||||
|
|
||||||
if (!err)
|
|
||||||
err = remove_inode_page(inode);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we skip truncate_node in remove_inode_page bacause we failed
|
|
||||||
* before, it's better to find another way to release resource of
|
|
||||||
* this inode (e.g. valid block count, node block or nid). Here we
|
|
||||||
* choose to add this inode to orphan list, so that we can call iput
|
|
||||||
* for releasing in orphan recovery flow.
|
|
||||||
*
|
|
||||||
* Note: we should add inode to orphan list before f2fs_unlock_op()
|
* Note: we should add inode to orphan list before f2fs_unlock_op()
|
||||||
* so we can prevent losing this orphan when encoutering checkpoint
|
* so we can prevent losing this orphan when encoutering checkpoint
|
||||||
* and following suddenly power-off.
|
* and following suddenly power-off.
|
||||||
*/
|
*/
|
||||||
if (err && err != -ENOENT) {
|
get_node_info(sbi, inode->i_ino, &ni);
|
||||||
err = acquire_orphan_inode(sbi);
|
|
||||||
if (!err)
|
if (ni.blk_addr != NULL_ADDR) {
|
||||||
|
int err = acquire_orphan_inode(sbi);
|
||||||
|
if (err) {
|
||||||
|
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||||
|
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||||
|
"Too many orphan inodes, run fsck to fix.");
|
||||||
|
} else {
|
||||||
add_orphan_inode(sbi, inode->i_ino);
|
add_orphan_inode(sbi, inode->i_ino);
|
||||||
}
|
}
|
||||||
|
alloc_nid_done(sbi, inode->i_ino);
|
||||||
|
} else {
|
||||||
set_inode_flag(F2FS_I(inode), FI_FREE_NID);
|
set_inode_flag(F2FS_I(inode), FI_FREE_NID);
|
||||||
|
}
|
||||||
|
|
||||||
f2fs_unlock_op(sbi);
|
f2fs_unlock_op(sbi);
|
||||||
|
|
||||||
/* iput will drop the inode object */
|
/* iput will drop the inode object */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче