forked from mirrors/linux
		
	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
					
				
					 6 changed files with 204 additions and 74 deletions
				
			
		| 
						 | 
					@ -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 a new issue