diff options
author | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-04-24 00:19:56 -0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-04-25 21:35:10 -0400 |
commit | c718379b6b0954a04a153d7e5dc8b3136a301ee6 (patch) | |
tree | eca5d2d44291de009acb51ebc934f70de6d0ffa7 /fs/f2fs | |
parent | 6cb968d9b0358c7e807416a85699a526e820083c (diff) |
f2fs: give a chance to merge IOs by IO scheduler
Previously, background GC submits many 4KB read requests to load victim blocks
and/or its (i)node blocks.
...
f2fs_gc : f2fs_readpage: ino = 1, page_index = 0xb61, blkaddr = 0x3b964ed
f2fs_gc : block_rq_complete: 8,16 R () 499854968 + 8 [0]
f2fs_gc : f2fs_readpage: ino = 1, page_index = 0xb6f, blkaddr = 0x3b964ee
f2fs_gc : block_rq_complete: 8,16 R () 499854976 + 8 [0]
f2fs_gc : f2fs_readpage: ino = 1, page_index = 0xb79, blkaddr = 0x3b964ef
f2fs_gc : block_rq_complete: 8,16 R () 499854984 + 8 [0]
...
However, by the fact that many IOs are sequential, we can give a chance to merge
the IOs by IO scheduler.
In order to do that, let's use blk_plug.
...
f2fs_gc : f2fs_iget: ino = 143
f2fs_gc : f2fs_readpage: ino = 143, page_index = 0x1c6, blkaddr = 0x2e6ee
f2fs_gc : f2fs_iget: ino = 143
f2fs_gc : f2fs_readpage: ino = 143, page_index = 0x1c7, blkaddr = 0x2e6ef
<idle> : block_rq_complete: 8,16 R () 1519616 + 8 [0]
<idle> : block_rq_complete: 8,16 R () 1519848 + 8 [0]
<idle> : block_rq_complete: 8,16 R () 1520432 + 96 [0]
<idle> : block_rq_complete: 8,16 R () 1520536 + 104 [0]
<idle> : block_rq_complete: 8,16 R () 1521008 + 112 [0]
<idle> : block_rq_complete: 8,16 R () 1521440 + 152 [0]
<idle> : block_rq_complete: 8,16 R () 1521688 + 144 [0]
<idle> : block_rq_complete: 8,16 R () 1522128 + 192 [0]
<idle> : block_rq_complete: 8,16 R () 1523256 + 328 [0]
...
Note that this issue should be addressed in checkpoint, and some readahead
flows too.
Reviewed-by: Namjae Jeon <namjae.jeon@samsung.com>
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs/f2fs')
-rw-r--r-- | fs/f2fs/checkpoint.c | 5 | ||||
-rw-r--r-- | fs/f2fs/data.c | 15 | ||||
-rw-r--r-- | fs/f2fs/dir.c | 2 | ||||
-rw-r--r-- | fs/f2fs/f2fs.h | 2 | ||||
-rw-r--r-- | fs/f2fs/file.c | 2 | ||||
-rw-r--r-- | fs/f2fs/gc.c | 11 | ||||
-rw-r--r-- | fs/f2fs/node.c | 9 |
7 files changed, 36 insertions, 10 deletions
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index f54b83b4d90b..590ea50c80a7 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c | |||
@@ -549,6 +549,10 @@ static void block_operations(struct f2fs_sb_info *sbi) | |||
549 | .nr_to_write = LONG_MAX, | 549 | .nr_to_write = LONG_MAX, |
550 | .for_reclaim = 0, | 550 | .for_reclaim = 0, |
551 | }; | 551 | }; |
552 | struct blk_plug plug; | ||
553 | |||
554 | blk_start_plug(&plug); | ||
555 | |||
552 | retry_flush_dents: | 556 | retry_flush_dents: |
553 | mutex_lock_all(sbi); | 557 | mutex_lock_all(sbi); |
554 | 558 | ||
@@ -571,6 +575,7 @@ retry_flush_nodes: | |||
571 | sync_node_pages(sbi, 0, &wbc); | 575 | sync_node_pages(sbi, 0, &wbc); |
572 | goto retry_flush_nodes; | 576 | goto retry_flush_nodes; |
573 | } | 577 | } |
578 | blk_finish_plug(&plug); | ||
574 | } | 579 | } |
575 | 580 | ||
576 | static void unblock_operations(struct f2fs_sb_info *sbi) | 581 | static void unblock_operations(struct f2fs_sb_info *sbi) |
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 1220b5c2ea21..eba7e84d1ffd 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c | |||
@@ -172,7 +172,7 @@ end_update: | |||
172 | return; | 172 | return; |
173 | } | 173 | } |
174 | 174 | ||
175 | struct page *find_data_page(struct inode *inode, pgoff_t index) | 175 | struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync) |
176 | { | 176 | { |
177 | struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); | 177 | struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); |
178 | struct address_space *mapping = inode->i_mapping; | 178 | struct address_space *mapping = inode->i_mapping; |
@@ -207,11 +207,14 @@ struct page *find_data_page(struct inode *inode, pgoff_t index) | |||
207 | return page; | 207 | return page; |
208 | } | 208 | } |
209 | 209 | ||
210 | err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC); | 210 | err = f2fs_readpage(sbi, page, dn.data_blkaddr, |
211 | wait_on_page_locked(page); | 211 | sync ? READ_SYNC : READA); |
212 | if (!PageUptodate(page)) { | 212 | if (sync) { |
213 | f2fs_put_page(page, 0); | 213 | wait_on_page_locked(page); |
214 | return ERR_PTR(-EIO); | 214 | if (!PageUptodate(page)) { |
215 | f2fs_put_page(page, 0); | ||
216 | return ERR_PTR(-EIO); | ||
217 | } | ||
215 | } | 218 | } |
216 | return page; | 219 | return page; |
217 | } | 220 | } |
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index cd3342d4a3a7..3ddb1bc7d07a 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c | |||
@@ -148,7 +148,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir, | |||
148 | 148 | ||
149 | for (; bidx < end_block; bidx++) { | 149 | for (; bidx < end_block; bidx++) { |
150 | /* no need to allocate new dentry pages to all the indices */ | 150 | /* no need to allocate new dentry pages to all the indices */ |
151 | dentry_page = find_data_page(dir, bidx); | 151 | dentry_page = find_data_page(dir, bidx, true); |
152 | if (IS_ERR(dentry_page)) { | 152 | if (IS_ERR(dentry_page)) { |
153 | room = true; | 153 | room = true; |
154 | continue; | 154 | continue; |
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 06cc75c66c88..6283c8d77c2e 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h | |||
@@ -1023,7 +1023,7 @@ void destroy_checkpoint_caches(void); | |||
1023 | */ | 1023 | */ |
1024 | int reserve_new_block(struct dnode_of_data *); | 1024 | int reserve_new_block(struct dnode_of_data *); |
1025 | void update_extent_cache(block_t, struct dnode_of_data *); | 1025 | void update_extent_cache(block_t, struct dnode_of_data *); |
1026 | struct page *find_data_page(struct inode *, pgoff_t); | 1026 | struct page *find_data_page(struct inode *, pgoff_t, bool); |
1027 | struct page *get_lock_data_page(struct inode *, pgoff_t); | 1027 | struct page *get_lock_data_page(struct inode *, pgoff_t); |
1028 | struct page *get_new_data_page(struct inode *, pgoff_t, bool); | 1028 | struct page *get_new_data_page(struct inode *, pgoff_t, bool); |
1029 | int f2fs_readpage(struct f2fs_sb_info *, struct page *, block_t, int); | 1029 | int f2fs_readpage(struct f2fs_sb_info *, struct page *, block_t, int); |
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 0e56db2d3cc9..9dfcdab5ea7c 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c | |||
@@ -212,7 +212,7 @@ static void truncate_partial_data_page(struct inode *inode, u64 from) | |||
212 | if (!offset) | 212 | if (!offset) |
213 | return; | 213 | return; |
214 | 214 | ||
215 | page = find_data_page(inode, from >> PAGE_CACHE_SHIFT); | 215 | page = find_data_page(inode, from >> PAGE_CACHE_SHIFT, false); |
216 | if (IS_ERR(page)) | 216 | if (IS_ERR(page)) |
217 | return; | 217 | return; |
218 | 218 | ||
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 6ed3263eeee8..25a1f7e593e0 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c | |||
@@ -386,6 +386,7 @@ static void gc_node_segment(struct f2fs_sb_info *sbi, | |||
386 | 386 | ||
387 | next_step: | 387 | next_step: |
388 | entry = sum; | 388 | entry = sum; |
389 | |||
389 | for (off = 0; off < sbi->blocks_per_seg; off++, entry++) { | 390 | for (off = 0; off < sbi->blocks_per_seg; off++, entry++) { |
390 | nid_t nid = le32_to_cpu(entry->nid); | 391 | nid_t nid = le32_to_cpu(entry->nid); |
391 | struct page *node_page; | 392 | struct page *node_page; |
@@ -417,6 +418,7 @@ next_step: | |||
417 | f2fs_put_page(node_page, 1); | 418 | f2fs_put_page(node_page, 1); |
418 | stat_inc_node_blk_count(sbi, 1); | 419 | stat_inc_node_blk_count(sbi, 1); |
419 | } | 420 | } |
421 | |||
420 | if (initial) { | 422 | if (initial) { |
421 | initial = false; | 423 | initial = false; |
422 | goto next_step; | 424 | goto next_step; |
@@ -545,6 +547,7 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, | |||
545 | 547 | ||
546 | next_step: | 548 | next_step: |
547 | entry = sum; | 549 | entry = sum; |
550 | |||
548 | for (off = 0; off < sbi->blocks_per_seg; off++, entry++) { | 551 | for (off = 0; off < sbi->blocks_per_seg; off++, entry++) { |
549 | struct page *data_page; | 552 | struct page *data_page; |
550 | struct inode *inode; | 553 | struct inode *inode; |
@@ -582,7 +585,7 @@ next_step: | |||
582 | continue; | 585 | continue; |
583 | 586 | ||
584 | data_page = find_data_page(inode, | 587 | data_page = find_data_page(inode, |
585 | start_bidx + ofs_in_node); | 588 | start_bidx + ofs_in_node, false); |
586 | if (IS_ERR(data_page)) | 589 | if (IS_ERR(data_page)) |
587 | goto next_iput; | 590 | goto next_iput; |
588 | 591 | ||
@@ -603,6 +606,7 @@ next_step: | |||
603 | next_iput: | 606 | next_iput: |
604 | iput(inode); | 607 | iput(inode); |
605 | } | 608 | } |
609 | |||
606 | if (++phase < 4) | 610 | if (++phase < 4) |
607 | goto next_step; | 611 | goto next_step; |
608 | 612 | ||
@@ -636,12 +640,15 @@ static void do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno, | |||
636 | { | 640 | { |
637 | struct page *sum_page; | 641 | struct page *sum_page; |
638 | struct f2fs_summary_block *sum; | 642 | struct f2fs_summary_block *sum; |
643 | struct blk_plug plug; | ||
639 | 644 | ||
640 | /* read segment summary of victim */ | 645 | /* read segment summary of victim */ |
641 | sum_page = get_sum_page(sbi, segno); | 646 | sum_page = get_sum_page(sbi, segno); |
642 | if (IS_ERR(sum_page)) | 647 | if (IS_ERR(sum_page)) |
643 | return; | 648 | return; |
644 | 649 | ||
650 | blk_start_plug(&plug); | ||
651 | |||
645 | sum = page_address(sum_page); | 652 | sum = page_address(sum_page); |
646 | 653 | ||
647 | switch (GET_SUM_TYPE((&sum->footer))) { | 654 | switch (GET_SUM_TYPE((&sum->footer))) { |
@@ -652,6 +659,8 @@ static void do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno, | |||
652 | gc_data_segment(sbi, sum->entries, ilist, segno, gc_type); | 659 | gc_data_segment(sbi, sum->entries, ilist, segno, gc_type); |
653 | break; | 660 | break; |
654 | } | 661 | } |
662 | blk_finish_plug(&plug); | ||
663 | |||
655 | stat_inc_seg_count(sbi, GET_SUM_TYPE((&sum->footer))); | 664 | stat_inc_seg_count(sbi, GET_SUM_TYPE((&sum->footer))); |
656 | stat_inc_call_count(sbi->stat_info); | 665 | stat_inc_call_count(sbi->stat_info); |
657 | 666 | ||
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 5a825502b0b0..a0aa0446a237 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c | |||
@@ -89,10 +89,13 @@ static void ra_nat_pages(struct f2fs_sb_info *sbi, int nid) | |||
89 | { | 89 | { |
90 | struct address_space *mapping = sbi->meta_inode->i_mapping; | 90 | struct address_space *mapping = sbi->meta_inode->i_mapping; |
91 | struct f2fs_nm_info *nm_i = NM_I(sbi); | 91 | struct f2fs_nm_info *nm_i = NM_I(sbi); |
92 | struct blk_plug plug; | ||
92 | struct page *page; | 93 | struct page *page; |
93 | pgoff_t index; | 94 | pgoff_t index; |
94 | int i; | 95 | int i; |
95 | 96 | ||
97 | blk_start_plug(&plug); | ||
98 | |||
96 | for (i = 0; i < FREE_NID_PAGES; i++, nid += NAT_ENTRY_PER_BLOCK) { | 99 | for (i = 0; i < FREE_NID_PAGES; i++, nid += NAT_ENTRY_PER_BLOCK) { |
97 | if (nid >= nm_i->max_nid) | 100 | if (nid >= nm_i->max_nid) |
98 | nid = 0; | 101 | nid = 0; |
@@ -110,6 +113,7 @@ static void ra_nat_pages(struct f2fs_sb_info *sbi, int nid) | |||
110 | 113 | ||
111 | f2fs_put_page(page, 0); | 114 | f2fs_put_page(page, 0); |
112 | } | 115 | } |
116 | blk_finish_plug(&plug); | ||
113 | } | 117 | } |
114 | 118 | ||
115 | static struct nat_entry *__lookup_nat_cache(struct f2fs_nm_info *nm_i, nid_t n) | 119 | static struct nat_entry *__lookup_nat_cache(struct f2fs_nm_info *nm_i, nid_t n) |
@@ -942,6 +946,7 @@ struct page *get_node_page_ra(struct page *parent, int start) | |||
942 | { | 946 | { |
943 | struct f2fs_sb_info *sbi = F2FS_SB(parent->mapping->host->i_sb); | 947 | struct f2fs_sb_info *sbi = F2FS_SB(parent->mapping->host->i_sb); |
944 | struct address_space *mapping = sbi->node_inode->i_mapping; | 948 | struct address_space *mapping = sbi->node_inode->i_mapping; |
949 | struct blk_plug plug; | ||
945 | struct page *page; | 950 | struct page *page; |
946 | int err, i, end; | 951 | int err, i, end; |
947 | nid_t nid; | 952 | nid_t nid; |
@@ -961,6 +966,8 @@ struct page *get_node_page_ra(struct page *parent, int start) | |||
961 | else if (err == LOCKED_PAGE) | 966 | else if (err == LOCKED_PAGE) |
962 | goto page_hit; | 967 | goto page_hit; |
963 | 968 | ||
969 | blk_start_plug(&plug); | ||
970 | |||
964 | /* Then, try readahead for siblings of the desired node */ | 971 | /* Then, try readahead for siblings of the desired node */ |
965 | end = start + MAX_RA_NODE; | 972 | end = start + MAX_RA_NODE; |
966 | end = min(end, NIDS_PER_BLOCK); | 973 | end = min(end, NIDS_PER_BLOCK); |
@@ -971,6 +978,8 @@ struct page *get_node_page_ra(struct page *parent, int start) | |||
971 | ra_node_page(sbi, nid); | 978 | ra_node_page(sbi, nid); |
972 | } | 979 | } |
973 | 980 | ||
981 | blk_finish_plug(&plug); | ||
982 | |||
974 | lock_page(page); | 983 | lock_page(page); |
975 | 984 | ||
976 | page_hit: | 985 | page_hit: |