mirror of https://gitee.com/openkylin/linux.git
f2fs: invalidate the node page if allocation is failed
The new_node_page() is processed as the following procedure. 1. A new node page is allocated. 2. Set PageUptodate with proper footer information. 3. Check if there is a free space for allocation 4.a. If there is no space, f2fs returns with -ENOSPC. 4.b. Otherwise, go next. In the case of step #4.a, f2fs remains a wrong node page in the page cache with the uptodate flag. Also, even though a new node page is allocated successfully, an error can be occurred afterwards due to allocation failure of the other data structures. In such a case, remove_inode_page() would be triggered, so that we have to clear uptodate flag in truncate_node() too. So, we should remove the uptodate flag, if allocation is failed. Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
This commit is contained in:
parent
690e4a3ead
commit
71e9fec548
|
@ -484,12 +484,14 @@ static void truncate_node(struct dnode_of_data *dn)
|
||||||
struct node_info ni;
|
struct node_info ni;
|
||||||
|
|
||||||
get_node_info(sbi, dn->nid, &ni);
|
get_node_info(sbi, dn->nid, &ni);
|
||||||
|
if (dn->inode->i_blocks == 0) {
|
||||||
|
BUG_ON(ni.blk_addr != NULL_ADDR);
|
||||||
|
goto invalidate;
|
||||||
|
}
|
||||||
BUG_ON(ni.blk_addr == NULL_ADDR);
|
BUG_ON(ni.blk_addr == NULL_ADDR);
|
||||||
|
|
||||||
if (ni.blk_addr != NULL_ADDR)
|
|
||||||
invalidate_blocks(sbi, ni.blk_addr);
|
|
||||||
|
|
||||||
/* Deallocate node address */
|
/* Deallocate node address */
|
||||||
|
invalidate_blocks(sbi, ni.blk_addr);
|
||||||
dec_valid_node_count(sbi, dn->inode, 1);
|
dec_valid_node_count(sbi, dn->inode, 1);
|
||||||
set_node_addr(sbi, &ni, NULL_ADDR);
|
set_node_addr(sbi, &ni, NULL_ADDR);
|
||||||
|
|
||||||
|
@ -499,7 +501,7 @@ static void truncate_node(struct dnode_of_data *dn)
|
||||||
} else {
|
} else {
|
||||||
sync_inode_page(dn);
|
sync_inode_page(dn);
|
||||||
}
|
}
|
||||||
|
invalidate:
|
||||||
clear_node_page_dirty(dn->node_page);
|
clear_node_page_dirty(dn->node_page);
|
||||||
F2FS_SET_SB_DIRT(sbi);
|
F2FS_SET_SB_DIRT(sbi);
|
||||||
|
|
||||||
|
@ -768,20 +770,12 @@ int remove_inode_page(struct inode *inode)
|
||||||
dn.inode_page_locked = 1;
|
dn.inode_page_locked = 1;
|
||||||
truncate_node(&dn);
|
truncate_node(&dn);
|
||||||
}
|
}
|
||||||
if (inode->i_blocks == 1) {
|
|
||||||
/* inernally call f2fs_put_page() */
|
|
||||||
set_new_dnode(&dn, inode, page, page, ino);
|
|
||||||
truncate_node(&dn);
|
|
||||||
} else if (inode->i_blocks == 0) {
|
|
||||||
struct node_info ni;
|
|
||||||
get_node_info(sbi, inode->i_ino, &ni);
|
|
||||||
|
|
||||||
/* called after f2fs_new_inode() is failed */
|
/* 0 is possible, after f2fs_new_inode() is failed */
|
||||||
BUG_ON(ni.blk_addr != NULL_ADDR);
|
BUG_ON(inode->i_blocks != 0 && inode->i_blocks != 1);
|
||||||
f2fs_put_page(page, 1);
|
set_new_dnode(&dn, inode, page, page, ino);
|
||||||
} else {
|
truncate_node(&dn);
|
||||||
BUG();
|
|
||||||
}
|
|
||||||
mutex_unlock_op(sbi, NODE_TRUNC);
|
mutex_unlock_op(sbi, NODE_TRUNC);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -845,6 +839,7 @@ struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs)
|
||||||
return page;
|
return page;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
clear_node_page_dirty(page);
|
||||||
f2fs_put_page(page, 1);
|
f2fs_put_page(page, 1);
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue