Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e1b0048 authored by Hridya Valsaraju's avatar Hridya Valsaraju Committed by Jaegeuk Kim
Browse files

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: default avatarHridya Valsaraju <hridya@google.com>
[Jaegeuk Kim: allow STAT_FS without DEBUG_FS]
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent b2c09c65
Loading
Loading
Loading
Loading
+47 −0
Original line number Diff line number Diff line
@@ -271,3 +271,50 @@ Date July 2019
Contact:	"Daniel Rosenberg" <drosen@google.com>
Description:	Displays name and version of the encoding set for the filesystem.
		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.
+1 −1
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@ config F2FS_FS

config F2FS_STAT_FS
	bool "F2FS Status Information"
	depends on F2FS_FS && DEBUG_FS
	depends on F2FS_FS
	default y
	help
	  /sys/kernel/debug/f2fs/ contains information about all the partitions
+43 −36
Original line number Diff line number Diff line
@@ -21,9 +21,45 @@
#include "gc.h"

static LIST_HEAD(f2fs_stat_list);
static struct dentry *f2fs_debugfs_root;
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)
{
	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->avail_nids = NM_I(sbi)->available_nids;
	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->other_skip_bggc = sbi->other_skip_bggc;
	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);
}

/*
 * 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.
 */
@@ -445,7 +447,7 @@ static int stat_show(struct seq_file *s, void *v)
			   si->block_count[LFS], si->segment_count[LFS]);

		/* segment usage info */
		update_sit_info(si->sbi);
		f2fs_update_sit_info(si->sbi);
		seq_printf(s, "\nBDF: %u, avg. vblocks: %u\n",
			   si->bimodal, si->avg_vblocks);

@@ -465,6 +467,7 @@ static int stat_show(struct seq_file *s, void *v)
}

DEFINE_SHOW_ATTRIBUTE(stat);
#endif

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)
{
#ifdef CONFIG_DEBUG_FS
	f2fs_debugfs_root = debugfs_create_dir("f2fs", NULL);

	debugfs_create_file("status", S_IRUGO, f2fs_debugfs_root, NULL,
			    &stat_fops);
#endif
}

void f2fs_destroy_root_stats(void)
{
#ifdef CONFIG_DEBUG_FS
	debugfs_remove_recursive(f2fs_debugfs_root);
	f2fs_debugfs_root = NULL;
#endif
}
+5 −4
Original line number Diff line number Diff line
@@ -1435,7 +1435,6 @@ struct f2fs_sb_info {
	atomic_t vw_cnt;			/* # of volatile writes */
	atomic_t max_aw_cnt;			/* max # of atomic 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 other_skip_bggc;		/* skip background gc for other reasons */
	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_bg_cp_count(si)	((si)->bg_cp_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_other_skip_bggc_count(sbi)	((sbi)->other_skip_bggc++)
#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 __init f2fs_create_root_stats(void);
void f2fs_destroy_root_stats(void);
void f2fs_update_sit_info(struct f2fs_sb_info *sbi);
#else
#define stat_inc_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_inc_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_rbtree_node_hit(sb)			do { } while (0)
#define stat_inc_total_hit(sbi)				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_cached_node_hit(sbi)			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 __init f2fs_create_root_stats(void) { }
static inline void f2fs_destroy_root_stats(void) { }
static inline void update_sit_info(struct f2fs_sb_info *sbi) {}
#endif

extern const struct file_operations f2fs_dir_operations;
+1 −1
Original line number Diff line number Diff line
@@ -99,7 +99,7 @@ static int gc_thread_func(void *data)
		else
			increase_sleep_time(gc_th, &wait_ms);
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 (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC), true, NULL_SEGNO))
Loading