/* * Clear the name of the specified quota file.
*/ staticint f2fs_unnote_qf_name(struct fs_context *fc, int qtype)
{ struct f2fs_fs_context *ctx = fc->fs_private;
for (i = 0; i < ext_cnt; i++) { if (!strcasecmp(new_ext, ext[i])) returntrue;
}
returnfalse;
}
/* * 1. The same extension name cannot not appear in both compress and non-compress extension * at the same time. * 2. If the compress extension specifies all files, the types specified by the non-compress * extension will be treated as special cases and will not be compressed. * 3. Don't allow the non-compress extension specifies all files.
*/ staticint f2fs_test_compress_extension(unsignedchar (*noext)[F2FS_EXTENSION_LEN], int noext_cnt, unsignedchar (*ext)[F2FS_EXTENSION_LEN], int ext_cnt)
{ int index = 0, no_index = 0;
if (!noext_cnt) return 0;
for (no_index = 0; no_index < noext_cnt; no_index++) { if (strlen(noext[no_index]) == 0) continue; if (!strcasecmp("*", noext[no_index])) {
f2fs_info(NULL, "Don't allow the nocompress extension specifies all files"); return -EINVAL;
} for (index = 0; index < ext_cnt; index++) { if (strlen(ext[index]) == 0) continue; if (!strcasecmp(ext[index], noext[no_index])) {
f2fs_info(NULL, "Don't allow the same extension %s appear in both compress and nocompress extension",
ext[index]); return -EINVAL;
}
}
} return 0;
}
if (str[0] != ':') {
f2fs_info(NULL, "wrong format, e.g. <alg_name>:<compr_level>"); return -EINVAL;
} if (kstrtoint(str + 1, 10, &level)) return -EINVAL;
/* f2fs does not support negative compress level now */ if (level < 0) {
f2fs_info(NULL, "do not support negative compress level: %d", level); return -ERANGE;
}
switch (token) { case Opt_gc_background:
F2FS_CTX_INFO(ctx).bggc_mode = result.uint_32;
ctx->spec_mask |= F2FS_SPEC_background_gc; break; case Opt_disable_roll_forward:
ctx_set_opt(ctx, F2FS_MOUNT_DISABLE_ROLL_FORWARD); break; case Opt_norecovery: /* requires ro mount, checked in f2fs_validate_options */
ctx_set_opt(ctx, F2FS_MOUNT_NORECOVERY); break; case Opt_discard: if (result.negated)
ctx_clear_opt(ctx, F2FS_MOUNT_DISCARD); else
ctx_set_opt(ctx, F2FS_MOUNT_DISCARD); break; case Opt_noheap: case Opt_heap:
f2fs_warn(NULL, "heap/no_heap options were deprecated"); break; #ifdef CONFIG_F2FS_FS_XATTR case Opt_user_xattr: if (result.negated)
ctx_clear_opt(ctx, F2FS_MOUNT_XATTR_USER); else
ctx_set_opt(ctx, F2FS_MOUNT_XATTR_USER); break; case Opt_inline_xattr: if (result.negated)
ctx_clear_opt(ctx, F2FS_MOUNT_INLINE_XATTR); else
ctx_set_opt(ctx, F2FS_MOUNT_INLINE_XATTR); break; case Opt_inline_xattr_size: if (result.int_32 < MIN_INLINE_XATTR_SIZE ||
result.int_32 > MAX_INLINE_XATTR_SIZE) {
f2fs_err(NULL, "inline xattr size is out of range: %u ~ %u",
(u32)MIN_INLINE_XATTR_SIZE, (u32)MAX_INLINE_XATTR_SIZE); return -EINVAL;
}
ctx_set_opt(ctx, F2FS_MOUNT_INLINE_XATTR_SIZE);
F2FS_CTX_INFO(ctx).inline_xattr_size = result.int_32;
ctx->spec_mask |= F2FS_SPEC_inline_xattr_size; break; #else case Opt_user_xattr: case Opt_inline_xattr: case Opt_inline_xattr_size:
f2fs_info(NULL, "%s options not supported", param->key); break; #endif #ifdef CONFIG_F2FS_FS_POSIX_ACL case Opt_acl: if (result.negated)
ctx_clear_opt(ctx, F2FS_MOUNT_POSIX_ACL); else
ctx_set_opt(ctx, F2FS_MOUNT_POSIX_ACL); break; #else case Opt_acl:
f2fs_info(NULL, "%s options not supported", param->key); break; #endif case Opt_active_logs: if (result.int_32 != 2 && result.int_32 != 4 &&
result.int_32 != NR_CURSEG_PERSIST_TYPE) return -EINVAL;
ctx->spec_mask |= F2FS_SPEC_active_logs;
F2FS_CTX_INFO(ctx).active_logs = result.int_32; break; case Opt_disable_ext_identify:
ctx_set_opt(ctx, F2FS_MOUNT_DISABLE_EXT_IDENTIFY); break; case Opt_inline_data: if (result.negated)
ctx_clear_opt(ctx, F2FS_MOUNT_INLINE_DATA); else
ctx_set_opt(ctx, F2FS_MOUNT_INLINE_DATA); break; case Opt_inline_dentry: if (result.negated)
ctx_clear_opt(ctx, F2FS_MOUNT_INLINE_DENTRY); else
ctx_set_opt(ctx, F2FS_MOUNT_INLINE_DENTRY); break; case Opt_flush_merge: if (result.negated)
ctx_clear_opt(ctx, F2FS_MOUNT_FLUSH_MERGE); else
ctx_set_opt(ctx, F2FS_MOUNT_FLUSH_MERGE); break; case Opt_barrier: if (result.negated)
ctx_set_opt(ctx, F2FS_MOUNT_NOBARRIER); else
ctx_clear_opt(ctx, F2FS_MOUNT_NOBARRIER); break; case Opt_fastboot:
ctx_set_opt(ctx, F2FS_MOUNT_FASTBOOT); break; case Opt_extent_cache: if (result.negated)
ctx_clear_opt(ctx, F2FS_MOUNT_READ_EXTENT_CACHE); else
ctx_set_opt(ctx, F2FS_MOUNT_READ_EXTENT_CACHE); break; case Opt_data_flush:
ctx_set_opt(ctx, F2FS_MOUNT_DATA_FLUSH); break; case Opt_reserve_root:
ctx_set_opt(ctx, F2FS_MOUNT_RESERVE_ROOT);
F2FS_CTX_INFO(ctx).root_reserved_blocks = result.uint_32;
ctx->spec_mask |= F2FS_SPEC_reserve_root; break; case Opt_resuid:
F2FS_CTX_INFO(ctx).s_resuid = result.uid;
ctx->spec_mask |= F2FS_SPEC_resuid; break; case Opt_resgid:
F2FS_CTX_INFO(ctx).s_resgid = result.gid;
ctx->spec_mask |= F2FS_SPEC_resgid; break; case Opt_mode:
F2FS_CTX_INFO(ctx).fs_mode = result.uint_32;
ctx->spec_mask |= F2FS_SPEC_mode; break; #ifdef CONFIG_F2FS_FAULT_INJECTION case Opt_fault_injection:
F2FS_CTX_INFO(ctx).fault_info.inject_rate = result.int_32;
ctx->spec_mask |= F2FS_SPEC_fault_injection;
ctx_set_opt(ctx, F2FS_MOUNT_FAULT_INJECTION); break;
case Opt_fault_type: if (result.uint_32 > BIT(FAULT_MAX)) return -EINVAL;
F2FS_CTX_INFO(ctx).fault_info.inject_type = result.uint_32;
ctx->spec_mask |= F2FS_SPEC_fault_type;
ctx_set_opt(ctx, F2FS_MOUNT_FAULT_INJECTION); break; #else case Opt_fault_injection: case Opt_fault_type:
f2fs_info(NULL, "%s options not supported", param->key); break; #endif case Opt_lazytime: if (result.negated)
ctx_clear_opt(ctx, F2FS_MOUNT_LAZYTIME); else
ctx_set_opt(ctx, F2FS_MOUNT_LAZYTIME); break; #ifdef CONFIG_QUOTA case Opt_quota: if (result.negated) {
ctx_clear_opt(ctx, F2FS_MOUNT_QUOTA);
ctx_clear_opt(ctx, F2FS_MOUNT_USRQUOTA);
ctx_clear_opt(ctx, F2FS_MOUNT_GRPQUOTA);
ctx_clear_opt(ctx, F2FS_MOUNT_PRJQUOTA);
} else
ctx_set_opt(ctx, F2FS_MOUNT_USRQUOTA); break; case Opt_usrquota:
ctx_set_opt(ctx, F2FS_MOUNT_USRQUOTA); break; case Opt_grpquota:
ctx_set_opt(ctx, F2FS_MOUNT_GRPQUOTA); break; case Opt_prjquota:
ctx_set_opt(ctx, F2FS_MOUNT_PRJQUOTA); break; case Opt_usrjquota: if (!*param->string)
ret = f2fs_unnote_qf_name(fc, USRQUOTA); else
ret = f2fs_note_qf_name(fc, USRQUOTA, param); if (ret) return ret; break; case Opt_grpjquota: if (!*param->string)
ret = f2fs_unnote_qf_name(fc, GRPQUOTA); else
ret = f2fs_note_qf_name(fc, GRPQUOTA, param); if (ret) return ret; break; case Opt_prjjquota: if (!*param->string)
ret = f2fs_unnote_qf_name(fc, PRJQUOTA); else
ret = f2fs_note_qf_name(fc, PRJQUOTA, param); if (ret) return ret; break; case Opt_jqfmt:
F2FS_CTX_INFO(ctx).s_jquota_fmt = result.int_32;
ctx->spec_mask |= F2FS_SPEC_jqfmt; break; #else case Opt_quota: case Opt_usrquota: case Opt_grpquota: case Opt_prjquota: case Opt_usrjquota: case Opt_grpjquota: case Opt_prjjquota:
f2fs_info(NULL, "quota operations not supported"); break; #endif case Opt_alloc:
F2FS_CTX_INFO(ctx).alloc_mode = result.uint_32;
ctx->spec_mask |= F2FS_SPEC_alloc_mode; break; case Opt_fsync:
F2FS_CTX_INFO(ctx).fsync_mode = result.uint_32;
ctx->spec_mask |= F2FS_SPEC_fsync_mode; break; case Opt_test_dummy_encryption:
ret = f2fs_parse_test_dummy_encryption(param, ctx); if (ret) return ret; break; case Opt_inlinecrypt: #ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
ctx_set_opt(ctx, F2FS_MOUNT_INLINECRYPT); #else
f2fs_info(NULL, "inline encryption not supported"); #endif break; case Opt_checkpoint: /* * Initialize args struct so we know whether arg was * found; some options take optional arguments.
*/
args[0].from = args[0].to = NULL;
arg = 0;
/* revert to match_table for checkpoint= options */
token = match_token(param->string, f2fs_checkpoint_tokens, args); switch (token) { case Opt_checkpoint_disable_cap_perc: if (args->from && match_int(args, &arg)) return -EINVAL; if (arg < 0 || arg > 100) return -EINVAL;
F2FS_CTX_INFO(ctx).unusable_cap_perc = arg;
ctx->spec_mask |= F2FS_SPEC_checkpoint_disable_cap_perc;
ctx_set_opt(ctx, F2FS_MOUNT_DISABLE_CHECKPOINT); break; case Opt_checkpoint_disable_cap: if (args->from && match_int(args, &arg)) return -EINVAL;
F2FS_CTX_INFO(ctx).unusable_cap = arg;
ctx->spec_mask |= F2FS_SPEC_checkpoint_disable_cap;
ctx_set_opt(ctx, F2FS_MOUNT_DISABLE_CHECKPOINT); break; case Opt_checkpoint_disable:
ctx_set_opt(ctx, F2FS_MOUNT_DISABLE_CHECKPOINT); break; case Opt_checkpoint_enable:
F2FS_CTX_INFO(ctx).unusable_cap_perc = 0;
ctx->spec_mask |= F2FS_SPEC_checkpoint_disable_cap_perc;
F2FS_CTX_INFO(ctx).unusable_cap = 0;
ctx->spec_mask |= F2FS_SPEC_checkpoint_disable_cap;
ctx_clear_opt(ctx, F2FS_MOUNT_DISABLE_CHECKPOINT); break; default: return -EINVAL;
} break; case Opt_checkpoint_merge: if (result.negated)
ctx_clear_opt(ctx, F2FS_MOUNT_MERGE_CHECKPOINT); else
ctx_set_opt(ctx, F2FS_MOUNT_MERGE_CHECKPOINT); break; #ifdef CONFIG_F2FS_FS_COMPRESSION case Opt_compress_algorithm:
name = param->string; if (!strcmp(name, "lzo")) { #ifdef CONFIG_F2FS_FS_LZO
F2FS_CTX_INFO(ctx).compress_level = 0;
F2FS_CTX_INFO(ctx).compress_algorithm = COMPRESS_LZO;
ctx->spec_mask |= F2FS_SPEC_compress_level;
ctx->spec_mask |= F2FS_SPEC_compress_algorithm; #else
f2fs_info(NULL, "kernel doesn't support lzo compression"); #endif
} elseif (!strncmp(name, "lz4", 3)) { #ifdef CONFIG_F2FS_FS_LZ4
ret = f2fs_set_lz4hc_level(ctx, name); if (ret) return -EINVAL;
F2FS_CTX_INFO(ctx).compress_algorithm = COMPRESS_LZ4;
ctx->spec_mask |= F2FS_SPEC_compress_algorithm; #else
f2fs_info(NULL, "kernel doesn't support lz4 compression"); #endif
} elseif (!strncmp(name, "zstd", 4)) { #ifdef CONFIG_F2FS_FS_ZSTD
ret = f2fs_set_zstd_level(ctx, name); if (ret) return -EINVAL;
F2FS_CTX_INFO(ctx).compress_algorithm = COMPRESS_ZSTD;
ctx->spec_mask |= F2FS_SPEC_compress_algorithm; #else
f2fs_info(NULL, "kernel doesn't support zstd compression"); #endif
} elseif (!strcmp(name, "lzo-rle")) { #ifdef CONFIG_F2FS_FS_LZORLE
F2FS_CTX_INFO(ctx).compress_level = 0;
F2FS_CTX_INFO(ctx).compress_algorithm = COMPRESS_LZORLE;
ctx->spec_mask |= F2FS_SPEC_compress_level;
ctx->spec_mask |= F2FS_SPEC_compress_algorithm; #else
f2fs_info(NULL, "kernel doesn't support lzorle compression"); #endif
} else return -EINVAL; break; case Opt_compress_log_size: if (result.uint_32 < MIN_COMPRESS_LOG_SIZE ||
result.uint_32 > MAX_COMPRESS_LOG_SIZE) {
f2fs_err(NULL, "Compress cluster log size is out of range"); return -EINVAL;
}
F2FS_CTX_INFO(ctx).compress_log_size = result.uint_32;
ctx->spec_mask |= F2FS_SPEC_compress_log_size; break; case Opt_compress_extension:
name = param->string;
ext = F2FS_CTX_INFO(ctx).extensions;
ext_cnt = F2FS_CTX_INFO(ctx).compress_ext_cnt;
/* * We do the test below only for project quotas. 'usrquota' and * 'grpquota' mount options are allowed even without quota feature * to support legacy quotas in quota files.
*/ if (ctx_test_opt(ctx, F2FS_MOUNT_PRJQUOTA) &&
!f2fs_sb_has_project_quota(sbi)) {
f2fs_err(sbi, "Project quota feature not enabled. Cannot enable project quota enforcement."); return -EINVAL;
}
if (ctx->qname_mask) { for (i = 0; i < MAXQUOTAS; i++) { if (!(ctx->qname_mask & (1 << i))) continue;
#else if (f2fs_readonly(sbi->sb)) return 0; if (f2fs_sb_has_quota_ino(sbi)) {
f2fs_info(sbi, "Filesystem with quota feature cannot be mounted RDWR without CONFIG_QUOTA"); return -EINVAL;
} if (f2fs_sb_has_project_quota(sbi)) {
f2fs_err(sbi, "Filesystem with project quota feature cannot be mounted RDWR without CONFIG_QUOTA"); return -EINVAL;
}
if (!fscrypt_is_dummy_policy_set(&F2FS_CTX_INFO(ctx).dummy_enc_policy)) return 0;
if (!f2fs_sb_has_encrypt(sbi)) {
f2fs_err(sbi, "Encrypt feature is off"); return -EINVAL;
}
/* * This mount option is just for testing, and it's not worthwhile to * implement the extra complexity (e.g. RCU protection) that would be * needed to allow it to be set or changed during remount. We do allow * it to be specified during remount, but only if there is no change.
*/ if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) { if (fscrypt_dummy_policies_equal(&F2FS_OPTION(sbi).dummy_enc_policy,
&F2FS_CTX_INFO(ctx).dummy_enc_policy)) return 0;
f2fs_warn(sbi, "Can't set or change test_dummy_encryption on remount"); return -EINVAL;
} return 0;
}
if (!f2fs_sb_has_compression(sbi)) { if (test_compression_spec(ctx->spec_mask) ||
ctx_test_opt(ctx, F2FS_MOUNT_COMPRESS_CACHE))
f2fs_info(sbi, "Image doesn't support compression");
clear_compression_spec(ctx);
ctx->opt_mask &= ~F2FS_MOUNT_COMPRESS_CACHE; return 0;
} if (ctx->spec_mask & F2FS_SPEC_compress_extension) {
cnt = F2FS_CTX_INFO(ctx).compress_ext_cnt; for (i = 0; i < F2FS_CTX_INFO(ctx).compress_ext_cnt; i++) { if (is_compress_extension_exist(&F2FS_OPTION(sbi),
F2FS_CTX_INFO(ctx).extensions[i], true)) {
F2FS_CTX_INFO(ctx).extensions[i][0] = '\0';
cnt--;
}
} if (F2FS_OPTION(sbi).compress_ext_cnt + cnt > COMPRESS_EXT_NUM) {
f2fs_err(sbi, "invalid extension length/number"); return -EINVAL;
}
} if (ctx->spec_mask & F2FS_SPEC_nocompress_extension) {
cnt = F2FS_CTX_INFO(ctx).nocompress_ext_cnt; for (i = 0; i < F2FS_CTX_INFO(ctx).nocompress_ext_cnt; i++) { if (is_compress_extension_exist(&F2FS_OPTION(sbi),
F2FS_CTX_INFO(ctx).noextensions[i], false)) {
F2FS_CTX_INFO(ctx).noextensions[i][0] = '\0';
cnt--;
}
} if (F2FS_OPTION(sbi).nocompress_ext_cnt + cnt > COMPRESS_EXT_NUM) {
f2fs_err(sbi, "invalid noextension length/number"); return -EINVAL;
}
}
if (f2fs_test_compress_extension(F2FS_CTX_INFO(ctx).noextensions,
F2FS_CTX_INFO(ctx).nocompress_ext_cnt,
F2FS_CTX_INFO(ctx).extensions,
F2FS_CTX_INFO(ctx).compress_ext_cnt)) {
f2fs_err(sbi, "new noextensions conflicts with new extensions"); return -EINVAL;
} if (f2fs_test_compress_extension(F2FS_CTX_INFO(ctx).noextensions,
F2FS_CTX_INFO(ctx).nocompress_ext_cnt,
F2FS_OPTION(sbi).extensions,
F2FS_OPTION(sbi).compress_ext_cnt)) {
f2fs_err(sbi, "new noextensions conflicts with old extensions"); return -EINVAL;
} if (f2fs_test_compress_extension(F2FS_OPTION(sbi).noextensions,
F2FS_OPTION(sbi).nocompress_ext_cnt,
F2FS_CTX_INFO(ctx).extensions,
F2FS_CTX_INFO(ctx).compress_ext_cnt)) {
f2fs_err(sbi, "new extensions conflicts with old noextensions"); return -EINVAL;
} #endif return 0;
}
err = f2fs_check_test_dummy_encryption(fc, sb); if (err) return err;
err = f2fs_check_compression(fc, sb); if (err) return err;
err = f2fs_check_quota_consistency(fc, sb); if (err) return err;
if (!IS_ENABLED(CONFIG_UNICODE) && f2fs_sb_has_casefold(sbi)) {
f2fs_err(sbi, "Filesystem with casefold feature cannot be mounted without CONFIG_UNICODE"); return -EINVAL;
}
/* * The BLKZONED feature indicates that the drive was formatted with * zone alignment optimization. This is optional for host-aware * devices, but mandatory for host-managed zoned block devices.
*/ if (f2fs_sb_has_blkzoned(sbi)) { if (F2FS_CTX_INFO(ctx).bggc_mode == BGGC_MODE_OFF) {
f2fs_warn(sbi, "zoned devices need bggc"); return -EINVAL;
} #ifdef CONFIG_BLK_DEV_ZONED if ((ctx->spec_mask & F2FS_SPEC_discard_unit) &&
F2FS_CTX_INFO(ctx).discard_unit != DISCARD_UNIT_SECTION) {
f2fs_info(sbi, "Zoned block device doesn't need small discard, set discard_unit=section by default");
F2FS_CTX_INFO(ctx).discard_unit = DISCARD_UNIT_SECTION;
}
if ((ctx->spec_mask & F2FS_SPEC_mode) &&
F2FS_CTX_INFO(ctx).fs_mode != FS_MODE_LFS) {
f2fs_info(sbi, "Only lfs mode is allowed with zoned block device feature"); return -EINVAL;
} #else
f2fs_err(sbi, "Zoned block device support is not enabled"); return -EINVAL; #endif
}
if (ctx_test_opt(ctx, F2FS_MOUNT_INLINE_XATTR_SIZE)) { if (!f2fs_sb_has_extra_attr(sbi) ||
!f2fs_sb_has_flexible_inline_xattr(sbi)) {
f2fs_err(sbi, "extra_attr or flexible_inline_xattr feature is off"); return -EINVAL;
} if (!ctx_test_opt(ctx, F2FS_MOUNT_INLINE_XATTR) && !test_opt(sbi, INLINE_XATTR)) {
f2fs_err(sbi, "inline_xattr_size option should be set with inline_xattr option"); return -EINVAL;
}
}
if (ctx_test_opt(ctx, F2FS_MOUNT_ATGC) &&
F2FS_CTX_INFO(ctx).fs_mode == FS_MODE_LFS) {
f2fs_err(sbi, "LFS is not compatible with ATGC"); return -EINVAL;
}
if (f2fs_is_readonly(sbi) && ctx_test_opt(ctx, F2FS_MOUNT_FLUSH_MERGE)) {
f2fs_err(sbi, "FLUSH_MERGE not compatible with readonly mode"); return -EINVAL;
}
if (f2fs_sb_has_readonly(sbi) && !f2fs_readonly(sbi->sb)) {
f2fs_err(sbi, "Allow to mount readonly mode only"); return -EROFS;
} return 0;
}
if (!fscrypt_is_dummy_policy_set(&F2FS_CTX_INFO(ctx).dummy_enc_policy) || /* if already set, it was already verified to be the same */
fscrypt_is_dummy_policy_set(&F2FS_OPTION(sbi).dummy_enc_policy)) return;
swap(F2FS_OPTION(sbi).dummy_enc_policy, F2FS_CTX_INFO(ctx).dummy_enc_policy);
f2fs_warn(sbi, "Test dummy encryption mode enabled");
}
#ifdef CONFIG_BLK_DEV_ZONED if (f2fs_sb_has_blkzoned(sbi) &&
sbi->max_open_zones < F2FS_OPTION(sbi).active_logs) {
f2fs_err(sbi, "zoned: max open zones %u is too small, need at least %u open zones",
sbi->max_open_zones, F2FS_OPTION(sbi).active_logs); return -EINVAL;
} #endif if (f2fs_lfs_mode(sbi) && !IS_F2FS_IPU_DISABLE(sbi)) {
f2fs_warn(sbi, "LFS is not compatible with IPU"); return -EINVAL;
} return 0;
}
spin_lock(&inode->i_lock);
atomic_dec(&inode->i_count);
}
trace_f2fs_drop_inode(inode, 0); return 0;
}
ret = generic_drop_inode(inode); if (!ret)
ret = fscrypt_drop_inode(inode);
trace_f2fs_drop_inode(inode, ret); return ret;
}
int f2fs_inode_dirtied(struct inode *inode, bool sync)
{ struct f2fs_sb_info *sbi = F2FS_I_SB(inode); int ret = 0;
spin_lock(&sbi->inode_lock[DIRTY_META]); if (is_inode_flag_set(inode, FI_DIRTY_INODE)) {
ret = 1;
} else {
set_inode_flag(inode, FI_DIRTY_INODE);
stat_inc_dirty_inode(sbi, DIRTY_META);
} if (sync && list_empty(&F2FS_I(inode)->gdirty_list)) {
list_add_tail(&F2FS_I(inode)->gdirty_list,
&sbi->inode_list[DIRTY_META]);
inc_page_count(sbi, F2FS_DIRTY_IMETA);
}
spin_unlock(&sbi->inode_lock[DIRTY_META]);
/* if atomic write is not committed, set inode w/ atomic dirty */ if (!ret && f2fs_is_atomic_file(inode) &&
!is_inode_flag_set(inode, FI_ATOMIC_COMMITTED))
set_inode_flag(inode, FI_ATOMIC_DIRTIED);
/* * f2fs_dirty_inode() is called from __mark_inode_dirty() * * We should call set_dirty_inode to write the dirty inode through write_inode.
*/ staticvoid f2fs_dirty_inode(struct inode *inode, int flags)
{ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
if (inode->i_ino == F2FS_NODE_INO(sbi) ||
inode->i_ino == F2FS_META_INO(sbi)) return;
if (is_inode_flag_set(inode, FI_AUTO_RECOVER))
clear_inode_flag(inode, FI_AUTO_RECOVER);
staticvoid destroy_device_list(struct f2fs_sb_info *sbi)
{ int i;
for (i = 0; i < sbi->s_ndevs; i++) { if (i > 0)
bdev_fput(FDEV(i).bdev_file); #ifdef CONFIG_BLK_DEV_ZONED
kvfree(FDEV(i).blkz_seq); #endif
}
kvfree(sbi->devs);
}
staticvoid f2fs_put_super(struct super_block *sb)
{ struct f2fs_sb_info *sbi = F2FS_SB(sb); int i; int err = 0; bool done;
/* unregister procfs/sysfs entries in advance to avoid race case */
f2fs_unregister_sysfs(sbi);
f2fs_quota_off_umount(sb);
/* prevent remaining shrinker jobs */
mutex_lock(&sbi->umount_mutex);
/* * flush all issued checkpoints and stop checkpoint issue thread. * after then, all checkpoints should be done by each process context.
*/
f2fs_stop_ckpt_thread(sbi);
/* * We don't need to do checkpoint when superblock is clean. * But, the previous checkpoint was not done by umount, it needs to do * clean checkpoint again.
*/ if ((is_sbi_flag_set(sbi, SBI_IS_DIRTY) ||
!is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG))) { struct cp_control cpc = {
.reason = CP_UMOUNT,
};
stat_inc_cp_call_count(sbi, TOTAL_CALL);
err = f2fs_write_checkpoint(sbi, &cpc);
}
/* be sure to wait for any on-going discard commands */
done = f2fs_issue_discard_timeout(sbi); if (f2fs_realtime_discard_enable(sbi) && !sbi->discard_blks && done) { struct cp_control cpc = {
.reason = CP_UMOUNT | CP_TRIMMED,
};
stat_inc_cp_call_count(sbi, TOTAL_CALL);
err = f2fs_write_checkpoint(sbi, &cpc);
}
/* * normally superblock is clean, so we need to release this. * In addition, EIO will skip do checkpoint, we need this as well.
*/
f2fs_release_ino_entry(sbi, true);
/* * It will update discard_max_bytes of mounted lvm device to zero * after creating snapshot on this lvm device, let's drop all * remained discards. * We don't need to disable real-time discard because discard_max_bytes * will recover after removal of snapshot.
*/ if (test_opt(sbi, DISCARD) && !f2fs_hw_support_discard(sbi))
f2fs_issue_discard_timeout(sbi);
staticvoid f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
{ int retry = DEFAULT_RETRY_IO_COUNT;
/* we should flush all the data to keep data consistency */ do {
sync_inodes_sb(sbi->sb);
f2fs_io_schedule_timeout(DEFAULT_IO_TIMEOUT);
} while (get_pages(sbi, F2FS_DIRTY_DATA) && retry--);
if (unlikely(retry < 0))
f2fs_warn(sbi, "checkpoint=enable has some unwritten data.");
/* * Save the old mount options in case we * need to restore them.
*/
org_mount_opt = sbi->mount_opt;
old_sb_flags = sb->s_flags;
sbi->umount_lock_holder = current;
#ifdef CONFIG_QUOTA
org_mount_opt.s_jquota_fmt = F2FS_OPTION(sbi).s_jquota_fmt; for (i = 0; i < MAXQUOTAS; i++) { if (F2FS_OPTION(sbi).s_qf_names[i]) {
org_mount_opt.s_qf_names[i] =
kstrdup(F2FS_OPTION(sbi).s_qf_names[i],
GFP_KERNEL); if (!org_mount_opt.s_qf_names[i]) { for (j = 0; j < i; j++)
kfree(org_mount_opt.s_qf_names[j]); return -ENOMEM;
}
} else {
org_mount_opt.s_qf_names[i] = NULL;
}
} #endif
/* recover superblocks we couldn't write due to previous RO mount */ if (!(flags & SB_RDONLY) && is_sbi_flag_set(sbi, SBI_NEED_SB_WRITE)) {
err = f2fs_commit_super(sbi, false);
f2fs_info(sbi, "Try to recover all the superblocks, ret: %d",
err); if (!err)
clear_sbi_flag(sbi, SBI_NEED_SB_WRITE);
}
default_options(sbi, true);
err = f2fs_check_opt_consistency(fc, sb); if (err) goto restore_opts;
f2fs_apply_options(fc, sb);
err = f2fs_sanity_check_options(sbi, true); if (err) goto restore_opts;
/* flush outstanding errors before changing fs state */
flush_work(&sbi->s_error_work);
/* * Previous and new state of filesystem is RO, * so skip checking GC and FLUSH_MERGE conditions.
*/ if (f2fs_readonly(sb) && (flags & SB_RDONLY)) goto skip;
/* disallow enable/disable extent_cache dynamically */ if (no_read_extent_cache == !!test_opt(sbi, READ_EXTENT_CACHE)) {
err = -EINVAL;
f2fs_warn(sbi, "switch extent_cache option is not allowed"); goto restore_opts;
} /* disallow enable/disable age extent_cache dynamically */ if (no_age_extent_cache == !!test_opt(sbi, AGE_EXTENT_CACHE)) {
err = -EINVAL;
f2fs_warn(sbi, "switch age_extent_cache option is not allowed"); goto restore_opts;
}
if (no_compress_cache == !!test_opt(sbi, COMPRESS_CACHE)) {
err = -EINVAL;
f2fs_warn(sbi, "switch compress_cache option is not allowed"); goto restore_opts;
}
if (block_unit_discard != f2fs_block_unit_discard(sbi)) {
err = -EINVAL;
f2fs_warn(sbi, "switch discard_unit option is not allowed"); goto restore_opts;
}
if (no_nat_bits == !!test_opt(sbi, NAT_BITS)) {
err = -EINVAL;
f2fs_warn(sbi, "switch nat_bits option is not allowed"); goto restore_opts;
}
if ((flags & SB_RDONLY) && test_opt(sbi, DISABLE_CHECKPOINT)) {
err = -EINVAL;
f2fs_warn(sbi, "disabling checkpoint not compatible with read-only"); goto restore_opts;
}
/* * We stop the GC thread if FS is mounted as RO * or if background_gc = off is passed in mount * option. Also sync the filesystem.
*/ if ((flags & SB_RDONLY) ||
(F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_OFF &&
!test_opt(sbi, GC_MERGE))) { if (sbi->gc_thread) {
f2fs_stop_gc_thread(sbi);
need_restart_gc = true;
}
} elseif (!sbi->gc_thread) {
err = f2fs_start_gc_thread(sbi); if (err) goto restore_opts;
need_stop_gc = true;
}
/* * We stop issue flush thread if FS is mounted as RO * or if flush_merge is not passed in mount option.
*/ if ((flags & SB_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) {
clear_opt(sbi, FLUSH_MERGE);
f2fs_destroy_flush_cmd_control(sbi, false);
need_restart_flush = true;
} else {
err = f2fs_create_flush_cmd_control(sbi); if (err) goto restore_gc;
need_stop_flush = true;
}
if (no_discard == !!test_opt(sbi, DISCARD)) { if (test_opt(sbi, DISCARD)) {
err = f2fs_start_discard_thread(sbi); if (err) goto restore_flush;
need_stop_discard = true;
} else {
f2fs_stop_discard_thread(sbi);
f2fs_issue_discard_timeout(sbi);
need_restart_discard = true;
}
}
adjust_unusable_cap_perc(sbi); if (enable_checkpoint == !!test_opt(sbi, DISABLE_CHECKPOINT)) { if (test_opt(sbi, DISABLE_CHECKPOINT)) {
err = f2fs_disable_checkpoint(sbi); if (err) goto restore_discard;
need_enable_checkpoint = true;
} else {
f2fs_enable_checkpoint(sbi);
need_disable_checkpoint = true;
}
}
/* * Place this routine at the end, since a new checkpoint would be * triggered while remount and we need to take care of it before * returning from remount.
*/ if ((flags & SB_RDONLY) || test_opt(sbi, DISABLE_CHECKPOINT) ||
!test_opt(sbi, MERGE_CHECKPOINT)) {
f2fs_stop_ckpt_thread(sbi);
} else { /* Flush if the previous checkpoint, if exists. */
f2fs_flush_ckpt_thread(sbi);
err = f2fs_start_ckpt_thread(sbi); if (err) {
f2fs_err(sbi, "Failed to start F2FS issue_checkpoint_thread (%d)",
err); goto restore_checkpoint;
}
}
skip: #ifdef CONFIG_QUOTA /* Release old quota file names */ for (i = 0; i < MAXQUOTAS; i++)
kfree(org_mount_opt.s_qf_names[i]); #endif /* Update the POSIXACL Flag */
sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
(test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0);
#ifdef CONFIG_QUOTA staticbool f2fs_need_recovery(struct f2fs_sb_info *sbi)
{ /* need to recovery orphan */ if (is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG)) returntrue; /* need to recovery data */ if (test_opt(sbi, DISABLE_ROLL_FORWARD)) returnfalse; if (test_opt(sbi, NORECOVERY)) returnfalse; return !is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG);
}
/* it doesn't need to check f2fs_sb_has_readonly() */ if (f2fs_hw_is_readonly(sbi)) returnfalse;
if (readonly) {
sbi->sb->s_flags &= ~SB_RDONLY;
set_sbi_flag(sbi, SBI_IS_WRITABLE);
}
/* * Turn on quotas which were not enabled for read-only mounts if * filesystem has quota feature, so that they are updated correctly.
*/ return f2fs_enable_quota_files(sbi, readonly);
}
staticvoid f2fs_recover_quota_end(struct f2fs_sb_info *sbi, bool quota_enabled)
{ if (quota_enabled)
f2fs_quota_off_umount(sbi->sb);
if (is_set_ckpt_flags(F2FS_SB(sb), CP_QUOTA_NEED_FSCK_FLAG)) {
f2fs_err(sbi, "quota file may be corrupted, skip loading it"); return 0;
}
sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
for (type = 0; type < MAXQUOTAS; type++) {
qf_inum = f2fs_qf_ino(sb, type); if (qf_inum) {
err = f2fs_quota_enable(sb, type, QFMT_VFS_V1,
DQUOT_USAGE_ENABLED |
(quota_mopt[type] ? DQUOT_LIMITS_ENABLED : 0)); if (err) {
f2fs_err(sbi, "Failed to enable quota tracking (type=%d, err=%d). Please run fsck to fix.",
type, err); for (type--; type >= 0; type--)
dquot_quota_off(sb, type);
set_sbi_flag(F2FS_SB(sb),
SBI_QUOTA_NEED_REPAIR); return err;
}
}
} return 0;
}
staticint f2fs_quota_sync_file(struct f2fs_sb_info *sbi, int type)
{ struct quota_info *dqopt = sb_dqopt(sbi->sb); struct address_space *mapping = dqopt->files[type]->i_mapping; int ret = 0;
ret = dquot_writeback_dquots(sbi->sb, type); if (ret) goto out;
ret = filemap_fdatawrite(mapping); if (ret) goto out;
/* if we are using journalled quota */ if (is_journalled_quota(sbi)) goto out;
ret = filemap_fdatawait(mapping);
truncate_inode_pages(&dqopt->files[type]->i_data, 0);
out: if (ret)
set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); return ret;
}
int f2fs_do_quota_sync(struct super_block *sb, int type)
{ struct f2fs_sb_info *sbi = F2FS_SB(sb); struct quota_info *dqopt = sb_dqopt(sb); int cnt; int ret = 0;
/* * Now when everything is written we can discard the pagecache so * that userspace sees the changes.
*/ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (type != -1 && cnt != type) continue;
if (!sb_has_quota_active(sb, cnt)) continue;
if (!f2fs_sb_has_quota_ino(sbi))
inode_lock(dqopt->files[cnt]);
staticint f2fs_quota_off(struct super_block *sb, int type)
{ struct f2fs_sb_info *sbi = F2FS_SB(sb); int err;
F2FS_SB(sb)->umount_lock_holder = current;
err = __f2fs_quota_off(sb, type);
/* * quotactl can shutdown journalled quota, result in inconsistence * between quota record and fs data by following updates, tag the * flag to let fsck be aware of it.
*/ if (is_journalled_quota(sbi))
set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
F2FS_SB(sb)->umount_lock_holder = NULL;
return err;
}
void f2fs_quota_off_umount(struct super_block *sb)
{ int type; int err;
for (type = 0; type < MAXQUOTAS; type++) {
err = __f2fs_quota_off(sb, type); if (err) { int ret = dquot_quota_off(sb, type);
f2fs_err(F2FS_SB(sb), "Fail to turn off disk quota (type: %d, err: %d, ret:%d), Please run fsck to fix it.",
type, err, ret);
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);
}
/* * Encrypting the root directory is not allowed because fsck * expects lost+found directory to exist and remain unencrypted * if LOST_FOUND feature is enabled. *
*/ if (f2fs_sb_has_lost_found(sbi) &&
inode->i_ino == F2FS_ROOT_INO(sbi)) return -EPERM;
if (f2fs_check_nid_range(sbi, ino)) return ERR_PTR(-ESTALE);
/* * f2fs_iget isn't quite right if the inode is currently unallocated! * However f2fs_iget currently does appropriate checks to handle stale * inodes so everything is OK.
*/
inode = f2fs_iget(sb, ino); if (IS_ERR(inode)) return ERR_CAST(inode); if (unlikely(generation && inode->i_generation != generation)) { /* we didn't find the right inode.. */
iput(inode); return ERR_PTR(-ESTALE);
} return inode;
}
staticstruct dentry *f2fs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
{ return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
f2fs_nfs_get_inode);
}
staticstruct dentry *f2fs_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
{ return generic_fh_to_parent(sb, fid, fh_len, fh_type,
f2fs_nfs_get_inode);
}
/* * note: previously, result is equal to (DEF_ADDRS_PER_INODE - * DEFAULT_INLINE_XATTR_ADDRS), but now f2fs try to reserve more * space in inode.i_addr, it will be more safe to reassign * result as zero.
*/
/* two direct node blocks */
result += (leaf_count * 2);
/* two indirect node blocks */
leaf_count *= NIDS_PER_BLOCK;
result += (leaf_count * 2);
/* one double indirect node block */
leaf_count *= NIDS_PER_BLOCK;
result += leaf_count;
/* * For compatibility with FSCRYPT_POLICY_FLAG_IV_INO_LBLK_{64,32} with * a 4K crypto data unit, we must restrict the max filesize to what can * fit within U32_MAX + 1 data units.
*/
result = umin(result, F2FS_BYTES_TO_BLK(((loff_t)U32_MAX + 1) * 4096));
return result;
}
staticint __f2fs_commit_super(struct f2fs_sb_info *sbi, struct folio *folio,
pgoff_t index, bool update)
{ struct bio *bio; /* it's rare case, we can do fua all the time */
blk_opf_t opf = REQ_OP_WRITE | REQ_SYNC | REQ_PREFLUSH | REQ_FUA; int ret;
/* only support block_size equals to PAGE_SIZE */ if (le32_to_cpu(raw_super->log_blocksize) != F2FS_BLKSIZE_BITS) {
f2fs_info(sbi, "Invalid log_blocksize (%u), supports only %u",
le32_to_cpu(raw_super->log_blocksize),
F2FS_BLKSIZE_BITS); return -EFSCORRUPTED;
}
/* check log blocks per segment */ if (le32_to_cpu(raw_super->log_blocks_per_seg) != 9) {
f2fs_info(sbi, "Invalid log blocks per segment (%u)",
le32_to_cpu(raw_super->log_blocks_per_seg)); return -EFSCORRUPTED;
}
for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { if (le32_to_cpu(ckpt->cur_node_segno[i]) >= main_segs ||
le16_to_cpu(ckpt->cur_node_blkoff[i]) >= blocks_per_seg) return 1;
if (f2fs_sb_has_readonly(sbi)) goto check_data;
for (j = i + 1; j < NR_CURSEG_NODE_TYPE; j++) { if (le32_to_cpu(ckpt->cur_node_segno[i]) ==
le32_to_cpu(ckpt->cur_node_segno[j])) {
f2fs_err(sbi, "Node segment (%u, %u) has the same segno: %u",
i, j,
le32_to_cpu(ckpt->cur_node_segno[i])); return 1;
}
}
}
check_data: for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) { if (le32_to_cpu(ckpt->cur_data_segno[i]) >= main_segs ||
le16_to_cpu(ckpt->cur_data_blkoff[i]) >= blocks_per_seg) return 1;
if (f2fs_sb_has_readonly(sbi)) goto skip_cross;
for (j = i + 1; j < NR_CURSEG_DATA_TYPE; j++) { if (le32_to_cpu(ckpt->cur_data_segno[i]) ==
le32_to_cpu(ckpt->cur_data_segno[j])) {
f2fs_err(sbi, "Data segment (%u, %u) has the same segno: %u",
i, j,
le32_to_cpu(ckpt->cur_data_segno[i])); return 1;
}
}
} for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { for (j = 0; j < NR_CURSEG_DATA_TYPE; j++) { if (le32_to_cpu(ckpt->cur_node_segno[i]) ==
le32_to_cpu(ckpt->cur_data_segno[j])) {
f2fs_err(sbi, "Node segment (%u) and Data segment (%u) has the same segno: %u",
i, j,
le32_to_cpu(ckpt->cur_node_segno[i])); return 1;
}
}
}
skip_cross:
sit_bitmap_size = le32_to_cpu(ckpt->sit_ver_bitmap_bytesize);
nat_bitmap_size = le32_to_cpu(ckpt->nat_ver_bitmap_bytesize);
if (bdev_is_zoned(FDEV(devi).bdev)) {
max_open_zones = bdev_max_open_zones(bdev); if (max_open_zones && (max_open_zones < sbi->max_open_zones))
sbi->max_open_zones = max_open_zones; if (sbi->max_open_zones < F2FS_OPTION(sbi).active_logs) {
f2fs_err(sbi, "zoned: max open zones %u is too small, need at least %u open zones",
sbi->max_open_zones, F2FS_OPTION(sbi).active_logs); return -EINVAL;
}
}
ret = blkdev_report_zones(bdev, 0, BLK_ALL_ZONES, f2fs_report_zone_cb,
&rep_zone_arg); if (ret < 0) return ret; return 0;
} #endif
/* * Read f2fs raw super block. * Because we have two copies of super block, so read both of them * to get the first valid one. If any one of them is broken, we pass * them recovery flag back to the caller.
*/ staticint read_raw_super_block(struct f2fs_sb_info *sbi, struct f2fs_super_block **raw_super, int *valid_super_block, int *recovery)
{ struct super_block *sb = sbi->sb; int block; struct folio *folio; struct f2fs_super_block *super; int err = 0;
super = kzalloc(sizeof(struct f2fs_super_block), GFP_KERNEL); if (!super) return -ENOMEM;
if (!f2fs_hw_is_readonly(sbi)) {
save_stop_reason(sbi, reason);
/* * always create an asynchronous task to record stop_reason * in order to avoid potential deadlock when running into * f2fs_record_stop_reason() synchronously.
*/
schedule_work(&sbi->s_error_work);
}
/* * We force ERRORS_RO behavior when system is rebooting. Otherwise we * could panic during 'reboot -f' as the underlying device got already * disabled.
*/ if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_PANIC &&
!shutdown && !system_going_down() &&
!is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN))
panic("F2FS-fs (device %s): panic forced after error\n",
sb->s_id);
if (shutdown)
set_sbi_flag(sbi, SBI_IS_SHUTDOWN); else
dump_stack();
/* * Continue filesystem operators if errors=continue. Should not set * RO by shutdown, since RO bypasses thaw_super which can hang the * system.
*/ if (continue_fs || f2fs_readonly(sb) || shutdown) {
f2fs_warn(sbi, "Stopped filesystem due to reason: %d", reason); return;
}
/* * We have already set CP_ERROR_FLAG flag to stop all updates * to filesystem, so it doesn't need to set SB_RDONLY flag here * because the flag should be set covered w/ sb->s_umount semaphore * via remount procedure, otherwise, it will confuse code like * freeze_super() which will lead to deadlocks and other problems.
*/
}
/* init f2fs-specific super block info */
sbi->valid_super_block = valid_super_block;
/* disallow all the data/node/meta page writes */
set_sbi_flag(sbi, SBI_POR_DOING);
err = f2fs_init_write_merge_io(sbi); if (err) goto free_bio_info;
init_sb_info(sbi);
err = f2fs_init_iostat(sbi); if (err) goto free_bio_info;
err = init_percpu_info(sbi); if (err) goto free_iostat;
/* init per sbi slab cache */
err = f2fs_init_xattr_caches(sbi); if (err) goto free_percpu;
err = f2fs_init_page_array_cache(sbi); if (err) goto free_xattr_cache;
/* get an inode for meta space */
sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi)); if (IS_ERR(sbi->meta_inode)) {
f2fs_err(sbi, "Failed to read F2FS meta data inode");
err = PTR_ERR(sbi->meta_inode); goto free_page_array_cache;
}
err = f2fs_get_valid_checkpoint(sbi); if (err) {
f2fs_err(sbi, "Failed to get valid F2FS checkpoint"); goto free_meta_inode;
}
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;
}
if (__is_set_ckpt_flags(F2FS_CKPT(sbi), CP_FSCK_FLAG))
set_sbi_flag(sbi, SBI_NEED_FSCK);
/* Initialize device list */
err = f2fs_scan_devices(sbi); if (err) {
f2fs_err(sbi, "Failed to find devices"); goto free_devices;
}
err = f2fs_init_post_read_wq(sbi); if (err) {
f2fs_err(sbi, "Failed to initialize post read workqueue"); goto free_devices;
}
/* Read accumulated write IO statistics if exists */
seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE); if (__exist_node_summaries(sbi))
sbi->kbytes_written =
le64_to_cpu(seg_i->journal->info.kbytes_written);
f2fs_build_gc_manager(sbi);
err = f2fs_build_stats(sbi); if (err) goto free_nm;
/* get an inode for node space */
sbi->node_inode = f2fs_iget(sb, F2FS_NODE_INO(sbi)); if (IS_ERR(sbi->node_inode)) {
f2fs_err(sbi, "Failed to read node inode");
err = PTR_ERR(sbi->node_inode); goto free_stats;
}
err = f2fs_init_compress_inode(sbi); if (err) goto free_root_inode;
err = f2fs_register_sysfs(sbi); if (err) goto free_compress_inode;
sbi->umount_lock_holder = current; #ifdef CONFIG_QUOTA /* Enable quota usage during mount */ if (f2fs_sb_has_quota_ino(sbi) && !f2fs_readonly(sb)) {
err = f2fs_enable_quotas(sb); if (err)
f2fs_err(sbi, "Cannot turn on quotas: error %d", err);
}
quota_enabled = f2fs_recover_quota_begin(sbi); #endif /* if there are any orphan inodes, free them */
err = f2fs_recover_orphan_inodes(sbi); if (err) goto free_meta;
if (unlikely(is_set_ckpt_flags(sbi, CP_DISABLED_FLAG))) {
skip_recovery = true; goto reset_checkpoint;
}
/* recover fsynced data */ if (!test_opt(sbi, DISABLE_ROLL_FORWARD) &&
!test_opt(sbi, NORECOVERY)) { /* * mount should be failed, when device has readonly mode, and * previous checkpoint was not done by clean system shutdown.
*/ if (f2fs_hw_is_readonly(sbi)) { if (!is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) {
err = f2fs_recover_fsync_data(sbi, true); if (err > 0) {
err = -EROFS;
f2fs_err(sbi, "Need to recover fsync data, but " "write access unavailable, please try " "mount w/ disable_roll_forward or norecovery");
} if (err < 0) goto free_meta;
}
f2fs_info(sbi, "write access unavailable, skipping recovery"); goto reset_checkpoint;
}
if (need_fsck)
set_sbi_flag(sbi, SBI_NEED_FSCK);
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_err(sbi, "Cannot recover all fsync data errno=%d",
err); goto free_meta;
}
} else {
err = f2fs_recover_fsync_data(sbi, true);
if (!f2fs_readonly(sb) && err > 0) {
err = -EINVAL;
f2fs_err(sbi, "Need to recover fsync data"); goto free_meta;
}
}
reset_checkpoint: #ifdef CONFIG_QUOTA
f2fs_recover_quota_end(sbi, quota_enabled); #endif /* * If the f2fs is not readonly and fsync data recovery succeeds, * write pointer consistency of cursegs and other zones are already * checked and fixed during recovery. However, if recovery fails, * write pointers are left untouched, and retry-mount should check * them here.
*/ if (skip_recovery)
err = f2fs_check_and_fix_write_pointer(sbi); if (err) goto free_meta;
/* f2fs_recover_fsync_data() cleared this already */
clear_sbi_flag(sbi, SBI_POR_DOING);
err = f2fs_init_inmem_curseg(sbi); if (err) goto sync_free_meta;
if (test_opt(sbi, DISABLE_CHECKPOINT)) {
err = f2fs_disable_checkpoint(sbi); if (err) goto sync_free_meta;
} elseif (is_set_ckpt_flags(sbi, CP_DISABLED_FLAG)) {
f2fs_enable_checkpoint(sbi);
}
/* * If filesystem is not mounted as read-only then * do start the gc_thread.
*/ if ((F2FS_OPTION(sbi).bggc_mode != BGGC_MODE_OFF ||
test_opt(sbi, GC_MERGE)) && !f2fs_readonly(sb)) { /* After POR, we can run background GC thread.*/
err = f2fs_start_gc_thread(sbi); if (err) goto sync_free_meta;
}
f2fs_notice(sbi, "Mounted with checkpoint version = %llx",
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);
sbi->umount_lock_holder = NULL; 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); if (f2fs_sb_has_quota_ino(sbi) && !f2fs_readonly(sb))
f2fs_quota_off_umount(sbi->sb); #endif /* * Some dirty meta pages can be produced by f2fs_recover_orphan_inodes() * failed by EIO. Then, iput(node_inode) can trigger balance_fs_bg() * followed by f2fs_write_checkpoint() through f2fs_write_node_pages(), which * 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_compress_inode:
f2fs_destroy_compress_inode(sbi);
free_root_inode:
dput(sb->s_root);
sb->s_root = NULL;
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: /* stop discard thread before destroying node manager */
f2fs_stop_discard_thread(sbi);
f2fs_destroy_node_manager(sbi);
free_sm:
f2fs_destroy_segment_manager(sbi);
stop_ckpt_thread:
f2fs_stop_ckpt_thread(sbi); /* flush s_error_work before sbi destroy */
flush_work(&sbi->s_error_work);
f2fs_destroy_post_read_wq(sbi);
free_devices:
destroy_device_list(sbi);
kvfree(sbi->ckpt);
free_meta_inode:
make_bad_inode(sbi->meta_inode);
iput(sbi->meta_inode);
sbi->meta_inode = NULL;
free_page_array_cache:
f2fs_destroy_page_array_cache(sbi);
free_xattr_cache:
f2fs_destroy_xattr_caches(sbi);
free_percpu:
destroy_percpu_info(sbi);
free_iostat:
f2fs_destroy_iostat(sbi);
free_bio_info: for (i = 0; i < NR_PAGE_TYPE; i++)
kfree(sbi->write_io[i]);
#if IS_ENABLED(CONFIG_UNICODE)
utf8_unload(sb->s_encoding);
sb->s_encoding = NULL; #endif
free_options: #ifdef CONFIG_QUOTA for (i = 0; i < MAXQUOTAS; i++)
kfree(F2FS_OPTION(sbi).s_qf_names[i]); #endif /* no need to free dummy_enc_policy, we just keep it in ctx when failed */
swap(F2FS_CTX_INFO(ctx).dummy_enc_policy, F2FS_OPTION(sbi).dummy_enc_policy);
free_sb_buf:
kfree(raw_super);
free_sbi:
kfree(sbi);
sb->s_fs_info = NULL;
/* give only one another chance */ if (retry_cnt > 0 && skip_recovery) {
retry_cnt--;
shrink_dcache_sb(sb); goto try_onemore;
} return err;
}
staticvoid destroy_inodecache(void)
{ /* * Make sure all delayed rcu free inodes are flushed before we * destroy cache.
*/
rcu_barrier();
kmem_cache_destroy(f2fs_inode_cachep);
}
staticint __init init_f2fs_fs(void)
{ int err;
err = init_inodecache(); if (err) goto fail;
err = f2fs_create_node_manager_caches(); if (err) goto free_inodecache;
err = f2fs_create_segment_manager_caches(); if (err) goto free_node_manager_caches;
err = f2fs_create_checkpoint_caches(); if (err) goto free_segment_manager_caches;
err = f2fs_create_recovery_cache(); if (err) goto free_checkpoint_caches;
err = f2fs_create_extent_cache(); if (err) goto free_recovery_cache;
err = f2fs_create_garbage_collection_cache(); if (err) goto free_extent_cache;
err = f2fs_init_sysfs(); if (err) goto free_garbage_collection_cache;
err = f2fs_init_shrinker(); if (err) goto free_sysfs;
f2fs_create_root_stats();
err = f2fs_init_post_read_processing(); if (err) goto free_root_stats;
err = f2fs_init_iostat_processing(); if (err) goto free_post_read;
err = f2fs_init_bio_entry_cache(); if (err) goto free_iostat;
err = f2fs_init_bioset(); if (err) goto free_bio_entry_cache;
err = f2fs_init_compress_mempool(); if (err) goto free_bioset;
err = f2fs_init_compress_cache(); if (err) goto free_compress_mempool;
err = f2fs_create_casefold_cache(); if (err) goto free_compress_cache;
err = register_filesystem(&f2fs_fs_type); if (err) goto free_casefold_cache; return 0;
free_casefold_cache:
f2fs_destroy_casefold_cache();
free_compress_cache:
f2fs_destroy_compress_cache();
free_compress_mempool:
f2fs_destroy_compress_mempool();
free_bioset:
f2fs_destroy_bioset();
free_bio_entry_cache:
f2fs_destroy_bio_entry_cache();
free_iostat:
f2fs_destroy_iostat_processing();
free_post_read:
f2fs_destroy_post_read_processing();
free_root_stats:
f2fs_destroy_root_stats();
f2fs_exit_shrinker();
free_sysfs:
f2fs_exit_sysfs();
free_garbage_collection_cache:
f2fs_destroy_garbage_collection_cache();
free_extent_cache:
f2fs_destroy_extent_cache();
free_recovery_cache:
f2fs_destroy_recovery_cache();
free_checkpoint_caches:
f2fs_destroy_checkpoint_caches();
free_segment_manager_caches:
f2fs_destroy_segment_manager_caches();
free_node_manager_caches:
f2fs_destroy_node_manager_caches();
free_inodecache:
destroy_inodecache();
fail: return err;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.