diff options
Diffstat (limited to 'fs/f2fs/segment.c')
| -rw-r--r-- | fs/f2fs/segment.c | 132 | 
1 files changed, 97 insertions, 35 deletions
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 4fd76e867e0a..a0ce3d080f80 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -771,8 +771,10 @@ static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,  			block_t valid_blocks =  				get_valid_blocks(sbi, segno, true); -			f2fs_bug_on(sbi, unlikely(!valid_blocks || -					valid_blocks == CAP_BLKS_PER_SEC(sbi))); +			f2fs_bug_on(sbi, +				(!is_sbi_flag_set(sbi, SBI_CP_DISABLED) && +				!valid_blocks) || +				valid_blocks == CAP_BLKS_PER_SEC(sbi));  			if (!IS_CURSEC(sbi, secno))  				set_bit(secno, dirty_i->dirty_secmap); @@ -1109,9 +1111,8 @@ static void __remove_discard_cmd(struct f2fs_sb_info *sbi,  		dc->error = 0;  	if (dc->error) -		printk_ratelimited( -			"%sF2FS-fs (%s): Issue discard(%u, %u, %u) failed, ret: %d", -			KERN_INFO, sbi->sb->s_id, +		f2fs_info_ratelimited(sbi, +			"Issue discard(%u, %u, %u) failed, ret: %d",  			dc->di.lstart, dc->di.start, dc->di.len, dc->error);  	__detach_discard_cmd(dcc, dc);  } @@ -2645,7 +2646,7 @@ static void write_current_sum_page(struct f2fs_sb_info *sbi,  }  static int is_next_segment_free(struct f2fs_sb_info *sbi, -				struct curseg_info *curseg, int type) +				struct curseg_info *curseg)  {  	unsigned int segno = curseg->segno + 1;  	struct free_segmap_info *free_i = FREE_I(sbi); @@ -3073,8 +3074,7 @@ static bool need_new_seg(struct f2fs_sb_info *sbi, int type)  	if (!is_set_ckpt_flags(sbi, CP_CRC_RECOVERY_FLAG) &&  	    curseg->seg_type == CURSEG_WARM_NODE)  		return true; -	if (curseg->alloc_type == LFS && -	    is_next_segment_free(sbi, curseg, type) && +	if (curseg->alloc_type == LFS && is_next_segment_free(sbi, curseg) &&  	    likely(!is_sbi_flag_set(sbi, SBI_CP_DISABLED)))  		return true;  	if (!f2fs_need_SSR(sbi) || !get_ssr_segment(sbi, type, SSR, 0)) @@ -3352,8 +3352,14 @@ out:  	return err;  } -int f2fs_rw_hint_to_seg_type(enum rw_hint hint) +int f2fs_rw_hint_to_seg_type(struct f2fs_sb_info *sbi, enum rw_hint hint)  { +	if (F2FS_OPTION(sbi).active_logs == 2) +		return CURSEG_HOT_DATA; +	else if (F2FS_OPTION(sbi).active_logs == 4) +		return CURSEG_COLD_DATA; + +	/* active_log == 6 */  	switch (hint) {  	case WRITE_LIFE_SHORT:  		return CURSEG_HOT_DATA; @@ -3364,6 +3370,65 @@ int f2fs_rw_hint_to_seg_type(enum rw_hint hint)  	}  } +/* + * This returns write hints for each segment type. This hints will be + * passed down to block layer as below by default. + * + * User                  F2FS                     Block + * ----                  ----                     ----- + *                       META                     WRITE_LIFE_NONE|REQ_META + *                       HOT_NODE                 WRITE_LIFE_NONE + *                       WARM_NODE                WRITE_LIFE_MEDIUM + *                       COLD_NODE                WRITE_LIFE_LONG + * ioctl(COLD)           COLD_DATA                WRITE_LIFE_EXTREME + * extension list        "                        " + * + * -- buffered io + *                       COLD_DATA                WRITE_LIFE_EXTREME + *                       HOT_DATA                 WRITE_LIFE_SHORT + *                       WARM_DATA                WRITE_LIFE_NOT_SET + * + * -- direct io + * WRITE_LIFE_EXTREME    COLD_DATA                WRITE_LIFE_EXTREME + * WRITE_LIFE_SHORT      HOT_DATA                 WRITE_LIFE_SHORT + * WRITE_LIFE_NOT_SET    WARM_DATA                WRITE_LIFE_NOT_SET + * WRITE_LIFE_NONE       "                        WRITE_LIFE_NONE + * WRITE_LIFE_MEDIUM     "                        WRITE_LIFE_MEDIUM + * WRITE_LIFE_LONG       "                        WRITE_LIFE_LONG + */ +enum rw_hint f2fs_io_type_to_rw_hint(struct f2fs_sb_info *sbi, +				enum page_type type, enum temp_type temp) +{ +	switch (type) { +	case DATA: +		switch (temp) { +		case WARM: +			return WRITE_LIFE_NOT_SET; +		case HOT: +			return WRITE_LIFE_SHORT; +		case COLD: +			return WRITE_LIFE_EXTREME; +		default: +			return WRITE_LIFE_NONE; +		} +	case NODE: +		switch (temp) { +		case WARM: +			return WRITE_LIFE_MEDIUM; +		case HOT: +			return WRITE_LIFE_NONE; +		case COLD: +			return WRITE_LIFE_LONG; +		default: +			return WRITE_LIFE_NONE; +		} +	case META: +		return WRITE_LIFE_NONE; +	default: +		return WRITE_LIFE_NONE; +	} +} +  static int __get_segment_type_2(struct f2fs_io_info *fio)  {  	if (fio->type == DATA) @@ -3434,7 +3499,8 @@ static int __get_segment_type_6(struct f2fs_io_info *fio)  				is_inode_flag_set(inode, FI_HOT_DATA) ||  				f2fs_is_cow_file(inode))  			return CURSEG_HOT_DATA; -		return f2fs_rw_hint_to_seg_type(inode->i_write_hint); +		return f2fs_rw_hint_to_seg_type(F2FS_I_SB(inode), +						inode->i_write_hint);  	} else {  		if (IS_DNODE(fio->page))  			return is_cold_node(fio->page) ? CURSEG_WARM_NODE : @@ -3443,6 +3509,15 @@ static int __get_segment_type_6(struct f2fs_io_info *fio)  	}  } +int f2fs_get_segment_temp(int seg_type) +{ +	if (IS_HOT(seg_type)) +		return HOT; +	else if (IS_WARM(seg_type)) +		return WARM; +	return COLD; +} +  static int __get_segment_type(struct f2fs_io_info *fio)  {  	int type = 0; @@ -3461,12 +3536,8 @@ static int __get_segment_type(struct f2fs_io_info *fio)  		f2fs_bug_on(fio->sbi, true);  	} -	if (IS_HOT(type)) -		fio->temp = HOT; -	else if (IS_WARM(type)) -		fio->temp = WARM; -	else -		fio->temp = COLD; +	fio->temp = f2fs_get_segment_temp(type); +  	return type;  } @@ -3559,6 +3630,8 @@ int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,  	if (segment_full) {  		if (type == CURSEG_COLD_DATA_PINNED &&  		    !((curseg->segno + 1) % sbi->segs_per_sec)) { +			write_sum_page(sbi, curseg->sum_blk, +					GET_SUM_BLOCK(sbi, curseg->segno));  			reset_curseg_fields(curseg);  			goto skip_new_segment;  		} @@ -3612,13 +3685,13 @@ skip_new_segment:  	mutex_unlock(&curseg->curseg_mutex);  	f2fs_up_read(&SM_I(sbi)->curseg_lock);  	return 0; +  out_err:  	*new_blkaddr = NULL_ADDR;  	up_write(&sit_i->sentry_lock);  	mutex_unlock(&curseg->curseg_mutex);  	f2fs_up_read(&SM_I(sbi)->curseg_lock);  	return ret; -  }  void f2fs_update_device_state(struct f2fs_sb_info *sbi, nid_t ino, @@ -3660,8 +3733,7 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)  			&fio->new_blkaddr, sum, type, fio)) {  		if (fscrypt_inode_uses_fs_layer_crypto(fio->page->mapping->host))  			fscrypt_finalize_bounce_page(&fio->encrypted_page); -		if (PageWriteback(fio->page)) -			end_page_writeback(fio->page); +		end_page_writeback(fio->page);  		if (f2fs_in_warm_node_list(fio->sbi, fio->page))  			f2fs_del_fsync_node_entry(fio->sbi, fio->page);  		goto out; @@ -3904,7 +3976,7 @@ void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,  void f2fs_wait_on_page_writeback(struct page *page,  				enum page_type type, bool ordered, bool locked)  { -	if (PageWriteback(page)) { +	if (folio_test_writeback(page_folio(page))) {  		struct f2fs_sb_info *sbi = F2FS_P_SB(page);  		/* submit cached LFS IO */ @@ -3913,7 +3985,8 @@ void f2fs_wait_on_page_writeback(struct page *page,  		f2fs_submit_merged_ipu_write(sbi, NULL, page);  		if (ordered) {  			wait_on_page_writeback(page); -			f2fs_bug_on(sbi, locked && PageWriteback(page)); +			f2fs_bug_on(sbi, locked && +				folio_test_writeback(page_folio(page)));  		} else {  			wait_for_stable_page(page);  		} @@ -4959,17 +5032,6 @@ out:  }  #ifdef CONFIG_BLK_DEV_ZONED -static const char *f2fs_zone_status[BLK_ZONE_COND_OFFLINE + 1] = { -	[BLK_ZONE_COND_NOT_WP]		= "NOT_WP", -	[BLK_ZONE_COND_EMPTY]		= "EMPTY", -	[BLK_ZONE_COND_IMP_OPEN]	= "IMPLICIT_OPEN", -	[BLK_ZONE_COND_EXP_OPEN]	= "EXPLICIT_OPEN", -	[BLK_ZONE_COND_CLOSED]		= "CLOSED", -	[BLK_ZONE_COND_READONLY]	= "READONLY", -	[BLK_ZONE_COND_FULL]		= "FULL", -	[BLK_ZONE_COND_OFFLINE]		= "OFFLINE", -}; -  static int check_zone_write_pointer(struct f2fs_sb_info *sbi,  				    struct f2fs_dev_info *fdev,  				    struct blk_zone *zone) @@ -5000,7 +5062,7 @@ static int check_zone_write_pointer(struct f2fs_sb_info *sbi,  	if (IS_CURSEC(sbi, GET_SEC_FROM_SEG(sbi, zone_segno))) {  		f2fs_notice(sbi, "Open zones: valid block[0x%x,0x%x] cond[%s]",  				zone_segno, valid_block_cnt, -				f2fs_zone_status[zone->cond]); +				blk_zone_cond_str(zone->cond));  		return 0;  	} @@ -5011,7 +5073,7 @@ static int check_zone_write_pointer(struct f2fs_sb_info *sbi,  	if (!valid_block_cnt) {  		f2fs_notice(sbi, "Zone without valid block has non-zero write "  			    "pointer. Reset the write pointer: cond[%s]", -			    f2fs_zone_status[zone->cond]); +			    blk_zone_cond_str(zone->cond));  		ret = __f2fs_issue_discard_zone(sbi, fdev->bdev, zone_block,  					zone->len >> log_sectors_per_block);  		if (ret) @@ -5029,7 +5091,7 @@ static int check_zone_write_pointer(struct f2fs_sb_info *sbi,  	 */  	f2fs_notice(sbi, "Valid blocks are not aligned with write "  		    "pointer: valid block[0x%x,0x%x] cond[%s]", -		    zone_segno, valid_block_cnt, f2fs_zone_status[zone->cond]); +		    zone_segno, valid_block_cnt, blk_zone_cond_str(zone->cond));  	nofs_flags = memalloc_nofs_save();  	ret = blkdev_zone_mgmt(fdev->bdev, REQ_OP_ZONE_FINISH,  |