diff options
Diffstat (limited to 'fs/f2fs/segment.c')
| -rw-r--r-- | fs/f2fs/segment.c | 129 | 
1 files changed, 91 insertions, 38 deletions
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 196f31503511..a65d357f89a9 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -174,7 +174,7 @@ bool f2fs_need_SSR(struct f2fs_sb_info *sbi)  	if (f2fs_lfs_mode(sbi))  		return false; -	if (sbi->gc_mode == GC_URGENT) +	if (sbi->gc_mode == GC_URGENT_HIGH)  		return true;  	if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))  		return true; @@ -796,6 +796,18 @@ static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,  		}  		if (!test_and_set_bit(segno, dirty_i->dirty_segmap[t]))  			dirty_i->nr_dirty[t]++; + +		if (__is_large_section(sbi)) { +			unsigned int secno = GET_SEC_FROM_SEG(sbi, segno); +			unsigned short valid_blocks = +				get_valid_blocks(sbi, segno, true); + +			f2fs_bug_on(sbi, unlikely(!valid_blocks || +					valid_blocks == BLKS_PER_SEC(sbi))); + +			if (!IS_CURSEC(sbi, secno)) +				set_bit(secno, dirty_i->dirty_secmap); +		}  	}  } @@ -803,6 +815,7 @@ static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,  		enum dirty_type dirty_type)  {  	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); +	unsigned short valid_blocks;  	if (test_and_clear_bit(segno, dirty_i->dirty_segmap[dirty_type]))  		dirty_i->nr_dirty[dirty_type]--; @@ -814,13 +827,26 @@ 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) { +		valid_blocks = get_valid_blocks(sbi, segno, true); +		if (valid_blocks == 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  		} +		if (__is_large_section(sbi)) { +			unsigned int secno = GET_SEC_FROM_SEG(sbi, segno); + +			if (!valid_blocks || +					valid_blocks == BLKS_PER_SEC(sbi)) { +				clear_bit(secno, dirty_i->dirty_secmap); +				return; +			} + +			if (!IS_CURSEC(sbi, secno)) +				set_bit(secno, dirty_i->dirty_secmap); +		}  	}  } @@ -1733,7 +1759,7 @@ static int issue_discard_thread(void *data)  			continue;  		} -		if (sbi->gc_mode == GC_URGENT) +		if (sbi->gc_mode == GC_URGENT_HIGH)  			__init_discard_policy(sbi, &dpolicy, DPOLICY_FORCE, 1);  		sb_start_intwrite(sbi->sb); @@ -2140,7 +2166,7 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)  	new_vblocks = se->valid_blocks + del;  	offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr); -	f2fs_bug_on(sbi, (new_vblocks >> (sizeof(unsigned short) << 3) || +	f2fs_bug_on(sbi, (new_vblocks < 0 ||  				(new_vblocks > sbi->blocks_per_seg)));  	se->valid_blocks = new_vblocks; @@ -2605,7 +2631,7 @@ static int get_ssr_segment(struct f2fs_sb_info *sbi, int type)  	bool reversed = false;  	/* f2fs_need_SSR() already forces to do this */ -	if (v_ops->get_victim(sbi, &segno, BG_GC, type, SSR)) { +	if (!v_ops->get_victim(sbi, &segno, BG_GC, type, SSR)) {  		curseg->next_segno = segno;  		return 1;  	} @@ -2632,7 +2658,7 @@ static int get_ssr_segment(struct f2fs_sb_info *sbi, int type)  	for (; cnt-- > 0; reversed ? i-- : i++) {  		if (i == type)  			continue; -		if (v_ops->get_victim(sbi, &segno, BG_GC, i, SSR)) { +		if (!v_ops->get_victim(sbi, &segno, BG_GC, i, SSR)) {  			curseg->next_segno = segno;  			return 1;  		} @@ -2674,7 +2700,7 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi,  	stat_inc_seg_type(sbi, curseg);  } -void allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type, +void f2fs_allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type,  					unsigned int start, unsigned int end)  {  	struct curseg_info *curseg = CURSEG_I(sbi, type); @@ -2707,28 +2733,35 @@ unlock:  	up_read(&SM_I(sbi)->curseg_lock);  } -void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi, int type) +static void __allocate_new_segment(struct f2fs_sb_info *sbi, int type)  { -	struct curseg_info *curseg; +	struct curseg_info *curseg = CURSEG_I(sbi, type);  	unsigned int old_segno; -	int i; -	down_write(&SIT_I(sbi)->sentry_lock); +	if (!curseg->next_blkoff && +		!get_valid_blocks(sbi, curseg->segno, false) && +		!get_ckpt_valid_blocks(sbi, curseg->segno)) +		return; -	for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { -		if (type != NO_CHECK_TYPE && i != type) -			continue; +	old_segno = curseg->segno; +	SIT_I(sbi)->s_ops->allocate_segment(sbi, type, true); +	locate_dirty_segment(sbi, old_segno); +} -		curseg = CURSEG_I(sbi, i); -		if (type == NO_CHECK_TYPE || curseg->next_blkoff || -				get_valid_blocks(sbi, curseg->segno, false) || -				get_ckpt_valid_blocks(sbi, curseg->segno)) { -			old_segno = curseg->segno; -			SIT_I(sbi)->s_ops->allocate_segment(sbi, i, true); -			locate_dirty_segment(sbi, old_segno); -		} -	} +void f2fs_allocate_new_segment(struct f2fs_sb_info *sbi, int type) +{ +	down_write(&SIT_I(sbi)->sentry_lock); +	__allocate_new_segment(sbi, type); +	up_write(&SIT_I(sbi)->sentry_lock); +} +void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi) +{ +	int i; + +	down_write(&SIT_I(sbi)->sentry_lock); +	for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) +		__allocate_new_segment(sbi, i);  	up_write(&SIT_I(sbi)->sentry_lock);  } @@ -3089,7 +3122,7 @@ static int __get_segment_type(struct f2fs_io_info *fio)  void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,  		block_t old_blkaddr, block_t *new_blkaddr,  		struct f2fs_summary *sum, int type, -		struct f2fs_io_info *fio, bool add_list) +		struct f2fs_io_info *fio)  {  	struct sit_info *sit_i = SIT_I(sbi);  	struct curseg_info *curseg = CURSEG_I(sbi, type); @@ -3107,14 +3140,6 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,  		type = CURSEG_COLD_DATA;  	} -	/* -	 * We need to wait for node_write to avoid block allocation during -	 * checkpoint. This can only happen to quota writes which can cause -	 * the below discard race condition. -	 */ -	if (IS_DATASEG(type)) -		down_write(&sbi->node_write); -  	down_read(&SM_I(sbi)->curseg_lock);  	mutex_lock(&curseg->curseg_mutex); @@ -3165,7 +3190,7 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,  	if (F2FS_IO_ALIGNED(sbi))  		fio->retry = false; -	if (add_list) { +	if (fio) {  		struct f2fs_bio_info *io;  		INIT_LIST_HEAD(&fio->list); @@ -3180,9 +3205,6 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,  	up_read(&SM_I(sbi)->curseg_lock); -	if (IS_DATASEG(type)) -		up_write(&sbi->node_write); -  	if (put_pin_sem)  		up_read(&sbi->pin_sem);  } @@ -3217,7 +3239,7 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)  		down_read(&fio->sbi->io_order_lock);  reallocate:  	f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr, -			&fio->new_blkaddr, sum, type, fio, true); +			&fio->new_blkaddr, sum, type, fio);  	if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO)  		invalidate_mapping_pages(META_MAPPING(fio->sbi),  					fio->old_blkaddr, fio->old_blkaddr); @@ -4293,8 +4315,9 @@ static void init_dirty_segmap(struct f2fs_sb_info *sbi)  {  	struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);  	struct free_segmap_info *free_i = FREE_I(sbi); -	unsigned int segno = 0, offset = 0; +	unsigned int segno = 0, offset = 0, secno;  	unsigned short valid_blocks; +	unsigned short blks_per_sec = BLKS_PER_SEC(sbi);  	while (1) {  		/* find dirty segment based on free segmap */ @@ -4313,6 +4336,22 @@ static void init_dirty_segmap(struct f2fs_sb_info *sbi)  		__locate_dirty_segment(sbi, segno, DIRTY);  		mutex_unlock(&dirty_i->seglist_lock);  	} + +	if (!__is_large_section(sbi)) +		return; + +	mutex_lock(&dirty_i->seglist_lock); +	for (segno = 0; segno < MAIN_SECS(sbi); segno += blks_per_sec) { +		valid_blocks = get_valid_blocks(sbi, segno, true); +		secno = GET_SEC_FROM_SEG(sbi, segno); + +		if (!valid_blocks || valid_blocks == blks_per_sec) +			continue; +		if (IS_CURSEC(sbi, secno)) +			continue; +		set_bit(secno, dirty_i->dirty_secmap); +	} +	mutex_unlock(&dirty_i->seglist_lock);  }  static int init_victim_secmap(struct f2fs_sb_info *sbi) @@ -4349,6 +4388,14 @@ static int build_dirty_segmap(struct f2fs_sb_info *sbi)  			return -ENOMEM;  	} +	if (__is_large_section(sbi)) { +		bitmap_size = f2fs_bitmap_size(MAIN_SECS(sbi)); +		dirty_i->dirty_secmap = f2fs_kvzalloc(sbi, +						bitmap_size, GFP_KERNEL); +		if (!dirty_i->dirty_secmap) +			return -ENOMEM; +	} +  	init_dirty_segmap(sbi);  	return init_victim_secmap(sbi);  } @@ -4775,6 +4822,12 @@ static void destroy_dirty_segmap(struct f2fs_sb_info *sbi)  	for (i = 0; i < NR_DIRTY_TYPE; i++)  		discard_dirty_segmap(sbi, i); +	if (__is_large_section(sbi)) { +		mutex_lock(&dirty_i->seglist_lock); +		kvfree(dirty_i->dirty_secmap); +		mutex_unlock(&dirty_i->seglist_lock); +	} +  	destroy_victim_secmap(sbi);  	SM_I(sbi)->dirty_info = NULL;  	kvfree(dirty_i);  |