f2fs: add mount option for segment allocation policy

This patch adds an mount option, "alloc_mode=%s" having two options, "default"
and "reuse".

In "alloc_mode=reuse" case, f2fs starts to allocate segments from 0'th segment
all the time to reassign segments. It'd be useful for small-sized eMMC parts.

Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
Jaegeuk Kim 2018-02-18 08:50:49 -08:00
parent b798298912
commit 0ffdffc8f1
4 changed files with 47 additions and 0 deletions

View file

@ -172,6 +172,14 @@ offgrpjquota Turn off group journelled quota.
offprjjquota Turn off project journelled quota. offprjjquota Turn off project journelled quota.
quota Enable plain user disk quota accounting. quota Enable plain user disk quota accounting.
noquota Disable all plain disk quota option. noquota Disable all plain disk quota option.
whint_mode=%s Control which write hints are passed down to block
layer. This supports "off", "user-based", and
"fs-based". In "off" mode (default), f2fs does not pass
down hints. In "user-based" mode, f2fs tries to pass
down hints given by users. And in "fs-based" mode, f2fs
passes down hints with its policy.
alloc_mode=%s Adjust block allocation policy, which supports "reuse"
and "default".
================================================================================ ================================================================================
DEBUGFS ENTRIES DEBUGFS ENTRIES

View file

@ -1107,6 +1107,11 @@ enum {
WHINT_MODE_FS, /* pass down hints with F2FS policy */ WHINT_MODE_FS, /* pass down hints with F2FS policy */
}; };
enum {
ALLOC_MODE_DEFAULT, /* stay default */
ALLOC_MODE_REUSE, /* reuse segments as much as possible */
};
struct f2fs_sb_info { struct f2fs_sb_info {
struct super_block *sb; /* pointer to VFS super block */ struct super_block *sb; /* pointer to VFS super block */
struct proc_dir_entry *s_proc; /* proc entry */ struct proc_dir_entry *s_proc; /* proc entry */
@ -1293,6 +1298,9 @@ struct f2fs_sb_info {
#endif #endif
/* For which write hints are passed down to block layer */ /* For which write hints are passed down to block layer */
int whint_mode; int whint_mode;
/* segment allocation policy */
int alloc_mode;
}; };
#ifdef CONFIG_F2FS_FAULT_INJECTION #ifdef CONFIG_F2FS_FAULT_INJECTION

View file

@ -2250,6 +2250,11 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)
if (SIT_I(sbi)->last_victim[ALLOC_NEXT]) if (SIT_I(sbi)->last_victim[ALLOC_NEXT])
return SIT_I(sbi)->last_victim[ALLOC_NEXT]; return SIT_I(sbi)->last_victim[ALLOC_NEXT];
/* find segments from 0 to reuse freed segments */
if (sbi->alloc_mode == ALLOC_MODE_REUSE)
return 0;
return CURSEG_I(sbi, type)->segno; return CURSEG_I(sbi, type)->segno;
} }

View file

@ -130,6 +130,7 @@ enum {
Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv0,
Opt_jqfmt_vfsv1, Opt_jqfmt_vfsv1,
Opt_whint, Opt_whint,
Opt_alloc,
Opt_err, Opt_err,
}; };
@ -184,6 +185,7 @@ static match_table_t f2fs_tokens = {
{Opt_jqfmt_vfsv0, "jqfmt=vfsv0"}, {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
{Opt_jqfmt_vfsv1, "jqfmt=vfsv1"}, {Opt_jqfmt_vfsv1, "jqfmt=vfsv1"},
{Opt_whint, "whint_mode=%s"}, {Opt_whint, "whint_mode=%s"},
{Opt_alloc, "alloc_mode=%s"},
{Opt_err, NULL}, {Opt_err, NULL},
}; };
@ -700,6 +702,23 @@ static int parse_options(struct super_block *sb, char *options)
} }
kfree(name); kfree(name);
break; break;
case Opt_alloc:
name = match_strdup(&args[0]);
if (!name)
return -ENOMEM;
if (strlen(name) == 7 &&
!strncmp(name, "default", 7)) {
sbi->alloc_mode = ALLOC_MODE_DEFAULT;
} else if (strlen(name) == 5 &&
!strncmp(name, "reuse", 5)) {
sbi->alloc_mode = ALLOC_MODE_REUSE;
} else {
kfree(name);
return -EINVAL;
}
kfree(name);
break;
default: default:
f2fs_msg(sb, KERN_ERR, f2fs_msg(sb, KERN_ERR,
"Unrecognized mount option \"%s\" or missing value", "Unrecognized mount option \"%s\" or missing value",
@ -1265,6 +1284,10 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
else if (sbi->whint_mode == WHINT_MODE_FS) else if (sbi->whint_mode == WHINT_MODE_FS)
seq_printf(seq, ",whint_mode=%s", "fs-based"); seq_printf(seq, ",whint_mode=%s", "fs-based");
if (sbi->alloc_mode == ALLOC_MODE_DEFAULT)
seq_printf(seq, ",alloc_mode=%s", "default");
else if (sbi->alloc_mode == ALLOC_MODE_REUSE)
seq_printf(seq, ",alloc_mode=%s", "reuse");
return 0; return 0;
} }
@ -1274,6 +1297,7 @@ static void default_options(struct f2fs_sb_info *sbi)
sbi->active_logs = NR_CURSEG_TYPE; sbi->active_logs = NR_CURSEG_TYPE;
sbi->inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS; sbi->inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
sbi->whint_mode = WHINT_MODE_OFF; sbi->whint_mode = WHINT_MODE_OFF;
sbi->alloc_mode = ALLOC_MODE_DEFAULT;
set_opt(sbi, BG_GC); set_opt(sbi, BG_GC);
set_opt(sbi, INLINE_XATTR); set_opt(sbi, INLINE_XATTR);
@ -1315,6 +1339,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
bool need_stop_gc = false; bool need_stop_gc = false;
bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE); bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE);
int old_whint_mode = sbi->whint_mode; int old_whint_mode = sbi->whint_mode;
int old_alloc_mode = sbi->alloc_mode;
#ifdef CONFIG_F2FS_FAULT_INJECTION #ifdef CONFIG_F2FS_FAULT_INJECTION
struct f2fs_fault_info ffi = sbi->fault_info; struct f2fs_fault_info ffi = sbi->fault_info;
#endif #endif
@ -1464,6 +1489,7 @@ restore_opts:
sbi->s_qf_names[i] = s_qf_names[i]; sbi->s_qf_names[i] = s_qf_names[i];
} }
#endif #endif
sbi->alloc_mode = old_alloc_mode;
sbi->whint_mode = old_whint_mode; sbi->whint_mode = old_whint_mode;
sbi->mount_opt = org_mount_opt; sbi->mount_opt = org_mount_opt;
sbi->active_logs = active_logs; sbi->active_logs = active_logs;