Commit 39a86958 authored by Chao Yu's avatar Chao Yu Committed by Jaegeuk Kim

f2fs: refactor ->page_mkwrite() flow

Thread A				Thread B
- f2fs_vm_page_mkwrite
					- f2fs_setattr
					 - down_write(i_mmap_sem)
					 - truncate_setsize
					 - f2fs_truncate
					 - up_write(i_mmap_sem)
 - f2fs_reserve_block
 reserve NEW_ADDR
 - skip dirty page due to truncation

1. we don't need to rserve new block address for a truncated page.
2. dn.data_blkaddr is used out of node page lock coverage.

Refactor ->page_mkwrite() flow to fix above issues:
- use __do_map_lock() to avoid racing checkpoint()
- lock data page in prior to dnode page
- cover f2fs_reserve_block with i_mmap_sem lock
- wait page writeback before zeroing page
Signed-off-by: default avatarChao Yu <yuchao0@huawei.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent bab475c5
...@@ -972,7 +972,7 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from) ...@@ -972,7 +972,7 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
return err; return err;
} }
static inline void __do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock) void __do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock)
{ {
if (flag == F2FS_GET_BLOCK_PRE_AIO) { if (flag == F2FS_GET_BLOCK_PRE_AIO) {
if (lock) if (lock)
......
...@@ -3055,6 +3055,7 @@ struct page *f2fs_get_lock_data_page(struct inode *inode, pgoff_t index, ...@@ -3055,6 +3055,7 @@ struct page *f2fs_get_lock_data_page(struct inode *inode, pgoff_t index,
struct page *f2fs_get_new_data_page(struct inode *inode, struct page *f2fs_get_new_data_page(struct inode *inode,
struct page *ipage, pgoff_t index, bool new_i_size); struct page *ipage, pgoff_t index, bool new_i_size);
int f2fs_do_write_data_page(struct f2fs_io_info *fio); int f2fs_do_write_data_page(struct f2fs_io_info *fio);
void __do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock);
int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
int create, int flag); int create, int flag);
int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
......
...@@ -47,7 +47,7 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) ...@@ -47,7 +47,7 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
struct page *page = vmf->page; struct page *page = vmf->page;
struct inode *inode = file_inode(vmf->vma->vm_file); struct inode *inode = file_inode(vmf->vma->vm_file);
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct dnode_of_data dn; struct dnode_of_data dn = { .node_changed = false };
int err; int err;
if (unlikely(f2fs_cp_error(sbi))) { if (unlikely(f2fs_cp_error(sbi))) {
...@@ -59,19 +59,6 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) ...@@ -59,19 +59,6 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
f2fs_bug_on(sbi, f2fs_has_inline_data(inode)); f2fs_bug_on(sbi, f2fs_has_inline_data(inode));
/* block allocation */
f2fs_lock_op(sbi);
set_new_dnode(&dn, inode, NULL, NULL, 0);
err = f2fs_reserve_block(&dn, page->index);
if (err) {
f2fs_unlock_op(sbi);
goto out;
}
f2fs_put_dnode(&dn);
f2fs_unlock_op(sbi);
f2fs_balance_fs(sbi, dn.node_changed);
file_update_time(vmf->vma->vm_file); file_update_time(vmf->vma->vm_file);
down_read(&F2FS_I(inode)->i_mmap_sem); down_read(&F2FS_I(inode)->i_mmap_sem);
lock_page(page); lock_page(page);
...@@ -83,11 +70,28 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) ...@@ -83,11 +70,28 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
goto out_sem; goto out_sem;
} }
/* block allocation */
__do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true);
set_new_dnode(&dn, inode, NULL, NULL, 0);
err = f2fs_get_block(&dn, page->index);
f2fs_put_dnode(&dn);
__do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false);
if (err) {
unlock_page(page);
goto out_sem;
}
/* fill the page */
f2fs_wait_on_page_writeback(page, DATA, false);
/* wait for GCed page writeback via META_MAPPING */
f2fs_wait_on_block_writeback(inode, dn.data_blkaddr);
/* /*
* check to see if the page is mapped already (no holes) * check to see if the page is mapped already (no holes)
*/ */
if (PageMappedToDisk(page)) if (PageMappedToDisk(page))
goto mapped; goto out_sem;
/* page is wholly or partially inside EOF */ /* page is wholly or partially inside EOF */
if (((loff_t)(page->index + 1) << PAGE_SHIFT) > if (((loff_t)(page->index + 1) << PAGE_SHIFT) >
...@@ -104,16 +108,11 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) ...@@ -104,16 +108,11 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
f2fs_update_iostat(sbi, APP_MAPPED_IO, F2FS_BLKSIZE); f2fs_update_iostat(sbi, APP_MAPPED_IO, F2FS_BLKSIZE);
trace_f2fs_vm_page_mkwrite(page, DATA); trace_f2fs_vm_page_mkwrite(page, DATA);
mapped:
/* fill the page */
f2fs_wait_on_page_writeback(page, DATA, false);
/* wait for GCed page writeback via META_MAPPING */
f2fs_wait_on_block_writeback(inode, dn.data_blkaddr);
out_sem: out_sem:
up_read(&F2FS_I(inode)->i_mmap_sem); up_read(&F2FS_I(inode)->i_mmap_sem);
out:
f2fs_balance_fs(sbi, dn.node_changed);
sb_end_pagefault(inode->i_sb); sb_end_pagefault(inode->i_sb);
f2fs_update_time(sbi, REQ_TIME); f2fs_update_time(sbi, REQ_TIME);
err: err:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment