Merge tag 'f2fs-for-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs
Pull f2fs updates from Jaegeuk Kim: "We've continued mainly to fix bugs in this round, as f2fs has been shipped in more devices. Especially, we've focused on stabilizing checkpoint=disable feature, and provided some interfaces for QA. Enhancements: - expose FS_NOCOW_FL for pin_file - run discard jobs at unmount time with timeout - tune discarding thread to avoid idling which consumes power - some checking codes to address vulnerabilities - give random value to i_generation - shutdown with more flags for QA Bug fixes: - clean up stale objects when mount is failed along with checkpoint=disable - fix system being stuck due to wrong count by atomic writes - handle some corrupted disk cases - fix a deadlock in f2fs_read_inline_dir We've also added some minor build error fixes and clean-up patches" * tag 'f2fs-for-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (53 commits) f2fs: set pin_file under CAP_SYS_ADMIN f2fs: fix to avoid deadlock in f2fs_read_inline_dir() f2fs: fix to adapt small inline xattr space in __find_inline_xattr() f2fs: fix to do sanity check with inode.i_inline_xattr_size f2fs: give some messages for inline_xattr_size f2fs: don't trigger read IO for beyond EOF page f2fs: fix to add refcount once page is tagged PG_private f2fs: remove wrong comment in f2fs_invalidate_page() f2fs: fix to use kvfree instead of kzfree f2fs: print more parameters in trace_f2fs_map_blocks f2fs: trace f2fs_ioc_shutdown f2fs: fix to avoid deadlock of atomic file operations f2fs: fix to dirty inode for i_mode recovery f2fs: give random value to i_generation f2fs: no need to take page lock in readdir f2fs: fix to update iostat correctly in IPU path f2fs: fix encrypted page memory leak f2fs: make fault injection covering __submit_flush_wait() f2fs: fix to retry fill_super only if recovery failed f2fs: silence VM_WARN_ON_ONCE in mempool_alloc ...
This commit is contained in:
109
fs/f2fs/super.c
109
fs/f2fs/super.c
@@ -269,7 +269,7 @@ static int f2fs_set_qf_name(struct super_block *sb, int qtype,
|
||||
if (!qname) {
|
||||
f2fs_msg(sb, KERN_ERR,
|
||||
"Not enough memory for storing quotafile name");
|
||||
return -EINVAL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (F2FS_OPTION(sbi).s_qf_names[qtype]) {
|
||||
if (strcmp(F2FS_OPTION(sbi).s_qf_names[qtype], qname) == 0)
|
||||
@@ -586,7 +586,7 @@ static int parse_options(struct super_block *sb, char *options)
|
||||
case Opt_io_size_bits:
|
||||
if (args->from && match_int(args, &arg))
|
||||
return -EINVAL;
|
||||
if (arg > __ilog2_u32(BIO_MAX_PAGES)) {
|
||||
if (arg <= 0 || arg > __ilog2_u32(BIO_MAX_PAGES)) {
|
||||
f2fs_msg(sb, KERN_WARNING,
|
||||
"Not support %d, larger than %d",
|
||||
1 << arg, BIO_MAX_PAGES);
|
||||
@@ -821,6 +821,8 @@ static int parse_options(struct super_block *sb, char *options)
|
||||
}
|
||||
|
||||
if (test_opt(sbi, INLINE_XATTR_SIZE)) {
|
||||
int min_size, max_size;
|
||||
|
||||
if (!f2fs_sb_has_extra_attr(sbi) ||
|
||||
!f2fs_sb_has_flexible_inline_xattr(sbi)) {
|
||||
f2fs_msg(sb, KERN_ERR,
|
||||
@@ -834,14 +836,15 @@ static int parse_options(struct super_block *sb, char *options)
|
||||
"set with inline_xattr option");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!F2FS_OPTION(sbi).inline_xattr_size ||
|
||||
F2FS_OPTION(sbi).inline_xattr_size >=
|
||||
DEF_ADDRS_PER_INODE -
|
||||
F2FS_TOTAL_EXTRA_ATTR_SIZE -
|
||||
DEF_INLINE_RESERVED_SIZE -
|
||||
DEF_MIN_INLINE_SIZE) {
|
||||
|
||||
min_size = sizeof(struct f2fs_xattr_header) / sizeof(__le32);
|
||||
max_size = MAX_INLINE_XATTR_SIZE;
|
||||
|
||||
if (F2FS_OPTION(sbi).inline_xattr_size < min_size ||
|
||||
F2FS_OPTION(sbi).inline_xattr_size > max_size) {
|
||||
f2fs_msg(sb, KERN_ERR,
|
||||
"inline xattr size is out of range");
|
||||
"inline xattr size is out of range: %d ~ %d",
|
||||
min_size, max_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
@@ -915,6 +918,10 @@ static int f2fs_drop_inode(struct inode *inode)
|
||||
sb_start_intwrite(inode->i_sb);
|
||||
f2fs_i_size_write(inode, 0);
|
||||
|
||||
f2fs_submit_merged_write_cond(F2FS_I_SB(inode),
|
||||
inode, NULL, 0, DATA);
|
||||
truncate_inode_pages_final(inode->i_mapping);
|
||||
|
||||
if (F2FS_HAS_BLOCKS(inode))
|
||||
f2fs_truncate(inode);
|
||||
|
||||
@@ -1048,7 +1055,7 @@ static void f2fs_put_super(struct super_block *sb)
|
||||
}
|
||||
|
||||
/* be sure to wait for any on-going discard commands */
|
||||
dropped = f2fs_wait_discard_bios(sbi);
|
||||
dropped = f2fs_issue_discard_timeout(sbi);
|
||||
|
||||
if ((f2fs_hw_support_discard(sbi) || f2fs_hw_should_discard(sbi)) &&
|
||||
!sbi->discard_blks && !dropped) {
|
||||
@@ -1075,7 +1082,10 @@ static void f2fs_put_super(struct super_block *sb)
|
||||
f2fs_bug_on(sbi, sbi->fsync_node_num);
|
||||
|
||||
iput(sbi->node_inode);
|
||||
sbi->node_inode = NULL;
|
||||
|
||||
iput(sbi->meta_inode);
|
||||
sbi->meta_inode = NULL;
|
||||
|
||||
/*
|
||||
* iput() can update stat information, if f2fs_write_checkpoint()
|
||||
@@ -1455,9 +1465,16 @@ static int f2fs_enable_quotas(struct super_block *sb);
|
||||
|
||||
static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
unsigned int s_flags = sbi->sb->s_flags;
|
||||
struct cp_control cpc;
|
||||
int err;
|
||||
int err = 0;
|
||||
int ret;
|
||||
|
||||
if (s_flags & SB_RDONLY) {
|
||||
f2fs_msg(sbi->sb, KERN_ERR,
|
||||
"checkpoint=disable on readonly fs");
|
||||
return -EINVAL;
|
||||
}
|
||||
sbi->sb->s_flags |= SB_ACTIVE;
|
||||
|
||||
f2fs_update_time(sbi, DISABLE_TIME);
|
||||
@@ -1465,18 +1482,24 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
|
||||
while (!f2fs_time_over(sbi, DISABLE_TIME)) {
|
||||
mutex_lock(&sbi->gc_mutex);
|
||||
err = f2fs_gc(sbi, true, false, NULL_SEGNO);
|
||||
if (err == -ENODATA)
|
||||
if (err == -ENODATA) {
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
if (err && err != -EAGAIN)
|
||||
return err;
|
||||
break;
|
||||
}
|
||||
|
||||
err = sync_filesystem(sbi->sb);
|
||||
if (err)
|
||||
return err;
|
||||
ret = sync_filesystem(sbi->sb);
|
||||
if (ret || err) {
|
||||
err = ret ? ret: err;
|
||||
goto restore_flag;
|
||||
}
|
||||
|
||||
if (f2fs_disable_cp_again(sbi))
|
||||
return -EAGAIN;
|
||||
if (f2fs_disable_cp_again(sbi)) {
|
||||
err = -EAGAIN;
|
||||
goto restore_flag;
|
||||
}
|
||||
|
||||
mutex_lock(&sbi->gc_mutex);
|
||||
cpc.reason = CP_PAUSE;
|
||||
@@ -1485,7 +1508,9 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
|
||||
|
||||
sbi->unusable_block_count = 0;
|
||||
mutex_unlock(&sbi->gc_mutex);
|
||||
return 0;
|
||||
restore_flag:
|
||||
sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */
|
||||
return err;
|
||||
}
|
||||
|
||||
static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
|
||||
@@ -2023,6 +2048,12 @@ void f2fs_quota_off_umount(struct super_block *sb)
|
||||
set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* In case of checkpoint=disable, we must flush quota blocks.
|
||||
* This can cause NULL exception for node_inode in end_io, since
|
||||
* put_super already dropped it.
|
||||
*/
|
||||
sync_filesystem(sb);
|
||||
}
|
||||
|
||||
static void f2fs_truncate_quota_inode_pages(struct super_block *sb)
|
||||
@@ -2703,6 +2734,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
|
||||
sbi->interval_time[DISCARD_TIME] = DEF_IDLE_INTERVAL;
|
||||
sbi->interval_time[GC_TIME] = DEF_IDLE_INTERVAL;
|
||||
sbi->interval_time[DISABLE_TIME] = DEF_DISABLE_INTERVAL;
|
||||
sbi->interval_time[UMOUNT_DISCARD_TIMEOUT] =
|
||||
DEF_UMOUNT_DISCARD_TIMEOUT;
|
||||
clear_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
|
||||
for (i = 0; i < NR_COUNT_TYPE; i++)
|
||||
@@ -3022,10 +3055,11 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
struct f2fs_super_block *raw_super;
|
||||
struct inode *root;
|
||||
int err;
|
||||
bool retry = true, need_fsck = false;
|
||||
bool skip_recovery = false, need_fsck = false;
|
||||
char *options = NULL;
|
||||
int recovery, i, valid_super_block;
|
||||
struct curseg_info *seg_i;
|
||||
int retry_cnt = 1;
|
||||
|
||||
try_onemore:
|
||||
err = -EINVAL;
|
||||
@@ -3097,7 +3131,6 @@ try_onemore:
|
||||
sb->s_maxbytes = sbi->max_file_blocks <<
|
||||
le32_to_cpu(raw_super->log_blocksize);
|
||||
sb->s_max_links = F2FS_LINK_MAX;
|
||||
get_random_bytes(&sbi->s_next_generation, sizeof(u32));
|
||||
|
||||
#ifdef CONFIG_QUOTA
|
||||
sb->dq_op = &f2fs_quota_operations;
|
||||
@@ -3200,6 +3233,10 @@ try_onemore:
|
||||
|
||||
if (__is_set_ckpt_flags(F2FS_CKPT(sbi), CP_QUOTA_NEED_FSCK_FLAG))
|
||||
set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
|
||||
if (__is_set_ckpt_flags(F2FS_CKPT(sbi), CP_DISABLED_QUICK_FLAG)) {
|
||||
set_sbi_flag(sbi, SBI_CP_DISABLED_QUICK);
|
||||
sbi->interval_time[DISABLE_TIME] = DEF_DISABLE_QUICK_INTERVAL;
|
||||
}
|
||||
|
||||
/* Initialize device list */
|
||||
err = f2fs_scan_devices(sbi);
|
||||
@@ -3288,7 +3325,7 @@ try_onemore:
|
||||
sb->s_root = d_make_root(root); /* allocate root dentry */
|
||||
if (!sb->s_root) {
|
||||
err = -ENOMEM;
|
||||
goto free_root_inode;
|
||||
goto free_node_inode;
|
||||
}
|
||||
|
||||
err = f2fs_register_sysfs(sbi);
|
||||
@@ -3310,7 +3347,7 @@ try_onemore:
|
||||
goto free_meta;
|
||||
|
||||
if (unlikely(is_set_ckpt_flags(sbi, CP_DISABLED_FLAG)))
|
||||
goto skip_recovery;
|
||||
goto reset_checkpoint;
|
||||
|
||||
/* recover fsynced data */
|
||||
if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
|
||||
@@ -3327,11 +3364,13 @@ try_onemore:
|
||||
if (need_fsck)
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
|
||||
if (!retry)
|
||||
goto skip_recovery;
|
||||
if (skip_recovery)
|
||||
goto reset_checkpoint;
|
||||
|
||||
err = f2fs_recover_fsync_data(sbi, false);
|
||||
if (err < 0) {
|
||||
if (err != -ENOMEM)
|
||||
skip_recovery = true;
|
||||
need_fsck = true;
|
||||
f2fs_msg(sb, KERN_ERR,
|
||||
"Cannot recover all fsync data errno=%d", err);
|
||||
@@ -3347,14 +3386,14 @@ try_onemore:
|
||||
goto free_meta;
|
||||
}
|
||||
}
|
||||
skip_recovery:
|
||||
reset_checkpoint:
|
||||
/* f2fs_recover_fsync_data() cleared this already */
|
||||
clear_sbi_flag(sbi, SBI_POR_DOING);
|
||||
|
||||
if (test_opt(sbi, DISABLE_CHECKPOINT)) {
|
||||
err = f2fs_disable_checkpoint(sbi);
|
||||
if (err)
|
||||
goto free_meta;
|
||||
goto sync_free_meta;
|
||||
} else if (is_set_ckpt_flags(sbi, CP_DISABLED_FLAG)) {
|
||||
f2fs_enable_checkpoint(sbi);
|
||||
}
|
||||
@@ -3367,7 +3406,7 @@ skip_recovery:
|
||||
/* After POR, we can run background GC thread.*/
|
||||
err = f2fs_start_gc_thread(sbi);
|
||||
if (err)
|
||||
goto free_meta;
|
||||
goto sync_free_meta;
|
||||
}
|
||||
kvfree(options);
|
||||
|
||||
@@ -3387,8 +3426,14 @@ skip_recovery:
|
||||
cur_cp_version(F2FS_CKPT(sbi)));
|
||||
f2fs_update_time(sbi, CP_TIME);
|
||||
f2fs_update_time(sbi, REQ_TIME);
|
||||
clear_sbi_flag(sbi, SBI_CP_DISABLED_QUICK);
|
||||
return 0;
|
||||
|
||||
sync_free_meta:
|
||||
/* safe to flush all the data */
|
||||
sync_filesystem(sbi->sb);
|
||||
retry_cnt = 0;
|
||||
|
||||
free_meta:
|
||||
#ifdef CONFIG_QUOTA
|
||||
f2fs_truncate_quota_inode_pages(sb);
|
||||
@@ -3402,6 +3447,8 @@ free_meta:
|
||||
* falls into an infinite loop in f2fs_sync_meta_pages().
|
||||
*/
|
||||
truncate_inode_pages_final(META_MAPPING(sbi));
|
||||
/* evict some inodes being cached by GC */
|
||||
evict_inodes(sb);
|
||||
f2fs_unregister_sysfs(sbi);
|
||||
free_root_inode:
|
||||
dput(sb->s_root);
|
||||
@@ -3410,6 +3457,7 @@ free_node_inode:
|
||||
f2fs_release_ino_entry(sbi, true);
|
||||
truncate_inode_pages_final(NODE_MAPPING(sbi));
|
||||
iput(sbi->node_inode);
|
||||
sbi->node_inode = NULL;
|
||||
free_stats:
|
||||
f2fs_destroy_stats(sbi);
|
||||
free_nm:
|
||||
@@ -3422,6 +3470,7 @@ free_devices:
|
||||
free_meta_inode:
|
||||
make_bad_inode(sbi->meta_inode);
|
||||
iput(sbi->meta_inode);
|
||||
sbi->meta_inode = NULL;
|
||||
free_io_dummy:
|
||||
mempool_destroy(sbi->write_io_dummy);
|
||||
free_percpu:
|
||||
@@ -3443,8 +3492,8 @@ free_sbi:
|
||||
kvfree(sbi);
|
||||
|
||||
/* give only one another chance */
|
||||
if (retry) {
|
||||
retry = false;
|
||||
if (retry_cnt > 0 && skip_recovery) {
|
||||
retry_cnt--;
|
||||
shrink_dcache_sb(sb);
|
||||
goto try_onemore;
|
||||
}
|
||||
|
Reference in New Issue
Block a user