Commit d615b541 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'f2fs-fix-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs

Pull f2fs fixes from Jaegeuk Kim:
 "This includes major bug fixes introduced in 5.18-rc1 and 5.17+:

   - Remove obsolete whint_mode (5.18-rc1)

   - Fix IO split issue caused by op_flags change in f2fs (5.18-rc1)

   - Fix a wrong condition check to detect IO failure loop (5.18-rc1)

   - Fix wrong data truncation during roll-forward (5.17+)"

* tag 'f2fs-fix-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs:
  f2fs: should not truncate blocks during roll-forward recovery
  f2fs: fix wrong condition check when failing metapage read
  f2fs: keep io_flags to avoid IO split due to different op_flags in two fio holders
  f2fs: remove obsolete whint_mode
parents 0fc74d82 4d8ec912
...@@ -235,12 +235,6 @@ offgrpjquota Turn off group journalled quota. ...@@ -235,12 +235,6 @@ offgrpjquota Turn off group journalled quota.
offprjjquota Turn off project journalled quota. offprjjquota Turn off project journalled 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" alloc_mode=%s Adjust block allocation policy, which supports "reuse"
and "default". and "default".
fsync_mode=%s Control the policy of fsync. Currently supports "posix", fsync_mode=%s Control the policy of fsync. Currently supports "posix",
...@@ -751,70 +745,6 @@ In order to identify whether the data in the victim segment are valid or not, ...@@ -751,70 +745,6 @@ In order to identify whether the data in the victim segment are valid or not,
F2FS manages a bitmap. Each bit represents the validity of a block, and the F2FS manages a bitmap. Each bit represents the validity of a block, and the
bitmap is composed of a bit stream covering whole blocks in main area. bitmap is composed of a bit stream covering whole blocks in main area.
Write-hint Policy
-----------------
1) whint_mode=off. F2FS only passes down WRITE_LIFE_NOT_SET.
2) whint_mode=user-based. F2FS tries to pass down hints given by
users.
===================== ======================== ===================
User F2FS Block
===================== ======================== ===================
N/A META WRITE_LIFE_NOT_SET
N/A HOT_NODE "
N/A WARM_NODE "
N/A COLD_NODE "
ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME
extension list " "
-- buffered io
WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET
WRITE_LIFE_NONE " "
WRITE_LIFE_MEDIUM " "
WRITE_LIFE_LONG " "
-- direct io
WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET
WRITE_LIFE_NONE " WRITE_LIFE_NONE
WRITE_LIFE_MEDIUM " WRITE_LIFE_MEDIUM
WRITE_LIFE_LONG " WRITE_LIFE_LONG
===================== ======================== ===================
3) whint_mode=fs-based. F2FS passes down hints with its policy.
===================== ======================== ===================
User F2FS Block
===================== ======================== ===================
N/A META WRITE_LIFE_MEDIUM;
N/A HOT_NODE WRITE_LIFE_NOT_SET
N/A WARM_NODE "
N/A COLD_NODE WRITE_LIFE_NONE
ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME
extension list " "
-- buffered io
WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_LONG
WRITE_LIFE_NONE " "
WRITE_LIFE_MEDIUM " "
WRITE_LIFE_LONG " "
-- direct io
WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET
WRITE_LIFE_NONE " WRITE_LIFE_NONE
WRITE_LIFE_MEDIUM " WRITE_LIFE_MEDIUM
WRITE_LIFE_LONG " WRITE_LIFE_LONG
===================== ======================== ===================
Fallocate(2) Policy Fallocate(2) Policy
------------------- -------------------
......
...@@ -98,9 +98,9 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index, ...@@ -98,9 +98,9 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index,
} }
if (unlikely(!PageUptodate(page))) { if (unlikely(!PageUptodate(page))) {
if (page->index == sbi->metapage_eio_ofs && if (page->index == sbi->metapage_eio_ofs) {
sbi->metapage_eio_cnt++ == MAX_RETRY_META_PAGE_EIO) { if (sbi->metapage_eio_cnt++ == MAX_RETRY_META_PAGE_EIO)
set_ckpt_flags(sbi, CP_ERROR_FLAG); set_ckpt_flags(sbi, CP_ERROR_FLAG);
} else { } else {
sbi->metapage_eio_ofs = page->index; sbi->metapage_eio_ofs = page->index;
sbi->metapage_eio_cnt = 0; sbi->metapage_eio_cnt = 0;
......
...@@ -388,11 +388,23 @@ int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr) ...@@ -388,11 +388,23 @@ int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr)
return 0; return 0;
} }
static void __attach_io_flag(struct f2fs_io_info *fio, unsigned int io_flag) static unsigned int f2fs_io_flags(struct f2fs_io_info *fio)
{ {
unsigned int temp_mask = (1 << NR_TEMP_TYPE) - 1; unsigned int temp_mask = (1 << NR_TEMP_TYPE) - 1;
unsigned int fua_flag = io_flag & temp_mask; unsigned int fua_flag, meta_flag, io_flag;
unsigned int meta_flag = (io_flag >> NR_TEMP_TYPE) & temp_mask; unsigned int op_flags = 0;
if (fio->op != REQ_OP_WRITE)
return 0;
if (fio->type == DATA)
io_flag = fio->sbi->data_io_flag;
else if (fio->type == NODE)
io_flag = fio->sbi->node_io_flag;
else
return 0;
fua_flag = io_flag & temp_mask;
meta_flag = (io_flag >> NR_TEMP_TYPE) & temp_mask;
/* /*
* data/node io flag bits per temp: * data/node io flag bits per temp:
...@@ -401,9 +413,10 @@ static void __attach_io_flag(struct f2fs_io_info *fio, unsigned int io_flag) ...@@ -401,9 +413,10 @@ static void __attach_io_flag(struct f2fs_io_info *fio, unsigned int io_flag)
* Cold | Warm | Hot | Cold | Warm | Hot | * Cold | Warm | Hot | Cold | Warm | Hot |
*/ */
if ((1 << fio->temp) & meta_flag) if ((1 << fio->temp) & meta_flag)
fio->op_flags |= REQ_META; op_flags |= REQ_META;
if ((1 << fio->temp) & fua_flag) if ((1 << fio->temp) & fua_flag)
fio->op_flags |= REQ_FUA; op_flags |= REQ_FUA;
return op_flags;
} }
static struct bio *__bio_alloc(struct f2fs_io_info *fio, int npages) static struct bio *__bio_alloc(struct f2fs_io_info *fio, int npages)
...@@ -413,14 +426,10 @@ static struct bio *__bio_alloc(struct f2fs_io_info *fio, int npages) ...@@ -413,14 +426,10 @@ static struct bio *__bio_alloc(struct f2fs_io_info *fio, int npages)
sector_t sector; sector_t sector;
struct bio *bio; struct bio *bio;
if (fio->type == DATA)
__attach_io_flag(fio, sbi->data_io_flag);
else if (fio->type == NODE)
__attach_io_flag(fio, sbi->node_io_flag);
bdev = f2fs_target_device(sbi, fio->new_blkaddr, &sector); bdev = f2fs_target_device(sbi, fio->new_blkaddr, &sector);
bio = bio_alloc_bioset(bdev, npages, fio->op | fio->op_flags, GFP_NOIO, bio = bio_alloc_bioset(bdev, npages,
&f2fs_bioset); fio->op | fio->op_flags | f2fs_io_flags(fio),
GFP_NOIO, &f2fs_bioset);
bio->bi_iter.bi_sector = sector; bio->bi_iter.bi_sector = sector;
if (is_read_io(fio->op)) { if (is_read_io(fio->op)) {
bio->bi_end_io = f2fs_read_end_io; bio->bi_end_io = f2fs_read_end_io;
......
...@@ -154,7 +154,6 @@ struct f2fs_mount_info { ...@@ -154,7 +154,6 @@ struct f2fs_mount_info {
int s_jquota_fmt; /* Format of quota to use */ int s_jquota_fmt; /* Format of quota to use */
#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 alloc_mode; /* segment allocation policy */ int alloc_mode; /* segment allocation policy */
int fsync_mode; /* fsync policy */ int fsync_mode; /* fsync policy */
int fs_mode; /* fs mode: LFS or ADAPTIVE */ int fs_mode; /* fs mode: LFS or ADAPTIVE */
...@@ -1333,12 +1332,6 @@ enum { ...@@ -1333,12 +1332,6 @@ enum {
FS_MODE_FRAGMENT_BLK, /* block fragmentation mode */ FS_MODE_FRAGMENT_BLK, /* block fragmentation mode */
}; };
enum {
WHINT_MODE_OFF, /* not pass down write hints */
WHINT_MODE_USER, /* try to pass down hints given by users */
WHINT_MODE_FS, /* pass down hints with F2FS policy */
};
enum { enum {
ALLOC_MODE_DEFAULT, /* stay default */ ALLOC_MODE_DEFAULT, /* stay default */
ALLOC_MODE_REUSE, /* reuse segments as much as possible */ ALLOC_MODE_REUSE, /* reuse segments as much as possible */
...@@ -3657,8 +3650,6 @@ void f2fs_destroy_segment_manager(struct f2fs_sb_info *sbi); ...@@ -3657,8 +3650,6 @@ void f2fs_destroy_segment_manager(struct f2fs_sb_info *sbi);
int __init f2fs_create_segment_manager_caches(void); int __init f2fs_create_segment_manager_caches(void);
void f2fs_destroy_segment_manager_caches(void); void f2fs_destroy_segment_manager_caches(void);
int f2fs_rw_hint_to_seg_type(enum rw_hint hint); int f2fs_rw_hint_to_seg_type(enum rw_hint hint);
enum rw_hint f2fs_io_type_to_rw_hint(struct f2fs_sb_info *sbi,
enum page_type type, enum temp_type temp);
unsigned int f2fs_usable_segs_in_sec(struct f2fs_sb_info *sbi, unsigned int f2fs_usable_segs_in_sec(struct f2fs_sb_info *sbi,
unsigned int segno); unsigned int segno);
unsigned int f2fs_usable_blks_in_seg(struct f2fs_sb_info *sbi, unsigned int f2fs_usable_blks_in_seg(struct f2fs_sb_info *sbi,
......
...@@ -550,7 +550,8 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) ...@@ -550,7 +550,8 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
} }
f2fs_set_inode_flags(inode); f2fs_set_inode_flags(inode);
if (file_should_truncate(inode)) { if (file_should_truncate(inode) &&
!is_sbi_flag_set(sbi, SBI_POR_DOING)) {
ret = f2fs_truncate(inode); ret = f2fs_truncate(inode);
if (ret) if (ret)
goto bad_inode; goto bad_inode;
......
...@@ -3243,101 +3243,6 @@ int f2fs_rw_hint_to_seg_type(enum rw_hint hint) ...@@ -3243,101 +3243,6 @@ int f2fs_rw_hint_to_seg_type(enum rw_hint hint)
} }
} }
/* This returns write hints for each segment type. This hints will be
* passed down to block layer. There are mapping tables which depend on
* the mount option 'whint_mode'.
*
* 1) whint_mode=off. F2FS only passes down WRITE_LIFE_NOT_SET.
*
* 2) whint_mode=user-based. F2FS tries to pass down hints given by users.
*
* User F2FS Block
* ---- ---- -----
* META WRITE_LIFE_NOT_SET
* HOT_NODE "
* WARM_NODE "
* COLD_NODE "
* ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME
* extension list " "
*
* -- buffered io
* WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
* WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
* WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET
* WRITE_LIFE_NONE " "
* WRITE_LIFE_MEDIUM " "
* WRITE_LIFE_LONG " "
*
* -- direct io
* WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
* WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
* WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET
* WRITE_LIFE_NONE " WRITE_LIFE_NONE
* WRITE_LIFE_MEDIUM " WRITE_LIFE_MEDIUM
* WRITE_LIFE_LONG " WRITE_LIFE_LONG
*
* 3) whint_mode=fs-based. F2FS passes down hints with its policy.
*
* User F2FS Block
* ---- ---- -----
* META WRITE_LIFE_MEDIUM;
* HOT_NODE WRITE_LIFE_NOT_SET
* WARM_NODE "
* COLD_NODE WRITE_LIFE_NONE
* ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME
* extension list " "
*
* -- buffered io
* WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
* WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
* WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_LONG
* WRITE_LIFE_NONE " "
* WRITE_LIFE_MEDIUM " "
* WRITE_LIFE_LONG " "
*
* -- direct io
* WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
* WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
* WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET
* WRITE_LIFE_NONE " WRITE_LIFE_NONE
* WRITE_LIFE_MEDIUM " WRITE_LIFE_MEDIUM
* WRITE_LIFE_LONG " WRITE_LIFE_LONG
*/
enum rw_hint f2fs_io_type_to_rw_hint(struct f2fs_sb_info *sbi,
enum page_type type, enum temp_type temp)
{
if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_USER) {
if (type == DATA) {
if (temp == WARM)
return WRITE_LIFE_NOT_SET;
else if (temp == HOT)
return WRITE_LIFE_SHORT;
else if (temp == COLD)
return WRITE_LIFE_EXTREME;
} else {
return WRITE_LIFE_NOT_SET;
}
} else if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_FS) {
if (type == DATA) {
if (temp == WARM)
return WRITE_LIFE_LONG;
else if (temp == HOT)
return WRITE_LIFE_SHORT;
else if (temp == COLD)
return WRITE_LIFE_EXTREME;
} else if (type == NODE) {
if (temp == WARM || temp == HOT)
return WRITE_LIFE_NOT_SET;
else if (temp == COLD)
return WRITE_LIFE_NONE;
} else if (type == META) {
return WRITE_LIFE_MEDIUM;
}
}
return WRITE_LIFE_NOT_SET;
}
static int __get_segment_type_2(struct f2fs_io_info *fio) static int __get_segment_type_2(struct f2fs_io_info *fio)
{ {
if (fio->type == DATA) if (fio->type == DATA)
......
...@@ -138,7 +138,6 @@ enum { ...@@ -138,7 +138,6 @@ enum {
Opt_jqfmt_vfsold, Opt_jqfmt_vfsold,
Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv0,
Opt_jqfmt_vfsv1, Opt_jqfmt_vfsv1,
Opt_whint,
Opt_alloc, Opt_alloc,
Opt_fsync, Opt_fsync,
Opt_test_dummy_encryption, Opt_test_dummy_encryption,
...@@ -214,7 +213,6 @@ static match_table_t f2fs_tokens = { ...@@ -214,7 +213,6 @@ static match_table_t f2fs_tokens = {
{Opt_jqfmt_vfsold, "jqfmt=vfsold"}, {Opt_jqfmt_vfsold, "jqfmt=vfsold"},
{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_alloc, "alloc_mode=%s"}, {Opt_alloc, "alloc_mode=%s"},
{Opt_fsync, "fsync_mode=%s"}, {Opt_fsync, "fsync_mode=%s"},
{Opt_test_dummy_encryption, "test_dummy_encryption=%s"}, {Opt_test_dummy_encryption, "test_dummy_encryption=%s"},
...@@ -975,22 +973,6 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) ...@@ -975,22 +973,6 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
f2fs_info(sbi, "quota operations not supported"); f2fs_info(sbi, "quota operations not supported");
break; break;
#endif #endif
case Opt_whint:
name = match_strdup(&args[0]);
if (!name)
return -ENOMEM;
if (!strcmp(name, "user-based")) {
F2FS_OPTION(sbi).whint_mode = WHINT_MODE_USER;
} else if (!strcmp(name, "off")) {
F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF;
} else if (!strcmp(name, "fs-based")) {
F2FS_OPTION(sbi).whint_mode = WHINT_MODE_FS;
} else {
kfree(name);
return -EINVAL;
}
kfree(name);
break;
case Opt_alloc: case Opt_alloc:
name = match_strdup(&args[0]); name = match_strdup(&args[0]);
if (!name) if (!name)
...@@ -1328,12 +1310,6 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount) ...@@ -1328,12 +1310,6 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
return -EINVAL; return -EINVAL;
} }
/* Not pass down write hints if the number of active logs is lesser
* than NR_CURSEG_PERSIST_TYPE.
*/
if (F2FS_OPTION(sbi).active_logs != NR_CURSEG_PERSIST_TYPE)
F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF;
if (f2fs_sb_has_readonly(sbi) && !f2fs_readonly(sbi->sb)) { if (f2fs_sb_has_readonly(sbi) && !f2fs_readonly(sbi->sb)) {
f2fs_err(sbi, "Allow to mount readonly mode only"); f2fs_err(sbi, "Allow to mount readonly mode only");
return -EROFS; return -EROFS;
...@@ -1978,10 +1954,6 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) ...@@ -1978,10 +1954,6 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
seq_puts(seq, ",prjquota"); seq_puts(seq, ",prjquota");
#endif #endif
f2fs_show_quota_options(seq, sbi->sb); f2fs_show_quota_options(seq, sbi->sb);
if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_USER)
seq_printf(seq, ",whint_mode=%s", "user-based");
else if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_FS)
seq_printf(seq, ",whint_mode=%s", "fs-based");
fscrypt_show_test_dummy_encryption(seq, ',', sbi->sb); fscrypt_show_test_dummy_encryption(seq, ',', sbi->sb);
...@@ -2033,7 +2005,6 @@ static void default_options(struct f2fs_sb_info *sbi) ...@@ -2033,7 +2005,6 @@ static void default_options(struct f2fs_sb_info *sbi)
F2FS_OPTION(sbi).active_logs = NR_CURSEG_PERSIST_TYPE; F2FS_OPTION(sbi).active_logs = NR_CURSEG_PERSIST_TYPE;
F2FS_OPTION(sbi).inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS; F2FS_OPTION(sbi).inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF;
F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT; F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT;
F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX; F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX;
F2FS_OPTION(sbi).s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID); F2FS_OPTION(sbi).s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID);
...@@ -2314,8 +2285,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) ...@@ -2314,8 +2285,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
need_stop_gc = true; need_stop_gc = true;
} }
if (*flags & SB_RDONLY || if (*flags & SB_RDONLY) {
F2FS_OPTION(sbi).whint_mode != org_mount_opt.whint_mode) {
sync_inodes_sb(sb); sync_inodes_sb(sb);
set_sbi_flag(sbi, SBI_IS_DIRTY); set_sbi_flag(sbi, SBI_IS_DIRTY);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment