linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] f2fs: split bio cache
@ 2017-05-08 12:36 Chao Yu
  2017-05-08 21:23 ` Jaegeuk Kim
  0 siblings, 1 reply; 9+ messages in thread
From: Chao Yu @ 2017-05-08 12:36 UTC (permalink / raw)
  To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, chao, Chao Yu

Split DATA/NODE type bio cache according to different temperature,
so write IOs with the same temperature can be merged in corresponding
bio cache as much as possible, otherwise, different temperature write
IOs submitting into one bio cache will always cause split of bio.

Signed-off-by: Chao Yu <yuchao0@huawei.com>
---
 fs/f2fs/checkpoint.c | 10 +++----
 fs/f2fs/data.c       | 78 ++++++++++++++++++++++++++++++++--------------------
 fs/f2fs/f2fs.h       | 15 ++++++----
 fs/f2fs/gc.c         |  5 ++--
 fs/f2fs/node.c       |  8 +++---
 fs/f2fs/segment.c    | 14 +++++++---
 fs/f2fs/super.c      | 16 ++++++-----
 7 files changed, 89 insertions(+), 57 deletions(-)

diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index ea9c317b5916..2a475e83a092 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -212,7 +212,7 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
 		f2fs_put_page(page, 0);
 	}
 out:
-	f2fs_submit_merged_bio(sbi, META, READ);
+	f2fs_submit_meta_bio(sbi, META, READ);
 	blk_finish_plug(&plug);
 	return blkno - start;
 }
@@ -249,13 +249,13 @@ static int f2fs_write_meta_page(struct page *page,
 	dec_page_count(sbi, F2FS_DIRTY_META);
 
 	if (wbc->for_reclaim)
-		f2fs_submit_merged_bio_cond(sbi, page->mapping->host,
+		f2fs_submit_meta_bio_cond(sbi, page->mapping->host,
 						0, page->index, META, WRITE);
 
 	unlock_page(page);
 
 	if (unlikely(f2fs_cp_error(sbi)))
-		f2fs_submit_merged_bio(sbi, META, WRITE);
+		f2fs_submit_meta_bio(sbi, META, WRITE);
 
 	return 0;
 
@@ -358,7 +358,7 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
 	}
 stop:
 	if (nwritten)
-		f2fs_submit_merged_bio(sbi, type, WRITE);
+		f2fs_submit_meta_bio(sbi, type, WRITE);
 
 	blk_finish_plug(&plug);
 
@@ -906,7 +906,7 @@ int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)
 		 * We should submit bio, since it exists several
 		 * wribacking dentry pages in the freeing inode.
 		 */
-		f2fs_submit_merged_bio(sbi, DATA, WRITE);
+		f2fs_submit_log_bio(sbi, DATA, WRITE);
 		cond_resched();
 	}
 	goto retry;
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 7c0f6bdf817d..37d0896021c7 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -278,28 +278,27 @@ static bool __has_merged_page(struct f2fs_bio_info *io,
 	return false;
 }
 
-static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode,
-				nid_t ino, pgoff_t idx, enum page_type type)
+static struct f2fs_bio_info *__get_bio_info(struct f2fs_sb_info *sbi, int rw,
+					enum page_type type, int seg_type)
 {
 	enum page_type btype = PAGE_TYPE_OF_BIO(type);
-	struct f2fs_bio_info *io = &sbi->write_io[btype];
-	bool ret;
+	struct f2fs_bio_info *io;
 
-	down_read(&io->io_rwsem);
-	ret = __has_merged_page(io, inode, ino, idx);
-	up_read(&io->io_rwsem);
-	return ret;
+	if (btype == META) {
+		int io_type = is_read_io(rw) ? READ : WRITE;
+
+		io = &sbi->meta_io[io_type];
+	} else {
+		io = &sbi->log_io[seg_type];
+	}
+
+	return io;
 }
 
-static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
+static void __f2fs_submit_merged_bio(struct f2fs_bio_info *io,
 				struct inode *inode, nid_t ino, pgoff_t idx,
-				enum page_type type, int rw)
+				enum page_type type)
 {
-	enum page_type btype = PAGE_TYPE_OF_BIO(type);
-	struct f2fs_bio_info *io;
-
-	io = is_read_io(rw) ? &sbi->read_io : &sbi->write_io[btype];
-
 	down_write(&io->io_rwsem);
 
 	if (!__has_merged_page(io, inode, ino, idx))
@@ -310,7 +309,7 @@ static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
 		io->fio.type = META_FLUSH;
 		io->fio.op = REQ_OP_WRITE;
 		io->fio.op_flags = REQ_META | REQ_PRIO | REQ_SYNC;
-		if (!test_opt(sbi, NOBARRIER))
+		if (!test_opt(io->sbi, NOBARRIER))
 			io->fio.op_flags |= REQ_PREFLUSH | REQ_FUA;
 	}
 	__submit_merged_bio(io);
@@ -318,25 +317,45 @@ static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
 	up_write(&io->io_rwsem);
 }
 
-void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, enum page_type type,
-									int rw)
+void f2fs_submit_log_bio_cond(struct f2fs_sb_info *sbi,
+				struct inode *inode, nid_t ino, pgoff_t idx,
+				enum page_type type, int rw)
+{
+	bool is_data = (type == DATA);
+	int i = is_data ? CURSEG_HOT_DATA : CURSEG_HOT_NODE;
+	int max = is_data ? CURSEG_COLD_DATA : CURSEG_COLD_NODE;
+
+	for (; i <= max; i++)
+		__f2fs_submit_merged_bio(&sbi->log_io[i],
+					inode, ino, idx, type);
+}
+
+void f2fs_submit_log_bio(struct f2fs_sb_info *sbi,
+					enum page_type type, int rw)
 {
-	__f2fs_submit_merged_bio(sbi, NULL, 0, 0, type, rw);
+	f2fs_submit_log_bio_cond(sbi, NULL, 0, 0, type, rw);
 }
 
-void f2fs_submit_merged_bio_cond(struct f2fs_sb_info *sbi,
+void f2fs_submit_meta_bio_cond(struct f2fs_sb_info *sbi,
 				struct inode *inode, nid_t ino, pgoff_t idx,
 				enum page_type type, int rw)
 {
-	if (has_merged_page(sbi, inode, ino, idx, type))
-		__f2fs_submit_merged_bio(sbi, inode, ino, idx, type, rw);
+	int io_type = is_read_io(rw) ? READ : WRITE;
+
+	__f2fs_submit_merged_bio(&sbi->meta_io[io_type], inode, ino, idx, type);
+}
+
+void f2fs_submit_meta_bio(struct f2fs_sb_info *sbi,
+					enum page_type type, int rw)
+{
+	f2fs_submit_meta_bio_cond(sbi, NULL, 0, 0, type, rw);
 }
 
 void f2fs_flush_merged_bios(struct f2fs_sb_info *sbi)
 {
-	f2fs_submit_merged_bio(sbi, DATA, WRITE);
-	f2fs_submit_merged_bio(sbi, NODE, WRITE);
-	f2fs_submit_merged_bio(sbi, META, WRITE);
+	f2fs_submit_log_bio(sbi, DATA, WRITE);
+	f2fs_submit_log_bio(sbi, NODE, WRITE);
+	f2fs_submit_meta_bio(sbi, META, WRITE);
 }
 
 /*
@@ -371,13 +390,12 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
 int f2fs_submit_page_mbio(struct f2fs_io_info *fio)
 {
 	struct f2fs_sb_info *sbi = fio->sbi;
-	enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
 	struct f2fs_bio_info *io;
 	bool is_read = is_read_io(fio->op);
 	struct page *bio_page;
 	int err = 0;
 
-	io = is_read ? &sbi->read_io : &sbi->write_io[btype];
+	io = __get_bio_info(sbi, fio->op, fio->type, fio->seg_type);
 
 	if (fio->old_blkaddr != NEW_ADDR)
 		verify_block_addr(sbi, fio->old_blkaddr);
@@ -1513,7 +1531,7 @@ static int __write_data_page(struct page *page, bool *submitted,
 		ClearPageUptodate(page);
 
 	if (wbc->for_reclaim) {
-		f2fs_submit_merged_bio_cond(sbi, inode, 0, page->index,
+		f2fs_submit_log_bio_cond(sbi, inode, 0, page->index,
 						DATA, WRITE);
 		clear_inode_flag(inode, FI_HOT_DATA);
 		remove_dirty_inode(inode);
@@ -1525,7 +1543,7 @@ static int __write_data_page(struct page *page, bool *submitted,
 		f2fs_balance_fs(sbi, need_balance_fs);
 
 	if (unlikely(f2fs_cp_error(sbi))) {
-		f2fs_submit_merged_bio(sbi, DATA, WRITE);
+		f2fs_submit_log_bio(sbi, DATA, WRITE);
 		submitted = NULL;
 	}
 
@@ -1684,7 +1702,7 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
 		mapping->writeback_index = done_index;
 
 	if (last_idx != ULONG_MAX)
-		f2fs_submit_merged_bio_cond(F2FS_M_SB(mapping), mapping->host,
+		f2fs_submit_log_bio_cond(F2FS_M_SB(mapping), mapping->host,
 						0, last_idx, DATA, WRITE);
 
 	return ret;
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index e26999a74522..4ab42749fd5f 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -795,6 +795,7 @@ enum page_type {
 struct f2fs_io_info {
 	struct f2fs_sb_info *sbi;	/* f2fs_sb_info pointer */
 	enum page_type type;	/* contains DATA/NODE/META/META_FLUSH */
+	int seg_type;		/* indicate current segment type */
 	int op;			/* contains REQ_OP_ */
 	int op_flags;		/* req_flag_bits */
 	block_t new_blkaddr;	/* new block address to be written */
@@ -879,8 +880,8 @@ struct f2fs_sb_info {
 	struct f2fs_sm_info *sm_info;		/* segment manager */
 
 	/* for bio operations */
-	struct f2fs_bio_info read_io;			/* for read bios */
-	struct f2fs_bio_info write_io[NR_PAGE_TYPE];	/* for write bios */
+	struct f2fs_bio_info meta_io[2];		/* for meta bios */
+	struct f2fs_bio_info log_io[NR_CURSEG_TYPE];	/* for log bios */
 	struct mutex wio_mutex[NODE + 1];	/* bio ordering for NODE/DATA */
 	int write_io_size_bits;			/* Write IO size bits */
 	mempool_t *write_io_dummy;		/* Dummy pages */
@@ -2325,11 +2326,15 @@ void destroy_checkpoint_caches(void);
 /*
  * data.c
  */
-void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, enum page_type type,
-			int rw);
-void f2fs_submit_merged_bio_cond(struct f2fs_sb_info *sbi,
+void f2fs_submit_log_bio_cond(struct f2fs_sb_info *sbi,
 				struct inode *inode, nid_t ino, pgoff_t idx,
 				enum page_type type, int rw);
+void f2fs_submit_log_bio(struct f2fs_sb_info *sbi, enum page_type type, int rw);
+void f2fs_submit_meta_bio_cond(struct f2fs_sb_info *sbi,
+				struct inode *inode, nid_t ino, pgoff_t idx,
+				enum page_type type, int rw);
+void f2fs_submit_meta_bio(struct f2fs_sb_info *sbi,
+					enum page_type type, int rw);
 void f2fs_flush_merged_bios(struct f2fs_sb_info *sbi);
 int f2fs_submit_page_bio(struct f2fs_io_info *fio);
 int f2fs_submit_page_mbio(struct f2fs_io_info *fio);
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 026522107ca3..8b267ca30926 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -586,6 +586,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
 	struct f2fs_io_info fio = {
 		.sbi = F2FS_I_SB(inode),
 		.type = DATA,
+		.seg_type = CURSEG_COLD_DATA,
 		.op = REQ_OP_READ,
 		.op_flags = 0,
 		.encrypted_page = NULL,
@@ -632,7 +633,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
 	fio.new_blkaddr = fio.old_blkaddr = dn.data_blkaddr;
 
 	allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr,
-							&sum, CURSEG_COLD_DATA);
+							&sum, fio.seg_type);
 
 	fio.encrypted_page = pagecache_get_page(META_MAPPING(fio.sbi), newaddr,
 					FGP_LOCK | FGP_CREAT, GFP_NOFS);
@@ -936,7 +937,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
 	}
 
 	if (gc_type == FG_GC)
-		f2fs_submit_merged_bio(sbi,
+		f2fs_submit_log_bio(sbi,
 				(type == SUM_TYPE_NODE) ? NODE : DATA, WRITE);
 
 	blk_finish_plug(&plug);
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 98351a4a4da3..28f6d1723327 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -1373,7 +1373,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
 	up_read(&sbi->node_write);
 
 	if (wbc->for_reclaim) {
-		f2fs_submit_merged_bio_cond(sbi, page->mapping->host, 0,
+		f2fs_submit_log_bio_cond(sbi, page->mapping->host, 0,
 						page->index, NODE, WRITE);
 		submitted = NULL;
 	}
@@ -1381,7 +1381,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
 	unlock_page(page);
 
 	if (unlikely(f2fs_cp_error(sbi))) {
-		f2fs_submit_merged_bio(sbi, NODE, WRITE);
+		f2fs_submit_log_bio(sbi, NODE, WRITE);
 		submitted = NULL;
 	}
 	if (submitted)
@@ -1518,7 +1518,7 @@ int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
 	}
 out:
 	if (last_idx != ULONG_MAX)
-		f2fs_submit_merged_bio_cond(sbi, NULL, ino, last_idx,
+		f2fs_submit_log_bio_cond(sbi, NULL, ino, last_idx,
 							NODE, WRITE);
 	return ret ? -EIO: 0;
 }
@@ -1625,7 +1625,7 @@ int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc)
 	}
 out:
 	if (nwritten)
-		f2fs_submit_merged_bio(sbi, NODE, WRITE);
+		f2fs_submit_log_bio(sbi, NODE, WRITE);
 	return ret;
 }
 
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index b084b3a8f2c7..cdf7d61ac213 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -328,7 +328,7 @@ static int __commit_inmem_pages(struct inode *inode,
 	}
 
 	if (last_idx != ULONG_MAX)
-		f2fs_submit_merged_bio_cond(sbi, inode, 0, last_idx,
+		f2fs_submit_log_bio_cond(sbi, inode, 0, last_idx,
 							DATA, WRITE);
 
 	if (!err)
@@ -2141,14 +2141,15 @@ void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
 
 static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
 {
-	int type = __get_segment_type(fio->page, fio->type);
 	int err;
 
+	fio->seg_type = __get_segment_type(fio->page, fio->type);
+
 	if (fio->type == NODE || fio->type == DATA)
 		mutex_lock(&fio->sbi->wio_mutex[fio->type]);
 reallocate:
 	allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
-					&fio->new_blkaddr, sum, type);
+					&fio->new_blkaddr, sum, fio->seg_type);
 
 	/* writeout dirty page into bdev */
 	err = f2fs_submit_page_mbio(fio);
@@ -2297,8 +2298,13 @@ void f2fs_wait_on_page_writeback(struct page *page,
 	if (PageWriteback(page)) {
 		struct f2fs_sb_info *sbi = F2FS_P_SB(page);
 
-		f2fs_submit_merged_bio_cond(sbi, page->mapping->host,
+		if (type == META)
+			f2fs_submit_meta_bio_cond(sbi, page->mapping->host,
+						0, page->index, type, WRITE);
+		else
+			f2fs_submit_log_bio_cond(sbi, page->mapping->host,
 						0, page->index, type, WRITE);
+
 		if (ordered)
 			wait_on_page_writeback(page);
 		else
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 83355ec4a92c..fed25ca609e4 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -1950,13 +1950,15 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 	set_sbi_flag(sbi, SBI_POR_DOING);
 	spin_lock_init(&sbi->stat_lock);
 
-	init_rwsem(&sbi->read_io.io_rwsem);
-	sbi->read_io.sbi = sbi;
-	sbi->read_io.bio = NULL;
-	for (i = 0; i < NR_PAGE_TYPE; i++) {
-		init_rwsem(&sbi->write_io[i].io_rwsem);
-		sbi->write_io[i].sbi = sbi;
-		sbi->write_io[i].bio = NULL;
+	for (i = 0; i < 2; i++) {
+		init_rwsem(&sbi->meta_io[i].io_rwsem);
+		sbi->meta_io[i].sbi = sbi;
+		sbi->meta_io[i].bio = NULL;
+	}
+	for (i = 0; i < NR_CURSEG_TYPE; i++) {
+		init_rwsem(&sbi->log_io[i].io_rwsem);
+		sbi->log_io[i].sbi = sbi;
+		sbi->log_io[i].bio = NULL;
 	}
 
 	init_rwsem(&sbi->cp_rwsem);
-- 
2.12.2.510.ge1104a5ee539

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH] f2fs: split bio cache
  2017-05-08 12:36 [PATCH] f2fs: split bio cache Chao Yu
@ 2017-05-08 21:23 ` Jaegeuk Kim
  2017-05-09  1:49   ` Chao Yu
  0 siblings, 1 reply; 9+ messages in thread
From: Jaegeuk Kim @ 2017-05-08 21:23 UTC (permalink / raw)
  To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, chao

Hi Chao,

I can't see a strong reason to split meta from data/node and rename the existing
function names. Instead, how about keeping the existing one while adding some
page types to deal with log types?

Thanks,

On 05/08, Chao Yu wrote:
> Split DATA/NODE type bio cache according to different temperature,
> so write IOs with the same temperature can be merged in corresponding
> bio cache as much as possible, otherwise, different temperature write
> IOs submitting into one bio cache will always cause split of bio.
> 
> Signed-off-by: Chao Yu <yuchao0@huawei.com>
> ---
>  fs/f2fs/checkpoint.c | 10 +++----
>  fs/f2fs/data.c       | 78 ++++++++++++++++++++++++++++++++--------------------
>  fs/f2fs/f2fs.h       | 15 ++++++----
>  fs/f2fs/gc.c         |  5 ++--
>  fs/f2fs/node.c       |  8 +++---
>  fs/f2fs/segment.c    | 14 +++++++---
>  fs/f2fs/super.c      | 16 ++++++-----
>  7 files changed, 89 insertions(+), 57 deletions(-)
> 
> diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
> index ea9c317b5916..2a475e83a092 100644
> --- a/fs/f2fs/checkpoint.c
> +++ b/fs/f2fs/checkpoint.c
> @@ -212,7 +212,7 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
>  		f2fs_put_page(page, 0);
>  	}
>  out:
> -	f2fs_submit_merged_bio(sbi, META, READ);
> +	f2fs_submit_meta_bio(sbi, META, READ);
>  	blk_finish_plug(&plug);
>  	return blkno - start;
>  }
> @@ -249,13 +249,13 @@ static int f2fs_write_meta_page(struct page *page,
>  	dec_page_count(sbi, F2FS_DIRTY_META);
>  
>  	if (wbc->for_reclaim)
> -		f2fs_submit_merged_bio_cond(sbi, page->mapping->host,
> +		f2fs_submit_meta_bio_cond(sbi, page->mapping->host,
>  						0, page->index, META, WRITE);
>  
>  	unlock_page(page);
>  
>  	if (unlikely(f2fs_cp_error(sbi)))
> -		f2fs_submit_merged_bio(sbi, META, WRITE);
> +		f2fs_submit_meta_bio(sbi, META, WRITE);
>  
>  	return 0;
>  
> @@ -358,7 +358,7 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
>  	}
>  stop:
>  	if (nwritten)
> -		f2fs_submit_merged_bio(sbi, type, WRITE);
> +		f2fs_submit_meta_bio(sbi, type, WRITE);
>  
>  	blk_finish_plug(&plug);
>  
> @@ -906,7 +906,7 @@ int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)
>  		 * We should submit bio, since it exists several
>  		 * wribacking dentry pages in the freeing inode.
>  		 */
> -		f2fs_submit_merged_bio(sbi, DATA, WRITE);
> +		f2fs_submit_log_bio(sbi, DATA, WRITE);
>  		cond_resched();
>  	}
>  	goto retry;
> diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
> index 7c0f6bdf817d..37d0896021c7 100644
> --- a/fs/f2fs/data.c
> +++ b/fs/f2fs/data.c
> @@ -278,28 +278,27 @@ static bool __has_merged_page(struct f2fs_bio_info *io,
>  	return false;
>  }
>  
> -static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode,
> -				nid_t ino, pgoff_t idx, enum page_type type)
> +static struct f2fs_bio_info *__get_bio_info(struct f2fs_sb_info *sbi, int rw,
> +					enum page_type type, int seg_type)
>  {
>  	enum page_type btype = PAGE_TYPE_OF_BIO(type);
> -	struct f2fs_bio_info *io = &sbi->write_io[btype];
> -	bool ret;
> +	struct f2fs_bio_info *io;
>  
> -	down_read(&io->io_rwsem);
> -	ret = __has_merged_page(io, inode, ino, idx);
> -	up_read(&io->io_rwsem);
> -	return ret;
> +	if (btype == META) {
> +		int io_type = is_read_io(rw) ? READ : WRITE;
> +
> +		io = &sbi->meta_io[io_type];
> +	} else {
> +		io = &sbi->log_io[seg_type];
> +	}
> +
> +	return io;
>  }
>  
> -static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
> +static void __f2fs_submit_merged_bio(struct f2fs_bio_info *io,
>  				struct inode *inode, nid_t ino, pgoff_t idx,
> -				enum page_type type, int rw)
> +				enum page_type type)
>  {
> -	enum page_type btype = PAGE_TYPE_OF_BIO(type);
> -	struct f2fs_bio_info *io;
> -
> -	io = is_read_io(rw) ? &sbi->read_io : &sbi->write_io[btype];
> -
>  	down_write(&io->io_rwsem);
>  
>  	if (!__has_merged_page(io, inode, ino, idx))
> @@ -310,7 +309,7 @@ static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
>  		io->fio.type = META_FLUSH;
>  		io->fio.op = REQ_OP_WRITE;
>  		io->fio.op_flags = REQ_META | REQ_PRIO | REQ_SYNC;
> -		if (!test_opt(sbi, NOBARRIER))
> +		if (!test_opt(io->sbi, NOBARRIER))
>  			io->fio.op_flags |= REQ_PREFLUSH | REQ_FUA;
>  	}
>  	__submit_merged_bio(io);
> @@ -318,25 +317,45 @@ static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
>  	up_write(&io->io_rwsem);
>  }
>  
> -void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, enum page_type type,
> -									int rw)
> +void f2fs_submit_log_bio_cond(struct f2fs_sb_info *sbi,
> +				struct inode *inode, nid_t ino, pgoff_t idx,
> +				enum page_type type, int rw)
> +{
> +	bool is_data = (type == DATA);
> +	int i = is_data ? CURSEG_HOT_DATA : CURSEG_HOT_NODE;
> +	int max = is_data ? CURSEG_COLD_DATA : CURSEG_COLD_NODE;
> +
> +	for (; i <= max; i++)
> +		__f2fs_submit_merged_bio(&sbi->log_io[i],
> +					inode, ino, idx, type);
> +}
> +
> +void f2fs_submit_log_bio(struct f2fs_sb_info *sbi,
> +					enum page_type type, int rw)
>  {
> -	__f2fs_submit_merged_bio(sbi, NULL, 0, 0, type, rw);
> +	f2fs_submit_log_bio_cond(sbi, NULL, 0, 0, type, rw);
>  }
>  
> -void f2fs_submit_merged_bio_cond(struct f2fs_sb_info *sbi,
> +void f2fs_submit_meta_bio_cond(struct f2fs_sb_info *sbi,
>  				struct inode *inode, nid_t ino, pgoff_t idx,
>  				enum page_type type, int rw)
>  {
> -	if (has_merged_page(sbi, inode, ino, idx, type))
> -		__f2fs_submit_merged_bio(sbi, inode, ino, idx, type, rw);
> +	int io_type = is_read_io(rw) ? READ : WRITE;
> +
> +	__f2fs_submit_merged_bio(&sbi->meta_io[io_type], inode, ino, idx, type);
> +}
> +
> +void f2fs_submit_meta_bio(struct f2fs_sb_info *sbi,
> +					enum page_type type, int rw)
> +{
> +	f2fs_submit_meta_bio_cond(sbi, NULL, 0, 0, type, rw);
>  }
>  
>  void f2fs_flush_merged_bios(struct f2fs_sb_info *sbi)
>  {
> -	f2fs_submit_merged_bio(sbi, DATA, WRITE);
> -	f2fs_submit_merged_bio(sbi, NODE, WRITE);
> -	f2fs_submit_merged_bio(sbi, META, WRITE);
> +	f2fs_submit_log_bio(sbi, DATA, WRITE);
> +	f2fs_submit_log_bio(sbi, NODE, WRITE);
> +	f2fs_submit_meta_bio(sbi, META, WRITE);
>  }
>  
>  /*
> @@ -371,13 +390,12 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
>  int f2fs_submit_page_mbio(struct f2fs_io_info *fio)
>  {
>  	struct f2fs_sb_info *sbi = fio->sbi;
> -	enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
>  	struct f2fs_bio_info *io;
>  	bool is_read = is_read_io(fio->op);
>  	struct page *bio_page;
>  	int err = 0;
>  
> -	io = is_read ? &sbi->read_io : &sbi->write_io[btype];
> +	io = __get_bio_info(sbi, fio->op, fio->type, fio->seg_type);
>  
>  	if (fio->old_blkaddr != NEW_ADDR)
>  		verify_block_addr(sbi, fio->old_blkaddr);
> @@ -1513,7 +1531,7 @@ static int __write_data_page(struct page *page, bool *submitted,
>  		ClearPageUptodate(page);
>  
>  	if (wbc->for_reclaim) {
> -		f2fs_submit_merged_bio_cond(sbi, inode, 0, page->index,
> +		f2fs_submit_log_bio_cond(sbi, inode, 0, page->index,
>  						DATA, WRITE);
>  		clear_inode_flag(inode, FI_HOT_DATA);
>  		remove_dirty_inode(inode);
> @@ -1525,7 +1543,7 @@ static int __write_data_page(struct page *page, bool *submitted,
>  		f2fs_balance_fs(sbi, need_balance_fs);
>  
>  	if (unlikely(f2fs_cp_error(sbi))) {
> -		f2fs_submit_merged_bio(sbi, DATA, WRITE);
> +		f2fs_submit_log_bio(sbi, DATA, WRITE);
>  		submitted = NULL;
>  	}
>  
> @@ -1684,7 +1702,7 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
>  		mapping->writeback_index = done_index;
>  
>  	if (last_idx != ULONG_MAX)
> -		f2fs_submit_merged_bio_cond(F2FS_M_SB(mapping), mapping->host,
> +		f2fs_submit_log_bio_cond(F2FS_M_SB(mapping), mapping->host,
>  						0, last_idx, DATA, WRITE);
>  
>  	return ret;
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index e26999a74522..4ab42749fd5f 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -795,6 +795,7 @@ enum page_type {
>  struct f2fs_io_info {
>  	struct f2fs_sb_info *sbi;	/* f2fs_sb_info pointer */
>  	enum page_type type;	/* contains DATA/NODE/META/META_FLUSH */
> +	int seg_type;		/* indicate current segment type */
>  	int op;			/* contains REQ_OP_ */
>  	int op_flags;		/* req_flag_bits */
>  	block_t new_blkaddr;	/* new block address to be written */
> @@ -879,8 +880,8 @@ struct f2fs_sb_info {
>  	struct f2fs_sm_info *sm_info;		/* segment manager */
>  
>  	/* for bio operations */
> -	struct f2fs_bio_info read_io;			/* for read bios */
> -	struct f2fs_bio_info write_io[NR_PAGE_TYPE];	/* for write bios */
> +	struct f2fs_bio_info meta_io[2];		/* for meta bios */
> +	struct f2fs_bio_info log_io[NR_CURSEG_TYPE];	/* for log bios */
>  	struct mutex wio_mutex[NODE + 1];	/* bio ordering for NODE/DATA */
>  	int write_io_size_bits;			/* Write IO size bits */
>  	mempool_t *write_io_dummy;		/* Dummy pages */
> @@ -2325,11 +2326,15 @@ void destroy_checkpoint_caches(void);
>  /*
>   * data.c
>   */
> -void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, enum page_type type,
> -			int rw);
> -void f2fs_submit_merged_bio_cond(struct f2fs_sb_info *sbi,
> +void f2fs_submit_log_bio_cond(struct f2fs_sb_info *sbi,
>  				struct inode *inode, nid_t ino, pgoff_t idx,
>  				enum page_type type, int rw);
> +void f2fs_submit_log_bio(struct f2fs_sb_info *sbi, enum page_type type, int rw);
> +void f2fs_submit_meta_bio_cond(struct f2fs_sb_info *sbi,
> +				struct inode *inode, nid_t ino, pgoff_t idx,
> +				enum page_type type, int rw);
> +void f2fs_submit_meta_bio(struct f2fs_sb_info *sbi,
> +					enum page_type type, int rw);
>  void f2fs_flush_merged_bios(struct f2fs_sb_info *sbi);
>  int f2fs_submit_page_bio(struct f2fs_io_info *fio);
>  int f2fs_submit_page_mbio(struct f2fs_io_info *fio);
> diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
> index 026522107ca3..8b267ca30926 100644
> --- a/fs/f2fs/gc.c
> +++ b/fs/f2fs/gc.c
> @@ -586,6 +586,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
>  	struct f2fs_io_info fio = {
>  		.sbi = F2FS_I_SB(inode),
>  		.type = DATA,
> +		.seg_type = CURSEG_COLD_DATA,
>  		.op = REQ_OP_READ,
>  		.op_flags = 0,
>  		.encrypted_page = NULL,
> @@ -632,7 +633,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
>  	fio.new_blkaddr = fio.old_blkaddr = dn.data_blkaddr;
>  
>  	allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr,
> -							&sum, CURSEG_COLD_DATA);
> +							&sum, fio.seg_type);
>  
>  	fio.encrypted_page = pagecache_get_page(META_MAPPING(fio.sbi), newaddr,
>  					FGP_LOCK | FGP_CREAT, GFP_NOFS);
> @@ -936,7 +937,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
>  	}
>  
>  	if (gc_type == FG_GC)
> -		f2fs_submit_merged_bio(sbi,
> +		f2fs_submit_log_bio(sbi,
>  				(type == SUM_TYPE_NODE) ? NODE : DATA, WRITE);
>  
>  	blk_finish_plug(&plug);
> diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
> index 98351a4a4da3..28f6d1723327 100644
> --- a/fs/f2fs/node.c
> +++ b/fs/f2fs/node.c
> @@ -1373,7 +1373,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
>  	up_read(&sbi->node_write);
>  
>  	if (wbc->for_reclaim) {
> -		f2fs_submit_merged_bio_cond(sbi, page->mapping->host, 0,
> +		f2fs_submit_log_bio_cond(sbi, page->mapping->host, 0,
>  						page->index, NODE, WRITE);
>  		submitted = NULL;
>  	}
> @@ -1381,7 +1381,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
>  	unlock_page(page);
>  
>  	if (unlikely(f2fs_cp_error(sbi))) {
> -		f2fs_submit_merged_bio(sbi, NODE, WRITE);
> +		f2fs_submit_log_bio(sbi, NODE, WRITE);
>  		submitted = NULL;
>  	}
>  	if (submitted)
> @@ -1518,7 +1518,7 @@ int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
>  	}
>  out:
>  	if (last_idx != ULONG_MAX)
> -		f2fs_submit_merged_bio_cond(sbi, NULL, ino, last_idx,
> +		f2fs_submit_log_bio_cond(sbi, NULL, ino, last_idx,
>  							NODE, WRITE);
>  	return ret ? -EIO: 0;
>  }
> @@ -1625,7 +1625,7 @@ int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc)
>  	}
>  out:
>  	if (nwritten)
> -		f2fs_submit_merged_bio(sbi, NODE, WRITE);
> +		f2fs_submit_log_bio(sbi, NODE, WRITE);
>  	return ret;
>  }
>  
> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
> index b084b3a8f2c7..cdf7d61ac213 100644
> --- a/fs/f2fs/segment.c
> +++ b/fs/f2fs/segment.c
> @@ -328,7 +328,7 @@ static int __commit_inmem_pages(struct inode *inode,
>  	}
>  
>  	if (last_idx != ULONG_MAX)
> -		f2fs_submit_merged_bio_cond(sbi, inode, 0, last_idx,
> +		f2fs_submit_log_bio_cond(sbi, inode, 0, last_idx,
>  							DATA, WRITE);
>  
>  	if (!err)
> @@ -2141,14 +2141,15 @@ void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
>  
>  static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
>  {
> -	int type = __get_segment_type(fio->page, fio->type);
>  	int err;
>  
> +	fio->seg_type = __get_segment_type(fio->page, fio->type);
> +
>  	if (fio->type == NODE || fio->type == DATA)
>  		mutex_lock(&fio->sbi->wio_mutex[fio->type]);
>  reallocate:
>  	allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
> -					&fio->new_blkaddr, sum, type);
> +					&fio->new_blkaddr, sum, fio->seg_type);
>  
>  	/* writeout dirty page into bdev */
>  	err = f2fs_submit_page_mbio(fio);
> @@ -2297,8 +2298,13 @@ void f2fs_wait_on_page_writeback(struct page *page,
>  	if (PageWriteback(page)) {
>  		struct f2fs_sb_info *sbi = F2FS_P_SB(page);
>  
> -		f2fs_submit_merged_bio_cond(sbi, page->mapping->host,
> +		if (type == META)
> +			f2fs_submit_meta_bio_cond(sbi, page->mapping->host,
> +						0, page->index, type, WRITE);
> +		else
> +			f2fs_submit_log_bio_cond(sbi, page->mapping->host,
>  						0, page->index, type, WRITE);
> +
>  		if (ordered)
>  			wait_on_page_writeback(page);
>  		else
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index 83355ec4a92c..fed25ca609e4 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -1950,13 +1950,15 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>  	set_sbi_flag(sbi, SBI_POR_DOING);
>  	spin_lock_init(&sbi->stat_lock);
>  
> -	init_rwsem(&sbi->read_io.io_rwsem);
> -	sbi->read_io.sbi = sbi;
> -	sbi->read_io.bio = NULL;
> -	for (i = 0; i < NR_PAGE_TYPE; i++) {
> -		init_rwsem(&sbi->write_io[i].io_rwsem);
> -		sbi->write_io[i].sbi = sbi;
> -		sbi->write_io[i].bio = NULL;
> +	for (i = 0; i < 2; i++) {
> +		init_rwsem(&sbi->meta_io[i].io_rwsem);
> +		sbi->meta_io[i].sbi = sbi;
> +		sbi->meta_io[i].bio = NULL;
> +	}
> +	for (i = 0; i < NR_CURSEG_TYPE; i++) {
> +		init_rwsem(&sbi->log_io[i].io_rwsem);
> +		sbi->log_io[i].sbi = sbi;
> +		sbi->log_io[i].bio = NULL;
>  	}
>  
>  	init_rwsem(&sbi->cp_rwsem);
> -- 
> 2.12.2.510.ge1104a5ee539

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] f2fs: split bio cache
  2017-05-08 21:23 ` Jaegeuk Kim
@ 2017-05-09  1:49   ` Chao Yu
  2017-05-10  3:19     ` Chao Yu
  2017-05-10 23:50     ` Jaegeuk Kim
  0 siblings, 2 replies; 9+ messages in thread
From: Chao Yu @ 2017-05-09  1:49 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: linux-f2fs-devel, linux-kernel, chao

Hi Jaegeuk,

On 2017/5/9 5:23, Jaegeuk Kim wrote:
> Hi Chao,
> 
> I can't see a strong reason to split meta from data/node and rename the existing
> function names. Instead, how about keeping the existing one while adding some
> page types to deal with log types?

Hmm.. before write this patch, I have thought about this implementation which
adds HOT_DATA/WARM_DATA/.. into page_type enum, but the final target is making
different temperature log-header being with independent bio cache, io lock, and
io list, eliminating interaction of different temperature IOs, also expanding
f2fs' scalability when adding more log-headers. If we don't split meta from
data/node, it's a little bit hard to approach this. What do you think?

Thanks,

> 
> Thanks,
> 
> On 05/08, Chao Yu wrote:
>> Split DATA/NODE type bio cache according to different temperature,
>> so write IOs with the same temperature can be merged in corresponding
>> bio cache as much as possible, otherwise, different temperature write
>> IOs submitting into one bio cache will always cause split of bio.
>>
>> Signed-off-by: Chao Yu <yuchao0@huawei.com>
>> ---
>>  fs/f2fs/checkpoint.c | 10 +++----
>>  fs/f2fs/data.c       | 78 ++++++++++++++++++++++++++++++++--------------------
>>  fs/f2fs/f2fs.h       | 15 ++++++----
>>  fs/f2fs/gc.c         |  5 ++--
>>  fs/f2fs/node.c       |  8 +++---
>>  fs/f2fs/segment.c    | 14 +++++++---
>>  fs/f2fs/super.c      | 16 ++++++-----
>>  7 files changed, 89 insertions(+), 57 deletions(-)
>>
>> diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
>> index ea9c317b5916..2a475e83a092 100644
>> --- a/fs/f2fs/checkpoint.c
>> +++ b/fs/f2fs/checkpoint.c
>> @@ -212,7 +212,7 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
>>  		f2fs_put_page(page, 0);
>>  	}
>>  out:
>> -	f2fs_submit_merged_bio(sbi, META, READ);
>> +	f2fs_submit_meta_bio(sbi, META, READ);
>>  	blk_finish_plug(&plug);
>>  	return blkno - start;
>>  }
>> @@ -249,13 +249,13 @@ static int f2fs_write_meta_page(struct page *page,
>>  	dec_page_count(sbi, F2FS_DIRTY_META);
>>  
>>  	if (wbc->for_reclaim)
>> -		f2fs_submit_merged_bio_cond(sbi, page->mapping->host,
>> +		f2fs_submit_meta_bio_cond(sbi, page->mapping->host,
>>  						0, page->index, META, WRITE);
>>  
>>  	unlock_page(page);
>>  
>>  	if (unlikely(f2fs_cp_error(sbi)))
>> -		f2fs_submit_merged_bio(sbi, META, WRITE);
>> +		f2fs_submit_meta_bio(sbi, META, WRITE);
>>  
>>  	return 0;
>>  
>> @@ -358,7 +358,7 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
>>  	}
>>  stop:
>>  	if (nwritten)
>> -		f2fs_submit_merged_bio(sbi, type, WRITE);
>> +		f2fs_submit_meta_bio(sbi, type, WRITE);
>>  
>>  	blk_finish_plug(&plug);
>>  
>> @@ -906,7 +906,7 @@ int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)
>>  		 * We should submit bio, since it exists several
>>  		 * wribacking dentry pages in the freeing inode.
>>  		 */
>> -		f2fs_submit_merged_bio(sbi, DATA, WRITE);
>> +		f2fs_submit_log_bio(sbi, DATA, WRITE);
>>  		cond_resched();
>>  	}
>>  	goto retry;
>> diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
>> index 7c0f6bdf817d..37d0896021c7 100644
>> --- a/fs/f2fs/data.c
>> +++ b/fs/f2fs/data.c
>> @@ -278,28 +278,27 @@ static bool __has_merged_page(struct f2fs_bio_info *io,
>>  	return false;
>>  }
>>  
>> -static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode,
>> -				nid_t ino, pgoff_t idx, enum page_type type)
>> +static struct f2fs_bio_info *__get_bio_info(struct f2fs_sb_info *sbi, int rw,
>> +					enum page_type type, int seg_type)
>>  {
>>  	enum page_type btype = PAGE_TYPE_OF_BIO(type);
>> -	struct f2fs_bio_info *io = &sbi->write_io[btype];
>> -	bool ret;
>> +	struct f2fs_bio_info *io;
>>  
>> -	down_read(&io->io_rwsem);
>> -	ret = __has_merged_page(io, inode, ino, idx);
>> -	up_read(&io->io_rwsem);
>> -	return ret;
>> +	if (btype == META) {
>> +		int io_type = is_read_io(rw) ? READ : WRITE;
>> +
>> +		io = &sbi->meta_io[io_type];
>> +	} else {
>> +		io = &sbi->log_io[seg_type];
>> +	}
>> +
>> +	return io;
>>  }
>>  
>> -static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
>> +static void __f2fs_submit_merged_bio(struct f2fs_bio_info *io,
>>  				struct inode *inode, nid_t ino, pgoff_t idx,
>> -				enum page_type type, int rw)
>> +				enum page_type type)
>>  {
>> -	enum page_type btype = PAGE_TYPE_OF_BIO(type);
>> -	struct f2fs_bio_info *io;
>> -
>> -	io = is_read_io(rw) ? &sbi->read_io : &sbi->write_io[btype];
>> -
>>  	down_write(&io->io_rwsem);
>>  
>>  	if (!__has_merged_page(io, inode, ino, idx))
>> @@ -310,7 +309,7 @@ static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
>>  		io->fio.type = META_FLUSH;
>>  		io->fio.op = REQ_OP_WRITE;
>>  		io->fio.op_flags = REQ_META | REQ_PRIO | REQ_SYNC;
>> -		if (!test_opt(sbi, NOBARRIER))
>> +		if (!test_opt(io->sbi, NOBARRIER))
>>  			io->fio.op_flags |= REQ_PREFLUSH | REQ_FUA;
>>  	}
>>  	__submit_merged_bio(io);
>> @@ -318,25 +317,45 @@ static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
>>  	up_write(&io->io_rwsem);
>>  }
>>  
>> -void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, enum page_type type,
>> -									int rw)
>> +void f2fs_submit_log_bio_cond(struct f2fs_sb_info *sbi,
>> +				struct inode *inode, nid_t ino, pgoff_t idx,
>> +				enum page_type type, int rw)
>> +{
>> +	bool is_data = (type == DATA);
>> +	int i = is_data ? CURSEG_HOT_DATA : CURSEG_HOT_NODE;
>> +	int max = is_data ? CURSEG_COLD_DATA : CURSEG_COLD_NODE;
>> +
>> +	for (; i <= max; i++)
>> +		__f2fs_submit_merged_bio(&sbi->log_io[i],
>> +					inode, ino, idx, type);
>> +}
>> +
>> +void f2fs_submit_log_bio(struct f2fs_sb_info *sbi,
>> +					enum page_type type, int rw)
>>  {
>> -	__f2fs_submit_merged_bio(sbi, NULL, 0, 0, type, rw);
>> +	f2fs_submit_log_bio_cond(sbi, NULL, 0, 0, type, rw);
>>  }
>>  
>> -void f2fs_submit_merged_bio_cond(struct f2fs_sb_info *sbi,
>> +void f2fs_submit_meta_bio_cond(struct f2fs_sb_info *sbi,
>>  				struct inode *inode, nid_t ino, pgoff_t idx,
>>  				enum page_type type, int rw)
>>  {
>> -	if (has_merged_page(sbi, inode, ino, idx, type))
>> -		__f2fs_submit_merged_bio(sbi, inode, ino, idx, type, rw);
>> +	int io_type = is_read_io(rw) ? READ : WRITE;
>> +
>> +	__f2fs_submit_merged_bio(&sbi->meta_io[io_type], inode, ino, idx, type);
>> +}
>> +
>> +void f2fs_submit_meta_bio(struct f2fs_sb_info *sbi,
>> +					enum page_type type, int rw)
>> +{
>> +	f2fs_submit_meta_bio_cond(sbi, NULL, 0, 0, type, rw);
>>  }
>>  
>>  void f2fs_flush_merged_bios(struct f2fs_sb_info *sbi)
>>  {
>> -	f2fs_submit_merged_bio(sbi, DATA, WRITE);
>> -	f2fs_submit_merged_bio(sbi, NODE, WRITE);
>> -	f2fs_submit_merged_bio(sbi, META, WRITE);
>> +	f2fs_submit_log_bio(sbi, DATA, WRITE);
>> +	f2fs_submit_log_bio(sbi, NODE, WRITE);
>> +	f2fs_submit_meta_bio(sbi, META, WRITE);
>>  }
>>  
>>  /*
>> @@ -371,13 +390,12 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
>>  int f2fs_submit_page_mbio(struct f2fs_io_info *fio)
>>  {
>>  	struct f2fs_sb_info *sbi = fio->sbi;
>> -	enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
>>  	struct f2fs_bio_info *io;
>>  	bool is_read = is_read_io(fio->op);
>>  	struct page *bio_page;
>>  	int err = 0;
>>  
>> -	io = is_read ? &sbi->read_io : &sbi->write_io[btype];
>> +	io = __get_bio_info(sbi, fio->op, fio->type, fio->seg_type);
>>  
>>  	if (fio->old_blkaddr != NEW_ADDR)
>>  		verify_block_addr(sbi, fio->old_blkaddr);
>> @@ -1513,7 +1531,7 @@ static int __write_data_page(struct page *page, bool *submitted,
>>  		ClearPageUptodate(page);
>>  
>>  	if (wbc->for_reclaim) {
>> -		f2fs_submit_merged_bio_cond(sbi, inode, 0, page->index,
>> +		f2fs_submit_log_bio_cond(sbi, inode, 0, page->index,
>>  						DATA, WRITE);
>>  		clear_inode_flag(inode, FI_HOT_DATA);
>>  		remove_dirty_inode(inode);
>> @@ -1525,7 +1543,7 @@ static int __write_data_page(struct page *page, bool *submitted,
>>  		f2fs_balance_fs(sbi, need_balance_fs);
>>  
>>  	if (unlikely(f2fs_cp_error(sbi))) {
>> -		f2fs_submit_merged_bio(sbi, DATA, WRITE);
>> +		f2fs_submit_log_bio(sbi, DATA, WRITE);
>>  		submitted = NULL;
>>  	}
>>  
>> @@ -1684,7 +1702,7 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
>>  		mapping->writeback_index = done_index;
>>  
>>  	if (last_idx != ULONG_MAX)
>> -		f2fs_submit_merged_bio_cond(F2FS_M_SB(mapping), mapping->host,
>> +		f2fs_submit_log_bio_cond(F2FS_M_SB(mapping), mapping->host,
>>  						0, last_idx, DATA, WRITE);
>>  
>>  	return ret;
>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
>> index e26999a74522..4ab42749fd5f 100644
>> --- a/fs/f2fs/f2fs.h
>> +++ b/fs/f2fs/f2fs.h
>> @@ -795,6 +795,7 @@ enum page_type {
>>  struct f2fs_io_info {
>>  	struct f2fs_sb_info *sbi;	/* f2fs_sb_info pointer */
>>  	enum page_type type;	/* contains DATA/NODE/META/META_FLUSH */
>> +	int seg_type;		/* indicate current segment type */
>>  	int op;			/* contains REQ_OP_ */
>>  	int op_flags;		/* req_flag_bits */
>>  	block_t new_blkaddr;	/* new block address to be written */
>> @@ -879,8 +880,8 @@ struct f2fs_sb_info {
>>  	struct f2fs_sm_info *sm_info;		/* segment manager */
>>  
>>  	/* for bio operations */
>> -	struct f2fs_bio_info read_io;			/* for read bios */
>> -	struct f2fs_bio_info write_io[NR_PAGE_TYPE];	/* for write bios */
>> +	struct f2fs_bio_info meta_io[2];		/* for meta bios */
>> +	struct f2fs_bio_info log_io[NR_CURSEG_TYPE];	/* for log bios */
>>  	struct mutex wio_mutex[NODE + 1];	/* bio ordering for NODE/DATA */
>>  	int write_io_size_bits;			/* Write IO size bits */
>>  	mempool_t *write_io_dummy;		/* Dummy pages */
>> @@ -2325,11 +2326,15 @@ void destroy_checkpoint_caches(void);
>>  /*
>>   * data.c
>>   */
>> -void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, enum page_type type,
>> -			int rw);
>> -void f2fs_submit_merged_bio_cond(struct f2fs_sb_info *sbi,
>> +void f2fs_submit_log_bio_cond(struct f2fs_sb_info *sbi,
>>  				struct inode *inode, nid_t ino, pgoff_t idx,
>>  				enum page_type type, int rw);
>> +void f2fs_submit_log_bio(struct f2fs_sb_info *sbi, enum page_type type, int rw);
>> +void f2fs_submit_meta_bio_cond(struct f2fs_sb_info *sbi,
>> +				struct inode *inode, nid_t ino, pgoff_t idx,
>> +				enum page_type type, int rw);
>> +void f2fs_submit_meta_bio(struct f2fs_sb_info *sbi,
>> +					enum page_type type, int rw);
>>  void f2fs_flush_merged_bios(struct f2fs_sb_info *sbi);
>>  int f2fs_submit_page_bio(struct f2fs_io_info *fio);
>>  int f2fs_submit_page_mbio(struct f2fs_io_info *fio);
>> diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
>> index 026522107ca3..8b267ca30926 100644
>> --- a/fs/f2fs/gc.c
>> +++ b/fs/f2fs/gc.c
>> @@ -586,6 +586,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
>>  	struct f2fs_io_info fio = {
>>  		.sbi = F2FS_I_SB(inode),
>>  		.type = DATA,
>> +		.seg_type = CURSEG_COLD_DATA,
>>  		.op = REQ_OP_READ,
>>  		.op_flags = 0,
>>  		.encrypted_page = NULL,
>> @@ -632,7 +633,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
>>  	fio.new_blkaddr = fio.old_blkaddr = dn.data_blkaddr;
>>  
>>  	allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr,
>> -							&sum, CURSEG_COLD_DATA);
>> +							&sum, fio.seg_type);
>>  
>>  	fio.encrypted_page = pagecache_get_page(META_MAPPING(fio.sbi), newaddr,
>>  					FGP_LOCK | FGP_CREAT, GFP_NOFS);
>> @@ -936,7 +937,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
>>  	}
>>  
>>  	if (gc_type == FG_GC)
>> -		f2fs_submit_merged_bio(sbi,
>> +		f2fs_submit_log_bio(sbi,
>>  				(type == SUM_TYPE_NODE) ? NODE : DATA, WRITE);
>>  
>>  	blk_finish_plug(&plug);
>> diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
>> index 98351a4a4da3..28f6d1723327 100644
>> --- a/fs/f2fs/node.c
>> +++ b/fs/f2fs/node.c
>> @@ -1373,7 +1373,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
>>  	up_read(&sbi->node_write);
>>  
>>  	if (wbc->for_reclaim) {
>> -		f2fs_submit_merged_bio_cond(sbi, page->mapping->host, 0,
>> +		f2fs_submit_log_bio_cond(sbi, page->mapping->host, 0,
>>  						page->index, NODE, WRITE);
>>  		submitted = NULL;
>>  	}
>> @@ -1381,7 +1381,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
>>  	unlock_page(page);
>>  
>>  	if (unlikely(f2fs_cp_error(sbi))) {
>> -		f2fs_submit_merged_bio(sbi, NODE, WRITE);
>> +		f2fs_submit_log_bio(sbi, NODE, WRITE);
>>  		submitted = NULL;
>>  	}
>>  	if (submitted)
>> @@ -1518,7 +1518,7 @@ int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
>>  	}
>>  out:
>>  	if (last_idx != ULONG_MAX)
>> -		f2fs_submit_merged_bio_cond(sbi, NULL, ino, last_idx,
>> +		f2fs_submit_log_bio_cond(sbi, NULL, ino, last_idx,
>>  							NODE, WRITE);
>>  	return ret ? -EIO: 0;
>>  }
>> @@ -1625,7 +1625,7 @@ int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc)
>>  	}
>>  out:
>>  	if (nwritten)
>> -		f2fs_submit_merged_bio(sbi, NODE, WRITE);
>> +		f2fs_submit_log_bio(sbi, NODE, WRITE);
>>  	return ret;
>>  }
>>  
>> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
>> index b084b3a8f2c7..cdf7d61ac213 100644
>> --- a/fs/f2fs/segment.c
>> +++ b/fs/f2fs/segment.c
>> @@ -328,7 +328,7 @@ static int __commit_inmem_pages(struct inode *inode,
>>  	}
>>  
>>  	if (last_idx != ULONG_MAX)
>> -		f2fs_submit_merged_bio_cond(sbi, inode, 0, last_idx,
>> +		f2fs_submit_log_bio_cond(sbi, inode, 0, last_idx,
>>  							DATA, WRITE);
>>  
>>  	if (!err)
>> @@ -2141,14 +2141,15 @@ void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
>>  
>>  static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
>>  {
>> -	int type = __get_segment_type(fio->page, fio->type);
>>  	int err;
>>  
>> +	fio->seg_type = __get_segment_type(fio->page, fio->type);
>> +
>>  	if (fio->type == NODE || fio->type == DATA)
>>  		mutex_lock(&fio->sbi->wio_mutex[fio->type]);
>>  reallocate:
>>  	allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
>> -					&fio->new_blkaddr, sum, type);
>> +					&fio->new_blkaddr, sum, fio->seg_type);
>>  
>>  	/* writeout dirty page into bdev */
>>  	err = f2fs_submit_page_mbio(fio);
>> @@ -2297,8 +2298,13 @@ void f2fs_wait_on_page_writeback(struct page *page,
>>  	if (PageWriteback(page)) {
>>  		struct f2fs_sb_info *sbi = F2FS_P_SB(page);
>>  
>> -		f2fs_submit_merged_bio_cond(sbi, page->mapping->host,
>> +		if (type == META)
>> +			f2fs_submit_meta_bio_cond(sbi, page->mapping->host,
>> +						0, page->index, type, WRITE);
>> +		else
>> +			f2fs_submit_log_bio_cond(sbi, page->mapping->host,
>>  						0, page->index, type, WRITE);
>> +
>>  		if (ordered)
>>  			wait_on_page_writeback(page);
>>  		else
>> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
>> index 83355ec4a92c..fed25ca609e4 100644
>> --- a/fs/f2fs/super.c
>> +++ b/fs/f2fs/super.c
>> @@ -1950,13 +1950,15 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>>  	set_sbi_flag(sbi, SBI_POR_DOING);
>>  	spin_lock_init(&sbi->stat_lock);
>>  
>> -	init_rwsem(&sbi->read_io.io_rwsem);
>> -	sbi->read_io.sbi = sbi;
>> -	sbi->read_io.bio = NULL;
>> -	for (i = 0; i < NR_PAGE_TYPE; i++) {
>> -		init_rwsem(&sbi->write_io[i].io_rwsem);
>> -		sbi->write_io[i].sbi = sbi;
>> -		sbi->write_io[i].bio = NULL;
>> +	for (i = 0; i < 2; i++) {
>> +		init_rwsem(&sbi->meta_io[i].io_rwsem);
>> +		sbi->meta_io[i].sbi = sbi;
>> +		sbi->meta_io[i].bio = NULL;
>> +	}
>> +	for (i = 0; i < NR_CURSEG_TYPE; i++) {
>> +		init_rwsem(&sbi->log_io[i].io_rwsem);
>> +		sbi->log_io[i].sbi = sbi;
>> +		sbi->log_io[i].bio = NULL;
>>  	}
>>  
>>  	init_rwsem(&sbi->cp_rwsem);
>> -- 
>> 2.12.2.510.ge1104a5ee539
> 
> .
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] f2fs: split bio cache
  2017-05-09  1:49   ` Chao Yu
@ 2017-05-10  3:19     ` Chao Yu
  2017-05-10 23:50     ` Jaegeuk Kim
  1 sibling, 0 replies; 9+ messages in thread
From: Chao Yu @ 2017-05-10  3:19 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: linux-f2fs-devel, linux-kernel, chao

On 2017/5/9 9:49, Chao Yu wrote:
> Hi Jaegeuk,
> 
> On 2017/5/9 5:23, Jaegeuk Kim wrote:
>> Hi Chao,
>>
>> I can't see a strong reason to split meta from data/node and rename the existing
>> function names. Instead, how about keeping the existing one while adding some
>> page types to deal with log types?
> 
> Hmm.. before write this patch, I have thought about this implementation which
> adds HOT_DATA/WARM_DATA/.. into page_type enum, but the final target is making
> different temperature log-header being with independent bio cache, io lock, and
> io list, eliminating interaction of different temperature IOs, also expanding
> f2fs' scalability when adding more log-headers. If we don't split meta from
> data/node, it's a little bit hard to approach this. What do you think?

Or like this?

diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index ea9c317b5916..61191df47a09 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -159,6 +159,7 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
 	struct f2fs_io_info fio = {
 		.sbi = sbi,
 		.type = META,
+		.btype = META,
 		.op = REQ_OP_READ,
 		.op_flags = sync ? (REQ_META | REQ_PRIO) : REQ_RAHEAD,
 		.encrypted_page = NULL,
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 7c0f6bdf817d..13c351e873d6 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -182,16 +182,17 @@ static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr,
 }

 static inline void __submit_bio(struct f2fs_sb_info *sbi,
-				struct bio *bio, enum page_type type)
+				struct bio *bio, enum page_type btype)
 {
 	if (!is_read_io(bio_op(bio))) {
 		unsigned int start;

 		if (f2fs_sb_mounted_blkzoned(sbi->sb) &&
-			current->plug && (type == DATA || type == NODE))
+			current->plug &&
+			(btype == DATA || btype == NODE || btype <= COLD_NODE))
 			blk_finish_plug(current->plug);

-		if (type != DATA && type != NODE)
+		if (btype > COLD_NODE && btype != DATA && btype != NODE)
 			goto submit_io;

 		start = bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS;
@@ -217,14 +218,14 @@ static inline void __submit_bio(struct f2fs_sb_info *sbi,
 		 * In the NODE case, we lose next block address chain. So, we
 		 * need to do checkpoint in f2fs_sync_file.
 		 */
-		if (type == NODE)
+		if (btype == DATA || btype == NODE || btype <= COLD_NODE)
 			set_sbi_flag(sbi, SBI_NEED_CP);
 	}
 submit_io:
 	if (is_read_io(bio_op(bio)))
-		trace_f2fs_submit_read_bio(sbi->sb, type, bio);
+		trace_f2fs_submit_read_bio(sbi->sb, btype, bio);
 	else
-		trace_f2fs_submit_write_bio(sbi->sb, type, bio);
+		trace_f2fs_submit_write_bio(sbi->sb, btype, bio);
 	submit_bio(bio);
 }

@@ -238,11 +239,11 @@ static void __submit_merged_bio(struct f2fs_bio_info *io)
 	bio_set_op_attrs(io->bio, fio->op, fio->op_flags);

 	if (is_read_io(fio->op))
-		trace_f2fs_prepare_read_bio(io->sbi->sb, fio->type, io->bio);
+		trace_f2fs_prepare_read_bio(io->sbi->sb, fio->btype, io->bio);
 	else
-		trace_f2fs_prepare_write_bio(io->sbi->sb, fio->type, io->bio);
+		trace_f2fs_prepare_write_bio(io->sbi->sb, fio->btype, io->bio);

-	__submit_bio(io->sbi, io->bio, fio->type);
+	__submit_bio(io->sbi, io->bio, fio->btype);
 	io->bio = NULL;
 }

@@ -279,12 +280,14 @@ static bool __has_merged_page(struct f2fs_bio_info *io,
 }

 static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode,
-				nid_t ino, pgoff_t idx, enum page_type type)
+			nid_t ino, pgoff_t idx, enum page_type type, int rw)
 {
 	enum page_type btype = PAGE_TYPE_OF_BIO(type);
-	struct f2fs_bio_info *io = &sbi->write_io[btype];
+	struct f2fs_bio_info *io;
 	bool ret;

+	io = is_read_io(rw) ? &sbi->read_io : &sbi->write_io[btype];
+
 	down_read(&io->io_rwsem);
 	ret = __has_merged_page(io, inode, ino, idx);
 	up_read(&io->io_rwsem);
@@ -318,18 +321,34 @@ static void __f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
 	up_write(&io->io_rwsem);
 }

-void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, enum page_type type,
-									int rw)
-{
-	__f2fs_submit_merged_bio(sbi, NULL, 0, 0, type, rw);
-}
-
 void f2fs_submit_merged_bio_cond(struct f2fs_sb_info *sbi,
 				struct inode *inode, nid_t ino, pgoff_t idx,
 				enum page_type type, int rw)
 {
-	if (has_merged_page(sbi, inode, ino, idx, type))
-		__f2fs_submit_merged_bio(sbi, inode, ino, idx, type, rw);
+	int i;
+
+	if (type == DATA) {
+		for (i = HOT_DATA; i <= COLD_DATA; i++) {
+			if (has_merged_page(sbi, inode, ino, idx, i, rw))
+				__f2fs_submit_merged_bio(sbi, inode, ino, idx,
+									i, rw);
+		}
+	} else if (type == NODE) {
+		for (i = HOT_NODE; i <= COLD_NODE; i++) {
+			if (has_merged_page(sbi, inode, ino, idx, i, rw))
+				__f2fs_submit_merged_bio(sbi, inode, ino, idx,
+									i, rw);
+		}
+	} else {
+		if (has_merged_page(sbi, inode, ino, idx, type, rw))
+			__f2fs_submit_merged_bio(sbi, inode, ino, idx, type, rw);
+	}
+}
+
+void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi, enum page_type type,
+									int rw)
+{
+	f2fs_submit_merged_bio_cond(sbi, NULL, 0, 0, type, rw);
 }

 void f2fs_flush_merged_bios(struct f2fs_sb_info *sbi)
@@ -371,7 +390,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
 int f2fs_submit_page_mbio(struct f2fs_io_info *fio)
 {
 	struct f2fs_sb_info *sbi = fio->sbi;
-	enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
+	enum page_type btype = PAGE_TYPE_OF_BIO(fio->btype);
 	struct f2fs_bio_info *io;
 	bool is_read = is_read_io(fio->op);
 	struct page *bio_page;
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index e26999a74522..177bccfad9ff 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -779,10 +779,16 @@ enum count_type {
  */
 #define PAGE_TYPE_OF_BIO(type)	((type) > META ? META : (type))
 enum page_type {
-	DATA,
-	NODE,
+	HOT_DATA,	/* CURSEG_HOT_DATA */
+	WARM_DATA,	/* CURSEG_WARM_DATA */
+	COLD_DATA,	/* CURSEG_COLD_DATA */
+	HOT_NODE,	/* CURSEG_HOT_NODE */
+	WARM_NODE,	/* CURSEG_WARM_NODE */
+	COLD_NODE,	/* CURSEG_COLD_NODE */
 	META,
 	NR_PAGE_TYPE,
+	DATA,
+	NODE,
 	META_FLUSH,
 	INMEM,		/* the below types are used by tracepoints only. */
 	INMEM_DROP,
@@ -795,6 +801,7 @@ enum page_type {
 struct f2fs_io_info {
 	struct f2fs_sb_info *sbi;	/* f2fs_sb_info pointer */
 	enum page_type type;	/* contains DATA/NODE/META/META_FLUSH */
+	int btype;		/* segment type and meta type */
 	int op;			/* contains REQ_OP_ */
 	int op_flags;		/* req_flag_bits */
 	block_t new_blkaddr;	/* new block address to be written */
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 026522107ca3..94a4a7ab141a 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -586,6 +586,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
 	struct f2fs_io_info fio = {
 		.sbi = F2FS_I_SB(inode),
 		.type = DATA,
+		.btype = CURSEG_COLD_DATA,
 		.op = REQ_OP_READ,
 		.op_flags = 0,
 		.encrypted_page = NULL,
@@ -632,7 +633,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
 	fio.new_blkaddr = fio.old_blkaddr = dn.data_blkaddr;

 	allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr,
-							&sum, CURSEG_COLD_DATA);
+							&sum, fio.btype);

 	fio.encrypted_page = pagecache_get_page(META_MAPPING(fio.sbi), newaddr,
 					FGP_LOCK | FGP_CREAT, GFP_NOFS);
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index b084b3a8f2c7..7167c502c09a 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2141,14 +2141,15 @@ void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,

 static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
 {
-	int type = __get_segment_type(fio->page, fio->type);
 	int err;

+	fio->btype = __get_segment_type(fio->page, fio->type);
+
 	if (fio->type == NODE || fio->type == DATA)
 		mutex_lock(&fio->sbi->wio_mutex[fio->type]);
 reallocate:
 	allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
-					&fio->new_blkaddr, sum, type);
+					&fio->new_blkaddr, sum, fio->btype);

 	/* writeout dirty page into bdev */
 	err = f2fs_submit_page_mbio(fio);
@@ -2166,6 +2167,7 @@ void write_meta_page(struct f2fs_sb_info *sbi, struct page *page)
 	struct f2fs_io_info fio = {
 		.sbi = sbi,
 		.type = META,
+		.btype = META,
 		.op = REQ_OP_WRITE,
 		.op_flags = REQ_SYNC | REQ_META | REQ_PRIO,
 		.old_blkaddr = page->index,
diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
index 15da88c5c3a4..d9886c49b05e 100644
--- a/include/trace/events/f2fs.h
+++ b/include/trace/events/f2fs.h
@@ -9,8 +9,14 @@
 #define show_dev(dev)		MAJOR(dev), MINOR(dev)
 #define show_dev_ino(entry)	show_dev(entry->dev), (unsigned long)entry->ino

-TRACE_DEFINE_ENUM(NODE);
+TRACE_DEFINE_ENUM(HOT_DATA);
+TRACE_DEFINE_ENUM(WARM_DATA);
+TRACE_DEFINE_ENUM(COLD_DATA);
+TRACE_DEFINE_ENUM(HOT_NODE);
+TRACE_DEFINE_ENUM(WARM_NODE);
+TRACE_DEFINE_ENUM(COLD_NODE);
 TRACE_DEFINE_ENUM(DATA);
+TRACE_DEFINE_ENUM(NODE);
 TRACE_DEFINE_ENUM(META);
 TRACE_DEFINE_ENUM(META_FLUSH);
 TRACE_DEFINE_ENUM(INMEM);
@@ -48,9 +54,15 @@ TRACE_DEFINE_ENUM(CP_TRIMMED);

 #define show_block_type(type)						\
 	__print_symbolic(type,						\
-		{ NODE,		"NODE" },				\
-		{ DATA,		"DATA" },				\
+		{ HOT_DATA,	"HOT_DATA" },				\
+		{ WARM_DATA,	"WARM_DATA" },				\
+		{ COLD_DATA,	"COLD_DATA" },				\
+		{ HOT_NODE,	"HOT_NODE" },				\
+		{ WARM_NODE,	"WARM_NODE" },				\
+		{ COLD_NODE,	"COLD_NODE" },				\
 		{ META,		"META" },				\
+		{ DATA,		"DATA" },				\
+		{ NODE,		"NODE" },				\
 		{ META_FLUSH,	"META_FLUSH" },				\
 		{ INMEM,	"INMEM" },				\
 		{ INMEM_DROP,	"INMEM_DROP" },				\
@@ -757,7 +769,7 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
 		__field(block_t, new_blkaddr)
 		__field(int, op)
 		__field(int, op_flags)
-		__field(int, type)
+		__field(int, btype)
 	),

 	TP_fast_assign(
@@ -768,7 +780,7 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
 		__entry->new_blkaddr	= fio->new_blkaddr;
 		__entry->op		= fio->op;
 		__entry->op_flags	= fio->op_flags;
-		__entry->type		= fio->type;
+		__entry->btype		= fio->btype;
 	),

 	TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, "
@@ -778,7 +790,7 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
 		(unsigned long long)__entry->old_blkaddr,
 		(unsigned long long)__entry->new_blkaddr,
 		show_bio_type(__entry->op, __entry->op_flags),
-		show_block_type(__entry->type))
+		show_block_type(__entry->btype))
 );

 DEFINE_EVENT_CONDITION(f2fs__submit_page_bio, f2fs_submit_page_bio,
@@ -810,7 +822,7 @@ DECLARE_EVENT_CLASS(f2fs__bio,
 		__field(dev_t,	target)
 		__field(int,	op)
 		__field(int,	op_flags)
-		__field(int,	type)
+		__field(int,	btype)
 		__field(sector_t,	sector)
 		__field(unsigned int,	size)
 	),
@@ -820,7 +832,7 @@ DECLARE_EVENT_CLASS(f2fs__bio,
 		__entry->target		= bio->bi_bdev->bd_dev;
 		__entry->op		= bio_op(bio);
 		__entry->op_flags	= bio->bi_opf;
-		__entry->type		= type;
+		__entry->btype		= btype;
 		__entry->sector		= bio->bi_iter.bi_sector;
 		__entry->size		= bio->bi_iter.bi_size;
 	),
@@ -829,7 +841,7 @@ DECLARE_EVENT_CLASS(f2fs__bio,
 		show_dev(__entry->target),
 		show_dev(__entry->dev),
 		show_bio_type(__entry->op, __entry->op_flags),
-		show_block_type(__entry->type),
+		show_block_type(__entry->btype),
 		(unsigned long long)__entry->sector,
 		__entry->size)
 );

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH] f2fs: split bio cache
  2017-05-09  1:49   ` Chao Yu
  2017-05-10  3:19     ` Chao Yu
@ 2017-05-10 23:50     ` Jaegeuk Kim
  2017-05-11  2:20       ` Chao Yu
  1 sibling, 1 reply; 9+ messages in thread
From: Jaegeuk Kim @ 2017-05-10 23:50 UTC (permalink / raw)
  To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, chao

On 05/09, Chao Yu wrote:
> Hi Jaegeuk,
> 
> On 2017/5/9 5:23, Jaegeuk Kim wrote:
> > Hi Chao,
> > 
> > I can't see a strong reason to split meta from data/node and rename the existing
> > function names. Instead, how about keeping the existing one while adding some
> > page types to deal with log types?
> 
> Hmm.. before write this patch, I have thought about this implementation which
> adds HOT_DATA/WARM_DATA/.. into page_type enum, but the final target is making
> different temperature log-header being with independent bio cache, io lock, and
> io list, eliminating interaction of different temperature IOs, also expanding
> f2fs' scalability when adding more log-headers. If we don't split meta from
> data/node, it's a little bit hard to approach this. What do you think?

I submitted clean-up patches. How about this on top of them?

---
 fs/f2fs/data.c              | 51 +++++++++++++++++++++++++++++++++------------
 fs/f2fs/f2fs.h              | 10 ++++++++-
 fs/f2fs/gc.c                |  2 ++
 fs/f2fs/segment.c           | 24 +++++++++++++++------
 fs/f2fs/segment.h           |  4 ++++
 fs/f2fs/super.c             | 21 ++++++++++++++++---
 include/trace/events/f2fs.h | 14 ++++++++++++-
 7 files changed, 102 insertions(+), 24 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 06bb2042385e..49b7e3918484 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -282,21 +282,30 @@ static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode,
 				nid_t ino, pgoff_t idx, enum page_type type)
 {
 	enum page_type btype = PAGE_TYPE_OF_BIO(type);
-	struct f2fs_bio_info *io = &sbi->write_io[btype];
-	bool ret;
+	enum temp_type temp;
+	struct f2fs_bio_info *io;
+	bool ret = false;
 
-	down_read(&io->io_rwsem);
-	ret = __has_merged_page(io, inode, ino, idx);
-	up_read(&io->io_rwsem);
+	for (temp = HOT; temp < NR_TEMP_TYPE; temp++) {
+		io = sbi->write_io[btype] + temp;
+
+		down_read(&io->io_rwsem);
+		ret = __has_merged_page(io, inode, ino, idx);
+		up_read(&io->io_rwsem);
+
+		/* TODO: use HOT temp only for meta pages now. */
+		if (ret || btype == META)
+			break;
+	}
 	return ret;
 }
 
 static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi,
 				struct inode *inode, nid_t ino, pgoff_t idx,
-				enum page_type type)
+				enum page_type type, enum temp_type temp)
 {
 	enum page_type btype = PAGE_TYPE_OF_BIO(type);
-	struct f2fs_bio_info *io = &sbi->write_io[btype];
+	struct f2fs_bio_info *io = sbi->write_io[btype] + temp;
 
 	down_write(&io->io_rwsem);
 
@@ -316,17 +325,34 @@ static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi,
 	up_write(&io->io_rwsem);
 }
 
+static void __submit_merged_write_cond(struct f2fs_sb_info *sbi,
+				struct inode *inode, nid_t ino, pgoff_t idx,
+				enum page_type type, bool force)
+{
+	enum temp_type temp;
+
+	if (!force && !has_merged_page(sbi, inode, ino, idx, type))
+		return;
+
+	for (temp = HOT; temp < NR_TEMP_TYPE; temp++) {
+		__f2fs_submit_merged_write(sbi, inode, ino, idx, type, temp);
+
+		/* TODO: use HOT temp only for meta pages now. */
+		if (type >= META)
+			break;
+	}
+}
+
 void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type)
 {
-	__f2fs_submit_merged_write(sbi, NULL, 0, 0, type);
+	__submit_merged_write_cond(sbi, NULL, 0, 0, type, true);
 }
 
 void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi,
 				struct inode *inode, nid_t ino, pgoff_t idx,
 				enum page_type type)
 {
-	if (has_merged_page(sbi, inode, ino, idx, type))
-		__f2fs_submit_merged_write(sbi, inode, ino, idx, type);
+	__submit_merged_write_cond(sbi, inode, ino, idx, type, false);
 }
 
 void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi)
@@ -369,7 +395,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
 {
 	struct f2fs_sb_info *sbi = fio->sbi;
 	enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
-	struct f2fs_bio_info *io = &sbi->write_io[btype];
+	struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp;
 	struct page *bio_page;
 	int err = 0;
 
@@ -405,8 +431,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
 		io->fio = *fio;
 	}
 
-	if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) <
-							PAGE_SIZE) {
+	if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) < PAGE_SIZE) {
 		__submit_merged_bio(io);
 		goto alloc_new;
 	}
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index bf837458cb18..90e97bc11972 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -792,9 +792,17 @@ enum page_type {
 	OPU,
 };
 
+enum temp_type {
+	HOT = 0,	/* must be zero for meta bio */
+	WARM,
+	COLD,
+	NR_TEMP_TYPE,
+};
+
 struct f2fs_io_info {
 	struct f2fs_sb_info *sbi;	/* f2fs_sb_info pointer */
 	enum page_type type;	/* contains DATA/NODE/META/META_FLUSH */
+	enum temp_type temp;	/* contains HOT/WARM/COLD */
 	int op;			/* contains REQ_OP_ */
 	int op_flags;		/* req_flag_bits */
 	block_t new_blkaddr;	/* new block address to be written */
@@ -880,7 +888,7 @@ struct f2fs_sb_info {
 
 	/* for bio operations */
 	struct f2fs_bio_info read_io;			/* for read bios */
-	struct f2fs_bio_info write_io[NR_PAGE_TYPE];	/* for write bios */
+	struct f2fs_bio_info *write_io[NR_PAGE_TYPE];	/* for write bios */
 	struct mutex wio_mutex[NODE + 1];	/* bio ordering for NODE/DATA */
 	int write_io_size_bits;			/* Write IO size bits */
 	mempool_t *write_io_dummy;		/* Dummy pages */
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 67b87155bc48..e2b13558a915 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -586,6 +586,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
 	struct f2fs_io_info fio = {
 		.sbi = F2FS_I_SB(inode),
 		.type = DATA,
+		.temp = COLD,
 		.op = REQ_OP_READ,
 		.op_flags = 0,
 		.encrypted_page = NULL,
@@ -712,6 +713,7 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,
 		struct f2fs_io_info fio = {
 			.sbi = F2FS_I_SB(inode),
 			.type = DATA,
+			.temp = COLD,
 			.op = REQ_OP_WRITE,
 			.op_flags = REQ_SYNC,
 			.old_blkaddr = NULL_ADDR,
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index c9f3a2faee21..da4fd2c29e86 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2084,17 +2084,29 @@ static int __get_segment_type_6(struct f2fs_io_info *fio)
 
 static int __get_segment_type(struct f2fs_io_info *fio)
 {
+	int type;
+
 	switch (fio->sbi->active_logs) {
 	case 2:
-		return __get_segment_type_2(fio);
+		type = __get_segment_type_2(fio);
+		break;
 	case 4:
-		return __get_segment_type_4(fio);
+		type = __get_segment_type_4(fio);
+		break;
+	case 6:
+		type = __get_segment_type_6(fio);
+		break;
+	default:
+		f2fs_bug_on(fio->sbi, true);
 	}
 
-	/* NR_CURSEG_TYPE(6) logs by default */
-	f2fs_bug_on(fio->sbi, fio->sbi->active_logs != NR_CURSEG_TYPE);
-
-	return __get_segment_type_6(fio);
+	if (IS_HOT(type))
+		fio->temp = HOT;
+	else if (IS_WARM(type))
+		fio->temp = WARM;
+	else
+		fio->temp = COLD;
+	return type;
 }
 
 void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index 10bf05d4cff4..e9ba1f1d9723 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -27,6 +27,10 @@
 #define IS_DATASEG(t)	((t) <= CURSEG_COLD_DATA)
 #define IS_NODESEG(t)	((t) >= CURSEG_HOT_NODE)
 
+#define IS_HOT(t)	((t) == CURSEG_HOT_NODE || (t) == CURSEG_HOT_DATA)
+#define IS_WARM(t)	((t) == CURSEG_WARM_NODE || (t) == CURSEG_WARM_DATA)
+#define IS_COLD(t)	((t) == CURSEG_COLD_NODE || (t) == CURSEG_COLD_DATA)
+
 #define IS_CURSEG(sbi, seg)						\
 	(((seg) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) ||	\
 	 ((seg) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) ||	\
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 104a571a41c0..91599c9c3ef6 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -768,6 +768,7 @@ static void destroy_device_list(struct f2fs_sb_info *sbi)
 static void f2fs_put_super(struct super_block *sb)
 {
 	struct f2fs_sb_info *sbi = F2FS_SB(sb);
+	int i;
 
 	if (sbi->s_proc) {
 		remove_proc_entry("segment_info", sbi->s_proc);
@@ -838,6 +839,8 @@ static void f2fs_put_super(struct super_block *sb)
 	destroy_device_list(sbi);
 	mempool_destroy(sbi->write_io_dummy);
 	destroy_percpu_info(sbi);
+	for (i = 0; i < NR_PAGE_TYPE; i++)
+		kfree(sbi->write_io[i]);
 	kfree(sbi);
 }
 
@@ -1954,9 +1957,19 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 	sbi->read_io.sbi = sbi;
 	sbi->read_io.bio = NULL;
 	for (i = 0; i < NR_PAGE_TYPE; i++) {
-		init_rwsem(&sbi->write_io[i].io_rwsem);
-		sbi->write_io[i].sbi = sbi;
-		sbi->write_io[i].bio = NULL;
+		int n = (i == META) ? 1: NR_TEMP_TYPE;
+		int j;
+
+		sbi->write_io[i] = kmalloc(n * sizeof(struct f2fs_bio_info),
+								GFP_KERNEL);
+		if (!sbi->write_io[i])
+			goto free_options;
+
+		for (j = HOT; j < n; j++) {
+			init_rwsem(&sbi->write_io[i][j].io_rwsem);
+			sbi->write_io[i][j].sbi = sbi;
+			sbi->write_io[i][j].bio = NULL;
+		}
 	}
 
 	init_rwsem(&sbi->cp_rwsem);
@@ -2202,6 +2215,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
 free_io_dummy:
 	mempool_destroy(sbi->write_io_dummy);
 free_options:
+	for (i = 0; i < NR_PAGE_TYPE; i++)
+		kfree(sbi->write_io[i]);
 	destroy_percpu_info(sbi);
 	kfree(options);
 free_sb_buf:
diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
index 5805d92893a8..6f77a2755abb 100644
--- a/include/trace/events/f2fs.h
+++ b/include/trace/events/f2fs.h
@@ -19,6 +19,9 @@ TRACE_DEFINE_ENUM(INMEM_INVALIDATE);
 TRACE_DEFINE_ENUM(INMEM_REVOKE);
 TRACE_DEFINE_ENUM(IPU);
 TRACE_DEFINE_ENUM(OPU);
+TRACE_DEFINE_ENUM(HOT);
+TRACE_DEFINE_ENUM(WARM);
+TRACE_DEFINE_ENUM(COLD);
 TRACE_DEFINE_ENUM(CURSEG_HOT_DATA);
 TRACE_DEFINE_ENUM(CURSEG_WARM_DATA);
 TRACE_DEFINE_ENUM(CURSEG_COLD_DATA);
@@ -59,6 +62,12 @@ TRACE_DEFINE_ENUM(CP_TRIMMED);
 		{ IPU,		"IN-PLACE" },				\
 		{ OPU,		"OUT-OF-PLACE" })
 
+#define show_block_temp(temp)						\
+	__print_symbolic(temp,						\
+		{ HOT,		"HOT" },				\
+		{ WARM,		"WARM" },				\
+		{ COLD,		"COLD" })
+
 #define F2FS_OP_FLAGS (REQ_RAHEAD | REQ_SYNC | REQ_META | REQ_PRIO |	\
 			REQ_PREFLUSH | REQ_FUA)
 #define F2FS_BIO_FLAG_MASK(t)	(t & F2FS_OP_FLAGS)
@@ -757,6 +766,7 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
 		__field(block_t, new_blkaddr)
 		__field(int, op)
 		__field(int, op_flags)
+		__field(int, temp)
 		__field(int, type)
 	),
 
@@ -768,16 +778,18 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
 		__entry->new_blkaddr	= fio->new_blkaddr;
 		__entry->op		= fio->op;
 		__entry->op_flags	= fio->op_flags;
+		__entry->temp		= fio->temp;
 		__entry->type		= fio->type;
 	),
 
 	TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, "
-		"oldaddr = 0x%llx, newaddr = 0x%llx, rw = %s(%s), type = %s",
+		"oldaddr = 0x%llx, newaddr = 0x%llx, rw = %s(%s), type = %s_%s",
 		show_dev_ino(__entry),
 		(unsigned long)__entry->index,
 		(unsigned long long)__entry->old_blkaddr,
 		(unsigned long long)__entry->new_blkaddr,
 		show_bio_type(__entry->op, __entry->op_flags),
+		show_block_temp(__entry->temp),
 		show_block_type(__entry->type))
 );
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH] f2fs: split bio cache
  2017-05-10 23:50     ` Jaegeuk Kim
@ 2017-05-11  2:20       ` Chao Yu
  2017-05-11  2:35         ` Jaegeuk Kim
  0 siblings, 1 reply; 9+ messages in thread
From: Chao Yu @ 2017-05-11  2:20 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: linux-f2fs-devel, linux-kernel, chao

On 2017/5/11 7:50, Jaegeuk Kim wrote:
> On 05/09, Chao Yu wrote:
>> Hi Jaegeuk,
>>
>> On 2017/5/9 5:23, Jaegeuk Kim wrote:
>>> Hi Chao,
>>>
>>> I can't see a strong reason to split meta from data/node and rename the existing
>>> function names. Instead, how about keeping the existing one while adding some
>>> page types to deal with log types?
>>
>> Hmm.. before write this patch, I have thought about this implementation which
>> adds HOT_DATA/WARM_DATA/.. into page_type enum, but the final target is making
>> different temperature log-header being with independent bio cache, io lock, and
>> io list, eliminating interaction of different temperature IOs, also expanding
>> f2fs' scalability when adding more log-headers. If we don't split meta from
>> data/node, it's a little bit hard to approach this. What do you think?
> 
> I submitted clean-up patches. How about this on top of them?

After splitting, bio caches is connected to log-header, so why not moving bio
cache into log-header (SM_I(sbi)->curseg_array)? after the merging:
- we could avoid redundant enum. e.g. temp_type, page_type::{DATA/NODE}, since
we have seg_type enum instead.
- once we add special log-header like journal log or random IO log making
DATA/NODE and HOT/WARM/COLD non-orthogonalization, we just need to change few
codes to adjust it.

How do you think?

Thanks,

> 
> ---
>  fs/f2fs/data.c              | 51 +++++++++++++++++++++++++++++++++------------
>  fs/f2fs/f2fs.h              | 10 ++++++++-
>  fs/f2fs/gc.c                |  2 ++
>  fs/f2fs/segment.c           | 24 +++++++++++++++------
>  fs/f2fs/segment.h           |  4 ++++
>  fs/f2fs/super.c             | 21 ++++++++++++++++---
>  include/trace/events/f2fs.h | 14 ++++++++++++-
>  7 files changed, 102 insertions(+), 24 deletions(-)
> 
> diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
> index 06bb2042385e..49b7e3918484 100644
> --- a/fs/f2fs/data.c
> +++ b/fs/f2fs/data.c
> @@ -282,21 +282,30 @@ static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode,
>  				nid_t ino, pgoff_t idx, enum page_type type)
>  {
>  	enum page_type btype = PAGE_TYPE_OF_BIO(type);
> -	struct f2fs_bio_info *io = &sbi->write_io[btype];
> -	bool ret;
> +	enum temp_type temp;
> +	struct f2fs_bio_info *io;
> +	bool ret = false;
>  
> -	down_read(&io->io_rwsem);
> -	ret = __has_merged_page(io, inode, ino, idx);
> -	up_read(&io->io_rwsem);
> +	for (temp = HOT; temp < NR_TEMP_TYPE; temp++) {
> +		io = sbi->write_io[btype] + temp;
> +
> +		down_read(&io->io_rwsem);
> +		ret = __has_merged_page(io, inode, ino, idx);
> +		up_read(&io->io_rwsem);
> +
> +		/* TODO: use HOT temp only for meta pages now. */
> +		if (ret || btype == META)
> +			break;
> +	}
>  	return ret;
>  }
>  
>  static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi,
>  				struct inode *inode, nid_t ino, pgoff_t idx,
> -				enum page_type type)
> +				enum page_type type, enum temp_type temp)
>  {
>  	enum page_type btype = PAGE_TYPE_OF_BIO(type);
> -	struct f2fs_bio_info *io = &sbi->write_io[btype];
> +	struct f2fs_bio_info *io = sbi->write_io[btype] + temp;
>  
>  	down_write(&io->io_rwsem);
>  
> @@ -316,17 +325,34 @@ static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi,
>  	up_write(&io->io_rwsem);
>  }
>  
> +static void __submit_merged_write_cond(struct f2fs_sb_info *sbi,
> +				struct inode *inode, nid_t ino, pgoff_t idx,
> +				enum page_type type, bool force)
> +{
> +	enum temp_type temp;
> +
> +	if (!force && !has_merged_page(sbi, inode, ino, idx, type))
> +		return;
> +
> +	for (temp = HOT; temp < NR_TEMP_TYPE; temp++) {
> +		__f2fs_submit_merged_write(sbi, inode, ino, idx, type, temp);
> +
> +		/* TODO: use HOT temp only for meta pages now. */
> +		if (type >= META)
> +			break;
> +	}
> +}
> +
>  void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type)
>  {
> -	__f2fs_submit_merged_write(sbi, NULL, 0, 0, type);
> +	__submit_merged_write_cond(sbi, NULL, 0, 0, type, true);
>  }
>  
>  void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi,
>  				struct inode *inode, nid_t ino, pgoff_t idx,
>  				enum page_type type)
>  {
> -	if (has_merged_page(sbi, inode, ino, idx, type))
> -		__f2fs_submit_merged_write(sbi, inode, ino, idx, type);
> +	__submit_merged_write_cond(sbi, inode, ino, idx, type, false);
>  }
>  
>  void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi)
> @@ -369,7 +395,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
>  {
>  	struct f2fs_sb_info *sbi = fio->sbi;
>  	enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
> -	struct f2fs_bio_info *io = &sbi->write_io[btype];
> +	struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp;
>  	struct page *bio_page;
>  	int err = 0;
>  
> @@ -405,8 +431,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
>  		io->fio = *fio;
>  	}
>  
> -	if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) <
> -							PAGE_SIZE) {
> +	if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) < PAGE_SIZE) {
>  		__submit_merged_bio(io);
>  		goto alloc_new;
>  	}
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index bf837458cb18..90e97bc11972 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -792,9 +792,17 @@ enum page_type {
>  	OPU,
>  };
>  
> +enum temp_type {
> +	HOT = 0,	/* must be zero for meta bio */
> +	WARM,
> +	COLD,
> +	NR_TEMP_TYPE,
> +};
> +
>  struct f2fs_io_info {
>  	struct f2fs_sb_info *sbi;	/* f2fs_sb_info pointer */
>  	enum page_type type;	/* contains DATA/NODE/META/META_FLUSH */
> +	enum temp_type temp;	/* contains HOT/WARM/COLD */
>  	int op;			/* contains REQ_OP_ */
>  	int op_flags;		/* req_flag_bits */
>  	block_t new_blkaddr;	/* new block address to be written */
> @@ -880,7 +888,7 @@ struct f2fs_sb_info {
>  
>  	/* for bio operations */
>  	struct f2fs_bio_info read_io;			/* for read bios */
> -	struct f2fs_bio_info write_io[NR_PAGE_TYPE];	/* for write bios */
> +	struct f2fs_bio_info *write_io[NR_PAGE_TYPE];	/* for write bios */
>  	struct mutex wio_mutex[NODE + 1];	/* bio ordering for NODE/DATA */
>  	int write_io_size_bits;			/* Write IO size bits */
>  	mempool_t *write_io_dummy;		/* Dummy pages */
> diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
> index 67b87155bc48..e2b13558a915 100644
> --- a/fs/f2fs/gc.c
> +++ b/fs/f2fs/gc.c
> @@ -586,6 +586,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
>  	struct f2fs_io_info fio = {
>  		.sbi = F2FS_I_SB(inode),
>  		.type = DATA,
> +		.temp = COLD,
>  		.op = REQ_OP_READ,
>  		.op_flags = 0,
>  		.encrypted_page = NULL,
> @@ -712,6 +713,7 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,
>  		struct f2fs_io_info fio = {
>  			.sbi = F2FS_I_SB(inode),
>  			.type = DATA,
> +			.temp = COLD,
>  			.op = REQ_OP_WRITE,
>  			.op_flags = REQ_SYNC,
>  			.old_blkaddr = NULL_ADDR,
> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
> index c9f3a2faee21..da4fd2c29e86 100644
> --- a/fs/f2fs/segment.c
> +++ b/fs/f2fs/segment.c
> @@ -2084,17 +2084,29 @@ static int __get_segment_type_6(struct f2fs_io_info *fio)
>  
>  static int __get_segment_type(struct f2fs_io_info *fio)
>  {
> +	int type;
> +
>  	switch (fio->sbi->active_logs) {
>  	case 2:
> -		return __get_segment_type_2(fio);
> +		type = __get_segment_type_2(fio);
> +		break;
>  	case 4:
> -		return __get_segment_type_4(fio);
> +		type = __get_segment_type_4(fio);
> +		break;
> +	case 6:
> +		type = __get_segment_type_6(fio);
> +		break;
> +	default:
> +		f2fs_bug_on(fio->sbi, true);
>  	}
>  
> -	/* NR_CURSEG_TYPE(6) logs by default */
> -	f2fs_bug_on(fio->sbi, fio->sbi->active_logs != NR_CURSEG_TYPE);
> -
> -	return __get_segment_type_6(fio);
> +	if (IS_HOT(type))
> +		fio->temp = HOT;
> +	else if (IS_WARM(type))
> +		fio->temp = WARM;
> +	else
> +		fio->temp = COLD;
> +	return type;
>  }
>  
>  void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
> diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
> index 10bf05d4cff4..e9ba1f1d9723 100644
> --- a/fs/f2fs/segment.h
> +++ b/fs/f2fs/segment.h
> @@ -27,6 +27,10 @@
>  #define IS_DATASEG(t)	((t) <= CURSEG_COLD_DATA)
>  #define IS_NODESEG(t)	((t) >= CURSEG_HOT_NODE)
>  
> +#define IS_HOT(t)	((t) == CURSEG_HOT_NODE || (t) == CURSEG_HOT_DATA)
> +#define IS_WARM(t)	((t) == CURSEG_WARM_NODE || (t) == CURSEG_WARM_DATA)
> +#define IS_COLD(t)	((t) == CURSEG_COLD_NODE || (t) == CURSEG_COLD_DATA)
> +
>  #define IS_CURSEG(sbi, seg)						\
>  	(((seg) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) ||	\
>  	 ((seg) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) ||	\
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index 104a571a41c0..91599c9c3ef6 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -768,6 +768,7 @@ static void destroy_device_list(struct f2fs_sb_info *sbi)
>  static void f2fs_put_super(struct super_block *sb)
>  {
>  	struct f2fs_sb_info *sbi = F2FS_SB(sb);
> +	int i;
>  
>  	if (sbi->s_proc) {
>  		remove_proc_entry("segment_info", sbi->s_proc);
> @@ -838,6 +839,8 @@ static void f2fs_put_super(struct super_block *sb)
>  	destroy_device_list(sbi);
>  	mempool_destroy(sbi->write_io_dummy);
>  	destroy_percpu_info(sbi);
> +	for (i = 0; i < NR_PAGE_TYPE; i++)
> +		kfree(sbi->write_io[i]);
>  	kfree(sbi);
>  }
>  
> @@ -1954,9 +1957,19 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>  	sbi->read_io.sbi = sbi;
>  	sbi->read_io.bio = NULL;
>  	for (i = 0; i < NR_PAGE_TYPE; i++) {
> -		init_rwsem(&sbi->write_io[i].io_rwsem);
> -		sbi->write_io[i].sbi = sbi;
> -		sbi->write_io[i].bio = NULL;
> +		int n = (i == META) ? 1: NR_TEMP_TYPE;
> +		int j;
> +
> +		sbi->write_io[i] = kmalloc(n * sizeof(struct f2fs_bio_info),
> +								GFP_KERNEL);
> +		if (!sbi->write_io[i])
> +			goto free_options;
> +
> +		for (j = HOT; j < n; j++) {
> +			init_rwsem(&sbi->write_io[i][j].io_rwsem);
> +			sbi->write_io[i][j].sbi = sbi;
> +			sbi->write_io[i][j].bio = NULL;
> +		}
>  	}
>  
>  	init_rwsem(&sbi->cp_rwsem);
> @@ -2202,6 +2215,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>  free_io_dummy:
>  	mempool_destroy(sbi->write_io_dummy);
>  free_options:
> +	for (i = 0; i < NR_PAGE_TYPE; i++)
> +		kfree(sbi->write_io[i]);
>  	destroy_percpu_info(sbi);
>  	kfree(options);
>  free_sb_buf:
> diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
> index 5805d92893a8..6f77a2755abb 100644
> --- a/include/trace/events/f2fs.h
> +++ b/include/trace/events/f2fs.h
> @@ -19,6 +19,9 @@ TRACE_DEFINE_ENUM(INMEM_INVALIDATE);
>  TRACE_DEFINE_ENUM(INMEM_REVOKE);
>  TRACE_DEFINE_ENUM(IPU);
>  TRACE_DEFINE_ENUM(OPU);
> +TRACE_DEFINE_ENUM(HOT);
> +TRACE_DEFINE_ENUM(WARM);
> +TRACE_DEFINE_ENUM(COLD);
>  TRACE_DEFINE_ENUM(CURSEG_HOT_DATA);
>  TRACE_DEFINE_ENUM(CURSEG_WARM_DATA);
>  TRACE_DEFINE_ENUM(CURSEG_COLD_DATA);
> @@ -59,6 +62,12 @@ TRACE_DEFINE_ENUM(CP_TRIMMED);
>  		{ IPU,		"IN-PLACE" },				\
>  		{ OPU,		"OUT-OF-PLACE" })
>  
> +#define show_block_temp(temp)						\
> +	__print_symbolic(temp,						\
> +		{ HOT,		"HOT" },				\
> +		{ WARM,		"WARM" },				\
> +		{ COLD,		"COLD" })
> +
>  #define F2FS_OP_FLAGS (REQ_RAHEAD | REQ_SYNC | REQ_META | REQ_PRIO |	\
>  			REQ_PREFLUSH | REQ_FUA)
>  #define F2FS_BIO_FLAG_MASK(t)	(t & F2FS_OP_FLAGS)
> @@ -757,6 +766,7 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
>  		__field(block_t, new_blkaddr)
>  		__field(int, op)
>  		__field(int, op_flags)
> +		__field(int, temp)
>  		__field(int, type)
>  	),
>  
> @@ -768,16 +778,18 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
>  		__entry->new_blkaddr	= fio->new_blkaddr;
>  		__entry->op		= fio->op;
>  		__entry->op_flags	= fio->op_flags;
> +		__entry->temp		= fio->temp;
>  		__entry->type		= fio->type;
>  	),
>  
>  	TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, "
> -		"oldaddr = 0x%llx, newaddr = 0x%llx, rw = %s(%s), type = %s",
> +		"oldaddr = 0x%llx, newaddr = 0x%llx, rw = %s(%s), type = %s_%s",
>  		show_dev_ino(__entry),
>  		(unsigned long)__entry->index,
>  		(unsigned long long)__entry->old_blkaddr,
>  		(unsigned long long)__entry->new_blkaddr,
>  		show_bio_type(__entry->op, __entry->op_flags),
> +		show_block_temp(__entry->temp),
>  		show_block_type(__entry->type))
>  );
>  
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] f2fs: split bio cache
  2017-05-11  2:20       ` Chao Yu
@ 2017-05-11  2:35         ` Jaegeuk Kim
  2017-05-12  3:19           ` Chao Yu
  0 siblings, 1 reply; 9+ messages in thread
From: Jaegeuk Kim @ 2017-05-11  2:35 UTC (permalink / raw)
  To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, chao

On 05/11, Chao Yu wrote:
> On 2017/5/11 7:50, Jaegeuk Kim wrote:
> > On 05/09, Chao Yu wrote:
> >> Hi Jaegeuk,
> >>
> >> On 2017/5/9 5:23, Jaegeuk Kim wrote:
> >>> Hi Chao,
> >>>
> >>> I can't see a strong reason to split meta from data/node and rename the existing
> >>> function names. Instead, how about keeping the existing one while adding some
> >>> page types to deal with log types?
> >>
> >> Hmm.. before write this patch, I have thought about this implementation which
> >> adds HOT_DATA/WARM_DATA/.. into page_type enum, but the final target is making
> >> different temperature log-header being with independent bio cache, io lock, and
> >> io list, eliminating interaction of different temperature IOs, also expanding
> >> f2fs' scalability when adding more log-headers. If we don't split meta from
> >> data/node, it's a little bit hard to approach this. What do you think?
> > 
> > I submitted clean-up patches. How about this on top of them?
> 
> After splitting, bio caches is connected to log-header, so why not moving bio
> cache into log-header (SM_I(sbi)->curseg_array)? after the merging:
> - we could avoid redundant enum. e.g. temp_type, page_type::{DATA/NODE}, since
> we have seg_type enum instead.
> - once we add special log-header like journal log or random IO log making
> DATA/NODE and HOT/WARM/COLD non-orthogonalization, we just need to change few
> codes to adjust it.

Well, I perfer to keep block allocation and IO control in a separate way as is.
Moreover, I don't think performance gain would be large enough comparing to what
we need to change both of whole flows.

Thanks,

> 
> How do you think?
> 
> Thanks,
> 
> > 
> > ---
> >  fs/f2fs/data.c              | 51 +++++++++++++++++++++++++++++++++------------
> >  fs/f2fs/f2fs.h              | 10 ++++++++-
> >  fs/f2fs/gc.c                |  2 ++
> >  fs/f2fs/segment.c           | 24 +++++++++++++++------
> >  fs/f2fs/segment.h           |  4 ++++
> >  fs/f2fs/super.c             | 21 ++++++++++++++++---
> >  include/trace/events/f2fs.h | 14 ++++++++++++-
> >  7 files changed, 102 insertions(+), 24 deletions(-)
> > 
> > diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
> > index 06bb2042385e..49b7e3918484 100644
> > --- a/fs/f2fs/data.c
> > +++ b/fs/f2fs/data.c
> > @@ -282,21 +282,30 @@ static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode,
> >  				nid_t ino, pgoff_t idx, enum page_type type)
> >  {
> >  	enum page_type btype = PAGE_TYPE_OF_BIO(type);
> > -	struct f2fs_bio_info *io = &sbi->write_io[btype];
> > -	bool ret;
> > +	enum temp_type temp;
> > +	struct f2fs_bio_info *io;
> > +	bool ret = false;
> >  
> > -	down_read(&io->io_rwsem);
> > -	ret = __has_merged_page(io, inode, ino, idx);
> > -	up_read(&io->io_rwsem);
> > +	for (temp = HOT; temp < NR_TEMP_TYPE; temp++) {
> > +		io = sbi->write_io[btype] + temp;
> > +
> > +		down_read(&io->io_rwsem);
> > +		ret = __has_merged_page(io, inode, ino, idx);
> > +		up_read(&io->io_rwsem);
> > +
> > +		/* TODO: use HOT temp only for meta pages now. */
> > +		if (ret || btype == META)
> > +			break;
> > +	}
> >  	return ret;
> >  }
> >  
> >  static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi,
> >  				struct inode *inode, nid_t ino, pgoff_t idx,
> > -				enum page_type type)
> > +				enum page_type type, enum temp_type temp)
> >  {
> >  	enum page_type btype = PAGE_TYPE_OF_BIO(type);
> > -	struct f2fs_bio_info *io = &sbi->write_io[btype];
> > +	struct f2fs_bio_info *io = sbi->write_io[btype] + temp;
> >  
> >  	down_write(&io->io_rwsem);
> >  
> > @@ -316,17 +325,34 @@ static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi,
> >  	up_write(&io->io_rwsem);
> >  }
> >  
> > +static void __submit_merged_write_cond(struct f2fs_sb_info *sbi,
> > +				struct inode *inode, nid_t ino, pgoff_t idx,
> > +				enum page_type type, bool force)
> > +{
> > +	enum temp_type temp;
> > +
> > +	if (!force && !has_merged_page(sbi, inode, ino, idx, type))
> > +		return;
> > +
> > +	for (temp = HOT; temp < NR_TEMP_TYPE; temp++) {
> > +		__f2fs_submit_merged_write(sbi, inode, ino, idx, type, temp);
> > +
> > +		/* TODO: use HOT temp only for meta pages now. */
> > +		if (type >= META)
> > +			break;
> > +	}
> > +}
> > +
> >  void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type)
> >  {
> > -	__f2fs_submit_merged_write(sbi, NULL, 0, 0, type);
> > +	__submit_merged_write_cond(sbi, NULL, 0, 0, type, true);
> >  }
> >  
> >  void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi,
> >  				struct inode *inode, nid_t ino, pgoff_t idx,
> >  				enum page_type type)
> >  {
> > -	if (has_merged_page(sbi, inode, ino, idx, type))
> > -		__f2fs_submit_merged_write(sbi, inode, ino, idx, type);
> > +	__submit_merged_write_cond(sbi, inode, ino, idx, type, false);
> >  }
> >  
> >  void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi)
> > @@ -369,7 +395,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
> >  {
> >  	struct f2fs_sb_info *sbi = fio->sbi;
> >  	enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
> > -	struct f2fs_bio_info *io = &sbi->write_io[btype];
> > +	struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp;
> >  	struct page *bio_page;
> >  	int err = 0;
> >  
> > @@ -405,8 +431,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
> >  		io->fio = *fio;
> >  	}
> >  
> > -	if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) <
> > -							PAGE_SIZE) {
> > +	if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) < PAGE_SIZE) {
> >  		__submit_merged_bio(io);
> >  		goto alloc_new;
> >  	}
> > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> > index bf837458cb18..90e97bc11972 100644
> > --- a/fs/f2fs/f2fs.h
> > +++ b/fs/f2fs/f2fs.h
> > @@ -792,9 +792,17 @@ enum page_type {
> >  	OPU,
> >  };
> >  
> > +enum temp_type {
> > +	HOT = 0,	/* must be zero for meta bio */
> > +	WARM,
> > +	COLD,
> > +	NR_TEMP_TYPE,
> > +};
> > +
> >  struct f2fs_io_info {
> >  	struct f2fs_sb_info *sbi;	/* f2fs_sb_info pointer */
> >  	enum page_type type;	/* contains DATA/NODE/META/META_FLUSH */
> > +	enum temp_type temp;	/* contains HOT/WARM/COLD */
> >  	int op;			/* contains REQ_OP_ */
> >  	int op_flags;		/* req_flag_bits */
> >  	block_t new_blkaddr;	/* new block address to be written */
> > @@ -880,7 +888,7 @@ struct f2fs_sb_info {
> >  
> >  	/* for bio operations */
> >  	struct f2fs_bio_info read_io;			/* for read bios */
> > -	struct f2fs_bio_info write_io[NR_PAGE_TYPE];	/* for write bios */
> > +	struct f2fs_bio_info *write_io[NR_PAGE_TYPE];	/* for write bios */
> >  	struct mutex wio_mutex[NODE + 1];	/* bio ordering for NODE/DATA */
> >  	int write_io_size_bits;			/* Write IO size bits */
> >  	mempool_t *write_io_dummy;		/* Dummy pages */
> > diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
> > index 67b87155bc48..e2b13558a915 100644
> > --- a/fs/f2fs/gc.c
> > +++ b/fs/f2fs/gc.c
> > @@ -586,6 +586,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
> >  	struct f2fs_io_info fio = {
> >  		.sbi = F2FS_I_SB(inode),
> >  		.type = DATA,
> > +		.temp = COLD,
> >  		.op = REQ_OP_READ,
> >  		.op_flags = 0,
> >  		.encrypted_page = NULL,
> > @@ -712,6 +713,7 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,
> >  		struct f2fs_io_info fio = {
> >  			.sbi = F2FS_I_SB(inode),
> >  			.type = DATA,
> > +			.temp = COLD,
> >  			.op = REQ_OP_WRITE,
> >  			.op_flags = REQ_SYNC,
> >  			.old_blkaddr = NULL_ADDR,
> > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
> > index c9f3a2faee21..da4fd2c29e86 100644
> > --- a/fs/f2fs/segment.c
> > +++ b/fs/f2fs/segment.c
> > @@ -2084,17 +2084,29 @@ static int __get_segment_type_6(struct f2fs_io_info *fio)
> >  
> >  static int __get_segment_type(struct f2fs_io_info *fio)
> >  {
> > +	int type;
> > +
> >  	switch (fio->sbi->active_logs) {
> >  	case 2:
> > -		return __get_segment_type_2(fio);
> > +		type = __get_segment_type_2(fio);
> > +		break;
> >  	case 4:
> > -		return __get_segment_type_4(fio);
> > +		type = __get_segment_type_4(fio);
> > +		break;
> > +	case 6:
> > +		type = __get_segment_type_6(fio);
> > +		break;
> > +	default:
> > +		f2fs_bug_on(fio->sbi, true);
> >  	}
> >  
> > -	/* NR_CURSEG_TYPE(6) logs by default */
> > -	f2fs_bug_on(fio->sbi, fio->sbi->active_logs != NR_CURSEG_TYPE);
> > -
> > -	return __get_segment_type_6(fio);
> > +	if (IS_HOT(type))
> > +		fio->temp = HOT;
> > +	else if (IS_WARM(type))
> > +		fio->temp = WARM;
> > +	else
> > +		fio->temp = COLD;
> > +	return type;
> >  }
> >  
> >  void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
> > diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
> > index 10bf05d4cff4..e9ba1f1d9723 100644
> > --- a/fs/f2fs/segment.h
> > +++ b/fs/f2fs/segment.h
> > @@ -27,6 +27,10 @@
> >  #define IS_DATASEG(t)	((t) <= CURSEG_COLD_DATA)
> >  #define IS_NODESEG(t)	((t) >= CURSEG_HOT_NODE)
> >  
> > +#define IS_HOT(t)	((t) == CURSEG_HOT_NODE || (t) == CURSEG_HOT_DATA)
> > +#define IS_WARM(t)	((t) == CURSEG_WARM_NODE || (t) == CURSEG_WARM_DATA)
> > +#define IS_COLD(t)	((t) == CURSEG_COLD_NODE || (t) == CURSEG_COLD_DATA)
> > +
> >  #define IS_CURSEG(sbi, seg)						\
> >  	(((seg) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) ||	\
> >  	 ((seg) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) ||	\
> > diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> > index 104a571a41c0..91599c9c3ef6 100644
> > --- a/fs/f2fs/super.c
> > +++ b/fs/f2fs/super.c
> > @@ -768,6 +768,7 @@ static void destroy_device_list(struct f2fs_sb_info *sbi)
> >  static void f2fs_put_super(struct super_block *sb)
> >  {
> >  	struct f2fs_sb_info *sbi = F2FS_SB(sb);
> > +	int i;
> >  
> >  	if (sbi->s_proc) {
> >  		remove_proc_entry("segment_info", sbi->s_proc);
> > @@ -838,6 +839,8 @@ static void f2fs_put_super(struct super_block *sb)
> >  	destroy_device_list(sbi);
> >  	mempool_destroy(sbi->write_io_dummy);
> >  	destroy_percpu_info(sbi);
> > +	for (i = 0; i < NR_PAGE_TYPE; i++)
> > +		kfree(sbi->write_io[i]);
> >  	kfree(sbi);
> >  }
> >  
> > @@ -1954,9 +1957,19 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> >  	sbi->read_io.sbi = sbi;
> >  	sbi->read_io.bio = NULL;
> >  	for (i = 0; i < NR_PAGE_TYPE; i++) {
> > -		init_rwsem(&sbi->write_io[i].io_rwsem);
> > -		sbi->write_io[i].sbi = sbi;
> > -		sbi->write_io[i].bio = NULL;
> > +		int n = (i == META) ? 1: NR_TEMP_TYPE;
> > +		int j;
> > +
> > +		sbi->write_io[i] = kmalloc(n * sizeof(struct f2fs_bio_info),
> > +								GFP_KERNEL);
> > +		if (!sbi->write_io[i])
> > +			goto free_options;
> > +
> > +		for (j = HOT; j < n; j++) {
> > +			init_rwsem(&sbi->write_io[i][j].io_rwsem);
> > +			sbi->write_io[i][j].sbi = sbi;
> > +			sbi->write_io[i][j].bio = NULL;
> > +		}
> >  	}
> >  
> >  	init_rwsem(&sbi->cp_rwsem);
> > @@ -2202,6 +2215,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> >  free_io_dummy:
> >  	mempool_destroy(sbi->write_io_dummy);
> >  free_options:
> > +	for (i = 0; i < NR_PAGE_TYPE; i++)
> > +		kfree(sbi->write_io[i]);
> >  	destroy_percpu_info(sbi);
> >  	kfree(options);
> >  free_sb_buf:
> > diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
> > index 5805d92893a8..6f77a2755abb 100644
> > --- a/include/trace/events/f2fs.h
> > +++ b/include/trace/events/f2fs.h
> > @@ -19,6 +19,9 @@ TRACE_DEFINE_ENUM(INMEM_INVALIDATE);
> >  TRACE_DEFINE_ENUM(INMEM_REVOKE);
> >  TRACE_DEFINE_ENUM(IPU);
> >  TRACE_DEFINE_ENUM(OPU);
> > +TRACE_DEFINE_ENUM(HOT);
> > +TRACE_DEFINE_ENUM(WARM);
> > +TRACE_DEFINE_ENUM(COLD);
> >  TRACE_DEFINE_ENUM(CURSEG_HOT_DATA);
> >  TRACE_DEFINE_ENUM(CURSEG_WARM_DATA);
> >  TRACE_DEFINE_ENUM(CURSEG_COLD_DATA);
> > @@ -59,6 +62,12 @@ TRACE_DEFINE_ENUM(CP_TRIMMED);
> >  		{ IPU,		"IN-PLACE" },				\
> >  		{ OPU,		"OUT-OF-PLACE" })
> >  
> > +#define show_block_temp(temp)						\
> > +	__print_symbolic(temp,						\
> > +		{ HOT,		"HOT" },				\
> > +		{ WARM,		"WARM" },				\
> > +		{ COLD,		"COLD" })
> > +
> >  #define F2FS_OP_FLAGS (REQ_RAHEAD | REQ_SYNC | REQ_META | REQ_PRIO |	\
> >  			REQ_PREFLUSH | REQ_FUA)
> >  #define F2FS_BIO_FLAG_MASK(t)	(t & F2FS_OP_FLAGS)
> > @@ -757,6 +766,7 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
> >  		__field(block_t, new_blkaddr)
> >  		__field(int, op)
> >  		__field(int, op_flags)
> > +		__field(int, temp)
> >  		__field(int, type)
> >  	),
> >  
> > @@ -768,16 +778,18 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
> >  		__entry->new_blkaddr	= fio->new_blkaddr;
> >  		__entry->op		= fio->op;
> >  		__entry->op_flags	= fio->op_flags;
> > +		__entry->temp		= fio->temp;
> >  		__entry->type		= fio->type;
> >  	),
> >  
> >  	TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, "
> > -		"oldaddr = 0x%llx, newaddr = 0x%llx, rw = %s(%s), type = %s",
> > +		"oldaddr = 0x%llx, newaddr = 0x%llx, rw = %s(%s), type = %s_%s",
> >  		show_dev_ino(__entry),
> >  		(unsigned long)__entry->index,
> >  		(unsigned long long)__entry->old_blkaddr,
> >  		(unsigned long long)__entry->new_blkaddr,
> >  		show_bio_type(__entry->op, __entry->op_flags),
> > +		show_block_temp(__entry->temp),
> >  		show_block_type(__entry->type))
> >  );
> >  
> > 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] f2fs: split bio cache
  2017-05-11  2:35         ` Jaegeuk Kim
@ 2017-05-12  3:19           ` Chao Yu
  2017-05-12 17:43             ` [f2fs-dev] " Jaegeuk Kim
  0 siblings, 1 reply; 9+ messages in thread
From: Chao Yu @ 2017-05-12  3:19 UTC (permalink / raw)
  To: Jaegeuk Kim; +Cc: linux-f2fs-devel, linux-kernel, chao

On 2017/5/11 10:35, Jaegeuk Kim wrote:
> On 05/11, Chao Yu wrote:
>> On 2017/5/11 7:50, Jaegeuk Kim wrote:
>>> On 05/09, Chao Yu wrote:
>>>> Hi Jaegeuk,
>>>>
>>>> On 2017/5/9 5:23, Jaegeuk Kim wrote:
>>>>> Hi Chao,
>>>>>
>>>>> I can't see a strong reason to split meta from data/node and rename the existing
>>>>> function names. Instead, how about keeping the existing one while adding some
>>>>> page types to deal with log types?
>>>>
>>>> Hmm.. before write this patch, I have thought about this implementation which
>>>> adds HOT_DATA/WARM_DATA/.. into page_type enum, but the final target is making
>>>> different temperature log-header being with independent bio cache, io lock, and
>>>> io list, eliminating interaction of different temperature IOs, also expanding
>>>> f2fs' scalability when adding more log-headers. If we don't split meta from
>>>> data/node, it's a little bit hard to approach this. What do you think?
>>>
>>> I submitted clean-up patches. How about this on top of them?
>>
>> After splitting, bio caches is connected to log-header, so why not moving bio
>> cache into log-header (SM_I(sbi)->curseg_array)? after the merging:
>> - we could avoid redundant enum. e.g. temp_type, page_type::{DATA/NODE}, since
>> we have seg_type enum instead.
>> - once we add special log-header like journal log or random IO log making
>> DATA/NODE and HOT/WARM/COLD non-orthogonalization, we just need to change few
>> codes to adjust it.
> 
> Well, I perfer to keep block allocation and IO control in a separate way as is.
> Moreover, I don't think performance gain would be large enough comparing to what
> we need to change both of whole flows.

Alright, let's use your implementation. ;)

Could you resend this patch? and then I will rebase my patch on this one.

Thanks,

> 
> Thanks,
> 
>>
>> How do you think?
>>
>> Thanks,
>>
>>>
>>> ---
>>>  fs/f2fs/data.c              | 51 +++++++++++++++++++++++++++++++++------------
>>>  fs/f2fs/f2fs.h              | 10 ++++++++-
>>>  fs/f2fs/gc.c                |  2 ++
>>>  fs/f2fs/segment.c           | 24 +++++++++++++++------
>>>  fs/f2fs/segment.h           |  4 ++++
>>>  fs/f2fs/super.c             | 21 ++++++++++++++++---
>>>  include/trace/events/f2fs.h | 14 ++++++++++++-
>>>  7 files changed, 102 insertions(+), 24 deletions(-)
>>>
>>> diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
>>> index 06bb2042385e..49b7e3918484 100644
>>> --- a/fs/f2fs/data.c
>>> +++ b/fs/f2fs/data.c
>>> @@ -282,21 +282,30 @@ static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode,
>>>  				nid_t ino, pgoff_t idx, enum page_type type)
>>>  {
>>>  	enum page_type btype = PAGE_TYPE_OF_BIO(type);
>>> -	struct f2fs_bio_info *io = &sbi->write_io[btype];
>>> -	bool ret;
>>> +	enum temp_type temp;
>>> +	struct f2fs_bio_info *io;
>>> +	bool ret = false;
>>>  
>>> -	down_read(&io->io_rwsem);
>>> -	ret = __has_merged_page(io, inode, ino, idx);
>>> -	up_read(&io->io_rwsem);
>>> +	for (temp = HOT; temp < NR_TEMP_TYPE; temp++) {
>>> +		io = sbi->write_io[btype] + temp;
>>> +
>>> +		down_read(&io->io_rwsem);
>>> +		ret = __has_merged_page(io, inode, ino, idx);
>>> +		up_read(&io->io_rwsem);
>>> +
>>> +		/* TODO: use HOT temp only for meta pages now. */
>>> +		if (ret || btype == META)
>>> +			break;
>>> +	}
>>>  	return ret;
>>>  }
>>>  
>>>  static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi,
>>>  				struct inode *inode, nid_t ino, pgoff_t idx,
>>> -				enum page_type type)
>>> +				enum page_type type, enum temp_type temp)
>>>  {
>>>  	enum page_type btype = PAGE_TYPE_OF_BIO(type);
>>> -	struct f2fs_bio_info *io = &sbi->write_io[btype];
>>> +	struct f2fs_bio_info *io = sbi->write_io[btype] + temp;
>>>  
>>>  	down_write(&io->io_rwsem);
>>>  
>>> @@ -316,17 +325,34 @@ static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi,
>>>  	up_write(&io->io_rwsem);
>>>  }
>>>  
>>> +static void __submit_merged_write_cond(struct f2fs_sb_info *sbi,
>>> +				struct inode *inode, nid_t ino, pgoff_t idx,
>>> +				enum page_type type, bool force)
>>> +{
>>> +	enum temp_type temp;
>>> +
>>> +	if (!force && !has_merged_page(sbi, inode, ino, idx, type))
>>> +		return;
>>> +
>>> +	for (temp = HOT; temp < NR_TEMP_TYPE; temp++) {
>>> +		__f2fs_submit_merged_write(sbi, inode, ino, idx, type, temp);
>>> +
>>> +		/* TODO: use HOT temp only for meta pages now. */
>>> +		if (type >= META)
>>> +			break;
>>> +	}
>>> +}
>>> +
>>>  void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type)
>>>  {
>>> -	__f2fs_submit_merged_write(sbi, NULL, 0, 0, type);
>>> +	__submit_merged_write_cond(sbi, NULL, 0, 0, type, true);
>>>  }
>>>  
>>>  void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi,
>>>  				struct inode *inode, nid_t ino, pgoff_t idx,
>>>  				enum page_type type)
>>>  {
>>> -	if (has_merged_page(sbi, inode, ino, idx, type))
>>> -		__f2fs_submit_merged_write(sbi, inode, ino, idx, type);
>>> +	__submit_merged_write_cond(sbi, inode, ino, idx, type, false);
>>>  }
>>>  
>>>  void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi)
>>> @@ -369,7 +395,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
>>>  {
>>>  	struct f2fs_sb_info *sbi = fio->sbi;
>>>  	enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
>>> -	struct f2fs_bio_info *io = &sbi->write_io[btype];
>>> +	struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp;
>>>  	struct page *bio_page;
>>>  	int err = 0;
>>>  
>>> @@ -405,8 +431,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
>>>  		io->fio = *fio;
>>>  	}
>>>  
>>> -	if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) <
>>> -							PAGE_SIZE) {
>>> +	if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) < PAGE_SIZE) {
>>>  		__submit_merged_bio(io);
>>>  		goto alloc_new;
>>>  	}
>>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
>>> index bf837458cb18..90e97bc11972 100644
>>> --- a/fs/f2fs/f2fs.h
>>> +++ b/fs/f2fs/f2fs.h
>>> @@ -792,9 +792,17 @@ enum page_type {
>>>  	OPU,
>>>  };
>>>  
>>> +enum temp_type {
>>> +	HOT = 0,	/* must be zero for meta bio */
>>> +	WARM,
>>> +	COLD,
>>> +	NR_TEMP_TYPE,
>>> +};
>>> +
>>>  struct f2fs_io_info {
>>>  	struct f2fs_sb_info *sbi;	/* f2fs_sb_info pointer */
>>>  	enum page_type type;	/* contains DATA/NODE/META/META_FLUSH */
>>> +	enum temp_type temp;	/* contains HOT/WARM/COLD */
>>>  	int op;			/* contains REQ_OP_ */
>>>  	int op_flags;		/* req_flag_bits */
>>>  	block_t new_blkaddr;	/* new block address to be written */
>>> @@ -880,7 +888,7 @@ struct f2fs_sb_info {
>>>  
>>>  	/* for bio operations */
>>>  	struct f2fs_bio_info read_io;			/* for read bios */
>>> -	struct f2fs_bio_info write_io[NR_PAGE_TYPE];	/* for write bios */
>>> +	struct f2fs_bio_info *write_io[NR_PAGE_TYPE];	/* for write bios */
>>>  	struct mutex wio_mutex[NODE + 1];	/* bio ordering for NODE/DATA */
>>>  	int write_io_size_bits;			/* Write IO size bits */
>>>  	mempool_t *write_io_dummy;		/* Dummy pages */
>>> diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
>>> index 67b87155bc48..e2b13558a915 100644
>>> --- a/fs/f2fs/gc.c
>>> +++ b/fs/f2fs/gc.c
>>> @@ -586,6 +586,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
>>>  	struct f2fs_io_info fio = {
>>>  		.sbi = F2FS_I_SB(inode),
>>>  		.type = DATA,
>>> +		.temp = COLD,
>>>  		.op = REQ_OP_READ,
>>>  		.op_flags = 0,
>>>  		.encrypted_page = NULL,
>>> @@ -712,6 +713,7 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,
>>>  		struct f2fs_io_info fio = {
>>>  			.sbi = F2FS_I_SB(inode),
>>>  			.type = DATA,
>>> +			.temp = COLD,
>>>  			.op = REQ_OP_WRITE,
>>>  			.op_flags = REQ_SYNC,
>>>  			.old_blkaddr = NULL_ADDR,
>>> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
>>> index c9f3a2faee21..da4fd2c29e86 100644
>>> --- a/fs/f2fs/segment.c
>>> +++ b/fs/f2fs/segment.c
>>> @@ -2084,17 +2084,29 @@ static int __get_segment_type_6(struct f2fs_io_info *fio)
>>>  
>>>  static int __get_segment_type(struct f2fs_io_info *fio)
>>>  {
>>> +	int type;
>>> +
>>>  	switch (fio->sbi->active_logs) {
>>>  	case 2:
>>> -		return __get_segment_type_2(fio);
>>> +		type = __get_segment_type_2(fio);
>>> +		break;
>>>  	case 4:
>>> -		return __get_segment_type_4(fio);
>>> +		type = __get_segment_type_4(fio);
>>> +		break;
>>> +	case 6:
>>> +		type = __get_segment_type_6(fio);
>>> +		break;
>>> +	default:
>>> +		f2fs_bug_on(fio->sbi, true);
>>>  	}
>>>  
>>> -	/* NR_CURSEG_TYPE(6) logs by default */
>>> -	f2fs_bug_on(fio->sbi, fio->sbi->active_logs != NR_CURSEG_TYPE);
>>> -
>>> -	return __get_segment_type_6(fio);
>>> +	if (IS_HOT(type))
>>> +		fio->temp = HOT;
>>> +	else if (IS_WARM(type))
>>> +		fio->temp = WARM;
>>> +	else
>>> +		fio->temp = COLD;
>>> +	return type;
>>>  }
>>>  
>>>  void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
>>> diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
>>> index 10bf05d4cff4..e9ba1f1d9723 100644
>>> --- a/fs/f2fs/segment.h
>>> +++ b/fs/f2fs/segment.h
>>> @@ -27,6 +27,10 @@
>>>  #define IS_DATASEG(t)	((t) <= CURSEG_COLD_DATA)
>>>  #define IS_NODESEG(t)	((t) >= CURSEG_HOT_NODE)
>>>  
>>> +#define IS_HOT(t)	((t) == CURSEG_HOT_NODE || (t) == CURSEG_HOT_DATA)
>>> +#define IS_WARM(t)	((t) == CURSEG_WARM_NODE || (t) == CURSEG_WARM_DATA)
>>> +#define IS_COLD(t)	((t) == CURSEG_COLD_NODE || (t) == CURSEG_COLD_DATA)
>>> +
>>>  #define IS_CURSEG(sbi, seg)						\
>>>  	(((seg) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) ||	\
>>>  	 ((seg) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) ||	\
>>> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
>>> index 104a571a41c0..91599c9c3ef6 100644
>>> --- a/fs/f2fs/super.c
>>> +++ b/fs/f2fs/super.c
>>> @@ -768,6 +768,7 @@ static void destroy_device_list(struct f2fs_sb_info *sbi)
>>>  static void f2fs_put_super(struct super_block *sb)
>>>  {
>>>  	struct f2fs_sb_info *sbi = F2FS_SB(sb);
>>> +	int i;
>>>  
>>>  	if (sbi->s_proc) {
>>>  		remove_proc_entry("segment_info", sbi->s_proc);
>>> @@ -838,6 +839,8 @@ static void f2fs_put_super(struct super_block *sb)
>>>  	destroy_device_list(sbi);
>>>  	mempool_destroy(sbi->write_io_dummy);
>>>  	destroy_percpu_info(sbi);
>>> +	for (i = 0; i < NR_PAGE_TYPE; i++)
>>> +		kfree(sbi->write_io[i]);
>>>  	kfree(sbi);
>>>  }
>>>  
>>> @@ -1954,9 +1957,19 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>>>  	sbi->read_io.sbi = sbi;
>>>  	sbi->read_io.bio = NULL;
>>>  	for (i = 0; i < NR_PAGE_TYPE; i++) {
>>> -		init_rwsem(&sbi->write_io[i].io_rwsem);
>>> -		sbi->write_io[i].sbi = sbi;
>>> -		sbi->write_io[i].bio = NULL;
>>> +		int n = (i == META) ? 1: NR_TEMP_TYPE;
>>> +		int j;
>>> +
>>> +		sbi->write_io[i] = kmalloc(n * sizeof(struct f2fs_bio_info),
>>> +								GFP_KERNEL);
>>> +		if (!sbi->write_io[i])
>>> +			goto free_options;
>>> +
>>> +		for (j = HOT; j < n; j++) {
>>> +			init_rwsem(&sbi->write_io[i][j].io_rwsem);
>>> +			sbi->write_io[i][j].sbi = sbi;
>>> +			sbi->write_io[i][j].bio = NULL;
>>> +		}
>>>  	}
>>>  
>>>  	init_rwsem(&sbi->cp_rwsem);
>>> @@ -2202,6 +2215,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
>>>  free_io_dummy:
>>>  	mempool_destroy(sbi->write_io_dummy);
>>>  free_options:
>>> +	for (i = 0; i < NR_PAGE_TYPE; i++)
>>> +		kfree(sbi->write_io[i]);
>>>  	destroy_percpu_info(sbi);
>>>  	kfree(options);
>>>  free_sb_buf:
>>> diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
>>> index 5805d92893a8..6f77a2755abb 100644
>>> --- a/include/trace/events/f2fs.h
>>> +++ b/include/trace/events/f2fs.h
>>> @@ -19,6 +19,9 @@ TRACE_DEFINE_ENUM(INMEM_INVALIDATE);
>>>  TRACE_DEFINE_ENUM(INMEM_REVOKE);
>>>  TRACE_DEFINE_ENUM(IPU);
>>>  TRACE_DEFINE_ENUM(OPU);
>>> +TRACE_DEFINE_ENUM(HOT);
>>> +TRACE_DEFINE_ENUM(WARM);
>>> +TRACE_DEFINE_ENUM(COLD);
>>>  TRACE_DEFINE_ENUM(CURSEG_HOT_DATA);
>>>  TRACE_DEFINE_ENUM(CURSEG_WARM_DATA);
>>>  TRACE_DEFINE_ENUM(CURSEG_COLD_DATA);
>>> @@ -59,6 +62,12 @@ TRACE_DEFINE_ENUM(CP_TRIMMED);
>>>  		{ IPU,		"IN-PLACE" },				\
>>>  		{ OPU,		"OUT-OF-PLACE" })
>>>  
>>> +#define show_block_temp(temp)						\
>>> +	__print_symbolic(temp,						\
>>> +		{ HOT,		"HOT" },				\
>>> +		{ WARM,		"WARM" },				\
>>> +		{ COLD,		"COLD" })
>>> +
>>>  #define F2FS_OP_FLAGS (REQ_RAHEAD | REQ_SYNC | REQ_META | REQ_PRIO |	\
>>>  			REQ_PREFLUSH | REQ_FUA)
>>>  #define F2FS_BIO_FLAG_MASK(t)	(t & F2FS_OP_FLAGS)
>>> @@ -757,6 +766,7 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
>>>  		__field(block_t, new_blkaddr)
>>>  		__field(int, op)
>>>  		__field(int, op_flags)
>>> +		__field(int, temp)
>>>  		__field(int, type)
>>>  	),
>>>  
>>> @@ -768,16 +778,18 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
>>>  		__entry->new_blkaddr	= fio->new_blkaddr;
>>>  		__entry->op		= fio->op;
>>>  		__entry->op_flags	= fio->op_flags;
>>> +		__entry->temp		= fio->temp;
>>>  		__entry->type		= fio->type;
>>>  	),
>>>  
>>>  	TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, "
>>> -		"oldaddr = 0x%llx, newaddr = 0x%llx, rw = %s(%s), type = %s",
>>> +		"oldaddr = 0x%llx, newaddr = 0x%llx, rw = %s(%s), type = %s_%s",
>>>  		show_dev_ino(__entry),
>>>  		(unsigned long)__entry->index,
>>>  		(unsigned long long)__entry->old_blkaddr,
>>>  		(unsigned long long)__entry->new_blkaddr,
>>>  		show_bio_type(__entry->op, __entry->op_flags),
>>> +		show_block_temp(__entry->temp),
>>>  		show_block_type(__entry->type))
>>>  );
>>>  
>>>
> 
> .
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [f2fs-dev] [PATCH] f2fs: split bio cache
  2017-05-12  3:19           ` Chao Yu
@ 2017-05-12 17:43             ` Jaegeuk Kim
  0 siblings, 0 replies; 9+ messages in thread
From: Jaegeuk Kim @ 2017-05-12 17:43 UTC (permalink / raw)
  To: Chao Yu; +Cc: chao, linux-kernel, linux-f2fs-devel

On 05/12, Chao Yu wrote:
> On 2017/5/11 10:35, Jaegeuk Kim wrote:
> > On 05/11, Chao Yu wrote:
> >> On 2017/5/11 7:50, Jaegeuk Kim wrote:
> >>> On 05/09, Chao Yu wrote:
> >>>> Hi Jaegeuk,
> >>>>
> >>>> On 2017/5/9 5:23, Jaegeuk Kim wrote:
> >>>>> Hi Chao,
> >>>>>
> >>>>> I can't see a strong reason to split meta from data/node and rename the existing
> >>>>> function names. Instead, how about keeping the existing one while adding some
> >>>>> page types to deal with log types?
> >>>>
> >>>> Hmm.. before write this patch, I have thought about this implementation which
> >>>> adds HOT_DATA/WARM_DATA/.. into page_type enum, but the final target is making
> >>>> different temperature log-header being with independent bio cache, io lock, and
> >>>> io list, eliminating interaction of different temperature IOs, also expanding
> >>>> f2fs' scalability when adding more log-headers. If we don't split meta from
> >>>> data/node, it's a little bit hard to approach this. What do you think?
> >>>
> >>> I submitted clean-up patches. How about this on top of them?
> >>
> >> After splitting, bio caches is connected to log-header, so why not moving bio
> >> cache into log-header (SM_I(sbi)->curseg_array)? after the merging:
> >> - we could avoid redundant enum. e.g. temp_type, page_type::{DATA/NODE}, since
> >> we have seg_type enum instead.
> >> - once we add special log-header like journal log or random IO log making
> >> DATA/NODE and HOT/WARM/COLD non-orthogonalization, we just need to change few
> >> codes to adjust it.
> > 
> > Well, I perfer to keep block allocation and IO control in a separate way as is.
> > Moreover, I don't think performance gain would be large enough comparing to what
> > we need to change both of whole flows.
> 
> Alright, let's use your implementation. ;)
> 
> Could you resend this patch? and then I will rebase my patch on this one.

I just pushed them into dev-test branch, and have been conducting stress tests.

Thanks,

> 
> Thanks,
> 
> > 
> > Thanks,
> > 
> >>
> >> How do you think?
> >>
> >> Thanks,
> >>
> >>>
> >>> ---
> >>>  fs/f2fs/data.c              | 51 +++++++++++++++++++++++++++++++++------------
> >>>  fs/f2fs/f2fs.h              | 10 ++++++++-
> >>>  fs/f2fs/gc.c                |  2 ++
> >>>  fs/f2fs/segment.c           | 24 +++++++++++++++------
> >>>  fs/f2fs/segment.h           |  4 ++++
> >>>  fs/f2fs/super.c             | 21 ++++++++++++++++---
> >>>  include/trace/events/f2fs.h | 14 ++++++++++++-
> >>>  7 files changed, 102 insertions(+), 24 deletions(-)
> >>>
> >>> diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
> >>> index 06bb2042385e..49b7e3918484 100644
> >>> --- a/fs/f2fs/data.c
> >>> +++ b/fs/f2fs/data.c
> >>> @@ -282,21 +282,30 @@ static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode,
> >>>  				nid_t ino, pgoff_t idx, enum page_type type)
> >>>  {
> >>>  	enum page_type btype = PAGE_TYPE_OF_BIO(type);
> >>> -	struct f2fs_bio_info *io = &sbi->write_io[btype];
> >>> -	bool ret;
> >>> +	enum temp_type temp;
> >>> +	struct f2fs_bio_info *io;
> >>> +	bool ret = false;
> >>>  
> >>> -	down_read(&io->io_rwsem);
> >>> -	ret = __has_merged_page(io, inode, ino, idx);
> >>> -	up_read(&io->io_rwsem);
> >>> +	for (temp = HOT; temp < NR_TEMP_TYPE; temp++) {
> >>> +		io = sbi->write_io[btype] + temp;
> >>> +
> >>> +		down_read(&io->io_rwsem);
> >>> +		ret = __has_merged_page(io, inode, ino, idx);
> >>> +		up_read(&io->io_rwsem);
> >>> +
> >>> +		/* TODO: use HOT temp only for meta pages now. */
> >>> +		if (ret || btype == META)
> >>> +			break;
> >>> +	}
> >>>  	return ret;
> >>>  }
> >>>  
> >>>  static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi,
> >>>  				struct inode *inode, nid_t ino, pgoff_t idx,
> >>> -				enum page_type type)
> >>> +				enum page_type type, enum temp_type temp)
> >>>  {
> >>>  	enum page_type btype = PAGE_TYPE_OF_BIO(type);
> >>> -	struct f2fs_bio_info *io = &sbi->write_io[btype];
> >>> +	struct f2fs_bio_info *io = sbi->write_io[btype] + temp;
> >>>  
> >>>  	down_write(&io->io_rwsem);
> >>>  
> >>> @@ -316,17 +325,34 @@ static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi,
> >>>  	up_write(&io->io_rwsem);
> >>>  }
> >>>  
> >>> +static void __submit_merged_write_cond(struct f2fs_sb_info *sbi,
> >>> +				struct inode *inode, nid_t ino, pgoff_t idx,
> >>> +				enum page_type type, bool force)
> >>> +{
> >>> +	enum temp_type temp;
> >>> +
> >>> +	if (!force && !has_merged_page(sbi, inode, ino, idx, type))
> >>> +		return;
> >>> +
> >>> +	for (temp = HOT; temp < NR_TEMP_TYPE; temp++) {
> >>> +		__f2fs_submit_merged_write(sbi, inode, ino, idx, type, temp);
> >>> +
> >>> +		/* TODO: use HOT temp only for meta pages now. */
> >>> +		if (type >= META)
> >>> +			break;
> >>> +	}
> >>> +}
> >>> +
> >>>  void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type)
> >>>  {
> >>> -	__f2fs_submit_merged_write(sbi, NULL, 0, 0, type);
> >>> +	__submit_merged_write_cond(sbi, NULL, 0, 0, type, true);
> >>>  }
> >>>  
> >>>  void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi,
> >>>  				struct inode *inode, nid_t ino, pgoff_t idx,
> >>>  				enum page_type type)
> >>>  {
> >>> -	if (has_merged_page(sbi, inode, ino, idx, type))
> >>> -		__f2fs_submit_merged_write(sbi, inode, ino, idx, type);
> >>> +	__submit_merged_write_cond(sbi, inode, ino, idx, type, false);
> >>>  }
> >>>  
> >>>  void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi)
> >>> @@ -369,7 +395,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
> >>>  {
> >>>  	struct f2fs_sb_info *sbi = fio->sbi;
> >>>  	enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
> >>> -	struct f2fs_bio_info *io = &sbi->write_io[btype];
> >>> +	struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp;
> >>>  	struct page *bio_page;
> >>>  	int err = 0;
> >>>  
> >>> @@ -405,8 +431,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
> >>>  		io->fio = *fio;
> >>>  	}
> >>>  
> >>> -	if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) <
> >>> -							PAGE_SIZE) {
> >>> +	if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) < PAGE_SIZE) {
> >>>  		__submit_merged_bio(io);
> >>>  		goto alloc_new;
> >>>  	}
> >>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> >>> index bf837458cb18..90e97bc11972 100644
> >>> --- a/fs/f2fs/f2fs.h
> >>> +++ b/fs/f2fs/f2fs.h
> >>> @@ -792,9 +792,17 @@ enum page_type {
> >>>  	OPU,
> >>>  };
> >>>  
> >>> +enum temp_type {
> >>> +	HOT = 0,	/* must be zero for meta bio */
> >>> +	WARM,
> >>> +	COLD,
> >>> +	NR_TEMP_TYPE,
> >>> +};
> >>> +
> >>>  struct f2fs_io_info {
> >>>  	struct f2fs_sb_info *sbi;	/* f2fs_sb_info pointer */
> >>>  	enum page_type type;	/* contains DATA/NODE/META/META_FLUSH */
> >>> +	enum temp_type temp;	/* contains HOT/WARM/COLD */
> >>>  	int op;			/* contains REQ_OP_ */
> >>>  	int op_flags;		/* req_flag_bits */
> >>>  	block_t new_blkaddr;	/* new block address to be written */
> >>> @@ -880,7 +888,7 @@ struct f2fs_sb_info {
> >>>  
> >>>  	/* for bio operations */
> >>>  	struct f2fs_bio_info read_io;			/* for read bios */
> >>> -	struct f2fs_bio_info write_io[NR_PAGE_TYPE];	/* for write bios */
> >>> +	struct f2fs_bio_info *write_io[NR_PAGE_TYPE];	/* for write bios */
> >>>  	struct mutex wio_mutex[NODE + 1];	/* bio ordering for NODE/DATA */
> >>>  	int write_io_size_bits;			/* Write IO size bits */
> >>>  	mempool_t *write_io_dummy;		/* Dummy pages */
> >>> diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
> >>> index 67b87155bc48..e2b13558a915 100644
> >>> --- a/fs/f2fs/gc.c
> >>> +++ b/fs/f2fs/gc.c
> >>> @@ -586,6 +586,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
> >>>  	struct f2fs_io_info fio = {
> >>>  		.sbi = F2FS_I_SB(inode),
> >>>  		.type = DATA,
> >>> +		.temp = COLD,
> >>>  		.op = REQ_OP_READ,
> >>>  		.op_flags = 0,
> >>>  		.encrypted_page = NULL,
> >>> @@ -712,6 +713,7 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,
> >>>  		struct f2fs_io_info fio = {
> >>>  			.sbi = F2FS_I_SB(inode),
> >>>  			.type = DATA,
> >>> +			.temp = COLD,
> >>>  			.op = REQ_OP_WRITE,
> >>>  			.op_flags = REQ_SYNC,
> >>>  			.old_blkaddr = NULL_ADDR,
> >>> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
> >>> index c9f3a2faee21..da4fd2c29e86 100644
> >>> --- a/fs/f2fs/segment.c
> >>> +++ b/fs/f2fs/segment.c
> >>> @@ -2084,17 +2084,29 @@ static int __get_segment_type_6(struct f2fs_io_info *fio)
> >>>  
> >>>  static int __get_segment_type(struct f2fs_io_info *fio)
> >>>  {
> >>> +	int type;
> >>> +
> >>>  	switch (fio->sbi->active_logs) {
> >>>  	case 2:
> >>> -		return __get_segment_type_2(fio);
> >>> +		type = __get_segment_type_2(fio);
> >>> +		break;
> >>>  	case 4:
> >>> -		return __get_segment_type_4(fio);
> >>> +		type = __get_segment_type_4(fio);
> >>> +		break;
> >>> +	case 6:
> >>> +		type = __get_segment_type_6(fio);
> >>> +		break;
> >>> +	default:
> >>> +		f2fs_bug_on(fio->sbi, true);
> >>>  	}
> >>>  
> >>> -	/* NR_CURSEG_TYPE(6) logs by default */
> >>> -	f2fs_bug_on(fio->sbi, fio->sbi->active_logs != NR_CURSEG_TYPE);
> >>> -
> >>> -	return __get_segment_type_6(fio);
> >>> +	if (IS_HOT(type))
> >>> +		fio->temp = HOT;
> >>> +	else if (IS_WARM(type))
> >>> +		fio->temp = WARM;
> >>> +	else
> >>> +		fio->temp = COLD;
> >>> +	return type;
> >>>  }
> >>>  
> >>>  void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
> >>> diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
> >>> index 10bf05d4cff4..e9ba1f1d9723 100644
> >>> --- a/fs/f2fs/segment.h
> >>> +++ b/fs/f2fs/segment.h
> >>> @@ -27,6 +27,10 @@
> >>>  #define IS_DATASEG(t)	((t) <= CURSEG_COLD_DATA)
> >>>  #define IS_NODESEG(t)	((t) >= CURSEG_HOT_NODE)
> >>>  
> >>> +#define IS_HOT(t)	((t) == CURSEG_HOT_NODE || (t) == CURSEG_HOT_DATA)
> >>> +#define IS_WARM(t)	((t) == CURSEG_WARM_NODE || (t) == CURSEG_WARM_DATA)
> >>> +#define IS_COLD(t)	((t) == CURSEG_COLD_NODE || (t) == CURSEG_COLD_DATA)
> >>> +
> >>>  #define IS_CURSEG(sbi, seg)						\
> >>>  	(((seg) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) ||	\
> >>>  	 ((seg) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) ||	\
> >>> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> >>> index 104a571a41c0..91599c9c3ef6 100644
> >>> --- a/fs/f2fs/super.c
> >>> +++ b/fs/f2fs/super.c
> >>> @@ -768,6 +768,7 @@ static void destroy_device_list(struct f2fs_sb_info *sbi)
> >>>  static void f2fs_put_super(struct super_block *sb)
> >>>  {
> >>>  	struct f2fs_sb_info *sbi = F2FS_SB(sb);
> >>> +	int i;
> >>>  
> >>>  	if (sbi->s_proc) {
> >>>  		remove_proc_entry("segment_info", sbi->s_proc);
> >>> @@ -838,6 +839,8 @@ static void f2fs_put_super(struct super_block *sb)
> >>>  	destroy_device_list(sbi);
> >>>  	mempool_destroy(sbi->write_io_dummy);
> >>>  	destroy_percpu_info(sbi);
> >>> +	for (i = 0; i < NR_PAGE_TYPE; i++)
> >>> +		kfree(sbi->write_io[i]);
> >>>  	kfree(sbi);
> >>>  }
> >>>  
> >>> @@ -1954,9 +1957,19 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> >>>  	sbi->read_io.sbi = sbi;
> >>>  	sbi->read_io.bio = NULL;
> >>>  	for (i = 0; i < NR_PAGE_TYPE; i++) {
> >>> -		init_rwsem(&sbi->write_io[i].io_rwsem);
> >>> -		sbi->write_io[i].sbi = sbi;
> >>> -		sbi->write_io[i].bio = NULL;
> >>> +		int n = (i == META) ? 1: NR_TEMP_TYPE;
> >>> +		int j;
> >>> +
> >>> +		sbi->write_io[i] = kmalloc(n * sizeof(struct f2fs_bio_info),
> >>> +								GFP_KERNEL);
> >>> +		if (!sbi->write_io[i])
> >>> +			goto free_options;
> >>> +
> >>> +		for (j = HOT; j < n; j++) {
> >>> +			init_rwsem(&sbi->write_io[i][j].io_rwsem);
> >>> +			sbi->write_io[i][j].sbi = sbi;
> >>> +			sbi->write_io[i][j].bio = NULL;
> >>> +		}
> >>>  	}
> >>>  
> >>>  	init_rwsem(&sbi->cp_rwsem);
> >>> @@ -2202,6 +2215,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
> >>>  free_io_dummy:
> >>>  	mempool_destroy(sbi->write_io_dummy);
> >>>  free_options:
> >>> +	for (i = 0; i < NR_PAGE_TYPE; i++)
> >>> +		kfree(sbi->write_io[i]);
> >>>  	destroy_percpu_info(sbi);
> >>>  	kfree(options);
> >>>  free_sb_buf:
> >>> diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h
> >>> index 5805d92893a8..6f77a2755abb 100644
> >>> --- a/include/trace/events/f2fs.h
> >>> +++ b/include/trace/events/f2fs.h
> >>> @@ -19,6 +19,9 @@ TRACE_DEFINE_ENUM(INMEM_INVALIDATE);
> >>>  TRACE_DEFINE_ENUM(INMEM_REVOKE);
> >>>  TRACE_DEFINE_ENUM(IPU);
> >>>  TRACE_DEFINE_ENUM(OPU);
> >>> +TRACE_DEFINE_ENUM(HOT);
> >>> +TRACE_DEFINE_ENUM(WARM);
> >>> +TRACE_DEFINE_ENUM(COLD);
> >>>  TRACE_DEFINE_ENUM(CURSEG_HOT_DATA);
> >>>  TRACE_DEFINE_ENUM(CURSEG_WARM_DATA);
> >>>  TRACE_DEFINE_ENUM(CURSEG_COLD_DATA);
> >>> @@ -59,6 +62,12 @@ TRACE_DEFINE_ENUM(CP_TRIMMED);
> >>>  		{ IPU,		"IN-PLACE" },				\
> >>>  		{ OPU,		"OUT-OF-PLACE" })
> >>>  
> >>> +#define show_block_temp(temp)						\
> >>> +	__print_symbolic(temp,						\
> >>> +		{ HOT,		"HOT" },				\
> >>> +		{ WARM,		"WARM" },				\
> >>> +		{ COLD,		"COLD" })
> >>> +
> >>>  #define F2FS_OP_FLAGS (REQ_RAHEAD | REQ_SYNC | REQ_META | REQ_PRIO |	\
> >>>  			REQ_PREFLUSH | REQ_FUA)
> >>>  #define F2FS_BIO_FLAG_MASK(t)	(t & F2FS_OP_FLAGS)
> >>> @@ -757,6 +766,7 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
> >>>  		__field(block_t, new_blkaddr)
> >>>  		__field(int, op)
> >>>  		__field(int, op_flags)
> >>> +		__field(int, temp)
> >>>  		__field(int, type)
> >>>  	),
> >>>  
> >>> @@ -768,16 +778,18 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
> >>>  		__entry->new_blkaddr	= fio->new_blkaddr;
> >>>  		__entry->op		= fio->op;
> >>>  		__entry->op_flags	= fio->op_flags;
> >>> +		__entry->temp		= fio->temp;
> >>>  		__entry->type		= fio->type;
> >>>  	),
> >>>  
> >>>  	TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, "
> >>> -		"oldaddr = 0x%llx, newaddr = 0x%llx, rw = %s(%s), type = %s",
> >>> +		"oldaddr = 0x%llx, newaddr = 0x%llx, rw = %s(%s), type = %s_%s",
> >>>  		show_dev_ino(__entry),
> >>>  		(unsigned long)__entry->index,
> >>>  		(unsigned long long)__entry->old_blkaddr,
> >>>  		(unsigned long long)__entry->new_blkaddr,
> >>>  		show_bio_type(__entry->op, __entry->op_flags),
> >>> +		show_block_temp(__entry->temp),
> >>>  		show_block_type(__entry->type))
> >>>  );
> >>>  
> >>>
> > 
> > .
> > 
> 
> 
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> Linux-f2fs-devel mailing list
> Linux-f2fs-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2017-05-12 17:43 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-08 12:36 [PATCH] f2fs: split bio cache Chao Yu
2017-05-08 21:23 ` Jaegeuk Kim
2017-05-09  1:49   ` Chao Yu
2017-05-10  3:19     ` Chao Yu
2017-05-10 23:50     ` Jaegeuk Kim
2017-05-11  2:20       ` Chao Yu
2017-05-11  2:35         ` Jaegeuk Kim
2017-05-12  3:19           ` Chao Yu
2017-05-12 17:43             ` [f2fs-dev] " Jaegeuk Kim

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).