Commit afcb7ca0 authored by Jaegeuk Kim's avatar Jaegeuk Kim
Browse files

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: default avatarJaegeuk Kim <jaegeuk.kim@samsung.com>
parent 55008d84
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -65,6 +65,10 @@ struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
		goto repeat;

	lock_page(page);
	if (page->mapping != mapping) {
		f2fs_put_page(page, 1);
		goto repeat;
	}
out:
	mark_page_accessed(page);
	return page;
+15 −3
Original line number Diff line number Diff line
@@ -240,7 +240,7 @@ struct page *get_lock_data_page(struct inode *inode, pgoff_t index)

	if (dn.data_blkaddr == NULL_ADDR)
		return ERR_PTR(-ENOENT);

repeat:
	page = grab_cache_page(mapping, index);
	if (!page)
		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);
		return ERR_PTR(-EIO);
	}
	if (page->mapping != mapping) {
		f2fs_put_page(page, 1);
		goto repeat;
	}
	return page;
}

@@ -291,7 +295,7 @@ struct page *get_new_data_page(struct inode *inode, pgoff_t index,
		}
	}
	f2fs_put_dnode(&dn);

repeat:
	page = grab_cache_page(mapping, index);
	if (!page)
		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);
			return ERR_PTR(-EIO);
		}
		if (page->mapping != mapping) {
			f2fs_put_page(page, 1);
			goto repeat;
		}
	}

	if (new_i_size &&
@@ -611,7 +619,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
	*fsdata = NULL;

	f2fs_balance_fs(sbi);

repeat:
	page = grab_cache_page_write_begin(mapping, index, flags);
	if (!page)
		return -ENOMEM;
@@ -656,6 +664,10 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
			f2fs_put_page(page, 1);
			return -EIO;
		}
		if (page->mapping != mapping) {
			f2fs_put_page(page, 1);
			goto repeat;
		}
	}
out:
	SetPageUptodate(page);
+4 −0
Original line number Diff line number Diff line
@@ -217,6 +217,10 @@ static void truncate_partial_data_page(struct inode *inode, u64 from)
		return;

	lock_page(page);
	if (page->mapping != inode->i_mapping) {
		f2fs_put_page(page, 1);
		return;
	}
	wait_on_page_writeback(page);
	zero_user(page, offset, PAGE_CACHE_SIZE - offset);
	set_page_dirty(page);
+16 −4
Original line number Diff line number Diff line
@@ -674,6 +674,7 @@ static int truncate_partial_nodes(struct dnode_of_data *dn,
int truncate_inode_blocks(struct inode *inode, pgoff_t from)
{
	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 level, offset[4], noffset[4];
	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);

	level = get_node_path(from, offset, noffset);

restart:
	page = get_node_page(sbi, inode->i_ino);
	if (IS_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 &&
				rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK]) {
			lock_page(page);
			if (page->mapping != node_mapping) {
				f2fs_put_page(page, 1);
				goto restart;
			}
			wait_on_page_writeback(page);
			rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK] = 0;
			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 page *page;
	int err;

repeat:
	page = grab_cache_page(mapping, nid);
	if (!page)
		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);
		return ERR_PTR(-EIO);
	}
	if (page->mapping != mapping) {
		f2fs_put_page(page, 1);
		goto repeat;
	}
got_it:
	BUG_ON(nid != nid_of_node(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);
	if (!nid)
		return ERR_PTR(-ENOENT);

repeat:
	page = grab_cache_page(mapping, nid);
	if (!page)
		return ERR_PTR(-ENOMEM);
@@ -981,7 +990,10 @@ struct page *get_node_page_ra(struct page *parent, int start)
	blk_finish_plug(&plug);

	lock_page(page);

	if (page->mapping != mapping) {
		f2fs_put_page(page, 1);
		goto repeat;
	}
page_hit:
	if (!PageUptodate(page)) {
		f2fs_put_page(page, 1);