From 91942321e4c9f8460f260cdfcf0a7a48a73a84a4 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 20 May 2016 10:13:22 -0700 Subject: f2fs: use inode pointer for {set, clear}_inode_flag This patch refactors to use inode pointer for set_inode_flag and clear_inode_flag. Signed-off-by: Jaegeuk Kim --- fs/f2fs/gc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/f2fs/gc.c') diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 38d56f678912..4a03076074af 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -617,9 +617,9 @@ static void move_encrypted_block(struct inode *inode, block_t bidx) f2fs_submit_page_mbio(&fio); f2fs_update_data_blkaddr(&dn, newaddr); - set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE); + set_inode_flag(inode, FI_APPEND_WRITE); if (page->index == 0) - set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN); + set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN); put_page_out: f2fs_put_page(fio.encrypted_page, 1); recover_block: -- cgit v1.2.3-59-g8ed1b From 19a5f5e2ef37f032efd840ada257bce2e91c8066 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Sat, 4 Jun 2016 14:25:24 -0700 Subject: f2fs: drop any block plugging In f2fs, we don't need to keep block plugging for NODE and DATA writes, since we already merged bios as much as possible. Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 4 ---- fs/f2fs/data.c | 17 ++++++++++------- fs/f2fs/gc.c | 5 ----- fs/f2fs/segment.c | 7 +------ 4 files changed, 11 insertions(+), 22 deletions(-) (limited to 'fs/f2fs/gc.c') diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 5ddd15cd6c6c..4179c7b971fc 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -897,11 +897,8 @@ static int block_operations(struct f2fs_sb_info *sbi) .nr_to_write = LONG_MAX, .for_reclaim = 0, }; - struct blk_plug plug; int err = 0; - blk_start_plug(&plug); - retry_flush_dents: f2fs_lock_all(sbi); /* write all the dirty dentry pages */ @@ -938,7 +935,6 @@ retry_flush_nodes: goto retry_flush_nodes; } out: - blk_finish_plug(&plug); return err; } diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 30dc448cae60..5f655d0c5b1f 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -98,10 +98,13 @@ static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr, } static inline void __submit_bio(struct f2fs_sb_info *sbi, int rw, - struct bio *bio) + struct bio *bio, enum page_type type) { - if (!is_read_io(rw)) + if (!is_read_io(rw)) { atomic_inc(&sbi->nr_wb_bios); + if (current->plug && (type == DATA || type == NODE)) + blk_finish_plug(current->plug); + } submit_bio(rw, bio); } @@ -117,7 +120,7 @@ static void __submit_merged_bio(struct f2fs_bio_info *io) else trace_f2fs_submit_write_bio(io->sbi->sb, fio, io->bio); - __submit_bio(io->sbi, fio->rw, io->bio); + __submit_bio(io->sbi, fio->rw, io->bio, fio->type); io->bio = NULL; } @@ -235,7 +238,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) return -EFAULT; } - __submit_bio(fio->sbi, fio->rw, bio); + __submit_bio(fio->sbi, fio->rw, bio, fio->type); return 0; } @@ -1040,7 +1043,7 @@ got_it: */ if (bio && (last_block_in_bio != block_nr - 1)) { submit_and_realloc: - __submit_bio(F2FS_I_SB(inode), READ, bio); + __submit_bio(F2FS_I_SB(inode), READ, bio, DATA); bio = NULL; } if (bio == NULL) { @@ -1083,7 +1086,7 @@ set_error_page: goto next_page; confused: if (bio) { - __submit_bio(F2FS_I_SB(inode), READ, bio); + __submit_bio(F2FS_I_SB(inode), READ, bio, DATA); bio = NULL; } unlock_page(page); @@ -1093,7 +1096,7 @@ next_page: } BUG_ON(pages && !list_empty(pages)); if (bio) - __submit_bio(F2FS_I_SB(inode), READ, bio); + __submit_bio(F2FS_I_SB(inode), READ, bio, DATA); return 0; } diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 4a03076074af..67fd2855ccc9 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -777,7 +777,6 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, { struct page *sum_page; struct f2fs_summary_block *sum; - struct blk_plug plug; unsigned int segno = start_segno; unsigned int end_segno = start_segno + sbi->segs_per_sec; int seg_freed = 0; @@ -795,8 +794,6 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, unlock_page(sum_page); } - blk_start_plug(&plug); - for (segno = start_segno; segno < end_segno; segno++) { /* find segment summary of victim */ sum_page = find_get_page(META_MAPPING(sbi), @@ -830,8 +827,6 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, f2fs_submit_merged_bio(sbi, (type == SUM_TYPE_NODE) ? NODE : DATA, WRITE); - blk_finish_plug(&plug); - if (gc_type == FG_GC) { while (start_segno < end_segno) if (get_valid_blocks(sbi, start_segno++, 1) == 0) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 7b58bfbd84a3..eff046a792ad 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -379,13 +379,8 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) excess_prefree_segs(sbi) || excess_dirty_nats(sbi) || (is_idle(sbi) && f2fs_time_over(sbi, CP_TIME))) { - if (test_opt(sbi, DATA_FLUSH)) { - struct blk_plug plug; - - blk_start_plug(&plug); + if (test_opt(sbi, DATA_FLUSH)) sync_dirty_inodes(sbi, FILE_INODE); - blk_finish_plug(&plug); - } f2fs_sync_fs(sbi->sb, true); stat_inc_bg_cp_count(sbi->stat_info); } -- cgit v1.2.3-59-g8ed1b From aa987273290d206b298e9d09db83e32ead661098 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Mon, 6 Jun 2016 18:49:54 -0700 Subject: f2fs: skip clean segment for gc If a segment in a section is clean or prefreed, we don't need to get its summary and do gc. Signed-off-by: Jaegeuk Kim --- fs/f2fs/gc.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'fs/f2fs/gc.c') diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 67fd2855ccc9..e1d274cdecb8 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -795,6 +795,10 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, } for (segno = start_segno; segno < end_segno; segno++) { + + if (get_valid_blocks(sbi, segno, 1) == 0) + continue; + /* find segment summary of victim */ sum_page = find_get_page(META_MAPPING(sbi), GET_SUM_BLOCK(sbi, segno)); -- cgit v1.2.3-59-g8ed1b From 1563ac75e7e45adcdc1271e6bb55fe27a23d4e4e Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Sun, 3 Jul 2016 22:05:12 +0800 Subject: f2fs: fix to detect truncation prior rather than EIO during read In procedure of synchonized read, after sending out the read request, reader will try to lock the page for waiting device to finish the read jobs and unlock the page, but meanwhile, truncater will race with reader, so after reader get lock of the page, it should check page's mapping to detect whether someone has truncated the page in advance, then reader has the chance to do the retry if truncation was done, otherwise read can be failed due to previous condition check. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 16 ++++++++-------- fs/f2fs/gc.c | 4 ++-- fs/f2fs/node.c | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'fs/f2fs/gc.c') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 53fae38009d3..3d93cf184114 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -500,14 +500,14 @@ repeat: /* wait for read completion */ lock_page(page); - if (unlikely(!PageUptodate(page))) { - f2fs_put_page(page, 1); - return ERR_PTR(-EIO); - } if (unlikely(page->mapping != mapping)) { f2fs_put_page(page, 1); goto repeat; } + if (unlikely(!PageUptodate(page))) { + f2fs_put_page(page, 1); + return ERR_PTR(-EIO); + } return page; } @@ -1647,14 +1647,14 @@ repeat: __submit_bio(sbi, READ_SYNC, bio, DATA); lock_page(page); - if (unlikely(!PageUptodate(page))) { - err = -EIO; - goto fail; - } if (unlikely(page->mapping != mapping)) { f2fs_put_page(page, 1); goto repeat; } + if (unlikely(!PageUptodate(page))) { + err = -EIO; + goto fail; + } } out_update: SetPageUptodate(page); diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index e1d274cdecb8..c9602d0dc57a 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -593,11 +593,11 @@ static void move_encrypted_block(struct inode *inode, block_t bidx) /* write page */ lock_page(fio.encrypted_page); - if (unlikely(!PageUptodate(fio.encrypted_page))) { + if (unlikely(fio.encrypted_page->mapping != META_MAPPING(fio.sbi))) { err = -EIO; goto put_page_out; } - if (unlikely(fio.encrypted_page->mapping != META_MAPPING(fio.sbi))) { + if (unlikely(!PageUptodate(fio.encrypted_page))) { err = -EIO; goto put_page_out; } diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 729fb1eb86ce..69171ce9b4b1 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1146,13 +1146,13 @@ repeat: lock_page(page); - if (unlikely(!PageUptodate(page))) - goto out_err; - if (unlikely(page->mapping != NODE_MAPPING(sbi))) { f2fs_put_page(page, 1); goto repeat; } + + if (unlikely(!PageUptodate(page))) + goto out_err; page_hit: if(unlikely(nid != nid_of_node(page))) { f2fs_bug_on(sbi, 1); -- cgit v1.2.3-59-g8ed1b From 72e1c797b57da42ce8f75c5636720f40c4f607a2 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Sun, 3 Jul 2016 22:05:13 +0800 Subject: f2fs: fix to redirty page if fail to gc data page If we fail to move data page during foreground GC, we should give another chance to writeback that page which was set dirty previously by writer. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/gc.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'fs/f2fs/gc.c') diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index c9602d0dc57a..c61213785914 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -653,12 +653,23 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type) .page = page, .encrypted_page = NULL, }; + bool is_dirty = PageDirty(page); + int err; + +retry: set_page_dirty(page); f2fs_wait_on_page_writeback(page, DATA, true); if (clear_page_dirty_for_io(page)) inode_dec_dirty_pages(inode); + set_cold_data(page); - do_write_data_page(&fio); + + err = do_write_data_page(&fio); + if (err == -ENOMEM && is_dirty) { + congestion_wait(BLK_RW_ASYNC, HZ/50); + goto retry; + } + clear_cold_data(page); } out: -- cgit v1.2.3-59-g8ed1b From 82e0a5aa5ddf794b3e1b21fcd091228736871882 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 13 Jul 2016 09:18:29 +0800 Subject: f2fs: fix to avoid data update racing between GC and DIO Datas in file can be operated by GC and DIO simultaneously, so we will face race case as below: For write case: Thread A Thread B - generic_file_direct_write - invalidate_inode_pages2_range - f2fs_direct_IO - do_blockdev_direct_IO - do_direct_IO - get_more_blocks - f2fs_gc - do_garbage_collect - gc_data_segment - move_data_page - do_write_data_page migrate data block to new block address - dio_bio_submit update user data to old block address For read case: Thread A Thread B - generic_file_direct_write - invalidate_inode_pages2_range - f2fs_direct_IO - do_blockdev_direct_IO - do_direct_IO - get_more_blocks - f2fs_balance_fs - f2fs_gc - do_garbage_collect - gc_data_segment - move_data_page - do_write_data_page migrate data block to new block address - write_checkpoint - do_checkpoint - clear_prefree_segments - f2fs_issue_discard discard old block adress - dio_bio_submit update user buffer from obsolete block address In order to fix this, for one file, we should let DIO and GC getting exclusion against with each other. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 6 +++++- fs/f2fs/f2fs.h | 1 + fs/f2fs/gc.c | 20 ++++++++++++++++++++ fs/f2fs/super.c | 2 ++ 4 files changed, 28 insertions(+), 1 deletion(-) (limited to 'fs/f2fs/gc.c') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 650099597dd2..adfe47b21991 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1716,6 +1716,7 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) struct inode *inode = mapping->host; size_t count = iov_iter_count(iter); loff_t offset = iocb->ki_pos; + int rw = iov_iter_rw(iter); int err; err = check_direct_IO(inode, iter, offset); @@ -1729,8 +1730,11 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) trace_f2fs_direct_IO_enter(inode, offset, count, iov_iter_rw(iter)); + down_read(&F2FS_I(inode)->dio_rwsem[rw]); err = blockdev_direct_IO(iocb, inode, iter, get_data_block_dio); - if (iov_iter_rw(iter) == WRITE) { + up_read(&F2FS_I(inode)->dio_rwsem[rw]); + + if (rw == WRITE) { if (err > 0) set_inode_flag(inode, FI_UPDATE_WRITE); else if (err < 0) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index b4a46b6823dc..211183c4e5c3 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -454,6 +454,7 @@ struct f2fs_inode_info { struct list_head inmem_pages; /* inmemory pages managed by f2fs */ struct mutex inmem_lock; /* lock for inmemory pages */ struct extent_tree *extent_tree; /* cached extent_tree entry */ + struct rw_semaphore dio_rwsem[2];/* avoid racing between dio and gc */ }; static inline void get_extent_info(struct extent_info *ext, diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index c61213785914..5c8acf754513 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -755,12 +755,32 @@ next_step: /* phase 3 */ inode = find_gc_inode(gc_list, dni.ino); if (inode) { + struct f2fs_inode_info *fi = F2FS_I(inode); + bool locked = false; + + if (S_ISREG(inode->i_mode)) { + if (!down_write_trylock(&fi->dio_rwsem[READ])) + continue; + if (!down_write_trylock( + &fi->dio_rwsem[WRITE])) { + up_write(&fi->dio_rwsem[READ]); + continue; + } + locked = true; + } + start_bidx = start_bidx_of_node(nofs, inode) + ofs_in_node; if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) move_encrypted_block(inode, start_bidx); else move_data_page(inode, start_bidx, gc_type); + + if (locked) { + up_write(&fi->dio_rwsem[WRITE]); + up_write(&fi->dio_rwsem[READ]); + } + stat_inc_data_blk_count(sbi, 1, gc_type); } } diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 451dfb4041e8..b97c065cbe74 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -579,6 +579,8 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) INIT_LIST_HEAD(&fi->gdirty_list); INIT_LIST_HEAD(&fi->inmem_pages); mutex_init(&fi->inmem_lock); + init_rwsem(&fi->dio_rwsem[READ]); + init_rwsem(&fi->dio_rwsem[WRITE]); /* Will be used by directory only */ fi->i_dir_level = F2FS_SB(sb)->dir_level; -- cgit v1.2.3-59-g8ed1b From 9dfa1baff76d08843aaf5e3c78f6da6950957702 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 13 Jul 2016 19:33:19 -0700 Subject: f2fs: use blk_plug in all the possible paths This patch reverts 19a5f5e2ef37 (f2fs: drop any block plugging), and adds blk_plug in write paths additionally. The main reason is that blk_start_plug can be used to wake up from low-power mode before submitting further bios. Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 7 +++++++ fs/f2fs/data.c | 3 +++ fs/f2fs/file.c | 6 +++++- fs/f2fs/gc.c | 5 +++++ fs/f2fs/node.c | 3 +++ fs/f2fs/segment.c | 7 ++++++- 6 files changed, 29 insertions(+), 2 deletions(-) (limited to 'fs/f2fs/gc.c') diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 8ea895389ae4..be1c54b62388 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -265,6 +265,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping, struct writeback_control *wbc) { struct f2fs_sb_info *sbi = F2FS_M_SB(mapping); + struct blk_plug plug; long diff, written; /* collect a number of dirty meta pages and write together */ @@ -277,7 +278,9 @@ static int f2fs_write_meta_pages(struct address_space *mapping, /* if mounting is failed, skip writing node pages */ mutex_lock(&sbi->cp_mutex); diff = nr_pages_to_write(sbi, META, wbc); + blk_start_plug(&plug); written = sync_meta_pages(sbi, META, wbc->nr_to_write); + blk_finish_plug(&plug); mutex_unlock(&sbi->cp_mutex); wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff); return 0; @@ -899,8 +902,11 @@ static int block_operations(struct f2fs_sb_info *sbi) .nr_to_write = LONG_MAX, .for_reclaim = 0, }; + struct blk_plug plug; int err = 0; + blk_start_plug(&plug); + retry_flush_dents: f2fs_lock_all(sbi); /* write all the dirty dentry pages */ @@ -937,6 +943,7 @@ retry_flush_nodes: goto retry_flush_nodes; } out: + blk_finish_plug(&plug); return err; } diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index adfe47b21991..87a458fb8afe 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1438,6 +1438,7 @@ static int f2fs_write_data_pages(struct address_space *mapping, { struct inode *inode = mapping->host; struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct blk_plug plug; int ret; /* deal with chardevs and other special file */ @@ -1463,7 +1464,9 @@ static int f2fs_write_data_pages(struct address_space *mapping, trace_f2fs_writepages(mapping->host, wbc, DATA); + blk_start_plug(&plug); ret = f2fs_write_cache_pages(mapping, wbc); + blk_finish_plug(&plug); /* * if some pages were truncated, we cannot guarantee its mapping->host * to detect pending bios. diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 72e52cd15b60..47f1f5e36d1c 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -2102,6 +2102,7 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); + struct blk_plug plug; ssize_t ret; if (f2fs_encrypted_inode(inode) && @@ -2113,8 +2114,11 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ret = generic_write_checks(iocb, from); if (ret > 0) { ret = f2fs_preallocate_blocks(iocb, from); - if (!ret) + if (!ret) { + blk_start_plug(&plug); ret = __generic_file_write_iter(iocb, from); + blk_finish_plug(&plug); + } } inode_unlock(inode); diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 5c8acf754513..de6c41c32c62 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -808,6 +808,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, { struct page *sum_page; struct f2fs_summary_block *sum; + struct blk_plug plug; unsigned int segno = start_segno; unsigned int end_segno = start_segno + sbi->segs_per_sec; int seg_freed = 0; @@ -825,6 +826,8 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, unlock_page(sum_page); } + blk_start_plug(&plug); + for (segno = start_segno; segno < end_segno; segno++) { if (get_valid_blocks(sbi, segno, 1) == 0) @@ -862,6 +865,8 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, f2fs_submit_merged_bio(sbi, (type == SUM_TYPE_NODE) ? NODE : DATA, WRITE); + blk_finish_plug(&plug); + if (gc_type == FG_GC) { while (start_segno < end_segno) if (get_valid_blocks(sbi, start_segno++, 1) == 0) diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index d78f61d647c0..79a93c6e632f 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1618,6 +1618,7 @@ static int f2fs_write_node_pages(struct address_space *mapping, struct writeback_control *wbc) { struct f2fs_sb_info *sbi = F2FS_M_SB(mapping); + struct blk_plug plug; long diff; /* balancing f2fs's metadata in background */ @@ -1631,7 +1632,9 @@ static int f2fs_write_node_pages(struct address_space *mapping, diff = nr_pages_to_write(sbi, NODE, wbc); wbc->sync_mode = WB_SYNC_NONE; + blk_start_plug(&plug); sync_node_pages(sbi, wbc); + blk_finish_plug(&plug); wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff); return 0; diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index e87aa058f57a..d45e6bbf8493 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -381,8 +381,13 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) excess_prefree_segs(sbi) || excess_dirty_nats(sbi) || (is_idle(sbi) && f2fs_time_over(sbi, CP_TIME))) { - if (test_opt(sbi, DATA_FLUSH)) + if (test_opt(sbi, DATA_FLUSH)) { + struct blk_plug plug; + + blk_start_plug(&plug); sync_dirty_inodes(sbi, FILE_INODE); + blk_finish_plug(&plug); + } f2fs_sync_fs(sbi->sb, true); stat_inc_bg_cp_count(sbi->stat_info); } -- cgit v1.2.3-59-g8ed1b From fe94793e555f650fab656649521fc38aaab4874e Mon Sep 17 00:00:00 2001 From: Yunlei He Date: Fri, 22 Jul 2016 19:08:31 +0800 Subject: f2fs: get victim segment again after new cp Previous selected segment may become free after write_checkpoint, if we do garbage collect on this segment, and then new_curseg happen to reuse it, it may cause f2fs_bug_on as below. panic+0x154/0x29c do_garbage_collect+0x15c/0xaf4 f2fs_gc+0x2dc/0x444 f2fs_balance_fs.part.22+0xcc/0x14c f2fs_balance_fs+0x28/0x34 f2fs_map_blocks+0x5ec/0x790 f2fs_preallocate_blocks+0xe0/0x100 f2fs_file_write_iter+0x64/0x11c new_sync_write+0xac/0x11c vfs_write+0x144/0x1e4 SyS_write+0x60/0xc0 Here, maybe we check sit and ssa type during reset_curseg. So, we check segment is stale or not, and select a new victim to avoid this. Signed-off-by: Yunlei He Signed-off-by: Jaegeuk Kim --- fs/f2fs/gc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'fs/f2fs/gc.c') diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index de6c41c32c62..06cfb94cc3db 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -908,10 +908,13 @@ gc_more: * enough free sections, we should flush dent/node blocks and do * garbage collections. */ - if (__get_victim(sbi, &segno, gc_type) || prefree_segments(sbi)) + if (__get_victim(sbi, &segno, gc_type) || + prefree_segments(sbi)) { write_checkpoint(sbi, &cpc); - else if (has_not_enough_free_secs(sbi, 0)) + segno = NULL_SEGNO; + } else if (has_not_enough_free_secs(sbi, 0)) { write_checkpoint(sbi, &cpc); + } } if (segno == NULL_SEGNO && !__get_victim(sbi, &segno, gc_type)) -- cgit v1.2.3-59-g8ed1b