2012-11-29 08:28:09 +04:00
/*
2012-11-03 01:50:41 +04:00
* f2fs debugging statistics
*
* Copyright ( c ) 2012 Samsung Electronics Co . , Ltd .
* http : //www.samsung.com/
* Copyright ( c ) 2012 Linux Foundation
* Copyright ( c ) 2012 Greg Kroah - Hartman < gregkh @ linuxfoundation . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/fs.h>
# include <linux/backing-dev.h>
# include <linux/f2fs_fs.h>
# include <linux/blkdev.h>
# include <linux/debugfs.h>
# include <linux/seq_file.h>
# include "f2fs.h"
# include "node.h"
# include "segment.h"
# include "gc.h"
static LIST_HEAD ( f2fs_stat_list ) ;
2013-12-03 17:09:29 +04:00
static struct dentry * f2fs_debugfs_root ;
2013-01-14 16:08:16 +04:00
static DEFINE_MUTEX ( f2fs_stat_mutex ) ;
2012-11-03 01:50:41 +04:00
2012-11-28 11:12:41 +04:00
static void update_general_status ( struct f2fs_sb_info * sbi )
2012-11-03 01:50:41 +04:00
{
2013-07-12 10:47:11 +04:00
struct f2fs_stat_info * si = F2FS_STAT ( sbi ) ;
2012-11-03 01:50:41 +04:00
int i ;
2014-08-06 18:22:50 +04:00
/* validation check of the segment numbers */
2012-11-03 01:50:41 +04:00
si - > hit_ext = sbi - > read_hit_ext ;
si - > total_ext = sbi - > total_hit_ext ;
si - > ndirty_node = get_pages ( sbi , F2FS_DIRTY_NODES ) ;
si - > ndirty_dent = get_pages ( sbi , F2FS_DIRTY_DENTS ) ;
si - > ndirty_dirs = sbi - > n_dirty_dirs ;
si - > ndirty_meta = get_pages ( sbi , F2FS_DIRTY_META ) ;
2014-12-06 04:18:15 +03:00
si - > inmem_pages = get_pages ( sbi , F2FS_INMEM_PAGES ) ;
2012-11-03 01:50:41 +04:00
si - > total_count = ( int ) sbi - > user_block_count / sbi - > blocks_per_seg ;
si - > rsvd_segs = reserved_segments ( sbi ) ;
si - > overp_segs = overprovision_segments ( sbi ) ;
si - > valid_count = valid_user_blocks ( sbi ) ;
si - > valid_node_count = valid_node_count ( sbi ) ;
si - > valid_inode_count = valid_inode_count ( sbi ) ;
2014-12-08 14:08:20 +03:00
si - > inline_inode = atomic_read ( & sbi - > inline_inode ) ;
si - > inline_dir = atomic_read ( & sbi - > inline_dir ) ;
2012-11-03 01:50:41 +04:00
si - > utilization = utilization ( sbi ) ;
si - > free_segs = free_segments ( sbi ) ;
si - > free_secs = free_sections ( sbi ) ;
si - > prefree_count = prefree_segments ( sbi ) ;
si - > dirty_count = dirty_segments ( sbi ) ;
2014-01-21 13:51:16 +04:00
si - > node_pages = NODE_MAPPING ( sbi ) - > nrpages ;
2014-01-20 14:37:04 +04:00
si - > meta_pages = META_MAPPING ( sbi ) - > nrpages ;
2012-11-03 01:50:41 +04:00
si - > nats = NM_I ( sbi ) - > nat_cnt ;
2015-01-07 22:09:37 +03:00
si - > dirty_nats = NM_I ( sbi ) - > dirty_nat_cnt ;
si - > sits = MAIN_SEGS ( sbi ) ;
si - > dirty_sits = SIT_I ( sbi ) - > dirty_sentries ;
2012-11-03 01:50:41 +04:00
si - > fnids = NM_I ( sbi ) - > fcnt ;
si - > bg_gc = sbi - > bg_gc ;
si - > util_free = ( int ) ( free_user_blocks ( sbi ) > > sbi - > log_blocks_per_seg )
* 100 / ( int ) ( sbi - > user_block_count > > sbi - > log_blocks_per_seg )
/ 2 ;
si - > util_valid = ( int ) ( written_block_count ( sbi ) > >
sbi - > log_blocks_per_seg )
* 100 / ( int ) ( sbi - > user_block_count > > sbi - > log_blocks_per_seg )
/ 2 ;
si - > util_invalid = 50 - si - > util_free - si - > util_valid ;
for ( i = CURSEG_HOT_DATA ; i < = CURSEG_COLD_NODE ; i + + ) {
struct curseg_info * curseg = CURSEG_I ( sbi , i ) ;
si - > curseg [ i ] = curseg - > segno ;
si - > cursec [ i ] = curseg - > segno / sbi - > segs_per_sec ;
si - > curzone [ i ] = si - > cursec [ i ] / sbi - > secs_per_zone ;
}
for ( i = 0 ; i < 2 ; i + + ) {
si - > segment_count [ i ] = sbi - > segment_count [ i ] ;
si - > block_count [ i ] = sbi - > block_count [ i ] ;
}
2014-12-23 20:16:54 +03:00
si - > inplace_count = atomic_read ( & sbi - > inplace_count ) ;
2012-11-03 01:50:41 +04:00
}
2012-11-29 08:28:09 +04:00
/*
2012-11-03 01:50:41 +04:00
* This function calculates BDF of every segments
*/
static void update_sit_info ( struct f2fs_sb_info * sbi )
{
2013-07-12 10:47:11 +04:00
struct f2fs_stat_info * si = F2FS_STAT ( sbi ) ;
2012-11-03 01:50:41 +04:00
unsigned int blks_per_sec , hblks_per_sec , total_vblocks , bimodal , dist ;
unsigned int segno , vblocks ;
int ndirty = 0 ;
bimodal = 0 ;
total_vblocks = 0 ;
blks_per_sec = sbi - > segs_per_sec * ( 1 < < sbi - > log_blocks_per_seg ) ;
hblks_per_sec = blks_per_sec / 2 ;
2014-09-23 22:23:01 +04:00
for ( segno = 0 ; segno < MAIN_SEGS ( sbi ) ; segno + = sbi - > segs_per_sec ) {
2012-11-03 01:50:41 +04:00
vblocks = get_valid_blocks ( sbi , segno , sbi - > segs_per_sec ) ;
dist = abs ( vblocks - hblks_per_sec ) ;
bimodal + = dist * dist ;
if ( vblocks > 0 & & vblocks < blks_per_sec ) {
total_vblocks + = vblocks ;
ndirty + + ;
}
}
2014-09-23 22:23:01 +04:00
dist = MAIN_SECS ( sbi ) * hblks_per_sec * hblks_per_sec / 100 ;
2012-11-03 01:50:41 +04:00
si - > bimodal = bimodal / dist ;
if ( si - > dirty_count )
si - > avg_vblocks = total_vblocks / ndirty ;
else
si - > avg_vblocks = 0 ;
}
2012-11-29 08:28:09 +04:00
/*
2012-11-03 01:50:41 +04:00
* This function calculates memory footprint .
*/
static void update_mem_info ( struct f2fs_sb_info * sbi )
{
2013-07-12 10:47:11 +04:00
struct f2fs_stat_info * si = F2FS_STAT ( sbi ) ;
2012-11-03 01:50:41 +04:00
unsigned npages ;
2014-11-07 02:16:04 +03:00
int i ;
2012-11-03 01:50:41 +04:00
if ( si - > base_mem )
goto get_cache ;
si - > base_mem = sizeof ( struct f2fs_sb_info ) + sbi - > sb - > s_blocksize ;
si - > base_mem + = 2 * sizeof ( struct f2fs_inode_info ) ;
si - > base_mem + = sizeof ( * sbi - > ckpt ) ;
/* build sm */
si - > base_mem + = sizeof ( struct f2fs_sm_info ) ;
/* build sit */
si - > base_mem + = sizeof ( struct sit_info ) ;
2014-09-23 22:23:01 +04:00
si - > base_mem + = MAIN_SEGS ( sbi ) * sizeof ( struct seg_entry ) ;
si - > base_mem + = f2fs_bitmap_size ( MAIN_SEGS ( sbi ) ) ;
si - > base_mem + = 2 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS ( sbi ) ;
2012-11-03 01:50:41 +04:00
if ( sbi - > segs_per_sec > 1 )
2014-09-23 22:23:01 +04:00
si - > base_mem + = MAIN_SECS ( sbi ) * sizeof ( struct sec_entry ) ;
2012-11-03 01:50:41 +04:00
si - > base_mem + = __bitmap_size ( sbi , SIT_BITMAP ) ;
/* build free segmap */
si - > base_mem + = sizeof ( struct free_segmap_info ) ;
2014-09-23 22:23:01 +04:00
si - > base_mem + = f2fs_bitmap_size ( MAIN_SEGS ( sbi ) ) ;
si - > base_mem + = f2fs_bitmap_size ( MAIN_SECS ( sbi ) ) ;
2012-11-03 01:50:41 +04:00
/* build curseg */
si - > base_mem + = sizeof ( struct curseg_info ) * NR_CURSEG_TYPE ;
si - > base_mem + = PAGE_CACHE_SIZE * NR_CURSEG_TYPE ;
/* build dirty segmap */
si - > base_mem + = sizeof ( struct dirty_seglist_info ) ;
2014-09-23 22:23:01 +04:00
si - > base_mem + = NR_DIRTY_TYPE * f2fs_bitmap_size ( MAIN_SEGS ( sbi ) ) ;
si - > base_mem + = f2fs_bitmap_size ( MAIN_SECS ( sbi ) ) ;
2012-11-03 01:50:41 +04:00
2014-08-06 18:22:50 +04:00
/* build nm */
2012-11-03 01:50:41 +04:00
si - > base_mem + = sizeof ( struct f2fs_nm_info ) ;
si - > base_mem + = __bitmap_size ( sbi , NAT_BITMAP ) ;
/* build gc */
si - > base_mem + = sizeof ( struct f2fs_gc_kthread ) ;
get_cache :
/* free nids */
si - > cache_mem = NM_I ( sbi ) - > fcnt ;
si - > cache_mem + = NM_I ( sbi ) - > nat_cnt ;
2014-01-21 13:51:16 +04:00
npages = NODE_MAPPING ( sbi ) - > nrpages ;
2012-11-03 01:50:41 +04:00
si - > cache_mem + = npages < < PAGE_CACHE_SHIFT ;
2014-01-20 14:37:04 +04:00
npages = META_MAPPING ( sbi ) - > nrpages ;
2012-11-03 01:50:41 +04:00
si - > cache_mem + = npages < < PAGE_CACHE_SHIFT ;
2014-12-29 10:56:18 +03:00
si - > cache_mem + = sbi - > n_dirty_dirs * sizeof ( struct inode_entry ) ;
2014-11-07 02:16:04 +03:00
for ( i = 0 ; i < = UPDATE_INO ; i + + )
2014-11-18 06:18:36 +03:00
si - > cache_mem + = sbi - > im [ i ] . ino_num * sizeof ( struct ino_entry ) ;
2012-11-03 01:50:41 +04:00
}
static int stat_show ( struct seq_file * s , void * v )
{
2013-05-14 16:06:46 +04:00
struct f2fs_stat_info * si ;
2012-11-03 01:50:41 +04:00
int i = 0 ;
int j ;
2013-01-14 16:08:16 +04:00
mutex_lock ( & f2fs_stat_mutex ) ;
2013-05-14 16:06:46 +04:00
list_for_each_entry ( si , & f2fs_stat_list , stat_list ) {
2013-02-01 11:00:30 +04:00
char devname [ BDEVNAME_SIZE ] ;
2012-11-03 01:50:41 +04:00
update_general_status ( si - > sbi ) ;
2013-02-01 11:00:30 +04:00
seq_printf ( s , " \n =====[ partition info(%s). #%d ]===== \n " ,
bdevname ( si - > sbi - > sb - > s_bdev , devname ) , i + + ) ;
2012-12-31 09:59:09 +04:00
seq_printf ( s , " [SB: 1] [CP: 2] [SIT: %d] [NAT: %d] " ,
si - > sit_area_segs , si - > nat_area_segs ) ;
2012-11-03 01:50:41 +04:00
seq_printf ( s , " [SSA: %d] [MAIN: %d " ,
si - > ssa_area_segs , si - > main_area_segs ) ;
seq_printf ( s , " (OverProv:%d Resv:%d)] \n \n " ,
si - > overp_segs , si - > rsvd_segs ) ;
seq_printf ( s , " Utilization: %d%% (%d valid blocks) \n " ,
si - > utilization , si - > valid_count ) ;
seq_printf ( s , " - Node: %u (Inode: %u, " ,
si - > valid_node_count , si - > valid_inode_count ) ;
seq_printf ( s , " Other: %u) \n - Data: %u \n " ,
si - > valid_node_count - si - > valid_inode_count ,
si - > valid_count - si - > valid_node_count ) ;
2013-11-26 06:08:57 +04:00
seq_printf ( s , " - Inline_data Inode: %u \n " ,
si - > inline_inode ) ;
2014-10-14 07:00:16 +04:00
seq_printf ( s , " - Inline_dentry Inode: %u \n " ,
si - > inline_dir ) ;
2012-11-03 01:50:41 +04:00
seq_printf ( s , " \n Main area: %d segs, %d secs %d zones \n " ,
si - > main_area_segs , si - > main_area_sections ,
si - > main_area_zones ) ;
seq_printf ( s , " - COLD data: %d, %d, %d \n " ,
si - > curseg [ CURSEG_COLD_DATA ] ,
si - > cursec [ CURSEG_COLD_DATA ] ,
si - > curzone [ CURSEG_COLD_DATA ] ) ;
seq_printf ( s , " - WARM data: %d, %d, %d \n " ,
si - > curseg [ CURSEG_WARM_DATA ] ,
si - > cursec [ CURSEG_WARM_DATA ] ,
si - > curzone [ CURSEG_WARM_DATA ] ) ;
seq_printf ( s , " - HOT data: %d, %d, %d \n " ,
si - > curseg [ CURSEG_HOT_DATA ] ,
si - > cursec [ CURSEG_HOT_DATA ] ,
si - > curzone [ CURSEG_HOT_DATA ] ) ;
seq_printf ( s , " - Dir dnode: %d, %d, %d \n " ,
si - > curseg [ CURSEG_HOT_NODE ] ,
si - > cursec [ CURSEG_HOT_NODE ] ,
si - > curzone [ CURSEG_HOT_NODE ] ) ;
seq_printf ( s , " - File dnode: %d, %d, %d \n " ,
si - > curseg [ CURSEG_WARM_NODE ] ,
si - > cursec [ CURSEG_WARM_NODE ] ,
si - > curzone [ CURSEG_WARM_NODE ] ) ;
seq_printf ( s , " - Indir nodes: %d, %d, %d \n " ,
si - > curseg [ CURSEG_COLD_NODE ] ,
si - > cursec [ CURSEG_COLD_NODE ] ,
si - > curzone [ CURSEG_COLD_NODE ] ) ;
seq_printf ( s , " \n - Valid: %d \n - Dirty: %d \n " ,
si - > main_area_segs - si - > dirty_count -
si - > prefree_count - si - > free_segs ,
si - > dirty_count ) ;
seq_printf ( s , " - Prefree: %d \n - Free: %d (%d) \n \n " ,
si - > prefree_count , si - > free_segs , si - > free_secs ) ;
2014-02-13 10:12:29 +04:00
seq_printf ( s , " CP calls: %d \n " , si - > cp_count ) ;
2012-11-03 01:50:41 +04:00
seq_printf ( s , " GC calls: %d (BG: %d) \n " ,
si - > call_count , si - > bg_gc ) ;
seq_printf ( s , " - data segments : %d \n " , si - > data_segs ) ;
seq_printf ( s , " - node segments : %d \n " , si - > node_segs ) ;
seq_printf ( s , " Try to move %d blocks \n " , si - > tot_blks ) ;
seq_printf ( s , " - data blocks : %d \n " , si - > data_blks ) ;
seq_printf ( s , " - node blocks : %d \n " , si - > node_blks ) ;
seq_printf ( s , " \n Extent Hit Ratio: %d / %d \n " ,
si - > hit_ext , si - > total_ext ) ;
2014-01-18 00:44:39 +04:00
seq_puts ( s , " \n Balancing F2FS Async: \n " ) ;
2014-12-06 04:18:15 +03:00
seq_printf ( s , " - inmem: %4d \n " ,
si - > inmem_pages ) ;
2014-01-13 05:34:18 +04:00
seq_printf ( s , " - nodes: %4d in %4d \n " ,
2012-11-03 01:50:41 +04:00
si - > ndirty_node , si - > node_pages ) ;
2014-01-13 05:34:18 +04:00
seq_printf ( s , " - dents: %4d in dirs:%4d \n " ,
2012-11-03 01:50:41 +04:00
si - > ndirty_dent , si - > ndirty_dirs ) ;
2014-01-13 05:34:18 +04:00
seq_printf ( s , " - meta: %4d in %4d \n " ,
2012-11-03 01:50:41 +04:00
si - > ndirty_meta , si - > meta_pages ) ;
2015-01-07 22:09:37 +03:00
seq_printf ( s , " - NATs: %9d/%9d \n - SITs: %9d/%9d \n " ,
si - > dirty_nats , si - > nats , si - > dirty_sits , si - > sits ) ;
2014-03-19 08:45:52 +04:00
seq_printf ( s , " - free_nids: %9d \n " ,
si - > fnids ) ;
2013-07-22 12:33:32 +04:00
seq_puts ( s , " \n Distribution of User Blocks: " ) ;
seq_puts ( s , " [ valid | invalid | free ] \n " ) ;
seq_puts ( s , " [ " ) ;
2012-11-03 01:50:41 +04:00
for ( j = 0 ; j < si - > util_valid ; j + + )
2013-07-22 12:33:32 +04:00
seq_putc ( s , ' - ' ) ;
seq_putc ( s , ' | ' ) ;
2012-11-03 01:50:41 +04:00
for ( j = 0 ; j < si - > util_invalid ; j + + )
2013-07-22 12:33:32 +04:00
seq_putc ( s , ' - ' ) ;
seq_putc ( s , ' | ' ) ;
2012-11-03 01:50:41 +04:00
for ( j = 0 ; j < si - > util_free ; j + + )
2013-07-22 12:33:32 +04:00
seq_putc ( s , ' - ' ) ;
seq_puts ( s , " ] \n \n " ) ;
2014-12-23 20:16:54 +03:00
seq_printf ( s , " IPU: %u blocks \n " , si - > inplace_count ) ;
2012-11-03 01:50:41 +04:00
seq_printf ( s , " SSR: %u blocks in %u segments \n " ,
si - > block_count [ SSR ] , si - > segment_count [ SSR ] ) ;
seq_printf ( s , " LFS: %u blocks in %u segments \n " ,
si - > block_count [ LFS ] , si - > segment_count [ LFS ] ) ;
/* segment usage info */
update_sit_info ( si - > sbi ) ;
seq_printf ( s , " \n BDF: %u, avg. vblocks: %u \n " ,
si - > bimodal , si - > avg_vblocks ) ;
/* memory footprint */
update_mem_info ( si - > sbi ) ;
seq_printf ( s , " \n Memory: %u KB = static: %u + cached: %u \n " ,
( si - > base_mem + si - > cache_mem ) > > 10 ,
si - > base_mem > > 10 , si - > cache_mem > > 10 ) ;
}
2013-01-14 16:08:16 +04:00
mutex_unlock ( & f2fs_stat_mutex ) ;
2012-11-03 01:50:41 +04:00
return 0 ;
}
static int stat_open ( struct inode * inode , struct file * file )
{
return single_open ( file , stat_show , inode - > i_private ) ;
}
static const struct file_operations stat_fops = {
. open = stat_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
2013-01-15 14:58:47 +04:00
int f2fs_build_stats ( struct f2fs_sb_info * sbi )
2012-11-03 01:50:41 +04:00
{
struct f2fs_super_block * raw_super = F2FS_RAW_SUPER ( sbi ) ;
struct f2fs_stat_info * si ;
2013-07-12 10:47:11 +04:00
si = kzalloc ( sizeof ( struct f2fs_stat_info ) , GFP_KERNEL ) ;
if ( ! si )
2012-11-03 01:50:41 +04:00
return - ENOMEM ;
si - > all_area_segs = le32_to_cpu ( raw_super - > segment_count ) ;
si - > sit_area_segs = le32_to_cpu ( raw_super - > segment_count_sit ) ;
si - > nat_area_segs = le32_to_cpu ( raw_super - > segment_count_nat ) ;
si - > ssa_area_segs = le32_to_cpu ( raw_super - > segment_count_ssa ) ;
si - > main_area_segs = le32_to_cpu ( raw_super - > segment_count_main ) ;
si - > main_area_sections = le32_to_cpu ( raw_super - > section_count ) ;
si - > main_area_zones = si - > main_area_sections /
le32_to_cpu ( raw_super - > secs_per_zone ) ;
si - > sbi = sbi ;
2013-07-12 10:47:11 +04:00
sbi - > stat_info = si ;
2013-01-14 16:08:16 +04:00
2014-12-08 14:08:20 +03:00
atomic_set ( & sbi - > inline_inode , 0 ) ;
atomic_set ( & sbi - > inline_dir , 0 ) ;
2014-12-23 20:16:54 +03:00
atomic_set ( & sbi - > inplace_count , 0 ) ;
2014-12-08 14:08:20 +03:00
2013-01-14 16:08:16 +04:00
mutex_lock ( & f2fs_stat_mutex ) ;
list_add_tail ( & si - > stat_list , & f2fs_stat_list ) ;
mutex_unlock ( & f2fs_stat_mutex ) ;
2012-11-03 01:50:41 +04:00
return 0 ;
}
void f2fs_destroy_stats ( struct f2fs_sb_info * sbi )
{
2013-07-12 10:47:11 +04:00
struct f2fs_stat_info * si = F2FS_STAT ( sbi ) ;
2012-11-03 01:50:41 +04:00
2013-01-14 16:08:16 +04:00
mutex_lock ( & f2fs_stat_mutex ) ;
2012-11-03 01:50:41 +04:00
list_del ( & si - > stat_list ) ;
2013-01-14 16:08:16 +04:00
mutex_unlock ( & f2fs_stat_mutex ) ;
2013-07-12 10:47:11 +04:00
kfree ( si ) ;
2012-11-03 01:50:41 +04:00
}
2013-01-15 14:58:47 +04:00
void __init f2fs_create_root_stats ( void )
{
2013-12-03 16:11:46 +04:00
struct dentry * file ;
2013-12-03 17:09:29 +04:00
f2fs_debugfs_root = debugfs_create_dir ( " f2fs " , NULL ) ;
if ( ! f2fs_debugfs_root )
2014-07-11 14:35:43 +04:00
return ;
2013-12-03 16:11:46 +04:00
2013-12-03 17:09:29 +04:00
file = debugfs_create_file ( " status " , S_IRUGO , f2fs_debugfs_root ,
2013-12-03 16:11:46 +04:00
NULL , & stat_fops ) ;
2014-07-11 14:35:43 +04:00
if ( ! file ) {
debugfs_remove ( f2fs_debugfs_root ) ;
f2fs_debugfs_root = NULL ;
}
2013-01-15 14:58:47 +04:00
}
void f2fs_destroy_root_stats ( void )
2012-11-03 01:50:41 +04:00
{
2013-12-03 17:09:29 +04:00
if ( ! f2fs_debugfs_root )
2013-12-03 16:11:46 +04:00
return ;
2013-12-03 17:09:29 +04:00
debugfs_remove_recursive ( f2fs_debugfs_root ) ;
f2fs_debugfs_root = NULL ;
2012-11-03 01:50:41 +04:00
}