From d8207f69589c74037128ff6c9e1a44223fad3b7c Mon Sep 17 00:00:00 2001 From: Gu Zheng Date: Thu, 25 Jul 2013 11:30:01 +0800 Subject: f2fs: move bio_private allocation out of f2fs_bio_alloc() bio->bi_private is not always needed. As in the reading data path, end_read_io does not need bio_private for further using, so moving bio_private allocation out of f2fs_bio_alloc(). Alloc it in the submit_write_page(), and ignore it in the f2fs_readpage(). Signed-off-by: Gu Zheng Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'fs/f2fs/segment.c') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index a86d125a988..9b74ae2137d 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -611,18 +611,12 @@ static void f2fs_end_io_write(struct bio *bio, int err) struct bio *f2fs_bio_alloc(struct block_device *bdev, int npages) { struct bio *bio; - struct bio_private *priv; -retry: - priv = kmalloc(sizeof(struct bio_private), GFP_NOFS); - if (!priv) { - cond_resched(); - goto retry; - } /* No failure on bio allocation */ bio = bio_alloc(GFP_NOIO, npages); bio->bi_bdev = bdev; - bio->bi_private = priv; + bio->bi_private = NULL; + return bio; } @@ -681,8 +675,17 @@ static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page, do_submit_bio(sbi, type, false); alloc_new: if (sbi->bio[type] == NULL) { + struct bio_private *priv; +retry: + priv = kmalloc(sizeof(struct bio_private), GFP_NOFS); + if (!priv) { + cond_resched(); + goto retry; + } + sbi->bio[type] = f2fs_bio_alloc(bdev, max_hw_blocks(sbi)); sbi->bio[type]->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr); + sbi->bio[type]->bi_private = priv; /* * The end_io will be assigned at the sumbission phase. * Until then, let bio_add_page() merge consecutive IOs as much -- cgit v1.2.3-70-g09d2 From a569469e967022d9ceeaa4b73619f96614087d2d Mon Sep 17 00:00:00 2001 From: Jin Xu Date: Mon, 5 Aug 2013 20:02:04 +0800 Subject: f2fs: fix a deadlock in fsync This patch fixes a deadlock bug that occurs quite often when there are concurrent write and fsync on a same file. Following is the simplified call trace when tasks get hung. fsync thread: - f2fs_sync_file ... - f2fs_write_data_pages ... - update_extent_cache ... - update_inode - wait_on_page_writeback bdi writeback thread - __writeback_single_inode - f2fs_write_data_pages - mutex_lock(sbi->writepages) The deadlock happens when the fsync thread waits on a inode page that has been added to the f2fs' cached bio sbi->bio[NODE], and unfortunately, no one else could be able to submit the cached bio to block layer for writeback. This is because the fsync thread already hold a sbi->fs_lock and the sbi->writepages lock, causing the bdi thread being blocked when attempt to write data pages for the same inode. At the same time, f2fs_gc thread does not notice the situation and could not help. Even the sync syscall gets blocked. To fix it, we could submit the cached bio first before waiting on a inode page that is being written back. Signed-off-by: Jin Xu [Jaegeuk Kim: add more cases to use f2fs_wait_on_page_writeback] Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 2 +- fs/f2fs/f2fs.h | 3 ++- fs/f2fs/gc.c | 8 ++------ fs/f2fs/inode.c | 2 +- fs/f2fs/segment.c | 10 ++++++++++ 5 files changed, 16 insertions(+), 9 deletions(-) (limited to 'fs/f2fs/segment.c') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index f458883af81..a7eb5292572 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -37,7 +37,7 @@ static void __set_data_blkaddr(struct dnode_of_data *dn, block_t new_addr) struct page *node_page = dn->node_page; unsigned int ofs_in_node = dn->ofs_in_node; - wait_on_page_writeback(node_page); + f2fs_wait_on_page_writeback(node_page, NODE, false); rn = F2FS_NODE(node_page); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 63813befdd8..13db10b70e6 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1023,7 +1023,8 @@ int npages_for_summary_flush(struct f2fs_sb_info *); void allocate_new_segments(struct f2fs_sb_info *); struct page *get_sum_page(struct f2fs_sb_info *, unsigned int); struct bio *f2fs_bio_alloc(struct block_device *, int); -void f2fs_submit_bio(struct f2fs_sb_info *, enum page_type, bool sync); +void f2fs_submit_bio(struct f2fs_sb_info *, enum page_type, bool); +void f2fs_wait_on_page_writeback(struct page *, enum page_type, bool); void write_meta_page(struct f2fs_sb_info *, struct page *); void write_node_page(struct f2fs_sb_info *, struct page *, unsigned int, block_t, block_t *); diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index d286d8be8e6..e6b3ffd5ff6 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -422,8 +422,7 @@ next_step: /* set page dirty and write it */ if (gc_type == FG_GC) { - f2fs_submit_bio(sbi, NODE, true); - wait_on_page_writeback(node_page); + f2fs_wait_on_page_writeback(node_page, NODE, true); set_page_dirty(node_page); } else { if (!PageWriteback(node_page)) @@ -523,10 +522,7 @@ static void move_data_page(struct inode *inode, struct page *page, int gc_type) } else { struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); - if (PageWriteback(page)) { - f2fs_submit_bio(sbi, DATA, true); - wait_on_page_writeback(page); - } + f2fs_wait_on_page_writeback(page, DATA, true); if (clear_page_dirty_for_io(page) && S_ISDIR(inode->i_mode)) { diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index debf7430804..9ab81e7472c 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -151,7 +151,7 @@ void update_inode(struct inode *inode, struct page *node_page) struct f2fs_node *rn; struct f2fs_inode *ri; - wait_on_page_writeback(node_page); + f2fs_wait_on_page_writeback(node_page, NODE, false); rn = F2FS_NODE(node_page); ri = &(rn->i); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 9b74ae2137d..68e344f9e04 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -705,6 +705,16 @@ retry: trace_f2fs_submit_write_page(page, blk_addr, type); } +void f2fs_wait_on_page_writeback(struct page *page, + enum page_type type, bool sync) +{ + struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb); + if (PageWriteback(page)) { + f2fs_submit_bio(sbi, type, sync); + wait_on_page_writeback(page); + } +} + static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type) { struct curseg_info *curseg = CURSEG_I(sbi, type); -- cgit v1.2.3-70-g09d2 From 41dfde135f9169948dd0c9bba948774f2e521210 Mon Sep 17 00:00:00 2001 From: Gu Zheng Date: Fri, 9 Aug 2013 18:21:24 +0800 Subject: f2fs: clean up the needless end 'return' of void function Signed-off-by: Gu Zheng Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 1 - fs/f2fs/node.c | 1 - fs/f2fs/segment.c | 4 ---- fs/f2fs/super.c | 1 - 4 files changed, 7 deletions(-) (limited to 'fs/f2fs/segment.c') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index a7eb5292572..ea3cb29018e 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -176,7 +176,6 @@ void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn) end_update: write_unlock(&fi->ext.ext_lock); sync_inode_page(dn); - return; } struct page *find_data_page(struct inode *inode, pgoff_t index, bool sync) diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index f5172e271d4..bb8fbda4366 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -916,7 +916,6 @@ void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid) f2fs_put_page(apage, 0); else if (err == LOCKED_PAGE) f2fs_put_page(apage, 1); - return; } struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 68e344f9e04..9c45b8ee688 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -117,7 +117,6 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) } mutex_unlock(&dirty_i->seglist_lock); - return; } /* @@ -261,7 +260,6 @@ static void __add_sum_entry(struct f2fs_sb_info *sbi, int type, void *addr = curseg->sum_blk; addr += curseg->next_blkoff * sizeof(struct f2fs_summary); memcpy(addr, sum, sizeof(struct f2fs_summary)); - return; } /* @@ -559,7 +557,6 @@ out: #ifdef CONFIG_F2FS_STAT_FS sbi->segment_count[curseg->alloc_type]++; #endif - return; } void allocate_new_segments(struct f2fs_sb_info *sbi) @@ -1192,7 +1189,6 @@ void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk) { if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG)) write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE); - return; } int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type, diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 66d1ec137e4..1d12e60c00d 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -317,7 +317,6 @@ static int f2fs_drop_inode(struct inode *inode) static void f2fs_dirty_inode(struct inode *inode, int flags) { set_inode_flag(F2FS_I(inode), FI_DIRTY_INODE); - return; } static void f2fs_i_callback(struct rcu_head *head) -- cgit v1.2.3-70-g09d2 From 7b40527508670e56d817b837b2114bc340446539 Mon Sep 17 00:00:00 2001 From: Gu Zheng Date: Mon, 19 Aug 2013 09:41:15 +0800 Subject: f2fs: fix a compound statement label error An error "label at end of compound statement" will occur if CONFIG_F2FS_STAT_FS disabled. fs/f2fs/segment.c:556:1: error: label at end of compound statement So clean up the 'out' label to fix it. Reported-by: Fengguang Wu Signed-off-by: Gu Zheng Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'fs/f2fs/segment.c') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 9c45b8ee688..09af9c7b0f5 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -540,12 +540,9 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi, { struct curseg_info *curseg = CURSEG_I(sbi, type); - if (force) { + if (force) new_curseg(sbi, type, true); - goto out; - } - - if (type == CURSEG_WARM_NODE) + else if (type == CURSEG_WARM_NODE) new_curseg(sbi, type, false); else if (curseg->alloc_type == LFS && is_next_segment_free(sbi, type)) new_curseg(sbi, type, false); @@ -553,7 +550,6 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi, change_curseg(sbi, type, true); else new_curseg(sbi, type, false); -out: #ifdef CONFIG_F2FS_STAT_FS sbi->segment_count[curseg->alloc_type]++; #endif -- cgit v1.2.3-70-g09d2