diff options
Diffstat (limited to 'fs/f2fs/segment.c')
| -rw-r--r-- | fs/f2fs/segment.c | 399 | 
1 files changed, 308 insertions, 91 deletions
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 9efce174c51a..30779aaa9dba 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -250,7 +250,13 @@ retry:  				err = -EAGAIN;  				goto next;  			} -			f2fs_get_node_info(sbi, dn.nid, &ni); + +			err = f2fs_get_node_info(sbi, dn.nid, &ni); +			if (err) { +				f2fs_put_dnode(&dn); +				return err; +			} +  			if (cur->old_addr == NEW_ADDR) {  				f2fs_invalidate_blocks(sbi, dn.data_blkaddr);  				f2fs_update_data_blkaddr(&dn, NEW_ADDR); @@ -439,8 +445,10 @@ int f2fs_commit_inmem_pages(struct inode *inode)  	int err;  	f2fs_balance_fs(sbi, true); -	f2fs_lock_op(sbi); +	down_write(&fi->i_gc_rwsem[WRITE]); + +	f2fs_lock_op(sbi);  	set_inode_flag(inode, FI_ATOMIC_COMMIT);  	mutex_lock(&fi->inmem_lock); @@ -455,6 +463,8 @@ int f2fs_commit_inmem_pages(struct inode *inode)  	clear_inode_flag(inode, FI_ATOMIC_COMMIT);  	f2fs_unlock_op(sbi); +	up_write(&fi->i_gc_rwsem[WRITE]); +  	return err;  } @@ -464,12 +474,10 @@ int f2fs_commit_inmem_pages(struct inode *inode)   */  void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)  { -#ifdef CONFIG_F2FS_FAULT_INJECTION  	if (time_to_inject(sbi, FAULT_CHECKPOINT)) {  		f2fs_show_injection_info(FAULT_CHECKPOINT);  		f2fs_stop_checkpoint(sbi, false);  	} -#endif  	/* balance_fs_bg is able to be pending */  	if (need && excess_cached_nats(sbi)) @@ -503,7 +511,8 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)  	else  		f2fs_build_free_nids(sbi, false, false); -	if (!is_idle(sbi) && !excess_dirty_nats(sbi)) +	if (!is_idle(sbi) && +		(!excess_dirty_nats(sbi) && !excess_dirty_nodes(sbi)))  		return;  	/* checkpoint is the only way to shrink partial cached entries */ @@ -511,6 +520,7 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)  			!f2fs_available_free_memory(sbi, INO_ENTRIES) ||  			excess_prefree_segs(sbi) ||  			excess_dirty_nats(sbi) || +			excess_dirty_nodes(sbi) ||  			f2fs_time_over(sbi, CP_TIME)) {  		if (test_opt(sbi, DATA_FLUSH)) {  			struct blk_plug plug; @@ -831,9 +841,12 @@ static struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi,  	dc->len = len;  	dc->ref = 0;  	dc->state = D_PREP; +	dc->issuing = 0;  	dc->error = 0;  	init_completion(&dc->wait);  	list_add_tail(&dc->list, pend_list); +	spin_lock_init(&dc->lock); +	dc->bio_ref = 0;  	atomic_inc(&dcc->discard_cmd_cnt);  	dcc->undiscard_blks += len; @@ -860,7 +873,7 @@ static void __detach_discard_cmd(struct discard_cmd_control *dcc,  							struct discard_cmd *dc)  {  	if (dc->state == D_DONE) -		atomic_dec(&dcc->issing_discard); +		atomic_sub(dc->issuing, &dcc->issing_discard);  	list_del(&dc->list);  	rb_erase(&dc->rb_node, &dcc->root); @@ -875,9 +888,17 @@ static void __remove_discard_cmd(struct f2fs_sb_info *sbi,  							struct discard_cmd *dc)  {  	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; +	unsigned long flags;  	trace_f2fs_remove_discard(dc->bdev, dc->start, dc->len); +	spin_lock_irqsave(&dc->lock, flags); +	if (dc->bio_ref) { +		spin_unlock_irqrestore(&dc->lock, flags); +		return; +	} +	spin_unlock_irqrestore(&dc->lock, flags); +  	f2fs_bug_on(sbi, dc->ref);  	if (dc->error == -EOPNOTSUPP) @@ -893,10 +914,17 @@ static void __remove_discard_cmd(struct f2fs_sb_info *sbi,  static void f2fs_submit_discard_endio(struct bio *bio)  {  	struct discard_cmd *dc = (struct discard_cmd *)bio->bi_private; +	unsigned long flags;  	dc->error = blk_status_to_errno(bio->bi_status); -	dc->state = D_DONE; -	complete_all(&dc->wait); + +	spin_lock_irqsave(&dc->lock, flags); +	dc->bio_ref--; +	if (!dc->bio_ref && dc->state == D_SUBMIT) { +		dc->state = D_DONE; +		complete_all(&dc->wait); +	} +	spin_unlock_irqrestore(&dc->lock, flags);  	bio_put(bio);  } @@ -934,6 +962,7 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi,  	/* common policy */  	dpolicy->type = discard_type;  	dpolicy->sync = true; +	dpolicy->ordered = false;  	dpolicy->granularity = granularity;  	dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST; @@ -945,6 +974,7 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi,  		dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME;  		dpolicy->io_aware = true;  		dpolicy->sync = false; +		dpolicy->ordered = true;  		if (utilization(sbi) > DEF_DISCARD_URGENT_UTIL) {  			dpolicy->granularity = 1;  			dpolicy->max_interval = DEF_MIN_DISCARD_ISSUE_TIME; @@ -962,48 +992,115 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi,  	}  } - +static void __update_discard_tree_range(struct f2fs_sb_info *sbi, +				struct block_device *bdev, block_t lstart, +				block_t start, block_t len);  /* this function is copied from blkdev_issue_discard from block/blk-lib.c */ -static void __submit_discard_cmd(struct f2fs_sb_info *sbi, +static int __submit_discard_cmd(struct f2fs_sb_info *sbi,  						struct discard_policy *dpolicy, -						struct discard_cmd *dc) +						struct discard_cmd *dc, +						unsigned int *issued)  { +	struct block_device *bdev = dc->bdev; +	struct request_queue *q = bdev_get_queue(bdev); +	unsigned int max_discard_blocks = +			SECTOR_TO_BLOCK(q->limits.max_discard_sectors);  	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;  	struct list_head *wait_list = (dpolicy->type == DPOLICY_FSTRIM) ?  					&(dcc->fstrim_list) : &(dcc->wait_list); -	struct bio *bio = NULL;  	int flag = dpolicy->sync ? REQ_SYNC : 0; +	block_t lstart, start, len, total_len; +	int err = 0;  	if (dc->state != D_PREP) -		return; +		return 0;  	if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) -		return; +		return 0; -	trace_f2fs_issue_discard(dc->bdev, dc->start, dc->len); +	trace_f2fs_issue_discard(bdev, dc->start, dc->len); -	dc->error = __blkdev_issue_discard(dc->bdev, -				SECTOR_FROM_BLOCK(dc->start), -				SECTOR_FROM_BLOCK(dc->len), -				GFP_NOFS, 0, &bio); -	if (!dc->error) { -		/* should keep before submission to avoid D_DONE right away */ -		dc->state = D_SUBMIT; -		atomic_inc(&dcc->issued_discard); -		atomic_inc(&dcc->issing_discard); -		if (bio) { -			bio->bi_private = dc; -			bio->bi_end_io = f2fs_submit_discard_endio; -			bio->bi_opf |= flag; -			submit_bio(bio); -			list_move_tail(&dc->list, wait_list); -			__check_sit_bitmap(sbi, dc->start, dc->start + dc->len); - -			f2fs_update_iostat(sbi, FS_DISCARD, 1); +	lstart = dc->lstart; +	start = dc->start; +	len = dc->len; +	total_len = len; + +	dc->len = 0; + +	while (total_len && *issued < dpolicy->max_requests && !err) { +		struct bio *bio = NULL; +		unsigned long flags; +		bool last = true; + +		if (len > max_discard_blocks) { +			len = max_discard_blocks; +			last = false;  		} -	} else { -		__remove_discard_cmd(sbi, dc); + +		(*issued)++; +		if (*issued == dpolicy->max_requests) +			last = true; + +		dc->len += len; + +		if (time_to_inject(sbi, FAULT_DISCARD)) { +			f2fs_show_injection_info(FAULT_DISCARD); +			err = -EIO; +			goto submit; +		} +		err = __blkdev_issue_discard(bdev, +					SECTOR_FROM_BLOCK(start), +					SECTOR_FROM_BLOCK(len), +					GFP_NOFS, 0, &bio); +submit: +		if (err) { +			spin_lock_irqsave(&dc->lock, flags); +			if (dc->state == D_PARTIAL) +				dc->state = D_SUBMIT; +			spin_unlock_irqrestore(&dc->lock, flags); + +			break; +		} + +		f2fs_bug_on(sbi, !bio); + +		/* +		 * should keep before submission to avoid D_DONE +		 * right away +		 */ +		spin_lock_irqsave(&dc->lock, flags); +		if (last) +			dc->state = D_SUBMIT; +		else +			dc->state = D_PARTIAL; +		dc->bio_ref++; +		spin_unlock_irqrestore(&dc->lock, flags); + +		atomic_inc(&dcc->issing_discard); +		dc->issuing++; +		list_move_tail(&dc->list, wait_list); + +		/* sanity check on discard range */ +		__check_sit_bitmap(sbi, start, start + len); + +		bio->bi_private = dc; +		bio->bi_end_io = f2fs_submit_discard_endio; +		bio->bi_opf |= flag; +		submit_bio(bio); + +		atomic_inc(&dcc->issued_discard); + +		f2fs_update_iostat(sbi, FS_DISCARD, 1); + +		lstart += len; +		start += len; +		total_len -= len; +		len = total_len;  	} + +	if (!err && len) +		__update_discard_tree_range(sbi, bdev, lstart, start, len); +	return err;  }  static struct discard_cmd *__insert_discard_tree(struct f2fs_sb_info *sbi, @@ -1084,10 +1181,11 @@ static void __update_discard_tree_range(struct f2fs_sb_info *sbi,  	struct discard_cmd *dc;  	struct discard_info di = {0};  	struct rb_node **insert_p = NULL, *insert_parent = NULL; +	struct request_queue *q = bdev_get_queue(bdev); +	unsigned int max_discard_blocks = +			SECTOR_TO_BLOCK(q->limits.max_discard_sectors);  	block_t end = lstart + len; -	mutex_lock(&dcc->cmd_lock); -  	dc = (struct discard_cmd *)f2fs_lookup_rb_tree_ret(&dcc->root,  					NULL, lstart,  					(struct rb_entry **)&prev_dc, @@ -1127,7 +1225,8 @@ static void __update_discard_tree_range(struct f2fs_sb_info *sbi,  		if (prev_dc && prev_dc->state == D_PREP &&  			prev_dc->bdev == bdev && -			__is_discard_back_mergeable(&di, &prev_dc->di)) { +			__is_discard_back_mergeable(&di, &prev_dc->di, +							max_discard_blocks)) {  			prev_dc->di.len += di.len;  			dcc->undiscard_blks += di.len;  			__relocate_discard_cmd(dcc, prev_dc); @@ -1138,7 +1237,8 @@ static void __update_discard_tree_range(struct f2fs_sb_info *sbi,  		if (next_dc && next_dc->state == D_PREP &&  			next_dc->bdev == bdev && -			__is_discard_front_mergeable(&di, &next_dc->di)) { +			__is_discard_front_mergeable(&di, &next_dc->di, +							max_discard_blocks)) {  			next_dc->di.lstart = di.lstart;  			next_dc->di.len += di.len;  			next_dc->di.start = di.start; @@ -1161,8 +1261,6 @@ static void __update_discard_tree_range(struct f2fs_sb_info *sbi,  		node = rb_next(&prev_dc->rb_node);  		next_dc = rb_entry_safe(node, struct discard_cmd, rb_node);  	} - -	mutex_unlock(&dcc->cmd_lock);  }  static int __queue_discard_cmd(struct f2fs_sb_info *sbi, @@ -1177,10 +1275,72 @@ static int __queue_discard_cmd(struct f2fs_sb_info *sbi,  		blkstart -= FDEV(devi).start_blk;  	} +	mutex_lock(&SM_I(sbi)->dcc_info->cmd_lock);  	__update_discard_tree_range(sbi, bdev, lblkstart, blkstart, blklen); +	mutex_unlock(&SM_I(sbi)->dcc_info->cmd_lock);  	return 0;  } +static unsigned int __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi, +					struct discard_policy *dpolicy) +{ +	struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; +	struct discard_cmd *prev_dc = NULL, *next_dc = NULL; +	struct rb_node **insert_p = NULL, *insert_parent = NULL; +	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); +	dc = (struct discard_cmd *)f2fs_lookup_rb_tree_ret(&dcc->root, +					NULL, pos, +					(struct rb_entry **)&prev_dc, +					(struct rb_entry **)&next_dc, +					&insert_p, &insert_parent, true); +	if (!dc) +		dc = next_dc; + +	blk_start_plug(&plug); + +	while (dc) { +		struct rb_node *node; +		int err = 0; + +		if (dc->state != D_PREP) +			goto next; + +		if (dpolicy->io_aware && !is_idle(sbi)) { +			io_interrupted = true; +			break; +		} + +		dcc->next_pos = dc->lstart + dc->len; +		err = __submit_discard_cmd(sbi, dpolicy, dc, &issued); + +		if (issued >= dpolicy->max_requests) +			break; +next: +		node = rb_next(&dc->rb_node); +		if (err) +			__remove_discard_cmd(sbi, dc); +		dc = rb_entry_safe(node, struct discard_cmd, rb_node); +	} + +	blk_finish_plug(&plug); + +	if (!dc) +		dcc->next_pos = 0; + +	mutex_unlock(&dcc->cmd_lock); + +	if (!issued && io_interrupted) +		issued = -1; + +	return issued; +} +  static int __issue_discard_cmd(struct f2fs_sb_info *sbi,  					struct discard_policy *dpolicy)  { @@ -1188,19 +1348,24 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi,  	struct list_head *pend_list;  	struct discard_cmd *dc, *tmp;  	struct blk_plug plug; -	int i, iter = 0, issued = 0; +	int i, issued = 0;  	bool io_interrupted = false;  	for (i = MAX_PLIST_NUM - 1; i >= 0; i--) {  		if (i + 1 < dpolicy->granularity)  			break; + +		if (i < DEFAULT_DISCARD_GRANULARITY && dpolicy->ordered) +			return __issue_discard_cmd_orderly(sbi, dpolicy); +  		pend_list = &dcc->pend_list[i];  		mutex_lock(&dcc->cmd_lock);  		if (list_empty(pend_list))  			goto next; -		f2fs_bug_on(sbi, -			!f2fs_check_rb_tree_consistence(sbi, &dcc->root)); +		if (unlikely(dcc->rbtree_check)) +			f2fs_bug_on(sbi, !f2fs_check_rb_tree_consistence(sbi, +								&dcc->root));  		blk_start_plug(&plug);  		list_for_each_entry_safe(dc, tmp, pend_list, list) {  			f2fs_bug_on(sbi, dc->state != D_PREP); @@ -1208,20 +1373,19 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi,  			if (dpolicy->io_aware && i < dpolicy->io_aware_gran &&  								!is_idle(sbi)) {  				io_interrupted = true; -				goto skip; +				break;  			} -			__submit_discard_cmd(sbi, dpolicy, dc); -			issued++; -skip: -			if (++iter >= dpolicy->max_requests) +			__submit_discard_cmd(sbi, dpolicy, dc, &issued); + +			if (issued >= dpolicy->max_requests)  				break;  		}  		blk_finish_plug(&plug);  next:  		mutex_unlock(&dcc->cmd_lock); -		if (iter >= dpolicy->max_requests) +		if (issued >= dpolicy->max_requests || io_interrupted)  			break;  	} @@ -1319,21 +1483,22 @@ next:  	return trimmed;  } -static void __wait_all_discard_cmd(struct f2fs_sb_info *sbi, +static unsigned int __wait_all_discard_cmd(struct f2fs_sb_info *sbi,  						struct discard_policy *dpolicy)  {  	struct discard_policy dp; +	unsigned int discard_blks; -	if (dpolicy) { -		__wait_discard_cmd_range(sbi, dpolicy, 0, UINT_MAX); -		return; -	} +	if (dpolicy) +		return __wait_discard_cmd_range(sbi, dpolicy, 0, UINT_MAX);  	/* wait all */  	__init_discard_policy(sbi, &dp, DPOLICY_FSTRIM, 1); -	__wait_discard_cmd_range(sbi, &dp, 0, UINT_MAX); +	discard_blks = __wait_discard_cmd_range(sbi, &dp, 0, UINT_MAX);  	__init_discard_policy(sbi, &dp, DPOLICY_UMOUNT, 1); -	__wait_discard_cmd_range(sbi, &dp, 0, UINT_MAX); +	discard_blks += __wait_discard_cmd_range(sbi, &dp, 0, UINT_MAX); + +	return discard_blks;  }  /* This should be covered by global mutex, &sit_i->sentry_lock */ @@ -1386,6 +1551,8 @@ bool f2fs_wait_discard_bios(struct f2fs_sb_info *sbi)  	/* just to make sure there is no pending discard commands */  	__wait_all_discard_cmd(sbi, NULL); + +	f2fs_bug_on(sbi, atomic_read(&dcc->discard_cmd_cnt));  	return dropped;  } @@ -1643,21 +1810,30 @@ void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi,  	unsigned int start = 0, end = -1;  	unsigned int secno, start_segno;  	bool force = (cpc->reason & CP_DISCARD); +	bool need_align = test_opt(sbi, LFS) && sbi->segs_per_sec > 1;  	mutex_lock(&dirty_i->seglist_lock);  	while (1) {  		int i; + +		if (need_align && end != -1) +			end--;  		start = find_next_bit(prefree_map, MAIN_SEGS(sbi), end + 1);  		if (start >= MAIN_SEGS(sbi))  			break;  		end = find_next_zero_bit(prefree_map, MAIN_SEGS(sbi),  								start + 1); -		for (i = start; i < end; i++) -			clear_bit(i, prefree_map); +		if (need_align) { +			start = rounddown(start, sbi->segs_per_sec); +			end = roundup(end, sbi->segs_per_sec); +		} -		dirty_i->nr_dirty[PRE] -= end - start; +		for (i = start; i < end; i++) { +			if (test_and_clear_bit(i, prefree_map)) +				dirty_i->nr_dirty[PRE]--; +		}  		if (!test_opt(sbi, DISCARD))  			continue; @@ -1751,7 +1927,9 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi)  	dcc->nr_discards = 0;  	dcc->max_discards = MAIN_SEGS(sbi) << sbi->log_blocks_per_seg;  	dcc->undiscard_blks = 0; +	dcc->next_pos = 0;  	dcc->root = RB_ROOT; +	dcc->rbtree_check = false;  	init_waitqueue_head(&dcc->discard_wait_queue);  	SM_I(sbi)->dcc_info = dcc; @@ -1901,6 +2079,8 @@ void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr)  	if (addr == NEW_ADDR)  		return; +	invalidate_mapping_pages(META_MAPPING(sbi), addr, addr); +  	/* add it into sit main buffer */  	down_write(&sit_i->sentry_lock); @@ -1919,7 +2099,7 @@ bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr)  	struct seg_entry *se;  	bool is_cp = false; -	if (!is_valid_blkaddr(blkaddr)) +	if (!is_valid_data_blkaddr(sbi, blkaddr))  		return true;  	down_read(&sit_i->sentry_lock); @@ -1983,7 +2163,7 @@ int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra)   */  struct page *f2fs_get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno)  { -	return f2fs_get_meta_page(sbi, GET_SUM_BLOCK(sbi, segno)); +	return f2fs_get_meta_page_nofail(sbi, GET_SUM_BLOCK(sbi, segno));  }  void f2fs_update_meta_page(struct f2fs_sb_info *sbi, @@ -2366,7 +2546,7 @@ bool f2fs_exist_trim_candidates(struct f2fs_sb_info *sbi,  	return has_candidate;  } -static void __issue_discard_cmd_range(struct f2fs_sb_info *sbi, +static unsigned int __issue_discard_cmd_range(struct f2fs_sb_info *sbi,  					struct discard_policy *dpolicy,  					unsigned int start, unsigned int end)  { @@ -2376,12 +2556,15 @@ static void __issue_discard_cmd_range(struct f2fs_sb_info *sbi,  	struct discard_cmd *dc;  	struct blk_plug plug;  	int issued; +	unsigned int trimmed = 0;  next:  	issued = 0;  	mutex_lock(&dcc->cmd_lock); -	f2fs_bug_on(sbi, !f2fs_check_rb_tree_consistence(sbi, &dcc->root)); +	if (unlikely(dcc->rbtree_check)) +		f2fs_bug_on(sbi, !f2fs_check_rb_tree_consistence(sbi, +								&dcc->root));  	dc = (struct discard_cmd *)f2fs_lookup_rb_tree_ret(&dcc->root,  					NULL, start, @@ -2395,6 +2578,7 @@ next:  	while (dc && dc->lstart <= end) {  		struct rb_node *node; +		int err = 0;  		if (dc->len < dpolicy->granularity)  			goto skip; @@ -2404,19 +2588,24 @@ next:  			goto skip;  		} -		__submit_discard_cmd(sbi, dpolicy, dc); +		err = __submit_discard_cmd(sbi, dpolicy, dc, &issued); -		if (++issued >= dpolicy->max_requests) { +		if (issued >= dpolicy->max_requests) {  			start = dc->lstart + dc->len; +			if (err) +				__remove_discard_cmd(sbi, dc); +  			blk_finish_plug(&plug);  			mutex_unlock(&dcc->cmd_lock); -			__wait_all_discard_cmd(sbi, NULL); +			trimmed += __wait_all_discard_cmd(sbi, NULL);  			congestion_wait(BLK_RW_ASYNC, HZ/50);  			goto next;  		}  skip:  		node = rb_next(&dc->rb_node); +		if (err) +			__remove_discard_cmd(sbi, dc);  		dc = rb_entry_safe(node, struct discard_cmd, rb_node);  		if (fatal_signal_pending(current)) @@ -2425,6 +2614,8 @@ skip:  	blk_finish_plug(&plug);  	mutex_unlock(&dcc->cmd_lock); + +	return trimmed;  }  int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) @@ -2437,12 +2628,13 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)  	struct discard_policy dpolicy;  	unsigned long long trimmed = 0;  	int err = 0; +	bool need_align = test_opt(sbi, LFS) && sbi->segs_per_sec > 1;  	if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize)  		return -EINVAL; -	if (end <= MAIN_BLKADDR(sbi)) -		return -EINVAL; +	if (end < MAIN_BLKADDR(sbi)) +		goto out;  	if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) {  		f2fs_msg(sbi->sb, KERN_WARNING, @@ -2454,6 +2646,10 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)  	start_segno = (start <= MAIN_BLKADDR(sbi)) ? 0 : GET_SEGNO(sbi, start);  	end_segno = (end >= MAX_BLKADDR(sbi)) ? MAIN_SEGS(sbi) - 1 :  						GET_SEGNO(sbi, end); +	if (need_align) { +		start_segno = rounddown(start_segno, sbi->segs_per_sec); +		end_segno = roundup(end_segno + 1, sbi->segs_per_sec) - 1; +	}  	cpc.reason = CP_DISCARD;  	cpc.trim_minlen = max_t(__u64, 1, F2FS_BYTES_TO_BLK(range->minlen)); @@ -2469,24 +2665,27 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)  	if (err)  		goto out; -	start_block = START_BLOCK(sbi, start_segno); -	end_block = START_BLOCK(sbi, end_segno + 1); - -	__init_discard_policy(sbi, &dpolicy, DPOLICY_FSTRIM, cpc.trim_minlen); -	__issue_discard_cmd_range(sbi, &dpolicy, start_block, end_block); -  	/*  	 * We filed discard candidates, but actually we don't need to wait for  	 * all of them, since they'll be issued in idle time along with runtime  	 * discard option. User configuration looks like using runtime discard  	 * or periodic fstrim instead of it.  	 */ -	if (!test_opt(sbi, DISCARD)) { -		trimmed = __wait_discard_cmd_range(sbi, &dpolicy, +	if (test_opt(sbi, DISCARD)) +		goto out; + +	start_block = START_BLOCK(sbi, start_segno); +	end_block = START_BLOCK(sbi, end_segno + 1); + +	__init_discard_policy(sbi, &dpolicy, DPOLICY_FSTRIM, cpc.trim_minlen); +	trimmed = __issue_discard_cmd_range(sbi, &dpolicy, +					start_block, end_block); + +	trimmed += __wait_discard_cmd_range(sbi, &dpolicy,  					start_block, end_block); -		range->len = F2FS_BLK_TO_BYTES(trimmed); -	}  out: +	if (!err) +		range->len = F2FS_BLK_TO_BYTES(trimmed);  	return err;  } @@ -2639,8 +2838,8 @@ static int __get_segment_type_6(struct f2fs_io_info *fio)  			return CURSEG_COLD_DATA;  		if (file_is_hot(inode) ||  				is_inode_flag_set(inode, FI_HOT_DATA) || -				is_inode_flag_set(inode, FI_ATOMIC_FILE) || -				is_inode_flag_set(inode, FI_VOLATILE_FILE)) +				f2fs_is_atomic_file(inode) || +				f2fs_is_volatile_file(inode))  			return CURSEG_HOT_DATA;  		return f2fs_rw_hint_to_seg_type(inode->i_write_hint);  	} else { @@ -2781,6 +2980,9 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)  reallocate:  	f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,  			&fio->new_blkaddr, sum, type, fio, true); +	if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO) +		invalidate_mapping_pages(META_MAPPING(fio->sbi), +					fio->old_blkaddr, fio->old_blkaddr);  	/* writeout dirty page into bdev */  	f2fs_submit_page_write(fio); @@ -2836,11 +3038,9 @@ void f2fs_outplace_write_data(struct dnode_of_data *dn,  {  	struct f2fs_sb_info *sbi = fio->sbi;  	struct f2fs_summary sum; -	struct node_info ni;  	f2fs_bug_on(sbi, dn->data_blkaddr == NULL_ADDR); -	f2fs_get_node_info(sbi, dn->nid, &ni); -	set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); +	set_summary(&sum, dn->nid, dn->ofs_in_node, fio->version);  	do_write_page(&sum, fio);  	f2fs_update_data_blkaddr(dn, fio->new_blkaddr); @@ -2937,8 +3137,11 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,  	if (!recover_curseg || recover_newaddr)  		update_sit_entry(sbi, new_blkaddr, 1); -	if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) +	if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) { +		invalidate_mapping_pages(META_MAPPING(sbi), +					old_blkaddr, old_blkaddr);  		update_sit_entry(sbi, old_blkaddr, -1); +	}  	locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr));  	locate_dirty_segment(sbi, GET_SEGNO(sbi, new_blkaddr)); @@ -2992,7 +3195,7 @@ void f2fs_wait_on_block_writeback(struct f2fs_sb_info *sbi, block_t blkaddr)  {  	struct page *cpage; -	if (!is_valid_blkaddr(blkaddr)) +	if (!is_valid_data_blkaddr(sbi, blkaddr))  		return;  	cpage = find_lock_page(META_MAPPING(sbi), blkaddr); @@ -3002,7 +3205,7 @@ void f2fs_wait_on_block_writeback(struct f2fs_sb_info *sbi, block_t blkaddr)  	}  } -static void read_compacted_summaries(struct f2fs_sb_info *sbi) +static int read_compacted_summaries(struct f2fs_sb_info *sbi)  {  	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);  	struct curseg_info *seg_i; @@ -3014,6 +3217,8 @@ static void read_compacted_summaries(struct f2fs_sb_info *sbi)  	start = start_sum_block(sbi);  	page = f2fs_get_meta_page(sbi, start++); +	if (IS_ERR(page)) +		return PTR_ERR(page);  	kaddr = (unsigned char *)page_address(page);  	/* Step 1: restore nat cache */ @@ -3054,11 +3259,14 @@ static void read_compacted_summaries(struct f2fs_sb_info *sbi)  			page = NULL;  			page = f2fs_get_meta_page(sbi, start++); +			if (IS_ERR(page)) +				return PTR_ERR(page);  			kaddr = (unsigned char *)page_address(page);  			offset = 0;  		}  	}  	f2fs_put_page(page, 1); +	return 0;  }  static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) @@ -3070,6 +3278,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)  	unsigned short blk_off;  	unsigned int segno = 0;  	block_t blk_addr = 0; +	int err = 0;  	/* get segment number and block addr */  	if (IS_DATASEG(type)) { @@ -3093,6 +3302,8 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)  	}  	new = f2fs_get_meta_page(sbi, blk_addr); +	if (IS_ERR(new)) +		return PTR_ERR(new);  	sum = (struct f2fs_summary_block *)page_address(new);  	if (IS_NODESEG(type)) { @@ -3104,7 +3315,9 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)  				ns->ofs_in_node = 0;  			}  		} else { -			f2fs_restore_node_summary(sbi, segno, sum); +			err = f2fs_restore_node_summary(sbi, segno, sum); +			if (err) +				goto out;  		}  	} @@ -3124,8 +3337,9 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)  	curseg->alloc_type = ckpt->alloc_type[type];  	curseg->next_blkoff = blk_off;  	mutex_unlock(&curseg->curseg_mutex); +out:  	f2fs_put_page(new, 1); -	return 0; +	return err;  }  static int restore_curseg_summaries(struct f2fs_sb_info *sbi) @@ -3143,7 +3357,9 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi)  							META_CP, true);  		/* restore for compacted data summary */ -		read_compacted_summaries(sbi); +		err = read_compacted_summaries(sbi); +		if (err) +			return err;  		type = CURSEG_HOT_NODE;  	} @@ -3274,7 +3490,7 @@ int f2fs_lookup_journal_in_cursum(struct f2fs_journal *journal, int type,  static struct page *get_current_sit_page(struct f2fs_sb_info *sbi,  					unsigned int segno)  { -	return f2fs_get_meta_page(sbi, current_sit_addr(sbi, segno)); +	return f2fs_get_meta_page_nofail(sbi, current_sit_addr(sbi, segno));  }  static struct page *get_next_sit_page(struct f2fs_sb_info *sbi, @@ -3923,6 +4139,7 @@ int f2fs_build_segment_manager(struct f2fs_sb_info *sbi)  		sm_info->ipu_policy = 1 << 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 * sbi->segs_per_sec;  	sm_info->min_hot_blocks = DEF_MIN_HOT_BLOCKS;  	sm_info->min_ssr_sections = reserved_sections(sbi);  |