This patch adds per-device stats in debugfs, the examples
are as below:

mkfs.f2fs -f -c /dev/vdc /dev/vdb
mount /dev/vdb /mnt/f2fs/
cat /sys/kernel/debug/f2fs/status

Multidevice stats:
  [seg:      inuse    dirty     full     free  prefree]
  #0             5        0        0     4007        0
  #1             1        0        0     8191        0

mkfs.f2fs -f -s 2 -c /dev/vdc /dev/vdb
mount /dev/vdb /mnt/f2fs
cat /sys/kernel/debug/f2fs/status

Multidevice stats:
  [seg:      inuse    dirty     full     free  prefree] [sec:      inuse    
dirty     full     free  prefree]
  #0             5        0        0     4005        0                 5        
0        0     2000        0
  #1             1        0        0     8191        0                 1        
0        0     4095        0

Signed-off-by: Chao Yu <c...@kernel.org>
---
 fs/f2fs/debug.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++
 fs/f2fs/f2fs.h  |  14 +++++++
 2 files changed, 121 insertions(+)

diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
index 546b8ba91261..278c8855ac0a 100644
--- a/fs/f2fs/debug.c
+++ b/fs/f2fs/debug.c
@@ -60,6 +60,70 @@ void f2fs_update_sit_info(struct f2fs_sb_info *sbi)
 }
 
 #ifdef CONFIG_DEBUG_FS
+static void update_multidevice_stats(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_stat_info *si = F2FS_STAT(sbi);
+       struct f2fs_dev_stats *dev_stats = si->dev_stats;
+       int i, j;
+
+       if (!f2fs_is_multi_device(sbi))
+               return;
+
+       memset(dev_stats, 0, sizeof(struct f2fs_dev_stats) * sbi->s_ndevs);
+       for (i = 0; i < sbi->s_ndevs; i++) {
+               unsigned int start_segno, end_segno;
+               block_t start_blk, end_blk;
+
+               if (i == 0) {
+                       start_blk = MAIN_BLKADDR(sbi);
+                       end_blk = FDEV(i).end_blk + 1 - SEG0_BLKADDR(sbi);
+               } else {
+                       start_blk = FDEV(i).start_blk;
+                       end_blk = FDEV(i).end_blk + 1;
+               }
+
+               start_segno = GET_SEGNO(sbi, start_blk);
+               end_segno = GET_SEGNO(sbi, end_blk);
+
+               for (j = start_segno; j < end_segno; j++) {
+                       unsigned int seg_blks, sec_blks;
+
+                       seg_blks = get_seg_entry(sbi, j)->valid_blocks;
+
+                       /* update segment stats */
+                       if (IS_CURSEG(sbi, j))
+                               dev_stats[i].devstats[0][DEVSTAT_INUSE]++;
+                       else if (seg_blks == BLKS_PER_SEG(sbi))
+                               dev_stats[i].devstats[0][DEVSTAT_FULL]++;
+                       else if (seg_blks != 0)
+                               dev_stats[i].devstats[0][DEVSTAT_DIRTY]++;
+                       else if (!test_bit(j, FREE_I(sbi)->free_segmap))
+                               dev_stats[i].devstats[0][DEVSTAT_FREE]++;
+                       else
+                               dev_stats[i].devstats[0][DEVSTAT_PREFREE]++;
+
+                       if (!__is_large_section(sbi) ||
+                               (j % SEGS_PER_SEC(sbi)) != 0)
+                               continue;
+
+                       sec_blks = get_sec_entry(sbi, j)->valid_blocks;
+
+                       /* update section stats */
+                       if (IS_CURSEC(sbi, GET_SEC_FROM_SEG(sbi, j)))
+                               dev_stats[i].devstats[1][DEVSTAT_INUSE]++;
+                       else if (sec_blks == BLKS_PER_SEC(sbi))
+                               dev_stats[i].devstats[1][DEVSTAT_FULL]++;
+                       else if (sec_blks != 0)
+                               dev_stats[i].devstats[1][DEVSTAT_DIRTY]++;
+                       else if (!test_bit(GET_SEC_FROM_SEG(sbi, j),
+                                       FREE_I(sbi)->free_secmap))
+                               dev_stats[i].devstats[1][DEVSTAT_FREE]++;
+                       else
+                               dev_stats[i].devstats[1][DEVSTAT_PREFREE]++;
+               }
+       }
+}
+
 static void update_general_status(struct f2fs_sb_info *sbi)
 {
        struct f2fs_stat_info *si = F2FS_STAT(sbi);
@@ -214,6 +278,8 @@ static void update_general_status(struct f2fs_sb_info *sbi)
                si->valid_blks[type] += blks;
        }
 
+       update_multidevice_stats(sbi);
+
        for (i = 0; i < MAX_CALL_TYPE; i++)
                si->cp_call_count[i] = atomic_read(&sbi->cp_call_count[i]);
 
@@ -498,6 +564,36 @@ static int stat_show(struct seq_file *s, void *v)
                           si->dirty_count);
                seq_printf(s, "  - Prefree: %d\n  - Free: %d (%d)\n\n",
                           si->prefree_count, si->free_segs, si->free_secs);
+               if (f2fs_is_multi_device(sbi)) {
+                       seq_puts(s, "Multidevice stats:\n");
+                       seq_printf(s, "  [seg:   %8s %8s %8s %8s %8s]",
+                                       "inuse", "dirty", "full", "free", 
"prefree");
+                       if (__is_large_section(sbi))
+                               seq_printf(s, " [sec:   %8s %8s %8s %8s %8s]\n",
+                                       "inuse", "dirty", "full", "free", 
"prefree");
+                       else
+                               seq_puts(s, "\n");
+
+                       for (i = 0; i < sbi->s_ndevs; i++) {
+                               seq_printf(s, "  #%-2d     %8u %8u %8u %8u 
%8u", i,
+                                       
si->dev_stats[i].devstats[0][DEVSTAT_INUSE],
+                                       
si->dev_stats[i].devstats[0][DEVSTAT_DIRTY],
+                                       
si->dev_stats[i].devstats[0][DEVSTAT_FULL],
+                                       
si->dev_stats[i].devstats[0][DEVSTAT_FREE],
+                                       
si->dev_stats[i].devstats[0][DEVSTAT_PREFREE]);
+                               if (!__is_large_section(sbi)) {
+                                       seq_puts(s, "\n");
+                                       continue;
+                               }
+                               seq_printf(s, "          %8u %8u %8u %8u %8u\n",
+                                       
si->dev_stats[i].devstats[1][DEVSTAT_INUSE],
+                                       
si->dev_stats[i].devstats[1][DEVSTAT_DIRTY],
+                                       
si->dev_stats[i].devstats[1][DEVSTAT_FULL],
+                                       
si->dev_stats[i].devstats[1][DEVSTAT_FREE],
+                                       
si->dev_stats[i].devstats[1][DEVSTAT_PREFREE]);
+                       }
+                       seq_puts(s, "\n");
+               }
                seq_printf(s, "CP calls: %d (BG: %d)\n",
                           si->cp_call_count[TOTAL_CALL],
                           si->cp_call_count[BACKGROUND]);
@@ -665,6 +761,7 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
 {
        struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
        struct f2fs_stat_info *si;
+       struct f2fs_dev_stats *dev_stats;
        unsigned long flags;
        int i;
 
@@ -672,6 +769,15 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
        if (!si)
                return -ENOMEM;
 
+       dev_stats = f2fs_kzalloc(sbi, sizeof(struct f2fs_dev_stats) *
+                                               sbi->s_ndevs, GFP_KERNEL);
+       if (!dev_stats) {
+               kfree(si);
+               return -ENOMEM;
+       }
+
+       si->dev_stats = dev_stats;
+
        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);
@@ -724,6 +830,7 @@ void f2fs_destroy_stats(struct f2fs_sb_info *sbi)
        list_del(&si->stat_list);
        raw_spin_unlock_irqrestore(&f2fs_stat_lock, flags);
 
+       kfree(si->dev_stats);
        kfree(si);
 }
 
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index bda61d7ca8dd..56797f8e6659 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3942,6 +3942,19 @@ void f2fs_destroy_recovery_cache(void);
  * debug.c
  */
 #ifdef CONFIG_F2FS_STAT_FS
+enum {
+       DEVSTAT_INUSE,
+       DEVSTAT_DIRTY,
+       DEVSTAT_FULL,
+       DEVSTAT_FREE,
+       DEVSTAT_PREFREE,
+       DEVSTAT_MAX,
+};
+
+struct f2fs_dev_stats {
+       unsigned int devstats[2][DEVSTAT_MAX];          /* 0: segs, 1: secs */
+};
+
 struct f2fs_stat_info {
        struct list_head stat_list;
        struct f2fs_sb_info *sbi;
@@ -4005,6 +4018,7 @@ struct f2fs_stat_info {
        unsigned int block_count[2];
        unsigned int inplace_count;
        unsigned long long base_mem, cache_mem, page_mem;
+       struct f2fs_dev_stats *dev_stats;
 };
 
 static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi)
-- 
2.40.1



_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to