Commit b0af6d49 authored by Chao Yu's avatar Chao Yu Committed by Jaegeuk Kim

f2fs: add app/fs io stat

This patch enables inner app/fs io stats and introduces below virtual fs
nodes for exposing stats info:
/sys/fs/f2fs/<dev>/iostat_enable
/proc/fs/f2fs/<dev>/iostat_info
Signed-off-by: default avatarChao Yu <yuchao0@huawei.com>
[Jaegeuk Kim: fix wrong stat assignment]
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 35ee82ca
...@@ -230,8 +230,9 @@ void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index) ...@@ -230,8 +230,9 @@ void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index)
ra_meta_pages(sbi, index, BIO_MAX_PAGES, META_POR, true); ra_meta_pages(sbi, index, BIO_MAX_PAGES, META_POR, true);
} }
static int f2fs_write_meta_page(struct page *page, static int __f2fs_write_meta_page(struct page *page,
struct writeback_control *wbc) struct writeback_control *wbc,
enum iostat_type io_type)
{ {
struct f2fs_sb_info *sbi = F2FS_P_SB(page); struct f2fs_sb_info *sbi = F2FS_P_SB(page);
...@@ -244,7 +245,7 @@ static int f2fs_write_meta_page(struct page *page, ...@@ -244,7 +245,7 @@ static int f2fs_write_meta_page(struct page *page,
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi)))
goto redirty_out; goto redirty_out;
write_meta_page(sbi, page); write_meta_page(sbi, page, io_type);
dec_page_count(sbi, F2FS_DIRTY_META); dec_page_count(sbi, F2FS_DIRTY_META);
if (wbc->for_reclaim) if (wbc->for_reclaim)
...@@ -263,6 +264,12 @@ static int f2fs_write_meta_page(struct page *page, ...@@ -263,6 +264,12 @@ static int f2fs_write_meta_page(struct page *page,
return AOP_WRITEPAGE_ACTIVATE; return AOP_WRITEPAGE_ACTIVATE;
} }
static int f2fs_write_meta_page(struct page *page,
struct writeback_control *wbc)
{
return __f2fs_write_meta_page(page, wbc, FS_META_IO);
}
static int f2fs_write_meta_pages(struct address_space *mapping, static int f2fs_write_meta_pages(struct address_space *mapping,
struct writeback_control *wbc) struct writeback_control *wbc)
{ {
...@@ -283,7 +290,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping, ...@@ -283,7 +290,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
trace_f2fs_writepages(mapping->host, wbc, META); trace_f2fs_writepages(mapping->host, wbc, META);
diff = nr_pages_to_write(sbi, META, wbc); diff = nr_pages_to_write(sbi, META, wbc);
written = sync_meta_pages(sbi, META, wbc->nr_to_write); written = sync_meta_pages(sbi, META, wbc->nr_to_write, FS_META_IO);
mutex_unlock(&sbi->cp_mutex); mutex_unlock(&sbi->cp_mutex);
wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff); wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff);
return 0; return 0;
...@@ -295,7 +302,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping, ...@@ -295,7 +302,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
} }
long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
long nr_to_write) long nr_to_write, enum iostat_type io_type)
{ {
struct address_space *mapping = META_MAPPING(sbi); struct address_space *mapping = META_MAPPING(sbi);
pgoff_t index = 0, end = ULONG_MAX, prev = ULONG_MAX; pgoff_t index = 0, end = ULONG_MAX, prev = ULONG_MAX;
...@@ -346,7 +353,7 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, ...@@ -346,7 +353,7 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
if (!clear_page_dirty_for_io(page)) if (!clear_page_dirty_for_io(page))
goto continue_unlock; goto continue_unlock;
if (mapping->a_ops->writepage(page, &wbc)) { if (__f2fs_write_meta_page(page, &wbc, io_type)) {
unlock_page(page); unlock_page(page);
break; break;
} }
...@@ -904,7 +911,14 @@ int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type) ...@@ -904,7 +911,14 @@ int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)
if (inode) { if (inode) {
unsigned long cur_ino = inode->i_ino; unsigned long cur_ino = inode->i_ino;
if (is_dir)
F2FS_I(inode)->cp_task = current;
filemap_fdatawrite(inode->i_mapping); filemap_fdatawrite(inode->i_mapping);
if (is_dir)
F2FS_I(inode)->cp_task = NULL;
iput(inode); iput(inode);
/* We need to give cpu to another writers. */ /* We need to give cpu to another writers. */
if (ino == cur_ino) { if (ino == cur_ino) {
...@@ -1017,7 +1031,7 @@ static int block_operations(struct f2fs_sb_info *sbi) ...@@ -1017,7 +1031,7 @@ static int block_operations(struct f2fs_sb_info *sbi)
if (get_pages(sbi, F2FS_DIRTY_NODES)) { if (get_pages(sbi, F2FS_DIRTY_NODES)) {
up_write(&sbi->node_write); up_write(&sbi->node_write);
err = sync_node_pages(sbi, &wbc, false); err = sync_node_pages(sbi, &wbc, false, FS_CP_NODE_IO);
if (err) { if (err) {
up_write(&sbi->node_change); up_write(&sbi->node_change);
f2fs_unlock_all(sbi); f2fs_unlock_all(sbi);
...@@ -1115,7 +1129,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1115,7 +1129,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
/* Flush all the NAT/SIT pages */ /* Flush all the NAT/SIT pages */
while (get_pages(sbi, F2FS_DIRTY_META)) { while (get_pages(sbi, F2FS_DIRTY_META)) {
sync_meta_pages(sbi, META, LONG_MAX); sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi)))
return -EIO; return -EIO;
} }
...@@ -1194,7 +1208,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1194,7 +1208,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
/* Flush all the NAT BITS pages */ /* Flush all the NAT BITS pages */
while (get_pages(sbi, F2FS_DIRTY_META)) { while (get_pages(sbi, F2FS_DIRTY_META)) {
sync_meta_pages(sbi, META, LONG_MAX); sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi)))
return -EIO; return -EIO;
} }
...@@ -1249,7 +1263,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1249,7 +1263,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
percpu_counter_set(&sbi->alloc_valid_block_count, 0); percpu_counter_set(&sbi->alloc_valid_block_count, 0);
/* Here, we only have one bio having CP pack */ /* Here, we only have one bio having CP pack */
sync_meta_pages(sbi, META_FLUSH, LONG_MAX); sync_meta_pages(sbi, META_FLUSH, LONG_MAX, FS_CP_META_IO);
/* wait for previous submitted meta pages writeback */ /* wait for previous submitted meta pages writeback */
wait_on_all_pages_writeback(sbi); wait_on_all_pages_writeback(sbi);
......
...@@ -1475,7 +1475,8 @@ int do_write_data_page(struct f2fs_io_info *fio) ...@@ -1475,7 +1475,8 @@ int do_write_data_page(struct f2fs_io_info *fio)
} }
static int __write_data_page(struct page *page, bool *submitted, static int __write_data_page(struct page *page, bool *submitted,
struct writeback_control *wbc) struct writeback_control *wbc,
enum iostat_type io_type)
{ {
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
...@@ -1496,6 +1497,7 @@ static int __write_data_page(struct page *page, bool *submitted, ...@@ -1496,6 +1497,7 @@ static int __write_data_page(struct page *page, bool *submitted,
.encrypted_page = NULL, .encrypted_page = NULL,
.submitted = false, .submitted = false,
.need_lock = LOCK_RETRY, .need_lock = LOCK_RETRY,
.io_type = io_type,
}; };
trace_f2fs_writepage(page, DATA); trace_f2fs_writepage(page, DATA);
...@@ -1602,7 +1604,7 @@ static int __write_data_page(struct page *page, bool *submitted, ...@@ -1602,7 +1604,7 @@ static int __write_data_page(struct page *page, bool *submitted,
static int f2fs_write_data_page(struct page *page, static int f2fs_write_data_page(struct page *page,
struct writeback_control *wbc) struct writeback_control *wbc)
{ {
return __write_data_page(page, NULL, wbc); return __write_data_page(page, NULL, wbc, FS_DATA_IO);
} }
/* /*
...@@ -1611,7 +1613,8 @@ static int f2fs_write_data_page(struct page *page, ...@@ -1611,7 +1613,8 @@ static int f2fs_write_data_page(struct page *page,
* warm/hot data page. * warm/hot data page.
*/ */
static int f2fs_write_cache_pages(struct address_space *mapping, static int f2fs_write_cache_pages(struct address_space *mapping,
struct writeback_control *wbc) struct writeback_control *wbc,
enum iostat_type io_type)
{ {
int ret = 0; int ret = 0;
int done = 0; int done = 0;
...@@ -1701,7 +1704,7 @@ static int f2fs_write_cache_pages(struct address_space *mapping, ...@@ -1701,7 +1704,7 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
if (!clear_page_dirty_for_io(page)) if (!clear_page_dirty_for_io(page))
goto continue_unlock; goto continue_unlock;
ret = __write_data_page(page, &submitted, wbc); ret = __write_data_page(page, &submitted, wbc, io_type);
if (unlikely(ret)) { if (unlikely(ret)) {
/* /*
* keep nr_to_write, since vfs uses this to * keep nr_to_write, since vfs uses this to
...@@ -1756,8 +1759,9 @@ static int f2fs_write_cache_pages(struct address_space *mapping, ...@@ -1756,8 +1759,9 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
return ret; return ret;
} }
static int f2fs_write_data_pages(struct address_space *mapping, int __f2fs_write_data_pages(struct address_space *mapping,
struct writeback_control *wbc) struct writeback_control *wbc,
enum iostat_type io_type)
{ {
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
...@@ -1794,7 +1798,7 @@ static int f2fs_write_data_pages(struct address_space *mapping, ...@@ -1794,7 +1798,7 @@ static int f2fs_write_data_pages(struct address_space *mapping,
goto skip_write; goto skip_write;
blk_start_plug(&plug); blk_start_plug(&plug);
ret = f2fs_write_cache_pages(mapping, wbc); ret = f2fs_write_cache_pages(mapping, wbc, io_type);
blk_finish_plug(&plug); blk_finish_plug(&plug);
if (wbc->sync_mode == WB_SYNC_ALL) if (wbc->sync_mode == WB_SYNC_ALL)
...@@ -1813,6 +1817,16 @@ static int f2fs_write_data_pages(struct address_space *mapping, ...@@ -1813,6 +1817,16 @@ static int f2fs_write_data_pages(struct address_space *mapping,
return 0; return 0;
} }
static int f2fs_write_data_pages(struct address_space *mapping,
struct writeback_control *wbc)
{
struct inode *inode = mapping->host;
return __f2fs_write_data_pages(mapping, wbc,
F2FS_I(inode)->cp_task == current ?
FS_CP_DATA_IO : FS_DATA_IO);
}
static void f2fs_write_failed(struct address_space *mapping, loff_t to) static void f2fs_write_failed(struct address_space *mapping, loff_t to)
{ {
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
...@@ -2079,10 +2093,13 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ...@@ -2079,10 +2093,13 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
up_read(&F2FS_I(inode)->dio_rwsem[rw]); up_read(&F2FS_I(inode)->dio_rwsem[rw]);
if (rw == WRITE) { if (rw == WRITE) {
if (err > 0) if (err > 0) {
f2fs_update_iostat(F2FS_I_SB(inode), APP_DIRECT_IO,
err);
set_inode_flag(inode, FI_UPDATE_WRITE); set_inode_flag(inode, FI_UPDATE_WRITE);
else if (err < 0) } else if (err < 0) {
f2fs_write_failed(mapping, offset + count); f2fs_write_failed(mapping, offset + count);
}
} }
trace_f2fs_direct_IO_exit(inode, offset, count, rw, err); trace_f2fs_direct_IO_exit(inode, offset, count, rw, err);
......
...@@ -557,6 +557,7 @@ struct f2fs_inode_info { ...@@ -557,6 +557,7 @@ struct f2fs_inode_info {
f2fs_hash_t chash; /* hash value of given file name */ f2fs_hash_t chash; /* hash value of given file name */
unsigned int clevel; /* maximum level of given file name */ unsigned int clevel; /* maximum level of given file name */
struct task_struct *task; /* lookup and create consistency */ struct task_struct *task; /* lookup and create consistency */
struct task_struct *cp_task; /* separate cp/wb IO stats*/
nid_t i_xattr_nid; /* node id that contains xattrs */ nid_t i_xattr_nid; /* node id that contains xattrs */
loff_t last_disk_size; /* lastly written file size */ loff_t last_disk_size; /* lastly written file size */
...@@ -863,6 +864,23 @@ enum need_lock_type { ...@@ -863,6 +864,23 @@ enum need_lock_type {
LOCK_RETRY, LOCK_RETRY,
}; };
enum iostat_type {
APP_DIRECT_IO, /* app direct IOs */
APP_BUFFERED_IO, /* app buffered IOs */
APP_WRITE_IO, /* app write IOs */
APP_MAPPED_IO, /* app mapped IOs */
FS_DATA_IO, /* data IOs from kworker/fsync/reclaimer */
FS_NODE_IO, /* node IOs from kworker/fsync/reclaimer */
FS_META_IO, /* meta IOs from kworker/reclaimer */
FS_GC_DATA_IO, /* data IOs from forground gc */
FS_GC_NODE_IO, /* node IOs from forground gc */
FS_CP_DATA_IO, /* data IOs from checkpoint */
FS_CP_NODE_IO, /* node IOs from checkpoint */
FS_CP_META_IO, /* meta IOs from checkpoint */
FS_DISCARD, /* discard */
NR_IO_TYPE,
};
struct f2fs_io_info { struct f2fs_io_info {
struct f2fs_sb_info *sbi; /* f2fs_sb_info pointer */ struct f2fs_sb_info *sbi; /* f2fs_sb_info pointer */
enum page_type type; /* contains DATA/NODE/META/META_FLUSH */ enum page_type type; /* contains DATA/NODE/META/META_FLUSH */
...@@ -877,6 +895,7 @@ struct f2fs_io_info { ...@@ -877,6 +895,7 @@ struct f2fs_io_info {
bool submitted; /* indicate IO submission */ bool submitted; /* indicate IO submission */
int need_lock; /* indicate we need to lock cp_rwsem */ int need_lock; /* indicate we need to lock cp_rwsem */
bool in_list; /* indicate fio is in io_list */ bool in_list; /* indicate fio is in io_list */
enum iostat_type io_type; /* io type */
}; };
#define is_read_io(rw) ((rw) == READ) #define is_read_io(rw) ((rw) == READ)
...@@ -1068,6 +1087,11 @@ struct f2fs_sb_info { ...@@ -1068,6 +1087,11 @@ struct f2fs_sb_info {
#endif #endif
spinlock_t stat_lock; /* lock for stat operations */ spinlock_t stat_lock; /* lock for stat operations */
/* For app/fs IO statistics */
spinlock_t iostat_lock;
unsigned long long write_iostat[NR_IO_TYPE];
bool iostat_enable;
/* For sysfs suppport */ /* For sysfs suppport */
struct kobject s_kobj; struct kobject s_kobj;
struct completion s_kobj_unregister; struct completion s_kobj_unregister;
...@@ -2291,6 +2315,31 @@ static inline int get_extra_isize(struct inode *inode) ...@@ -2291,6 +2315,31 @@ static inline int get_extra_isize(struct inode *inode)
sizeof((f2fs_inode)->field)) \ sizeof((f2fs_inode)->field)) \
<= (F2FS_OLD_ATTRIBUTE_SIZE + extra_isize)) \ <= (F2FS_OLD_ATTRIBUTE_SIZE + extra_isize)) \
static inline void f2fs_reset_iostat(struct f2fs_sb_info *sbi)
{
int i;
spin_lock(&sbi->iostat_lock);
for (i = 0; i < NR_IO_TYPE; i++)
sbi->write_iostat[i] = 0;
spin_unlock(&sbi->iostat_lock);
}
static inline void f2fs_update_iostat(struct f2fs_sb_info *sbi,
enum iostat_type type, unsigned long long io_bytes)
{
if (!sbi->iostat_enable)
return;
spin_lock(&sbi->iostat_lock);
sbi->write_iostat[type] += io_bytes;
if (type == APP_WRITE_IO || type == APP_DIRECT_IO)
sbi->write_iostat[APP_BUFFERED_IO] =
sbi->write_iostat[APP_WRITE_IO] -
sbi->write_iostat[APP_DIRECT_IO];
spin_unlock(&sbi->iostat_lock);
}
/* /*
* file.c * file.c
*/ */
...@@ -2418,7 +2467,7 @@ void move_node_page(struct page *node_page, int gc_type); ...@@ -2418,7 +2467,7 @@ void move_node_page(struct page *node_page, int gc_type);
int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode, int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
struct writeback_control *wbc, bool atomic); struct writeback_control *wbc, bool atomic);
int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc, int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc,
bool do_balance); bool do_balance, enum iostat_type io_type);
void build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount); void build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount);
bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid); bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid);
void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid); void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid);
...@@ -2461,7 +2510,8 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range); ...@@ -2461,7 +2510,8 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range);
bool exist_trim_candidates(struct f2fs_sb_info *sbi, struct cp_control *cpc); bool exist_trim_candidates(struct f2fs_sb_info *sbi, struct cp_control *cpc);
struct page *get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno); struct page *get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno);
void update_meta_page(struct f2fs_sb_info *sbi, void *src, block_t blk_addr); void update_meta_page(struct f2fs_sb_info *sbi, void *src, block_t blk_addr);
void write_meta_page(struct f2fs_sb_info *sbi, struct page *page); void write_meta_page(struct f2fs_sb_info *sbi, struct page *page,
enum iostat_type io_type);
void write_node_page(unsigned int nid, struct f2fs_io_info *fio); void write_node_page(unsigned int nid, struct f2fs_io_info *fio);
void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio); void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio);
int rewrite_data_page(struct f2fs_io_info *fio); int rewrite_data_page(struct f2fs_io_info *fio);
...@@ -2502,7 +2552,7 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, ...@@ -2502,7 +2552,7 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
int type, bool sync); int type, bool sync);
void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index); void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index);
long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
long nr_to_write); long nr_to_write, enum iostat_type io_type);
void add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type); void add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type);
void remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type); void remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type);
void release_ino_entry(struct f2fs_sb_info *sbi, bool all); void release_ino_entry(struct f2fs_sb_info *sbi, bool all);
...@@ -2555,6 +2605,9 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, ...@@ -2555,6 +2605,9 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
u64 start, u64 len); u64 start, u64 len);
void f2fs_set_page_dirty_nobuffers(struct page *page); void f2fs_set_page_dirty_nobuffers(struct page *page);
int __f2fs_write_data_pages(struct address_space *mapping,
struct writeback_control *wbc,
enum iostat_type io_type);
void f2fs_invalidate_page(struct page *page, unsigned int offset, void f2fs_invalidate_page(struct page *page, unsigned int offset,
unsigned int length); unsigned int length);
int f2fs_release_page(struct page *page, gfp_t wait); int f2fs_release_page(struct page *page, gfp_t wait);
......
...@@ -98,6 +98,8 @@ static int f2fs_vm_page_mkwrite(struct vm_fault *vmf) ...@@ -98,6 +98,8 @@ static int f2fs_vm_page_mkwrite(struct vm_fault *vmf)
if (!PageUptodate(page)) if (!PageUptodate(page))
SetPageUptodate(page); SetPageUptodate(page);
f2fs_update_iostat(sbi, APP_MAPPED_IO, F2FS_BLKSIZE);
trace_f2fs_vm_page_mkwrite(page, DATA); trace_f2fs_vm_page_mkwrite(page, DATA);
mapped: mapped:
/* fill the page */ /* fill the page */
...@@ -1815,7 +1817,7 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg) ...@@ -1815,7 +1817,7 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
f2fs_stop_checkpoint(sbi, false); f2fs_stop_checkpoint(sbi, false);
break; break;
case F2FS_GOING_DOWN_METAFLUSH: case F2FS_GOING_DOWN_METAFLUSH:
sync_meta_pages(sbi, META, LONG_MAX); sync_meta_pages(sbi, META, LONG_MAX, FS_META_IO);
f2fs_stop_checkpoint(sbi, false); f2fs_stop_checkpoint(sbi, false);
break; break;
default: default:
...@@ -2694,6 +2696,9 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -2694,6 +2696,9 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
ret = __generic_file_write_iter(iocb, from); ret = __generic_file_write_iter(iocb, from);
blk_finish_plug(&plug); blk_finish_plug(&plug);
clear_inode_flag(inode, FI_NO_PREALLOC); clear_inode_flag(inode, FI_NO_PREALLOC);
if (ret > 0)
f2fs_update_iostat(F2FS_I_SB(inode), APP_WRITE_IO, ret);
} }
inode_unlock(inode); inode_unlock(inode);
......
...@@ -689,6 +689,8 @@ static void move_encrypted_block(struct inode *inode, block_t bidx, ...@@ -689,6 +689,8 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
fio.new_blkaddr = newaddr; fio.new_blkaddr = newaddr;
f2fs_submit_page_write(&fio); f2fs_submit_page_write(&fio);
f2fs_update_iostat(fio.sbi, FS_GC_DATA_IO, F2FS_BLKSIZE);
f2fs_update_data_blkaddr(&dn, newaddr); f2fs_update_data_blkaddr(&dn, newaddr);
set_inode_flag(inode, FI_APPEND_WRITE); set_inode_flag(inode, FI_APPEND_WRITE);
if (page->index == 0) if (page->index == 0)
...@@ -736,6 +738,7 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type, ...@@ -736,6 +738,7 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,
.page = page, .page = page,
.encrypted_page = NULL, .encrypted_page = NULL,
.need_lock = LOCK_REQ, .need_lock = LOCK_REQ,
.io_type = FS_GC_DATA_IO,
}; };
bool is_dirty = PageDirty(page); bool is_dirty = PageDirty(page);
int err; int err;
......
...@@ -117,6 +117,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page) ...@@ -117,6 +117,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
.op_flags = REQ_SYNC | REQ_PRIO, .op_flags = REQ_SYNC | REQ_PRIO,
.page = page, .page = page,
.encrypted_page = NULL, .encrypted_page = NULL,
.io_type = FS_DATA_IO,
}; };
int dirty, err; int dirty, err;
......
...@@ -1332,7 +1332,8 @@ static struct page *last_fsync_dnode(struct f2fs_sb_info *sbi, nid_t ino) ...@@ -1332,7 +1332,8 @@ static struct page *last_fsync_dnode(struct f2fs_sb_info *sbi, nid_t ino)
} }
static int __write_node_page(struct page *page, bool atomic, bool *submitted, static int __write_node_page(struct page *page, bool atomic, bool *submitted,
struct writeback_control *wbc, bool do_balance) struct writeback_control *wbc, bool do_balance,
enum iostat_type io_type)
{ {
struct f2fs_sb_info *sbi = F2FS_P_SB(page); struct f2fs_sb_info *sbi = F2FS_P_SB(page);
nid_t nid; nid_t nid;
...@@ -1345,6 +1346,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted, ...@@ -1345,6 +1346,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
.page = page, .page = page,
.encrypted_page = NULL, .encrypted_page = NULL,
.submitted = false, .submitted = false,
.io_type = io_type,
}; };
trace_f2fs_writepage(page, NODE); trace_f2fs_writepage(page, NODE);
...@@ -1413,7 +1415,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted, ...@@ -1413,7 +1415,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
static int f2fs_write_node_page(struct page *page, static int f2fs_write_node_page(struct page *page,
struct writeback_control *wbc) struct writeback_control *wbc)
{ {
return __write_node_page(page, false, NULL, wbc, false); return __write_node_page(page, false, NULL, wbc, false, FS_NODE_IO);
} }
int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode, int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
...@@ -1501,7 +1503,8 @@ int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode, ...@@ -1501,7 +1503,8 @@ int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
ret = __write_node_page(page, atomic && ret = __write_node_page(page, atomic &&
page == last_page, page == last_page,
&submitted, wbc, true); &submitted, wbc, true,
FS_NODE_IO);
if (ret) { if (ret) {
unlock_page(page); unlock_page(page);
f2fs_put_page(last_page, 0); f2fs_put_page(last_page, 0);
...@@ -1539,7 +1542,7 @@ int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode, ...@@ -1539,7 +1542,7 @@ int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
} }
int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc, int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc,
bool do_balance) bool do_balance, enum iostat_type io_type)
{ {
pgoff_t index, end; pgoff_t index, end;
struct pagevec pvec; struct pagevec pvec;
...@@ -1618,7 +1621,7 @@ int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc, ...@@ -1618,7 +1621,7 @@ int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc,
set_dentry_mark(page, 0); set_dentry_mark(page, 0);
ret = __write_node_page(page, false, &submitted, ret = __write_node_page(page, false, &submitted,
wbc, do_balance); wbc, do_balance, io_type);
if (ret) if (ret)
unlock_page(page); unlock_page(page);
else if (submitted) else if (submitted)
...@@ -1707,7 +1710,7 @@ static int f2fs_write_node_pages(struct address_space *mapping, ...@@ -1707,7 +1710,7 @@ static int f2fs_write_node_pages(struct address_space *mapping,
diff = nr_pages_to_write(sbi, NODE, wbc); diff = nr_pages_to_write(sbi, NODE, wbc);
wbc->sync_mode = WB_SYNC_NONE; wbc->sync_mode = WB_SYNC_NONE;
blk_start_plug(&plug); blk_start_plug(&plug);
sync_node_pages(sbi, wbc, true); sync_node_pages(sbi, wbc, true, FS_NODE_IO);
blk_finish_plug(&plug); blk_finish_plug(&plug);
wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff); wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff);
return 0; return 0;
......
...@@ -292,6 +292,7 @@ static int __commit_inmem_pages(struct inode *inode, ...@@ -292,6 +292,7 @@ static int __commit_inmem_pages(struct inode *inode,
.type = DATA, .type = DATA,
.op = REQ_OP_WRITE, .op = REQ_OP_WRITE,
.op_flags = REQ_SYNC | REQ_PRIO, .op_flags = REQ_SYNC | REQ_PRIO,
.io_type = FS_DATA_IO,
}; };
pgoff_t last_idx = ULONG_MAX; pgoff_t last_idx = ULONG_MAX;
int err = 0; int err = 0;
...@@ -823,6 +824,8 @@ static void __submit_discard_cmd(struct f2fs_sb_info *sbi, ...@@ -823,6 +824,8 @@ static void __submit_discard_cmd(struct f2fs_sb_info *sbi,
submit_bio(bio); submit_bio(bio);
list_move_tail(&dc->list, &dcc->wait_list); list_move_tail(&dc->list, &dcc->wait_list);
__check_sit_bitmap(sbi, dc->start, dc->start + dc->len); __check_sit_bitmap(sbi, dc->start, dc->start + dc->len);
f2fs_update_iostat(sbi, FS_DISCARD, 1);
} }
} else { } else {
__remove_discard_cmd(sbi, dc); __remove_discard_cmd(sbi, dc);
...@@ -2271,7 +2274,8 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio) ...@@ -2271,7 +2274,8 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
} }
} }
void write_meta_page(struct f2fs_sb_info *sbi, struct page *page) void write_meta_page(struct f2fs_sb_info *sbi, struct page *page,
enum iostat_type io_type)
{ {
struct f2fs_io_info fio = { struct f2fs_io_info fio = {
.sbi = sbi, .sbi = sbi,
...@@ -2290,6 +2294,8 @@ void write_meta_page(struct f2fs_sb_info *sbi, struct page *page) ...@@ -2290,6 +2294,8 @@ void write_meta_page(struct f2fs_sb_info *sbi, struct page *page)
set_page_writeback(page); set_page_writeback(page);
f2fs_submit_page_write(&fio); f2fs_submit_page_write(&fio);
f2fs_update_iostat(sbi, io_type, F2FS_BLKSIZE);
} }
void write_node_page(unsigned int nid, struct f2fs_io_info *fio) void write_node_page(unsigned int nid, struct f2fs_io_info *fio)
...@@ -2298,6 +2304,8 @@ void write_node_page(unsigned int nid, struct f2fs_io_info *fio) ...@@ -2298,6 +2304,8 @@ void write_node_page(unsigned int nid, struct f2fs_io_info *fio)
set_summary(&sum, nid, 0, 0); set_summary(&sum, nid, 0, 0);
do_write_page(&sum, fio); do_write_page(&sum, fio);
f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE);
} }
void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio) void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio)
...@@ -2311,13 +2319,22 @@ void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio) ...@@ -2311,13 +2319,22 @@ void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio)
set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
do_write_page(&sum, fio); do_write_page(&sum, fio);
f2fs_update_data_blkaddr(dn, fio->new_blkaddr); f2fs_update_data_blkaddr(dn, fio->new_blkaddr);
f2fs_update_iostat(sbi, fio->io_type, F2FS_BLKSIZE);
} }
int rewrite_data_page(struct f2fs_io_info *fio) int rewrite_data_page(struct f2fs_io_info *fio)
{ {
int err;
fio->new_blkaddr = fio->old_blkaddr; fio->new_blkaddr = fio->old_blkaddr;
stat_inc_inplace_blocks(fio->sbi); stat_inc_inplace_blocks(fio->sbi);
return f2fs_submit_page_bio(fio);
err = f2fs_submit_page_bio(fio);
f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE);
return err;
} }
void __f2fs_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, void __f2fs_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
......
...@@ -2056,6 +2056,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -2056,6 +2056,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
set_sbi_flag(sbi, SBI_POR_DOING); set_sbi_flag(sbi, SBI_POR_DOING);
spin_lock_init(&sbi->stat_lock); spin_lock_init(&sbi->stat_lock);
/* init iostat info */
spin_lock_init(&sbi->iostat_lock);
sbi->iostat_enable = false;
for (i = 0; i < NR_PAGE_TYPE; i++) { for (i = 0; i < NR_PAGE_TYPE; i++) {
int n = (i == META) ? 1: NR_TEMP_TYPE; int n = (i == META) ? 1: NR_TEMP_TYPE;
int j; int j;
......
...@@ -153,6 +153,10 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a, ...@@ -153,6 +153,10 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
return count; return count;
} }
*ui = t; *ui = t;
if (!strcmp(a->attr.name, "iostat_enable") && *ui == 0)
f2fs_reset_iostat(sbi);
return count; return count;
} }
...@@ -250,6 +254,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search); ...@@ -250,6 +254,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search);
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level);
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, cp_interval, interval_time[CP_TIME]);
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]);
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable);
#ifdef CONFIG_F2FS_FAULT_INJECTION #ifdef CONFIG_F2FS_FAULT_INJECTION
F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate); 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);
...@@ -288,6 +293,7 @@ static struct attribute *f2fs_attrs[] = { ...@@ -288,6 +293,7 @@ static struct attribute *f2fs_attrs[] = {
ATTR_LIST(dirty_nats_ratio), ATTR_LIST(dirty_nats_ratio),
ATTR_LIST(cp_interval), ATTR_LIST(cp_interval),
ATTR_LIST(idle_interval), ATTR_LIST(idle_interval),
ATTR_LIST(iostat_enable),
#ifdef CONFIG_F2FS_FAULT_INJECTION #ifdef CONFIG_F2FS_FAULT_INJECTION
ATTR_LIST(inject_rate), ATTR_LIST(inject_rate),
ATTR_LIST(inject_type), ATTR_LIST(inject_type),
...@@ -391,6 +397,48 @@ static int segment_bits_seq_show(struct seq_file *seq, void *offset) ...@@ -391,6 +397,48 @@ static int segment_bits_seq_show(struct seq_file *seq, void *offset)
return 0; return 0;
} }
static int iostat_info_seq_show(struct seq_file *seq, void *offset)
{
struct super_block *sb = seq->private;
struct f2fs_sb_info *sbi = F2FS_SB(sb);
time64_t now = ktime_get_real_seconds();
if (!sbi->iostat_enable)
return 0;
seq_printf(seq, "time: %-16llu\n", now);
/* print app IOs */
seq_printf(seq, "app buffered: %-16llu\n",
sbi->write_iostat[APP_BUFFERED_IO]);
seq_printf(seq, "app direct: %-16llu\n",
sbi->write_iostat[APP_DIRECT_IO]);
seq_printf(seq, "app mapped: %-16llu\n",
sbi->write_iostat[APP_MAPPED_IO]);
/* print fs IOs */
seq_printf(seq, "fs data: %-16llu\n",
sbi->write_iostat[FS_DATA_IO]);
seq_printf(seq, "fs node: %-16llu\n",
sbi->write_iostat[FS_NODE_IO]);
seq_printf(seq, "fs meta: %-16llu\n",
sbi->write_iostat[FS_META_IO]);
seq_printf(seq, "fs gc data: %-16llu\n",
sbi->write_iostat[FS_GC_DATA_IO]);
seq_printf(seq, "fs gc node: %-16llu\n",
sbi->write_iostat[FS_GC_NODE_IO]);
seq_printf(seq, "fs cp data: %-16llu\n",
sbi->write_iostat[FS_CP_DATA_IO]);
seq_printf(seq, "fs cp node: %-16llu\n",
sbi->write_iostat[FS_CP_NODE_IO]);
seq_printf(seq, "fs cp meta: %-16llu\n",
sbi->write_iostat[FS_CP_META_IO]);
seq_printf(seq, "fs discard: %-16llu\n",
sbi->write_iostat[FS_DISCARD]);
return 0;
}
#define F2FS_PROC_FILE_DEF(_name) \ #define F2FS_PROC_FILE_DEF(_name) \
static int _name##_open_fs(struct inode *inode, struct file *file) \ static int _name##_open_fs(struct inode *inode, struct file *file) \
{ \ { \
...@@ -406,6 +454,7 @@ static const struct file_operations f2fs_seq_##_name##_fops = { \ ...@@ -406,6 +454,7 @@ static const struct file_operations f2fs_seq_##_name##_fops = { \
F2FS_PROC_FILE_DEF(segment_info); F2FS_PROC_FILE_DEF(segment_info);
F2FS_PROC_FILE_DEF(segment_bits); F2FS_PROC_FILE_DEF(segment_bits);
F2FS_PROC_FILE_DEF(iostat_info);
int __init f2fs_init_sysfs(void) int __init f2fs_init_sysfs(void)
{ {
...@@ -454,6 +503,8 @@ int f2fs_register_sysfs(struct f2fs_sb_info *sbi) ...@@ -454,6 +503,8 @@ int f2fs_register_sysfs(struct f2fs_sb_info *sbi)
&f2fs_seq_segment_info_fops, sb); &f2fs_seq_segment_info_fops, sb);
proc_create_data("segment_bits", S_IRUGO, sbi->s_proc, proc_create_data("segment_bits", S_IRUGO, sbi->s_proc,
&f2fs_seq_segment_bits_fops, sb); &f2fs_seq_segment_bits_fops, sb);
proc_create_data("iostat_info", S_IRUGO, sbi->s_proc,
&f2fs_seq_iostat_info_fops, sb);
} }
return 0; return 0;
} }
...@@ -461,6 +512,7 @@ int f2fs_register_sysfs(struct f2fs_sb_info *sbi) ...@@ -461,6 +512,7 @@ int f2fs_register_sysfs(struct f2fs_sb_info *sbi)
void f2fs_unregister_sysfs(struct f2fs_sb_info *sbi) void f2fs_unregister_sysfs(struct f2fs_sb_info *sbi)
{ {
if (sbi->s_proc) { if (sbi->s_proc) {
remove_proc_entry("iostat_info", sbi->s_proc);
remove_proc_entry("segment_info", sbi->s_proc); remove_proc_entry("segment_info", sbi->s_proc);
remove_proc_entry("segment_bits", sbi->s_proc); remove_proc_entry("segment_bits", sbi->s_proc);
remove_proc_entry(sbi->sb->s_id, f2fs_proc_root); remove_proc_entry(sbi->sb->s_id, f2fs_proc_root);
......
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