diff options
Diffstat (limited to 'fs/f2fs/data.c')
| -rw-r--r-- | fs/f2fs/data.c | 191 | 
1 files changed, 66 insertions, 125 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 26e317696b33..d9494b5fc7c1 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -48,7 +48,7 @@ void f2fs_destroy_bioset(void)  	bioset_exit(&f2fs_bioset);  } -static bool __is_cp_guaranteed(struct page *page) +bool f2fs_is_cp_guaranteed(struct page *page)  {  	struct address_space *mapping = page->mapping;  	struct inode *inode; @@ -65,8 +65,6 @@ static bool __is_cp_guaranteed(struct page *page)  			S_ISDIR(inode->i_mode))  		return true; -	if (f2fs_is_compressed_page(page)) -		return false;  	if ((S_ISREG(inode->i_mode) && IS_NOQUOTA(inode)) ||  			page_private_gcing(page))  		return true; @@ -338,18 +336,7 @@ static void f2fs_write_end_io(struct bio *bio)  	bio_for_each_segment_all(bvec, bio, iter_all) {  		struct page *page = bvec->bv_page; -		enum count_type type = WB_DATA_TYPE(page); - -		if (page_private_dummy(page)) { -			clear_page_private_dummy(page); -			unlock_page(page); -			mempool_free(page, sbi->write_io_dummy); - -			if (unlikely(bio->bi_status)) -				f2fs_stop_checkpoint(sbi, true, -						STOP_CP_REASON_WRITE_FAIL); -			continue; -		} +		enum count_type type = WB_DATA_TYPE(page, false);  		fscrypt_finalize_bounce_page(&page); @@ -524,50 +511,13 @@ void f2fs_submit_read_bio(struct f2fs_sb_info *sbi, struct bio *bio,  	submit_bio(bio);  } -static void f2fs_align_write_bio(struct f2fs_sb_info *sbi, struct bio *bio) -{ -	unsigned int start = -		(bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS) % F2FS_IO_SIZE(sbi); - -	if (start == 0) -		return; - -	/* fill dummy pages */ -	for (; start < F2FS_IO_SIZE(sbi); start++) { -		struct page *page = -			mempool_alloc(sbi->write_io_dummy, -				      GFP_NOIO | __GFP_NOFAIL); -		f2fs_bug_on(sbi, !page); - -		lock_page(page); - -		zero_user_segment(page, 0, PAGE_SIZE); -		set_page_private_dummy(page); - -		if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) -			f2fs_bug_on(sbi, 1); -	} -} -  static void f2fs_submit_write_bio(struct f2fs_sb_info *sbi, struct bio *bio,  				  enum page_type type)  {  	WARN_ON_ONCE(is_read_io(bio_op(bio))); -	if (type == DATA || type == NODE) { -		if (f2fs_lfs_mode(sbi) && current->plug) -			blk_finish_plug(current->plug); - -		if (F2FS_IO_ALIGNED(sbi)) { -			f2fs_align_write_bio(sbi, bio); -			/* -			 * In the NODE case, we lose next block address chain. -			 * So, we need to do checkpoint in f2fs_sync_file. -			 */ -			if (type == NODE) -				set_sbi_flag(sbi, SBI_NEED_CP); -		} -	} +	if (f2fs_lfs_mode(sbi) && current->plug && PAGE_TYPE_ON_MAIN(type)) +		blk_finish_plug(current->plug);  	trace_f2fs_submit_write_bio(sbi->sb, type, bio);  	iostat_update_submit_ctx(bio, type); @@ -740,10 +690,8 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)  	if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr,  			fio->is_por ? META_POR : (__is_meta_io(fio) ? -			META_GENERIC : DATA_GENERIC_ENHANCE))) { -		f2fs_handle_error(fio->sbi, ERROR_INVALID_BLKADDR); +			META_GENERIC : DATA_GENERIC_ENHANCE)))  		return -EFSCORRUPTED; -	}  	trace_f2fs_submit_page_bio(page, fio); @@ -762,7 +710,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)  		wbc_account_cgroup_owner(fio->io_wbc, fio->page, PAGE_SIZE);  	inc_page_count(fio->sbi, is_read_io(fio->op) ? -			__read_io_type(page) : WB_DATA_TYPE(fio->page)); +			__read_io_type(page) : WB_DATA_TYPE(fio->page, false));  	if (is_read_io(bio_op(bio)))  		f2fs_submit_read_bio(fio->sbi, bio, fio->type); @@ -796,16 +744,6 @@ static bool io_is_mergeable(struct f2fs_sb_info *sbi, struct bio *bio,  					block_t last_blkaddr,  					block_t cur_blkaddr)  { -	if (F2FS_IO_ALIGNED(sbi) && (fio->type == DATA || fio->type == NODE)) { -		unsigned int filled_blocks = -				F2FS_BYTES_TO_BLK(bio->bi_iter.bi_size); -		unsigned int io_size = F2FS_IO_SIZE(sbi); -		unsigned int left_vecs = bio->bi_max_vecs - bio->bi_vcnt; - -		/* IOs in bio is aligned and left space of vectors is not enough */ -		if (!(filled_blocks % io_size) && left_vecs < io_size) -			return false; -	}  	if (!page_is_mergeable(sbi, bio, last_blkaddr, cur_blkaddr))  		return false;  	return io_type_is_mergeable(io, fio); @@ -948,10 +886,8 @@ int f2fs_merge_page_bio(struct f2fs_io_info *fio)  			fio->encrypted_page : fio->page;  	if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr, -			__is_meta_io(fio) ? META_GENERIC : DATA_GENERIC)) { -		f2fs_handle_error(fio->sbi, ERROR_INVALID_BLKADDR); +			__is_meta_io(fio) ? META_GENERIC : DATA_GENERIC))  		return -EFSCORRUPTED; -	}  	trace_f2fs_submit_page_bio(page, fio); @@ -973,7 +909,7 @@ alloc_new:  	if (fio->io_wbc)  		wbc_account_cgroup_owner(fio->io_wbc, fio->page, PAGE_SIZE); -	inc_page_count(fio->sbi, WB_DATA_TYPE(page)); +	inc_page_count(fio->sbi, WB_DATA_TYPE(page, false));  	*fio->last_block = fio->new_blkaddr;  	*fio->bio = bio; @@ -1007,11 +943,12 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)  	enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);  	struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp;  	struct page *bio_page; +	enum count_type type;  	f2fs_bug_on(sbi, is_read_io(fio->op));  	f2fs_down_write(&io->io_rwsem); - +next:  #ifdef CONFIG_BLK_DEV_ZONED  	if (f2fs_sb_has_blkzoned(sbi) && btype < META && io->zone_pending_bio) {  		wait_for_completion_io(&io->zone_wait); @@ -1021,7 +958,6 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)  	}  #endif -next:  	if (fio->in_list) {  		spin_lock(&io->io_lock);  		if (list_empty(&io->io_list)) { @@ -1046,7 +982,8 @@ next:  	/* set submitted = true as a return value */  	fio->submitted = 1; -	inc_page_count(sbi, WB_DATA_TYPE(bio_page)); +	type = WB_DATA_TYPE(bio_page, fio->compressed_page); +	inc_page_count(sbi, type);  	if (io->bio &&  	    (!io_is_mergeable(sbi, io->bio, io, fio, io->last_block_in_bio, @@ -1056,13 +993,6 @@ next:  		__submit_merged_bio(io);  alloc_new:  	if (io->bio == NULL) { -		if (F2FS_IO_ALIGNED(sbi) && -				(fio->type == DATA || fio->type == NODE) && -				fio->new_blkaddr & F2FS_IO_SIZE_MASK(sbi)) { -			dec_page_count(sbi, WB_DATA_TYPE(bio_page)); -			fio->retry = 1; -			goto skip; -		}  		io->bio = __bio_alloc(fio, BIO_MAX_VECS);  		f2fs_set_bio_crypt_ctx(io->bio, fio->page->mapping->host,  				       bio_page->index, fio, GFP_NOIO); @@ -1080,10 +1010,6 @@ alloc_new:  	io->last_block_in_bio = fio->new_blkaddr;  	trace_f2fs_submit_page_write(fio->page, fio); -skip: -	if (fio->in_list) -		goto next; -out:  #ifdef CONFIG_BLK_DEV_ZONED  	if (f2fs_sb_has_blkzoned(sbi) && btype < META &&  			is_end_zone_blkaddr(sbi, fio->new_blkaddr)) { @@ -1096,6 +1022,9 @@ out:  		__submit_merged_bio(io);  	}  #endif +	if (fio->in_list) +		goto next; +out:  	if (is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN) ||  				!f2fs_is_checkpoint_ready(sbi))  		__submit_merged_bio(io); @@ -1218,7 +1147,8 @@ int f2fs_reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count)  	if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC)))  		return -EPERM; -	if (unlikely((err = inc_valid_block_count(sbi, dn->inode, &count)))) +	err = inc_valid_block_count(sbi, dn->inode, &count, true); +	if (unlikely(err))  		return err;  	trace_f2fs_reserve_new_blocks(dn->inode, dn->nid, @@ -1285,8 +1215,6 @@ struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,  		if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), dn.data_blkaddr,  						DATA_GENERIC_ENHANCE_READ)) {  			err = -EFSCORRUPTED; -			f2fs_handle_error(F2FS_I_SB(inode), -						ERROR_INVALID_BLKADDR);  			goto put_err;  		}  		goto got_it; @@ -1312,8 +1240,6 @@ struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,  						dn.data_blkaddr,  						DATA_GENERIC_ENHANCE)) {  		err = -EFSCORRUPTED; -		f2fs_handle_error(F2FS_I_SB(inode), -					ERROR_INVALID_BLKADDR);  		goto put_err;  	}  got_it: @@ -1475,15 +1401,18 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)  	dn->data_blkaddr = f2fs_data_blkaddr(dn);  	if (dn->data_blkaddr == NULL_ADDR) { -		err = inc_valid_block_count(sbi, dn->inode, &count); +		err = inc_valid_block_count(sbi, dn->inode, &count, true);  		if (unlikely(err))  			return err;  	}  	set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);  	old_blkaddr = dn->data_blkaddr; -	f2fs_allocate_data_block(sbi, NULL, old_blkaddr, &dn->data_blkaddr, -				&sum, seg_type, NULL); +	err = f2fs_allocate_data_block(sbi, NULL, old_blkaddr, +				&dn->data_blkaddr, &sum, seg_type, NULL); +	if (err) +		return err; +  	if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO)  		f2fs_invalidate_internal_cache(sbi, old_blkaddr); @@ -1641,7 +1570,6 @@ next_block:  	if (!is_hole &&  	    !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) {  		err = -EFSCORRUPTED; -		f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);  		goto sync_out;  	} @@ -2165,8 +2093,6 @@ got_it:  		if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), block_nr,  						DATA_GENERIC_ENHANCE_READ)) {  			ret = -EFSCORRUPTED; -			f2fs_handle_error(F2FS_I_SB(inode), -						ERROR_INVALID_BLKADDR);  			goto out;  		}  	} else { @@ -2668,8 +2594,6 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)  	if (fio) {  		if (page_private_gcing(fio->page))  			return true; -		if (page_private_dummy(fio->page)) -			return true;  		if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) &&  			f2fs_is_checkpointed_data(sbi, fio->old_blkaddr)))  			return true; @@ -2706,11 +2630,8 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)  	    f2fs_lookup_read_extent_cache_block(inode, page->index,  						&fio->old_blkaddr)) {  		if (!f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr, -						DATA_GENERIC_ENHANCE)) { -			f2fs_handle_error(fio->sbi, -						ERROR_INVALID_BLKADDR); +						DATA_GENERIC_ENHANCE))  			return -EFSCORRUPTED; -		}  		ipu_force = true;  		fio->need_lock = LOCK_DONE; @@ -2738,7 +2659,6 @@ got_it:  		!f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,  						DATA_GENERIC_ENHANCE)) {  		err = -EFSCORRUPTED; -		f2fs_handle_error(fio->sbi, ERROR_INVALID_BLKADDR);  		goto out_writepage;  	} @@ -2838,7 +2758,7 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,  		.encrypted_page = NULL,  		.submitted = 0,  		.compr_blocks = compr_blocks, -		.need_lock = LOCK_RETRY, +		.need_lock = compr_blocks ? LOCK_DONE : LOCK_RETRY,  		.post_read = f2fs_post_read_required(inode) ? 1 : 0,  		.io_type = io_type,  		.io_wbc = wbc, @@ -2919,6 +2839,7 @@ write:  	if (err == -EAGAIN) {  		err = f2fs_do_write_data_page(&fio);  		if (err == -EAGAIN) { +			f2fs_bug_on(sbi, compr_blocks);  			fio.need_lock = LOCK_REQ;  			err = f2fs_do_write_data_page(&fio);  		} @@ -3704,7 +3625,6 @@ repeat:  		if (!f2fs_is_valid_blkaddr(sbi, blkaddr,  				DATA_GENERIC_ENHANCE_READ)) {  			err = -EFSCORRUPTED; -			f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);  			goto fail;  		}  		err = f2fs_submit_page_read(use_cow ? @@ -3905,26 +3825,36 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk,  	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);  	unsigned int blkofs;  	unsigned int blk_per_sec = BLKS_PER_SEC(sbi); +	unsigned int end_blk = start_blk + blkcnt - 1;  	unsigned int secidx = start_blk / blk_per_sec; -	unsigned int end_sec = secidx + blkcnt / blk_per_sec; +	unsigned int end_sec;  	int ret = 0; +	if (!blkcnt) +		return 0; +	end_sec = end_blk / blk_per_sec; +  	f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);  	filemap_invalidate_lock(inode->i_mapping);  	set_inode_flag(inode, FI_ALIGNED_WRITE);  	set_inode_flag(inode, FI_OPU_WRITE); -	for (; secidx < end_sec; secidx++) { +	for (; secidx <= end_sec; secidx++) { +		unsigned int blkofs_end = secidx == end_sec ? +				end_blk % blk_per_sec : blk_per_sec - 1; +  		f2fs_down_write(&sbi->pin_sem); -		f2fs_lock_op(sbi); -		f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false); -		f2fs_unlock_op(sbi); +		ret = f2fs_allocate_pinning_section(sbi); +		if (ret) { +			f2fs_up_write(&sbi->pin_sem); +			break; +		}  		set_inode_flag(inode, FI_SKIP_WRITES); -		for (blkofs = 0; blkofs < blk_per_sec; blkofs++) { +		for (blkofs = 0; blkofs <= blkofs_end; blkofs++) {  			struct page *page;  			unsigned int blkidx = secidx * blk_per_sec + blkofs; @@ -4013,27 +3943,34 @@ retry:  		nr_pblocks = map.m_len;  		if ((pblock - SM_I(sbi)->main_blkaddr) & sec_blks_mask || -				nr_pblocks & sec_blks_mask) { +				nr_pblocks & sec_blks_mask || +				!f2fs_valid_pinned_area(sbi, pblock)) { +			bool last_extent = false; +  			not_aligned++;  			nr_pblocks = roundup(nr_pblocks, blks_per_sec);  			if (cur_lblock + nr_pblocks > sis->max)  				nr_pblocks -= blks_per_sec; +			/* this extent is last one */  			if (!nr_pblocks) { -				/* this extent is last one */ -				nr_pblocks = map.m_len; -				f2fs_warn(sbi, "Swapfile: last extent is not aligned to section"); -				goto next; +				nr_pblocks = last_lblock - cur_lblock; +				last_extent = true;  			}  			ret = f2fs_migrate_blocks(inode, cur_lblock,  							nr_pblocks); -			if (ret) +			if (ret) { +				if (ret == -ENOENT) +					ret = -EINVAL;  				goto out; -			goto retry; +			} + +			if (!last_extent) +				goto retry;  		} -next: +  		if (cur_lblock + nr_pblocks >= sis->max)  			nr_pblocks = sis->max - cur_lblock; @@ -4071,17 +4008,17 @@ static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,  				sector_t *span)  {  	struct inode *inode = file_inode(file); +	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);  	int ret;  	if (!S_ISREG(inode->i_mode))  		return -EINVAL; -	if (f2fs_readonly(F2FS_I_SB(inode)->sb)) +	if (f2fs_readonly(sbi->sb))  		return -EROFS; -	if (f2fs_lfs_mode(F2FS_I_SB(inode))) { -		f2fs_err(F2FS_I_SB(inode), -			"Swapfile not supported in LFS mode"); +	if (f2fs_lfs_mode(sbi) && !f2fs_sb_has_blkzoned(sbi)) { +		f2fs_err(sbi, "Swapfile not supported in LFS mode");  		return -EINVAL;  	} @@ -4092,6 +4029,10 @@ static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,  	if (!f2fs_disable_compressed_file(inode))  		return -EINVAL; +	ret = filemap_fdatawrite(inode->i_mapping); +	if (ret < 0) +		return ret; +  	f2fs_precache_extents(inode);  	ret = check_swap_activate(sis, file, span); @@ -4100,7 +4041,7 @@ static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,  	stat_inc_swapfile_inode(inode);  	set_inode_flag(inode, FI_PIN_FILE); -	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); +	f2fs_update_time(sbi, REQ_TIME);  	return ret;  }  |