From: Nanzhe <[email protected]> Now write protect `mmap` also need to support large folio, Change `f2fs_vm_page_mkwrite` to acheive that.
Note it currently marks the whole large folio dirty to avoid data loss which causes write amplification. Further optimization is welcome. Signed-off-by: Nanzhe <[email protected]> --- fs/f2fs/data.c | 5 ++--- fs/f2fs/f2fs.h | 2 ++ fs/f2fs/file.c | 50 +++++++++++++++++++++++++++++++++----------------- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 2de8c7963080..346057826835 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -2512,7 +2512,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret, } #endif -static struct f2fs_folio_state *ffs_find_or_alloc(struct folio *folio) +struct f2fs_folio_state *ffs_find_or_alloc(struct folio *folio) { struct f2fs_folio_state *ffs; unsigned int nr_subpages = folio_nr_pages(folio); @@ -2596,8 +2596,7 @@ void ffs_mark_subrange_uptodate(struct folio *folio, size_t offset, size_t len) folio_mark_uptodate(folio); } -static void ffs_mark_subrange_dirty(struct folio *folio, - size_t offset, size_t len) +void ffs_mark_subrange_dirty(struct folio *folio, size_t offset, size_t len) { struct f2fs_folio_state *ffs; unsigned int nr_subpages, start, end; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index ac71d0d22a81..c9d0e9b41a91 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -4255,6 +4255,8 @@ int f2fs_write_single_data_page(struct folio *folio, int *submitted, int compr_blocks, bool allow_balance); bool ffs_test_blk_uptodate(const struct folio *folio, pgoff_t index); void ffs_mark_subrange_uptodate(struct folio *folio, size_t offset, size_t len); +struct f2fs_folio_state *ffs_find_or_alloc(struct folio *folio); +void ffs_mark_subrange_dirty(struct folio *folio, size_t offset, size_t len); void f2fs_write_failed(struct inode *inode, loff_t to); void f2fs_invalidate_folio(struct folio *folio, size_t offset, size_t length); bool f2fs_release_folio(struct folio *folio, gfp_t wait); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index eb8e237f3dad..c1b3c9d1ab92 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -78,6 +78,12 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct dnode_of_data dn; bool need_alloc = !f2fs_is_pinned_file(inode); + pgoff_t pidx = folio->index + folio_page_idx(folio, vmf->page); + loff_t pos = (loff_t)pidx << PAGE_SHIFT; + loff_t isize; + loff_t folio_start; + loff_t valid_end; + size_t dirty_len; int err = 0; vm_fault_t ret; @@ -114,7 +120,7 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) #ifdef CONFIG_F2FS_FS_COMPRESSION if (f2fs_compressed_file(inode)) { - int ret = f2fs_is_compressed_cluster(inode, folio->index); + int ret = f2fs_is_compressed_cluster(inode, pidx); if (ret < 0) { err = ret; @@ -132,14 +138,17 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) f2fs_bug_on(sbi, f2fs_has_inline_data(inode)); - f2fs_zero_post_eof_page(inode, (folio->index + 1) << PAGE_SHIFT, true); - file_update_time(vmf->vma->vm_file); filemap_invalidate_lock_shared(inode->i_mapping); folio_lock(folio); + isize = i_size_read(inode); + folio_start = folio_pos(folio); + valid_end = min_t(loff_t, folio_start + folio_size(folio), isize); + dirty_len = valid_end > folio_start ? valid_end - folio_start : 0; + if (unlikely(folio->mapping != inode->i_mapping || - folio_pos(folio) > i_size_read(inode) || + pos >= isize || !folio_test_uptodate(folio))) { folio_unlock(folio); err = -EFAULT; @@ -149,9 +158,19 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) set_new_dnode(&dn, inode, NULL, NULL, 0); if (need_alloc) { /* block allocation */ - err = f2fs_get_block_locked(&dn, folio->index); + if (folio_test_large(folio)) { + pgoff_t i, nr = DIV_ROUND_UP(dirty_len, PAGE_SIZE); + + for (i = 0; i < nr; i++) { + err = f2fs_get_block_locked(&dn, folio->index + i); + if (err) + break; + } + } else { + err = f2fs_get_block_locked(&dn, pidx); + } } else { - err = f2fs_get_dnode_of_data(&dn, folio->index, LOOKUP_NODE); + err = f2fs_get_dnode_of_data(&dn, pidx, LOOKUP_NODE); f2fs_put_dnode(&dn); if (f2fs_is_pinned_file(inode) && !__is_valid_data_blkaddr(dn.data_blkaddr)) @@ -168,20 +187,17 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) /* 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) - */ - if (folio_test_mappedtodisk(folio)) - goto out_sem; - /* page is wholly or partially inside EOF */ - if (((loff_t)(folio->index + 1) << PAGE_SHIFT) > - i_size_read(inode)) { - loff_t offset; + if (folio_start + folio_size(folio) > isize) { + size_t offset = offset_in_folio(folio, isize); - offset = i_size_read(inode) & ~PAGE_MASK; folio_zero_segment(folio, offset, folio_size(folio)); } + + if (folio_test_large(folio)) { + ffs_find_or_alloc(folio); + ffs_mark_subrange_dirty(folio, 0, dirty_len); + } folio_mark_dirty(folio); f2fs_update_iostat(sbi, inode, APP_MAPPED_IO, F2FS_BLKSIZE); @@ -194,7 +210,7 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) out: ret = vmf_fs_error(err); - trace_f2fs_vm_page_mkwrite(inode, folio->index, vmf->vma->vm_flags, ret); + trace_f2fs_vm_page_mkwrite(inode, pidx, vmf->vma->vm_flags, ret); return ret; } -- 2.34.1 _______________________________________________ Linux-f2fs-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
