On 2016/9/19 22:48, Chao Yu wrote: > On 2016/9/20 5:03, Weichao Guo wrote: >> This patch improves the migration of dirty pages and allows migrating atomic >> written pages that F2FS uses in Page Cache. Instead of the fallback releasing >> page path, it provides better performance for memory compaction, CMA and >> other >> users of memory page migrating. For dirty pages, there is no need to write >> back >> first when migrating. For an atomic written page before committing, we can >> migrate the page and update the related 'inmem_pages' list at the same time. >> >> Signed-off-by: Weichao Guo <guoweic...@huawei.com> >> --- >> fs/f2fs/checkpoint.c | 3 +++ >> fs/f2fs/data.c | 56 >> ++++++++++++++++++++++++++++++++++++++++++++++++++++ >> fs/f2fs/f2fs.h | 4 ++++ >> fs/f2fs/node.c | 3 +++ >> 4 files changed, 66 insertions(+) >> >> diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c >> index df56a43..a366521 100644 >> --- a/fs/f2fs/checkpoint.c >> +++ b/fs/f2fs/checkpoint.c >> @@ -388,6 +388,9 @@ const struct address_space_operations f2fs_meta_aops = { >> .set_page_dirty = f2fs_set_meta_page_dirty, >> .invalidatepage = f2fs_invalidate_page, >> .releasepage = f2fs_release_page, >> +#ifdef CONFIG_MIGRATION >> + .migratepage = f2fs_migrate_page, >> +#endif >> }; >> >> static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) >> diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c >> index 528c3c0..eb0d63f 100644 >> --- a/fs/f2fs/data.c >> +++ b/fs/f2fs/data.c >> @@ -1882,6 +1882,59 @@ static sector_t f2fs_bmap(struct address_space >> *mapping, sector_t block) >> return generic_block_bmap(mapping, block, get_data_block_bmap); >> } >> >> +#ifdef CONFIG_MIGRATION >> + >> +#include <linux/migrate.h> >> + >> +int f2fs_migrate_page(struct address_space *mapping, >> + struct page *newpage, struct page *page, enum migrate_mode mode) >> +{ >> + int rc, extra_count; >> + struct f2fs_inode_info *fi = F2FS_I(mapping->host); >> + bool atomic_written = IS_ATOMIC_WRITTEN_PAGE(page); >> + >> + BUG_ON(PageWriteback(page)); >> + >> + /* migrating an atomic written page is safe with the inmem_lock hold */ >> + if (atomic_written && !mutex_trylock(&fi->inmem_lock)) >> + return -EAGAIN; >> + >> + /* >> + * A reference is expected if PagePrivate set when move mapping, >> + * however F2FS breaks this for maintaining dirty page counts when >> + * truncating pages. So here adjusting the 'extra_count' make it work. >> + */ >> + extra_count = (atomic_written ? 1 : 0) - page_has_private(page); >> + rc = migrate_page_move_mapping(mapping, newpage, >> + page, NULL, mode, extra_count); >> + if (rc != MIGRATEPAGE_SUCCESS) { >> + if (atomic_written) >> + mutex_unlock(&fi->inmem_lock); >> + return rc; >> + } >> + >> + if (atomic_written) { >> + struct inmem_pages *cur; >> + list_for_each_entry(cur, &fi->inmem_pages, list) >> + if (cur->page == page) { >> + cur->page = newpage; >> + break; >> + } >> + mutex_unlock(&fi->inmem_lock); >> + put_page(page); >> + get_page(newpage); > > Should we also do put_page(oldpage) & get_page(newpage) for > non-atomic-written page? > No, the 'page_count' of the old/new page for Page Cache has been maintained in 'migrate_page_move_mapping'. As atomic-written pages have an additional reference, we should update their 'page_count' here. > Thanks, > >> + } >> + >> + if (PagePrivate(page)) >> + SetPagePrivate(newpage); >> + set_page_private(newpage, page_private(page)); >> + >> + migrate_page_copy(newpage, page); >> + >> + return MIGRATEPAGE_SUCCESS; >> +} >> +#endif >> + >> const struct address_space_operations f2fs_dblock_aops = { >> .readpage = f2fs_read_data_page, >> .readpages = f2fs_read_data_pages, >> @@ -1894,4 +1947,7 @@ const struct address_space_operations f2fs_dblock_aops >> = { >> .releasepage = f2fs_release_page, >> .direct_IO = f2fs_direct_IO, >> .bmap = f2fs_bmap, >> +#ifdef CONFIG_MIGRATION >> + .migratepage = f2fs_migrate_page, >> +#endif >> }; >> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h >> index 5d2aa6a..b951482 100644 >> --- a/fs/f2fs/f2fs.h >> +++ b/fs/f2fs/f2fs.h >> @@ -2126,6 +2126,10 @@ int f2fs_fiemap(struct inode *inode, struct >> fiemap_extent_info *, u64, u64); >> void f2fs_set_page_dirty_nobuffers(struct page *); >> void f2fs_invalidate_page(struct page *, unsigned int, unsigned int); >> int f2fs_release_page(struct page *, gfp_t); >> +#ifdef CONFIG_MIGRATION >> +int f2fs_migrate_page(struct address_space *mapping, >> + struct page *newpage, struct page *page, enum migrate_mode mode); >> +#endif >> >> /* >> * gc.c >> diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c >> index 2322a8e..55c22a9 100644 >> --- a/fs/f2fs/node.c >> +++ b/fs/f2fs/node.c >> @@ -1670,6 +1670,9 @@ const struct address_space_operations f2fs_node_aops = >> { >> .set_page_dirty = f2fs_set_node_page_dirty, >> .invalidatepage = f2fs_invalidate_page, >> .releasepage = f2fs_release_page, >> +#ifdef CONFIG_MIGRATION >> + .migratepage = f2fs_migrate_page, >> +#endif >> }; >> >> static struct free_nid *__lookup_free_nid_list(struct f2fs_nm_info *nm_i, >> > > . >
------------------------------------------------------------------------------ _______________________________________________ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel