f2fs: Add f2fs stats to sysfs
Currently f2fs stats are only available from /d/f2fs/status. This patch adds some of the f2fs stats to sysfs so that they are accessible even when debugfs is not mounted. The following sysfs nodes are added: -/sys/fs/f2fs/<disk>/free_segments -/sys/fs/f2fs/<disk>/cp_foreground_calls -/sys/fs/f2fs/<disk>/cp_background_calls -/sys/fs/f2fs/<disk>/gc_foreground_calls -/sys/fs/f2fs/<disk>/gc_background_calls -/sys/fs/f2fs/<disk>/moved_blocks_foreground -/sys/fs/f2fs/<disk>/moved_blocks_background -/sys/fs/f2fs/<disk>/avg_vblocks Signed-off-by: Hridya Valsaraju <hridya@google.com> [Jaegeuk Kim: allow STAT_FS without DEBUG_FS] Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
		
							parent
							
								
									f5fa7c8bb6
								
							
						
					
					
						commit
						fc7100ea2a
					
				| @ -271,3 +271,50 @@ Date		July 2019 | |||||||
| Contact:	"Daniel Rosenberg" <drosen@google.com> | Contact:	"Daniel Rosenberg" <drosen@google.com> | ||||||
| Description:	Displays name and version of the encoding set for the filesystem. | Description:	Displays name and version of the encoding set for the filesystem. | ||||||
| 		If no encoding is set, displays (none) | 		If no encoding is set, displays (none) | ||||||
|  | 
 | ||||||
|  | What:		/sys/fs/f2fs/<disk>/free_segments | ||||||
|  | Date:		September 2019 | ||||||
|  | Contact:	"Hridya Valsaraju" <hridya@google.com> | ||||||
|  | Description:	Number of free segments in disk. | ||||||
|  | 
 | ||||||
|  | What:		/sys/fs/f2fs/<disk>/cp_foreground_calls | ||||||
|  | Date:		September 2019 | ||||||
|  | Contact:	"Hridya Valsaraju" <hridya@google.com> | ||||||
|  | Description:	Number of checkpoint operations performed on demand. Available when | ||||||
|  | 		CONFIG_F2FS_STAT_FS=y. | ||||||
|  | 
 | ||||||
|  | What:		/sys/fs/f2fs/<disk>/cp_background_calls | ||||||
|  | Date:		September 2019 | ||||||
|  | Contact:	"Hridya Valsaraju" <hridya@google.com> | ||||||
|  | Description:	Number of checkpoint operations performed in the background to | ||||||
|  | 		free segments. Available when CONFIG_F2FS_STAT_FS=y. | ||||||
|  | 
 | ||||||
|  | What:		/sys/fs/f2fs/<disk>/gc_foreground_calls | ||||||
|  | Date:		September 2019 | ||||||
|  | Contact:	"Hridya Valsaraju" <hridya@google.com> | ||||||
|  | Description:	Number of garbage collection operations performed on demand. | ||||||
|  | 		Available when CONFIG_F2FS_STAT_FS=y. | ||||||
|  | 
 | ||||||
|  | What:		/sys/fs/f2fs/<disk>/gc_background_calls | ||||||
|  | Date:		September 2019 | ||||||
|  | Contact:	"Hridya Valsaraju" <hridya@google.com> | ||||||
|  | Description:	Number of garbage collection operations triggered in background. | ||||||
|  | 		Available when CONFIG_F2FS_STAT_FS=y. | ||||||
|  | 
 | ||||||
|  | What:		/sys/fs/f2fs/<disk>/moved_blocks_foreground | ||||||
|  | Date:		September 2019 | ||||||
|  | Contact:	"Hridya Valsaraju" <hridya@google.com> | ||||||
|  | Description:	Number of blocks moved by garbage collection in foreground. | ||||||
|  | 		Available when CONFIG_F2FS_STAT_FS=y. | ||||||
|  | 
 | ||||||
|  | What:		/sys/fs/f2fs/<disk>/moved_blocks_background | ||||||
|  | Date:		September 2019 | ||||||
|  | Contact:	"Hridya Valsaraju" <hridya@google.com> | ||||||
|  | Description:	Number of blocks moved by garbage collection in background. | ||||||
|  | 		Available when CONFIG_F2FS_STAT_FS=y. | ||||||
|  | 
 | ||||||
|  | What:		/sys/fs/f2fs/<disk>/avg_vblocks | ||||||
|  | Date:		September 2019 | ||||||
|  | Contact:	"Hridya Valsaraju" <hridya@google.com> | ||||||
|  | Description:	Average number of valid blocks. | ||||||
|  | 		Available when CONFIG_F2FS_STAT_FS=y. | ||||||
|  | |||||||
| @ -21,7 +21,7 @@ config F2FS_FS | |||||||
| 
 | 
 | ||||||
| config F2FS_STAT_FS | config F2FS_STAT_FS | ||||||
| 	bool "F2FS Status Information" | 	bool "F2FS Status Information" | ||||||
| 	depends on F2FS_FS && DEBUG_FS | 	depends on F2FS_FS | ||||||
| 	default y | 	default y | ||||||
| 	help | 	help | ||||||
| 	  /sys/kernel/debug/f2fs/ contains information about all the partitions | 	  /sys/kernel/debug/f2fs/ contains information about all the partitions | ||||||
|  | |||||||
| @ -21,9 +21,45 @@ | |||||||
| #include "gc.h" | #include "gc.h" | ||||||
| 
 | 
 | ||||||
| static LIST_HEAD(f2fs_stat_list); | static LIST_HEAD(f2fs_stat_list); | ||||||
| static struct dentry *f2fs_debugfs_root; |  | ||||||
| static DEFINE_MUTEX(f2fs_stat_mutex); | static DEFINE_MUTEX(f2fs_stat_mutex); | ||||||
|  | #ifdef CONFIG_DEBUG_FS | ||||||
|  | static struct dentry *f2fs_debugfs_root; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * This function calculates BDF of every segments | ||||||
|  |  */ | ||||||
|  | void f2fs_update_sit_info(struct f2fs_sb_info *sbi) | ||||||
|  | { | ||||||
|  | 	struct f2fs_stat_info *si = F2FS_STAT(sbi); | ||||||
|  | 	unsigned long long blks_per_sec, hblks_per_sec, total_vblocks; | ||||||
|  | 	unsigned long long bimodal, dist; | ||||||
|  | 	unsigned int segno, vblocks; | ||||||
|  | 	int ndirty = 0; | ||||||
|  | 
 | ||||||
|  | 	bimodal = 0; | ||||||
|  | 	total_vblocks = 0; | ||||||
|  | 	blks_per_sec = BLKS_PER_SEC(sbi); | ||||||
|  | 	hblks_per_sec = blks_per_sec / 2; | ||||||
|  | 	for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) { | ||||||
|  | 		vblocks = get_valid_blocks(sbi, segno, true); | ||||||
|  | 		dist = abs(vblocks - hblks_per_sec); | ||||||
|  | 		bimodal += dist * dist; | ||||||
|  | 
 | ||||||
|  | 		if (vblocks > 0 && vblocks < blks_per_sec) { | ||||||
|  | 			total_vblocks += vblocks; | ||||||
|  | 			ndirty++; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	dist = div_u64(MAIN_SECS(sbi) * hblks_per_sec * hblks_per_sec, 100); | ||||||
|  | 	si->bimodal = div64_u64(bimodal, dist); | ||||||
|  | 	if (si->dirty_count) | ||||||
|  | 		si->avg_vblocks = div_u64(total_vblocks, ndirty); | ||||||
|  | 	else | ||||||
|  | 		si->avg_vblocks = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_DEBUG_FS | ||||||
| static void update_general_status(struct f2fs_sb_info *sbi) | static void update_general_status(struct f2fs_sb_info *sbi) | ||||||
| { | { | ||||||
| 	struct f2fs_stat_info *si = F2FS_STAT(sbi); | 	struct f2fs_stat_info *si = F2FS_STAT(sbi); | ||||||
| @ -116,7 +152,6 @@ static void update_general_status(struct f2fs_sb_info *sbi) | |||||||
| 	si->free_nids = NM_I(sbi)->nid_cnt[FREE_NID]; | 	si->free_nids = NM_I(sbi)->nid_cnt[FREE_NID]; | ||||||
| 	si->avail_nids = NM_I(sbi)->available_nids; | 	si->avail_nids = NM_I(sbi)->available_nids; | ||||||
| 	si->alloc_nids = NM_I(sbi)->nid_cnt[PREALLOC_NID]; | 	si->alloc_nids = NM_I(sbi)->nid_cnt[PREALLOC_NID]; | ||||||
| 	si->bg_gc = sbi->bg_gc; |  | ||||||
| 	si->io_skip_bggc = sbi->io_skip_bggc; | 	si->io_skip_bggc = sbi->io_skip_bggc; | ||||||
| 	si->other_skip_bggc = sbi->other_skip_bggc; | 	si->other_skip_bggc = sbi->other_skip_bggc; | ||||||
| 	si->skipped_atomic_files[BG_GC] = sbi->skipped_atomic_files[BG_GC]; | 	si->skipped_atomic_files[BG_GC] = sbi->skipped_atomic_files[BG_GC]; | ||||||
| @ -147,39 +182,6 @@ static void update_general_status(struct f2fs_sb_info *sbi) | |||||||
| 	si->inplace_count = atomic_read(&sbi->inplace_count); | 	si->inplace_count = atomic_read(&sbi->inplace_count); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 |  | ||||||
|  * This function calculates BDF of every segments |  | ||||||
|  */ |  | ||||||
| static void update_sit_info(struct f2fs_sb_info *sbi) |  | ||||||
| { |  | ||||||
| 	struct f2fs_stat_info *si = F2FS_STAT(sbi); |  | ||||||
| 	unsigned long long blks_per_sec, hblks_per_sec, total_vblocks; |  | ||||||
| 	unsigned long long bimodal, dist; |  | ||||||
| 	unsigned int segno, vblocks; |  | ||||||
| 	int ndirty = 0; |  | ||||||
| 
 |  | ||||||
| 	bimodal = 0; |  | ||||||
| 	total_vblocks = 0; |  | ||||||
| 	blks_per_sec = BLKS_PER_SEC(sbi); |  | ||||||
| 	hblks_per_sec = blks_per_sec / 2; |  | ||||||
| 	for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) { |  | ||||||
| 		vblocks = get_valid_blocks(sbi, segno, true); |  | ||||||
| 		dist = abs(vblocks - hblks_per_sec); |  | ||||||
| 		bimodal += dist * dist; |  | ||||||
| 
 |  | ||||||
| 		if (vblocks > 0 && vblocks < blks_per_sec) { |  | ||||||
| 			total_vblocks += vblocks; |  | ||||||
| 			ndirty++; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	dist = div_u64(MAIN_SECS(sbi) * hblks_per_sec * hblks_per_sec, 100); |  | ||||||
| 	si->bimodal = div64_u64(bimodal, dist); |  | ||||||
| 	if (si->dirty_count) |  | ||||||
| 		si->avg_vblocks = div_u64(total_vblocks, ndirty); |  | ||||||
| 	else |  | ||||||
| 		si->avg_vblocks = 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /*
 | /*
 | ||||||
|  * This function calculates memory footprint. |  * This function calculates memory footprint. | ||||||
|  */ |  */ | ||||||
| @ -445,7 +447,7 @@ static int stat_show(struct seq_file *s, void *v) | |||||||
| 			   si->block_count[LFS], si->segment_count[LFS]); | 			   si->block_count[LFS], si->segment_count[LFS]); | ||||||
| 
 | 
 | ||||||
| 		/* segment usage info */ | 		/* segment usage info */ | ||||||
| 		update_sit_info(si->sbi); | 		f2fs_update_sit_info(si->sbi); | ||||||
| 		seq_printf(s, "\nBDF: %u, avg. vblocks: %u\n", | 		seq_printf(s, "\nBDF: %u, avg. vblocks: %u\n", | ||||||
| 			   si->bimodal, si->avg_vblocks); | 			   si->bimodal, si->avg_vblocks); | ||||||
| 
 | 
 | ||||||
| @ -465,6 +467,7 @@ static int stat_show(struct seq_file *s, void *v) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| DEFINE_SHOW_ATTRIBUTE(stat); | DEFINE_SHOW_ATTRIBUTE(stat); | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| int f2fs_build_stats(struct f2fs_sb_info *sbi) | int f2fs_build_stats(struct f2fs_sb_info *sbi) | ||||||
| { | { | ||||||
| @ -525,14 +528,18 @@ void f2fs_destroy_stats(struct f2fs_sb_info *sbi) | |||||||
| 
 | 
 | ||||||
| void __init f2fs_create_root_stats(void) | void __init f2fs_create_root_stats(void) | ||||||
| { | { | ||||||
|  | #ifdef CONFIG_DEBUG_FS | ||||||
| 	f2fs_debugfs_root = debugfs_create_dir("f2fs", NULL); | 	f2fs_debugfs_root = debugfs_create_dir("f2fs", NULL); | ||||||
| 
 | 
 | ||||||
| 	debugfs_create_file("status", S_IRUGO, f2fs_debugfs_root, NULL, | 	debugfs_create_file("status", S_IRUGO, f2fs_debugfs_root, NULL, | ||||||
| 			    &stat_fops); | 			    &stat_fops); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void f2fs_destroy_root_stats(void) | void f2fs_destroy_root_stats(void) | ||||||
| { | { | ||||||
|  | #ifdef CONFIG_DEBUG_FS | ||||||
| 	debugfs_remove_recursive(f2fs_debugfs_root); | 	debugfs_remove_recursive(f2fs_debugfs_root); | ||||||
| 	f2fs_debugfs_root = NULL; | 	f2fs_debugfs_root = NULL; | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  | |||||||
| @ -1435,7 +1435,6 @@ struct f2fs_sb_info { | |||||||
| 	atomic_t vw_cnt;			/* # of volatile writes */ | 	atomic_t vw_cnt;			/* # of volatile writes */ | ||||||
| 	atomic_t max_aw_cnt;			/* max # of atomic writes */ | 	atomic_t max_aw_cnt;			/* max # of atomic writes */ | ||||||
| 	atomic_t max_vw_cnt;			/* max # of volatile writes */ | 	atomic_t max_vw_cnt;			/* max # of volatile writes */ | ||||||
| 	int bg_gc;				/* background gc calls */ |  | ||||||
| 	unsigned int io_skip_bggc;		/* skip background gc for in-flight IO */ | 	unsigned int io_skip_bggc;		/* skip background gc for in-flight IO */ | ||||||
| 	unsigned int other_skip_bggc;		/* skip background gc for other reasons */ | 	unsigned int other_skip_bggc;		/* skip background gc for other reasons */ | ||||||
| 	unsigned int ndirty_inode[NR_INODE_TYPE];	/* # of dirty inodes */ | 	unsigned int ndirty_inode[NR_INODE_TYPE];	/* # of dirty inodes */ | ||||||
| @ -3460,7 +3459,7 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi) | |||||||
| #define stat_inc_cp_count(si)		((si)->cp_count++) | #define stat_inc_cp_count(si)		((si)->cp_count++) | ||||||
| #define stat_inc_bg_cp_count(si)	((si)->bg_cp_count++) | #define stat_inc_bg_cp_count(si)	((si)->bg_cp_count++) | ||||||
| #define stat_inc_call_count(si)		((si)->call_count++) | #define stat_inc_call_count(si)		((si)->call_count++) | ||||||
| #define stat_inc_bggc_count(sbi)	((sbi)->bg_gc++) | #define stat_inc_bggc_count(si)		((si)->bg_gc++) | ||||||
| #define stat_io_skip_bggc_count(sbi)	((sbi)->io_skip_bggc++) | #define stat_io_skip_bggc_count(sbi)	((sbi)->io_skip_bggc++) | ||||||
| #define stat_other_skip_bggc_count(sbi)	((sbi)->other_skip_bggc++) | #define stat_other_skip_bggc_count(sbi)	((sbi)->other_skip_bggc++) | ||||||
| #define stat_inc_dirty_inode(sbi, type)	((sbi)->ndirty_inode[type]++) | #define stat_inc_dirty_inode(sbi, type)	((sbi)->ndirty_inode[type]++) | ||||||
| @ -3584,6 +3583,7 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi); | |||||||
| void f2fs_destroy_stats(struct f2fs_sb_info *sbi); | void f2fs_destroy_stats(struct f2fs_sb_info *sbi); | ||||||
| void __init f2fs_create_root_stats(void); | void __init f2fs_create_root_stats(void); | ||||||
| void f2fs_destroy_root_stats(void); | void f2fs_destroy_root_stats(void); | ||||||
|  | void f2fs_update_sit_info(struct f2fs_sb_info *sbi); | ||||||
| #else | #else | ||||||
| #define stat_inc_cp_count(si)				do { } while (0) | #define stat_inc_cp_count(si)				do { } while (0) | ||||||
| #define stat_inc_bg_cp_count(si)			do { } while (0) | #define stat_inc_bg_cp_count(si)			do { } while (0) | ||||||
| @ -3593,8 +3593,8 @@ void f2fs_destroy_root_stats(void); | |||||||
| #define stat_other_skip_bggc_count(sbi)			do { } while (0) | #define stat_other_skip_bggc_count(sbi)			do { } while (0) | ||||||
| #define stat_inc_dirty_inode(sbi, type)			do { } while (0) | #define stat_inc_dirty_inode(sbi, type)			do { } while (0) | ||||||
| #define stat_dec_dirty_inode(sbi, type)			do { } while (0) | #define stat_dec_dirty_inode(sbi, type)			do { } while (0) | ||||||
| #define stat_inc_total_hit(sb)				do { } while (0) | #define stat_inc_total_hit(sbi)				do { } while (0) | ||||||
| #define stat_inc_rbtree_node_hit(sb)			do { } while (0) | #define stat_inc_rbtree_node_hit(sbi)			do { } while (0) | ||||||
| #define stat_inc_largest_node_hit(sbi)			do { } while (0) | #define stat_inc_largest_node_hit(sbi)			do { } while (0) | ||||||
| #define stat_inc_cached_node_hit(sbi)			do { } while (0) | #define stat_inc_cached_node_hit(sbi)			do { } while (0) | ||||||
| #define stat_inc_inline_xattr(inode)			do { } while (0) | #define stat_inc_inline_xattr(inode)			do { } while (0) | ||||||
| @ -3626,6 +3626,7 @@ static inline int f2fs_build_stats(struct f2fs_sb_info *sbi) { return 0; } | |||||||
| static inline void f2fs_destroy_stats(struct f2fs_sb_info *sbi) { } | static inline void f2fs_destroy_stats(struct f2fs_sb_info *sbi) { } | ||||||
| static inline void __init f2fs_create_root_stats(void) { } | static inline void __init f2fs_create_root_stats(void) { } | ||||||
| static inline void f2fs_destroy_root_stats(void) { } | static inline void f2fs_destroy_root_stats(void) { } | ||||||
|  | static inline void update_sit_info(struct f2fs_sb_info *sbi) {} | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| extern const struct file_operations f2fs_dir_operations; | extern const struct file_operations f2fs_dir_operations; | ||||||
|  | |||||||
| @ -99,7 +99,7 @@ static int gc_thread_func(void *data) | |||||||
| 		else | 		else | ||||||
| 			increase_sleep_time(gc_th, &wait_ms); | 			increase_sleep_time(gc_th, &wait_ms); | ||||||
| do_gc: | do_gc: | ||||||
| 		stat_inc_bggc_count(sbi); | 		stat_inc_bggc_count(sbi->stat_info); | ||||||
| 
 | 
 | ||||||
| 		/* if return value is not zero, no victim was selected */ | 		/* if return value is not zero, no victim was selected */ | ||||||
| 		if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC), true, NULL_SEGNO)) | 		if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC), true, NULL_SEGNO)) | ||||||
|  | |||||||
							
								
								
									
										139
									
								
								fs/f2fs/sysfs.c
									
									
									
									
									
								
							
							
						
						
									
										139
									
								
								fs/f2fs/sysfs.c
									
									
									
									
									
								
							| @ -25,6 +25,9 @@ enum { | |||||||
| 	DCC_INFO,	/* struct discard_cmd_control */ | 	DCC_INFO,	/* struct discard_cmd_control */ | ||||||
| 	NM_INFO,	/* struct f2fs_nm_info */ | 	NM_INFO,	/* struct f2fs_nm_info */ | ||||||
| 	F2FS_SBI,	/* struct f2fs_sb_info */ | 	F2FS_SBI,	/* struct f2fs_sb_info */ | ||||||
|  | #ifdef CONFIG_F2FS_STAT_FS | ||||||
|  | 	STAT_INFO,      /* struct f2fs_stat_info */ | ||||||
|  | #endif | ||||||
| #ifdef CONFIG_F2FS_FAULT_INJECTION | #ifdef CONFIG_F2FS_FAULT_INJECTION | ||||||
| 	FAULT_INFO_RATE,	/* struct f2fs_fault_info */ | 	FAULT_INFO_RATE,	/* struct f2fs_fault_info */ | ||||||
| 	FAULT_INFO_TYPE,	/* struct f2fs_fault_info */ | 	FAULT_INFO_TYPE,	/* struct f2fs_fault_info */ | ||||||
| @ -42,6 +45,9 @@ struct f2fs_attr { | |||||||
| 	int id; | 	int id; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static ssize_t f2fs_sbi_show(struct f2fs_attr *a, | ||||||
|  | 			     struct f2fs_sb_info *sbi, char *buf); | ||||||
|  | 
 | ||||||
| static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) | static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) | ||||||
| { | { | ||||||
| 	if (struct_type == GC_THREAD) | 	if (struct_type == GC_THREAD) | ||||||
| @ -58,6 +64,10 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) | |||||||
| 	else if (struct_type == FAULT_INFO_RATE || | 	else if (struct_type == FAULT_INFO_RATE || | ||||||
| 					struct_type == FAULT_INFO_TYPE) | 					struct_type == FAULT_INFO_TYPE) | ||||||
| 		return (unsigned char *)&F2FS_OPTION(sbi).fault_info; | 		return (unsigned char *)&F2FS_OPTION(sbi).fault_info; | ||||||
|  | #endif | ||||||
|  | #ifdef CONFIG_F2FS_STAT_FS | ||||||
|  | 	else if (struct_type == STAT_INFO) | ||||||
|  | 		return (unsigned char *)F2FS_STAT(sbi); | ||||||
| #endif | #endif | ||||||
| 	return NULL; | 	return NULL; | ||||||
| } | } | ||||||
| @ -65,35 +75,15 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) | |||||||
| static ssize_t dirty_segments_show(struct f2fs_attr *a, | static ssize_t dirty_segments_show(struct f2fs_attr *a, | ||||||
| 		struct f2fs_sb_info *sbi, char *buf) | 		struct f2fs_sb_info *sbi, char *buf) | ||||||
| { | { | ||||||
| 	return snprintf(buf, PAGE_SIZE, "%llu\n", | 	return sprintf(buf, "%llu\n", | ||||||
| 		(unsigned long long)(dirty_segments(sbi))); | 			(unsigned long long)(dirty_segments(sbi))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t unusable_show(struct f2fs_attr *a, | static ssize_t free_segments_show(struct f2fs_attr *a, | ||||||
| 		struct f2fs_sb_info *sbi, char *buf) | 		struct f2fs_sb_info *sbi, char *buf) | ||||||
| { | { | ||||||
| 	block_t unusable; | 	return sprintf(buf, "%llu\n", | ||||||
| 
 | 			(unsigned long long)(free_segments(sbi))); | ||||||
| 	if (test_opt(sbi, DISABLE_CHECKPOINT)) |  | ||||||
| 		unusable = sbi->unusable_block_count; |  | ||||||
| 	else |  | ||||||
| 		unusable = f2fs_get_unusable_blocks(sbi); |  | ||||||
| 	return snprintf(buf, PAGE_SIZE, "%llu\n", |  | ||||||
| 		(unsigned long long)unusable); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static ssize_t encoding_show(struct f2fs_attr *a, |  | ||||||
| 		struct f2fs_sb_info *sbi, char *buf) |  | ||||||
| { |  | ||||||
| #ifdef CONFIG_UNICODE |  | ||||||
| 	if (f2fs_sb_has_casefold(sbi)) |  | ||||||
| 		return snprintf(buf, PAGE_SIZE, "%s (%d.%d.%d)\n", |  | ||||||
| 			sbi->s_encoding->charset, |  | ||||||
| 			(sbi->s_encoding->version >> 16) & 0xff, |  | ||||||
| 			(sbi->s_encoding->version >> 8) & 0xff, |  | ||||||
| 			sbi->s_encoding->version & 0xff); |  | ||||||
| #endif |  | ||||||
| 	return snprintf(buf, PAGE_SIZE, "(none)"); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a, | static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a, | ||||||
| @ -102,10 +92,10 @@ static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a, | |||||||
| 	struct super_block *sb = sbi->sb; | 	struct super_block *sb = sbi->sb; | ||||||
| 
 | 
 | ||||||
| 	if (!sb->s_bdev->bd_part) | 	if (!sb->s_bdev->bd_part) | ||||||
| 		return snprintf(buf, PAGE_SIZE, "0\n"); | 		return sprintf(buf, "0\n"); | ||||||
| 
 | 
 | ||||||
| 	return snprintf(buf, PAGE_SIZE, "%llu\n", | 	return sprintf(buf, "%llu\n", | ||||||
| 		(unsigned long long)(sbi->kbytes_written + | 			(unsigned long long)(sbi->kbytes_written + | ||||||
| 			BD_PART_WRITTEN(sbi))); | 			BD_PART_WRITTEN(sbi))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -116,7 +106,7 @@ static ssize_t features_show(struct f2fs_attr *a, | |||||||
| 	int len = 0; | 	int len = 0; | ||||||
| 
 | 
 | ||||||
| 	if (!sb->s_bdev->bd_part) | 	if (!sb->s_bdev->bd_part) | ||||||
| 		return snprintf(buf, PAGE_SIZE, "0\n"); | 		return sprintf(buf, "0\n"); | ||||||
| 
 | 
 | ||||||
| 	if (f2fs_sb_has_encrypt(sbi)) | 	if (f2fs_sb_has_encrypt(sbi)) | ||||||
| 		len += snprintf(buf, PAGE_SIZE - len, "%s", | 		len += snprintf(buf, PAGE_SIZE - len, "%s", | ||||||
| @ -166,9 +156,66 @@ static ssize_t features_show(struct f2fs_attr *a, | |||||||
| static ssize_t current_reserved_blocks_show(struct f2fs_attr *a, | static ssize_t current_reserved_blocks_show(struct f2fs_attr *a, | ||||||
| 					struct f2fs_sb_info *sbi, char *buf) | 					struct f2fs_sb_info *sbi, char *buf) | ||||||
| { | { | ||||||
| 	return snprintf(buf, PAGE_SIZE, "%u\n", sbi->current_reserved_blocks); | 	return sprintf(buf, "%u\n", sbi->current_reserved_blocks); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static ssize_t unusable_show(struct f2fs_attr *a, | ||||||
|  | 		struct f2fs_sb_info *sbi, char *buf) | ||||||
|  | { | ||||||
|  | 	block_t unusable; | ||||||
|  | 
 | ||||||
|  | 	if (test_opt(sbi, DISABLE_CHECKPOINT)) | ||||||
|  | 		unusable = sbi->unusable_block_count; | ||||||
|  | 	else | ||||||
|  | 		unusable = f2fs_get_unusable_blocks(sbi); | ||||||
|  | 	return sprintf(buf, "%llu\n", (unsigned long long)unusable); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ssize_t encoding_show(struct f2fs_attr *a, | ||||||
|  | 		struct f2fs_sb_info *sbi, char *buf) | ||||||
|  | { | ||||||
|  | #ifdef CONFIG_UNICODE | ||||||
|  | 	if (f2fs_sb_has_casefold(sbi)) | ||||||
|  | 		return snprintf(buf, PAGE_SIZE, "%s (%d.%d.%d)\n", | ||||||
|  | 			sbi->s_encoding->charset, | ||||||
|  | 			(sbi->s_encoding->version >> 16) & 0xff, | ||||||
|  | 			(sbi->s_encoding->version >> 8) & 0xff, | ||||||
|  | 			sbi->s_encoding->version & 0xff); | ||||||
|  | #endif | ||||||
|  | 	return sprintf(buf, "(none)"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_F2FS_STAT_FS | ||||||
|  | static ssize_t moved_blocks_foreground_show(struct f2fs_attr *a, | ||||||
|  | 				struct f2fs_sb_info *sbi, char *buf) | ||||||
|  | { | ||||||
|  | 	struct f2fs_stat_info *si = F2FS_STAT(sbi); | ||||||
|  | 
 | ||||||
|  | 	return sprintf(buf, "%llu\n", | ||||||
|  | 		(unsigned long long)(si->tot_blks - | ||||||
|  | 			(si->bg_data_blks + si->bg_node_blks))); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ssize_t moved_blocks_background_show(struct f2fs_attr *a, | ||||||
|  | 				struct f2fs_sb_info *sbi, char *buf) | ||||||
|  | { | ||||||
|  | 	struct f2fs_stat_info *si = F2FS_STAT(sbi); | ||||||
|  | 
 | ||||||
|  | 	return sprintf(buf, "%llu\n", | ||||||
|  | 		(unsigned long long)(si->bg_data_blks + si->bg_node_blks)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ssize_t avg_vblocks_show(struct f2fs_attr *a, | ||||||
|  | 		struct f2fs_sb_info *sbi, char *buf) | ||||||
|  | { | ||||||
|  | 	struct f2fs_stat_info *si = F2FS_STAT(sbi); | ||||||
|  | 
 | ||||||
|  | 	si->dirty_count = dirty_segments(sbi); | ||||||
|  | 	f2fs_update_sit_info(sbi); | ||||||
|  | 	return sprintf(buf, "%llu\n", (unsigned long long)(si->avg_vblocks)); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| static ssize_t f2fs_sbi_show(struct f2fs_attr *a, | static ssize_t f2fs_sbi_show(struct f2fs_attr *a, | ||||||
| 			struct f2fs_sb_info *sbi, char *buf) | 			struct f2fs_sb_info *sbi, char *buf) | ||||||
| { | { | ||||||
| @ -202,7 +249,7 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, | |||||||
| 
 | 
 | ||||||
| 	ui = (unsigned int *)(ptr + a->offset); | 	ui = (unsigned int *)(ptr + a->offset); | ||||||
| 
 | 
 | ||||||
| 	return snprintf(buf, PAGE_SIZE, "%u\n", *ui); | 	return sprintf(buf, "%u\n", *ui); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static ssize_t __sbi_store(struct f2fs_attr *a, | static ssize_t __sbi_store(struct f2fs_attr *a, | ||||||
| @ -413,7 +460,7 @@ static ssize_t f2fs_feature_show(struct f2fs_attr *a, | |||||||
| 	case FEAT_SB_CHECKSUM: | 	case FEAT_SB_CHECKSUM: | ||||||
| 	case FEAT_CASEFOLD: | 	case FEAT_CASEFOLD: | ||||||
| 	case FEAT_COMPRESSION: | 	case FEAT_COMPRESSION: | ||||||
| 		return snprintf(buf, PAGE_SIZE, "supported\n"); | 		return sprintf(buf, "supported\n"); | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| @ -442,6 +489,14 @@ static struct f2fs_attr f2fs_attr_##_name = {			\ | |||||||
| 	.id	= _id,						\ | 	.id	= _id,						\ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #define F2FS_STAT_ATTR(_struct_type, _struct_name, _name, _elname)	\ | ||||||
|  | static struct f2fs_attr f2fs_attr_##_name = {			\ | ||||||
|  | 	.attr = {.name = __stringify(_name), .mode = 0444 },	\ | ||||||
|  | 	.show = f2fs_sbi_show,					\ | ||||||
|  | 	.struct_type = _struct_type,				\ | ||||||
|  | 	.offset = offsetof(struct _struct_name, _elname),       \ | ||||||
|  | } | ||||||
|  | 
 | ||||||
| F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_urgent_sleep_time, | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_urgent_sleep_time, | ||||||
| 							urgent_sleep_time); | 							urgent_sleep_time); | ||||||
| F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time); | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time); | ||||||
| @ -483,11 +538,21 @@ F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate); | |||||||
| F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type); | F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type); | ||||||
| #endif | #endif | ||||||
| F2FS_GENERAL_RO_ATTR(dirty_segments); | F2FS_GENERAL_RO_ATTR(dirty_segments); | ||||||
|  | F2FS_GENERAL_RO_ATTR(free_segments); | ||||||
| F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes); | F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes); | ||||||
| F2FS_GENERAL_RO_ATTR(features); | F2FS_GENERAL_RO_ATTR(features); | ||||||
| F2FS_GENERAL_RO_ATTR(current_reserved_blocks); | F2FS_GENERAL_RO_ATTR(current_reserved_blocks); | ||||||
| F2FS_GENERAL_RO_ATTR(unusable); | F2FS_GENERAL_RO_ATTR(unusable); | ||||||
| F2FS_GENERAL_RO_ATTR(encoding); | F2FS_GENERAL_RO_ATTR(encoding); | ||||||
|  | #ifdef CONFIG_F2FS_STAT_FS | ||||||
|  | F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, cp_foreground_calls, cp_count); | ||||||
|  | F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, cp_background_calls, bg_cp_count); | ||||||
|  | F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, gc_foreground_calls, call_count); | ||||||
|  | F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, gc_background_calls, bg_gc); | ||||||
|  | F2FS_GENERAL_RO_ATTR(moved_blocks_background); | ||||||
|  | F2FS_GENERAL_RO_ATTR(moved_blocks_foreground); | ||||||
|  | F2FS_GENERAL_RO_ATTR(avg_vblocks); | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_FS_ENCRYPTION | #ifdef CONFIG_FS_ENCRYPTION | ||||||
| F2FS_FEATURE_RO_ATTR(encryption, FEAT_CRYPTO); | F2FS_FEATURE_RO_ATTR(encryption, FEAT_CRYPTO); | ||||||
| @ -549,12 +614,22 @@ static struct attribute *f2fs_attrs[] = { | |||||||
| 	ATTR_LIST(inject_type), | 	ATTR_LIST(inject_type), | ||||||
| #endif | #endif | ||||||
| 	ATTR_LIST(dirty_segments), | 	ATTR_LIST(dirty_segments), | ||||||
|  | 	ATTR_LIST(free_segments), | ||||||
| 	ATTR_LIST(unusable), | 	ATTR_LIST(unusable), | ||||||
| 	ATTR_LIST(lifetime_write_kbytes), | 	ATTR_LIST(lifetime_write_kbytes), | ||||||
| 	ATTR_LIST(features), | 	ATTR_LIST(features), | ||||||
| 	ATTR_LIST(reserved_blocks), | 	ATTR_LIST(reserved_blocks), | ||||||
| 	ATTR_LIST(current_reserved_blocks), | 	ATTR_LIST(current_reserved_blocks), | ||||||
| 	ATTR_LIST(encoding), | 	ATTR_LIST(encoding), | ||||||
|  | #ifdef CONFIG_F2FS_STAT_FS | ||||||
|  | 	ATTR_LIST(cp_foreground_calls), | ||||||
|  | 	ATTR_LIST(cp_background_calls), | ||||||
|  | 	ATTR_LIST(gc_foreground_calls), | ||||||
|  | 	ATTR_LIST(gc_background_calls), | ||||||
|  | 	ATTR_LIST(moved_blocks_foreground), | ||||||
|  | 	ATTR_LIST(moved_blocks_background), | ||||||
|  | 	ATTR_LIST(avg_vblocks), | ||||||
|  | #endif | ||||||
| 	NULL, | 	NULL, | ||||||
| }; | }; | ||||||
| ATTRIBUTE_GROUPS(f2fs); | ATTRIBUTE_GROUPS(f2fs); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user