mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-14 12:37:32 +00:00
f2fs: check truncation of mapping after lock_page
We call lock_page when we need to update a page after readpage. Between grab and lock page, the page can be truncated by other thread. So, we should check the page after lock_page whether it was truncated or not. Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
This commit is contained in:
parent
55008d845d
commit
afcb7ca01f
4 changed files with 39 additions and 7 deletions
|
@ -65,6 +65,10 @@ struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
|
||||||
goto repeat;
|
goto repeat;
|
||||||
|
|
||||||
lock_page(page);
|
lock_page(page);
|
||||||
|
if (page->mapping != mapping) {
|
||||||
|
f2fs_put_page(page, 1);
|
||||||
|
goto repeat;
|
||||||
|
}
|
||||||
out:
|
out:
|
||||||
mark_page_accessed(page);
|
mark_page_accessed(page);
|
||||||
return page;
|
return page;
|
||||||
|
|
|
@ -240,7 +240,7 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index)
|
||||||
|
|
||||||
if (dn.data_blkaddr == NULL_ADDR)
|
if (dn.data_blkaddr == NULL_ADDR)
|
||||||
return ERR_PTR(-ENOENT);
|
return ERR_PTR(-ENOENT);
|
||||||
|
repeat:
|
||||||
page = grab_cache_page(mapping, index);
|
page = grab_cache_page(mapping, index);
|
||||||
if (!page)
|
if (!page)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
@ -260,6 +260,10 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index)
|
||||||
f2fs_put_page(page, 1);
|
f2fs_put_page(page, 1);
|
||||||
return ERR_PTR(-EIO);
|
return ERR_PTR(-EIO);
|
||||||
}
|
}
|
||||||
|
if (page->mapping != mapping) {
|
||||||
|
f2fs_put_page(page, 1);
|
||||||
|
goto repeat;
|
||||||
|
}
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,7 +295,7 @@ struct page *get_new_data_page(struct inode *inode, pgoff_t index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f2fs_put_dnode(&dn);
|
f2fs_put_dnode(&dn);
|
||||||
|
repeat:
|
||||||
page = grab_cache_page(mapping, index);
|
page = grab_cache_page(mapping, index);
|
||||||
if (!page)
|
if (!page)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
@ -311,6 +315,10 @@ struct page *get_new_data_page(struct inode *inode, pgoff_t index,
|
||||||
f2fs_put_page(page, 1);
|
f2fs_put_page(page, 1);
|
||||||
return ERR_PTR(-EIO);
|
return ERR_PTR(-EIO);
|
||||||
}
|
}
|
||||||
|
if (page->mapping != mapping) {
|
||||||
|
f2fs_put_page(page, 1);
|
||||||
|
goto repeat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_i_size &&
|
if (new_i_size &&
|
||||||
|
@ -611,7 +619,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
|
||||||
*fsdata = NULL;
|
*fsdata = NULL;
|
||||||
|
|
||||||
f2fs_balance_fs(sbi);
|
f2fs_balance_fs(sbi);
|
||||||
|
repeat:
|
||||||
page = grab_cache_page_write_begin(mapping, index, flags);
|
page = grab_cache_page_write_begin(mapping, index, flags);
|
||||||
if (!page)
|
if (!page)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -656,6 +664,10 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
|
||||||
f2fs_put_page(page, 1);
|
f2fs_put_page(page, 1);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
if (page->mapping != mapping) {
|
||||||
|
f2fs_put_page(page, 1);
|
||||||
|
goto repeat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
SetPageUptodate(page);
|
SetPageUptodate(page);
|
||||||
|
|
|
@ -217,6 +217,10 @@ static void truncate_partial_data_page(struct inode *inode, u64 from)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lock_page(page);
|
lock_page(page);
|
||||||
|
if (page->mapping != inode->i_mapping) {
|
||||||
|
f2fs_put_page(page, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
wait_on_page_writeback(page);
|
wait_on_page_writeback(page);
|
||||||
zero_user(page, offset, PAGE_CACHE_SIZE - offset);
|
zero_user(page, offset, PAGE_CACHE_SIZE - offset);
|
||||||
set_page_dirty(page);
|
set_page_dirty(page);
|
||||||
|
|
|
@ -674,6 +674,7 @@ static int truncate_partial_nodes(struct dnode_of_data *dn,
|
||||||
int truncate_inode_blocks(struct inode *inode, pgoff_t from)
|
int truncate_inode_blocks(struct inode *inode, pgoff_t from)
|
||||||
{
|
{
|
||||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||||
|
struct address_space *node_mapping = sbi->node_inode->i_mapping;
|
||||||
int err = 0, cont = 1;
|
int err = 0, cont = 1;
|
||||||
int level, offset[4], noffset[4];
|
int level, offset[4], noffset[4];
|
||||||
unsigned int nofs = 0;
|
unsigned int nofs = 0;
|
||||||
|
@ -684,7 +685,7 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from)
|
||||||
trace_f2fs_truncate_inode_blocks_enter(inode, from);
|
trace_f2fs_truncate_inode_blocks_enter(inode, from);
|
||||||
|
|
||||||
level = get_node_path(from, offset, noffset);
|
level = get_node_path(from, offset, noffset);
|
||||||
|
restart:
|
||||||
page = get_node_page(sbi, inode->i_ino);
|
page = get_node_page(sbi, inode->i_ino);
|
||||||
if (IS_ERR(page)) {
|
if (IS_ERR(page)) {
|
||||||
trace_f2fs_truncate_inode_blocks_exit(inode, PTR_ERR(page));
|
trace_f2fs_truncate_inode_blocks_exit(inode, PTR_ERR(page));
|
||||||
|
@ -748,6 +749,10 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from)
|
||||||
if (offset[1] == 0 &&
|
if (offset[1] == 0 &&
|
||||||
rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK]) {
|
rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK]) {
|
||||||
lock_page(page);
|
lock_page(page);
|
||||||
|
if (page->mapping != node_mapping) {
|
||||||
|
f2fs_put_page(page, 1);
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
wait_on_page_writeback(page);
|
wait_on_page_writeback(page);
|
||||||
rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK] = 0;
|
rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK] = 0;
|
||||||
set_page_dirty(page);
|
set_page_dirty(page);
|
||||||
|
@ -916,7 +921,7 @@ struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
|
||||||
struct address_space *mapping = sbi->node_inode->i_mapping;
|
struct address_space *mapping = sbi->node_inode->i_mapping;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
int err;
|
int err;
|
||||||
|
repeat:
|
||||||
page = grab_cache_page(mapping, nid);
|
page = grab_cache_page(mapping, nid);
|
||||||
if (!page)
|
if (!page)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
@ -932,6 +937,10 @@ struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
|
||||||
f2fs_put_page(page, 1);
|
f2fs_put_page(page, 1);
|
||||||
return ERR_PTR(-EIO);
|
return ERR_PTR(-EIO);
|
||||||
}
|
}
|
||||||
|
if (page->mapping != mapping) {
|
||||||
|
f2fs_put_page(page, 1);
|
||||||
|
goto repeat;
|
||||||
|
}
|
||||||
got_it:
|
got_it:
|
||||||
BUG_ON(nid != nid_of_node(page));
|
BUG_ON(nid != nid_of_node(page));
|
||||||
mark_page_accessed(page);
|
mark_page_accessed(page);
|
||||||
|
@ -955,7 +964,7 @@ struct page *get_node_page_ra(struct page *parent, int start)
|
||||||
nid = get_nid(parent, start, false);
|
nid = get_nid(parent, start, false);
|
||||||
if (!nid)
|
if (!nid)
|
||||||
return ERR_PTR(-ENOENT);
|
return ERR_PTR(-ENOENT);
|
||||||
|
repeat:
|
||||||
page = grab_cache_page(mapping, nid);
|
page = grab_cache_page(mapping, nid);
|
||||||
if (!page)
|
if (!page)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
@ -981,7 +990,10 @@ struct page *get_node_page_ra(struct page *parent, int start)
|
||||||
blk_finish_plug(&plug);
|
blk_finish_plug(&plug);
|
||||||
|
|
||||||
lock_page(page);
|
lock_page(page);
|
||||||
|
if (page->mapping != mapping) {
|
||||||
|
f2fs_put_page(page, 1);
|
||||||
|
goto repeat;
|
||||||
|
}
|
||||||
page_hit:
|
page_hit:
|
||||||
if (!PageUptodate(page)) {
|
if (!PageUptodate(page)) {
|
||||||
f2fs_put_page(page, 1);
|
f2fs_put_page(page, 1);
|
||||||
|
|
Loading…
Reference in a new issue