diff options
Diffstat (limited to 'fs/f2fs/segment.c')
| -rw-r--r-- | fs/f2fs/segment.c | 135 | 
1 files changed, 66 insertions, 69 deletions
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index a661ac32e829..808709581481 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -185,8 +185,6 @@ bool f2fs_need_SSR(struct f2fs_sb_info *sbi)  void f2fs_register_inmem_page(struct inode *inode, struct page *page)  { -	struct f2fs_sb_info *sbi = F2FS_I_SB(inode); -	struct f2fs_inode_info *fi = F2FS_I(inode);  	struct inmem_pages *new;  	f2fs_trace_pid(page); @@ -200,15 +198,11 @@ void f2fs_register_inmem_page(struct inode *inode, struct page *page)  	INIT_LIST_HEAD(&new->list);  	/* increase reference count with clean state */ -	mutex_lock(&fi->inmem_lock);  	get_page(page); -	list_add_tail(&new->list, &fi->inmem_pages); -	spin_lock(&sbi->inode_lock[ATOMIC_FILE]); -	if (list_empty(&fi->inmem_ilist)) -		list_add_tail(&fi->inmem_ilist, &sbi->inode_list[ATOMIC_FILE]); -	spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); +	mutex_lock(&F2FS_I(inode)->inmem_lock); +	list_add_tail(&new->list, &F2FS_I(inode)->inmem_pages);  	inc_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES); -	mutex_unlock(&fi->inmem_lock); +	mutex_unlock(&F2FS_I(inode)->inmem_lock);  	trace_f2fs_register_inmem_page(page, INMEM);  } @@ -330,19 +324,17 @@ void f2fs_drop_inmem_pages(struct inode *inode)  		mutex_lock(&fi->inmem_lock);  		__revoke_inmem_pages(inode, &fi->inmem_pages,  						true, false, true); - -		if (list_empty(&fi->inmem_pages)) { -			spin_lock(&sbi->inode_lock[ATOMIC_FILE]); -			if (!list_empty(&fi->inmem_ilist)) -				list_del_init(&fi->inmem_ilist); -			spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); -		}  		mutex_unlock(&fi->inmem_lock);  	}  	clear_inode_flag(inode, FI_ATOMIC_FILE);  	fi->i_gc_failures[GC_FAILURE_ATOMIC] = 0;  	stat_dec_atomic_write(inode); + +	spin_lock(&sbi->inode_lock[ATOMIC_FILE]); +	if (!list_empty(&fi->inmem_ilist)) +		list_del_init(&fi->inmem_ilist); +	spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);  }  void f2fs_drop_inmem_page(struct inode *inode, struct page *page) @@ -471,11 +463,6 @@ int f2fs_commit_inmem_pages(struct inode *inode)  	mutex_lock(&fi->inmem_lock);  	err = __f2fs_commit_inmem_pages(inode); - -	spin_lock(&sbi->inode_lock[ATOMIC_FILE]); -	if (!list_empty(&fi->inmem_ilist)) -		list_del_init(&fi->inmem_ilist); -	spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);  	mutex_unlock(&fi->inmem_lock);  	clear_inode_flag(inode, FI_ATOMIC_COMMIT); @@ -501,7 +488,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)  	if (need && excess_cached_nats(sbi))  		f2fs_balance_fs_bg(sbi); -	if (f2fs_is_checkpoint_ready(sbi)) +	if (!f2fs_is_checkpoint_ready(sbi))  		return;  	/* @@ -817,9 +804,13 @@ static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,  		if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))  			dirty_i->nr_dirty[t]--; -		if (get_valid_blocks(sbi, segno, true) == 0) +		if (get_valid_blocks(sbi, segno, true) == 0) {  			clear_bit(GET_SEC_FROM_SEG(sbi, segno),  						dirty_i->victim_secmap); +#ifdef CONFIG_F2FS_CHECK_FS +			clear_bit(segno, SIT_I(sbi)->invalid_segmap); +#endif +		}  	}  } @@ -2084,6 +2075,13 @@ static void destroy_discard_cmd_control(struct f2fs_sb_info *sbi)  	f2fs_stop_discard_thread(sbi); +	/* +	 * Recovery can cache discard commands, so in error path of +	 * fill_super(), it needs to give a chance to handle them. +	 */ +	if (unlikely(atomic_read(&dcc->discard_cmd_cnt))) +		f2fs_issue_discard_timeout(sbi); +  	kvfree(dcc);  	SM_I(sbi)->dcc_info = NULL;  } @@ -2156,9 +2154,11 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)  		if (!f2fs_test_and_set_bit(offset, se->discard_map))  			sbi->discard_blks--; -		/* don't overwrite by SSR to keep node chain */ -		if (IS_NODESEG(se->type) && -				!is_sbi_flag_set(sbi, SBI_CP_DISABLED)) { +		/* +		 * SSR should never reuse block which is checkpointed +		 * or newly invalidated. +		 */ +		if (!is_sbi_flag_set(sbi, SBI_CP_DISABLED)) {  			if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map))  				se->ckpt_valid_blocks++;  		} @@ -3116,12 +3116,14 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,  		f2fs_inode_chksum_set(sbi, page);  	} +	if (F2FS_IO_ALIGNED(sbi)) +		fio->retry = false; +  	if (add_list) {  		struct f2fs_bio_info *io;  		INIT_LIST_HEAD(&fio->list);  		fio->in_list = true; -		fio->retry = false;  		io = sbi->write_io[fio->type] + fio->temp;  		spin_lock(&io->io_lock);  		list_add_tail(&fio->list, &io->io_list); @@ -3447,11 +3449,6 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi)  		seg_i = CURSEG_I(sbi, i);  		segno = le32_to_cpu(ckpt->cur_data_segno[i]);  		blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]); -		if (blk_off > ENTRIES_IN_SUM) { -			f2fs_bug_on(sbi, 1); -			f2fs_put_page(page, 1); -			return -EFAULT; -		}  		seg_i->next_segno = segno;  		reset_curseg(sbi, i, 0);  		seg_i->alloc_type = ckpt->alloc_type[i]; @@ -3941,8 +3938,8 @@ static int build_sit_info(struct f2fs_sb_info *sbi)  	struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);  	struct sit_info *sit_i;  	unsigned int sit_segs, start; -	char *src_bitmap; -	unsigned int bitmap_size; +	char *src_bitmap, *bitmap; +	unsigned int bitmap_size, main_bitmap_size, sit_bitmap_size;  	/* allocate memory for SIT information */  	sit_i = f2fs_kzalloc(sbi, sizeof(struct sit_info), GFP_KERNEL); @@ -3958,33 +3955,37 @@ static int build_sit_info(struct f2fs_sb_info *sbi)  	if (!sit_i->sentries)  		return -ENOMEM; -	bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi)); -	sit_i->dirty_sentries_bitmap = f2fs_kvzalloc(sbi, bitmap_size, +	main_bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi)); +	sit_i->dirty_sentries_bitmap = f2fs_kvzalloc(sbi, main_bitmap_size,  								GFP_KERNEL);  	if (!sit_i->dirty_sentries_bitmap)  		return -ENOMEM; +#ifdef CONFIG_F2FS_CHECK_FS +	bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * 4; +#else +	bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * 3; +#endif +	sit_i->bitmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL); +	if (!sit_i->bitmap) +		return -ENOMEM; + +	bitmap = sit_i->bitmap; +  	for (start = 0; start < MAIN_SEGS(sbi); start++) { -		sit_i->sentries[start].cur_valid_map -			= f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); -		sit_i->sentries[start].ckpt_valid_map -			= f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); -		if (!sit_i->sentries[start].cur_valid_map || -				!sit_i->sentries[start].ckpt_valid_map) -			return -ENOMEM; +		sit_i->sentries[start].cur_valid_map = bitmap; +		bitmap += SIT_VBLOCK_MAP_SIZE; + +		sit_i->sentries[start].ckpt_valid_map = bitmap; +		bitmap += SIT_VBLOCK_MAP_SIZE;  #ifdef CONFIG_F2FS_CHECK_FS -		sit_i->sentries[start].cur_valid_map_mir -			= f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); -		if (!sit_i->sentries[start].cur_valid_map_mir) -			return -ENOMEM; +		sit_i->sentries[start].cur_valid_map_mir = bitmap; +		bitmap += SIT_VBLOCK_MAP_SIZE;  #endif -		sit_i->sentries[start].discard_map -			= f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, -							GFP_KERNEL); -		if (!sit_i->sentries[start].discard_map) -			return -ENOMEM; +		sit_i->sentries[start].discard_map = bitmap; +		bitmap += SIT_VBLOCK_MAP_SIZE;  	}  	sit_i->tmp_map = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL); @@ -4004,17 +4005,23 @@ static int build_sit_info(struct f2fs_sb_info *sbi)  	sit_segs = le32_to_cpu(raw_super->segment_count_sit) >> 1;  	/* setup SIT bitmap from ckeckpoint pack */ -	bitmap_size = __bitmap_size(sbi, SIT_BITMAP); +	sit_bitmap_size = __bitmap_size(sbi, SIT_BITMAP);  	src_bitmap = __bitmap_ptr(sbi, SIT_BITMAP); -	sit_i->sit_bitmap = kmemdup(src_bitmap, bitmap_size, GFP_KERNEL); +	sit_i->sit_bitmap = kmemdup(src_bitmap, sit_bitmap_size, GFP_KERNEL);  	if (!sit_i->sit_bitmap)  		return -ENOMEM;  #ifdef CONFIG_F2FS_CHECK_FS -	sit_i->sit_bitmap_mir = kmemdup(src_bitmap, bitmap_size, GFP_KERNEL); +	sit_i->sit_bitmap_mir = kmemdup(src_bitmap, +					sit_bitmap_size, GFP_KERNEL);  	if (!sit_i->sit_bitmap_mir)  		return -ENOMEM; + +	sit_i->invalid_segmap = f2fs_kvzalloc(sbi, +					main_bitmap_size, GFP_KERNEL); +	if (!sit_i->invalid_segmap) +		return -ENOMEM;  #endif  	/* init SIT information */ @@ -4023,7 +4030,7 @@ static int build_sit_info(struct f2fs_sb_info *sbi)  	sit_i->sit_base_addr = le32_to_cpu(raw_super->sit_blkaddr);  	sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg;  	sit_i->written_valid_blocks = 0; -	sit_i->bitmap_size = bitmap_size; +	sit_i->bitmap_size = sit_bitmap_size;  	sit_i->dirty_sentries = 0;  	sit_i->sents_per_block = SIT_ENTRY_PER_BLOCK;  	sit_i->elapsed_time = le64_to_cpu(sbi->ckpt->elapsed_time); @@ -4161,7 +4168,6 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)  		if (start >= MAIN_SEGS(sbi)) {  			f2fs_err(sbi, "Wrong journal entry on segno %u",  				 start); -			set_sbi_flag(sbi, SBI_NEED_FSCK);  			err = -EFSCORRUPTED;  			break;  		} @@ -4201,7 +4207,6 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)  	if (!err && total_node_blocks != valid_node_count(sbi)) {  		f2fs_err(sbi, "SIT is corrupted node# %u vs %u",  			 total_node_blocks, valid_node_count(sbi)); -		set_sbi_flag(sbi, SBI_NEED_FSCK);  		err = -EFSCORRUPTED;  	} @@ -4492,21 +4497,12 @@ static void destroy_free_segmap(struct f2fs_sb_info *sbi)  static void destroy_sit_info(struct f2fs_sb_info *sbi)  {  	struct sit_info *sit_i = SIT_I(sbi); -	unsigned int start;  	if (!sit_i)  		return; -	if (sit_i->sentries) { -		for (start = 0; start < MAIN_SEGS(sbi); start++) { -			kvfree(sit_i->sentries[start].cur_valid_map); -#ifdef CONFIG_F2FS_CHECK_FS -			kvfree(sit_i->sentries[start].cur_valid_map_mir); -#endif -			kvfree(sit_i->sentries[start].ckpt_valid_map); -			kvfree(sit_i->sentries[start].discard_map); -		} -	} +	if (sit_i->sentries) +		kvfree(sit_i->bitmap);  	kvfree(sit_i->tmp_map);  	kvfree(sit_i->sentries); @@ -4517,6 +4513,7 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi)  	kvfree(sit_i->sit_bitmap);  #ifdef CONFIG_F2FS_CHECK_FS  	kvfree(sit_i->sit_bitmap_mir); +	kvfree(sit_i->invalid_segmap);  #endif  	kvfree(sit_i);  }  |