mirror of https://gitee.com/openkylin/linux.git
f2fs: split bio cache
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> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
81377bd628
commit
a912b54d3a
|
@ -282,27 +282,32 @@ 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)
|
||||||
{
|
{
|
||||||
enum page_type btype = PAGE_TYPE_OF_BIO(type);
|
enum page_type btype = PAGE_TYPE_OF_BIO(type);
|
||||||
struct f2fs_bio_info *io = &sbi->write_io[btype];
|
enum temp_type temp;
|
||||||
bool ret;
|
struct f2fs_bio_info *io;
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
down_read(&io->io_rwsem);
|
for (temp = HOT; temp < NR_TEMP_TYPE; temp++) {
|
||||||
ret = __has_merged_page(io, inode, ino, idx);
|
io = sbi->write_io[btype] + temp;
|
||||||
up_read(&io->io_rwsem);
|
|
||||||
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi,
|
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 temp_type temp)
|
||||||
enum page_type type)
|
|
||||||
{
|
{
|
||||||
enum page_type btype = PAGE_TYPE_OF_BIO(type);
|
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);
|
down_write(&io->io_rwsem);
|
||||||
|
|
||||||
if (!__has_merged_page(io, inode, ino, idx))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* change META to META_FLUSH in the checkpoint procedure */
|
/* change META to META_FLUSH in the checkpoint procedure */
|
||||||
if (type >= META_FLUSH) {
|
if (type >= META_FLUSH) {
|
||||||
io->fio.type = META_FLUSH;
|
io->fio.type = META_FLUSH;
|
||||||
|
@ -312,21 +317,38 @@ static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi,
|
||||||
io->fio.op_flags |= REQ_PREFLUSH | REQ_FUA;
|
io->fio.op_flags |= REQ_PREFLUSH | REQ_FUA;
|
||||||
}
|
}
|
||||||
__submit_merged_bio(io);
|
__submit_merged_bio(io);
|
||||||
out:
|
|
||||||
up_write(&io->io_rwsem);
|
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, 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)
|
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,
|
void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi,
|
||||||
struct inode *inode, nid_t ino, pgoff_t idx,
|
struct inode *inode, nid_t ino, pgoff_t idx,
|
||||||
enum page_type type)
|
enum page_type type)
|
||||||
{
|
{
|
||||||
if (has_merged_page(sbi, inode, ino, idx, type))
|
__submit_merged_write_cond(sbi, inode, ino, idx, type, false);
|
||||||
__f2fs_submit_merged_write(sbi, inode, ino, idx, type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi)
|
void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi)
|
||||||
|
@ -369,7 +391,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
|
||||||
{
|
{
|
||||||
struct f2fs_sb_info *sbi = fio->sbi;
|
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->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;
|
struct page *bio_page;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
@ -405,8 +427,7 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
|
||||||
io->fio = *fio;
|
io->fio = *fio;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) <
|
if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) < PAGE_SIZE) {
|
||||||
PAGE_SIZE) {
|
|
||||||
__submit_merged_bio(io);
|
__submit_merged_bio(io);
|
||||||
goto alloc_new;
|
goto alloc_new;
|
||||||
}
|
}
|
||||||
|
|
|
@ -792,9 +792,17 @@ enum page_type {
|
||||||
OPU,
|
OPU,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum temp_type {
|
||||||
|
HOT = 0, /* must be zero for meta bio */
|
||||||
|
WARM,
|
||||||
|
COLD,
|
||||||
|
NR_TEMP_TYPE,
|
||||||
|
};
|
||||||
|
|
||||||
struct f2fs_io_info {
|
struct f2fs_io_info {
|
||||||
struct f2fs_sb_info *sbi; /* f2fs_sb_info pointer */
|
struct f2fs_sb_info *sbi; /* f2fs_sb_info pointer */
|
||||||
enum page_type type; /* contains DATA/NODE/META/META_FLUSH */
|
enum page_type type; /* contains DATA/NODE/META/META_FLUSH */
|
||||||
|
enum temp_type temp; /* contains HOT/WARM/COLD */
|
||||||
int op; /* contains REQ_OP_ */
|
int op; /* contains REQ_OP_ */
|
||||||
int op_flags; /* req_flag_bits */
|
int op_flags; /* req_flag_bits */
|
||||||
block_t new_blkaddr; /* new block address to be written */
|
block_t new_blkaddr; /* new block address to be written */
|
||||||
|
@ -879,7 +887,7 @@ struct f2fs_sb_info {
|
||||||
struct f2fs_sm_info *sm_info; /* segment manager */
|
struct f2fs_sm_info *sm_info; /* segment manager */
|
||||||
|
|
||||||
/* for bio operations */
|
/* for bio operations */
|
||||||
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 */
|
struct mutex wio_mutex[NODE + 1]; /* bio ordering for NODE/DATA */
|
||||||
int write_io_size_bits; /* Write IO size bits */
|
int write_io_size_bits; /* Write IO size bits */
|
||||||
mempool_t *write_io_dummy; /* Dummy pages */
|
mempool_t *write_io_dummy; /* Dummy pages */
|
||||||
|
|
|
@ -586,6 +586,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
|
||||||
struct f2fs_io_info fio = {
|
struct f2fs_io_info fio = {
|
||||||
.sbi = F2FS_I_SB(inode),
|
.sbi = F2FS_I_SB(inode),
|
||||||
.type = DATA,
|
.type = DATA,
|
||||||
|
.temp = COLD,
|
||||||
.op = REQ_OP_READ,
|
.op = REQ_OP_READ,
|
||||||
.op_flags = 0,
|
.op_flags = 0,
|
||||||
.encrypted_page = NULL,
|
.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 = {
|
struct f2fs_io_info fio = {
|
||||||
.sbi = F2FS_I_SB(inode),
|
.sbi = F2FS_I_SB(inode),
|
||||||
.type = DATA,
|
.type = DATA,
|
||||||
|
.temp = COLD,
|
||||||
.op = REQ_OP_WRITE,
|
.op = REQ_OP_WRITE,
|
||||||
.op_flags = REQ_SYNC,
|
.op_flags = REQ_SYNC,
|
||||||
.old_blkaddr = NULL_ADDR,
|
.old_blkaddr = NULL_ADDR,
|
||||||
|
|
|
@ -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)
|
static int __get_segment_type(struct f2fs_io_info *fio)
|
||||||
{
|
{
|
||||||
|
int type = 0;
|
||||||
|
|
||||||
switch (fio->sbi->active_logs) {
|
switch (fio->sbi->active_logs) {
|
||||||
case 2:
|
case 2:
|
||||||
return __get_segment_type_2(fio);
|
type = __get_segment_type_2(fio);
|
||||||
|
break;
|
||||||
case 4:
|
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 */
|
if (IS_HOT(type))
|
||||||
f2fs_bug_on(fio->sbi, fio->sbi->active_logs != NR_CURSEG_TYPE);
|
fio->temp = HOT;
|
||||||
|
else if (IS_WARM(type))
|
||||||
return __get_segment_type_6(fio);
|
fio->temp = WARM;
|
||||||
|
else
|
||||||
|
fio->temp = COLD;
|
||||||
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||||
|
|
|
@ -27,6 +27,10 @@
|
||||||
#define IS_DATASEG(t) ((t) <= CURSEG_COLD_DATA)
|
#define IS_DATASEG(t) ((t) <= CURSEG_COLD_DATA)
|
||||||
#define IS_NODESEG(t) ((t) >= CURSEG_HOT_NODE)
|
#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) \
|
#define IS_CURSEG(sbi, seg) \
|
||||||
(((seg) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) || \
|
(((seg) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) || \
|
||||||
((seg) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) || \
|
((seg) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) || \
|
||||||
|
|
|
@ -768,6 +768,7 @@ static void destroy_device_list(struct f2fs_sb_info *sbi)
|
||||||
static void f2fs_put_super(struct super_block *sb)
|
static void f2fs_put_super(struct super_block *sb)
|
||||||
{
|
{
|
||||||
struct f2fs_sb_info *sbi = F2FS_SB(sb);
|
struct f2fs_sb_info *sbi = F2FS_SB(sb);
|
||||||
|
int i;
|
||||||
|
|
||||||
if (sbi->s_proc) {
|
if (sbi->s_proc) {
|
||||||
remove_proc_entry("segment_info", 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);
|
destroy_device_list(sbi);
|
||||||
mempool_destroy(sbi->write_io_dummy);
|
mempool_destroy(sbi->write_io_dummy);
|
||||||
destroy_percpu_info(sbi);
|
destroy_percpu_info(sbi);
|
||||||
|
for (i = 0; i < NR_PAGE_TYPE; i++)
|
||||||
|
kfree(sbi->write_io[i]);
|
||||||
kfree(sbi);
|
kfree(sbi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1967,9 +1970,19 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
spin_lock_init(&sbi->stat_lock);
|
spin_lock_init(&sbi->stat_lock);
|
||||||
|
|
||||||
for (i = 0; i < NR_PAGE_TYPE; i++) {
|
for (i = 0; i < NR_PAGE_TYPE; i++) {
|
||||||
init_rwsem(&sbi->write_io[i].io_rwsem);
|
int n = (i == META) ? 1: NR_TEMP_TYPE;
|
||||||
sbi->write_io[i].sbi = sbi;
|
int j;
|
||||||
sbi->write_io[i].bio = NULL;
|
|
||||||
|
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);
|
init_rwsem(&sbi->cp_rwsem);
|
||||||
|
@ -2215,6 +2228,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
free_io_dummy:
|
free_io_dummy:
|
||||||
mempool_destroy(sbi->write_io_dummy);
|
mempool_destroy(sbi->write_io_dummy);
|
||||||
free_options:
|
free_options:
|
||||||
|
for (i = 0; i < NR_PAGE_TYPE; i++)
|
||||||
|
kfree(sbi->write_io[i]);
|
||||||
destroy_percpu_info(sbi);
|
destroy_percpu_info(sbi);
|
||||||
kfree(options);
|
kfree(options);
|
||||||
free_sb_buf:
|
free_sb_buf:
|
||||||
|
|
|
@ -19,6 +19,9 @@ TRACE_DEFINE_ENUM(INMEM_INVALIDATE);
|
||||||
TRACE_DEFINE_ENUM(INMEM_REVOKE);
|
TRACE_DEFINE_ENUM(INMEM_REVOKE);
|
||||||
TRACE_DEFINE_ENUM(IPU);
|
TRACE_DEFINE_ENUM(IPU);
|
||||||
TRACE_DEFINE_ENUM(OPU);
|
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_HOT_DATA);
|
||||||
TRACE_DEFINE_ENUM(CURSEG_WARM_DATA);
|
TRACE_DEFINE_ENUM(CURSEG_WARM_DATA);
|
||||||
TRACE_DEFINE_ENUM(CURSEG_COLD_DATA);
|
TRACE_DEFINE_ENUM(CURSEG_COLD_DATA);
|
||||||
|
@ -59,6 +62,12 @@ TRACE_DEFINE_ENUM(CP_TRIMMED);
|
||||||
{ IPU, "IN-PLACE" }, \
|
{ IPU, "IN-PLACE" }, \
|
||||||
{ OPU, "OUT-OF-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 | \
|
#define F2FS_OP_FLAGS (REQ_RAHEAD | REQ_SYNC | REQ_META | REQ_PRIO | \
|
||||||
REQ_PREFLUSH | REQ_FUA)
|
REQ_PREFLUSH | REQ_FUA)
|
||||||
#define F2FS_BIO_FLAG_MASK(t) (t & F2FS_OP_FLAGS)
|
#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(block_t, new_blkaddr)
|
||||||
__field(int, op)
|
__field(int, op)
|
||||||
__field(int, op_flags)
|
__field(int, op_flags)
|
||||||
|
__field(int, temp)
|
||||||
__field(int, type)
|
__field(int, type)
|
||||||
),
|
),
|
||||||
|
|
||||||
|
@ -768,16 +778,18 @@ DECLARE_EVENT_CLASS(f2fs__submit_page_bio,
|
||||||
__entry->new_blkaddr = fio->new_blkaddr;
|
__entry->new_blkaddr = fio->new_blkaddr;
|
||||||
__entry->op = fio->op;
|
__entry->op = fio->op;
|
||||||
__entry->op_flags = fio->op_flags;
|
__entry->op_flags = fio->op_flags;
|
||||||
|
__entry->temp = fio->temp;
|
||||||
__entry->type = fio->type;
|
__entry->type = fio->type;
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk("dev = (%d,%d), ino = %lu, page_index = 0x%lx, "
|
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),
|
show_dev_ino(__entry),
|
||||||
(unsigned long)__entry->index,
|
(unsigned long)__entry->index,
|
||||||
(unsigned long long)__entry->old_blkaddr,
|
(unsigned long long)__entry->old_blkaddr,
|
||||||
(unsigned long long)__entry->new_blkaddr,
|
(unsigned long long)__entry->new_blkaddr,
|
||||||
show_bio_type(__entry->op, __entry->op_flags),
|
show_bio_type(__entry->op, __entry->op_flags),
|
||||||
|
show_block_temp(__entry->temp),
|
||||||
show_block_type(__entry->type))
|
show_block_type(__entry->type))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue