f2fs: add page-order information for large folio reads in iostat

Track read folio counts by order in F2FS iostat sysfs and tracepoints.

Signed-off-by: Daniel Lee <chullee@google.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
Daniel Lee 2026-04-17 10:50:40 -07:00 committed by Jaegeuk Kim
parent 1583a7ded0
commit cb8ff3ead9
5 changed files with 65 additions and 5 deletions

View File

@ -2508,6 +2508,8 @@ static int f2fs_read_data_large_folio(struct inode *inode,
if (!folio) if (!folio)
goto out; goto out;
f2fs_update_read_folio_count(F2FS_I_SB(inode), folio);
folio_in_bio = false; folio_in_bio = false;
index = folio->index; index = folio->index;
offset = 0; offset = 0;
@ -2682,6 +2684,8 @@ static int f2fs_mpage_readpages(struct inode *inode, struct fsverity_info *vi,
prefetchw(&folio->flags); prefetchw(&folio->flags);
} }
f2fs_update_read_folio_count(F2FS_I_SB(inode), folio);
#ifdef CONFIG_F2FS_FS_COMPRESSION #ifdef CONFIG_F2FS_FS_COMPRESSION
index = folio->index; index = folio->index;

View File

@ -10,6 +10,7 @@
#include <linux/uio.h> #include <linux/uio.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/mmzone.h>
#include <linux/page-flags.h> #include <linux/page-flags.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/crc32.h> #include <linux/crc32.h>
@ -2034,6 +2035,8 @@ struct f2fs_sb_info {
unsigned long long iostat_count[NR_IO_TYPE]; unsigned long long iostat_count[NR_IO_TYPE];
unsigned long long iostat_bytes[NR_IO_TYPE]; unsigned long long iostat_bytes[NR_IO_TYPE];
unsigned long long prev_iostat_bytes[NR_IO_TYPE]; unsigned long long prev_iostat_bytes[NR_IO_TYPE];
unsigned long long iostat_read_folio_count[NR_PAGE_ORDERS];
unsigned long long prev_iostat_read_folio_count[NR_PAGE_ORDERS];
bool iostat_enable; bool iostat_enable;
unsigned long iostat_next_period; unsigned long iostat_next_period;
unsigned int iostat_period_ms; unsigned int iostat_period_ms;

View File

@ -34,6 +34,7 @@ int __maybe_unused iostat_info_seq_show(struct seq_file *seq, void *offset)
{ {
struct super_block *sb = seq->private; struct super_block *sb = seq->private;
struct f2fs_sb_info *sbi = F2FS_SB(sb); struct f2fs_sb_info *sbi = F2FS_SB(sb);
int i;
if (!sbi->iostat_enable) if (!sbi->iostat_enable)
return 0; return 0;
@ -76,6 +77,12 @@ int __maybe_unused iostat_info_seq_show(struct seq_file *seq, void *offset)
IOSTAT_INFO_SHOW("fs node", FS_NODE_READ_IO); IOSTAT_INFO_SHOW("fs node", FS_NODE_READ_IO);
IOSTAT_INFO_SHOW("fs meta", FS_META_READ_IO); IOSTAT_INFO_SHOW("fs meta", FS_META_READ_IO);
/* print read folio order stats */
seq_printf(seq, "%-23s", "fs read folio order:");
for (i = 0; i < NR_PAGE_ORDERS; i++)
seq_printf(seq, " %llu", sbi->iostat_read_folio_count[i]);
seq_putc(seq, '\n');
/* print other IOs */ /* print other IOs */
seq_puts(seq, "[OTHER]\n"); seq_puts(seq, "[OTHER]\n");
IOSTAT_INFO_SHOW("fs discard", FS_DISCARD_IO); IOSTAT_INFO_SHOW("fs discard", FS_DISCARD_IO);
@ -113,6 +120,7 @@ static inline void __record_iostat_latency(struct f2fs_sb_info *sbi)
static inline void f2fs_record_iostat(struct f2fs_sb_info *sbi) static inline void f2fs_record_iostat(struct f2fs_sb_info *sbi)
{ {
unsigned long long iostat_diff[NR_IO_TYPE]; unsigned long long iostat_diff[NR_IO_TYPE];
unsigned long long read_folio_count_diff[NR_PAGE_ORDERS];
int i; int i;
unsigned long flags; unsigned long flags;
@ -133,9 +141,15 @@ static inline void f2fs_record_iostat(struct f2fs_sb_info *sbi)
sbi->prev_iostat_bytes[i]; sbi->prev_iostat_bytes[i];
sbi->prev_iostat_bytes[i] = sbi->iostat_bytes[i]; sbi->prev_iostat_bytes[i] = sbi->iostat_bytes[i];
} }
for (i = 0; i < NR_PAGE_ORDERS; i++) {
read_folio_count_diff[i] = sbi->iostat_read_folio_count[i] -
sbi->prev_iostat_read_folio_count[i];
sbi->prev_iostat_read_folio_count[i] = sbi->iostat_read_folio_count[i];
}
spin_unlock_irqrestore(&sbi->iostat_lock, flags); spin_unlock_irqrestore(&sbi->iostat_lock, flags);
trace_f2fs_iostat(sbi, iostat_diff); trace_f2fs_iostat(sbi, iostat_diff, read_folio_count_diff);
__record_iostat_latency(sbi); __record_iostat_latency(sbi);
} }
@ -151,6 +165,10 @@ void f2fs_reset_iostat(struct f2fs_sb_info *sbi)
sbi->iostat_bytes[i] = 0; sbi->iostat_bytes[i] = 0;
sbi->prev_iostat_bytes[i] = 0; sbi->prev_iostat_bytes[i] = 0;
} }
for (i = 0; i < NR_PAGE_ORDERS; i++) {
sbi->iostat_read_folio_count[i] = 0;
sbi->prev_iostat_read_folio_count[i] = 0;
}
spin_unlock_irq(&sbi->iostat_lock); spin_unlock_irq(&sbi->iostat_lock);
spin_lock_irq(&sbi->iostat_lat_lock); spin_lock_irq(&sbi->iostat_lat_lock);
@ -165,6 +183,24 @@ static inline void __f2fs_update_iostat(struct f2fs_sb_info *sbi,
sbi->iostat_count[type]++; sbi->iostat_count[type]++;
} }
void f2fs_update_read_folio_count(struct f2fs_sb_info *sbi, struct folio *folio)
{
unsigned int order = folio_order(folio);
unsigned long flags;
if (!sbi->iostat_enable)
return;
if (order >= NR_PAGE_ORDERS)
order = NR_PAGE_ORDERS - 1;
spin_lock_irqsave(&sbi->iostat_lock, flags);
sbi->iostat_read_folio_count[order]++;
spin_unlock_irqrestore(&sbi->iostat_lock, flags);
f2fs_record_iostat(sbi);
}
void f2fs_update_iostat(struct f2fs_sb_info *sbi, struct inode *inode, void f2fs_update_iostat(struct f2fs_sb_info *sbi, struct inode *inode,
enum iostat_type type, unsigned long long io_bytes) enum iostat_type type, unsigned long long io_bytes)
{ {

View File

@ -34,6 +34,8 @@ extern int __maybe_unused iostat_info_seq_show(struct seq_file *seq,
extern void f2fs_reset_iostat(struct f2fs_sb_info *sbi); extern void f2fs_reset_iostat(struct f2fs_sb_info *sbi);
extern void f2fs_update_iostat(struct f2fs_sb_info *sbi, struct inode *inode, extern void f2fs_update_iostat(struct f2fs_sb_info *sbi, struct inode *inode,
enum iostat_type type, unsigned long long io_bytes); enum iostat_type type, unsigned long long io_bytes);
extern void f2fs_update_read_folio_count(struct f2fs_sb_info *sbi,
struct folio *folio);
struct bio_iostat_ctx { struct bio_iostat_ctx {
struct f2fs_sb_info *sbi; struct f2fs_sb_info *sbi;
@ -68,6 +70,8 @@ extern void f2fs_destroy_iostat(struct f2fs_sb_info *sbi);
#else #else
static inline void f2fs_update_iostat(struct f2fs_sb_info *sbi, struct inode *inode, static inline void f2fs_update_iostat(struct f2fs_sb_info *sbi, struct inode *inode,
enum iostat_type type, unsigned long long io_bytes) {} enum iostat_type type, unsigned long long io_bytes) {}
static inline void f2fs_update_read_folio_count(struct f2fs_sb_info *sbi,
struct folio *folio) {}
static inline void iostat_update_and_unbind_ctx(struct bio *bio) {} static inline void iostat_update_and_unbind_ctx(struct bio *bio) {}
static inline void iostat_alloc_and_bind_ctx(struct f2fs_sb_info *sbi, static inline void iostat_alloc_and_bind_ctx(struct f2fs_sb_info *sbi,
struct bio *bio, struct bio_post_read_ctx *ctx) {} struct bio *bio, struct bio_post_read_ctx *ctx) {}

View File

@ -2116,9 +2116,10 @@ DEFINE_EVENT(f2fs_zip_end, f2fs_decompress_pages_end,
#ifdef CONFIG_F2FS_IOSTAT #ifdef CONFIG_F2FS_IOSTAT
TRACE_EVENT(f2fs_iostat, TRACE_EVENT(f2fs_iostat,
TP_PROTO(struct f2fs_sb_info *sbi, unsigned long long *iostat), TP_PROTO(struct f2fs_sb_info *sbi, unsigned long long *iostat,
unsigned long long *read_folio_count),
TP_ARGS(sbi, iostat), TP_ARGS(sbi, iostat, read_folio_count),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(dev_t, dev) __field(dev_t, dev)
@ -2150,6 +2151,7 @@ TRACE_EVENT(f2fs_iostat,
__field(unsigned long long, fs_mrio) __field(unsigned long long, fs_mrio)
__field(unsigned long long, fs_discard) __field(unsigned long long, fs_discard)
__field(unsigned long long, fs_reset_zone) __field(unsigned long long, fs_reset_zone)
__array(unsigned long long, read_folio_count, 11)
), ),
TP_fast_assign( TP_fast_assign(
@ -2182,6 +2184,9 @@ TRACE_EVENT(f2fs_iostat,
__entry->fs_mrio = iostat[FS_META_READ_IO]; __entry->fs_mrio = iostat[FS_META_READ_IO];
__entry->fs_discard = iostat[FS_DISCARD_IO]; __entry->fs_discard = iostat[FS_DISCARD_IO];
__entry->fs_reset_zone = iostat[FS_ZONE_RESET_IO]; __entry->fs_reset_zone = iostat[FS_ZONE_RESET_IO];
memset(__entry->read_folio_count, 0, sizeof(__entry->read_folio_count));
memcpy(__entry->read_folio_count, read_folio_count,
sizeof(unsigned long long) * min_t(int, NR_PAGE_ORDERS, 11));
), ),
TP_printk("dev = (%d,%d), " TP_printk("dev = (%d,%d), "
@ -2194,7 +2199,9 @@ TRACE_EVENT(f2fs_iostat,
"app [read=%llu (direct=%llu, buffered=%llu), mapped=%llu], " "app [read=%llu (direct=%llu, buffered=%llu), mapped=%llu], "
"compr(buffered=%llu, mapped=%llu)], " "compr(buffered=%llu, mapped=%llu)], "
"fs [data=%llu, (gc_data=%llu, cdata=%llu), " "fs [data=%llu, (gc_data=%llu, cdata=%llu), "
"node=%llu, meta=%llu]", "node=%llu, meta=%llu], "
"read_folio_count [0=%llu, 1=%llu, 2=%llu, 3=%llu, 4=%llu, "
"5=%llu, 6=%llu, 7=%llu, 8=%llu, 9=%llu, 10=%llu]",
show_dev(__entry->dev), __entry->app_wio, __entry->app_dio, show_dev(__entry->dev), __entry->app_wio, __entry->app_dio,
__entry->app_bio, __entry->app_mio, __entry->app_bcdio, __entry->app_bio, __entry->app_mio, __entry->app_bcdio,
__entry->app_mcdio, __entry->fs_dio, __entry->fs_cdio, __entry->app_mcdio, __entry->fs_dio, __entry->fs_cdio,
@ -2205,7 +2212,13 @@ TRACE_EVENT(f2fs_iostat,
__entry->app_rio, __entry->app_drio, __entry->app_brio, __entry->app_rio, __entry->app_drio, __entry->app_brio,
__entry->app_mrio, __entry->app_bcrio, __entry->app_mcrio, __entry->app_mrio, __entry->app_bcrio, __entry->app_mcrio,
__entry->fs_drio, __entry->fs_gdrio, __entry->fs_drio, __entry->fs_gdrio,
__entry->fs_cdrio, __entry->fs_nrio, __entry->fs_mrio) __entry->fs_cdrio, __entry->fs_nrio, __entry->fs_mrio,
__entry->read_folio_count[0], __entry->read_folio_count[1],
__entry->read_folio_count[2], __entry->read_folio_count[3],
__entry->read_folio_count[4], __entry->read_folio_count[5],
__entry->read_folio_count[6], __entry->read_folio_count[7],
__entry->read_folio_count[8], __entry->read_folio_count[9],
__entry->read_folio_count[10])
); );
#ifndef __F2FS_IOSTAT_LATENCY_TYPE #ifndef __F2FS_IOSTAT_LATENCY_TYPE