aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChao Yu <yuchao0@huawei.com>2018-08-14 10:37:25 -0400
committerJaegeuk Kim <jaegeuk@kernel.org>2018-08-21 02:13:42 -0400
commit6aa58d8ad20a3323f42274c25820a6f54192422d (patch)
tree63829cd8fe1ab14c9af2342c6d862d371613479d
parent6f8d4455060dfb0e32dfb8e685b97caf4ed1be41 (diff)
f2fs: readahead encrypted block during GC
During GC, for each encrypted block, we will read block synchronously into meta page, and then submit it into current cold data log area. So this block read model with 4k granularity can make poor performance, like migrating non-encrypted block, let's readahead encrypted block as well to improve migration performance. To implement this, we choose meta page that its index is old block address of the encrypted block, and readahead ciphertext into this page, later, if readaheaded page is still updated, we will load its data into target meta page, and submit the write IO. Note that for OPU, truncation, deletion, we need to invalid meta page after we invalid old block address, to make sure we won't load invalid data from target meta page during encrypted block migration. for ((i = 0; i < 1000; i++)) do { xfs_io -f /mnt/f2fs/dir/$i -c "pwrite 0 128k" -c "fsync"; } done for ((i = 0; i < 1000; i+=2)) do { rm /mnt/f2fs/dir/$i; } done ret = ioctl(fd, F2FS_IOC_GARBAGE_COLLECT, 0); Before: gc-6549 [001] d..1 214682.212797: block_rq_insert: 8,32 RA 32768 () 786400 + 64 [gc] gc-6549 [001] d..1 214682.212802: block_unplug: [gc] 1 gc-6549 [001] .... 214682.213892: block_bio_queue: 8,32 R 67494144 + 8 [gc] gc-6549 [001] .... 214682.213899: block_getrq: 8,32 R 67494144 + 8 [gc] gc-6549 [001] .... 214682.213902: block_plug: [gc] gc-6549 [001] d..1 214682.213905: block_rq_insert: 8,32 R 4096 () 67494144 + 8 [gc] gc-6549 [001] d..1 214682.213908: block_unplug: [gc] 1 gc-6549 [001] .... 214682.226405: block_bio_queue: 8,32 R 67494152 + 8 [gc] gc-6549 [001] .... 214682.226412: block_getrq: 8,32 R 67494152 + 8 [gc] gc-6549 [001] .... 214682.226414: block_plug: [gc] gc-6549 [001] d..1 214682.226417: block_rq_insert: 8,32 R 4096 () 67494152 + 8 [gc] gc-6549 [001] d..1 214682.226420: block_unplug: [gc] 1 gc-6549 [001] .... 214682.226904: block_bio_queue: 8,32 R 67494160 + 8 [gc] gc-6549 [001] .... 214682.226910: block_getrq: 8,32 R 67494160 + 8 [gc] gc-6549 [001] .... 214682.226911: block_plug: [gc] gc-6549 [001] d..1 214682.226914: block_rq_insert: 8,32 R 4096 () 67494160 + 8 [gc] gc-6549 [001] d..1 214682.226916: block_unplug: [gc] 1 After: gc-5678 [003] .... 214327.025906: block_bio_queue: 8,32 R 67493824 + 8 [gc] gc-5678 [003] .... 214327.025908: block_bio_backmerge: 8,32 R 67493824 + 8 [gc] gc-5678 [003] .... 214327.025915: block_bio_queue: 8,32 R 67493832 + 8 [gc] gc-5678 [003] .... 214327.025917: block_bio_backmerge: 8,32 R 67493832 + 8 [gc] gc-5678 [003] .... 214327.025923: block_bio_queue: 8,32 R 67493840 + 8 [gc] gc-5678 [003] .... 214327.025925: block_bio_backmerge: 8,32 R 67493840 + 8 [gc] gc-5678 [003] .... 214327.025932: block_bio_queue: 8,32 R 67493848 + 8 [gc] gc-5678 [003] .... 214327.025934: block_bio_backmerge: 8,32 R 67493848 + 8 [gc] gc-5678 [003] .... 214327.025941: block_bio_queue: 8,32 R 67493856 + 8 [gc] gc-5678 [003] .... 214327.025943: block_bio_backmerge: 8,32 R 67493856 + 8 [gc] gc-5678 [003] .... 214327.025953: block_bio_queue: 8,32 R 67493864 + 8 [gc] gc-5678 [003] .... 214327.025955: block_bio_backmerge: 8,32 R 67493864 + 8 [gc] gc-5678 [003] .... 214327.025962: block_bio_queue: 8,32 R 67493872 + 8 [gc] gc-5678 [003] .... 214327.025964: block_bio_backmerge: 8,32 R 67493872 + 8 [gc] gc-5678 [003] .... 214327.025970: block_bio_queue: 8,32 R 67493880 + 8 [gc] gc-5678 [003] .... 214327.025972: block_bio_backmerge: 8,32 R 67493880 + 8 [gc] gc-5678 [003] .... 214327.026000: block_bio_queue: 8,32 WS 34123776 + 2048 [gc] gc-5678 [003] .... 214327.026019: block_getrq: 8,32 WS 34123776 + 2048 [gc] gc-5678 [003] d..1 214327.026021: block_rq_insert: 8,32 R 131072 () 67493632 + 256 [gc] gc-5678 [003] d..1 214327.026023: block_unplug: [gc] 1 gc-5678 [003] d..1 214327.026026: block_rq_issue: 8,32 R 131072 () 67493632 + 256 [gc] gc-5678 [003] .... 214327.026046: block_plug: [gc] Signed-off-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--fs/f2fs/data.c35
-rw-r--r--fs/f2fs/gc.c111
-rw-r--r--fs/f2fs/segment.c10
3 files changed, 134 insertions, 22 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index e73ce11de02d..382c1ef9a9e4 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -875,6 +875,7 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
875 struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); 875 struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
876 struct f2fs_summary sum; 876 struct f2fs_summary sum;
877 struct node_info ni; 877 struct node_info ni;
878 block_t old_blkaddr;
878 pgoff_t fofs; 879 pgoff_t fofs;
879 blkcnt_t count = 1; 880 blkcnt_t count = 1;
880 int err; 881 int err;
@@ -896,9 +897,12 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
896 897
897alloc: 898alloc:
898 set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); 899 set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
899 900 old_blkaddr = dn->data_blkaddr;
900 f2fs_allocate_data_block(sbi, NULL, dn->data_blkaddr, &dn->data_blkaddr, 901 f2fs_allocate_data_block(sbi, NULL, old_blkaddr, &dn->data_blkaddr,
901 &sum, seg_type, NULL, false); 902 &sum, seg_type, NULL, false);
903 if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO)
904 invalidate_mapping_pages(META_MAPPING(sbi),
905 old_blkaddr, old_blkaddr);
902 f2fs_set_data_blkaddr(dn); 906 f2fs_set_data_blkaddr(dn);
903 907
904 /* update i_size */ 908 /* update i_size */
@@ -1614,6 +1618,7 @@ static int f2fs_read_data_pages(struct file *file,
1614static int encrypt_one_page(struct f2fs_io_info *fio) 1618static int encrypt_one_page(struct f2fs_io_info *fio)
1615{ 1619{
1616 struct inode *inode = fio->page->mapping->host; 1620 struct inode *inode = fio->page->mapping->host;
1621 struct page *mpage;
1617 gfp_t gfp_flags = GFP_NOFS; 1622 gfp_t gfp_flags = GFP_NOFS;
1618 1623
1619 if (!f2fs_encrypted_file(inode)) 1624 if (!f2fs_encrypted_file(inode))
@@ -1625,17 +1630,25 @@ static int encrypt_one_page(struct f2fs_io_info *fio)
1625retry_encrypt: 1630retry_encrypt:
1626 fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page, 1631 fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page,
1627 PAGE_SIZE, 0, fio->page->index, gfp_flags); 1632 PAGE_SIZE, 0, fio->page->index, gfp_flags);
1628 if (!IS_ERR(fio->encrypted_page)) 1633 if (IS_ERR(fio->encrypted_page)) {
1629 return 0; 1634 /* flush pending IOs and wait for a while in the ENOMEM case */
1635 if (PTR_ERR(fio->encrypted_page) == -ENOMEM) {
1636 f2fs_flush_merged_writes(fio->sbi);
1637 congestion_wait(BLK_RW_ASYNC, HZ/50);
1638 gfp_flags |= __GFP_NOFAIL;
1639 goto retry_encrypt;
1640 }
1641 return PTR_ERR(fio->encrypted_page);
1642 }
1630 1643
1631 /* flush pending IOs and wait for a while in the ENOMEM case */ 1644 mpage = find_lock_page(META_MAPPING(fio->sbi), fio->old_blkaddr);
1632 if (PTR_ERR(fio->encrypted_page) == -ENOMEM) { 1645 if (mpage) {
1633 f2fs_flush_merged_writes(fio->sbi); 1646 if (PageUptodate(mpage))
1634 congestion_wait(BLK_RW_ASYNC, HZ/50); 1647 memcpy(page_address(mpage),
1635 gfp_flags |= __GFP_NOFAIL; 1648 page_address(fio->encrypted_page), PAGE_SIZE);
1636 goto retry_encrypt; 1649 f2fs_put_page(mpage, 1);
1637 } 1650 }
1638 return PTR_ERR(fio->encrypted_page); 1651 return 0;
1639} 1652}
1640 1653
1641static inline bool check_inplace_update_policy(struct inode *inode, 1654static inline bool check_inplace_update_policy(struct inode *inode,
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index c598ae5ecbfa..5c8d00422237 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -599,6 +599,72 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
599 return true; 599 return true;
600} 600}
601 601
602static int ra_data_block(struct inode *inode, pgoff_t index)
603{
604 struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
605 struct address_space *mapping = inode->i_mapping;
606 struct dnode_of_data dn;
607 struct page *page;
608 struct extent_info ei = {0, 0, 0};
609 struct f2fs_io_info fio = {
610 .sbi = sbi,
611 .ino = inode->i_ino,
612 .type = DATA,
613 .temp = COLD,
614 .op = REQ_OP_READ,
615 .op_flags = 0,
616 .encrypted_page = NULL,
617 .in_list = false,
618 .retry = false,
619 };
620 int err;
621
622 page = f2fs_grab_cache_page(mapping, index, true);
623 if (!page)
624 return -ENOMEM;
625
626 if (f2fs_lookup_extent_cache(inode, index, &ei)) {
627 dn.data_blkaddr = ei.blk + index - ei.fofs;
628 goto got_it;
629 }
630
631 set_new_dnode(&dn, inode, NULL, NULL, 0);
632 err = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE);
633 if (err)
634 goto put_page;
635 f2fs_put_dnode(&dn);
636
637 if (unlikely(!f2fs_is_valid_blkaddr(sbi, dn.data_blkaddr,
638 DATA_GENERIC))) {
639 err = -EFAULT;
640 goto put_page;
641 }
642got_it:
643 /* read page */
644 fio.page = page;
645 fio.new_blkaddr = fio.old_blkaddr = dn.data_blkaddr;
646
647 fio.encrypted_page = f2fs_pagecache_get_page(META_MAPPING(sbi),
648 dn.data_blkaddr,
649 FGP_LOCK | FGP_CREAT, GFP_NOFS);
650 if (!fio.encrypted_page) {
651 err = -ENOMEM;
652 goto put_page;
653 }
654
655 err = f2fs_submit_page_bio(&fio);
656 if (err)
657 goto put_encrypted_page;
658 f2fs_put_page(fio.encrypted_page, 0);
659 f2fs_put_page(page, 1);
660 return 0;
661put_encrypted_page:
662 f2fs_put_page(fio.encrypted_page, 1);
663put_page:
664 f2fs_put_page(page, 1);
665 return err;
666}
667
602/* 668/*
603 * Move data block via META_MAPPING while keeping locked data page. 669 * Move data block via META_MAPPING while keeping locked data page.
604 * This can be used to move blocks, aka LBAs, directly on disk. 670 * This can be used to move blocks, aka LBAs, directly on disk.
@@ -620,7 +686,7 @@ static void move_data_block(struct inode *inode, block_t bidx,
620 struct dnode_of_data dn; 686 struct dnode_of_data dn;
621 struct f2fs_summary sum; 687 struct f2fs_summary sum;
622 struct node_info ni; 688 struct node_info ni;
623 struct page *page; 689 struct page *page, *mpage;
624 block_t newaddr; 690 block_t newaddr;
625 int err; 691 int err;
626 bool lfs_mode = test_opt(fio.sbi, LFS); 692 bool lfs_mode = test_opt(fio.sbi, LFS);
@@ -683,6 +749,23 @@ static void move_data_block(struct inode *inode, block_t bidx,
683 goto recover_block; 749 goto recover_block;
684 } 750 }
685 751
752 mpage = f2fs_pagecache_get_page(META_MAPPING(fio.sbi),
753 fio.old_blkaddr, FGP_LOCK, GFP_NOFS);
754 if (mpage) {
755 bool updated = false;
756
757 if (PageUptodate(mpage)) {
758 memcpy(page_address(fio.encrypted_page),
759 page_address(mpage), PAGE_SIZE);
760 updated = true;
761 }
762 f2fs_put_page(mpage, 1);
763 invalidate_mapping_pages(META_MAPPING(fio.sbi),
764 fio.old_blkaddr, fio.old_blkaddr);
765 if (updated)
766 goto write_page;
767 }
768
686 err = f2fs_submit_page_bio(&fio); 769 err = f2fs_submit_page_bio(&fio);
687 if (err) 770 if (err)
688 goto put_page_out; 771 goto put_page_out;
@@ -699,6 +782,7 @@ static void move_data_block(struct inode *inode, block_t bidx,
699 goto put_page_out; 782 goto put_page_out;
700 } 783 }
701 784
785write_page:
702 set_page_dirty(fio.encrypted_page); 786 set_page_dirty(fio.encrypted_page);
703 f2fs_wait_on_page_writeback(fio.encrypted_page, DATA, true); 787 f2fs_wait_on_page_writeback(fio.encrypted_page, DATA, true);
704 if (clear_page_dirty_for_io(fio.encrypted_page)) 788 if (clear_page_dirty_for_io(fio.encrypted_page))
@@ -873,12 +957,6 @@ next_step:
873 if (IS_ERR(inode) || is_bad_inode(inode)) 957 if (IS_ERR(inode) || is_bad_inode(inode))
874 continue; 958 continue;
875 959
876 /* if inode uses special I/O path, let's go phase 3 */
877 if (f2fs_post_read_required(inode)) {
878 add_gc_inode(gc_list, inode);
879 continue;
880 }
881
882 if (!down_write_trylock( 960 if (!down_write_trylock(
883 &F2FS_I(inode)->i_gc_rwsem[WRITE])) { 961 &F2FS_I(inode)->i_gc_rwsem[WRITE])) {
884 iput(inode); 962 iput(inode);
@@ -886,10 +964,23 @@ next_step:
886 continue; 964 continue;
887 } 965 }
888 966
889 start_bidx = f2fs_start_bidx_of_node(nofs, inode); 967 start_bidx = f2fs_start_bidx_of_node(nofs, inode) +
968 ofs_in_node;
969
970 if (f2fs_post_read_required(inode)) {
971 int err = ra_data_block(inode, start_bidx);
972
973 up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
974 if (err) {
975 iput(inode);
976 continue;
977 }
978 add_gc_inode(gc_list, inode);
979 continue;
980 }
981
890 data_page = f2fs_get_read_data_page(inode, 982 data_page = f2fs_get_read_data_page(inode,
891 start_bidx + ofs_in_node, REQ_RAHEAD, 983 start_bidx, REQ_RAHEAD, true);
892 true);
893 up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); 984 up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
894 if (IS_ERR(data_page)) { 985 if (IS_ERR(data_page)) {
895 iput(inode); 986 iput(inode);
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 7dcfe38e70cc..30779aaa9dba 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2079,6 +2079,8 @@ void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr)
2079 if (addr == NEW_ADDR) 2079 if (addr == NEW_ADDR)
2080 return; 2080 return;
2081 2081
2082 invalidate_mapping_pages(META_MAPPING(sbi), addr, addr);
2083
2082 /* add it into sit main buffer */ 2084 /* add it into sit main buffer */
2083 down_write(&sit_i->sentry_lock); 2085 down_write(&sit_i->sentry_lock);
2084 2086
@@ -2978,6 +2980,9 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
2978reallocate: 2980reallocate:
2979 f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr, 2981 f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
2980 &fio->new_blkaddr, sum, type, fio, true); 2982 &fio->new_blkaddr, sum, type, fio, true);
2983 if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO)
2984 invalidate_mapping_pages(META_MAPPING(fio->sbi),
2985 fio->old_blkaddr, fio->old_blkaddr);
2981 2986
2982 /* writeout dirty page into bdev */ 2987 /* writeout dirty page into bdev */
2983 f2fs_submit_page_write(fio); 2988 f2fs_submit_page_write(fio);
@@ -3132,8 +3137,11 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
3132 3137
3133 if (!recover_curseg || recover_newaddr) 3138 if (!recover_curseg || recover_newaddr)
3134 update_sit_entry(sbi, new_blkaddr, 1); 3139 update_sit_entry(sbi, new_blkaddr, 1);
3135 if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) 3140 if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) {
3141 invalidate_mapping_pages(META_MAPPING(sbi),
3142 old_blkaddr, old_blkaddr);
3136 update_sit_entry(sbi, old_blkaddr, -1); 3143 update_sit_entry(sbi, old_blkaddr, -1);
3144 }
3137 3145
3138 locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr)); 3146 locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr));
3139 locate_dirty_segment(sbi, GET_SEGNO(sbi, new_blkaddr)); 3147 locate_dirty_segment(sbi, GET_SEGNO(sbi, new_blkaddr));