diff options
Diffstat (limited to 'fs/f2fs/segment.c')
| -rw-r--r-- | fs/f2fs/segment.c | 225 | 
1 files changed, 101 insertions, 124 deletions
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index ae3c4e5474ef..227e25836173 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -192,18 +192,18 @@ void f2fs_abort_atomic_write(struct inode *inode, bool clean)  	if (!f2fs_is_atomic_file(inode))  		return; -	clear_inode_flag(fi->cow_inode, FI_COW_FILE); -	iput(fi->cow_inode); -	fi->cow_inode = NULL;  	release_atomic_write_cnt(inode);  	clear_inode_flag(inode, FI_ATOMIC_COMMITTED);  	clear_inode_flag(inode, FI_ATOMIC_REPLACE);  	clear_inode_flag(inode, FI_ATOMIC_FILE);  	stat_dec_atomic_inode(inode); +	F2FS_I(inode)->atomic_write_task = NULL; +  	if (clean) {  		truncate_inode_pages_final(inode->i_mapping);  		f2fs_i_size_write(inode, fi->original_i_size); +		fi->original_i_size = 0;  	}  } @@ -255,6 +255,9 @@ retry:  	}  	f2fs_put_dnode(&dn); + +	trace_f2fs_replace_atomic_write_block(inode, F2FS_I(inode)->cow_inode, +					index, *old_addr, new_addr, recover);  	return 0;  } @@ -262,19 +265,24 @@ static void __complete_revoke_list(struct inode *inode, struct list_head *head,  					bool revoke)  {  	struct revoke_entry *cur, *tmp; +	pgoff_t start_index = 0;  	bool truncate = is_inode_flag_set(inode, FI_ATOMIC_REPLACE);  	list_for_each_entry_safe(cur, tmp, head, list) { -		if (revoke) +		if (revoke) {  			__replace_atomic_write_block(inode, cur->index,  						cur->old_addr, NULL, true); +		} else if (truncate) { +			f2fs_truncate_hole(inode, start_index, cur->index); +			start_index = cur->index + 1; +		}  		list_del(&cur->list);  		kmem_cache_free(revoke_entry_slab, cur);  	}  	if (!revoke && truncate) -		f2fs_do_truncate_blocks(inode, 0, false); +		f2fs_do_truncate_blocks(inode, start_index * PAGE_SIZE, false);  }  static int __f2fs_commit_atomic_write(struct inode *inode) @@ -384,10 +392,8 @@ int f2fs_commit_atomic_write(struct inode *inode)   */  void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)  { -	if (time_to_inject(sbi, FAULT_CHECKPOINT)) { -		f2fs_show_injection_info(sbi, FAULT_CHECKPOINT); +	if (time_to_inject(sbi, FAULT_CHECKPOINT))  		f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_FAULT_INJECT); -	}  	/* balance_fs_bg is able to be pending */  	if (need && excess_cached_nats(sbi)) @@ -508,6 +514,8 @@ static int __submit_flush_wait(struct f2fs_sb_info *sbi,  	trace_f2fs_issue_flush(bdev, test_opt(sbi, NOBARRIER),  				test_opt(sbi, FLUSH_MERGE), ret); +	if (!ret) +		f2fs_update_iostat(sbi, NULL, FS_FLUSH_IO, 0);  	return ret;  } @@ -1059,7 +1067,7 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi,  	dpolicy->granularity = granularity;  	dpolicy->max_requests = dcc->max_discard_request; -	dpolicy->io_aware_gran = MAX_PLIST_NUM; +	dpolicy->io_aware_gran = dcc->discard_io_aware_gran;  	dpolicy->timeout = false;  	if (discard_type == DPOLICY_BG) { @@ -1095,9 +1103,8 @@ static void __update_discard_tree_range(struct f2fs_sb_info *sbi,  				block_t start, block_t len);  /* this function is copied from blkdev_issue_discard from block/blk-lib.c */  static int __submit_discard_cmd(struct f2fs_sb_info *sbi, -						struct discard_policy *dpolicy, -						struct discard_cmd *dc, -						unsigned int *issued) +				struct discard_policy *dpolicy, +				struct discard_cmd *dc, int *issued)  {  	struct block_device *bdev = dc->bdev;  	unsigned int max_discard_blocks = @@ -1141,7 +1148,6 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi,  		dc->len += len;  		if (time_to_inject(sbi, FAULT_DISCARD)) { -			f2fs_show_injection_info(sbi, FAULT_DISCARD);  			err = -EIO;  		} else {  			err = __blkdev_issue_discard(bdev, @@ -1186,7 +1192,7 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi,  		atomic_inc(&dcc->issued_discard); -		f2fs_update_iostat(sbi, NULL, FS_DISCARD, len * F2FS_BLKSIZE); +		f2fs_update_iostat(sbi, NULL, FS_DISCARD_IO, len * F2FS_BLKSIZE);  		lstart += len;  		start += len; @@ -1378,8 +1384,8 @@ static void __queue_discard_cmd(struct f2fs_sb_info *sbi,  	mutex_unlock(&SM_I(sbi)->dcc_info->cmd_lock);  } -static unsigned int __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi, -					struct discard_policy *dpolicy) +static void __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi, +		struct discard_policy *dpolicy, int *issued)  {  	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;  	struct discard_cmd *prev_dc = NULL, *next_dc = NULL; @@ -1387,7 +1393,6 @@ static unsigned int __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi,  	struct discard_cmd *dc;  	struct blk_plug plug;  	unsigned int pos = dcc->next_pos; -	unsigned int issued = 0;  	bool io_interrupted = false;  	mutex_lock(&dcc->cmd_lock); @@ -1414,9 +1419,9 @@ static unsigned int __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi,  		}  		dcc->next_pos = dc->lstart + dc->len; -		err = __submit_discard_cmd(sbi, dpolicy, dc, &issued); +		err = __submit_discard_cmd(sbi, dpolicy, dc, issued); -		if (issued >= dpolicy->max_requests) +		if (*issued >= dpolicy->max_requests)  			break;  next:  		node = rb_next(&dc->rb_node); @@ -1432,10 +1437,8 @@ next:  	mutex_unlock(&dcc->cmd_lock); -	if (!issued && io_interrupted) -		issued = -1; - -	return issued; +	if (!(*issued) && io_interrupted) +		*issued = -1;  }  static unsigned int __wait_all_discard_cmd(struct f2fs_sb_info *sbi,  					struct discard_policy *dpolicy); @@ -1463,8 +1466,10 @@ retry:  		if (i + 1 < dpolicy->granularity)  			break; -		if (i + 1 < dcc->max_ordered_discard && dpolicy->ordered) -			return __issue_discard_cmd_orderly(sbi, dpolicy); +		if (i + 1 < dcc->max_ordered_discard && dpolicy->ordered) { +			__issue_discard_cmd_orderly(sbi, dpolicy, &issued); +			return issued; +		}  		pend_list = &dcc->pend_list[i]; @@ -1609,9 +1614,9 @@ static unsigned int __wait_all_discard_cmd(struct f2fs_sb_info *sbi,  		return __wait_discard_cmd_range(sbi, dpolicy, 0, UINT_MAX);  	/* wait all */ -	__init_discard_policy(sbi, &dp, DPOLICY_FSTRIM, 1); +	__init_discard_policy(sbi, &dp, DPOLICY_FSTRIM, MIN_DISCARD_GRANULARITY);  	discard_blks = __wait_discard_cmd_range(sbi, &dp, 0, UINT_MAX); -	__init_discard_policy(sbi, &dp, DPOLICY_UMOUNT, 1); +	__init_discard_policy(sbi, &dp, DPOLICY_UMOUNT, MIN_DISCARD_GRANULARITY);  	discard_blks += __wait_discard_cmd_range(sbi, &dp, 0, UINT_MAX);  	return discard_blks; @@ -1653,7 +1658,14 @@ void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi)  	}  } -/* This comes from f2fs_put_super */ +/** + * f2fs_issue_discard_timeout() - Issue all discard cmd within UMOUNT_DISCARD_TIMEOUT + * @sbi: the f2fs_sb_info data for discard cmd to issue + * + * When UMOUNT_DISCARD_TIMEOUT is exceeded, all remaining discard commands will be dropped + * + * Return true if issued all discard cmd or no discard cmd need issue, otherwise return false. + */  bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi)  {  	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; @@ -1661,7 +1673,7 @@ bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi)  	bool dropped;  	if (!atomic_read(&dcc->discard_cmd_cnt)) -		return false; +		return true;  	__init_discard_policy(sbi, &dpolicy, DPOLICY_UMOUNT,  					dcc->discard_granularity); @@ -1672,7 +1684,7 @@ bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi)  	__wait_all_discard_cmd(sbi, NULL);  	f2fs_bug_on(sbi, atomic_read(&dcc->discard_cmd_cnt)); -	return dropped; +	return !dropped;  }  static int issue_discard_thread(void *data) @@ -1694,13 +1706,14 @@ static int issue_discard_thread(void *data)  		if (sbi->gc_mode == GC_URGENT_HIGH ||  			!f2fs_available_free_memory(sbi, DISCARD_CACHE)) -			__init_discard_policy(sbi, &dpolicy, DPOLICY_FORCE, 1); +			__init_discard_policy(sbi, &dpolicy, DPOLICY_FORCE, +						MIN_DISCARD_GRANULARITY);  		else  			__init_discard_policy(sbi, &dpolicy, DPOLICY_BG,  						dcc->discard_granularity);  		if (dcc->discard_wake) -			dcc->discard_wake = 0; +			dcc->discard_wake = false;  		/* clean up pending candidates before going to sleep */  		if (atomic_read(&dcc->queued_discard)) @@ -2065,6 +2078,7 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi)  	if (!dcc)  		return -ENOMEM; +	dcc->discard_io_aware_gran = MAX_PLIST_NUM;  	dcc->discard_granularity = DEFAULT_DISCARD_GRANULARITY;  	dcc->max_ordered_discard = DEFAULT_MAX_ORDERED_DISCARD_GRANULARITY;  	if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SEGMENT) @@ -2327,17 +2341,13 @@ bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr)  	return is_cp;  } -/* - * This function should be resided under the curseg_mutex lock - */ -static void __add_sum_entry(struct f2fs_sb_info *sbi, int type, -					struct f2fs_summary *sum) +static unsigned short f2fs_curseg_valid_blocks(struct f2fs_sb_info *sbi, int type)  {  	struct curseg_info *curseg = CURSEG_I(sbi, type); -	void *addr = curseg->sum_blk; -	addr += curseg->next_blkoff * sizeof(struct f2fs_summary); -	memcpy(addr, sum, sizeof(struct f2fs_summary)); +	if (sbi->ckpt->alloc_type[type] == SSR) +		return sbi->blocks_per_seg; +	return curseg->next_blkoff;  }  /* @@ -2349,15 +2359,11 @@ int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra)  	int i, sum_in_page;  	for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { -		if (sbi->ckpt->alloc_type[i] == SSR) -			valid_sum_count += sbi->blocks_per_seg; -		else { -			if (for_ra) -				valid_sum_count += le16_to_cpu( -					F2FS_CKPT(sbi)->cur_data_blkoff[i]); -			else -				valid_sum_count += curseg_blkoff(sbi, i); -		} +		if (sbi->ckpt->alloc_type[i] != SSR && for_ra) +			valid_sum_count += +				le16_to_cpu(F2FS_CKPT(sbi)->cur_data_blkoff[i]); +		else +			valid_sum_count += f2fs_curseg_valid_blocks(sbi, i);  	}  	sum_in_page = (PAGE_SIZE - 2 * SUM_JOURNAL_SIZE - @@ -2628,30 +2634,10 @@ static int __next_free_blkoff(struct f2fs_sb_info *sbi,  	return __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, start);  } -/* - * If a segment is written by LFS manner, next block offset is just obtained - * by increasing the current block offset. However, if a segment is written by - * SSR manner, next block offset obtained by calling __next_free_blkoff - */ -static void __refresh_next_blkoff(struct f2fs_sb_info *sbi, -				struct curseg_info *seg) +static int f2fs_find_next_ssr_block(struct f2fs_sb_info *sbi, +		struct curseg_info *seg)  { -	if (seg->alloc_type == SSR) { -		seg->next_blkoff = -			__next_free_blkoff(sbi, seg->segno, -						seg->next_blkoff + 1); -	} else { -		seg->next_blkoff++; -		if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK) { -			/* To allocate block chunks in different sizes, use random number */ -			if (--seg->fragment_remained_chunk <= 0) { -				seg->fragment_remained_chunk = -				   get_random_u32_inclusive(1, sbi->max_fragment_chunk); -				seg->next_blkoff += -				   get_random_u32_inclusive(1, sbi->max_fragment_hole); -			} -		} -	} +	return __next_free_blkoff(sbi, seg->segno, seg->next_blkoff + 1);  }  bool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno) @@ -2909,33 +2895,23 @@ static void __allocate_new_segment(struct f2fs_sb_info *sbi, int type,  	struct curseg_info *curseg = CURSEG_I(sbi, type);  	unsigned int old_segno; -	if (!curseg->inited) -		goto alloc; - -	if (force || curseg->next_blkoff || -		get_valid_blocks(sbi, curseg->segno, new_sec)) -		goto alloc; - -	if (!get_ckpt_valid_blocks(sbi, curseg->segno, new_sec)) +	if (!force && curseg->inited && +	    !curseg->next_blkoff && +	    !get_valid_blocks(sbi, curseg->segno, new_sec) && +	    !get_ckpt_valid_blocks(sbi, curseg->segno, new_sec))  		return; -alloc: +  	old_segno = curseg->segno;  	new_curseg(sbi, type, true);  	stat_inc_seg_type(sbi, curseg);  	locate_dirty_segment(sbi, old_segno);  } -static void __allocate_new_section(struct f2fs_sb_info *sbi, -						int type, bool force) -{ -	__allocate_new_segment(sbi, type, true, force); -} -  void f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type, bool force)  {  	f2fs_down_read(&SM_I(sbi)->curseg_lock);  	down_write(&SIT_I(sbi)->sentry_lock); -	__allocate_new_section(sbi, type, force); +	__allocate_new_segment(sbi, type, true, force);  	up_write(&SIT_I(sbi)->sentry_lock);  	f2fs_up_read(&SM_I(sbi)->curseg_lock);  } @@ -3113,13 +3089,6 @@ out:  	return err;  } -static bool __has_curseg_space(struct f2fs_sb_info *sbi, -					struct curseg_info *curseg) -{ -	return curseg->next_blkoff < f2fs_usable_blks_in_seg(sbi, -							curseg->segno); -} -  int f2fs_rw_hint_to_seg_type(enum rw_hint hint)  {  	switch (hint) { @@ -3238,6 +3207,19 @@ static int __get_segment_type(struct f2fs_io_info *fio)  	return type;  } +static void f2fs_randomize_chunk(struct f2fs_sb_info *sbi, +		struct curseg_info *seg) +{ +	/* To allocate block chunks in different sizes, use random number */ +	if (--seg->fragment_remained_chunk > 0) +		return; + +	seg->fragment_remained_chunk = +		get_random_u32_inclusive(1, sbi->max_fragment_chunk); +	seg->next_blkoff += +		get_random_u32_inclusive(1, sbi->max_fragment_hole); +} +  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, @@ -3248,6 +3230,7 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,  	unsigned long long old_mtime;  	bool from_gc = (type == CURSEG_ALL_DATA_ATGC);  	struct seg_entry *se = NULL; +	bool segment_full = false;  	f2fs_down_read(&SM_I(sbi)->curseg_lock); @@ -3266,15 +3249,16 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,  	f2fs_wait_discard_bio(sbi, *new_blkaddr); -	/* -	 * __add_sum_entry should be resided under the curseg_mutex -	 * because, this function updates a summary entry in the -	 * current summary block. -	 */ -	__add_sum_entry(sbi, type, sum); - -	__refresh_next_blkoff(sbi, curseg); - +	curseg->sum_blk->entries[curseg->next_blkoff] = *sum; +	if (curseg->alloc_type == SSR) { +		curseg->next_blkoff = f2fs_find_next_ssr_block(sbi, curseg); +	} else { +		curseg->next_blkoff++; +		if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK) +			f2fs_randomize_chunk(sbi, curseg); +	} +	if (curseg->next_blkoff >= f2fs_usable_blks_in_seg(sbi, curseg->segno)) +		segment_full = true;  	stat_inc_block_count(sbi, curseg);  	if (from_gc) { @@ -3293,10 +3277,11 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,  	if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO)  		update_sit_entry(sbi, old_blkaddr, -1); -	if (!__has_curseg_space(sbi, curseg)) { -		/* -		 * Flush out current segment and replace it with new segment. -		 */ +	/* +	 * If the current segment is full, flush it out and replace it with a +	 * new segment. +	 */ +	if (segment_full) {  		if (from_gc) {  			get_atssr_segment(sbi, type, se->type,  						AT_SSR, se->mtime); @@ -3331,10 +3316,10 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,  		struct f2fs_bio_info *io;  		if (F2FS_IO_ALIGNED(sbi)) -			fio->retry = false; +			fio->retry = 0;  		INIT_LIST_HEAD(&fio->list); -		fio->in_list = true; +		fio->in_list = 1;  		io = sbi->write_io[fio->type] + fio->temp;  		spin_lock(&io->io_lock);  		list_add_tail(&fio->list, &io->io_list); @@ -3415,14 +3400,13 @@ void f2fs_do_write_meta_page(struct f2fs_sb_info *sbi, struct page *page,  		.new_blkaddr = page->index,  		.page = page,  		.encrypted_page = NULL, -		.in_list = false, +		.in_list = 0,  	};  	if (unlikely(page->index >= MAIN_BLKADDR(sbi)))  		fio.op_flags &= ~REQ_META;  	set_page_writeback(page); -	ClearPageError(page);  	f2fs_submit_page_write(&fio);  	stat_inc_meta_count(sbi, page->index); @@ -3487,7 +3471,7 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio)  	stat_inc_inplace_blocks(fio->sbi); -	if (fio->bio && !(SM_I(sbi)->ipu_policy & (1 << F2FS_IPU_NOCACHE))) +	if (fio->bio && !IS_F2FS_IPU_NOCACHE(sbi))  		err = f2fs_merge_page_bio(fio);  	else  		err = f2fs_submit_page_bio(fio); @@ -3576,7 +3560,7 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,  	}  	curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr); -	__add_sum_entry(sbi, type, sum); +	curseg->sum_blk->entries[curseg->next_blkoff] = *sum;  	if (!recover_curseg || recover_newaddr) {  		if (!from_gc) @@ -3634,7 +3618,7 @@ void f2fs_wait_on_page_writeback(struct page *page,  		/* submit cached LFS IO */  		f2fs_submit_merged_write_cond(sbi, NULL, page, 0, type); -		/* sbumit cached IPU IO */ +		/* submit cached IPU IO */  		f2fs_submit_merged_ipu_write(sbi, NULL, page);  		if (ordered) {  			wait_on_page_writeback(page); @@ -3885,15 +3869,8 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr)  	/* Step 3: write summary entries */  	for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { -		unsigned short blkoff; -  		seg_i = CURSEG_I(sbi, i); -		if (sbi->ckpt->alloc_type[i] == SSR) -			blkoff = sbi->blocks_per_seg; -		else -			blkoff = curseg_blkoff(sbi, i); - -		for (j = 0; j < blkoff; j++) { +		for (j = 0; j < f2fs_curseg_valid_blocks(sbi, i); j++) {  			if (!page) {  				page = f2fs_grab_meta_page(sbi, blkaddr++);  				kaddr = (unsigned char *)page_address(page); @@ -5126,7 +5103,7 @@ int f2fs_build_segment_manager(struct f2fs_sb_info *sbi)  		sm_info->rec_prefree_segments = DEF_MAX_RECLAIM_PREFREE_SEGMENTS;  	if (!f2fs_lfs_mode(sbi)) -		sm_info->ipu_policy = 1 << F2FS_IPU_FSYNC; +		sm_info->ipu_policy = BIT(F2FS_IPU_FSYNC);  	sm_info->min_ipu_util = DEF_MIN_IPU_UTIL;  	sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS;  	sm_info->min_seq_blocks = sbi->blocks_per_seg;  |