Commit fc7100ea authored by Hridya Valsaraju's avatar Hridya Valsaraju Committed by Jaegeuk Kim

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 f5fa7c8b
...@@ -271,3 +271,50 @@ Date July 2019 ...@@ -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 ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 { ...@@ -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) ...@@ -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); ...@@ -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); ...@@ -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; } ...@@ -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) ...@@ -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))
......
...@@ -25,6 +25,9 @@ enum { ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 = { \ ...@@ -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); ...@@ -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[] = { ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment