diff options
| -rw-r--r-- | fs/f2fs/compress.c | 38 | ||||
| -rw-r--r-- | fs/f2fs/data.c | 62 | ||||
| -rw-r--r-- | fs/f2fs/dir.c | 53 | ||||
| -rw-r--r-- | fs/f2fs/f2fs.h | 29 | ||||
| -rw-r--r-- | fs/f2fs/file.c | 37 | ||||
| -rw-r--r-- | fs/f2fs/gc.c | 13 | ||||
| -rw-r--r-- | fs/f2fs/inline.c | 7 | ||||
| -rw-r--r-- | fs/f2fs/inode.c | 19 | ||||
| -rw-r--r-- | fs/f2fs/namei.c | 1 | ||||
| -rw-r--r-- | fs/f2fs/node.c | 10 | ||||
| -rw-r--r-- | fs/f2fs/recovery.c | 4 | ||||
| -rw-r--r-- | fs/f2fs/segment.c | 210 | ||||
| -rw-r--r-- | fs/f2fs/sysfs.c | 3 | ||||
| -rw-r--r-- | include/trace/events/f2fs.h | 39 | 
14 files changed, 324 insertions, 201 deletions
| diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index 7f26440e8595..985690d81a82 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -846,7 +846,7 @@ bool f2fs_cluster_can_merge_page(struct compress_ctx *cc, pgoff_t index)  bool f2fs_all_cluster_page_ready(struct compress_ctx *cc, struct page **pages,  				int index, int nr_pages, bool uptodate)  { -	unsigned long pgidx = pages[index]->index; +	unsigned long pgidx = page_folio(pages[index])->index;  	int i = uptodate ? 0 : 1;  	/* @@ -860,9 +860,11 @@ bool f2fs_all_cluster_page_ready(struct compress_ctx *cc, struct page **pages,  		return false;  	for (; i < cc->cluster_size; i++) { -		if (pages[index + i]->index != pgidx + i) +		struct folio *folio = page_folio(pages[index + i]); + +		if (folio->index != pgidx + i)  			return false; -		if (uptodate && !PageUptodate(pages[index + i])) +		if (uptodate && !folio_test_uptodate(folio))  			return false;  	} @@ -1195,7 +1197,8 @@ bool f2fs_compress_write_end(struct inode *inode, void *fsdata,  		.cluster_size = F2FS_I(inode)->i_cluster_size,  		.rpages = fsdata,  	}; -	bool first_index = (index == cc.rpages[0]->index); +	struct folio *folio = page_folio(cc.rpages[0]); +	bool first_index = (index == folio->index);  	if (copied)  		set_cluster_dirty(&cc); @@ -1239,13 +1242,14 @@ int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock)  		int i;  		for (i = cluster_size - 1; i >= 0; i--) { -			loff_t start = rpages[i]->index << PAGE_SHIFT; +			struct folio *folio = page_folio(rpages[i]); +			loff_t start = folio->index << PAGE_SHIFT;  			if (from <= start) { -				zero_user_segment(rpages[i], 0, PAGE_SIZE); +				folio_zero_segment(folio, 0, folio_size(folio));  			} else { -				zero_user_segment(rpages[i], from - start, -								PAGE_SIZE); +				folio_zero_segment(folio, from - start, +						folio_size(folio));  				break;  			}  		} @@ -1278,6 +1282,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,  		.encrypted = fscrypt_inode_uses_fs_layer_crypto(cc->inode) ?  									1 : 0,  	}; +	struct folio *folio;  	struct dnode_of_data dn;  	struct node_info ni;  	struct compress_io_ctx *cic; @@ -1289,7 +1294,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,  	/* we should bypass data pages to proceed the kworker jobs */  	if (unlikely(f2fs_cp_error(sbi))) { -		mapping_set_error(cc->rpages[0]->mapping, -EIO); +		mapping_set_error(inode->i_mapping, -EIO);  		goto out_free;  	} @@ -1316,7 +1321,8 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,  			goto out_put_dnode;  	} -	psize = (loff_t)(cc->rpages[last_index]->index + 1) << PAGE_SHIFT; +	folio = page_folio(cc->rpages[last_index]); +	psize = folio_pos(folio) + folio_size(folio);  	err = f2fs_get_node_info(fio.sbi, dn.nid, &ni, false);  	if (err) @@ -1339,7 +1345,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,  	for (i = 0; i < cc->valid_nr_cpages; i++) {  		f2fs_set_compressed_page(cc->cpages[i], inode, -					cc->rpages[i + 1]->index, cic); +				page_folio(cc->rpages[i + 1])->index, cic);  		fio.compressed_page = cc->cpages[i];  		fio.old_blkaddr = data_blkaddr(dn.inode, dn.node_page, @@ -1374,7 +1380,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,  			if (blkaddr == COMPRESS_ADDR)  				fio.compr_blocks++;  			if (__is_valid_data_blkaddr(blkaddr)) -				f2fs_invalidate_blocks(sbi, blkaddr); +				f2fs_invalidate_blocks(sbi, blkaddr, 1);  			f2fs_update_data_blkaddr(&dn, COMPRESS_ADDR);  			goto unlock_continue;  		} @@ -1384,7 +1390,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,  		if (i > cc->valid_nr_cpages) {  			if (__is_valid_data_blkaddr(blkaddr)) { -				f2fs_invalidate_blocks(sbi, blkaddr); +				f2fs_invalidate_blocks(sbi, blkaddr, 1);  				f2fs_update_data_blkaddr(&dn, NEW_ADDR);  			}  			goto unlock_continue; @@ -1545,6 +1551,7 @@ continue_unlock:  		if (!clear_page_dirty_for_io(cc->rpages[i]))  			goto continue_unlock; +		submitted = 0;  		ret = f2fs_write_single_data_page(page_folio(cc->rpages[i]),  						&submitted,  						NULL, NULL, wbc, io_type, @@ -1903,11 +1910,12 @@ struct address_space *COMPRESS_MAPPING(struct f2fs_sb_info *sbi)  	return sbi->compress_inode->i_mapping;  } -void f2fs_invalidate_compress_page(struct f2fs_sb_info *sbi, block_t blkaddr) +void f2fs_invalidate_compress_pages_range(struct f2fs_sb_info *sbi, +				block_t blkaddr, unsigned int len)  {  	if (!sbi->compress_inode)  		return; -	invalidate_mapping_pages(COMPRESS_MAPPING(sbi), blkaddr, blkaddr); +	invalidate_mapping_pages(COMPRESS_MAPPING(sbi), blkaddr, blkaddr + len - 1);  }  void f2fs_cache_compressed_page(struct f2fs_sb_info *sbi, struct page *page, diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index a9eddd782dbc..de4da6d9cd93 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -70,9 +70,9 @@ bool f2fs_is_cp_guaranteed(struct page *page)  	return false;  } -static enum count_type __read_io_type(struct page *page) +static enum count_type __read_io_type(struct folio *folio)  { -	struct address_space *mapping = page_file_mapping(page); +	struct address_space *mapping = folio->mapping;  	if (mapping) {  		struct inode *inode = mapping->host; @@ -136,27 +136,22 @@ struct bio_post_read_ctx {   */  static void f2fs_finish_read_bio(struct bio *bio, bool in_task)  { -	struct bio_vec *bv; -	struct bvec_iter_all iter_all; +	struct folio_iter fi;  	struct bio_post_read_ctx *ctx = bio->bi_private; -	bio_for_each_segment_all(bv, bio, iter_all) { -		struct page *page = bv->bv_page; +	bio_for_each_folio_all(fi, bio) { +		struct folio *folio = fi.folio; -		if (f2fs_is_compressed_page(page)) { +		if (f2fs_is_compressed_page(&folio->page)) {  			if (ctx && !ctx->decompression_attempted) -				f2fs_end_read_compressed_page(page, true, 0, +				f2fs_end_read_compressed_page(&folio->page, true, 0,  							in_task); -			f2fs_put_page_dic(page, in_task); +			f2fs_put_page_dic(&folio->page, in_task);  			continue;  		} -		if (bio->bi_status) -			ClearPageUptodate(page); -		else -			SetPageUptodate(page); -		dec_page_count(F2FS_P_SB(page), __read_io_type(page)); -		unlock_page(page); +		dec_page_count(F2FS_F_SB(folio), __read_io_type(folio)); +		folio_end_read(folio, bio->bi_status == 0);  	}  	if (ctx) @@ -516,10 +511,6 @@ 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 (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);  	submit_bio(bio); @@ -689,33 +680,29 @@ void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi)  int f2fs_submit_page_bio(struct f2fs_io_info *fio)  {  	struct bio *bio; -	struct page *page = fio->encrypted_page ? -			fio->encrypted_page : fio->page; +	struct folio *fio_folio = page_folio(fio->page); +	struct folio *data_folio = fio->encrypted_page ? +			page_folio(fio->encrypted_page) : fio_folio;  	if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr,  			fio->is_por ? META_POR : (__is_meta_io(fio) ?  			META_GENERIC : DATA_GENERIC_ENHANCE)))  		return -EFSCORRUPTED; -	trace_f2fs_submit_page_bio(page, fio); +	trace_f2fs_submit_folio_bio(data_folio, fio);  	/* Allocate a new bio */  	bio = __bio_alloc(fio, 1); -	f2fs_set_bio_crypt_ctx(bio, fio->page->mapping->host, -			page_folio(fio->page)->index, fio, GFP_NOIO); - -	if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { -		bio_put(bio); -		return -EFAULT; -	} +	f2fs_set_bio_crypt_ctx(bio, fio_folio->mapping->host, +			fio_folio->index, fio, GFP_NOIO); +	bio_add_folio_nofail(bio, data_folio, folio_size(data_folio), 0);  	if (fio->io_wbc && !is_read_io(fio->op)) -		wbc_account_cgroup_owner(fio->io_wbc, page_folio(fio->page), -					 PAGE_SIZE); +		wbc_account_cgroup_owner(fio->io_wbc, fio_folio, PAGE_SIZE);  	inc_page_count(fio->sbi, is_read_io(fio->op) ? -			__read_io_type(page) : WB_DATA_TYPE(fio->page, false)); +			__read_io_type(data_folio) : WB_DATA_TYPE(fio->page, false));  	if (is_read_io(bio_op(bio)))  		f2fs_submit_read_bio(fio->sbi, bio, fio->type); @@ -894,7 +881,7 @@ int f2fs_merge_page_bio(struct f2fs_io_info *fio)  			__is_meta_io(fio) ? META_GENERIC : DATA_GENERIC))  		return -EFSCORRUPTED; -	trace_f2fs_submit_page_bio(page, fio); +	trace_f2fs_submit_folio_bio(page_folio(page), fio);  	if (bio && !page_is_mergeable(fio->sbi, bio, *fio->last_block,  						fio->new_blkaddr)) @@ -1018,7 +1005,7 @@ alloc_new:  	io->last_block_in_bio = fio->new_blkaddr; -	trace_f2fs_submit_page_write(fio->page, fio); +	trace_f2fs_submit_folio_write(page_folio(fio->page), fio);  #ifdef CONFIG_BLK_DEV_ZONED  	if (f2fs_sb_has_blkzoned(sbi) && btype < META &&  			is_end_zone_blkaddr(sbi, fio->new_blkaddr)) { @@ -1289,7 +1276,7 @@ struct page *f2fs_find_data_page(struct inode *inode, pgoff_t index,  	struct address_space *mapping = inode->i_mapping;  	struct page *page; -	page = find_get_page(mapping, index); +	page = find_get_page_flags(mapping, index, FGP_ACCESSED);  	if (page && PageUptodate(page))  		return page;  	f2fs_put_page(page, 0); @@ -1423,7 +1410,7 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)  		return err;  	if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) -		f2fs_invalidate_internal_cache(sbi, old_blkaddr); +		f2fs_invalidate_internal_cache(sbi, old_blkaddr, 1);  	f2fs_update_data_blkaddr(dn, dn->data_blkaddr);  	return 0; @@ -2464,7 +2451,7 @@ next_page:  static int f2fs_read_data_folio(struct file *file, struct folio *folio)  { -	struct inode *inode = folio_file_mapping(folio)->host; +	struct inode *inode = folio->mapping->host;  	int ret = -EAGAIN;  	trace_f2fs_readpage(folio, DATA); @@ -3163,6 +3150,7 @@ continue_unlock:  				continue;  			}  #endif +			submitted = 0;  			ret = f2fs_write_single_data_page(folio,  					&submitted, &bio, &last_block,  					wbc, io_type, 0, true); diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 47a5c806cf16..54dd52de7269 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -175,7 +175,8 @@ static unsigned long dir_block_index(unsigned int level,  static struct f2fs_dir_entry *find_in_block(struct inode *dir,  				struct page *dentry_page,  				const struct f2fs_filename *fname, -				int *max_slots) +				int *max_slots, +				bool use_hash)  {  	struct f2fs_dentry_block *dentry_blk;  	struct f2fs_dentry_ptr d; @@ -183,7 +184,7 @@ static struct f2fs_dir_entry *find_in_block(struct inode *dir,  	dentry_blk = (struct f2fs_dentry_block *)page_address(dentry_page);  	make_dentry_ptr_block(dir, &d, dentry_blk); -	return f2fs_find_target_dentry(&d, fname, max_slots); +	return f2fs_find_target_dentry(&d, fname, max_slots, use_hash);  }  static inline int f2fs_match_name(const struct inode *dir, @@ -208,7 +209,8 @@ static inline int f2fs_match_name(const struct inode *dir,  }  struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d, -			const struct f2fs_filename *fname, int *max_slots) +			const struct f2fs_filename *fname, int *max_slots, +			bool use_hash)  {  	struct f2fs_dir_entry *de;  	unsigned long bit_pos = 0; @@ -231,7 +233,7 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d,  			continue;  		} -		if (de->hash_code == fname->hash) { +		if (!use_hash || de->hash_code == fname->hash) {  			res = f2fs_match_name(d->inode, fname,  					      d->filename[bit_pos],  					      le16_to_cpu(de->name_len)); @@ -258,11 +260,12 @@ found:  static struct f2fs_dir_entry *find_in_level(struct inode *dir,  					unsigned int level,  					const struct f2fs_filename *fname, -					struct page **res_page) +					struct page **res_page, +					bool use_hash)  {  	int s = GET_DENTRY_SLOTS(fname->disk_name.len);  	unsigned int nbucket, nblock; -	unsigned int bidx, end_block; +	unsigned int bidx, end_block, bucket_no;  	struct page *dentry_page;  	struct f2fs_dir_entry *de = NULL;  	pgoff_t next_pgofs; @@ -272,8 +275,11 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,  	nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level);  	nblock = bucket_blocks(level); +	bucket_no = use_hash ? le32_to_cpu(fname->hash) % nbucket : 0; + +start_find_bucket:  	bidx = dir_block_index(level, F2FS_I(dir)->i_dir_level, -			       le32_to_cpu(fname->hash) % nbucket); +			       bucket_no);  	end_block = bidx + nblock;  	while (bidx < end_block) { @@ -290,7 +296,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,  			}  		} -		de = find_in_block(dir, dentry_page, fname, &max_slots); +		de = find_in_block(dir, dentry_page, fname, &max_slots, use_hash);  		if (IS_ERR(de)) {  			*res_page = ERR_CAST(de);  			de = NULL; @@ -307,12 +313,18 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,  		bidx++;  	} -	if (!de && room && F2FS_I(dir)->chash != fname->hash) { -		F2FS_I(dir)->chash = fname->hash; -		F2FS_I(dir)->clevel = level; -	} +	if (de) +		return de; -	return de; +	if (likely(use_hash)) { +		if (room && F2FS_I(dir)->chash != fname->hash) { +			F2FS_I(dir)->chash = fname->hash; +			F2FS_I(dir)->clevel = level; +		} +	} else if (++bucket_no < nbucket) { +		goto start_find_bucket; +	} +	return NULL;  }  struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir, @@ -323,11 +335,15 @@ struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir,  	struct f2fs_dir_entry *de = NULL;  	unsigned int max_depth;  	unsigned int level; +	bool use_hash = true;  	*res_page = NULL; +#if IS_ENABLED(CONFIG_UNICODE) +start_find_entry: +#endif  	if (f2fs_has_inline_dentry(dir)) { -		de = f2fs_find_in_inline_dir(dir, fname, res_page); +		de = f2fs_find_in_inline_dir(dir, fname, res_page, use_hash);  		goto out;  	} @@ -343,11 +359,18 @@ struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir,  	}  	for (level = 0; level < max_depth; level++) { -		de = find_in_level(dir, level, fname, res_page); +		de = find_in_level(dir, level, fname, res_page, use_hash);  		if (de || IS_ERR(*res_page))  			break;  	} +  out: +#if IS_ENABLED(CONFIG_UNICODE) +	if (IS_CASEFOLDED(dir) && !de && use_hash) { +		use_hash = false; +		goto start_find_entry; +	} +#endif  	/* This is to increase the speed of f2fs_create */  	if (!de)  		F2FS_I(dir)->task = current; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index fd7e9cb6f893..1afa7be16e7d 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1985,9 +1985,14 @@ static inline struct f2fs_sb_info *F2FS_M_SB(struct address_space *mapping)  	return F2FS_I_SB(mapping->host);  } +static inline struct f2fs_sb_info *F2FS_F_SB(struct folio *folio) +{ +	return F2FS_M_SB(folio->mapping); +} +  static inline struct f2fs_sb_info *F2FS_P_SB(struct page *page)  { -	return F2FS_M_SB(page_file_mapping(page)); +	return F2FS_F_SB(page_folio(page));  }  static inline struct f2fs_super_block *F2FS_RAW_SUPER(struct f2fs_sb_info *sbi) @@ -3565,7 +3570,8 @@ int f2fs_prepare_lookup(struct inode *dir, struct dentry *dentry,  			struct f2fs_filename *fname);  void f2fs_free_filename(struct f2fs_filename *fname);  struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d, -			const struct f2fs_filename *fname, int *max_slots); +			const struct f2fs_filename *fname, int *max_slots, +			bool use_hash);  int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,  			unsigned int start_pos, struct fscrypt_str *fstr);  void f2fs_do_make_empty_dir(struct inode *inode, struct inode *parent, @@ -3700,7 +3706,8 @@ int f2fs_issue_flush(struct f2fs_sb_info *sbi, nid_t ino);  int f2fs_create_flush_cmd_control(struct f2fs_sb_info *sbi);  int f2fs_flush_device_cache(struct f2fs_sb_info *sbi);  void f2fs_destroy_flush_cmd_control(struct f2fs_sb_info *sbi, bool free); -void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr); +void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr, +						unsigned int len);  bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr);  int f2fs_start_discard_thread(struct f2fs_sb_info *sbi);  void f2fs_drop_discard_cmd(struct f2fs_sb_info *sbi); @@ -4201,7 +4208,8 @@ int f2fs_write_inline_data(struct inode *inode, struct folio *folio);  int f2fs_recover_inline_data(struct inode *inode, struct page *npage);  struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir,  					const struct f2fs_filename *fname, -					struct page **res_page); +					struct page **res_page, +					bool use_hash);  int f2fs_make_empty_inline_dir(struct inode *inode, struct inode *parent,  			struct page *ipage);  int f2fs_add_inline_entry(struct inode *dir, const struct f2fs_filename *fname, @@ -4368,7 +4376,8 @@ void f2fs_destroy_page_array_cache(struct f2fs_sb_info *sbi);  int __init f2fs_init_compress_cache(void);  void f2fs_destroy_compress_cache(void);  struct address_space *COMPRESS_MAPPING(struct f2fs_sb_info *sbi); -void f2fs_invalidate_compress_page(struct f2fs_sb_info *sbi, block_t blkaddr); +void f2fs_invalidate_compress_pages_range(struct f2fs_sb_info *sbi, +					block_t blkaddr, unsigned int len);  void f2fs_cache_compressed_page(struct f2fs_sb_info *sbi, struct page *page,  						nid_t ino, block_t blkaddr);  bool f2fs_load_compressed_page(struct f2fs_sb_info *sbi, struct page *page, @@ -4423,8 +4432,8 @@ static inline int f2fs_init_page_array_cache(struct f2fs_sb_info *sbi) { return  static inline void f2fs_destroy_page_array_cache(struct f2fs_sb_info *sbi) { }  static inline int __init f2fs_init_compress_cache(void) { return 0; }  static inline void f2fs_destroy_compress_cache(void) { } -static inline void f2fs_invalidate_compress_page(struct f2fs_sb_info *sbi, -				block_t blkaddr) { } +static inline void f2fs_invalidate_compress_pages_range(struct f2fs_sb_info *sbi, +				block_t blkaddr, unsigned int len) { }  static inline void f2fs_cache_compressed_page(struct f2fs_sb_info *sbi,  				struct page *page, nid_t ino, block_t blkaddr) { }  static inline bool f2fs_load_compressed_page(struct f2fs_sb_info *sbi, @@ -4740,10 +4749,10 @@ static inline void f2fs_truncate_meta_inode_pages(struct f2fs_sb_info *sbi,  }  static inline void f2fs_invalidate_internal_cache(struct f2fs_sb_info *sbi, -								block_t blkaddr) +						block_t blkaddr, unsigned int len)  { -	f2fs_truncate_meta_inode_pages(sbi, blkaddr, 1); -	f2fs_invalidate_compress_page(sbi, blkaddr); +	f2fs_truncate_meta_inode_pages(sbi, blkaddr, len); +	f2fs_invalidate_compress_pages_range(sbi, blkaddr, len);  }  #define EFSBADCRC	EBADMSG		/* Bad CRC detected */ diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index aa9679b3d8e4..f92a9fba9991 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -621,8 +621,11 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)  	int cluster_index = 0, valid_blocks = 0;  	int cluster_size = F2FS_I(dn->inode)->i_cluster_size;  	bool released = !atomic_read(&F2FS_I(dn->inode)->i_compr_blocks); +	block_t blkstart; +	int blklen = 0;  	addr = get_dnode_addr(dn->inode, dn->node_page) + ofs; +	blkstart = le32_to_cpu(*addr);  	/* Assumption: truncation starts with cluster */  	for (; count > 0; count--, addr++, dn->ofs_in_node++, cluster_index++) { @@ -638,26 +641,44 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)  		}  		if (blkaddr == NULL_ADDR) -			continue; +			goto next;  		f2fs_set_data_blkaddr(dn, NULL_ADDR);  		if (__is_valid_data_blkaddr(blkaddr)) {  			if (time_to_inject(sbi, FAULT_BLKADDR_CONSISTENCE)) -				continue; +				goto next;  			if (!f2fs_is_valid_blkaddr_raw(sbi, blkaddr,  						DATA_GENERIC_ENHANCE)) -				continue; +				goto next;  			if (compressed_cluster)  				valid_blocks++;  		} -		f2fs_invalidate_blocks(sbi, blkaddr); +		if (blkstart + blklen == blkaddr) { +			blklen++; +		} else { +			f2fs_invalidate_blocks(sbi, blkstart, blklen); +			blkstart = blkaddr; +			blklen = 1; +		}  		if (!released || blkaddr != COMPRESS_ADDR)  			nr_free++; + +		continue; + +next: +		if (blklen) +			f2fs_invalidate_blocks(sbi, blkstart, blklen); + +		blkstart = le32_to_cpu(*(addr + 1)); +		blklen = 0;  	} +	if (blklen) +		f2fs_invalidate_blocks(sbi, blkstart, blklen); +  	if (compressed_cluster)  		f2fs_i_compr_blocks_update(dn->inode, valid_blocks, false); @@ -747,10 +768,8 @@ int f2fs_do_truncate_blocks(struct inode *inode, u64 from, bool lock)  	if (IS_DEVICE_ALIASING(inode)) {  		struct extent_tree *et = F2FS_I(inode)->extent_tree[EX_READ];  		struct extent_info ei = et->largest; -		unsigned int i; -		for (i = 0; i < ei.len; i++) -			f2fs_invalidate_blocks(sbi, ei.blk + i); +		f2fs_invalidate_blocks(sbi, ei.blk, ei.len);  		dec_valid_block_count(sbi, inode, ei.len);  		f2fs_update_time(sbi, REQ_TIME); @@ -1323,7 +1342,7 @@ static int __roll_back_blkaddrs(struct inode *inode, block_t *blkaddr,  		ret = f2fs_get_dnode_of_data(&dn, off + i, LOOKUP_NODE_RA);  		if (ret) {  			dec_valid_block_count(sbi, inode, 1); -			f2fs_invalidate_blocks(sbi, *blkaddr); +			f2fs_invalidate_blocks(sbi, *blkaddr, 1);  		} else {  			f2fs_update_data_blkaddr(&dn, *blkaddr);  		} @@ -1575,7 +1594,7 @@ static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start,  			break;  		} -		f2fs_invalidate_blocks(sbi, dn->data_blkaddr); +		f2fs_invalidate_blocks(sbi, dn->data_blkaddr, 1);  		f2fs_set_data_blkaddr(dn, NEW_ADDR);  	} diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 3e1b6d2ff3a7..faf9fa1c804d 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -806,11 +806,14 @@ retry:  			goto out;  		} -		if (sec_usage_check(sbi, GET_SEC_FROM_SEG(sbi, *result))) +		if (sec_usage_check(sbi, GET_SEC_FROM_SEG(sbi, *result))) {  			ret = -EBUSY; -		else -			p.min_segno = *result; -		goto out; +			goto out; +		} +		if (gc_type == FG_GC) +			clear_bit(GET_SEC_FROM_SEG(sbi, *result), dirty_i->victim_secmap); +		p.min_segno = *result; +		goto got_result;  	}  	ret = -ENODATA; @@ -1412,7 +1415,7 @@ static int move_data_block(struct inode *inode, block_t bidx,  				page_address(mpage), PAGE_SIZE);  	f2fs_put_page(mpage, 1); -	f2fs_invalidate_internal_cache(fio.sbi, fio.old_blkaddr); +	f2fs_invalidate_internal_cache(fio.sbi, fio.old_blkaddr, 1);  	set_page_dirty(fio.encrypted_page);  	if (clear_page_dirty_for_io(fio.encrypted_page)) diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 005babf1bed1..3e3c35d4c98b 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -81,7 +81,7 @@ bool f2fs_may_inline_dentry(struct inode *inode)  void f2fs_do_read_inline_data(struct folio *folio, struct page *ipage)  { -	struct inode *inode = folio_file_mapping(folio)->host; +	struct inode *inode = folio->mapping->host;  	if (folio_test_uptodate(folio))  		return; @@ -352,7 +352,8 @@ process_inline:  struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir,  					const struct f2fs_filename *fname, -					struct page **res_page) +					struct page **res_page, +					bool use_hash)  {  	struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);  	struct f2fs_dir_entry *de; @@ -369,7 +370,7 @@ struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir,  	inline_dentry = inline_data_addr(dir, ipage);  	make_dentry_ptr_inline(dir, &d, inline_dentry); -	de = f2fs_find_target_dentry(&d, fname, NULL); +	de = f2fs_find_target_dentry(&d, fname, NULL, use_hash);  	unlock_page(ipage);  	if (IS_ERR(de)) {  		*res_page = ERR_CAST(de); diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 282fd320bdb3..3dd25f64d6f1 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -302,15 +302,6 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page)  				  F2FS_TOTAL_EXTRA_ATTR_SIZE);  			return false;  		} -		if (f2fs_sb_has_flexible_inline_xattr(sbi) && -			f2fs_has_inline_xattr(inode) && -			(!fi->i_inline_xattr_size || -			fi->i_inline_xattr_size > MAX_INLINE_XATTR_SIZE)) { -			f2fs_warn(sbi, "%s: inode (ino=%lx) has corrupted i_inline_xattr_size: %d, max: %lu", -				  __func__, inode->i_ino, fi->i_inline_xattr_size, -				  MAX_INLINE_XATTR_SIZE); -			return false; -		}  		if (f2fs_sb_has_compression(sbi) &&  			fi->i_flags & F2FS_COMPR_FL &&  			F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, @@ -320,6 +311,16 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page)  		}  	} +	if (f2fs_sb_has_flexible_inline_xattr(sbi) && +		f2fs_has_inline_xattr(inode) && +		(fi->i_inline_xattr_size < MIN_INLINE_XATTR_SIZE || +		fi->i_inline_xattr_size > MAX_INLINE_XATTR_SIZE)) { +		f2fs_warn(sbi, "%s: inode (ino=%lx) has corrupted i_inline_xattr_size: %d, min: %zu, max: %lu", +			  __func__, inode->i_ino, fi->i_inline_xattr_size, +			  MIN_INLINE_XATTR_SIZE, MAX_INLINE_XATTR_SIZE); +		return false; +	} +  	if (!f2fs_sb_has_extra_attr(sbi)) {  		if (f2fs_sb_has_project_quota(sbi)) {  			f2fs_warn(sbi, "%s: corrupted inode ino=%lx, wrong feature flag: %u, run fsck to fix.", diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 57d46e1439de..a278c7da8177 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -341,6 +341,7 @@ fail_drop:  	trace_f2fs_new_inode(inode, err);  	dquot_drop(inode);  	inode->i_flags |= S_NOQUOTA; +	make_bad_inode(inode);  	if (nid_free)  		set_inode_flag(inode, FI_FREE_NID);  	clear_nlink(inode); diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 0b900a7a48e5..f88392fc4ba9 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -558,6 +558,7 @@ int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,  	block_t blkaddr;  	int i; +	ni->flag = 0;  	ni->nid = nid;  retry:  	/* Check nat cache */ @@ -916,7 +917,7 @@ static int truncate_node(struct dnode_of_data *dn)  	}  	/* Deallocate node address */ -	f2fs_invalidate_blocks(sbi, ni.blk_addr); +	f2fs_invalidate_blocks(sbi, ni.blk_addr, 1);  	dec_valid_node_count(sbi, dn->inode, dn->nid == dn->inode->i_ino);  	set_node_addr(sbi, &ni, NULL_ADDR, false); @@ -1274,8 +1275,9 @@ int f2fs_remove_inode_page(struct inode *inode)  	}  	/* remove potential inline_data blocks */ -	if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || -				S_ISLNK(inode->i_mode)) +	if (!IS_DEVICE_ALIASING(inode) && +	    (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || +	     S_ISLNK(inode->i_mode)))  		f2fs_truncate_data_blocks_range(&dn, 1);  	/* 0 is possible, after f2fs_new_inode() has failed */ @@ -2763,7 +2765,7 @@ int f2fs_recover_xattr_data(struct inode *inode, struct page *page)  	if (err)  		return err; -	f2fs_invalidate_blocks(sbi, ni.blk_addr); +	f2fs_invalidate_blocks(sbi, ni.blk_addr, 1);  	dec_valid_node_count(sbi, inode, false);  	set_node_addr(sbi, &ni, NULL_ADDR, false); diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index f35be2c48e3c..69a2027e3ebc 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -899,10 +899,8 @@ skip:  	 * and the f2fs is not read only, check and fix zoned block devices'  	 * write pointer consistency.  	 */ -	if (!err) { +	if (!err)  		err = f2fs_check_and_fix_write_pointer(sbi); -		ret = err; -	}  	if (!err)  		clear_sbi_flag(sbi, SBI_POR_DOING); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index eade36c5ef13..c282e8a0a2ec 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -201,6 +201,12 @@ void f2fs_abort_atomic_write(struct inode *inode, bool clean)  	clear_inode_flag(inode, FI_ATOMIC_FILE);  	if (is_inode_flag_set(inode, FI_ATOMIC_DIRTIED)) {  		clear_inode_flag(inode, FI_ATOMIC_DIRTIED); +		/* +		 * The vfs inode keeps clean during commit, but the f2fs inode +		 * doesn't. So clear the dirty state after commit and let +		 * f2fs_mark_inode_dirty_sync ensure a consistent dirty state. +		 */ +		f2fs_inode_synced(inode);  		f2fs_mark_inode_dirty_sync(inode, true);  	}  	stat_dec_atomic_inode(inode); @@ -245,7 +251,7 @@ retry:  		if (!__is_valid_data_blkaddr(new_addr)) {  			if (new_addr == NULL_ADDR)  				dec_valid_block_count(sbi, inode, 1); -			f2fs_invalidate_blocks(sbi, dn.data_blkaddr); +			f2fs_invalidate_blocks(sbi, dn.data_blkaddr, 1);  			f2fs_update_data_blkaddr(&dn, new_addr);  		} else {  			f2fs_replace_block(sbi, &dn, dn.data_blkaddr, @@ -2426,78 +2432,38 @@ static void update_segment_mtime(struct f2fs_sb_info *sbi, block_t blkaddr,  		SIT_I(sbi)->max_mtime = ctime;  } -static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) +/* + * NOTE: when updating multiple blocks at the same time, please ensure + * that the consecutive input blocks belong to the same segment. + */ +static int update_sit_entry_for_release(struct f2fs_sb_info *sbi, struct seg_entry *se, +				block_t blkaddr, unsigned int offset, int del)  { -	struct seg_entry *se; -	unsigned int segno, offset; -	long int new_vblocks;  	bool exist;  #ifdef CONFIG_F2FS_CHECK_FS  	bool mir_exist;  #endif +	int i; +	int del_count = -del; -	segno = GET_SEGNO(sbi, blkaddr); -	if (segno == NULL_SEGNO) -		return; - -	se = get_seg_entry(sbi, segno); -	new_vblocks = se->valid_blocks + del; -	offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr); - -	f2fs_bug_on(sbi, (new_vblocks < 0 || -			(new_vblocks > f2fs_usable_blks_in_seg(sbi, segno)))); - -	se->valid_blocks = new_vblocks; - -	/* Update valid block bitmap */ -	if (del > 0) { -		exist = f2fs_test_and_set_bit(offset, se->cur_valid_map); -#ifdef CONFIG_F2FS_CHECK_FS -		mir_exist = f2fs_test_and_set_bit(offset, -						se->cur_valid_map_mir); -		if (unlikely(exist != mir_exist)) { -			f2fs_err(sbi, "Inconsistent error when setting bitmap, blk:%u, old bit:%d", -				 blkaddr, exist); -			f2fs_bug_on(sbi, 1); -		} -#endif -		if (unlikely(exist)) { -			f2fs_err(sbi, "Bitmap was wrongly set, blk:%u", -				 blkaddr); -			f2fs_bug_on(sbi, 1); -			se->valid_blocks--; -			del = 0; -		} - -		if (f2fs_block_unit_discard(sbi) && -				!f2fs_test_and_set_bit(offset, se->discard_map)) -			sbi->discard_blks--; +	f2fs_bug_on(sbi, GET_SEGNO(sbi, blkaddr) != GET_SEGNO(sbi, blkaddr + del_count - 1)); -		/* -		 * SSR should never reuse block which is checkpointed -		 * or newly invalidated. -		 */ -		if (!is_sbi_flag_set(sbi, SBI_CP_DISABLED)) { -			if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map)) -				se->ckpt_valid_blocks++; -		} -	} else { -		exist = f2fs_test_and_clear_bit(offset, se->cur_valid_map); +	for (i = 0; i < del_count; i++) { +		exist = f2fs_test_and_clear_bit(offset + i, se->cur_valid_map);  #ifdef CONFIG_F2FS_CHECK_FS -		mir_exist = f2fs_test_and_clear_bit(offset, +		mir_exist = f2fs_test_and_clear_bit(offset + i,  						se->cur_valid_map_mir);  		if (unlikely(exist != mir_exist)) {  			f2fs_err(sbi, "Inconsistent error when clearing bitmap, blk:%u, old bit:%d", -				 blkaddr, exist); +				blkaddr + i, exist);  			f2fs_bug_on(sbi, 1);  		}  #endif  		if (unlikely(!exist)) { -			f2fs_err(sbi, "Bitmap was wrongly cleared, blk:%u", -				 blkaddr); +			f2fs_err(sbi, "Bitmap was wrongly cleared, blk:%u", blkaddr + i);  			f2fs_bug_on(sbi, 1);  			se->valid_blocks++; -			del = 0; +			del += 1;  		} else if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {  			/*  			 * If checkpoints are off, we must not reuse data that @@ -2505,7 +2471,7 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)  			 * before, we must track that to know how much space we  			 * really have.  			 */ -			if (f2fs_test_bit(offset, se->ckpt_valid_map)) { +			if (f2fs_test_bit(offset + i, se->ckpt_valid_map)) {  				spin_lock(&sbi->stat_lock);  				sbi->unusable_block_count++;  				spin_unlock(&sbi->stat_lock); @@ -2513,12 +2479,91 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)  		}  		if (f2fs_block_unit_discard(sbi) && -			f2fs_test_and_clear_bit(offset, se->discard_map)) +				f2fs_test_and_clear_bit(offset + i, se->discard_map))  			sbi->discard_blks++; + +		if (!f2fs_test_bit(offset + i, se->ckpt_valid_map)) +			se->ckpt_valid_blocks -= 1; +	} + +	return del; +} + +static int update_sit_entry_for_alloc(struct f2fs_sb_info *sbi, struct seg_entry *se, +				block_t blkaddr, unsigned int offset, int del) +{ +	bool exist; +#ifdef CONFIG_F2FS_CHECK_FS +	bool mir_exist; +#endif + +	exist = f2fs_test_and_set_bit(offset, se->cur_valid_map); +#ifdef CONFIG_F2FS_CHECK_FS +	mir_exist = f2fs_test_and_set_bit(offset, +					se->cur_valid_map_mir); +	if (unlikely(exist != mir_exist)) { +		f2fs_err(sbi, "Inconsistent error when setting bitmap, blk:%u, old bit:%d", +			blkaddr, exist); +		f2fs_bug_on(sbi, 1);  	} +#endif +	if (unlikely(exist)) { +		f2fs_err(sbi, "Bitmap was wrongly set, blk:%u", blkaddr); +		f2fs_bug_on(sbi, 1); +		se->valid_blocks--; +		del = 0; +	} + +	if (f2fs_block_unit_discard(sbi) && +			!f2fs_test_and_set_bit(offset, se->discard_map)) +		sbi->discard_blks--; + +	/* +	 * SSR should never reuse block which is checkpointed +	 * or newly invalidated. +	 */ +	if (!is_sbi_flag_set(sbi, SBI_CP_DISABLED)) { +		if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map)) +			se->ckpt_valid_blocks++; +	} +  	if (!f2fs_test_bit(offset, se->ckpt_valid_map))  		se->ckpt_valid_blocks += del; +	return del; +} + +/* + * If releasing blocks, this function supports updating multiple consecutive blocks + * at one time, but please note that these consecutive blocks need to belong to the + * same segment. + */ +static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) +{ +	struct seg_entry *se; +	unsigned int segno, offset; +	long int new_vblocks; + +	segno = GET_SEGNO(sbi, blkaddr); +	if (segno == NULL_SEGNO) +		return; + +	se = get_seg_entry(sbi, segno); +	new_vblocks = se->valid_blocks + del; +	offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr); + +	f2fs_bug_on(sbi, (new_vblocks < 0 || +			(new_vblocks > f2fs_usable_blks_in_seg(sbi, segno)))); + +	se->valid_blocks = new_vblocks; + +	/* Update valid block bitmap */ +	if (del > 0) { +		del = update_sit_entry_for_alloc(sbi, se, blkaddr, offset, del); +	} else { +		del = update_sit_entry_for_release(sbi, se, blkaddr, offset, del); +	} +  	__mark_sit_entry_dirty(sbi, segno);  	/* update total number of valid blocks to be written in ckpt area */ @@ -2528,25 +2573,43 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)  		get_sec_entry(sbi, segno)->valid_blocks += del;  } -void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr) +void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr, +				unsigned int len)  {  	unsigned int segno = GET_SEGNO(sbi, addr);  	struct sit_info *sit_i = SIT_I(sbi); +	block_t addr_start = addr, addr_end = addr + len - 1; +	unsigned int seg_num = GET_SEGNO(sbi, addr_end) - segno + 1; +	unsigned int i = 1, max_blocks = sbi->blocks_per_seg, cnt;  	f2fs_bug_on(sbi, addr == NULL_ADDR);  	if (addr == NEW_ADDR || addr == COMPRESS_ADDR)  		return; -	f2fs_invalidate_internal_cache(sbi, addr); +	f2fs_invalidate_internal_cache(sbi, addr, len);  	/* add it into sit main buffer */  	down_write(&sit_i->sentry_lock); -	update_segment_mtime(sbi, addr, 0); -	update_sit_entry(sbi, addr, -1); +	if (seg_num == 1) +		cnt = len; +	else +		cnt = max_blocks - GET_BLKOFF_FROM_SEG0(sbi, addr); + +	do { +		update_segment_mtime(sbi, addr_start, 0); +		update_sit_entry(sbi, addr_start, -cnt); -	/* add it into dirty seglist */ -	locate_dirty_segment(sbi, segno); +		/* add it into dirty seglist */ +		locate_dirty_segment(sbi, segno); + +		/* update @addr_start and @cnt and @segno */ +		addr_start = START_BLOCK(sbi, ++segno); +		if (++i == seg_num) +			cnt = GET_BLKOFF_FROM_SEG0(sbi, addr_end) + 1; +		else +			cnt = max_blocks; +	} while (i <= seg_num);  	up_write(&sit_i->sentry_lock);  } @@ -3857,7 +3920,7 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)  		goto out;  	}  	if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO) -		f2fs_invalidate_internal_cache(fio->sbi, fio->old_blkaddr); +		f2fs_invalidate_internal_cache(fio->sbi, fio->old_blkaddr, 1);  	/* writeout dirty page into bdev */  	f2fs_submit_page_write(fio); @@ -4049,7 +4112,7 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,  		update_sit_entry(sbi, new_blkaddr, 1);  	}  	if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) { -		f2fs_invalidate_internal_cache(sbi, old_blkaddr); +		f2fs_invalidate_internal_cache(sbi, old_blkaddr, 1);  		if (!from_gc)  			update_segment_mtime(sbi, old_blkaddr, 0);  		update_sit_entry(sbi, old_blkaddr, -1); @@ -5405,7 +5468,8 @@ int f2fs_check_and_fix_write_pointer(struct f2fs_sb_info *sbi)  {  	int ret; -	if (!f2fs_sb_has_blkzoned(sbi) || f2fs_readonly(sbi->sb)) +	if (!f2fs_sb_has_blkzoned(sbi) || f2fs_readonly(sbi->sb) || +	    f2fs_hw_is_readonly(sbi))  		return 0;  	f2fs_notice(sbi, "Checking entire write pointers"); @@ -5492,8 +5556,10 @@ unsigned long long f2fs_get_section_mtime(struct f2fs_sb_info *sbi,  	secno = GET_SEC_FROM_SEG(sbi, segno);  	start = GET_SEG_FROM_SEC(sbi, secno); -	if (!__is_large_section(sbi)) -		return get_seg_entry(sbi, start + i)->mtime; +	if (!__is_large_section(sbi)) { +		mtime = get_seg_entry(sbi, start + i)->mtime; +		goto out; +	}  	for (i = 0; i < usable_segs_per_sec; i++) {  		/* for large section, only check the mtime of valid segments */ @@ -5506,7 +5572,11 @@ unsigned long long f2fs_get_section_mtime(struct f2fs_sb_info *sbi,  	if (total_valid_blocks == 0)  		return INVALID_MTIME; -	return div_u64(mtime, total_valid_blocks); +	mtime = div_u64(mtime, total_valid_blocks); +out: +	if (unlikely(mtime == INVALID_MTIME)) +		mtime -= 1; +	return mtime;  }  /* diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 6b99dc49f776..d15c68b28952 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -1472,7 +1472,7 @@ static int __maybe_unused segment_bits_seq_show(struct seq_file *seq,  			le32_to_cpu(sbi->raw_super->segment_count_main);  	int i, j; -	seq_puts(seq, "format: segment_type|valid_blocks|bitmaps\n" +	seq_puts(seq, "format: segment_type|valid_blocks|bitmaps|mtime\n"  		"segment_type(0:HD, 1:WD, 2:CD, 3:HN, 4:WN, 5:CN)\n");  	for (i = 0; i < total_segs; i++) { @@ -1482,6 +1482,7 @@ static int __maybe_unused segment_bits_seq_show(struct seq_file *seq,  		seq_printf(seq, "%d|%-3u|", se->type, se->valid_blocks);  		for (j = 0; j < SIT_VBLOCK_MAP_SIZE; j++)  			seq_printf(seq, " %.2x", se->cur_valid_map[j]); +		seq_printf(seq, "| %llx", se->mtime);  		seq_putc(seq, '\n');  	}  	return 0; diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 2851c823095b..eb3b2f1326b1 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -1119,11 +1119,11 @@ TRACE_EVENT(f2fs_reserve_new_blocks,  		(unsigned long long)__entry->count)  ); -DECLARE_EVENT_CLASS(f2fs__submit_page_bio, +DECLARE_EVENT_CLASS(f2fs__submit_folio_bio, -	TP_PROTO(struct page *page, struct f2fs_io_info *fio), +	TP_PROTO(struct folio *folio, struct f2fs_io_info *fio), -	TP_ARGS(page, fio), +	TP_ARGS(folio, fio),  	TP_STRUCT__entry(  		__field(dev_t, dev) @@ -1138,9 +1138,9 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,  	),  	TP_fast_assign( -		__entry->dev		= page_file_mapping(page)->host->i_sb->s_dev; -		__entry->ino		= page_file_mapping(page)->host->i_ino; -		__entry->index		= page->index; +		__entry->dev		= folio->mapping->host->i_sb->s_dev; +		__entry->ino		= folio->mapping->host->i_ino; +		__entry->index		= folio->index;  		__entry->old_blkaddr	= fio->old_blkaddr;  		__entry->new_blkaddr	= fio->new_blkaddr;  		__entry->op		= fio->op; @@ -1149,7 +1149,7 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,  		__entry->type		= fio->type;  	), -	TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, " +	TP_printk("dev = (%d,%d), ino = %lu, folio_index = 0x%lx, "  		"oldaddr = 0x%llx, newaddr = 0x%llx, rw = %s(%s), type = %s_%s",  		show_dev_ino(__entry),  		(unsigned long)__entry->index, @@ -1160,22 +1160,22 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,  		show_block_type(__entry->type))  ); -DEFINE_EVENT_CONDITION(f2fs__submit_page_bio, f2fs_submit_page_bio, +DEFINE_EVENT_CONDITION(f2fs__submit_folio_bio, f2fs_submit_folio_bio, -	TP_PROTO(struct page *page, struct f2fs_io_info *fio), +	TP_PROTO(struct folio *folio, struct f2fs_io_info *fio), -	TP_ARGS(page, fio), +	TP_ARGS(folio, fio), -	TP_CONDITION(page->mapping) +	TP_CONDITION(folio->mapping)  ); -DEFINE_EVENT_CONDITION(f2fs__submit_page_bio, f2fs_submit_page_write, +DEFINE_EVENT_CONDITION(f2fs__submit_folio_bio, f2fs_submit_folio_write, -	TP_PROTO(struct page *page, struct f2fs_io_info *fio), +	TP_PROTO(struct folio *folio, struct f2fs_io_info *fio), -	TP_ARGS(page, fio), +	TP_ARGS(folio, fio), -	TP_CONDITION(page->mapping) +	TP_CONDITION(folio->mapping)  );  DECLARE_EVENT_CLASS(f2fs__bio, @@ -1322,12 +1322,11 @@ DECLARE_EVENT_CLASS(f2fs__folio,  	),  	TP_fast_assign( -		__entry->dev	= folio_file_mapping(folio)->host->i_sb->s_dev; -		__entry->ino	= folio_file_mapping(folio)->host->i_ino; +		__entry->dev	= folio->mapping->host->i_sb->s_dev; +		__entry->ino	= folio->mapping->host->i_ino;  		__entry->type	= type; -		__entry->dir	= -			S_ISDIR(folio_file_mapping(folio)->host->i_mode); -		__entry->index	= folio_index(folio); +		__entry->dir	= S_ISDIR(folio->mapping->host->i_mode); +		__entry->index	= folio->index;  		__entry->dirty	= folio_test_dirty(folio);  		__entry->uptodate = folio_test_uptodate(folio);  	), | 
