162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * fs/f2fs/super.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2012 Samsung Electronics Co., Ltd. 662306a36Sopenharmony_ci * http://www.samsung.com/ 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/fs.h> 1162306a36Sopenharmony_ci#include <linux/fs_context.h> 1262306a36Sopenharmony_ci#include <linux/sched/mm.h> 1362306a36Sopenharmony_ci#include <linux/statfs.h> 1462306a36Sopenharmony_ci#include <linux/buffer_head.h> 1562306a36Sopenharmony_ci#include <linux/kthread.h> 1662306a36Sopenharmony_ci#include <linux/parser.h> 1762306a36Sopenharmony_ci#include <linux/mount.h> 1862306a36Sopenharmony_ci#include <linux/seq_file.h> 1962306a36Sopenharmony_ci#include <linux/proc_fs.h> 2062306a36Sopenharmony_ci#include <linux/random.h> 2162306a36Sopenharmony_ci#include <linux/exportfs.h> 2262306a36Sopenharmony_ci#include <linux/blkdev.h> 2362306a36Sopenharmony_ci#include <linux/quotaops.h> 2462306a36Sopenharmony_ci#include <linux/f2fs_fs.h> 2562306a36Sopenharmony_ci#include <linux/sysfs.h> 2662306a36Sopenharmony_ci#include <linux/quota.h> 2762306a36Sopenharmony_ci#include <linux/unicode.h> 2862306a36Sopenharmony_ci#include <linux/part_stat.h> 2962306a36Sopenharmony_ci#include <linux/zstd.h> 3062306a36Sopenharmony_ci#include <linux/lz4.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "f2fs.h" 3362306a36Sopenharmony_ci#include "node.h" 3462306a36Sopenharmony_ci#include "segment.h" 3562306a36Sopenharmony_ci#include "xattr.h" 3662306a36Sopenharmony_ci#include "gc.h" 3762306a36Sopenharmony_ci#include "iostat.h" 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 4062306a36Sopenharmony_ci#include <trace/events/f2fs.h> 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic struct kmem_cache *f2fs_inode_cachep; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FAULT_INJECTION 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ciconst char *f2fs_fault_name[FAULT_MAX] = { 4762306a36Sopenharmony_ci [FAULT_KMALLOC] = "kmalloc", 4862306a36Sopenharmony_ci [FAULT_KVMALLOC] = "kvmalloc", 4962306a36Sopenharmony_ci [FAULT_PAGE_ALLOC] = "page alloc", 5062306a36Sopenharmony_ci [FAULT_PAGE_GET] = "page get", 5162306a36Sopenharmony_ci [FAULT_ALLOC_NID] = "alloc nid", 5262306a36Sopenharmony_ci [FAULT_ORPHAN] = "orphan", 5362306a36Sopenharmony_ci [FAULT_BLOCK] = "no more block", 5462306a36Sopenharmony_ci [FAULT_DIR_DEPTH] = "too big dir depth", 5562306a36Sopenharmony_ci [FAULT_EVICT_INODE] = "evict_inode fail", 5662306a36Sopenharmony_ci [FAULT_TRUNCATE] = "truncate fail", 5762306a36Sopenharmony_ci [FAULT_READ_IO] = "read IO error", 5862306a36Sopenharmony_ci [FAULT_CHECKPOINT] = "checkpoint error", 5962306a36Sopenharmony_ci [FAULT_DISCARD] = "discard error", 6062306a36Sopenharmony_ci [FAULT_WRITE_IO] = "write IO error", 6162306a36Sopenharmony_ci [FAULT_SLAB_ALLOC] = "slab alloc", 6262306a36Sopenharmony_ci [FAULT_DQUOT_INIT] = "dquot initialize", 6362306a36Sopenharmony_ci [FAULT_LOCK_OP] = "lock_op", 6462306a36Sopenharmony_ci [FAULT_BLKADDR] = "invalid blkaddr", 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_civoid f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned int rate, 6862306a36Sopenharmony_ci unsigned int type) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct f2fs_fault_info *ffi = &F2FS_OPTION(sbi).fault_info; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (rate) { 7362306a36Sopenharmony_ci atomic_set(&ffi->inject_ops, 0); 7462306a36Sopenharmony_ci ffi->inject_rate = rate; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (type) 7862306a36Sopenharmony_ci ffi->inject_type = type; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (!rate && !type) 8162306a36Sopenharmony_ci memset(ffi, 0, sizeof(struct f2fs_fault_info)); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci#endif 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* f2fs-wide shrinker description */ 8662306a36Sopenharmony_cistatic struct shrinker f2fs_shrinker_info = { 8762306a36Sopenharmony_ci .scan_objects = f2fs_shrink_scan, 8862306a36Sopenharmony_ci .count_objects = f2fs_shrink_count, 8962306a36Sopenharmony_ci .seeks = DEFAULT_SEEKS, 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cienum { 9362306a36Sopenharmony_ci Opt_gc_background, 9462306a36Sopenharmony_ci Opt_disable_roll_forward, 9562306a36Sopenharmony_ci Opt_norecovery, 9662306a36Sopenharmony_ci Opt_discard, 9762306a36Sopenharmony_ci Opt_nodiscard, 9862306a36Sopenharmony_ci Opt_noheap, 9962306a36Sopenharmony_ci Opt_heap, 10062306a36Sopenharmony_ci Opt_user_xattr, 10162306a36Sopenharmony_ci Opt_nouser_xattr, 10262306a36Sopenharmony_ci Opt_acl, 10362306a36Sopenharmony_ci Opt_noacl, 10462306a36Sopenharmony_ci Opt_active_logs, 10562306a36Sopenharmony_ci Opt_disable_ext_identify, 10662306a36Sopenharmony_ci Opt_inline_xattr, 10762306a36Sopenharmony_ci Opt_noinline_xattr, 10862306a36Sopenharmony_ci Opt_inline_xattr_size, 10962306a36Sopenharmony_ci Opt_inline_data, 11062306a36Sopenharmony_ci Opt_inline_dentry, 11162306a36Sopenharmony_ci Opt_noinline_dentry, 11262306a36Sopenharmony_ci Opt_flush_merge, 11362306a36Sopenharmony_ci Opt_noflush_merge, 11462306a36Sopenharmony_ci Opt_barrier, 11562306a36Sopenharmony_ci Opt_nobarrier, 11662306a36Sopenharmony_ci Opt_fastboot, 11762306a36Sopenharmony_ci Opt_extent_cache, 11862306a36Sopenharmony_ci Opt_noextent_cache, 11962306a36Sopenharmony_ci Opt_noinline_data, 12062306a36Sopenharmony_ci Opt_data_flush, 12162306a36Sopenharmony_ci Opt_reserve_root, 12262306a36Sopenharmony_ci Opt_resgid, 12362306a36Sopenharmony_ci Opt_resuid, 12462306a36Sopenharmony_ci Opt_mode, 12562306a36Sopenharmony_ci Opt_io_size_bits, 12662306a36Sopenharmony_ci Opt_fault_injection, 12762306a36Sopenharmony_ci Opt_fault_type, 12862306a36Sopenharmony_ci Opt_lazytime, 12962306a36Sopenharmony_ci Opt_nolazytime, 13062306a36Sopenharmony_ci Opt_quota, 13162306a36Sopenharmony_ci Opt_noquota, 13262306a36Sopenharmony_ci Opt_usrquota, 13362306a36Sopenharmony_ci Opt_grpquota, 13462306a36Sopenharmony_ci Opt_prjquota, 13562306a36Sopenharmony_ci Opt_usrjquota, 13662306a36Sopenharmony_ci Opt_grpjquota, 13762306a36Sopenharmony_ci Opt_prjjquota, 13862306a36Sopenharmony_ci Opt_offusrjquota, 13962306a36Sopenharmony_ci Opt_offgrpjquota, 14062306a36Sopenharmony_ci Opt_offprjjquota, 14162306a36Sopenharmony_ci Opt_jqfmt_vfsold, 14262306a36Sopenharmony_ci Opt_jqfmt_vfsv0, 14362306a36Sopenharmony_ci Opt_jqfmt_vfsv1, 14462306a36Sopenharmony_ci Opt_alloc, 14562306a36Sopenharmony_ci Opt_fsync, 14662306a36Sopenharmony_ci Opt_test_dummy_encryption, 14762306a36Sopenharmony_ci Opt_inlinecrypt, 14862306a36Sopenharmony_ci Opt_checkpoint_disable, 14962306a36Sopenharmony_ci Opt_checkpoint_disable_cap, 15062306a36Sopenharmony_ci Opt_checkpoint_disable_cap_perc, 15162306a36Sopenharmony_ci Opt_checkpoint_enable, 15262306a36Sopenharmony_ci Opt_checkpoint_merge, 15362306a36Sopenharmony_ci Opt_nocheckpoint_merge, 15462306a36Sopenharmony_ci Opt_compress_algorithm, 15562306a36Sopenharmony_ci Opt_compress_log_size, 15662306a36Sopenharmony_ci Opt_compress_extension, 15762306a36Sopenharmony_ci Opt_nocompress_extension, 15862306a36Sopenharmony_ci Opt_compress_chksum, 15962306a36Sopenharmony_ci Opt_compress_mode, 16062306a36Sopenharmony_ci Opt_compress_cache, 16162306a36Sopenharmony_ci Opt_atgc, 16262306a36Sopenharmony_ci Opt_gc_merge, 16362306a36Sopenharmony_ci Opt_nogc_merge, 16462306a36Sopenharmony_ci Opt_discard_unit, 16562306a36Sopenharmony_ci Opt_memory_mode, 16662306a36Sopenharmony_ci Opt_age_extent_cache, 16762306a36Sopenharmony_ci Opt_errors, 16862306a36Sopenharmony_ci Opt_err, 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic match_table_t f2fs_tokens = { 17262306a36Sopenharmony_ci {Opt_gc_background, "background_gc=%s"}, 17362306a36Sopenharmony_ci {Opt_disable_roll_forward, "disable_roll_forward"}, 17462306a36Sopenharmony_ci {Opt_norecovery, "norecovery"}, 17562306a36Sopenharmony_ci {Opt_discard, "discard"}, 17662306a36Sopenharmony_ci {Opt_nodiscard, "nodiscard"}, 17762306a36Sopenharmony_ci {Opt_noheap, "no_heap"}, 17862306a36Sopenharmony_ci {Opt_heap, "heap"}, 17962306a36Sopenharmony_ci {Opt_user_xattr, "user_xattr"}, 18062306a36Sopenharmony_ci {Opt_nouser_xattr, "nouser_xattr"}, 18162306a36Sopenharmony_ci {Opt_acl, "acl"}, 18262306a36Sopenharmony_ci {Opt_noacl, "noacl"}, 18362306a36Sopenharmony_ci {Opt_active_logs, "active_logs=%u"}, 18462306a36Sopenharmony_ci {Opt_disable_ext_identify, "disable_ext_identify"}, 18562306a36Sopenharmony_ci {Opt_inline_xattr, "inline_xattr"}, 18662306a36Sopenharmony_ci {Opt_noinline_xattr, "noinline_xattr"}, 18762306a36Sopenharmony_ci {Opt_inline_xattr_size, "inline_xattr_size=%u"}, 18862306a36Sopenharmony_ci {Opt_inline_data, "inline_data"}, 18962306a36Sopenharmony_ci {Opt_inline_dentry, "inline_dentry"}, 19062306a36Sopenharmony_ci {Opt_noinline_dentry, "noinline_dentry"}, 19162306a36Sopenharmony_ci {Opt_flush_merge, "flush_merge"}, 19262306a36Sopenharmony_ci {Opt_noflush_merge, "noflush_merge"}, 19362306a36Sopenharmony_ci {Opt_barrier, "barrier"}, 19462306a36Sopenharmony_ci {Opt_nobarrier, "nobarrier"}, 19562306a36Sopenharmony_ci {Opt_fastboot, "fastboot"}, 19662306a36Sopenharmony_ci {Opt_extent_cache, "extent_cache"}, 19762306a36Sopenharmony_ci {Opt_noextent_cache, "noextent_cache"}, 19862306a36Sopenharmony_ci {Opt_noinline_data, "noinline_data"}, 19962306a36Sopenharmony_ci {Opt_data_flush, "data_flush"}, 20062306a36Sopenharmony_ci {Opt_reserve_root, "reserve_root=%u"}, 20162306a36Sopenharmony_ci {Opt_resgid, "resgid=%u"}, 20262306a36Sopenharmony_ci {Opt_resuid, "resuid=%u"}, 20362306a36Sopenharmony_ci {Opt_mode, "mode=%s"}, 20462306a36Sopenharmony_ci {Opt_io_size_bits, "io_bits=%u"}, 20562306a36Sopenharmony_ci {Opt_fault_injection, "fault_injection=%u"}, 20662306a36Sopenharmony_ci {Opt_fault_type, "fault_type=%u"}, 20762306a36Sopenharmony_ci {Opt_lazytime, "lazytime"}, 20862306a36Sopenharmony_ci {Opt_nolazytime, "nolazytime"}, 20962306a36Sopenharmony_ci {Opt_quota, "quota"}, 21062306a36Sopenharmony_ci {Opt_noquota, "noquota"}, 21162306a36Sopenharmony_ci {Opt_usrquota, "usrquota"}, 21262306a36Sopenharmony_ci {Opt_grpquota, "grpquota"}, 21362306a36Sopenharmony_ci {Opt_prjquota, "prjquota"}, 21462306a36Sopenharmony_ci {Opt_usrjquota, "usrjquota=%s"}, 21562306a36Sopenharmony_ci {Opt_grpjquota, "grpjquota=%s"}, 21662306a36Sopenharmony_ci {Opt_prjjquota, "prjjquota=%s"}, 21762306a36Sopenharmony_ci {Opt_offusrjquota, "usrjquota="}, 21862306a36Sopenharmony_ci {Opt_offgrpjquota, "grpjquota="}, 21962306a36Sopenharmony_ci {Opt_offprjjquota, "prjjquota="}, 22062306a36Sopenharmony_ci {Opt_jqfmt_vfsold, "jqfmt=vfsold"}, 22162306a36Sopenharmony_ci {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"}, 22262306a36Sopenharmony_ci {Opt_jqfmt_vfsv1, "jqfmt=vfsv1"}, 22362306a36Sopenharmony_ci {Opt_alloc, "alloc_mode=%s"}, 22462306a36Sopenharmony_ci {Opt_fsync, "fsync_mode=%s"}, 22562306a36Sopenharmony_ci {Opt_test_dummy_encryption, "test_dummy_encryption=%s"}, 22662306a36Sopenharmony_ci {Opt_test_dummy_encryption, "test_dummy_encryption"}, 22762306a36Sopenharmony_ci {Opt_inlinecrypt, "inlinecrypt"}, 22862306a36Sopenharmony_ci {Opt_checkpoint_disable, "checkpoint=disable"}, 22962306a36Sopenharmony_ci {Opt_checkpoint_disable_cap, "checkpoint=disable:%u"}, 23062306a36Sopenharmony_ci {Opt_checkpoint_disable_cap_perc, "checkpoint=disable:%u%%"}, 23162306a36Sopenharmony_ci {Opt_checkpoint_enable, "checkpoint=enable"}, 23262306a36Sopenharmony_ci {Opt_checkpoint_merge, "checkpoint_merge"}, 23362306a36Sopenharmony_ci {Opt_nocheckpoint_merge, "nocheckpoint_merge"}, 23462306a36Sopenharmony_ci {Opt_compress_algorithm, "compress_algorithm=%s"}, 23562306a36Sopenharmony_ci {Opt_compress_log_size, "compress_log_size=%u"}, 23662306a36Sopenharmony_ci {Opt_compress_extension, "compress_extension=%s"}, 23762306a36Sopenharmony_ci {Opt_nocompress_extension, "nocompress_extension=%s"}, 23862306a36Sopenharmony_ci {Opt_compress_chksum, "compress_chksum"}, 23962306a36Sopenharmony_ci {Opt_compress_mode, "compress_mode=%s"}, 24062306a36Sopenharmony_ci {Opt_compress_cache, "compress_cache"}, 24162306a36Sopenharmony_ci {Opt_atgc, "atgc"}, 24262306a36Sopenharmony_ci {Opt_gc_merge, "gc_merge"}, 24362306a36Sopenharmony_ci {Opt_nogc_merge, "nogc_merge"}, 24462306a36Sopenharmony_ci {Opt_discard_unit, "discard_unit=%s"}, 24562306a36Sopenharmony_ci {Opt_memory_mode, "memory=%s"}, 24662306a36Sopenharmony_ci {Opt_age_extent_cache, "age_extent_cache"}, 24762306a36Sopenharmony_ci {Opt_errors, "errors=%s"}, 24862306a36Sopenharmony_ci {Opt_err, NULL}, 24962306a36Sopenharmony_ci}; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_civoid f2fs_printk(struct f2fs_sb_info *sbi, const char *fmt, ...) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct va_format vaf; 25462306a36Sopenharmony_ci va_list args; 25562306a36Sopenharmony_ci int level; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci va_start(args, fmt); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci level = printk_get_level(fmt); 26062306a36Sopenharmony_ci vaf.fmt = printk_skip_level(fmt); 26162306a36Sopenharmony_ci vaf.va = &args; 26262306a36Sopenharmony_ci printk("%c%cF2FS-fs (%s): %pV\n", 26362306a36Sopenharmony_ci KERN_SOH_ASCII, level, sbi->sb->s_id, &vaf); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci va_end(args); 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE) 26962306a36Sopenharmony_cistatic const struct f2fs_sb_encodings { 27062306a36Sopenharmony_ci __u16 magic; 27162306a36Sopenharmony_ci char *name; 27262306a36Sopenharmony_ci unsigned int version; 27362306a36Sopenharmony_ci} f2fs_sb_encoding_map[] = { 27462306a36Sopenharmony_ci {F2FS_ENC_UTF8_12_1, "utf8", UNICODE_AGE(12, 1, 0)}, 27562306a36Sopenharmony_ci}; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic const struct f2fs_sb_encodings * 27862306a36Sopenharmony_cif2fs_sb_read_encoding(const struct f2fs_super_block *sb) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci __u16 magic = le16_to_cpu(sb->s_encoding); 28162306a36Sopenharmony_ci int i; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(f2fs_sb_encoding_map); i++) 28462306a36Sopenharmony_ci if (magic == f2fs_sb_encoding_map[i].magic) 28562306a36Sopenharmony_ci return &f2fs_sb_encoding_map[i]; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci return NULL; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistruct kmem_cache *f2fs_cf_name_slab; 29162306a36Sopenharmony_cistatic int __init f2fs_create_casefold_cache(void) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci f2fs_cf_name_slab = f2fs_kmem_cache_create("f2fs_casefolded_name", 29462306a36Sopenharmony_ci F2FS_NAME_LEN); 29562306a36Sopenharmony_ci return f2fs_cf_name_slab ? 0 : -ENOMEM; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic void f2fs_destroy_casefold_cache(void) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci kmem_cache_destroy(f2fs_cf_name_slab); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci#else 30362306a36Sopenharmony_cistatic int __init f2fs_create_casefold_cache(void) { return 0; } 30462306a36Sopenharmony_cistatic void f2fs_destroy_casefold_cache(void) { } 30562306a36Sopenharmony_ci#endif 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic inline void limit_reserve_root(struct f2fs_sb_info *sbi) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci block_t limit = min((sbi->user_block_count >> 3), 31062306a36Sopenharmony_ci sbi->user_block_count - sbi->reserved_blocks); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* limit is 12.5% */ 31362306a36Sopenharmony_ci if (test_opt(sbi, RESERVE_ROOT) && 31462306a36Sopenharmony_ci F2FS_OPTION(sbi).root_reserved_blocks > limit) { 31562306a36Sopenharmony_ci F2FS_OPTION(sbi).root_reserved_blocks = limit; 31662306a36Sopenharmony_ci f2fs_info(sbi, "Reduce reserved blocks for root = %u", 31762306a36Sopenharmony_ci F2FS_OPTION(sbi).root_reserved_blocks); 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci if (!test_opt(sbi, RESERVE_ROOT) && 32062306a36Sopenharmony_ci (!uid_eq(F2FS_OPTION(sbi).s_resuid, 32162306a36Sopenharmony_ci make_kuid(&init_user_ns, F2FS_DEF_RESUID)) || 32262306a36Sopenharmony_ci !gid_eq(F2FS_OPTION(sbi).s_resgid, 32362306a36Sopenharmony_ci make_kgid(&init_user_ns, F2FS_DEF_RESGID)))) 32462306a36Sopenharmony_ci f2fs_info(sbi, "Ignore s_resuid=%u, s_resgid=%u w/o reserve_root", 32562306a36Sopenharmony_ci from_kuid_munged(&init_user_ns, 32662306a36Sopenharmony_ci F2FS_OPTION(sbi).s_resuid), 32762306a36Sopenharmony_ci from_kgid_munged(&init_user_ns, 32862306a36Sopenharmony_ci F2FS_OPTION(sbi).s_resgid)); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic inline int adjust_reserved_segment(struct f2fs_sb_info *sbi) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci unsigned int sec_blks = sbi->blocks_per_seg * sbi->segs_per_sec; 33462306a36Sopenharmony_ci unsigned int avg_vblocks; 33562306a36Sopenharmony_ci unsigned int wanted_reserved_segments; 33662306a36Sopenharmony_ci block_t avail_user_block_count; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (!F2FS_IO_ALIGNED(sbi)) 33962306a36Sopenharmony_ci return 0; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* average valid block count in section in worst case */ 34262306a36Sopenharmony_ci avg_vblocks = sec_blks / F2FS_IO_SIZE(sbi); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* 34562306a36Sopenharmony_ci * we need enough free space when migrating one section in worst case 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_ci wanted_reserved_segments = (F2FS_IO_SIZE(sbi) / avg_vblocks) * 34862306a36Sopenharmony_ci reserved_segments(sbi); 34962306a36Sopenharmony_ci wanted_reserved_segments -= reserved_segments(sbi); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci avail_user_block_count = sbi->user_block_count - 35262306a36Sopenharmony_ci sbi->current_reserved_blocks - 35362306a36Sopenharmony_ci F2FS_OPTION(sbi).root_reserved_blocks; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (wanted_reserved_segments * sbi->blocks_per_seg > 35662306a36Sopenharmony_ci avail_user_block_count) { 35762306a36Sopenharmony_ci f2fs_err(sbi, "IO align feature can't grab additional reserved segment: %u, available segments: %u", 35862306a36Sopenharmony_ci wanted_reserved_segments, 35962306a36Sopenharmony_ci avail_user_block_count >> sbi->log_blocks_per_seg); 36062306a36Sopenharmony_ci return -ENOSPC; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci SM_I(sbi)->additional_reserved_segments = wanted_reserved_segments; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci f2fs_info(sbi, "IO align feature needs additional reserved segment: %u", 36662306a36Sopenharmony_ci wanted_reserved_segments); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return 0; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic inline void adjust_unusable_cap_perc(struct f2fs_sb_info *sbi) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci if (!F2FS_OPTION(sbi).unusable_cap_perc) 37462306a36Sopenharmony_ci return; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (F2FS_OPTION(sbi).unusable_cap_perc == 100) 37762306a36Sopenharmony_ci F2FS_OPTION(sbi).unusable_cap = sbi->user_block_count; 37862306a36Sopenharmony_ci else 37962306a36Sopenharmony_ci F2FS_OPTION(sbi).unusable_cap = (sbi->user_block_count / 100) * 38062306a36Sopenharmony_ci F2FS_OPTION(sbi).unusable_cap_perc; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci f2fs_info(sbi, "Adjust unusable cap for checkpoint=disable = %u / %u%%", 38362306a36Sopenharmony_ci F2FS_OPTION(sbi).unusable_cap, 38462306a36Sopenharmony_ci F2FS_OPTION(sbi).unusable_cap_perc); 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic void init_once(void *foo) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci struct f2fs_inode_info *fi = (struct f2fs_inode_info *) foo; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci inode_init_once(&fi->vfs_inode); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 39562306a36Sopenharmony_cistatic const char * const quotatypes[] = INITQFNAMES; 39662306a36Sopenharmony_ci#define QTYPE2NAME(t) (quotatypes[t]) 39762306a36Sopenharmony_cistatic int f2fs_set_qf_name(struct super_block *sb, int qtype, 39862306a36Sopenharmony_ci substring_t *args) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 40162306a36Sopenharmony_ci char *qname; 40262306a36Sopenharmony_ci int ret = -EINVAL; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (sb_any_quota_loaded(sb) && !F2FS_OPTION(sbi).s_qf_names[qtype]) { 40562306a36Sopenharmony_ci f2fs_err(sbi, "Cannot change journaled quota options when quota turned on"); 40662306a36Sopenharmony_ci return -EINVAL; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci if (f2fs_sb_has_quota_ino(sbi)) { 40962306a36Sopenharmony_ci f2fs_info(sbi, "QUOTA feature is enabled, so ignore qf_name"); 41062306a36Sopenharmony_ci return 0; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci qname = match_strdup(args); 41462306a36Sopenharmony_ci if (!qname) { 41562306a36Sopenharmony_ci f2fs_err(sbi, "Not enough memory for storing quotafile name"); 41662306a36Sopenharmony_ci return -ENOMEM; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci if (F2FS_OPTION(sbi).s_qf_names[qtype]) { 41962306a36Sopenharmony_ci if (strcmp(F2FS_OPTION(sbi).s_qf_names[qtype], qname) == 0) 42062306a36Sopenharmony_ci ret = 0; 42162306a36Sopenharmony_ci else 42262306a36Sopenharmony_ci f2fs_err(sbi, "%s quota file already specified", 42362306a36Sopenharmony_ci QTYPE2NAME(qtype)); 42462306a36Sopenharmony_ci goto errout; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci if (strchr(qname, '/')) { 42762306a36Sopenharmony_ci f2fs_err(sbi, "quotafile must be on filesystem root"); 42862306a36Sopenharmony_ci goto errout; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci F2FS_OPTION(sbi).s_qf_names[qtype] = qname; 43162306a36Sopenharmony_ci set_opt(sbi, QUOTA); 43262306a36Sopenharmony_ci return 0; 43362306a36Sopenharmony_cierrout: 43462306a36Sopenharmony_ci kfree(qname); 43562306a36Sopenharmony_ci return ret; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic int f2fs_clear_qf_name(struct super_block *sb, int qtype) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (sb_any_quota_loaded(sb) && F2FS_OPTION(sbi).s_qf_names[qtype]) { 44362306a36Sopenharmony_ci f2fs_err(sbi, "Cannot change journaled quota options when quota turned on"); 44462306a36Sopenharmony_ci return -EINVAL; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci kfree(F2FS_OPTION(sbi).s_qf_names[qtype]); 44762306a36Sopenharmony_ci F2FS_OPTION(sbi).s_qf_names[qtype] = NULL; 44862306a36Sopenharmony_ci return 0; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic int f2fs_check_quota_options(struct f2fs_sb_info *sbi) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci /* 45462306a36Sopenharmony_ci * We do the test below only for project quotas. 'usrquota' and 45562306a36Sopenharmony_ci * 'grpquota' mount options are allowed even without quota feature 45662306a36Sopenharmony_ci * to support legacy quotas in quota files. 45762306a36Sopenharmony_ci */ 45862306a36Sopenharmony_ci if (test_opt(sbi, PRJQUOTA) && !f2fs_sb_has_project_quota(sbi)) { 45962306a36Sopenharmony_ci f2fs_err(sbi, "Project quota feature not enabled. Cannot enable project quota enforcement."); 46062306a36Sopenharmony_ci return -1; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci if (F2FS_OPTION(sbi).s_qf_names[USRQUOTA] || 46362306a36Sopenharmony_ci F2FS_OPTION(sbi).s_qf_names[GRPQUOTA] || 46462306a36Sopenharmony_ci F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]) { 46562306a36Sopenharmony_ci if (test_opt(sbi, USRQUOTA) && 46662306a36Sopenharmony_ci F2FS_OPTION(sbi).s_qf_names[USRQUOTA]) 46762306a36Sopenharmony_ci clear_opt(sbi, USRQUOTA); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (test_opt(sbi, GRPQUOTA) && 47062306a36Sopenharmony_ci F2FS_OPTION(sbi).s_qf_names[GRPQUOTA]) 47162306a36Sopenharmony_ci clear_opt(sbi, GRPQUOTA); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (test_opt(sbi, PRJQUOTA) && 47462306a36Sopenharmony_ci F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]) 47562306a36Sopenharmony_ci clear_opt(sbi, PRJQUOTA); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci if (test_opt(sbi, GRPQUOTA) || test_opt(sbi, USRQUOTA) || 47862306a36Sopenharmony_ci test_opt(sbi, PRJQUOTA)) { 47962306a36Sopenharmony_ci f2fs_err(sbi, "old and new quota format mixing"); 48062306a36Sopenharmony_ci return -1; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (!F2FS_OPTION(sbi).s_jquota_fmt) { 48462306a36Sopenharmony_ci f2fs_err(sbi, "journaled quota format not specified"); 48562306a36Sopenharmony_ci return -1; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (f2fs_sb_has_quota_ino(sbi) && F2FS_OPTION(sbi).s_jquota_fmt) { 49062306a36Sopenharmony_ci f2fs_info(sbi, "QUOTA feature is enabled, so ignore jquota_fmt"); 49162306a36Sopenharmony_ci F2FS_OPTION(sbi).s_jquota_fmt = 0; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci return 0; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci#endif 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic int f2fs_set_test_dummy_encryption(struct super_block *sb, 49862306a36Sopenharmony_ci const char *opt, 49962306a36Sopenharmony_ci const substring_t *arg, 50062306a36Sopenharmony_ci bool is_remount) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 50362306a36Sopenharmony_ci struct fs_parameter param = { 50462306a36Sopenharmony_ci .type = fs_value_is_string, 50562306a36Sopenharmony_ci .string = arg->from ? arg->from : "", 50662306a36Sopenharmony_ci }; 50762306a36Sopenharmony_ci struct fscrypt_dummy_policy *policy = 50862306a36Sopenharmony_ci &F2FS_OPTION(sbi).dummy_enc_policy; 50962306a36Sopenharmony_ci int err; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_FS_ENCRYPTION)) { 51262306a36Sopenharmony_ci f2fs_warn(sbi, "test_dummy_encryption option not supported"); 51362306a36Sopenharmony_ci return -EINVAL; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci if (!f2fs_sb_has_encrypt(sbi)) { 51762306a36Sopenharmony_ci f2fs_err(sbi, "Encrypt feature is off"); 51862306a36Sopenharmony_ci return -EINVAL; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* 52262306a36Sopenharmony_ci * This mount option is just for testing, and it's not worthwhile to 52362306a36Sopenharmony_ci * implement the extra complexity (e.g. RCU protection) that would be 52462306a36Sopenharmony_ci * needed to allow it to be set or changed during remount. We do allow 52562306a36Sopenharmony_ci * it to be specified during remount, but only if there is no change. 52662306a36Sopenharmony_ci */ 52762306a36Sopenharmony_ci if (is_remount && !fscrypt_is_dummy_policy_set(policy)) { 52862306a36Sopenharmony_ci f2fs_warn(sbi, "Can't set test_dummy_encryption on remount"); 52962306a36Sopenharmony_ci return -EINVAL; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci err = fscrypt_parse_test_dummy_encryption(¶m, policy); 53362306a36Sopenharmony_ci if (err) { 53462306a36Sopenharmony_ci if (err == -EEXIST) 53562306a36Sopenharmony_ci f2fs_warn(sbi, 53662306a36Sopenharmony_ci "Can't change test_dummy_encryption on remount"); 53762306a36Sopenharmony_ci else if (err == -EINVAL) 53862306a36Sopenharmony_ci f2fs_warn(sbi, "Value of option \"%s\" is unrecognized", 53962306a36Sopenharmony_ci opt); 54062306a36Sopenharmony_ci else 54162306a36Sopenharmony_ci f2fs_warn(sbi, "Error processing option \"%s\" [%d]", 54262306a36Sopenharmony_ci opt, err); 54362306a36Sopenharmony_ci return -EINVAL; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci f2fs_warn(sbi, "Test dummy encryption mode enabled"); 54662306a36Sopenharmony_ci return 0; 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION 55062306a36Sopenharmony_cistatic bool is_compress_extension_exist(struct f2fs_sb_info *sbi, 55162306a36Sopenharmony_ci const char *new_ext, bool is_ext) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci unsigned char (*ext)[F2FS_EXTENSION_LEN]; 55462306a36Sopenharmony_ci int ext_cnt; 55562306a36Sopenharmony_ci int i; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (is_ext) { 55862306a36Sopenharmony_ci ext = F2FS_OPTION(sbi).extensions; 55962306a36Sopenharmony_ci ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt; 56062306a36Sopenharmony_ci } else { 56162306a36Sopenharmony_ci ext = F2FS_OPTION(sbi).noextensions; 56262306a36Sopenharmony_ci ext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci for (i = 0; i < ext_cnt; i++) { 56662306a36Sopenharmony_ci if (!strcasecmp(new_ext, ext[i])) 56762306a36Sopenharmony_ci return true; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci return false; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci/* 57462306a36Sopenharmony_ci * 1. The same extension name cannot not appear in both compress and non-compress extension 57562306a36Sopenharmony_ci * at the same time. 57662306a36Sopenharmony_ci * 2. If the compress extension specifies all files, the types specified by the non-compress 57762306a36Sopenharmony_ci * extension will be treated as special cases and will not be compressed. 57862306a36Sopenharmony_ci * 3. Don't allow the non-compress extension specifies all files. 57962306a36Sopenharmony_ci */ 58062306a36Sopenharmony_cistatic int f2fs_test_compress_extension(struct f2fs_sb_info *sbi) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci unsigned char (*ext)[F2FS_EXTENSION_LEN]; 58362306a36Sopenharmony_ci unsigned char (*noext)[F2FS_EXTENSION_LEN]; 58462306a36Sopenharmony_ci int ext_cnt, noext_cnt, index = 0, no_index = 0; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci ext = F2FS_OPTION(sbi).extensions; 58762306a36Sopenharmony_ci ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt; 58862306a36Sopenharmony_ci noext = F2FS_OPTION(sbi).noextensions; 58962306a36Sopenharmony_ci noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (!noext_cnt) 59262306a36Sopenharmony_ci return 0; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci for (no_index = 0; no_index < noext_cnt; no_index++) { 59562306a36Sopenharmony_ci if (!strcasecmp("*", noext[no_index])) { 59662306a36Sopenharmony_ci f2fs_info(sbi, "Don't allow the nocompress extension specifies all files"); 59762306a36Sopenharmony_ci return -EINVAL; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci for (index = 0; index < ext_cnt; index++) { 60062306a36Sopenharmony_ci if (!strcasecmp(ext[index], noext[no_index])) { 60162306a36Sopenharmony_ci f2fs_info(sbi, "Don't allow the same extension %s appear in both compress and nocompress extension", 60262306a36Sopenharmony_ci ext[index]); 60362306a36Sopenharmony_ci return -EINVAL; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci return 0; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZ4 61162306a36Sopenharmony_cistatic int f2fs_set_lz4hc_level(struct f2fs_sb_info *sbi, const char *str) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZ4HC 61462306a36Sopenharmony_ci unsigned int level; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (strlen(str) == 3) { 61762306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_level = 0; 61862306a36Sopenharmony_ci return 0; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci str += 3; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (str[0] != ':') { 62462306a36Sopenharmony_ci f2fs_info(sbi, "wrong format, e.g. <alg_name>:<compr_level>"); 62562306a36Sopenharmony_ci return -EINVAL; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci if (kstrtouint(str + 1, 10, &level)) 62862306a36Sopenharmony_ci return -EINVAL; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (!f2fs_is_compress_level_valid(COMPRESS_LZ4, level)) { 63162306a36Sopenharmony_ci f2fs_info(sbi, "invalid lz4hc compress level: %d", level); 63262306a36Sopenharmony_ci return -EINVAL; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_level = level; 63662306a36Sopenharmony_ci return 0; 63762306a36Sopenharmony_ci#else 63862306a36Sopenharmony_ci if (strlen(str) == 3) { 63962306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_level = 0; 64062306a36Sopenharmony_ci return 0; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci f2fs_info(sbi, "kernel doesn't support lz4hc compression"); 64362306a36Sopenharmony_ci return -EINVAL; 64462306a36Sopenharmony_ci#endif 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci#endif 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_ZSTD 64962306a36Sopenharmony_cistatic int f2fs_set_zstd_level(struct f2fs_sb_info *sbi, const char *str) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci int level; 65262306a36Sopenharmony_ci int len = 4; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if (strlen(str) == len) { 65562306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_level = F2FS_ZSTD_DEFAULT_CLEVEL; 65662306a36Sopenharmony_ci return 0; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci str += len; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (str[0] != ':') { 66262306a36Sopenharmony_ci f2fs_info(sbi, "wrong format, e.g. <alg_name>:<compr_level>"); 66362306a36Sopenharmony_ci return -EINVAL; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci if (kstrtoint(str + 1, 10, &level)) 66662306a36Sopenharmony_ci return -EINVAL; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci /* f2fs does not support negative compress level now */ 66962306a36Sopenharmony_ci if (level < 0) { 67062306a36Sopenharmony_ci f2fs_info(sbi, "do not support negative compress level: %d", level); 67162306a36Sopenharmony_ci return -ERANGE; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (!f2fs_is_compress_level_valid(COMPRESS_ZSTD, level)) { 67562306a36Sopenharmony_ci f2fs_info(sbi, "invalid zstd compress level: %d", level); 67662306a36Sopenharmony_ci return -EINVAL; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_level = level; 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci#endif 68362306a36Sopenharmony_ci#endif 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic int parse_options(struct super_block *sb, char *options, bool is_remount) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 68862306a36Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 68962306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION 69062306a36Sopenharmony_ci unsigned char (*ext)[F2FS_EXTENSION_LEN]; 69162306a36Sopenharmony_ci unsigned char (*noext)[F2FS_EXTENSION_LEN]; 69262306a36Sopenharmony_ci int ext_cnt, noext_cnt; 69362306a36Sopenharmony_ci#endif 69462306a36Sopenharmony_ci char *p, *name; 69562306a36Sopenharmony_ci int arg = 0; 69662306a36Sopenharmony_ci kuid_t uid; 69762306a36Sopenharmony_ci kgid_t gid; 69862306a36Sopenharmony_ci int ret; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci if (!options) 70162306a36Sopenharmony_ci goto default_check; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci while ((p = strsep(&options, ",")) != NULL) { 70462306a36Sopenharmony_ci int token; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (!*p) 70762306a36Sopenharmony_ci continue; 70862306a36Sopenharmony_ci /* 70962306a36Sopenharmony_ci * Initialize args struct so we know whether arg was 71062306a36Sopenharmony_ci * found; some options take optional arguments. 71162306a36Sopenharmony_ci */ 71262306a36Sopenharmony_ci args[0].to = args[0].from = NULL; 71362306a36Sopenharmony_ci token = match_token(p, f2fs_tokens, args); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci switch (token) { 71662306a36Sopenharmony_ci case Opt_gc_background: 71762306a36Sopenharmony_ci name = match_strdup(&args[0]); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci if (!name) 72062306a36Sopenharmony_ci return -ENOMEM; 72162306a36Sopenharmony_ci if (!strcmp(name, "on")) { 72262306a36Sopenharmony_ci F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_ON; 72362306a36Sopenharmony_ci } else if (!strcmp(name, "off")) { 72462306a36Sopenharmony_ci F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_OFF; 72562306a36Sopenharmony_ci } else if (!strcmp(name, "sync")) { 72662306a36Sopenharmony_ci F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_SYNC; 72762306a36Sopenharmony_ci } else { 72862306a36Sopenharmony_ci kfree(name); 72962306a36Sopenharmony_ci return -EINVAL; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci kfree(name); 73262306a36Sopenharmony_ci break; 73362306a36Sopenharmony_ci case Opt_disable_roll_forward: 73462306a36Sopenharmony_ci set_opt(sbi, DISABLE_ROLL_FORWARD); 73562306a36Sopenharmony_ci break; 73662306a36Sopenharmony_ci case Opt_norecovery: 73762306a36Sopenharmony_ci /* this option mounts f2fs with ro */ 73862306a36Sopenharmony_ci set_opt(sbi, NORECOVERY); 73962306a36Sopenharmony_ci if (!f2fs_readonly(sb)) 74062306a36Sopenharmony_ci return -EINVAL; 74162306a36Sopenharmony_ci break; 74262306a36Sopenharmony_ci case Opt_discard: 74362306a36Sopenharmony_ci if (!f2fs_hw_support_discard(sbi)) { 74462306a36Sopenharmony_ci f2fs_warn(sbi, "device does not support discard"); 74562306a36Sopenharmony_ci break; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci set_opt(sbi, DISCARD); 74862306a36Sopenharmony_ci break; 74962306a36Sopenharmony_ci case Opt_nodiscard: 75062306a36Sopenharmony_ci if (f2fs_hw_should_discard(sbi)) { 75162306a36Sopenharmony_ci f2fs_warn(sbi, "discard is required for zoned block devices"); 75262306a36Sopenharmony_ci return -EINVAL; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci clear_opt(sbi, DISCARD); 75562306a36Sopenharmony_ci break; 75662306a36Sopenharmony_ci case Opt_noheap: 75762306a36Sopenharmony_ci set_opt(sbi, NOHEAP); 75862306a36Sopenharmony_ci break; 75962306a36Sopenharmony_ci case Opt_heap: 76062306a36Sopenharmony_ci clear_opt(sbi, NOHEAP); 76162306a36Sopenharmony_ci break; 76262306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_XATTR 76362306a36Sopenharmony_ci case Opt_user_xattr: 76462306a36Sopenharmony_ci set_opt(sbi, XATTR_USER); 76562306a36Sopenharmony_ci break; 76662306a36Sopenharmony_ci case Opt_nouser_xattr: 76762306a36Sopenharmony_ci clear_opt(sbi, XATTR_USER); 76862306a36Sopenharmony_ci break; 76962306a36Sopenharmony_ci case Opt_inline_xattr: 77062306a36Sopenharmony_ci set_opt(sbi, INLINE_XATTR); 77162306a36Sopenharmony_ci break; 77262306a36Sopenharmony_ci case Opt_noinline_xattr: 77362306a36Sopenharmony_ci clear_opt(sbi, INLINE_XATTR); 77462306a36Sopenharmony_ci break; 77562306a36Sopenharmony_ci case Opt_inline_xattr_size: 77662306a36Sopenharmony_ci if (args->from && match_int(args, &arg)) 77762306a36Sopenharmony_ci return -EINVAL; 77862306a36Sopenharmony_ci set_opt(sbi, INLINE_XATTR_SIZE); 77962306a36Sopenharmony_ci F2FS_OPTION(sbi).inline_xattr_size = arg; 78062306a36Sopenharmony_ci break; 78162306a36Sopenharmony_ci#else 78262306a36Sopenharmony_ci case Opt_user_xattr: 78362306a36Sopenharmony_ci f2fs_info(sbi, "user_xattr options not supported"); 78462306a36Sopenharmony_ci break; 78562306a36Sopenharmony_ci case Opt_nouser_xattr: 78662306a36Sopenharmony_ci f2fs_info(sbi, "nouser_xattr options not supported"); 78762306a36Sopenharmony_ci break; 78862306a36Sopenharmony_ci case Opt_inline_xattr: 78962306a36Sopenharmony_ci f2fs_info(sbi, "inline_xattr options not supported"); 79062306a36Sopenharmony_ci break; 79162306a36Sopenharmony_ci case Opt_noinline_xattr: 79262306a36Sopenharmony_ci f2fs_info(sbi, "noinline_xattr options not supported"); 79362306a36Sopenharmony_ci break; 79462306a36Sopenharmony_ci#endif 79562306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_POSIX_ACL 79662306a36Sopenharmony_ci case Opt_acl: 79762306a36Sopenharmony_ci set_opt(sbi, POSIX_ACL); 79862306a36Sopenharmony_ci break; 79962306a36Sopenharmony_ci case Opt_noacl: 80062306a36Sopenharmony_ci clear_opt(sbi, POSIX_ACL); 80162306a36Sopenharmony_ci break; 80262306a36Sopenharmony_ci#else 80362306a36Sopenharmony_ci case Opt_acl: 80462306a36Sopenharmony_ci f2fs_info(sbi, "acl options not supported"); 80562306a36Sopenharmony_ci break; 80662306a36Sopenharmony_ci case Opt_noacl: 80762306a36Sopenharmony_ci f2fs_info(sbi, "noacl options not supported"); 80862306a36Sopenharmony_ci break; 80962306a36Sopenharmony_ci#endif 81062306a36Sopenharmony_ci case Opt_active_logs: 81162306a36Sopenharmony_ci if (args->from && match_int(args, &arg)) 81262306a36Sopenharmony_ci return -EINVAL; 81362306a36Sopenharmony_ci if (arg != 2 && arg != 4 && 81462306a36Sopenharmony_ci arg != NR_CURSEG_PERSIST_TYPE) 81562306a36Sopenharmony_ci return -EINVAL; 81662306a36Sopenharmony_ci F2FS_OPTION(sbi).active_logs = arg; 81762306a36Sopenharmony_ci break; 81862306a36Sopenharmony_ci case Opt_disable_ext_identify: 81962306a36Sopenharmony_ci set_opt(sbi, DISABLE_EXT_IDENTIFY); 82062306a36Sopenharmony_ci break; 82162306a36Sopenharmony_ci case Opt_inline_data: 82262306a36Sopenharmony_ci set_opt(sbi, INLINE_DATA); 82362306a36Sopenharmony_ci break; 82462306a36Sopenharmony_ci case Opt_inline_dentry: 82562306a36Sopenharmony_ci set_opt(sbi, INLINE_DENTRY); 82662306a36Sopenharmony_ci break; 82762306a36Sopenharmony_ci case Opt_noinline_dentry: 82862306a36Sopenharmony_ci clear_opt(sbi, INLINE_DENTRY); 82962306a36Sopenharmony_ci break; 83062306a36Sopenharmony_ci case Opt_flush_merge: 83162306a36Sopenharmony_ci set_opt(sbi, FLUSH_MERGE); 83262306a36Sopenharmony_ci break; 83362306a36Sopenharmony_ci case Opt_noflush_merge: 83462306a36Sopenharmony_ci clear_opt(sbi, FLUSH_MERGE); 83562306a36Sopenharmony_ci break; 83662306a36Sopenharmony_ci case Opt_nobarrier: 83762306a36Sopenharmony_ci set_opt(sbi, NOBARRIER); 83862306a36Sopenharmony_ci break; 83962306a36Sopenharmony_ci case Opt_barrier: 84062306a36Sopenharmony_ci clear_opt(sbi, NOBARRIER); 84162306a36Sopenharmony_ci break; 84262306a36Sopenharmony_ci case Opt_fastboot: 84362306a36Sopenharmony_ci set_opt(sbi, FASTBOOT); 84462306a36Sopenharmony_ci break; 84562306a36Sopenharmony_ci case Opt_extent_cache: 84662306a36Sopenharmony_ci set_opt(sbi, READ_EXTENT_CACHE); 84762306a36Sopenharmony_ci break; 84862306a36Sopenharmony_ci case Opt_noextent_cache: 84962306a36Sopenharmony_ci clear_opt(sbi, READ_EXTENT_CACHE); 85062306a36Sopenharmony_ci break; 85162306a36Sopenharmony_ci case Opt_noinline_data: 85262306a36Sopenharmony_ci clear_opt(sbi, INLINE_DATA); 85362306a36Sopenharmony_ci break; 85462306a36Sopenharmony_ci case Opt_data_flush: 85562306a36Sopenharmony_ci set_opt(sbi, DATA_FLUSH); 85662306a36Sopenharmony_ci break; 85762306a36Sopenharmony_ci case Opt_reserve_root: 85862306a36Sopenharmony_ci if (args->from && match_int(args, &arg)) 85962306a36Sopenharmony_ci return -EINVAL; 86062306a36Sopenharmony_ci if (test_opt(sbi, RESERVE_ROOT)) { 86162306a36Sopenharmony_ci f2fs_info(sbi, "Preserve previous reserve_root=%u", 86262306a36Sopenharmony_ci F2FS_OPTION(sbi).root_reserved_blocks); 86362306a36Sopenharmony_ci } else { 86462306a36Sopenharmony_ci F2FS_OPTION(sbi).root_reserved_blocks = arg; 86562306a36Sopenharmony_ci set_opt(sbi, RESERVE_ROOT); 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci break; 86862306a36Sopenharmony_ci case Opt_resuid: 86962306a36Sopenharmony_ci if (args->from && match_int(args, &arg)) 87062306a36Sopenharmony_ci return -EINVAL; 87162306a36Sopenharmony_ci uid = make_kuid(current_user_ns(), arg); 87262306a36Sopenharmony_ci if (!uid_valid(uid)) { 87362306a36Sopenharmony_ci f2fs_err(sbi, "Invalid uid value %d", arg); 87462306a36Sopenharmony_ci return -EINVAL; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci F2FS_OPTION(sbi).s_resuid = uid; 87762306a36Sopenharmony_ci break; 87862306a36Sopenharmony_ci case Opt_resgid: 87962306a36Sopenharmony_ci if (args->from && match_int(args, &arg)) 88062306a36Sopenharmony_ci return -EINVAL; 88162306a36Sopenharmony_ci gid = make_kgid(current_user_ns(), arg); 88262306a36Sopenharmony_ci if (!gid_valid(gid)) { 88362306a36Sopenharmony_ci f2fs_err(sbi, "Invalid gid value %d", arg); 88462306a36Sopenharmony_ci return -EINVAL; 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci F2FS_OPTION(sbi).s_resgid = gid; 88762306a36Sopenharmony_ci break; 88862306a36Sopenharmony_ci case Opt_mode: 88962306a36Sopenharmony_ci name = match_strdup(&args[0]); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci if (!name) 89262306a36Sopenharmony_ci return -ENOMEM; 89362306a36Sopenharmony_ci if (!strcmp(name, "adaptive")) { 89462306a36Sopenharmony_ci F2FS_OPTION(sbi).fs_mode = FS_MODE_ADAPTIVE; 89562306a36Sopenharmony_ci } else if (!strcmp(name, "lfs")) { 89662306a36Sopenharmony_ci F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS; 89762306a36Sopenharmony_ci } else if (!strcmp(name, "fragment:segment")) { 89862306a36Sopenharmony_ci F2FS_OPTION(sbi).fs_mode = FS_MODE_FRAGMENT_SEG; 89962306a36Sopenharmony_ci } else if (!strcmp(name, "fragment:block")) { 90062306a36Sopenharmony_ci F2FS_OPTION(sbi).fs_mode = FS_MODE_FRAGMENT_BLK; 90162306a36Sopenharmony_ci } else { 90262306a36Sopenharmony_ci kfree(name); 90362306a36Sopenharmony_ci return -EINVAL; 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci kfree(name); 90662306a36Sopenharmony_ci break; 90762306a36Sopenharmony_ci case Opt_io_size_bits: 90862306a36Sopenharmony_ci if (args->from && match_int(args, &arg)) 90962306a36Sopenharmony_ci return -EINVAL; 91062306a36Sopenharmony_ci if (arg <= 0 || arg > __ilog2_u32(BIO_MAX_VECS)) { 91162306a36Sopenharmony_ci f2fs_warn(sbi, "Not support %ld, larger than %d", 91262306a36Sopenharmony_ci BIT(arg), BIO_MAX_VECS); 91362306a36Sopenharmony_ci return -EINVAL; 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci F2FS_OPTION(sbi).write_io_size_bits = arg; 91662306a36Sopenharmony_ci break; 91762306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FAULT_INJECTION 91862306a36Sopenharmony_ci case Opt_fault_injection: 91962306a36Sopenharmony_ci if (args->from && match_int(args, &arg)) 92062306a36Sopenharmony_ci return -EINVAL; 92162306a36Sopenharmony_ci f2fs_build_fault_attr(sbi, arg, F2FS_ALL_FAULT_TYPE); 92262306a36Sopenharmony_ci set_opt(sbi, FAULT_INJECTION); 92362306a36Sopenharmony_ci break; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci case Opt_fault_type: 92662306a36Sopenharmony_ci if (args->from && match_int(args, &arg)) 92762306a36Sopenharmony_ci return -EINVAL; 92862306a36Sopenharmony_ci f2fs_build_fault_attr(sbi, 0, arg); 92962306a36Sopenharmony_ci set_opt(sbi, FAULT_INJECTION); 93062306a36Sopenharmony_ci break; 93162306a36Sopenharmony_ci#else 93262306a36Sopenharmony_ci case Opt_fault_injection: 93362306a36Sopenharmony_ci f2fs_info(sbi, "fault_injection options not supported"); 93462306a36Sopenharmony_ci break; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci case Opt_fault_type: 93762306a36Sopenharmony_ci f2fs_info(sbi, "fault_type options not supported"); 93862306a36Sopenharmony_ci break; 93962306a36Sopenharmony_ci#endif 94062306a36Sopenharmony_ci case Opt_lazytime: 94162306a36Sopenharmony_ci sb->s_flags |= SB_LAZYTIME; 94262306a36Sopenharmony_ci break; 94362306a36Sopenharmony_ci case Opt_nolazytime: 94462306a36Sopenharmony_ci sb->s_flags &= ~SB_LAZYTIME; 94562306a36Sopenharmony_ci break; 94662306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 94762306a36Sopenharmony_ci case Opt_quota: 94862306a36Sopenharmony_ci case Opt_usrquota: 94962306a36Sopenharmony_ci set_opt(sbi, USRQUOTA); 95062306a36Sopenharmony_ci break; 95162306a36Sopenharmony_ci case Opt_grpquota: 95262306a36Sopenharmony_ci set_opt(sbi, GRPQUOTA); 95362306a36Sopenharmony_ci break; 95462306a36Sopenharmony_ci case Opt_prjquota: 95562306a36Sopenharmony_ci set_opt(sbi, PRJQUOTA); 95662306a36Sopenharmony_ci break; 95762306a36Sopenharmony_ci case Opt_usrjquota: 95862306a36Sopenharmony_ci ret = f2fs_set_qf_name(sb, USRQUOTA, &args[0]); 95962306a36Sopenharmony_ci if (ret) 96062306a36Sopenharmony_ci return ret; 96162306a36Sopenharmony_ci break; 96262306a36Sopenharmony_ci case Opt_grpjquota: 96362306a36Sopenharmony_ci ret = f2fs_set_qf_name(sb, GRPQUOTA, &args[0]); 96462306a36Sopenharmony_ci if (ret) 96562306a36Sopenharmony_ci return ret; 96662306a36Sopenharmony_ci break; 96762306a36Sopenharmony_ci case Opt_prjjquota: 96862306a36Sopenharmony_ci ret = f2fs_set_qf_name(sb, PRJQUOTA, &args[0]); 96962306a36Sopenharmony_ci if (ret) 97062306a36Sopenharmony_ci return ret; 97162306a36Sopenharmony_ci break; 97262306a36Sopenharmony_ci case Opt_offusrjquota: 97362306a36Sopenharmony_ci ret = f2fs_clear_qf_name(sb, USRQUOTA); 97462306a36Sopenharmony_ci if (ret) 97562306a36Sopenharmony_ci return ret; 97662306a36Sopenharmony_ci break; 97762306a36Sopenharmony_ci case Opt_offgrpjquota: 97862306a36Sopenharmony_ci ret = f2fs_clear_qf_name(sb, GRPQUOTA); 97962306a36Sopenharmony_ci if (ret) 98062306a36Sopenharmony_ci return ret; 98162306a36Sopenharmony_ci break; 98262306a36Sopenharmony_ci case Opt_offprjjquota: 98362306a36Sopenharmony_ci ret = f2fs_clear_qf_name(sb, PRJQUOTA); 98462306a36Sopenharmony_ci if (ret) 98562306a36Sopenharmony_ci return ret; 98662306a36Sopenharmony_ci break; 98762306a36Sopenharmony_ci case Opt_jqfmt_vfsold: 98862306a36Sopenharmony_ci F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_OLD; 98962306a36Sopenharmony_ci break; 99062306a36Sopenharmony_ci case Opt_jqfmt_vfsv0: 99162306a36Sopenharmony_ci F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_V0; 99262306a36Sopenharmony_ci break; 99362306a36Sopenharmony_ci case Opt_jqfmt_vfsv1: 99462306a36Sopenharmony_ci F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_V1; 99562306a36Sopenharmony_ci break; 99662306a36Sopenharmony_ci case Opt_noquota: 99762306a36Sopenharmony_ci clear_opt(sbi, QUOTA); 99862306a36Sopenharmony_ci clear_opt(sbi, USRQUOTA); 99962306a36Sopenharmony_ci clear_opt(sbi, GRPQUOTA); 100062306a36Sopenharmony_ci clear_opt(sbi, PRJQUOTA); 100162306a36Sopenharmony_ci break; 100262306a36Sopenharmony_ci#else 100362306a36Sopenharmony_ci case Opt_quota: 100462306a36Sopenharmony_ci case Opt_usrquota: 100562306a36Sopenharmony_ci case Opt_grpquota: 100662306a36Sopenharmony_ci case Opt_prjquota: 100762306a36Sopenharmony_ci case Opt_usrjquota: 100862306a36Sopenharmony_ci case Opt_grpjquota: 100962306a36Sopenharmony_ci case Opt_prjjquota: 101062306a36Sopenharmony_ci case Opt_offusrjquota: 101162306a36Sopenharmony_ci case Opt_offgrpjquota: 101262306a36Sopenharmony_ci case Opt_offprjjquota: 101362306a36Sopenharmony_ci case Opt_jqfmt_vfsold: 101462306a36Sopenharmony_ci case Opt_jqfmt_vfsv0: 101562306a36Sopenharmony_ci case Opt_jqfmt_vfsv1: 101662306a36Sopenharmony_ci case Opt_noquota: 101762306a36Sopenharmony_ci f2fs_info(sbi, "quota operations not supported"); 101862306a36Sopenharmony_ci break; 101962306a36Sopenharmony_ci#endif 102062306a36Sopenharmony_ci case Opt_alloc: 102162306a36Sopenharmony_ci name = match_strdup(&args[0]); 102262306a36Sopenharmony_ci if (!name) 102362306a36Sopenharmony_ci return -ENOMEM; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci if (!strcmp(name, "default")) { 102662306a36Sopenharmony_ci F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT; 102762306a36Sopenharmony_ci } else if (!strcmp(name, "reuse")) { 102862306a36Sopenharmony_ci F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE; 102962306a36Sopenharmony_ci } else { 103062306a36Sopenharmony_ci kfree(name); 103162306a36Sopenharmony_ci return -EINVAL; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci kfree(name); 103462306a36Sopenharmony_ci break; 103562306a36Sopenharmony_ci case Opt_fsync: 103662306a36Sopenharmony_ci name = match_strdup(&args[0]); 103762306a36Sopenharmony_ci if (!name) 103862306a36Sopenharmony_ci return -ENOMEM; 103962306a36Sopenharmony_ci if (!strcmp(name, "posix")) { 104062306a36Sopenharmony_ci F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX; 104162306a36Sopenharmony_ci } else if (!strcmp(name, "strict")) { 104262306a36Sopenharmony_ci F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_STRICT; 104362306a36Sopenharmony_ci } else if (!strcmp(name, "nobarrier")) { 104462306a36Sopenharmony_ci F2FS_OPTION(sbi).fsync_mode = 104562306a36Sopenharmony_ci FSYNC_MODE_NOBARRIER; 104662306a36Sopenharmony_ci } else { 104762306a36Sopenharmony_ci kfree(name); 104862306a36Sopenharmony_ci return -EINVAL; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci kfree(name); 105162306a36Sopenharmony_ci break; 105262306a36Sopenharmony_ci case Opt_test_dummy_encryption: 105362306a36Sopenharmony_ci ret = f2fs_set_test_dummy_encryption(sb, p, &args[0], 105462306a36Sopenharmony_ci is_remount); 105562306a36Sopenharmony_ci if (ret) 105662306a36Sopenharmony_ci return ret; 105762306a36Sopenharmony_ci break; 105862306a36Sopenharmony_ci case Opt_inlinecrypt: 105962306a36Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT 106062306a36Sopenharmony_ci sb->s_flags |= SB_INLINECRYPT; 106162306a36Sopenharmony_ci#else 106262306a36Sopenharmony_ci f2fs_info(sbi, "inline encryption not supported"); 106362306a36Sopenharmony_ci#endif 106462306a36Sopenharmony_ci break; 106562306a36Sopenharmony_ci case Opt_checkpoint_disable_cap_perc: 106662306a36Sopenharmony_ci if (args->from && match_int(args, &arg)) 106762306a36Sopenharmony_ci return -EINVAL; 106862306a36Sopenharmony_ci if (arg < 0 || arg > 100) 106962306a36Sopenharmony_ci return -EINVAL; 107062306a36Sopenharmony_ci F2FS_OPTION(sbi).unusable_cap_perc = arg; 107162306a36Sopenharmony_ci set_opt(sbi, DISABLE_CHECKPOINT); 107262306a36Sopenharmony_ci break; 107362306a36Sopenharmony_ci case Opt_checkpoint_disable_cap: 107462306a36Sopenharmony_ci if (args->from && match_int(args, &arg)) 107562306a36Sopenharmony_ci return -EINVAL; 107662306a36Sopenharmony_ci F2FS_OPTION(sbi).unusable_cap = arg; 107762306a36Sopenharmony_ci set_opt(sbi, DISABLE_CHECKPOINT); 107862306a36Sopenharmony_ci break; 107962306a36Sopenharmony_ci case Opt_checkpoint_disable: 108062306a36Sopenharmony_ci set_opt(sbi, DISABLE_CHECKPOINT); 108162306a36Sopenharmony_ci break; 108262306a36Sopenharmony_ci case Opt_checkpoint_enable: 108362306a36Sopenharmony_ci clear_opt(sbi, DISABLE_CHECKPOINT); 108462306a36Sopenharmony_ci break; 108562306a36Sopenharmony_ci case Opt_checkpoint_merge: 108662306a36Sopenharmony_ci set_opt(sbi, MERGE_CHECKPOINT); 108762306a36Sopenharmony_ci break; 108862306a36Sopenharmony_ci case Opt_nocheckpoint_merge: 108962306a36Sopenharmony_ci clear_opt(sbi, MERGE_CHECKPOINT); 109062306a36Sopenharmony_ci break; 109162306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION 109262306a36Sopenharmony_ci case Opt_compress_algorithm: 109362306a36Sopenharmony_ci if (!f2fs_sb_has_compression(sbi)) { 109462306a36Sopenharmony_ci f2fs_info(sbi, "Image doesn't support compression"); 109562306a36Sopenharmony_ci break; 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci name = match_strdup(&args[0]); 109862306a36Sopenharmony_ci if (!name) 109962306a36Sopenharmony_ci return -ENOMEM; 110062306a36Sopenharmony_ci if (!strcmp(name, "lzo")) { 110162306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZO 110262306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_level = 0; 110362306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_algorithm = 110462306a36Sopenharmony_ci COMPRESS_LZO; 110562306a36Sopenharmony_ci#else 110662306a36Sopenharmony_ci f2fs_info(sbi, "kernel doesn't support lzo compression"); 110762306a36Sopenharmony_ci#endif 110862306a36Sopenharmony_ci } else if (!strncmp(name, "lz4", 3)) { 110962306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZ4 111062306a36Sopenharmony_ci ret = f2fs_set_lz4hc_level(sbi, name); 111162306a36Sopenharmony_ci if (ret) { 111262306a36Sopenharmony_ci kfree(name); 111362306a36Sopenharmony_ci return -EINVAL; 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_algorithm = 111662306a36Sopenharmony_ci COMPRESS_LZ4; 111762306a36Sopenharmony_ci#else 111862306a36Sopenharmony_ci f2fs_info(sbi, "kernel doesn't support lz4 compression"); 111962306a36Sopenharmony_ci#endif 112062306a36Sopenharmony_ci } else if (!strncmp(name, "zstd", 4)) { 112162306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_ZSTD 112262306a36Sopenharmony_ci ret = f2fs_set_zstd_level(sbi, name); 112362306a36Sopenharmony_ci if (ret) { 112462306a36Sopenharmony_ci kfree(name); 112562306a36Sopenharmony_ci return -EINVAL; 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_algorithm = 112862306a36Sopenharmony_ci COMPRESS_ZSTD; 112962306a36Sopenharmony_ci#else 113062306a36Sopenharmony_ci f2fs_info(sbi, "kernel doesn't support zstd compression"); 113162306a36Sopenharmony_ci#endif 113262306a36Sopenharmony_ci } else if (!strcmp(name, "lzo-rle")) { 113362306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZORLE 113462306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_level = 0; 113562306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_algorithm = 113662306a36Sopenharmony_ci COMPRESS_LZORLE; 113762306a36Sopenharmony_ci#else 113862306a36Sopenharmony_ci f2fs_info(sbi, "kernel doesn't support lzorle compression"); 113962306a36Sopenharmony_ci#endif 114062306a36Sopenharmony_ci } else { 114162306a36Sopenharmony_ci kfree(name); 114262306a36Sopenharmony_ci return -EINVAL; 114362306a36Sopenharmony_ci } 114462306a36Sopenharmony_ci kfree(name); 114562306a36Sopenharmony_ci break; 114662306a36Sopenharmony_ci case Opt_compress_log_size: 114762306a36Sopenharmony_ci if (!f2fs_sb_has_compression(sbi)) { 114862306a36Sopenharmony_ci f2fs_info(sbi, "Image doesn't support compression"); 114962306a36Sopenharmony_ci break; 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci if (args->from && match_int(args, &arg)) 115262306a36Sopenharmony_ci return -EINVAL; 115362306a36Sopenharmony_ci if (arg < MIN_COMPRESS_LOG_SIZE || 115462306a36Sopenharmony_ci arg > MAX_COMPRESS_LOG_SIZE) { 115562306a36Sopenharmony_ci f2fs_err(sbi, 115662306a36Sopenharmony_ci "Compress cluster log size is out of range"); 115762306a36Sopenharmony_ci return -EINVAL; 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_log_size = arg; 116062306a36Sopenharmony_ci break; 116162306a36Sopenharmony_ci case Opt_compress_extension: 116262306a36Sopenharmony_ci if (!f2fs_sb_has_compression(sbi)) { 116362306a36Sopenharmony_ci f2fs_info(sbi, "Image doesn't support compression"); 116462306a36Sopenharmony_ci break; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci name = match_strdup(&args[0]); 116762306a36Sopenharmony_ci if (!name) 116862306a36Sopenharmony_ci return -ENOMEM; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci ext = F2FS_OPTION(sbi).extensions; 117162306a36Sopenharmony_ci ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci if (strlen(name) >= F2FS_EXTENSION_LEN || 117462306a36Sopenharmony_ci ext_cnt >= COMPRESS_EXT_NUM) { 117562306a36Sopenharmony_ci f2fs_err(sbi, 117662306a36Sopenharmony_ci "invalid extension length/number"); 117762306a36Sopenharmony_ci kfree(name); 117862306a36Sopenharmony_ci return -EINVAL; 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci if (is_compress_extension_exist(sbi, name, true)) { 118262306a36Sopenharmony_ci kfree(name); 118362306a36Sopenharmony_ci break; 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci strcpy(ext[ext_cnt], name); 118762306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_ext_cnt++; 118862306a36Sopenharmony_ci kfree(name); 118962306a36Sopenharmony_ci break; 119062306a36Sopenharmony_ci case Opt_nocompress_extension: 119162306a36Sopenharmony_ci if (!f2fs_sb_has_compression(sbi)) { 119262306a36Sopenharmony_ci f2fs_info(sbi, "Image doesn't support compression"); 119362306a36Sopenharmony_ci break; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci name = match_strdup(&args[0]); 119662306a36Sopenharmony_ci if (!name) 119762306a36Sopenharmony_ci return -ENOMEM; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci noext = F2FS_OPTION(sbi).noextensions; 120062306a36Sopenharmony_ci noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci if (strlen(name) >= F2FS_EXTENSION_LEN || 120362306a36Sopenharmony_ci noext_cnt >= COMPRESS_EXT_NUM) { 120462306a36Sopenharmony_ci f2fs_err(sbi, 120562306a36Sopenharmony_ci "invalid extension length/number"); 120662306a36Sopenharmony_ci kfree(name); 120762306a36Sopenharmony_ci return -EINVAL; 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci if (is_compress_extension_exist(sbi, name, false)) { 121162306a36Sopenharmony_ci kfree(name); 121262306a36Sopenharmony_ci break; 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci strcpy(noext[noext_cnt], name); 121662306a36Sopenharmony_ci F2FS_OPTION(sbi).nocompress_ext_cnt++; 121762306a36Sopenharmony_ci kfree(name); 121862306a36Sopenharmony_ci break; 121962306a36Sopenharmony_ci case Opt_compress_chksum: 122062306a36Sopenharmony_ci if (!f2fs_sb_has_compression(sbi)) { 122162306a36Sopenharmony_ci f2fs_info(sbi, "Image doesn't support compression"); 122262306a36Sopenharmony_ci break; 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_chksum = true; 122562306a36Sopenharmony_ci break; 122662306a36Sopenharmony_ci case Opt_compress_mode: 122762306a36Sopenharmony_ci if (!f2fs_sb_has_compression(sbi)) { 122862306a36Sopenharmony_ci f2fs_info(sbi, "Image doesn't support compression"); 122962306a36Sopenharmony_ci break; 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci name = match_strdup(&args[0]); 123262306a36Sopenharmony_ci if (!name) 123362306a36Sopenharmony_ci return -ENOMEM; 123462306a36Sopenharmony_ci if (!strcmp(name, "fs")) { 123562306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_mode = COMPR_MODE_FS; 123662306a36Sopenharmony_ci } else if (!strcmp(name, "user")) { 123762306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_mode = COMPR_MODE_USER; 123862306a36Sopenharmony_ci } else { 123962306a36Sopenharmony_ci kfree(name); 124062306a36Sopenharmony_ci return -EINVAL; 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci kfree(name); 124362306a36Sopenharmony_ci break; 124462306a36Sopenharmony_ci case Opt_compress_cache: 124562306a36Sopenharmony_ci if (!f2fs_sb_has_compression(sbi)) { 124662306a36Sopenharmony_ci f2fs_info(sbi, "Image doesn't support compression"); 124762306a36Sopenharmony_ci break; 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci set_opt(sbi, COMPRESS_CACHE); 125062306a36Sopenharmony_ci break; 125162306a36Sopenharmony_ci#else 125262306a36Sopenharmony_ci case Opt_compress_algorithm: 125362306a36Sopenharmony_ci case Opt_compress_log_size: 125462306a36Sopenharmony_ci case Opt_compress_extension: 125562306a36Sopenharmony_ci case Opt_nocompress_extension: 125662306a36Sopenharmony_ci case Opt_compress_chksum: 125762306a36Sopenharmony_ci case Opt_compress_mode: 125862306a36Sopenharmony_ci case Opt_compress_cache: 125962306a36Sopenharmony_ci f2fs_info(sbi, "compression options not supported"); 126062306a36Sopenharmony_ci break; 126162306a36Sopenharmony_ci#endif 126262306a36Sopenharmony_ci case Opt_atgc: 126362306a36Sopenharmony_ci set_opt(sbi, ATGC); 126462306a36Sopenharmony_ci break; 126562306a36Sopenharmony_ci case Opt_gc_merge: 126662306a36Sopenharmony_ci set_opt(sbi, GC_MERGE); 126762306a36Sopenharmony_ci break; 126862306a36Sopenharmony_ci case Opt_nogc_merge: 126962306a36Sopenharmony_ci clear_opt(sbi, GC_MERGE); 127062306a36Sopenharmony_ci break; 127162306a36Sopenharmony_ci case Opt_discard_unit: 127262306a36Sopenharmony_ci name = match_strdup(&args[0]); 127362306a36Sopenharmony_ci if (!name) 127462306a36Sopenharmony_ci return -ENOMEM; 127562306a36Sopenharmony_ci if (!strcmp(name, "block")) { 127662306a36Sopenharmony_ci F2FS_OPTION(sbi).discard_unit = 127762306a36Sopenharmony_ci DISCARD_UNIT_BLOCK; 127862306a36Sopenharmony_ci } else if (!strcmp(name, "segment")) { 127962306a36Sopenharmony_ci F2FS_OPTION(sbi).discard_unit = 128062306a36Sopenharmony_ci DISCARD_UNIT_SEGMENT; 128162306a36Sopenharmony_ci } else if (!strcmp(name, "section")) { 128262306a36Sopenharmony_ci F2FS_OPTION(sbi).discard_unit = 128362306a36Sopenharmony_ci DISCARD_UNIT_SECTION; 128462306a36Sopenharmony_ci } else { 128562306a36Sopenharmony_ci kfree(name); 128662306a36Sopenharmony_ci return -EINVAL; 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci kfree(name); 128962306a36Sopenharmony_ci break; 129062306a36Sopenharmony_ci case Opt_memory_mode: 129162306a36Sopenharmony_ci name = match_strdup(&args[0]); 129262306a36Sopenharmony_ci if (!name) 129362306a36Sopenharmony_ci return -ENOMEM; 129462306a36Sopenharmony_ci if (!strcmp(name, "normal")) { 129562306a36Sopenharmony_ci F2FS_OPTION(sbi).memory_mode = 129662306a36Sopenharmony_ci MEMORY_MODE_NORMAL; 129762306a36Sopenharmony_ci } else if (!strcmp(name, "low")) { 129862306a36Sopenharmony_ci F2FS_OPTION(sbi).memory_mode = 129962306a36Sopenharmony_ci MEMORY_MODE_LOW; 130062306a36Sopenharmony_ci } else { 130162306a36Sopenharmony_ci kfree(name); 130262306a36Sopenharmony_ci return -EINVAL; 130362306a36Sopenharmony_ci } 130462306a36Sopenharmony_ci kfree(name); 130562306a36Sopenharmony_ci break; 130662306a36Sopenharmony_ci case Opt_age_extent_cache: 130762306a36Sopenharmony_ci set_opt(sbi, AGE_EXTENT_CACHE); 130862306a36Sopenharmony_ci break; 130962306a36Sopenharmony_ci case Opt_errors: 131062306a36Sopenharmony_ci name = match_strdup(&args[0]); 131162306a36Sopenharmony_ci if (!name) 131262306a36Sopenharmony_ci return -ENOMEM; 131362306a36Sopenharmony_ci if (!strcmp(name, "remount-ro")) { 131462306a36Sopenharmony_ci F2FS_OPTION(sbi).errors = 131562306a36Sopenharmony_ci MOUNT_ERRORS_READONLY; 131662306a36Sopenharmony_ci } else if (!strcmp(name, "continue")) { 131762306a36Sopenharmony_ci F2FS_OPTION(sbi).errors = 131862306a36Sopenharmony_ci MOUNT_ERRORS_CONTINUE; 131962306a36Sopenharmony_ci } else if (!strcmp(name, "panic")) { 132062306a36Sopenharmony_ci F2FS_OPTION(sbi).errors = 132162306a36Sopenharmony_ci MOUNT_ERRORS_PANIC; 132262306a36Sopenharmony_ci } else { 132362306a36Sopenharmony_ci kfree(name); 132462306a36Sopenharmony_ci return -EINVAL; 132562306a36Sopenharmony_ci } 132662306a36Sopenharmony_ci kfree(name); 132762306a36Sopenharmony_ci break; 132862306a36Sopenharmony_ci default: 132962306a36Sopenharmony_ci f2fs_err(sbi, "Unrecognized mount option \"%s\" or missing value", 133062306a36Sopenharmony_ci p); 133162306a36Sopenharmony_ci return -EINVAL; 133262306a36Sopenharmony_ci } 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_cidefault_check: 133562306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 133662306a36Sopenharmony_ci if (f2fs_check_quota_options(sbi)) 133762306a36Sopenharmony_ci return -EINVAL; 133862306a36Sopenharmony_ci#else 133962306a36Sopenharmony_ci if (f2fs_sb_has_quota_ino(sbi) && !f2fs_readonly(sbi->sb)) { 134062306a36Sopenharmony_ci f2fs_info(sbi, "Filesystem with quota feature cannot be mounted RDWR without CONFIG_QUOTA"); 134162306a36Sopenharmony_ci return -EINVAL; 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci if (f2fs_sb_has_project_quota(sbi) && !f2fs_readonly(sbi->sb)) { 134462306a36Sopenharmony_ci f2fs_err(sbi, "Filesystem with project quota feature cannot be mounted RDWR without CONFIG_QUOTA"); 134562306a36Sopenharmony_ci return -EINVAL; 134662306a36Sopenharmony_ci } 134762306a36Sopenharmony_ci#endif 134862306a36Sopenharmony_ci#if !IS_ENABLED(CONFIG_UNICODE) 134962306a36Sopenharmony_ci if (f2fs_sb_has_casefold(sbi)) { 135062306a36Sopenharmony_ci f2fs_err(sbi, 135162306a36Sopenharmony_ci "Filesystem with casefold feature cannot be mounted without CONFIG_UNICODE"); 135262306a36Sopenharmony_ci return -EINVAL; 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci#endif 135562306a36Sopenharmony_ci /* 135662306a36Sopenharmony_ci * The BLKZONED feature indicates that the drive was formatted with 135762306a36Sopenharmony_ci * zone alignment optimization. This is optional for host-aware 135862306a36Sopenharmony_ci * devices, but mandatory for host-managed zoned block devices. 135962306a36Sopenharmony_ci */ 136062306a36Sopenharmony_ci if (f2fs_sb_has_blkzoned(sbi)) { 136162306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED 136262306a36Sopenharmony_ci if (F2FS_OPTION(sbi).discard_unit != 136362306a36Sopenharmony_ci DISCARD_UNIT_SECTION) { 136462306a36Sopenharmony_ci f2fs_info(sbi, "Zoned block device doesn't need small discard, set discard_unit=section by default"); 136562306a36Sopenharmony_ci F2FS_OPTION(sbi).discard_unit = 136662306a36Sopenharmony_ci DISCARD_UNIT_SECTION; 136762306a36Sopenharmony_ci } 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci if (F2FS_OPTION(sbi).fs_mode != FS_MODE_LFS) { 137062306a36Sopenharmony_ci f2fs_info(sbi, "Only lfs mode is allowed with zoned block device feature"); 137162306a36Sopenharmony_ci return -EINVAL; 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci#else 137462306a36Sopenharmony_ci f2fs_err(sbi, "Zoned block device support is not enabled"); 137562306a36Sopenharmony_ci return -EINVAL; 137662306a36Sopenharmony_ci#endif 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION 138062306a36Sopenharmony_ci if (f2fs_test_compress_extension(sbi)) { 138162306a36Sopenharmony_ci f2fs_err(sbi, "invalid compress or nocompress extension"); 138262306a36Sopenharmony_ci return -EINVAL; 138362306a36Sopenharmony_ci } 138462306a36Sopenharmony_ci#endif 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (F2FS_IO_SIZE_BITS(sbi) && !f2fs_lfs_mode(sbi)) { 138762306a36Sopenharmony_ci f2fs_err(sbi, "Should set mode=lfs with %luKB-sized IO", 138862306a36Sopenharmony_ci F2FS_IO_SIZE_KB(sbi)); 138962306a36Sopenharmony_ci return -EINVAL; 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci if (test_opt(sbi, INLINE_XATTR_SIZE)) { 139362306a36Sopenharmony_ci int min_size, max_size; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci if (!f2fs_sb_has_extra_attr(sbi) || 139662306a36Sopenharmony_ci !f2fs_sb_has_flexible_inline_xattr(sbi)) { 139762306a36Sopenharmony_ci f2fs_err(sbi, "extra_attr or flexible_inline_xattr feature is off"); 139862306a36Sopenharmony_ci return -EINVAL; 139962306a36Sopenharmony_ci } 140062306a36Sopenharmony_ci if (!test_opt(sbi, INLINE_XATTR)) { 140162306a36Sopenharmony_ci f2fs_err(sbi, "inline_xattr_size option should be set with inline_xattr option"); 140262306a36Sopenharmony_ci return -EINVAL; 140362306a36Sopenharmony_ci } 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci min_size = MIN_INLINE_XATTR_SIZE; 140662306a36Sopenharmony_ci max_size = MAX_INLINE_XATTR_SIZE; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci if (F2FS_OPTION(sbi).inline_xattr_size < min_size || 140962306a36Sopenharmony_ci F2FS_OPTION(sbi).inline_xattr_size > max_size) { 141062306a36Sopenharmony_ci f2fs_err(sbi, "inline xattr size is out of range: %d ~ %d", 141162306a36Sopenharmony_ci min_size, max_size); 141262306a36Sopenharmony_ci return -EINVAL; 141362306a36Sopenharmony_ci } 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci if (test_opt(sbi, DISABLE_CHECKPOINT) && f2fs_lfs_mode(sbi)) { 141762306a36Sopenharmony_ci f2fs_err(sbi, "LFS is not compatible with checkpoint=disable"); 141862306a36Sopenharmony_ci return -EINVAL; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci if (test_opt(sbi, ATGC) && f2fs_lfs_mode(sbi)) { 142262306a36Sopenharmony_ci f2fs_err(sbi, "LFS is not compatible with ATGC"); 142362306a36Sopenharmony_ci return -EINVAL; 142462306a36Sopenharmony_ci } 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci if (f2fs_is_readonly(sbi) && test_opt(sbi, FLUSH_MERGE)) { 142762306a36Sopenharmony_ci f2fs_err(sbi, "FLUSH_MERGE not compatible with readonly mode"); 142862306a36Sopenharmony_ci return -EINVAL; 142962306a36Sopenharmony_ci } 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci if (f2fs_sb_has_readonly(sbi) && !f2fs_readonly(sbi->sb)) { 143262306a36Sopenharmony_ci f2fs_err(sbi, "Allow to mount readonly mode only"); 143362306a36Sopenharmony_ci return -EROFS; 143462306a36Sopenharmony_ci } 143562306a36Sopenharmony_ci return 0; 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_cistatic struct inode *f2fs_alloc_inode(struct super_block *sb) 143962306a36Sopenharmony_ci{ 144062306a36Sopenharmony_ci struct f2fs_inode_info *fi; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci if (time_to_inject(F2FS_SB(sb), FAULT_SLAB_ALLOC)) 144362306a36Sopenharmony_ci return NULL; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci fi = alloc_inode_sb(sb, f2fs_inode_cachep, GFP_F2FS_ZERO); 144662306a36Sopenharmony_ci if (!fi) 144762306a36Sopenharmony_ci return NULL; 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci init_once((void *) fi); 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci /* Initialize f2fs-specific inode info */ 145262306a36Sopenharmony_ci atomic_set(&fi->dirty_pages, 0); 145362306a36Sopenharmony_ci atomic_set(&fi->i_compr_blocks, 0); 145462306a36Sopenharmony_ci init_f2fs_rwsem(&fi->i_sem); 145562306a36Sopenharmony_ci spin_lock_init(&fi->i_size_lock); 145662306a36Sopenharmony_ci INIT_LIST_HEAD(&fi->dirty_list); 145762306a36Sopenharmony_ci INIT_LIST_HEAD(&fi->gdirty_list); 145862306a36Sopenharmony_ci init_f2fs_rwsem(&fi->i_gc_rwsem[READ]); 145962306a36Sopenharmony_ci init_f2fs_rwsem(&fi->i_gc_rwsem[WRITE]); 146062306a36Sopenharmony_ci init_f2fs_rwsem(&fi->i_xattr_sem); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci /* Will be used by directory only */ 146362306a36Sopenharmony_ci fi->i_dir_level = F2FS_SB(sb)->dir_level; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci return &fi->vfs_inode; 146662306a36Sopenharmony_ci} 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_cistatic int f2fs_drop_inode(struct inode *inode) 146962306a36Sopenharmony_ci{ 147062306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 147162306a36Sopenharmony_ci int ret; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci /* 147462306a36Sopenharmony_ci * during filesystem shutdown, if checkpoint is disabled, 147562306a36Sopenharmony_ci * drop useless meta/node dirty pages. 147662306a36Sopenharmony_ci */ 147762306a36Sopenharmony_ci if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) { 147862306a36Sopenharmony_ci if (inode->i_ino == F2FS_NODE_INO(sbi) || 147962306a36Sopenharmony_ci inode->i_ino == F2FS_META_INO(sbi)) { 148062306a36Sopenharmony_ci trace_f2fs_drop_inode(inode, 1); 148162306a36Sopenharmony_ci return 1; 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci /* 148662306a36Sopenharmony_ci * This is to avoid a deadlock condition like below. 148762306a36Sopenharmony_ci * writeback_single_inode(inode) 148862306a36Sopenharmony_ci * - f2fs_write_data_page 148962306a36Sopenharmony_ci * - f2fs_gc -> iput -> evict 149062306a36Sopenharmony_ci * - inode_wait_for_writeback(inode) 149162306a36Sopenharmony_ci */ 149262306a36Sopenharmony_ci if ((!inode_unhashed(inode) && inode->i_state & I_SYNC)) { 149362306a36Sopenharmony_ci if (!inode->i_nlink && !is_bad_inode(inode)) { 149462306a36Sopenharmony_ci /* to avoid evict_inode call simultaneously */ 149562306a36Sopenharmony_ci atomic_inc(&inode->i_count); 149662306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci /* should remain fi->extent_tree for writepage */ 149962306a36Sopenharmony_ci f2fs_destroy_extent_node(inode); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci sb_start_intwrite(inode->i_sb); 150262306a36Sopenharmony_ci f2fs_i_size_write(inode, 0); 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci f2fs_submit_merged_write_cond(F2FS_I_SB(inode), 150562306a36Sopenharmony_ci inode, NULL, 0, DATA); 150662306a36Sopenharmony_ci truncate_inode_pages_final(inode->i_mapping); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci if (F2FS_HAS_BLOCKS(inode)) 150962306a36Sopenharmony_ci f2fs_truncate(inode); 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci sb_end_intwrite(inode->i_sb); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci spin_lock(&inode->i_lock); 151462306a36Sopenharmony_ci atomic_dec(&inode->i_count); 151562306a36Sopenharmony_ci } 151662306a36Sopenharmony_ci trace_f2fs_drop_inode(inode, 0); 151762306a36Sopenharmony_ci return 0; 151862306a36Sopenharmony_ci } 151962306a36Sopenharmony_ci ret = generic_drop_inode(inode); 152062306a36Sopenharmony_ci if (!ret) 152162306a36Sopenharmony_ci ret = fscrypt_drop_inode(inode); 152262306a36Sopenharmony_ci trace_f2fs_drop_inode(inode, ret); 152362306a36Sopenharmony_ci return ret; 152462306a36Sopenharmony_ci} 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ciint f2fs_inode_dirtied(struct inode *inode, bool sync) 152762306a36Sopenharmony_ci{ 152862306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 152962306a36Sopenharmony_ci int ret = 0; 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci spin_lock(&sbi->inode_lock[DIRTY_META]); 153262306a36Sopenharmony_ci if (is_inode_flag_set(inode, FI_DIRTY_INODE)) { 153362306a36Sopenharmony_ci ret = 1; 153462306a36Sopenharmony_ci } else { 153562306a36Sopenharmony_ci set_inode_flag(inode, FI_DIRTY_INODE); 153662306a36Sopenharmony_ci stat_inc_dirty_inode(sbi, DIRTY_META); 153762306a36Sopenharmony_ci } 153862306a36Sopenharmony_ci if (sync && list_empty(&F2FS_I(inode)->gdirty_list)) { 153962306a36Sopenharmony_ci list_add_tail(&F2FS_I(inode)->gdirty_list, 154062306a36Sopenharmony_ci &sbi->inode_list[DIRTY_META]); 154162306a36Sopenharmony_ci inc_page_count(sbi, F2FS_DIRTY_IMETA); 154262306a36Sopenharmony_ci } 154362306a36Sopenharmony_ci spin_unlock(&sbi->inode_lock[DIRTY_META]); 154462306a36Sopenharmony_ci return ret; 154562306a36Sopenharmony_ci} 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_civoid f2fs_inode_synced(struct inode *inode) 154862306a36Sopenharmony_ci{ 154962306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci spin_lock(&sbi->inode_lock[DIRTY_META]); 155262306a36Sopenharmony_ci if (!is_inode_flag_set(inode, FI_DIRTY_INODE)) { 155362306a36Sopenharmony_ci spin_unlock(&sbi->inode_lock[DIRTY_META]); 155462306a36Sopenharmony_ci return; 155562306a36Sopenharmony_ci } 155662306a36Sopenharmony_ci if (!list_empty(&F2FS_I(inode)->gdirty_list)) { 155762306a36Sopenharmony_ci list_del_init(&F2FS_I(inode)->gdirty_list); 155862306a36Sopenharmony_ci dec_page_count(sbi, F2FS_DIRTY_IMETA); 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci clear_inode_flag(inode, FI_DIRTY_INODE); 156162306a36Sopenharmony_ci clear_inode_flag(inode, FI_AUTO_RECOVER); 156262306a36Sopenharmony_ci stat_dec_dirty_inode(F2FS_I_SB(inode), DIRTY_META); 156362306a36Sopenharmony_ci spin_unlock(&sbi->inode_lock[DIRTY_META]); 156462306a36Sopenharmony_ci} 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci/* 156762306a36Sopenharmony_ci * f2fs_dirty_inode() is called from __mark_inode_dirty() 156862306a36Sopenharmony_ci * 156962306a36Sopenharmony_ci * We should call set_dirty_inode to write the dirty inode through write_inode. 157062306a36Sopenharmony_ci */ 157162306a36Sopenharmony_cistatic void f2fs_dirty_inode(struct inode *inode, int flags) 157262306a36Sopenharmony_ci{ 157362306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci if (inode->i_ino == F2FS_NODE_INO(sbi) || 157662306a36Sopenharmony_ci inode->i_ino == F2FS_META_INO(sbi)) 157762306a36Sopenharmony_ci return; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci if (is_inode_flag_set(inode, FI_AUTO_RECOVER)) 158062306a36Sopenharmony_ci clear_inode_flag(inode, FI_AUTO_RECOVER); 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci f2fs_inode_dirtied(inode, false); 158362306a36Sopenharmony_ci} 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_cistatic void f2fs_free_inode(struct inode *inode) 158662306a36Sopenharmony_ci{ 158762306a36Sopenharmony_ci fscrypt_free_inode(inode); 158862306a36Sopenharmony_ci kmem_cache_free(f2fs_inode_cachep, F2FS_I(inode)); 158962306a36Sopenharmony_ci} 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_cistatic void destroy_percpu_info(struct f2fs_sb_info *sbi) 159262306a36Sopenharmony_ci{ 159362306a36Sopenharmony_ci percpu_counter_destroy(&sbi->total_valid_inode_count); 159462306a36Sopenharmony_ci percpu_counter_destroy(&sbi->rf_node_block_count); 159562306a36Sopenharmony_ci percpu_counter_destroy(&sbi->alloc_valid_block_count); 159662306a36Sopenharmony_ci} 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_cistatic void destroy_device_list(struct f2fs_sb_info *sbi) 159962306a36Sopenharmony_ci{ 160062306a36Sopenharmony_ci int i; 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci for (i = 0; i < sbi->s_ndevs; i++) { 160362306a36Sopenharmony_ci if (i > 0) 160462306a36Sopenharmony_ci blkdev_put(FDEV(i).bdev, sbi->sb); 160562306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED 160662306a36Sopenharmony_ci kvfree(FDEV(i).blkz_seq); 160762306a36Sopenharmony_ci#endif 160862306a36Sopenharmony_ci } 160962306a36Sopenharmony_ci kvfree(sbi->devs); 161062306a36Sopenharmony_ci} 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_cistatic void f2fs_put_super(struct super_block *sb) 161362306a36Sopenharmony_ci{ 161462306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 161562306a36Sopenharmony_ci int i; 161662306a36Sopenharmony_ci int err = 0; 161762306a36Sopenharmony_ci bool done; 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci /* unregister procfs/sysfs entries in advance to avoid race case */ 162062306a36Sopenharmony_ci f2fs_unregister_sysfs(sbi); 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci f2fs_quota_off_umount(sb); 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci /* prevent remaining shrinker jobs */ 162562306a36Sopenharmony_ci mutex_lock(&sbi->umount_mutex); 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci /* 162862306a36Sopenharmony_ci * flush all issued checkpoints and stop checkpoint issue thread. 162962306a36Sopenharmony_ci * after then, all checkpoints should be done by each process context. 163062306a36Sopenharmony_ci */ 163162306a36Sopenharmony_ci f2fs_stop_ckpt_thread(sbi); 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci /* 163462306a36Sopenharmony_ci * We don't need to do checkpoint when superblock is clean. 163562306a36Sopenharmony_ci * But, the previous checkpoint was not done by umount, it needs to do 163662306a36Sopenharmony_ci * clean checkpoint again. 163762306a36Sopenharmony_ci */ 163862306a36Sopenharmony_ci if ((is_sbi_flag_set(sbi, SBI_IS_DIRTY) || 163962306a36Sopenharmony_ci !is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG))) { 164062306a36Sopenharmony_ci struct cp_control cpc = { 164162306a36Sopenharmony_ci .reason = CP_UMOUNT, 164262306a36Sopenharmony_ci }; 164362306a36Sopenharmony_ci stat_inc_cp_call_count(sbi, TOTAL_CALL); 164462306a36Sopenharmony_ci err = f2fs_write_checkpoint(sbi, &cpc); 164562306a36Sopenharmony_ci } 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci /* be sure to wait for any on-going discard commands */ 164862306a36Sopenharmony_ci done = f2fs_issue_discard_timeout(sbi); 164962306a36Sopenharmony_ci if (f2fs_realtime_discard_enable(sbi) && !sbi->discard_blks && done) { 165062306a36Sopenharmony_ci struct cp_control cpc = { 165162306a36Sopenharmony_ci .reason = CP_UMOUNT | CP_TRIMMED, 165262306a36Sopenharmony_ci }; 165362306a36Sopenharmony_ci stat_inc_cp_call_count(sbi, TOTAL_CALL); 165462306a36Sopenharmony_ci err = f2fs_write_checkpoint(sbi, &cpc); 165562306a36Sopenharmony_ci } 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci /* 165862306a36Sopenharmony_ci * normally superblock is clean, so we need to release this. 165962306a36Sopenharmony_ci * In addition, EIO will skip do checkpoint, we need this as well. 166062306a36Sopenharmony_ci */ 166162306a36Sopenharmony_ci f2fs_release_ino_entry(sbi, true); 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci f2fs_leave_shrinker(sbi); 166462306a36Sopenharmony_ci mutex_unlock(&sbi->umount_mutex); 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci /* our cp_error case, we can wait for any writeback page */ 166762306a36Sopenharmony_ci f2fs_flush_merged_writes(sbi); 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA); 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci if (err || f2fs_cp_error(sbi)) { 167262306a36Sopenharmony_ci truncate_inode_pages_final(NODE_MAPPING(sbi)); 167362306a36Sopenharmony_ci truncate_inode_pages_final(META_MAPPING(sbi)); 167462306a36Sopenharmony_ci } 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci for (i = 0; i < NR_COUNT_TYPE; i++) { 167762306a36Sopenharmony_ci if (!get_pages(sbi, i)) 167862306a36Sopenharmony_ci continue; 167962306a36Sopenharmony_ci f2fs_err(sbi, "detect filesystem reference count leak during " 168062306a36Sopenharmony_ci "umount, type: %d, count: %lld", i, get_pages(sbi, i)); 168162306a36Sopenharmony_ci f2fs_bug_on(sbi, 1); 168262306a36Sopenharmony_ci } 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci f2fs_bug_on(sbi, sbi->fsync_node_num); 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci f2fs_destroy_compress_inode(sbi); 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci iput(sbi->node_inode); 168962306a36Sopenharmony_ci sbi->node_inode = NULL; 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci iput(sbi->meta_inode); 169262306a36Sopenharmony_ci sbi->meta_inode = NULL; 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci /* 169562306a36Sopenharmony_ci * iput() can update stat information, if f2fs_write_checkpoint() 169662306a36Sopenharmony_ci * above failed with error. 169762306a36Sopenharmony_ci */ 169862306a36Sopenharmony_ci f2fs_destroy_stats(sbi); 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci /* destroy f2fs internal modules */ 170162306a36Sopenharmony_ci f2fs_destroy_node_manager(sbi); 170262306a36Sopenharmony_ci f2fs_destroy_segment_manager(sbi); 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci /* flush s_error_work before sbi destroy */ 170562306a36Sopenharmony_ci flush_work(&sbi->s_error_work); 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci f2fs_destroy_post_read_wq(sbi); 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci kvfree(sbi->ckpt); 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci sb->s_fs_info = NULL; 171262306a36Sopenharmony_ci if (sbi->s_chksum_driver) 171362306a36Sopenharmony_ci crypto_free_shash(sbi->s_chksum_driver); 171462306a36Sopenharmony_ci kfree(sbi->raw_super); 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci destroy_device_list(sbi); 171762306a36Sopenharmony_ci f2fs_destroy_page_array_cache(sbi); 171862306a36Sopenharmony_ci f2fs_destroy_xattr_caches(sbi); 171962306a36Sopenharmony_ci mempool_destroy(sbi->write_io_dummy); 172062306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 172162306a36Sopenharmony_ci for (i = 0; i < MAXQUOTAS; i++) 172262306a36Sopenharmony_ci kfree(F2FS_OPTION(sbi).s_qf_names[i]); 172362306a36Sopenharmony_ci#endif 172462306a36Sopenharmony_ci fscrypt_free_dummy_policy(&F2FS_OPTION(sbi).dummy_enc_policy); 172562306a36Sopenharmony_ci destroy_percpu_info(sbi); 172662306a36Sopenharmony_ci f2fs_destroy_iostat(sbi); 172762306a36Sopenharmony_ci for (i = 0; i < NR_PAGE_TYPE; i++) 172862306a36Sopenharmony_ci kvfree(sbi->write_io[i]); 172962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE) 173062306a36Sopenharmony_ci utf8_unload(sb->s_encoding); 173162306a36Sopenharmony_ci#endif 173262306a36Sopenharmony_ci kfree(sbi); 173362306a36Sopenharmony_ci} 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ciint f2fs_sync_fs(struct super_block *sb, int sync) 173662306a36Sopenharmony_ci{ 173762306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 173862306a36Sopenharmony_ci int err = 0; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(sbi))) 174162306a36Sopenharmony_ci return 0; 174262306a36Sopenharmony_ci if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) 174362306a36Sopenharmony_ci return 0; 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci trace_f2fs_sync_fs(sb, sync); 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) 174862306a36Sopenharmony_ci return -EAGAIN; 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci if (sync) { 175162306a36Sopenharmony_ci stat_inc_cp_call_count(sbi, TOTAL_CALL); 175262306a36Sopenharmony_ci err = f2fs_issue_checkpoint(sbi); 175362306a36Sopenharmony_ci } 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci return err; 175662306a36Sopenharmony_ci} 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_cistatic int f2fs_freeze(struct super_block *sb) 175962306a36Sopenharmony_ci{ 176062306a36Sopenharmony_ci if (f2fs_readonly(sb)) 176162306a36Sopenharmony_ci return 0; 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci /* IO error happened before */ 176462306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(F2FS_SB(sb)))) 176562306a36Sopenharmony_ci return -EIO; 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci /* must be clean, since sync_filesystem() was already called */ 176862306a36Sopenharmony_ci if (is_sbi_flag_set(F2FS_SB(sb), SBI_IS_DIRTY)) 176962306a36Sopenharmony_ci return -EINVAL; 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci /* Let's flush checkpoints and stop the thread. */ 177262306a36Sopenharmony_ci f2fs_flush_ckpt_thread(F2FS_SB(sb)); 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci /* to avoid deadlock on f2fs_evict_inode->SB_FREEZE_FS */ 177562306a36Sopenharmony_ci set_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING); 177662306a36Sopenharmony_ci return 0; 177762306a36Sopenharmony_ci} 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_cistatic int f2fs_unfreeze(struct super_block *sb) 178062306a36Sopenharmony_ci{ 178162306a36Sopenharmony_ci clear_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING); 178262306a36Sopenharmony_ci return 0; 178362306a36Sopenharmony_ci} 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 178662306a36Sopenharmony_cistatic int f2fs_statfs_project(struct super_block *sb, 178762306a36Sopenharmony_ci kprojid_t projid, struct kstatfs *buf) 178862306a36Sopenharmony_ci{ 178962306a36Sopenharmony_ci struct kqid qid; 179062306a36Sopenharmony_ci struct dquot *dquot; 179162306a36Sopenharmony_ci u64 limit; 179262306a36Sopenharmony_ci u64 curblock; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci qid = make_kqid_projid(projid); 179562306a36Sopenharmony_ci dquot = dqget(sb, qid); 179662306a36Sopenharmony_ci if (IS_ERR(dquot)) 179762306a36Sopenharmony_ci return PTR_ERR(dquot); 179862306a36Sopenharmony_ci spin_lock(&dquot->dq_dqb_lock); 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci limit = min_not_zero(dquot->dq_dqb.dqb_bsoftlimit, 180162306a36Sopenharmony_ci dquot->dq_dqb.dqb_bhardlimit); 180262306a36Sopenharmony_ci if (limit) 180362306a36Sopenharmony_ci limit >>= sb->s_blocksize_bits; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci if (limit && buf->f_blocks > limit) { 180662306a36Sopenharmony_ci curblock = (dquot->dq_dqb.dqb_curspace + 180762306a36Sopenharmony_ci dquot->dq_dqb.dqb_rsvspace) >> sb->s_blocksize_bits; 180862306a36Sopenharmony_ci buf->f_blocks = limit; 180962306a36Sopenharmony_ci buf->f_bfree = buf->f_bavail = 181062306a36Sopenharmony_ci (buf->f_blocks > curblock) ? 181162306a36Sopenharmony_ci (buf->f_blocks - curblock) : 0; 181262306a36Sopenharmony_ci } 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci limit = min_not_zero(dquot->dq_dqb.dqb_isoftlimit, 181562306a36Sopenharmony_ci dquot->dq_dqb.dqb_ihardlimit); 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci if (limit && buf->f_files > limit) { 181862306a36Sopenharmony_ci buf->f_files = limit; 181962306a36Sopenharmony_ci buf->f_ffree = 182062306a36Sopenharmony_ci (buf->f_files > dquot->dq_dqb.dqb_curinodes) ? 182162306a36Sopenharmony_ci (buf->f_files - dquot->dq_dqb.dqb_curinodes) : 0; 182262306a36Sopenharmony_ci } 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci spin_unlock(&dquot->dq_dqb_lock); 182562306a36Sopenharmony_ci dqput(dquot); 182662306a36Sopenharmony_ci return 0; 182762306a36Sopenharmony_ci} 182862306a36Sopenharmony_ci#endif 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_cistatic int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf) 183162306a36Sopenharmony_ci{ 183262306a36Sopenharmony_ci struct super_block *sb = dentry->d_sb; 183362306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 183462306a36Sopenharmony_ci u64 id = huge_encode_dev(sb->s_bdev->bd_dev); 183562306a36Sopenharmony_ci block_t total_count, user_block_count, start_count; 183662306a36Sopenharmony_ci u64 avail_node_count; 183762306a36Sopenharmony_ci unsigned int total_valid_node_count; 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci total_count = le64_to_cpu(sbi->raw_super->block_count); 184062306a36Sopenharmony_ci start_count = le32_to_cpu(sbi->raw_super->segment0_blkaddr); 184162306a36Sopenharmony_ci buf->f_type = F2FS_SUPER_MAGIC; 184262306a36Sopenharmony_ci buf->f_bsize = sbi->blocksize; 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci buf->f_blocks = total_count - start_count; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci spin_lock(&sbi->stat_lock); 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci user_block_count = sbi->user_block_count; 184962306a36Sopenharmony_ci total_valid_node_count = valid_node_count(sbi); 185062306a36Sopenharmony_ci avail_node_count = sbi->total_node_count - F2FS_RESERVED_NODE_NUM; 185162306a36Sopenharmony_ci buf->f_bfree = user_block_count - valid_user_blocks(sbi) - 185262306a36Sopenharmony_ci sbi->current_reserved_blocks; 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci if (unlikely(buf->f_bfree <= sbi->unusable_block_count)) 185562306a36Sopenharmony_ci buf->f_bfree = 0; 185662306a36Sopenharmony_ci else 185762306a36Sopenharmony_ci buf->f_bfree -= sbi->unusable_block_count; 185862306a36Sopenharmony_ci spin_unlock(&sbi->stat_lock); 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci if (buf->f_bfree > F2FS_OPTION(sbi).root_reserved_blocks) 186162306a36Sopenharmony_ci buf->f_bavail = buf->f_bfree - 186262306a36Sopenharmony_ci F2FS_OPTION(sbi).root_reserved_blocks; 186362306a36Sopenharmony_ci else 186462306a36Sopenharmony_ci buf->f_bavail = 0; 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci if (avail_node_count > user_block_count) { 186762306a36Sopenharmony_ci buf->f_files = user_block_count; 186862306a36Sopenharmony_ci buf->f_ffree = buf->f_bavail; 186962306a36Sopenharmony_ci } else { 187062306a36Sopenharmony_ci buf->f_files = avail_node_count; 187162306a36Sopenharmony_ci buf->f_ffree = min(avail_node_count - total_valid_node_count, 187262306a36Sopenharmony_ci buf->f_bavail); 187362306a36Sopenharmony_ci } 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci buf->f_namelen = F2FS_NAME_LEN; 187662306a36Sopenharmony_ci buf->f_fsid = u64_to_fsid(id); 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 187962306a36Sopenharmony_ci if (is_inode_flag_set(dentry->d_inode, FI_PROJ_INHERIT) && 188062306a36Sopenharmony_ci sb_has_quota_limits_enabled(sb, PRJQUOTA)) { 188162306a36Sopenharmony_ci f2fs_statfs_project(sb, F2FS_I(dentry->d_inode)->i_projid, buf); 188262306a36Sopenharmony_ci } 188362306a36Sopenharmony_ci#endif 188462306a36Sopenharmony_ci return 0; 188562306a36Sopenharmony_ci} 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_cistatic inline void f2fs_show_quota_options(struct seq_file *seq, 188862306a36Sopenharmony_ci struct super_block *sb) 188962306a36Sopenharmony_ci{ 189062306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 189162306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci if (F2FS_OPTION(sbi).s_jquota_fmt) { 189462306a36Sopenharmony_ci char *fmtname = ""; 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci switch (F2FS_OPTION(sbi).s_jquota_fmt) { 189762306a36Sopenharmony_ci case QFMT_VFS_OLD: 189862306a36Sopenharmony_ci fmtname = "vfsold"; 189962306a36Sopenharmony_ci break; 190062306a36Sopenharmony_ci case QFMT_VFS_V0: 190162306a36Sopenharmony_ci fmtname = "vfsv0"; 190262306a36Sopenharmony_ci break; 190362306a36Sopenharmony_ci case QFMT_VFS_V1: 190462306a36Sopenharmony_ci fmtname = "vfsv1"; 190562306a36Sopenharmony_ci break; 190662306a36Sopenharmony_ci } 190762306a36Sopenharmony_ci seq_printf(seq, ",jqfmt=%s", fmtname); 190862306a36Sopenharmony_ci } 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci if (F2FS_OPTION(sbi).s_qf_names[USRQUOTA]) 191162306a36Sopenharmony_ci seq_show_option(seq, "usrjquota", 191262306a36Sopenharmony_ci F2FS_OPTION(sbi).s_qf_names[USRQUOTA]); 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci if (F2FS_OPTION(sbi).s_qf_names[GRPQUOTA]) 191562306a36Sopenharmony_ci seq_show_option(seq, "grpjquota", 191662306a36Sopenharmony_ci F2FS_OPTION(sbi).s_qf_names[GRPQUOTA]); 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci if (F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]) 191962306a36Sopenharmony_ci seq_show_option(seq, "prjjquota", 192062306a36Sopenharmony_ci F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]); 192162306a36Sopenharmony_ci#endif 192262306a36Sopenharmony_ci} 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION 192562306a36Sopenharmony_cistatic inline void f2fs_show_compress_options(struct seq_file *seq, 192662306a36Sopenharmony_ci struct super_block *sb) 192762306a36Sopenharmony_ci{ 192862306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 192962306a36Sopenharmony_ci char *algtype = ""; 193062306a36Sopenharmony_ci int i; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci if (!f2fs_sb_has_compression(sbi)) 193362306a36Sopenharmony_ci return; 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci switch (F2FS_OPTION(sbi).compress_algorithm) { 193662306a36Sopenharmony_ci case COMPRESS_LZO: 193762306a36Sopenharmony_ci algtype = "lzo"; 193862306a36Sopenharmony_ci break; 193962306a36Sopenharmony_ci case COMPRESS_LZ4: 194062306a36Sopenharmony_ci algtype = "lz4"; 194162306a36Sopenharmony_ci break; 194262306a36Sopenharmony_ci case COMPRESS_ZSTD: 194362306a36Sopenharmony_ci algtype = "zstd"; 194462306a36Sopenharmony_ci break; 194562306a36Sopenharmony_ci case COMPRESS_LZORLE: 194662306a36Sopenharmony_ci algtype = "lzo-rle"; 194762306a36Sopenharmony_ci break; 194862306a36Sopenharmony_ci } 194962306a36Sopenharmony_ci seq_printf(seq, ",compress_algorithm=%s", algtype); 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci if (F2FS_OPTION(sbi).compress_level) 195262306a36Sopenharmony_ci seq_printf(seq, ":%d", F2FS_OPTION(sbi).compress_level); 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci seq_printf(seq, ",compress_log_size=%u", 195562306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_log_size); 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci for (i = 0; i < F2FS_OPTION(sbi).compress_ext_cnt; i++) { 195862306a36Sopenharmony_ci seq_printf(seq, ",compress_extension=%s", 195962306a36Sopenharmony_ci F2FS_OPTION(sbi).extensions[i]); 196062306a36Sopenharmony_ci } 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci for (i = 0; i < F2FS_OPTION(sbi).nocompress_ext_cnt; i++) { 196362306a36Sopenharmony_ci seq_printf(seq, ",nocompress_extension=%s", 196462306a36Sopenharmony_ci F2FS_OPTION(sbi).noextensions[i]); 196562306a36Sopenharmony_ci } 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci if (F2FS_OPTION(sbi).compress_chksum) 196862306a36Sopenharmony_ci seq_puts(seq, ",compress_chksum"); 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci if (F2FS_OPTION(sbi).compress_mode == COMPR_MODE_FS) 197162306a36Sopenharmony_ci seq_printf(seq, ",compress_mode=%s", "fs"); 197262306a36Sopenharmony_ci else if (F2FS_OPTION(sbi).compress_mode == COMPR_MODE_USER) 197362306a36Sopenharmony_ci seq_printf(seq, ",compress_mode=%s", "user"); 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci if (test_opt(sbi, COMPRESS_CACHE)) 197662306a36Sopenharmony_ci seq_puts(seq, ",compress_cache"); 197762306a36Sopenharmony_ci} 197862306a36Sopenharmony_ci#endif 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_cistatic int f2fs_show_options(struct seq_file *seq, struct dentry *root) 198162306a36Sopenharmony_ci{ 198262306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb); 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci if (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_SYNC) 198562306a36Sopenharmony_ci seq_printf(seq, ",background_gc=%s", "sync"); 198662306a36Sopenharmony_ci else if (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_ON) 198762306a36Sopenharmony_ci seq_printf(seq, ",background_gc=%s", "on"); 198862306a36Sopenharmony_ci else if (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_OFF) 198962306a36Sopenharmony_ci seq_printf(seq, ",background_gc=%s", "off"); 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci if (test_opt(sbi, GC_MERGE)) 199262306a36Sopenharmony_ci seq_puts(seq, ",gc_merge"); 199362306a36Sopenharmony_ci else 199462306a36Sopenharmony_ci seq_puts(seq, ",nogc_merge"); 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci if (test_opt(sbi, DISABLE_ROLL_FORWARD)) 199762306a36Sopenharmony_ci seq_puts(seq, ",disable_roll_forward"); 199862306a36Sopenharmony_ci if (test_opt(sbi, NORECOVERY)) 199962306a36Sopenharmony_ci seq_puts(seq, ",norecovery"); 200062306a36Sopenharmony_ci if (test_opt(sbi, DISCARD)) { 200162306a36Sopenharmony_ci seq_puts(seq, ",discard"); 200262306a36Sopenharmony_ci if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_BLOCK) 200362306a36Sopenharmony_ci seq_printf(seq, ",discard_unit=%s", "block"); 200462306a36Sopenharmony_ci else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SEGMENT) 200562306a36Sopenharmony_ci seq_printf(seq, ",discard_unit=%s", "segment"); 200662306a36Sopenharmony_ci else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SECTION) 200762306a36Sopenharmony_ci seq_printf(seq, ",discard_unit=%s", "section"); 200862306a36Sopenharmony_ci } else { 200962306a36Sopenharmony_ci seq_puts(seq, ",nodiscard"); 201062306a36Sopenharmony_ci } 201162306a36Sopenharmony_ci if (test_opt(sbi, NOHEAP)) 201262306a36Sopenharmony_ci seq_puts(seq, ",no_heap"); 201362306a36Sopenharmony_ci else 201462306a36Sopenharmony_ci seq_puts(seq, ",heap"); 201562306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_XATTR 201662306a36Sopenharmony_ci if (test_opt(sbi, XATTR_USER)) 201762306a36Sopenharmony_ci seq_puts(seq, ",user_xattr"); 201862306a36Sopenharmony_ci else 201962306a36Sopenharmony_ci seq_puts(seq, ",nouser_xattr"); 202062306a36Sopenharmony_ci if (test_opt(sbi, INLINE_XATTR)) 202162306a36Sopenharmony_ci seq_puts(seq, ",inline_xattr"); 202262306a36Sopenharmony_ci else 202362306a36Sopenharmony_ci seq_puts(seq, ",noinline_xattr"); 202462306a36Sopenharmony_ci if (test_opt(sbi, INLINE_XATTR_SIZE)) 202562306a36Sopenharmony_ci seq_printf(seq, ",inline_xattr_size=%u", 202662306a36Sopenharmony_ci F2FS_OPTION(sbi).inline_xattr_size); 202762306a36Sopenharmony_ci#endif 202862306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_POSIX_ACL 202962306a36Sopenharmony_ci if (test_opt(sbi, POSIX_ACL)) 203062306a36Sopenharmony_ci seq_puts(seq, ",acl"); 203162306a36Sopenharmony_ci else 203262306a36Sopenharmony_ci seq_puts(seq, ",noacl"); 203362306a36Sopenharmony_ci#endif 203462306a36Sopenharmony_ci if (test_opt(sbi, DISABLE_EXT_IDENTIFY)) 203562306a36Sopenharmony_ci seq_puts(seq, ",disable_ext_identify"); 203662306a36Sopenharmony_ci if (test_opt(sbi, INLINE_DATA)) 203762306a36Sopenharmony_ci seq_puts(seq, ",inline_data"); 203862306a36Sopenharmony_ci else 203962306a36Sopenharmony_ci seq_puts(seq, ",noinline_data"); 204062306a36Sopenharmony_ci if (test_opt(sbi, INLINE_DENTRY)) 204162306a36Sopenharmony_ci seq_puts(seq, ",inline_dentry"); 204262306a36Sopenharmony_ci else 204362306a36Sopenharmony_ci seq_puts(seq, ",noinline_dentry"); 204462306a36Sopenharmony_ci if (test_opt(sbi, FLUSH_MERGE)) 204562306a36Sopenharmony_ci seq_puts(seq, ",flush_merge"); 204662306a36Sopenharmony_ci else 204762306a36Sopenharmony_ci seq_puts(seq, ",noflush_merge"); 204862306a36Sopenharmony_ci if (test_opt(sbi, NOBARRIER)) 204962306a36Sopenharmony_ci seq_puts(seq, ",nobarrier"); 205062306a36Sopenharmony_ci else 205162306a36Sopenharmony_ci seq_puts(seq, ",barrier"); 205262306a36Sopenharmony_ci if (test_opt(sbi, FASTBOOT)) 205362306a36Sopenharmony_ci seq_puts(seq, ",fastboot"); 205462306a36Sopenharmony_ci if (test_opt(sbi, READ_EXTENT_CACHE)) 205562306a36Sopenharmony_ci seq_puts(seq, ",extent_cache"); 205662306a36Sopenharmony_ci else 205762306a36Sopenharmony_ci seq_puts(seq, ",noextent_cache"); 205862306a36Sopenharmony_ci if (test_opt(sbi, AGE_EXTENT_CACHE)) 205962306a36Sopenharmony_ci seq_puts(seq, ",age_extent_cache"); 206062306a36Sopenharmony_ci if (test_opt(sbi, DATA_FLUSH)) 206162306a36Sopenharmony_ci seq_puts(seq, ",data_flush"); 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci seq_puts(seq, ",mode="); 206462306a36Sopenharmony_ci if (F2FS_OPTION(sbi).fs_mode == FS_MODE_ADAPTIVE) 206562306a36Sopenharmony_ci seq_puts(seq, "adaptive"); 206662306a36Sopenharmony_ci else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS) 206762306a36Sopenharmony_ci seq_puts(seq, "lfs"); 206862306a36Sopenharmony_ci else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_SEG) 206962306a36Sopenharmony_ci seq_puts(seq, "fragment:segment"); 207062306a36Sopenharmony_ci else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK) 207162306a36Sopenharmony_ci seq_puts(seq, "fragment:block"); 207262306a36Sopenharmony_ci seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs); 207362306a36Sopenharmony_ci if (test_opt(sbi, RESERVE_ROOT)) 207462306a36Sopenharmony_ci seq_printf(seq, ",reserve_root=%u,resuid=%u,resgid=%u", 207562306a36Sopenharmony_ci F2FS_OPTION(sbi).root_reserved_blocks, 207662306a36Sopenharmony_ci from_kuid_munged(&init_user_ns, 207762306a36Sopenharmony_ci F2FS_OPTION(sbi).s_resuid), 207862306a36Sopenharmony_ci from_kgid_munged(&init_user_ns, 207962306a36Sopenharmony_ci F2FS_OPTION(sbi).s_resgid)); 208062306a36Sopenharmony_ci if (F2FS_IO_SIZE_BITS(sbi)) 208162306a36Sopenharmony_ci seq_printf(seq, ",io_bits=%u", 208262306a36Sopenharmony_ci F2FS_OPTION(sbi).write_io_size_bits); 208362306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FAULT_INJECTION 208462306a36Sopenharmony_ci if (test_opt(sbi, FAULT_INJECTION)) { 208562306a36Sopenharmony_ci seq_printf(seq, ",fault_injection=%u", 208662306a36Sopenharmony_ci F2FS_OPTION(sbi).fault_info.inject_rate); 208762306a36Sopenharmony_ci seq_printf(seq, ",fault_type=%u", 208862306a36Sopenharmony_ci F2FS_OPTION(sbi).fault_info.inject_type); 208962306a36Sopenharmony_ci } 209062306a36Sopenharmony_ci#endif 209162306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 209262306a36Sopenharmony_ci if (test_opt(sbi, QUOTA)) 209362306a36Sopenharmony_ci seq_puts(seq, ",quota"); 209462306a36Sopenharmony_ci if (test_opt(sbi, USRQUOTA)) 209562306a36Sopenharmony_ci seq_puts(seq, ",usrquota"); 209662306a36Sopenharmony_ci if (test_opt(sbi, GRPQUOTA)) 209762306a36Sopenharmony_ci seq_puts(seq, ",grpquota"); 209862306a36Sopenharmony_ci if (test_opt(sbi, PRJQUOTA)) 209962306a36Sopenharmony_ci seq_puts(seq, ",prjquota"); 210062306a36Sopenharmony_ci#endif 210162306a36Sopenharmony_ci f2fs_show_quota_options(seq, sbi->sb); 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci fscrypt_show_test_dummy_encryption(seq, ',', sbi->sb); 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci if (sbi->sb->s_flags & SB_INLINECRYPT) 210662306a36Sopenharmony_ci seq_puts(seq, ",inlinecrypt"); 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_DEFAULT) 210962306a36Sopenharmony_ci seq_printf(seq, ",alloc_mode=%s", "default"); 211062306a36Sopenharmony_ci else if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_REUSE) 211162306a36Sopenharmony_ci seq_printf(seq, ",alloc_mode=%s", "reuse"); 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci if (test_opt(sbi, DISABLE_CHECKPOINT)) 211462306a36Sopenharmony_ci seq_printf(seq, ",checkpoint=disable:%u", 211562306a36Sopenharmony_ci F2FS_OPTION(sbi).unusable_cap); 211662306a36Sopenharmony_ci if (test_opt(sbi, MERGE_CHECKPOINT)) 211762306a36Sopenharmony_ci seq_puts(seq, ",checkpoint_merge"); 211862306a36Sopenharmony_ci else 211962306a36Sopenharmony_ci seq_puts(seq, ",nocheckpoint_merge"); 212062306a36Sopenharmony_ci if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_POSIX) 212162306a36Sopenharmony_ci seq_printf(seq, ",fsync_mode=%s", "posix"); 212262306a36Sopenharmony_ci else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) 212362306a36Sopenharmony_ci seq_printf(seq, ",fsync_mode=%s", "strict"); 212462306a36Sopenharmony_ci else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_NOBARRIER) 212562306a36Sopenharmony_ci seq_printf(seq, ",fsync_mode=%s", "nobarrier"); 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION 212862306a36Sopenharmony_ci f2fs_show_compress_options(seq, sbi->sb); 212962306a36Sopenharmony_ci#endif 213062306a36Sopenharmony_ci 213162306a36Sopenharmony_ci if (test_opt(sbi, ATGC)) 213262306a36Sopenharmony_ci seq_puts(seq, ",atgc"); 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_ci if (F2FS_OPTION(sbi).memory_mode == MEMORY_MODE_NORMAL) 213562306a36Sopenharmony_ci seq_printf(seq, ",memory=%s", "normal"); 213662306a36Sopenharmony_ci else if (F2FS_OPTION(sbi).memory_mode == MEMORY_MODE_LOW) 213762306a36Sopenharmony_ci seq_printf(seq, ",memory=%s", "low"); 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_READONLY) 214062306a36Sopenharmony_ci seq_printf(seq, ",errors=%s", "remount-ro"); 214162306a36Sopenharmony_ci else if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_CONTINUE) 214262306a36Sopenharmony_ci seq_printf(seq, ",errors=%s", "continue"); 214362306a36Sopenharmony_ci else if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_PANIC) 214462306a36Sopenharmony_ci seq_printf(seq, ",errors=%s", "panic"); 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci return 0; 214762306a36Sopenharmony_ci} 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_cistatic void default_options(struct f2fs_sb_info *sbi, bool remount) 215062306a36Sopenharmony_ci{ 215162306a36Sopenharmony_ci /* init some FS parameters */ 215262306a36Sopenharmony_ci if (!remount) { 215362306a36Sopenharmony_ci set_opt(sbi, READ_EXTENT_CACHE); 215462306a36Sopenharmony_ci clear_opt(sbi, DISABLE_CHECKPOINT); 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci if (f2fs_hw_support_discard(sbi) || f2fs_hw_should_discard(sbi)) 215762306a36Sopenharmony_ci set_opt(sbi, DISCARD); 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci if (f2fs_sb_has_blkzoned(sbi)) 216062306a36Sopenharmony_ci F2FS_OPTION(sbi).discard_unit = DISCARD_UNIT_SECTION; 216162306a36Sopenharmony_ci else 216262306a36Sopenharmony_ci F2FS_OPTION(sbi).discard_unit = DISCARD_UNIT_BLOCK; 216362306a36Sopenharmony_ci } 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci if (f2fs_sb_has_readonly(sbi)) 216662306a36Sopenharmony_ci F2FS_OPTION(sbi).active_logs = NR_CURSEG_RO_TYPE; 216762306a36Sopenharmony_ci else 216862306a36Sopenharmony_ci F2FS_OPTION(sbi).active_logs = NR_CURSEG_PERSIST_TYPE; 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci F2FS_OPTION(sbi).inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS; 217162306a36Sopenharmony_ci if (le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count_main) <= 217262306a36Sopenharmony_ci SMALL_VOLUME_SEGMENTS) 217362306a36Sopenharmony_ci F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE; 217462306a36Sopenharmony_ci else 217562306a36Sopenharmony_ci F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT; 217662306a36Sopenharmony_ci F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX; 217762306a36Sopenharmony_ci F2FS_OPTION(sbi).s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID); 217862306a36Sopenharmony_ci F2FS_OPTION(sbi).s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID); 217962306a36Sopenharmony_ci if (f2fs_sb_has_compression(sbi)) { 218062306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_algorithm = COMPRESS_LZ4; 218162306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_log_size = MIN_COMPRESS_LOG_SIZE; 218262306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_ext_cnt = 0; 218362306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_mode = COMPR_MODE_FS; 218462306a36Sopenharmony_ci } 218562306a36Sopenharmony_ci F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_ON; 218662306a36Sopenharmony_ci F2FS_OPTION(sbi).memory_mode = MEMORY_MODE_NORMAL; 218762306a36Sopenharmony_ci F2FS_OPTION(sbi).errors = MOUNT_ERRORS_CONTINUE; 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci sbi->sb->s_flags &= ~SB_INLINECRYPT; 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci set_opt(sbi, INLINE_XATTR); 219262306a36Sopenharmony_ci set_opt(sbi, INLINE_DATA); 219362306a36Sopenharmony_ci set_opt(sbi, INLINE_DENTRY); 219462306a36Sopenharmony_ci set_opt(sbi, NOHEAP); 219562306a36Sopenharmony_ci set_opt(sbi, MERGE_CHECKPOINT); 219662306a36Sopenharmony_ci F2FS_OPTION(sbi).unusable_cap = 0; 219762306a36Sopenharmony_ci sbi->sb->s_flags |= SB_LAZYTIME; 219862306a36Sopenharmony_ci if (!f2fs_is_readonly(sbi)) 219962306a36Sopenharmony_ci set_opt(sbi, FLUSH_MERGE); 220062306a36Sopenharmony_ci if (f2fs_sb_has_blkzoned(sbi)) 220162306a36Sopenharmony_ci F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS; 220262306a36Sopenharmony_ci else 220362306a36Sopenharmony_ci F2FS_OPTION(sbi).fs_mode = FS_MODE_ADAPTIVE; 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_XATTR 220662306a36Sopenharmony_ci set_opt(sbi, XATTR_USER); 220762306a36Sopenharmony_ci#endif 220862306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_POSIX_ACL 220962306a36Sopenharmony_ci set_opt(sbi, POSIX_ACL); 221062306a36Sopenharmony_ci#endif 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_ci f2fs_build_fault_attr(sbi, 0, 0); 221362306a36Sopenharmony_ci} 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 221662306a36Sopenharmony_cistatic int f2fs_enable_quotas(struct super_block *sb); 221762306a36Sopenharmony_ci#endif 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_cistatic int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) 222062306a36Sopenharmony_ci{ 222162306a36Sopenharmony_ci unsigned int s_flags = sbi->sb->s_flags; 222262306a36Sopenharmony_ci struct cp_control cpc; 222362306a36Sopenharmony_ci unsigned int gc_mode = sbi->gc_mode; 222462306a36Sopenharmony_ci int err = 0; 222562306a36Sopenharmony_ci int ret; 222662306a36Sopenharmony_ci block_t unusable; 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci if (s_flags & SB_RDONLY) { 222962306a36Sopenharmony_ci f2fs_err(sbi, "checkpoint=disable on readonly fs"); 223062306a36Sopenharmony_ci return -EINVAL; 223162306a36Sopenharmony_ci } 223262306a36Sopenharmony_ci sbi->sb->s_flags |= SB_ACTIVE; 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci /* check if we need more GC first */ 223562306a36Sopenharmony_ci unusable = f2fs_get_unusable_blocks(sbi); 223662306a36Sopenharmony_ci if (!f2fs_disable_cp_again(sbi, unusable)) 223762306a36Sopenharmony_ci goto skip_gc; 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci f2fs_update_time(sbi, DISABLE_TIME); 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci sbi->gc_mode = GC_URGENT_HIGH; 224262306a36Sopenharmony_ci 224362306a36Sopenharmony_ci while (!f2fs_time_over(sbi, DISABLE_TIME)) { 224462306a36Sopenharmony_ci struct f2fs_gc_control gc_control = { 224562306a36Sopenharmony_ci .victim_segno = NULL_SEGNO, 224662306a36Sopenharmony_ci .init_gc_type = FG_GC, 224762306a36Sopenharmony_ci .should_migrate_blocks = false, 224862306a36Sopenharmony_ci .err_gc_skipped = true, 224962306a36Sopenharmony_ci .nr_free_secs = 1 }; 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci f2fs_down_write(&sbi->gc_lock); 225262306a36Sopenharmony_ci stat_inc_gc_call_count(sbi, FOREGROUND); 225362306a36Sopenharmony_ci err = f2fs_gc(sbi, &gc_control); 225462306a36Sopenharmony_ci if (err == -ENODATA) { 225562306a36Sopenharmony_ci err = 0; 225662306a36Sopenharmony_ci break; 225762306a36Sopenharmony_ci } 225862306a36Sopenharmony_ci if (err && err != -EAGAIN) 225962306a36Sopenharmony_ci break; 226062306a36Sopenharmony_ci } 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci ret = sync_filesystem(sbi->sb); 226362306a36Sopenharmony_ci if (ret || err) { 226462306a36Sopenharmony_ci err = ret ? ret : err; 226562306a36Sopenharmony_ci goto restore_flag; 226662306a36Sopenharmony_ci } 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci unusable = f2fs_get_unusable_blocks(sbi); 226962306a36Sopenharmony_ci if (f2fs_disable_cp_again(sbi, unusable)) { 227062306a36Sopenharmony_ci err = -EAGAIN; 227162306a36Sopenharmony_ci goto restore_flag; 227262306a36Sopenharmony_ci } 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ciskip_gc: 227562306a36Sopenharmony_ci f2fs_down_write(&sbi->gc_lock); 227662306a36Sopenharmony_ci cpc.reason = CP_PAUSE; 227762306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_CP_DISABLED); 227862306a36Sopenharmony_ci stat_inc_cp_call_count(sbi, TOTAL_CALL); 227962306a36Sopenharmony_ci err = f2fs_write_checkpoint(sbi, &cpc); 228062306a36Sopenharmony_ci if (err) 228162306a36Sopenharmony_ci goto out_unlock; 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci spin_lock(&sbi->stat_lock); 228462306a36Sopenharmony_ci sbi->unusable_block_count = unusable; 228562306a36Sopenharmony_ci spin_unlock(&sbi->stat_lock); 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ciout_unlock: 228862306a36Sopenharmony_ci f2fs_up_write(&sbi->gc_lock); 228962306a36Sopenharmony_cirestore_flag: 229062306a36Sopenharmony_ci sbi->gc_mode = gc_mode; 229162306a36Sopenharmony_ci sbi->sb->s_flags = s_flags; /* Restore SB_RDONLY status */ 229262306a36Sopenharmony_ci return err; 229362306a36Sopenharmony_ci} 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_cistatic void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi) 229662306a36Sopenharmony_ci{ 229762306a36Sopenharmony_ci int retry = DEFAULT_RETRY_IO_COUNT; 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci /* we should flush all the data to keep data consistency */ 230062306a36Sopenharmony_ci do { 230162306a36Sopenharmony_ci sync_inodes_sb(sbi->sb); 230262306a36Sopenharmony_ci f2fs_io_schedule_timeout(DEFAULT_IO_TIMEOUT); 230362306a36Sopenharmony_ci } while (get_pages(sbi, F2FS_DIRTY_DATA) && retry--); 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci if (unlikely(retry < 0)) 230662306a36Sopenharmony_ci f2fs_warn(sbi, "checkpoint=enable has some unwritten data."); 230762306a36Sopenharmony_ci 230862306a36Sopenharmony_ci f2fs_down_write(&sbi->gc_lock); 230962306a36Sopenharmony_ci f2fs_dirty_to_prefree(sbi); 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci clear_sbi_flag(sbi, SBI_CP_DISABLED); 231262306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_IS_DIRTY); 231362306a36Sopenharmony_ci f2fs_up_write(&sbi->gc_lock); 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ci f2fs_sync_fs(sbi->sb, 1); 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci /* Let's ensure there's no pending checkpoint anymore */ 231862306a36Sopenharmony_ci f2fs_flush_ckpt_thread(sbi); 231962306a36Sopenharmony_ci} 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_cistatic int f2fs_remount(struct super_block *sb, int *flags, char *data) 232262306a36Sopenharmony_ci{ 232362306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 232462306a36Sopenharmony_ci struct f2fs_mount_info org_mount_opt; 232562306a36Sopenharmony_ci unsigned long old_sb_flags; 232662306a36Sopenharmony_ci int err; 232762306a36Sopenharmony_ci bool need_restart_gc = false, need_stop_gc = false; 232862306a36Sopenharmony_ci bool need_restart_ckpt = false, need_stop_ckpt = false; 232962306a36Sopenharmony_ci bool need_restart_flush = false, need_stop_flush = false; 233062306a36Sopenharmony_ci bool need_restart_discard = false, need_stop_discard = false; 233162306a36Sopenharmony_ci bool no_read_extent_cache = !test_opt(sbi, READ_EXTENT_CACHE); 233262306a36Sopenharmony_ci bool no_age_extent_cache = !test_opt(sbi, AGE_EXTENT_CACHE); 233362306a36Sopenharmony_ci bool enable_checkpoint = !test_opt(sbi, DISABLE_CHECKPOINT); 233462306a36Sopenharmony_ci bool no_io_align = !F2FS_IO_ALIGNED(sbi); 233562306a36Sopenharmony_ci bool no_atgc = !test_opt(sbi, ATGC); 233662306a36Sopenharmony_ci bool no_discard = !test_opt(sbi, DISCARD); 233762306a36Sopenharmony_ci bool no_compress_cache = !test_opt(sbi, COMPRESS_CACHE); 233862306a36Sopenharmony_ci bool block_unit_discard = f2fs_block_unit_discard(sbi); 233962306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 234062306a36Sopenharmony_ci int i, j; 234162306a36Sopenharmony_ci#endif 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci /* 234462306a36Sopenharmony_ci * Save the old mount options in case we 234562306a36Sopenharmony_ci * need to restore them. 234662306a36Sopenharmony_ci */ 234762306a36Sopenharmony_ci org_mount_opt = sbi->mount_opt; 234862306a36Sopenharmony_ci old_sb_flags = sb->s_flags; 234962306a36Sopenharmony_ci 235062306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 235162306a36Sopenharmony_ci org_mount_opt.s_jquota_fmt = F2FS_OPTION(sbi).s_jquota_fmt; 235262306a36Sopenharmony_ci for (i = 0; i < MAXQUOTAS; i++) { 235362306a36Sopenharmony_ci if (F2FS_OPTION(sbi).s_qf_names[i]) { 235462306a36Sopenharmony_ci org_mount_opt.s_qf_names[i] = 235562306a36Sopenharmony_ci kstrdup(F2FS_OPTION(sbi).s_qf_names[i], 235662306a36Sopenharmony_ci GFP_KERNEL); 235762306a36Sopenharmony_ci if (!org_mount_opt.s_qf_names[i]) { 235862306a36Sopenharmony_ci for (j = 0; j < i; j++) 235962306a36Sopenharmony_ci kfree(org_mount_opt.s_qf_names[j]); 236062306a36Sopenharmony_ci return -ENOMEM; 236162306a36Sopenharmony_ci } 236262306a36Sopenharmony_ci } else { 236362306a36Sopenharmony_ci org_mount_opt.s_qf_names[i] = NULL; 236462306a36Sopenharmony_ci } 236562306a36Sopenharmony_ci } 236662306a36Sopenharmony_ci#endif 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci /* recover superblocks we couldn't write due to previous RO mount */ 236962306a36Sopenharmony_ci if (!(*flags & SB_RDONLY) && is_sbi_flag_set(sbi, SBI_NEED_SB_WRITE)) { 237062306a36Sopenharmony_ci err = f2fs_commit_super(sbi, false); 237162306a36Sopenharmony_ci f2fs_info(sbi, "Try to recover all the superblocks, ret: %d", 237262306a36Sopenharmony_ci err); 237362306a36Sopenharmony_ci if (!err) 237462306a36Sopenharmony_ci clear_sbi_flag(sbi, SBI_NEED_SB_WRITE); 237562306a36Sopenharmony_ci } 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci default_options(sbi, true); 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_ci /* parse mount options */ 238062306a36Sopenharmony_ci err = parse_options(sb, data, true); 238162306a36Sopenharmony_ci if (err) 238262306a36Sopenharmony_ci goto restore_opts; 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci /* flush outstanding errors before changing fs state */ 238562306a36Sopenharmony_ci flush_work(&sbi->s_error_work); 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci /* 238862306a36Sopenharmony_ci * Previous and new state of filesystem is RO, 238962306a36Sopenharmony_ci * so skip checking GC and FLUSH_MERGE conditions. 239062306a36Sopenharmony_ci */ 239162306a36Sopenharmony_ci if (f2fs_readonly(sb) && (*flags & SB_RDONLY)) 239262306a36Sopenharmony_ci goto skip; 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci if (f2fs_dev_is_readonly(sbi) && !(*flags & SB_RDONLY)) { 239562306a36Sopenharmony_ci err = -EROFS; 239662306a36Sopenharmony_ci goto restore_opts; 239762306a36Sopenharmony_ci } 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 240062306a36Sopenharmony_ci if (!f2fs_readonly(sb) && (*flags & SB_RDONLY)) { 240162306a36Sopenharmony_ci err = dquot_suspend(sb, -1); 240262306a36Sopenharmony_ci if (err < 0) 240362306a36Sopenharmony_ci goto restore_opts; 240462306a36Sopenharmony_ci } else if (f2fs_readonly(sb) && !(*flags & SB_RDONLY)) { 240562306a36Sopenharmony_ci /* dquot_resume needs RW */ 240662306a36Sopenharmony_ci sb->s_flags &= ~SB_RDONLY; 240762306a36Sopenharmony_ci if (sb_any_quota_suspended(sb)) { 240862306a36Sopenharmony_ci dquot_resume(sb, -1); 240962306a36Sopenharmony_ci } else if (f2fs_sb_has_quota_ino(sbi)) { 241062306a36Sopenharmony_ci err = f2fs_enable_quotas(sb); 241162306a36Sopenharmony_ci if (err) 241262306a36Sopenharmony_ci goto restore_opts; 241362306a36Sopenharmony_ci } 241462306a36Sopenharmony_ci } 241562306a36Sopenharmony_ci#endif 241662306a36Sopenharmony_ci if (f2fs_lfs_mode(sbi) && !IS_F2FS_IPU_DISABLE(sbi)) { 241762306a36Sopenharmony_ci err = -EINVAL; 241862306a36Sopenharmony_ci f2fs_warn(sbi, "LFS is not compatible with IPU"); 241962306a36Sopenharmony_ci goto restore_opts; 242062306a36Sopenharmony_ci } 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci /* disallow enable atgc dynamically */ 242362306a36Sopenharmony_ci if (no_atgc == !!test_opt(sbi, ATGC)) { 242462306a36Sopenharmony_ci err = -EINVAL; 242562306a36Sopenharmony_ci f2fs_warn(sbi, "switch atgc option is not allowed"); 242662306a36Sopenharmony_ci goto restore_opts; 242762306a36Sopenharmony_ci } 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci /* disallow enable/disable extent_cache dynamically */ 243062306a36Sopenharmony_ci if (no_read_extent_cache == !!test_opt(sbi, READ_EXTENT_CACHE)) { 243162306a36Sopenharmony_ci err = -EINVAL; 243262306a36Sopenharmony_ci f2fs_warn(sbi, "switch extent_cache option is not allowed"); 243362306a36Sopenharmony_ci goto restore_opts; 243462306a36Sopenharmony_ci } 243562306a36Sopenharmony_ci /* disallow enable/disable age extent_cache dynamically */ 243662306a36Sopenharmony_ci if (no_age_extent_cache == !!test_opt(sbi, AGE_EXTENT_CACHE)) { 243762306a36Sopenharmony_ci err = -EINVAL; 243862306a36Sopenharmony_ci f2fs_warn(sbi, "switch age_extent_cache option is not allowed"); 243962306a36Sopenharmony_ci goto restore_opts; 244062306a36Sopenharmony_ci } 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_ci if (no_io_align == !!F2FS_IO_ALIGNED(sbi)) { 244362306a36Sopenharmony_ci err = -EINVAL; 244462306a36Sopenharmony_ci f2fs_warn(sbi, "switch io_bits option is not allowed"); 244562306a36Sopenharmony_ci goto restore_opts; 244662306a36Sopenharmony_ci } 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci if (no_compress_cache == !!test_opt(sbi, COMPRESS_CACHE)) { 244962306a36Sopenharmony_ci err = -EINVAL; 245062306a36Sopenharmony_ci f2fs_warn(sbi, "switch compress_cache option is not allowed"); 245162306a36Sopenharmony_ci goto restore_opts; 245262306a36Sopenharmony_ci } 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci if (block_unit_discard != f2fs_block_unit_discard(sbi)) { 245562306a36Sopenharmony_ci err = -EINVAL; 245662306a36Sopenharmony_ci f2fs_warn(sbi, "switch discard_unit option is not allowed"); 245762306a36Sopenharmony_ci goto restore_opts; 245862306a36Sopenharmony_ci } 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ci if ((*flags & SB_RDONLY) && test_opt(sbi, DISABLE_CHECKPOINT)) { 246162306a36Sopenharmony_ci err = -EINVAL; 246262306a36Sopenharmony_ci f2fs_warn(sbi, "disabling checkpoint not compatible with read-only"); 246362306a36Sopenharmony_ci goto restore_opts; 246462306a36Sopenharmony_ci } 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_ci /* 246762306a36Sopenharmony_ci * We stop the GC thread if FS is mounted as RO 246862306a36Sopenharmony_ci * or if background_gc = off is passed in mount 246962306a36Sopenharmony_ci * option. Also sync the filesystem. 247062306a36Sopenharmony_ci */ 247162306a36Sopenharmony_ci if ((*flags & SB_RDONLY) || 247262306a36Sopenharmony_ci (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_OFF && 247362306a36Sopenharmony_ci !test_opt(sbi, GC_MERGE))) { 247462306a36Sopenharmony_ci if (sbi->gc_thread) { 247562306a36Sopenharmony_ci f2fs_stop_gc_thread(sbi); 247662306a36Sopenharmony_ci need_restart_gc = true; 247762306a36Sopenharmony_ci } 247862306a36Sopenharmony_ci } else if (!sbi->gc_thread) { 247962306a36Sopenharmony_ci err = f2fs_start_gc_thread(sbi); 248062306a36Sopenharmony_ci if (err) 248162306a36Sopenharmony_ci goto restore_opts; 248262306a36Sopenharmony_ci need_stop_gc = true; 248362306a36Sopenharmony_ci } 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ci if (*flags & SB_RDONLY) { 248662306a36Sopenharmony_ci sync_inodes_sb(sb); 248762306a36Sopenharmony_ci 248862306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_IS_DIRTY); 248962306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_IS_CLOSE); 249062306a36Sopenharmony_ci f2fs_sync_fs(sb, 1); 249162306a36Sopenharmony_ci clear_sbi_flag(sbi, SBI_IS_CLOSE); 249262306a36Sopenharmony_ci } 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_ci if ((*flags & SB_RDONLY) || test_opt(sbi, DISABLE_CHECKPOINT) || 249562306a36Sopenharmony_ci !test_opt(sbi, MERGE_CHECKPOINT)) { 249662306a36Sopenharmony_ci f2fs_stop_ckpt_thread(sbi); 249762306a36Sopenharmony_ci need_restart_ckpt = true; 249862306a36Sopenharmony_ci } else { 249962306a36Sopenharmony_ci /* Flush if the prevous checkpoint, if exists. */ 250062306a36Sopenharmony_ci f2fs_flush_ckpt_thread(sbi); 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci err = f2fs_start_ckpt_thread(sbi); 250362306a36Sopenharmony_ci if (err) { 250462306a36Sopenharmony_ci f2fs_err(sbi, 250562306a36Sopenharmony_ci "Failed to start F2FS issue_checkpoint_thread (%d)", 250662306a36Sopenharmony_ci err); 250762306a36Sopenharmony_ci goto restore_gc; 250862306a36Sopenharmony_ci } 250962306a36Sopenharmony_ci need_stop_ckpt = true; 251062306a36Sopenharmony_ci } 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci /* 251362306a36Sopenharmony_ci * We stop issue flush thread if FS is mounted as RO 251462306a36Sopenharmony_ci * or if flush_merge is not passed in mount option. 251562306a36Sopenharmony_ci */ 251662306a36Sopenharmony_ci if ((*flags & SB_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) { 251762306a36Sopenharmony_ci clear_opt(sbi, FLUSH_MERGE); 251862306a36Sopenharmony_ci f2fs_destroy_flush_cmd_control(sbi, false); 251962306a36Sopenharmony_ci need_restart_flush = true; 252062306a36Sopenharmony_ci } else { 252162306a36Sopenharmony_ci err = f2fs_create_flush_cmd_control(sbi); 252262306a36Sopenharmony_ci if (err) 252362306a36Sopenharmony_ci goto restore_ckpt; 252462306a36Sopenharmony_ci need_stop_flush = true; 252562306a36Sopenharmony_ci } 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci if (no_discard == !!test_opt(sbi, DISCARD)) { 252862306a36Sopenharmony_ci if (test_opt(sbi, DISCARD)) { 252962306a36Sopenharmony_ci err = f2fs_start_discard_thread(sbi); 253062306a36Sopenharmony_ci if (err) 253162306a36Sopenharmony_ci goto restore_flush; 253262306a36Sopenharmony_ci need_stop_discard = true; 253362306a36Sopenharmony_ci } else { 253462306a36Sopenharmony_ci f2fs_stop_discard_thread(sbi); 253562306a36Sopenharmony_ci f2fs_issue_discard_timeout(sbi); 253662306a36Sopenharmony_ci need_restart_discard = true; 253762306a36Sopenharmony_ci } 253862306a36Sopenharmony_ci } 253962306a36Sopenharmony_ci 254062306a36Sopenharmony_ci if (enable_checkpoint == !!test_opt(sbi, DISABLE_CHECKPOINT)) { 254162306a36Sopenharmony_ci if (test_opt(sbi, DISABLE_CHECKPOINT)) { 254262306a36Sopenharmony_ci err = f2fs_disable_checkpoint(sbi); 254362306a36Sopenharmony_ci if (err) 254462306a36Sopenharmony_ci goto restore_discard; 254562306a36Sopenharmony_ci } else { 254662306a36Sopenharmony_ci f2fs_enable_checkpoint(sbi); 254762306a36Sopenharmony_ci } 254862306a36Sopenharmony_ci } 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ciskip: 255162306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 255262306a36Sopenharmony_ci /* Release old quota file names */ 255362306a36Sopenharmony_ci for (i = 0; i < MAXQUOTAS; i++) 255462306a36Sopenharmony_ci kfree(org_mount_opt.s_qf_names[i]); 255562306a36Sopenharmony_ci#endif 255662306a36Sopenharmony_ci /* Update the POSIXACL Flag */ 255762306a36Sopenharmony_ci sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | 255862306a36Sopenharmony_ci (test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0); 255962306a36Sopenharmony_ci 256062306a36Sopenharmony_ci limit_reserve_root(sbi); 256162306a36Sopenharmony_ci adjust_unusable_cap_perc(sbi); 256262306a36Sopenharmony_ci *flags = (*flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME); 256362306a36Sopenharmony_ci return 0; 256462306a36Sopenharmony_cirestore_discard: 256562306a36Sopenharmony_ci if (need_restart_discard) { 256662306a36Sopenharmony_ci if (f2fs_start_discard_thread(sbi)) 256762306a36Sopenharmony_ci f2fs_warn(sbi, "discard has been stopped"); 256862306a36Sopenharmony_ci } else if (need_stop_discard) { 256962306a36Sopenharmony_ci f2fs_stop_discard_thread(sbi); 257062306a36Sopenharmony_ci } 257162306a36Sopenharmony_cirestore_flush: 257262306a36Sopenharmony_ci if (need_restart_flush) { 257362306a36Sopenharmony_ci if (f2fs_create_flush_cmd_control(sbi)) 257462306a36Sopenharmony_ci f2fs_warn(sbi, "background flush thread has stopped"); 257562306a36Sopenharmony_ci } else if (need_stop_flush) { 257662306a36Sopenharmony_ci clear_opt(sbi, FLUSH_MERGE); 257762306a36Sopenharmony_ci f2fs_destroy_flush_cmd_control(sbi, false); 257862306a36Sopenharmony_ci } 257962306a36Sopenharmony_cirestore_ckpt: 258062306a36Sopenharmony_ci if (need_restart_ckpt) { 258162306a36Sopenharmony_ci if (f2fs_start_ckpt_thread(sbi)) 258262306a36Sopenharmony_ci f2fs_warn(sbi, "background ckpt thread has stopped"); 258362306a36Sopenharmony_ci } else if (need_stop_ckpt) { 258462306a36Sopenharmony_ci f2fs_stop_ckpt_thread(sbi); 258562306a36Sopenharmony_ci } 258662306a36Sopenharmony_cirestore_gc: 258762306a36Sopenharmony_ci if (need_restart_gc) { 258862306a36Sopenharmony_ci if (f2fs_start_gc_thread(sbi)) 258962306a36Sopenharmony_ci f2fs_warn(sbi, "background gc thread has stopped"); 259062306a36Sopenharmony_ci } else if (need_stop_gc) { 259162306a36Sopenharmony_ci f2fs_stop_gc_thread(sbi); 259262306a36Sopenharmony_ci } 259362306a36Sopenharmony_cirestore_opts: 259462306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 259562306a36Sopenharmony_ci F2FS_OPTION(sbi).s_jquota_fmt = org_mount_opt.s_jquota_fmt; 259662306a36Sopenharmony_ci for (i = 0; i < MAXQUOTAS; i++) { 259762306a36Sopenharmony_ci kfree(F2FS_OPTION(sbi).s_qf_names[i]); 259862306a36Sopenharmony_ci F2FS_OPTION(sbi).s_qf_names[i] = org_mount_opt.s_qf_names[i]; 259962306a36Sopenharmony_ci } 260062306a36Sopenharmony_ci#endif 260162306a36Sopenharmony_ci sbi->mount_opt = org_mount_opt; 260262306a36Sopenharmony_ci sb->s_flags = old_sb_flags; 260362306a36Sopenharmony_ci return err; 260462306a36Sopenharmony_ci} 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 260762306a36Sopenharmony_cistatic bool f2fs_need_recovery(struct f2fs_sb_info *sbi) 260862306a36Sopenharmony_ci{ 260962306a36Sopenharmony_ci /* need to recovery orphan */ 261062306a36Sopenharmony_ci if (is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG)) 261162306a36Sopenharmony_ci return true; 261262306a36Sopenharmony_ci /* need to recovery data */ 261362306a36Sopenharmony_ci if (test_opt(sbi, DISABLE_ROLL_FORWARD)) 261462306a36Sopenharmony_ci return false; 261562306a36Sopenharmony_ci if (test_opt(sbi, NORECOVERY)) 261662306a36Sopenharmony_ci return false; 261762306a36Sopenharmony_ci return !is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG); 261862306a36Sopenharmony_ci} 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_cistatic bool f2fs_recover_quota_begin(struct f2fs_sb_info *sbi) 262162306a36Sopenharmony_ci{ 262262306a36Sopenharmony_ci bool readonly = f2fs_readonly(sbi->sb); 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci if (!f2fs_need_recovery(sbi)) 262562306a36Sopenharmony_ci return false; 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci /* it doesn't need to check f2fs_sb_has_readonly() */ 262862306a36Sopenharmony_ci if (f2fs_hw_is_readonly(sbi)) 262962306a36Sopenharmony_ci return false; 263062306a36Sopenharmony_ci 263162306a36Sopenharmony_ci if (readonly) { 263262306a36Sopenharmony_ci sbi->sb->s_flags &= ~SB_RDONLY; 263362306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_IS_WRITABLE); 263462306a36Sopenharmony_ci } 263562306a36Sopenharmony_ci 263662306a36Sopenharmony_ci /* 263762306a36Sopenharmony_ci * Turn on quotas which were not enabled for read-only mounts if 263862306a36Sopenharmony_ci * filesystem has quota feature, so that they are updated correctly. 263962306a36Sopenharmony_ci */ 264062306a36Sopenharmony_ci return f2fs_enable_quota_files(sbi, readonly); 264162306a36Sopenharmony_ci} 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_cistatic void f2fs_recover_quota_end(struct f2fs_sb_info *sbi, 264462306a36Sopenharmony_ci bool quota_enabled) 264562306a36Sopenharmony_ci{ 264662306a36Sopenharmony_ci if (quota_enabled) 264762306a36Sopenharmony_ci f2fs_quota_off_umount(sbi->sb); 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_IS_WRITABLE)) { 265062306a36Sopenharmony_ci clear_sbi_flag(sbi, SBI_IS_WRITABLE); 265162306a36Sopenharmony_ci sbi->sb->s_flags |= SB_RDONLY; 265262306a36Sopenharmony_ci } 265362306a36Sopenharmony_ci} 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci/* Read data from quotafile */ 265662306a36Sopenharmony_cistatic ssize_t f2fs_quota_read(struct super_block *sb, int type, char *data, 265762306a36Sopenharmony_ci size_t len, loff_t off) 265862306a36Sopenharmony_ci{ 265962306a36Sopenharmony_ci struct inode *inode = sb_dqopt(sb)->files[type]; 266062306a36Sopenharmony_ci struct address_space *mapping = inode->i_mapping; 266162306a36Sopenharmony_ci block_t blkidx = F2FS_BYTES_TO_BLK(off); 266262306a36Sopenharmony_ci int offset = off & (sb->s_blocksize - 1); 266362306a36Sopenharmony_ci int tocopy; 266462306a36Sopenharmony_ci size_t toread; 266562306a36Sopenharmony_ci loff_t i_size = i_size_read(inode); 266662306a36Sopenharmony_ci struct page *page; 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_ci if (off > i_size) 266962306a36Sopenharmony_ci return 0; 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_ci if (off + len > i_size) 267262306a36Sopenharmony_ci len = i_size - off; 267362306a36Sopenharmony_ci toread = len; 267462306a36Sopenharmony_ci while (toread > 0) { 267562306a36Sopenharmony_ci tocopy = min_t(unsigned long, sb->s_blocksize - offset, toread); 267662306a36Sopenharmony_cirepeat: 267762306a36Sopenharmony_ci page = read_cache_page_gfp(mapping, blkidx, GFP_NOFS); 267862306a36Sopenharmony_ci if (IS_ERR(page)) { 267962306a36Sopenharmony_ci if (PTR_ERR(page) == -ENOMEM) { 268062306a36Sopenharmony_ci memalloc_retry_wait(GFP_NOFS); 268162306a36Sopenharmony_ci goto repeat; 268262306a36Sopenharmony_ci } 268362306a36Sopenharmony_ci set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR); 268462306a36Sopenharmony_ci return PTR_ERR(page); 268562306a36Sopenharmony_ci } 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci lock_page(page); 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_ci if (unlikely(page->mapping != mapping)) { 269062306a36Sopenharmony_ci f2fs_put_page(page, 1); 269162306a36Sopenharmony_ci goto repeat; 269262306a36Sopenharmony_ci } 269362306a36Sopenharmony_ci if (unlikely(!PageUptodate(page))) { 269462306a36Sopenharmony_ci f2fs_put_page(page, 1); 269562306a36Sopenharmony_ci set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR); 269662306a36Sopenharmony_ci return -EIO; 269762306a36Sopenharmony_ci } 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_ci memcpy_from_page(data, page, offset, tocopy); 270062306a36Sopenharmony_ci f2fs_put_page(page, 1); 270162306a36Sopenharmony_ci 270262306a36Sopenharmony_ci offset = 0; 270362306a36Sopenharmony_ci toread -= tocopy; 270462306a36Sopenharmony_ci data += tocopy; 270562306a36Sopenharmony_ci blkidx++; 270662306a36Sopenharmony_ci } 270762306a36Sopenharmony_ci return len; 270862306a36Sopenharmony_ci} 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci/* Write to quotafile */ 271162306a36Sopenharmony_cistatic ssize_t f2fs_quota_write(struct super_block *sb, int type, 271262306a36Sopenharmony_ci const char *data, size_t len, loff_t off) 271362306a36Sopenharmony_ci{ 271462306a36Sopenharmony_ci struct inode *inode = sb_dqopt(sb)->files[type]; 271562306a36Sopenharmony_ci struct address_space *mapping = inode->i_mapping; 271662306a36Sopenharmony_ci const struct address_space_operations *a_ops = mapping->a_ops; 271762306a36Sopenharmony_ci int offset = off & (sb->s_blocksize - 1); 271862306a36Sopenharmony_ci size_t towrite = len; 271962306a36Sopenharmony_ci struct page *page; 272062306a36Sopenharmony_ci void *fsdata = NULL; 272162306a36Sopenharmony_ci int err = 0; 272262306a36Sopenharmony_ci int tocopy; 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci while (towrite > 0) { 272562306a36Sopenharmony_ci tocopy = min_t(unsigned long, sb->s_blocksize - offset, 272662306a36Sopenharmony_ci towrite); 272762306a36Sopenharmony_ciretry: 272862306a36Sopenharmony_ci err = a_ops->write_begin(NULL, mapping, off, tocopy, 272962306a36Sopenharmony_ci &page, &fsdata); 273062306a36Sopenharmony_ci if (unlikely(err)) { 273162306a36Sopenharmony_ci if (err == -ENOMEM) { 273262306a36Sopenharmony_ci f2fs_io_schedule_timeout(DEFAULT_IO_TIMEOUT); 273362306a36Sopenharmony_ci goto retry; 273462306a36Sopenharmony_ci } 273562306a36Sopenharmony_ci set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR); 273662306a36Sopenharmony_ci break; 273762306a36Sopenharmony_ci } 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci memcpy_to_page(page, offset, data, tocopy); 274062306a36Sopenharmony_ci 274162306a36Sopenharmony_ci a_ops->write_end(NULL, mapping, off, tocopy, tocopy, 274262306a36Sopenharmony_ci page, fsdata); 274362306a36Sopenharmony_ci offset = 0; 274462306a36Sopenharmony_ci towrite -= tocopy; 274562306a36Sopenharmony_ci off += tocopy; 274662306a36Sopenharmony_ci data += tocopy; 274762306a36Sopenharmony_ci cond_resched(); 274862306a36Sopenharmony_ci } 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_ci if (len == towrite) 275162306a36Sopenharmony_ci return err; 275262306a36Sopenharmony_ci inode->i_mtime = inode_set_ctime_current(inode); 275362306a36Sopenharmony_ci f2fs_mark_inode_dirty_sync(inode, false); 275462306a36Sopenharmony_ci return len - towrite; 275562306a36Sopenharmony_ci} 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ciint f2fs_dquot_initialize(struct inode *inode) 275862306a36Sopenharmony_ci{ 275962306a36Sopenharmony_ci if (time_to_inject(F2FS_I_SB(inode), FAULT_DQUOT_INIT)) 276062306a36Sopenharmony_ci return -ESRCH; 276162306a36Sopenharmony_ci 276262306a36Sopenharmony_ci return dquot_initialize(inode); 276362306a36Sopenharmony_ci} 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_cistatic struct dquot __rcu **f2fs_get_dquots(struct inode *inode) 276662306a36Sopenharmony_ci{ 276762306a36Sopenharmony_ci return F2FS_I(inode)->i_dquot; 276862306a36Sopenharmony_ci} 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_cistatic qsize_t *f2fs_get_reserved_space(struct inode *inode) 277162306a36Sopenharmony_ci{ 277262306a36Sopenharmony_ci return &F2FS_I(inode)->i_reserved_quota; 277362306a36Sopenharmony_ci} 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_cistatic int f2fs_quota_on_mount(struct f2fs_sb_info *sbi, int type) 277662306a36Sopenharmony_ci{ 277762306a36Sopenharmony_ci if (is_set_ckpt_flags(sbi, CP_QUOTA_NEED_FSCK_FLAG)) { 277862306a36Sopenharmony_ci f2fs_err(sbi, "quota sysfile may be corrupted, skip loading it"); 277962306a36Sopenharmony_ci return 0; 278062306a36Sopenharmony_ci } 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci return dquot_quota_on_mount(sbi->sb, F2FS_OPTION(sbi).s_qf_names[type], 278362306a36Sopenharmony_ci F2FS_OPTION(sbi).s_jquota_fmt, type); 278462306a36Sopenharmony_ci} 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ciint f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly) 278762306a36Sopenharmony_ci{ 278862306a36Sopenharmony_ci int enabled = 0; 278962306a36Sopenharmony_ci int i, err; 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci if (f2fs_sb_has_quota_ino(sbi) && rdonly) { 279262306a36Sopenharmony_ci err = f2fs_enable_quotas(sbi->sb); 279362306a36Sopenharmony_ci if (err) { 279462306a36Sopenharmony_ci f2fs_err(sbi, "Cannot turn on quota_ino: %d", err); 279562306a36Sopenharmony_ci return 0; 279662306a36Sopenharmony_ci } 279762306a36Sopenharmony_ci return 1; 279862306a36Sopenharmony_ci } 279962306a36Sopenharmony_ci 280062306a36Sopenharmony_ci for (i = 0; i < MAXQUOTAS; i++) { 280162306a36Sopenharmony_ci if (F2FS_OPTION(sbi).s_qf_names[i]) { 280262306a36Sopenharmony_ci err = f2fs_quota_on_mount(sbi, i); 280362306a36Sopenharmony_ci if (!err) { 280462306a36Sopenharmony_ci enabled = 1; 280562306a36Sopenharmony_ci continue; 280662306a36Sopenharmony_ci } 280762306a36Sopenharmony_ci f2fs_err(sbi, "Cannot turn on quotas: %d on %d", 280862306a36Sopenharmony_ci err, i); 280962306a36Sopenharmony_ci } 281062306a36Sopenharmony_ci } 281162306a36Sopenharmony_ci return enabled; 281262306a36Sopenharmony_ci} 281362306a36Sopenharmony_ci 281462306a36Sopenharmony_cistatic int f2fs_quota_enable(struct super_block *sb, int type, int format_id, 281562306a36Sopenharmony_ci unsigned int flags) 281662306a36Sopenharmony_ci{ 281762306a36Sopenharmony_ci struct inode *qf_inode; 281862306a36Sopenharmony_ci unsigned long qf_inum; 281962306a36Sopenharmony_ci unsigned long qf_flag = F2FS_QUOTA_DEFAULT_FL; 282062306a36Sopenharmony_ci int err; 282162306a36Sopenharmony_ci 282262306a36Sopenharmony_ci BUG_ON(!f2fs_sb_has_quota_ino(F2FS_SB(sb))); 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci qf_inum = f2fs_qf_ino(sb, type); 282562306a36Sopenharmony_ci if (!qf_inum) 282662306a36Sopenharmony_ci return -EPERM; 282762306a36Sopenharmony_ci 282862306a36Sopenharmony_ci qf_inode = f2fs_iget(sb, qf_inum); 282962306a36Sopenharmony_ci if (IS_ERR(qf_inode)) { 283062306a36Sopenharmony_ci f2fs_err(F2FS_SB(sb), "Bad quota inode %u:%lu", type, qf_inum); 283162306a36Sopenharmony_ci return PTR_ERR(qf_inode); 283262306a36Sopenharmony_ci } 283362306a36Sopenharmony_ci 283462306a36Sopenharmony_ci /* Don't account quota for quota files to avoid recursion */ 283562306a36Sopenharmony_ci inode_lock(qf_inode); 283662306a36Sopenharmony_ci qf_inode->i_flags |= S_NOQUOTA; 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_ci if ((F2FS_I(qf_inode)->i_flags & qf_flag) != qf_flag) { 283962306a36Sopenharmony_ci F2FS_I(qf_inode)->i_flags |= qf_flag; 284062306a36Sopenharmony_ci f2fs_set_inode_flags(qf_inode); 284162306a36Sopenharmony_ci } 284262306a36Sopenharmony_ci inode_unlock(qf_inode); 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci err = dquot_load_quota_inode(qf_inode, type, format_id, flags); 284562306a36Sopenharmony_ci iput(qf_inode); 284662306a36Sopenharmony_ci return err; 284762306a36Sopenharmony_ci} 284862306a36Sopenharmony_ci 284962306a36Sopenharmony_cistatic int f2fs_enable_quotas(struct super_block *sb) 285062306a36Sopenharmony_ci{ 285162306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 285262306a36Sopenharmony_ci int type, err = 0; 285362306a36Sopenharmony_ci unsigned long qf_inum; 285462306a36Sopenharmony_ci bool quota_mopt[MAXQUOTAS] = { 285562306a36Sopenharmony_ci test_opt(sbi, USRQUOTA), 285662306a36Sopenharmony_ci test_opt(sbi, GRPQUOTA), 285762306a36Sopenharmony_ci test_opt(sbi, PRJQUOTA), 285862306a36Sopenharmony_ci }; 285962306a36Sopenharmony_ci 286062306a36Sopenharmony_ci if (is_set_ckpt_flags(F2FS_SB(sb), CP_QUOTA_NEED_FSCK_FLAG)) { 286162306a36Sopenharmony_ci f2fs_err(sbi, "quota file may be corrupted, skip loading it"); 286262306a36Sopenharmony_ci return 0; 286362306a36Sopenharmony_ci } 286462306a36Sopenharmony_ci 286562306a36Sopenharmony_ci sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE; 286662306a36Sopenharmony_ci 286762306a36Sopenharmony_ci for (type = 0; type < MAXQUOTAS; type++) { 286862306a36Sopenharmony_ci qf_inum = f2fs_qf_ino(sb, type); 286962306a36Sopenharmony_ci if (qf_inum) { 287062306a36Sopenharmony_ci err = f2fs_quota_enable(sb, type, QFMT_VFS_V1, 287162306a36Sopenharmony_ci DQUOT_USAGE_ENABLED | 287262306a36Sopenharmony_ci (quota_mopt[type] ? DQUOT_LIMITS_ENABLED : 0)); 287362306a36Sopenharmony_ci if (err) { 287462306a36Sopenharmony_ci f2fs_err(sbi, "Failed to enable quota tracking (type=%d, err=%d). Please run fsck to fix.", 287562306a36Sopenharmony_ci type, err); 287662306a36Sopenharmony_ci for (type--; type >= 0; type--) 287762306a36Sopenharmony_ci dquot_quota_off(sb, type); 287862306a36Sopenharmony_ci set_sbi_flag(F2FS_SB(sb), 287962306a36Sopenharmony_ci SBI_QUOTA_NEED_REPAIR); 288062306a36Sopenharmony_ci return err; 288162306a36Sopenharmony_ci } 288262306a36Sopenharmony_ci } 288362306a36Sopenharmony_ci } 288462306a36Sopenharmony_ci return 0; 288562306a36Sopenharmony_ci} 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_cistatic int f2fs_quota_sync_file(struct f2fs_sb_info *sbi, int type) 288862306a36Sopenharmony_ci{ 288962306a36Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(sbi->sb); 289062306a36Sopenharmony_ci struct address_space *mapping = dqopt->files[type]->i_mapping; 289162306a36Sopenharmony_ci int ret = 0; 289262306a36Sopenharmony_ci 289362306a36Sopenharmony_ci ret = dquot_writeback_dquots(sbi->sb, type); 289462306a36Sopenharmony_ci if (ret) 289562306a36Sopenharmony_ci goto out; 289662306a36Sopenharmony_ci 289762306a36Sopenharmony_ci ret = filemap_fdatawrite(mapping); 289862306a36Sopenharmony_ci if (ret) 289962306a36Sopenharmony_ci goto out; 290062306a36Sopenharmony_ci 290162306a36Sopenharmony_ci /* if we are using journalled quota */ 290262306a36Sopenharmony_ci if (is_journalled_quota(sbi)) 290362306a36Sopenharmony_ci goto out; 290462306a36Sopenharmony_ci 290562306a36Sopenharmony_ci ret = filemap_fdatawait(mapping); 290662306a36Sopenharmony_ci 290762306a36Sopenharmony_ci truncate_inode_pages(&dqopt->files[type]->i_data, 0); 290862306a36Sopenharmony_ciout: 290962306a36Sopenharmony_ci if (ret) 291062306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); 291162306a36Sopenharmony_ci return ret; 291262306a36Sopenharmony_ci} 291362306a36Sopenharmony_ci 291462306a36Sopenharmony_ciint f2fs_quota_sync(struct super_block *sb, int type) 291562306a36Sopenharmony_ci{ 291662306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 291762306a36Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(sb); 291862306a36Sopenharmony_ci int cnt; 291962306a36Sopenharmony_ci int ret = 0; 292062306a36Sopenharmony_ci 292162306a36Sopenharmony_ci /* 292262306a36Sopenharmony_ci * Now when everything is written we can discard the pagecache so 292362306a36Sopenharmony_ci * that userspace sees the changes. 292462306a36Sopenharmony_ci */ 292562306a36Sopenharmony_ci for (cnt = 0; cnt < MAXQUOTAS; cnt++) { 292662306a36Sopenharmony_ci 292762306a36Sopenharmony_ci if (type != -1 && cnt != type) 292862306a36Sopenharmony_ci continue; 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci if (!sb_has_quota_active(sb, cnt)) 293162306a36Sopenharmony_ci continue; 293262306a36Sopenharmony_ci 293362306a36Sopenharmony_ci if (!f2fs_sb_has_quota_ino(sbi)) 293462306a36Sopenharmony_ci inode_lock(dqopt->files[cnt]); 293562306a36Sopenharmony_ci 293662306a36Sopenharmony_ci /* 293762306a36Sopenharmony_ci * do_quotactl 293862306a36Sopenharmony_ci * f2fs_quota_sync 293962306a36Sopenharmony_ci * f2fs_down_read(quota_sem) 294062306a36Sopenharmony_ci * dquot_writeback_dquots() 294162306a36Sopenharmony_ci * f2fs_dquot_commit 294262306a36Sopenharmony_ci * block_operation 294362306a36Sopenharmony_ci * f2fs_down_read(quota_sem) 294462306a36Sopenharmony_ci */ 294562306a36Sopenharmony_ci f2fs_lock_op(sbi); 294662306a36Sopenharmony_ci f2fs_down_read(&sbi->quota_sem); 294762306a36Sopenharmony_ci 294862306a36Sopenharmony_ci ret = f2fs_quota_sync_file(sbi, cnt); 294962306a36Sopenharmony_ci 295062306a36Sopenharmony_ci f2fs_up_read(&sbi->quota_sem); 295162306a36Sopenharmony_ci f2fs_unlock_op(sbi); 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci if (!f2fs_sb_has_quota_ino(sbi)) 295462306a36Sopenharmony_ci inode_unlock(dqopt->files[cnt]); 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ci if (ret) 295762306a36Sopenharmony_ci break; 295862306a36Sopenharmony_ci } 295962306a36Sopenharmony_ci return ret; 296062306a36Sopenharmony_ci} 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_cistatic int f2fs_quota_on(struct super_block *sb, int type, int format_id, 296362306a36Sopenharmony_ci const struct path *path) 296462306a36Sopenharmony_ci{ 296562306a36Sopenharmony_ci struct inode *inode; 296662306a36Sopenharmony_ci int err; 296762306a36Sopenharmony_ci 296862306a36Sopenharmony_ci /* if quota sysfile exists, deny enabling quota with specific file */ 296962306a36Sopenharmony_ci if (f2fs_sb_has_quota_ino(F2FS_SB(sb))) { 297062306a36Sopenharmony_ci f2fs_err(F2FS_SB(sb), "quota sysfile already exists"); 297162306a36Sopenharmony_ci return -EBUSY; 297262306a36Sopenharmony_ci } 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci if (path->dentry->d_sb != sb) 297562306a36Sopenharmony_ci return -EXDEV; 297662306a36Sopenharmony_ci 297762306a36Sopenharmony_ci err = f2fs_quota_sync(sb, type); 297862306a36Sopenharmony_ci if (err) 297962306a36Sopenharmony_ci return err; 298062306a36Sopenharmony_ci 298162306a36Sopenharmony_ci inode = d_inode(path->dentry); 298262306a36Sopenharmony_ci 298362306a36Sopenharmony_ci err = filemap_fdatawrite(inode->i_mapping); 298462306a36Sopenharmony_ci if (err) 298562306a36Sopenharmony_ci return err; 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci err = filemap_fdatawait(inode->i_mapping); 298862306a36Sopenharmony_ci if (err) 298962306a36Sopenharmony_ci return err; 299062306a36Sopenharmony_ci 299162306a36Sopenharmony_ci err = dquot_quota_on(sb, type, format_id, path); 299262306a36Sopenharmony_ci if (err) 299362306a36Sopenharmony_ci return err; 299462306a36Sopenharmony_ci 299562306a36Sopenharmony_ci inode_lock(inode); 299662306a36Sopenharmony_ci F2FS_I(inode)->i_flags |= F2FS_QUOTA_DEFAULT_FL; 299762306a36Sopenharmony_ci f2fs_set_inode_flags(inode); 299862306a36Sopenharmony_ci inode_unlock(inode); 299962306a36Sopenharmony_ci f2fs_mark_inode_dirty_sync(inode, false); 300062306a36Sopenharmony_ci 300162306a36Sopenharmony_ci return 0; 300262306a36Sopenharmony_ci} 300362306a36Sopenharmony_ci 300462306a36Sopenharmony_cistatic int __f2fs_quota_off(struct super_block *sb, int type) 300562306a36Sopenharmony_ci{ 300662306a36Sopenharmony_ci struct inode *inode = sb_dqopt(sb)->files[type]; 300762306a36Sopenharmony_ci int err; 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_ci if (!inode || !igrab(inode)) 301062306a36Sopenharmony_ci return dquot_quota_off(sb, type); 301162306a36Sopenharmony_ci 301262306a36Sopenharmony_ci err = f2fs_quota_sync(sb, type); 301362306a36Sopenharmony_ci if (err) 301462306a36Sopenharmony_ci goto out_put; 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_ci err = dquot_quota_off(sb, type); 301762306a36Sopenharmony_ci if (err || f2fs_sb_has_quota_ino(F2FS_SB(sb))) 301862306a36Sopenharmony_ci goto out_put; 301962306a36Sopenharmony_ci 302062306a36Sopenharmony_ci inode_lock(inode); 302162306a36Sopenharmony_ci F2FS_I(inode)->i_flags &= ~F2FS_QUOTA_DEFAULT_FL; 302262306a36Sopenharmony_ci f2fs_set_inode_flags(inode); 302362306a36Sopenharmony_ci inode_unlock(inode); 302462306a36Sopenharmony_ci f2fs_mark_inode_dirty_sync(inode, false); 302562306a36Sopenharmony_ciout_put: 302662306a36Sopenharmony_ci iput(inode); 302762306a36Sopenharmony_ci return err; 302862306a36Sopenharmony_ci} 302962306a36Sopenharmony_ci 303062306a36Sopenharmony_cistatic int f2fs_quota_off(struct super_block *sb, int type) 303162306a36Sopenharmony_ci{ 303262306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 303362306a36Sopenharmony_ci int err; 303462306a36Sopenharmony_ci 303562306a36Sopenharmony_ci err = __f2fs_quota_off(sb, type); 303662306a36Sopenharmony_ci 303762306a36Sopenharmony_ci /* 303862306a36Sopenharmony_ci * quotactl can shutdown journalled quota, result in inconsistence 303962306a36Sopenharmony_ci * between quota record and fs data by following updates, tag the 304062306a36Sopenharmony_ci * flag to let fsck be aware of it. 304162306a36Sopenharmony_ci */ 304262306a36Sopenharmony_ci if (is_journalled_quota(sbi)) 304362306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); 304462306a36Sopenharmony_ci return err; 304562306a36Sopenharmony_ci} 304662306a36Sopenharmony_ci 304762306a36Sopenharmony_civoid f2fs_quota_off_umount(struct super_block *sb) 304862306a36Sopenharmony_ci{ 304962306a36Sopenharmony_ci int type; 305062306a36Sopenharmony_ci int err; 305162306a36Sopenharmony_ci 305262306a36Sopenharmony_ci for (type = 0; type < MAXQUOTAS; type++) { 305362306a36Sopenharmony_ci err = __f2fs_quota_off(sb, type); 305462306a36Sopenharmony_ci if (err) { 305562306a36Sopenharmony_ci int ret = dquot_quota_off(sb, type); 305662306a36Sopenharmony_ci 305762306a36Sopenharmony_ci f2fs_err(F2FS_SB(sb), "Fail to turn off disk quota (type: %d, err: %d, ret:%d), Please run fsck to fix it.", 305862306a36Sopenharmony_ci type, err, ret); 305962306a36Sopenharmony_ci set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR); 306062306a36Sopenharmony_ci } 306162306a36Sopenharmony_ci } 306262306a36Sopenharmony_ci /* 306362306a36Sopenharmony_ci * In case of checkpoint=disable, we must flush quota blocks. 306462306a36Sopenharmony_ci * This can cause NULL exception for node_inode in end_io, since 306562306a36Sopenharmony_ci * put_super already dropped it. 306662306a36Sopenharmony_ci */ 306762306a36Sopenharmony_ci sync_filesystem(sb); 306862306a36Sopenharmony_ci} 306962306a36Sopenharmony_ci 307062306a36Sopenharmony_cistatic void f2fs_truncate_quota_inode_pages(struct super_block *sb) 307162306a36Sopenharmony_ci{ 307262306a36Sopenharmony_ci struct quota_info *dqopt = sb_dqopt(sb); 307362306a36Sopenharmony_ci int type; 307462306a36Sopenharmony_ci 307562306a36Sopenharmony_ci for (type = 0; type < MAXQUOTAS; type++) { 307662306a36Sopenharmony_ci if (!dqopt->files[type]) 307762306a36Sopenharmony_ci continue; 307862306a36Sopenharmony_ci f2fs_inode_synced(dqopt->files[type]); 307962306a36Sopenharmony_ci } 308062306a36Sopenharmony_ci} 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_cistatic int f2fs_dquot_commit(struct dquot *dquot) 308362306a36Sopenharmony_ci{ 308462306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb); 308562306a36Sopenharmony_ci int ret; 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ci f2fs_down_read_nested(&sbi->quota_sem, SINGLE_DEPTH_NESTING); 308862306a36Sopenharmony_ci ret = dquot_commit(dquot); 308962306a36Sopenharmony_ci if (ret < 0) 309062306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); 309162306a36Sopenharmony_ci f2fs_up_read(&sbi->quota_sem); 309262306a36Sopenharmony_ci return ret; 309362306a36Sopenharmony_ci} 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_cistatic int f2fs_dquot_acquire(struct dquot *dquot) 309662306a36Sopenharmony_ci{ 309762306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb); 309862306a36Sopenharmony_ci int ret; 309962306a36Sopenharmony_ci 310062306a36Sopenharmony_ci f2fs_down_read(&sbi->quota_sem); 310162306a36Sopenharmony_ci ret = dquot_acquire(dquot); 310262306a36Sopenharmony_ci if (ret < 0) 310362306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); 310462306a36Sopenharmony_ci f2fs_up_read(&sbi->quota_sem); 310562306a36Sopenharmony_ci return ret; 310662306a36Sopenharmony_ci} 310762306a36Sopenharmony_ci 310862306a36Sopenharmony_cistatic int f2fs_dquot_release(struct dquot *dquot) 310962306a36Sopenharmony_ci{ 311062306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb); 311162306a36Sopenharmony_ci int ret = dquot_release(dquot); 311262306a36Sopenharmony_ci 311362306a36Sopenharmony_ci if (ret < 0) 311462306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); 311562306a36Sopenharmony_ci return ret; 311662306a36Sopenharmony_ci} 311762306a36Sopenharmony_ci 311862306a36Sopenharmony_cistatic int f2fs_dquot_mark_dquot_dirty(struct dquot *dquot) 311962306a36Sopenharmony_ci{ 312062306a36Sopenharmony_ci struct super_block *sb = dquot->dq_sb; 312162306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 312262306a36Sopenharmony_ci int ret = dquot_mark_dquot_dirty(dquot); 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_ci /* if we are using journalled quota */ 312562306a36Sopenharmony_ci if (is_journalled_quota(sbi)) 312662306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH); 312762306a36Sopenharmony_ci 312862306a36Sopenharmony_ci return ret; 312962306a36Sopenharmony_ci} 313062306a36Sopenharmony_ci 313162306a36Sopenharmony_cistatic int f2fs_dquot_commit_info(struct super_block *sb, int type) 313262306a36Sopenharmony_ci{ 313362306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 313462306a36Sopenharmony_ci int ret = dquot_commit_info(sb, type); 313562306a36Sopenharmony_ci 313662306a36Sopenharmony_ci if (ret < 0) 313762306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); 313862306a36Sopenharmony_ci return ret; 313962306a36Sopenharmony_ci} 314062306a36Sopenharmony_ci 314162306a36Sopenharmony_cistatic int f2fs_get_projid(struct inode *inode, kprojid_t *projid) 314262306a36Sopenharmony_ci{ 314362306a36Sopenharmony_ci *projid = F2FS_I(inode)->i_projid; 314462306a36Sopenharmony_ci return 0; 314562306a36Sopenharmony_ci} 314662306a36Sopenharmony_ci 314762306a36Sopenharmony_cistatic const struct dquot_operations f2fs_quota_operations = { 314862306a36Sopenharmony_ci .get_reserved_space = f2fs_get_reserved_space, 314962306a36Sopenharmony_ci .write_dquot = f2fs_dquot_commit, 315062306a36Sopenharmony_ci .acquire_dquot = f2fs_dquot_acquire, 315162306a36Sopenharmony_ci .release_dquot = f2fs_dquot_release, 315262306a36Sopenharmony_ci .mark_dirty = f2fs_dquot_mark_dquot_dirty, 315362306a36Sopenharmony_ci .write_info = f2fs_dquot_commit_info, 315462306a36Sopenharmony_ci .alloc_dquot = dquot_alloc, 315562306a36Sopenharmony_ci .destroy_dquot = dquot_destroy, 315662306a36Sopenharmony_ci .get_projid = f2fs_get_projid, 315762306a36Sopenharmony_ci .get_next_id = dquot_get_next_id, 315862306a36Sopenharmony_ci}; 315962306a36Sopenharmony_ci 316062306a36Sopenharmony_cistatic const struct quotactl_ops f2fs_quotactl_ops = { 316162306a36Sopenharmony_ci .quota_on = f2fs_quota_on, 316262306a36Sopenharmony_ci .quota_off = f2fs_quota_off, 316362306a36Sopenharmony_ci .quota_sync = f2fs_quota_sync, 316462306a36Sopenharmony_ci .get_state = dquot_get_state, 316562306a36Sopenharmony_ci .set_info = dquot_set_dqinfo, 316662306a36Sopenharmony_ci .get_dqblk = dquot_get_dqblk, 316762306a36Sopenharmony_ci .set_dqblk = dquot_set_dqblk, 316862306a36Sopenharmony_ci .get_nextdqblk = dquot_get_next_dqblk, 316962306a36Sopenharmony_ci}; 317062306a36Sopenharmony_ci#else 317162306a36Sopenharmony_ciint f2fs_dquot_initialize(struct inode *inode) 317262306a36Sopenharmony_ci{ 317362306a36Sopenharmony_ci return 0; 317462306a36Sopenharmony_ci} 317562306a36Sopenharmony_ci 317662306a36Sopenharmony_ciint f2fs_quota_sync(struct super_block *sb, int type) 317762306a36Sopenharmony_ci{ 317862306a36Sopenharmony_ci return 0; 317962306a36Sopenharmony_ci} 318062306a36Sopenharmony_ci 318162306a36Sopenharmony_civoid f2fs_quota_off_umount(struct super_block *sb) 318262306a36Sopenharmony_ci{ 318362306a36Sopenharmony_ci} 318462306a36Sopenharmony_ci#endif 318562306a36Sopenharmony_ci 318662306a36Sopenharmony_cistatic const struct super_operations f2fs_sops = { 318762306a36Sopenharmony_ci .alloc_inode = f2fs_alloc_inode, 318862306a36Sopenharmony_ci .free_inode = f2fs_free_inode, 318962306a36Sopenharmony_ci .drop_inode = f2fs_drop_inode, 319062306a36Sopenharmony_ci .write_inode = f2fs_write_inode, 319162306a36Sopenharmony_ci .dirty_inode = f2fs_dirty_inode, 319262306a36Sopenharmony_ci .show_options = f2fs_show_options, 319362306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 319462306a36Sopenharmony_ci .quota_read = f2fs_quota_read, 319562306a36Sopenharmony_ci .quota_write = f2fs_quota_write, 319662306a36Sopenharmony_ci .get_dquots = f2fs_get_dquots, 319762306a36Sopenharmony_ci#endif 319862306a36Sopenharmony_ci .evict_inode = f2fs_evict_inode, 319962306a36Sopenharmony_ci .put_super = f2fs_put_super, 320062306a36Sopenharmony_ci .sync_fs = f2fs_sync_fs, 320162306a36Sopenharmony_ci .freeze_fs = f2fs_freeze, 320262306a36Sopenharmony_ci .unfreeze_fs = f2fs_unfreeze, 320362306a36Sopenharmony_ci .statfs = f2fs_statfs, 320462306a36Sopenharmony_ci .remount_fs = f2fs_remount, 320562306a36Sopenharmony_ci}; 320662306a36Sopenharmony_ci 320762306a36Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION 320862306a36Sopenharmony_cistatic int f2fs_get_context(struct inode *inode, void *ctx, size_t len) 320962306a36Sopenharmony_ci{ 321062306a36Sopenharmony_ci return f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, 321162306a36Sopenharmony_ci F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, 321262306a36Sopenharmony_ci ctx, len, NULL); 321362306a36Sopenharmony_ci} 321462306a36Sopenharmony_ci 321562306a36Sopenharmony_cistatic int f2fs_set_context(struct inode *inode, const void *ctx, size_t len, 321662306a36Sopenharmony_ci void *fs_data) 321762306a36Sopenharmony_ci{ 321862306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 321962306a36Sopenharmony_ci 322062306a36Sopenharmony_ci /* 322162306a36Sopenharmony_ci * Encrypting the root directory is not allowed because fsck 322262306a36Sopenharmony_ci * expects lost+found directory to exist and remain unencrypted 322362306a36Sopenharmony_ci * if LOST_FOUND feature is enabled. 322462306a36Sopenharmony_ci * 322562306a36Sopenharmony_ci */ 322662306a36Sopenharmony_ci if (f2fs_sb_has_lost_found(sbi) && 322762306a36Sopenharmony_ci inode->i_ino == F2FS_ROOT_INO(sbi)) 322862306a36Sopenharmony_ci return -EPERM; 322962306a36Sopenharmony_ci 323062306a36Sopenharmony_ci return f2fs_setxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, 323162306a36Sopenharmony_ci F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, 323262306a36Sopenharmony_ci ctx, len, fs_data, XATTR_CREATE); 323362306a36Sopenharmony_ci} 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_cistatic const union fscrypt_policy *f2fs_get_dummy_policy(struct super_block *sb) 323662306a36Sopenharmony_ci{ 323762306a36Sopenharmony_ci return F2FS_OPTION(F2FS_SB(sb)).dummy_enc_policy.policy; 323862306a36Sopenharmony_ci} 323962306a36Sopenharmony_ci 324062306a36Sopenharmony_cistatic bool f2fs_has_stable_inodes(struct super_block *sb) 324162306a36Sopenharmony_ci{ 324262306a36Sopenharmony_ci return true; 324362306a36Sopenharmony_ci} 324462306a36Sopenharmony_ci 324562306a36Sopenharmony_cistatic void f2fs_get_ino_and_lblk_bits(struct super_block *sb, 324662306a36Sopenharmony_ci int *ino_bits_ret, int *lblk_bits_ret) 324762306a36Sopenharmony_ci{ 324862306a36Sopenharmony_ci *ino_bits_ret = 8 * sizeof(nid_t); 324962306a36Sopenharmony_ci *lblk_bits_ret = 8 * sizeof(block_t); 325062306a36Sopenharmony_ci} 325162306a36Sopenharmony_ci 325262306a36Sopenharmony_cistatic struct block_device **f2fs_get_devices(struct super_block *sb, 325362306a36Sopenharmony_ci unsigned int *num_devs) 325462306a36Sopenharmony_ci{ 325562306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 325662306a36Sopenharmony_ci struct block_device **devs; 325762306a36Sopenharmony_ci int i; 325862306a36Sopenharmony_ci 325962306a36Sopenharmony_ci if (!f2fs_is_multi_device(sbi)) 326062306a36Sopenharmony_ci return NULL; 326162306a36Sopenharmony_ci 326262306a36Sopenharmony_ci devs = kmalloc_array(sbi->s_ndevs, sizeof(*devs), GFP_KERNEL); 326362306a36Sopenharmony_ci if (!devs) 326462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_ci for (i = 0; i < sbi->s_ndevs; i++) 326762306a36Sopenharmony_ci devs[i] = FDEV(i).bdev; 326862306a36Sopenharmony_ci *num_devs = sbi->s_ndevs; 326962306a36Sopenharmony_ci return devs; 327062306a36Sopenharmony_ci} 327162306a36Sopenharmony_ci 327262306a36Sopenharmony_cistatic const struct fscrypt_operations f2fs_cryptops = { 327362306a36Sopenharmony_ci .key_prefix = "f2fs:", 327462306a36Sopenharmony_ci .get_context = f2fs_get_context, 327562306a36Sopenharmony_ci .set_context = f2fs_set_context, 327662306a36Sopenharmony_ci .get_dummy_policy = f2fs_get_dummy_policy, 327762306a36Sopenharmony_ci .empty_dir = f2fs_empty_dir, 327862306a36Sopenharmony_ci .has_stable_inodes = f2fs_has_stable_inodes, 327962306a36Sopenharmony_ci .get_ino_and_lblk_bits = f2fs_get_ino_and_lblk_bits, 328062306a36Sopenharmony_ci .get_devices = f2fs_get_devices, 328162306a36Sopenharmony_ci}; 328262306a36Sopenharmony_ci#endif 328362306a36Sopenharmony_ci 328462306a36Sopenharmony_cistatic struct inode *f2fs_nfs_get_inode(struct super_block *sb, 328562306a36Sopenharmony_ci u64 ino, u32 generation) 328662306a36Sopenharmony_ci{ 328762306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 328862306a36Sopenharmony_ci struct inode *inode; 328962306a36Sopenharmony_ci 329062306a36Sopenharmony_ci if (f2fs_check_nid_range(sbi, ino)) 329162306a36Sopenharmony_ci return ERR_PTR(-ESTALE); 329262306a36Sopenharmony_ci 329362306a36Sopenharmony_ci /* 329462306a36Sopenharmony_ci * f2fs_iget isn't quite right if the inode is currently unallocated! 329562306a36Sopenharmony_ci * However f2fs_iget currently does appropriate checks to handle stale 329662306a36Sopenharmony_ci * inodes so everything is OK. 329762306a36Sopenharmony_ci */ 329862306a36Sopenharmony_ci inode = f2fs_iget(sb, ino); 329962306a36Sopenharmony_ci if (IS_ERR(inode)) 330062306a36Sopenharmony_ci return ERR_CAST(inode); 330162306a36Sopenharmony_ci if (unlikely(generation && inode->i_generation != generation)) { 330262306a36Sopenharmony_ci /* we didn't find the right inode.. */ 330362306a36Sopenharmony_ci iput(inode); 330462306a36Sopenharmony_ci return ERR_PTR(-ESTALE); 330562306a36Sopenharmony_ci } 330662306a36Sopenharmony_ci return inode; 330762306a36Sopenharmony_ci} 330862306a36Sopenharmony_ci 330962306a36Sopenharmony_cistatic struct dentry *f2fs_fh_to_dentry(struct super_block *sb, struct fid *fid, 331062306a36Sopenharmony_ci int fh_len, int fh_type) 331162306a36Sopenharmony_ci{ 331262306a36Sopenharmony_ci return generic_fh_to_dentry(sb, fid, fh_len, fh_type, 331362306a36Sopenharmony_ci f2fs_nfs_get_inode); 331462306a36Sopenharmony_ci} 331562306a36Sopenharmony_ci 331662306a36Sopenharmony_cistatic struct dentry *f2fs_fh_to_parent(struct super_block *sb, struct fid *fid, 331762306a36Sopenharmony_ci int fh_len, int fh_type) 331862306a36Sopenharmony_ci{ 331962306a36Sopenharmony_ci return generic_fh_to_parent(sb, fid, fh_len, fh_type, 332062306a36Sopenharmony_ci f2fs_nfs_get_inode); 332162306a36Sopenharmony_ci} 332262306a36Sopenharmony_ci 332362306a36Sopenharmony_cistatic const struct export_operations f2fs_export_ops = { 332462306a36Sopenharmony_ci .fh_to_dentry = f2fs_fh_to_dentry, 332562306a36Sopenharmony_ci .fh_to_parent = f2fs_fh_to_parent, 332662306a36Sopenharmony_ci .get_parent = f2fs_get_parent, 332762306a36Sopenharmony_ci}; 332862306a36Sopenharmony_ci 332962306a36Sopenharmony_ciloff_t max_file_blocks(struct inode *inode) 333062306a36Sopenharmony_ci{ 333162306a36Sopenharmony_ci loff_t result = 0; 333262306a36Sopenharmony_ci loff_t leaf_count; 333362306a36Sopenharmony_ci 333462306a36Sopenharmony_ci /* 333562306a36Sopenharmony_ci * note: previously, result is equal to (DEF_ADDRS_PER_INODE - 333662306a36Sopenharmony_ci * DEFAULT_INLINE_XATTR_ADDRS), but now f2fs try to reserve more 333762306a36Sopenharmony_ci * space in inode.i_addr, it will be more safe to reassign 333862306a36Sopenharmony_ci * result as zero. 333962306a36Sopenharmony_ci */ 334062306a36Sopenharmony_ci 334162306a36Sopenharmony_ci if (inode && f2fs_compressed_file(inode)) 334262306a36Sopenharmony_ci leaf_count = ADDRS_PER_BLOCK(inode); 334362306a36Sopenharmony_ci else 334462306a36Sopenharmony_ci leaf_count = DEF_ADDRS_PER_BLOCK; 334562306a36Sopenharmony_ci 334662306a36Sopenharmony_ci /* two direct node blocks */ 334762306a36Sopenharmony_ci result += (leaf_count * 2); 334862306a36Sopenharmony_ci 334962306a36Sopenharmony_ci /* two indirect node blocks */ 335062306a36Sopenharmony_ci leaf_count *= NIDS_PER_BLOCK; 335162306a36Sopenharmony_ci result += (leaf_count * 2); 335262306a36Sopenharmony_ci 335362306a36Sopenharmony_ci /* one double indirect node block */ 335462306a36Sopenharmony_ci leaf_count *= NIDS_PER_BLOCK; 335562306a36Sopenharmony_ci result += leaf_count; 335662306a36Sopenharmony_ci 335762306a36Sopenharmony_ci return result; 335862306a36Sopenharmony_ci} 335962306a36Sopenharmony_ci 336062306a36Sopenharmony_cistatic int __f2fs_commit_super(struct buffer_head *bh, 336162306a36Sopenharmony_ci struct f2fs_super_block *super) 336262306a36Sopenharmony_ci{ 336362306a36Sopenharmony_ci lock_buffer(bh); 336462306a36Sopenharmony_ci if (super) 336562306a36Sopenharmony_ci memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super)); 336662306a36Sopenharmony_ci set_buffer_dirty(bh); 336762306a36Sopenharmony_ci unlock_buffer(bh); 336862306a36Sopenharmony_ci 336962306a36Sopenharmony_ci /* it's rare case, we can do fua all the time */ 337062306a36Sopenharmony_ci return __sync_dirty_buffer(bh, REQ_SYNC | REQ_PREFLUSH | REQ_FUA); 337162306a36Sopenharmony_ci} 337262306a36Sopenharmony_ci 337362306a36Sopenharmony_cistatic inline bool sanity_check_area_boundary(struct f2fs_sb_info *sbi, 337462306a36Sopenharmony_ci struct buffer_head *bh) 337562306a36Sopenharmony_ci{ 337662306a36Sopenharmony_ci struct f2fs_super_block *raw_super = (struct f2fs_super_block *) 337762306a36Sopenharmony_ci (bh->b_data + F2FS_SUPER_OFFSET); 337862306a36Sopenharmony_ci struct super_block *sb = sbi->sb; 337962306a36Sopenharmony_ci u32 segment0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr); 338062306a36Sopenharmony_ci u32 cp_blkaddr = le32_to_cpu(raw_super->cp_blkaddr); 338162306a36Sopenharmony_ci u32 sit_blkaddr = le32_to_cpu(raw_super->sit_blkaddr); 338262306a36Sopenharmony_ci u32 nat_blkaddr = le32_to_cpu(raw_super->nat_blkaddr); 338362306a36Sopenharmony_ci u32 ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr); 338462306a36Sopenharmony_ci u32 main_blkaddr = le32_to_cpu(raw_super->main_blkaddr); 338562306a36Sopenharmony_ci u32 segment_count_ckpt = le32_to_cpu(raw_super->segment_count_ckpt); 338662306a36Sopenharmony_ci u32 segment_count_sit = le32_to_cpu(raw_super->segment_count_sit); 338762306a36Sopenharmony_ci u32 segment_count_nat = le32_to_cpu(raw_super->segment_count_nat); 338862306a36Sopenharmony_ci u32 segment_count_ssa = le32_to_cpu(raw_super->segment_count_ssa); 338962306a36Sopenharmony_ci u32 segment_count_main = le32_to_cpu(raw_super->segment_count_main); 339062306a36Sopenharmony_ci u32 segment_count = le32_to_cpu(raw_super->segment_count); 339162306a36Sopenharmony_ci u32 log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg); 339262306a36Sopenharmony_ci u64 main_end_blkaddr = main_blkaddr + 339362306a36Sopenharmony_ci (segment_count_main << log_blocks_per_seg); 339462306a36Sopenharmony_ci u64 seg_end_blkaddr = segment0_blkaddr + 339562306a36Sopenharmony_ci (segment_count << log_blocks_per_seg); 339662306a36Sopenharmony_ci 339762306a36Sopenharmony_ci if (segment0_blkaddr != cp_blkaddr) { 339862306a36Sopenharmony_ci f2fs_info(sbi, "Mismatch start address, segment0(%u) cp_blkaddr(%u)", 339962306a36Sopenharmony_ci segment0_blkaddr, cp_blkaddr); 340062306a36Sopenharmony_ci return true; 340162306a36Sopenharmony_ci } 340262306a36Sopenharmony_ci 340362306a36Sopenharmony_ci if (cp_blkaddr + (segment_count_ckpt << log_blocks_per_seg) != 340462306a36Sopenharmony_ci sit_blkaddr) { 340562306a36Sopenharmony_ci f2fs_info(sbi, "Wrong CP boundary, start(%u) end(%u) blocks(%u)", 340662306a36Sopenharmony_ci cp_blkaddr, sit_blkaddr, 340762306a36Sopenharmony_ci segment_count_ckpt << log_blocks_per_seg); 340862306a36Sopenharmony_ci return true; 340962306a36Sopenharmony_ci } 341062306a36Sopenharmony_ci 341162306a36Sopenharmony_ci if (sit_blkaddr + (segment_count_sit << log_blocks_per_seg) != 341262306a36Sopenharmony_ci nat_blkaddr) { 341362306a36Sopenharmony_ci f2fs_info(sbi, "Wrong SIT boundary, start(%u) end(%u) blocks(%u)", 341462306a36Sopenharmony_ci sit_blkaddr, nat_blkaddr, 341562306a36Sopenharmony_ci segment_count_sit << log_blocks_per_seg); 341662306a36Sopenharmony_ci return true; 341762306a36Sopenharmony_ci } 341862306a36Sopenharmony_ci 341962306a36Sopenharmony_ci if (nat_blkaddr + (segment_count_nat << log_blocks_per_seg) != 342062306a36Sopenharmony_ci ssa_blkaddr) { 342162306a36Sopenharmony_ci f2fs_info(sbi, "Wrong NAT boundary, start(%u) end(%u) blocks(%u)", 342262306a36Sopenharmony_ci nat_blkaddr, ssa_blkaddr, 342362306a36Sopenharmony_ci segment_count_nat << log_blocks_per_seg); 342462306a36Sopenharmony_ci return true; 342562306a36Sopenharmony_ci } 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_ci if (ssa_blkaddr + (segment_count_ssa << log_blocks_per_seg) != 342862306a36Sopenharmony_ci main_blkaddr) { 342962306a36Sopenharmony_ci f2fs_info(sbi, "Wrong SSA boundary, start(%u) end(%u) blocks(%u)", 343062306a36Sopenharmony_ci ssa_blkaddr, main_blkaddr, 343162306a36Sopenharmony_ci segment_count_ssa << log_blocks_per_seg); 343262306a36Sopenharmony_ci return true; 343362306a36Sopenharmony_ci } 343462306a36Sopenharmony_ci 343562306a36Sopenharmony_ci if (main_end_blkaddr > seg_end_blkaddr) { 343662306a36Sopenharmony_ci f2fs_info(sbi, "Wrong MAIN_AREA boundary, start(%u) end(%llu) block(%u)", 343762306a36Sopenharmony_ci main_blkaddr, seg_end_blkaddr, 343862306a36Sopenharmony_ci segment_count_main << log_blocks_per_seg); 343962306a36Sopenharmony_ci return true; 344062306a36Sopenharmony_ci } else if (main_end_blkaddr < seg_end_blkaddr) { 344162306a36Sopenharmony_ci int err = 0; 344262306a36Sopenharmony_ci char *res; 344362306a36Sopenharmony_ci 344462306a36Sopenharmony_ci /* fix in-memory information all the time */ 344562306a36Sopenharmony_ci raw_super->segment_count = cpu_to_le32((main_end_blkaddr - 344662306a36Sopenharmony_ci segment0_blkaddr) >> log_blocks_per_seg); 344762306a36Sopenharmony_ci 344862306a36Sopenharmony_ci if (f2fs_readonly(sb) || f2fs_hw_is_readonly(sbi)) { 344962306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_NEED_SB_WRITE); 345062306a36Sopenharmony_ci res = "internally"; 345162306a36Sopenharmony_ci } else { 345262306a36Sopenharmony_ci err = __f2fs_commit_super(bh, NULL); 345362306a36Sopenharmony_ci res = err ? "failed" : "done"; 345462306a36Sopenharmony_ci } 345562306a36Sopenharmony_ci f2fs_info(sbi, "Fix alignment : %s, start(%u) end(%llu) block(%u)", 345662306a36Sopenharmony_ci res, main_blkaddr, seg_end_blkaddr, 345762306a36Sopenharmony_ci segment_count_main << log_blocks_per_seg); 345862306a36Sopenharmony_ci if (err) 345962306a36Sopenharmony_ci return true; 346062306a36Sopenharmony_ci } 346162306a36Sopenharmony_ci return false; 346262306a36Sopenharmony_ci} 346362306a36Sopenharmony_ci 346462306a36Sopenharmony_cistatic int sanity_check_raw_super(struct f2fs_sb_info *sbi, 346562306a36Sopenharmony_ci struct buffer_head *bh) 346662306a36Sopenharmony_ci{ 346762306a36Sopenharmony_ci block_t segment_count, segs_per_sec, secs_per_zone, segment_count_main; 346862306a36Sopenharmony_ci block_t total_sections, blocks_per_seg; 346962306a36Sopenharmony_ci struct f2fs_super_block *raw_super = (struct f2fs_super_block *) 347062306a36Sopenharmony_ci (bh->b_data + F2FS_SUPER_OFFSET); 347162306a36Sopenharmony_ci size_t crc_offset = 0; 347262306a36Sopenharmony_ci __u32 crc = 0; 347362306a36Sopenharmony_ci 347462306a36Sopenharmony_ci if (le32_to_cpu(raw_super->magic) != F2FS_SUPER_MAGIC) { 347562306a36Sopenharmony_ci f2fs_info(sbi, "Magic Mismatch, valid(0x%x) - read(0x%x)", 347662306a36Sopenharmony_ci F2FS_SUPER_MAGIC, le32_to_cpu(raw_super->magic)); 347762306a36Sopenharmony_ci return -EINVAL; 347862306a36Sopenharmony_ci } 347962306a36Sopenharmony_ci 348062306a36Sopenharmony_ci /* Check checksum_offset and crc in superblock */ 348162306a36Sopenharmony_ci if (__F2FS_HAS_FEATURE(raw_super, F2FS_FEATURE_SB_CHKSUM)) { 348262306a36Sopenharmony_ci crc_offset = le32_to_cpu(raw_super->checksum_offset); 348362306a36Sopenharmony_ci if (crc_offset != 348462306a36Sopenharmony_ci offsetof(struct f2fs_super_block, crc)) { 348562306a36Sopenharmony_ci f2fs_info(sbi, "Invalid SB checksum offset: %zu", 348662306a36Sopenharmony_ci crc_offset); 348762306a36Sopenharmony_ci return -EFSCORRUPTED; 348862306a36Sopenharmony_ci } 348962306a36Sopenharmony_ci crc = le32_to_cpu(raw_super->crc); 349062306a36Sopenharmony_ci if (!f2fs_crc_valid(sbi, crc, raw_super, crc_offset)) { 349162306a36Sopenharmony_ci f2fs_info(sbi, "Invalid SB checksum value: %u", crc); 349262306a36Sopenharmony_ci return -EFSCORRUPTED; 349362306a36Sopenharmony_ci } 349462306a36Sopenharmony_ci } 349562306a36Sopenharmony_ci 349662306a36Sopenharmony_ci /* Currently, support only 4KB block size */ 349762306a36Sopenharmony_ci if (le32_to_cpu(raw_super->log_blocksize) != F2FS_BLKSIZE_BITS) { 349862306a36Sopenharmony_ci f2fs_info(sbi, "Invalid log_blocksize (%u), supports only %u", 349962306a36Sopenharmony_ci le32_to_cpu(raw_super->log_blocksize), 350062306a36Sopenharmony_ci F2FS_BLKSIZE_BITS); 350162306a36Sopenharmony_ci return -EFSCORRUPTED; 350262306a36Sopenharmony_ci } 350362306a36Sopenharmony_ci 350462306a36Sopenharmony_ci /* check log blocks per segment */ 350562306a36Sopenharmony_ci if (le32_to_cpu(raw_super->log_blocks_per_seg) != 9) { 350662306a36Sopenharmony_ci f2fs_info(sbi, "Invalid log blocks per segment (%u)", 350762306a36Sopenharmony_ci le32_to_cpu(raw_super->log_blocks_per_seg)); 350862306a36Sopenharmony_ci return -EFSCORRUPTED; 350962306a36Sopenharmony_ci } 351062306a36Sopenharmony_ci 351162306a36Sopenharmony_ci /* Currently, support 512/1024/2048/4096 bytes sector size */ 351262306a36Sopenharmony_ci if (le32_to_cpu(raw_super->log_sectorsize) > 351362306a36Sopenharmony_ci F2FS_MAX_LOG_SECTOR_SIZE || 351462306a36Sopenharmony_ci le32_to_cpu(raw_super->log_sectorsize) < 351562306a36Sopenharmony_ci F2FS_MIN_LOG_SECTOR_SIZE) { 351662306a36Sopenharmony_ci f2fs_info(sbi, "Invalid log sectorsize (%u)", 351762306a36Sopenharmony_ci le32_to_cpu(raw_super->log_sectorsize)); 351862306a36Sopenharmony_ci return -EFSCORRUPTED; 351962306a36Sopenharmony_ci } 352062306a36Sopenharmony_ci if (le32_to_cpu(raw_super->log_sectors_per_block) + 352162306a36Sopenharmony_ci le32_to_cpu(raw_super->log_sectorsize) != 352262306a36Sopenharmony_ci F2FS_MAX_LOG_SECTOR_SIZE) { 352362306a36Sopenharmony_ci f2fs_info(sbi, "Invalid log sectors per block(%u) log sectorsize(%u)", 352462306a36Sopenharmony_ci le32_to_cpu(raw_super->log_sectors_per_block), 352562306a36Sopenharmony_ci le32_to_cpu(raw_super->log_sectorsize)); 352662306a36Sopenharmony_ci return -EFSCORRUPTED; 352762306a36Sopenharmony_ci } 352862306a36Sopenharmony_ci 352962306a36Sopenharmony_ci segment_count = le32_to_cpu(raw_super->segment_count); 353062306a36Sopenharmony_ci segment_count_main = le32_to_cpu(raw_super->segment_count_main); 353162306a36Sopenharmony_ci segs_per_sec = le32_to_cpu(raw_super->segs_per_sec); 353262306a36Sopenharmony_ci secs_per_zone = le32_to_cpu(raw_super->secs_per_zone); 353362306a36Sopenharmony_ci total_sections = le32_to_cpu(raw_super->section_count); 353462306a36Sopenharmony_ci 353562306a36Sopenharmony_ci /* blocks_per_seg should be 512, given the above check */ 353662306a36Sopenharmony_ci blocks_per_seg = BIT(le32_to_cpu(raw_super->log_blocks_per_seg)); 353762306a36Sopenharmony_ci 353862306a36Sopenharmony_ci if (segment_count > F2FS_MAX_SEGMENT || 353962306a36Sopenharmony_ci segment_count < F2FS_MIN_SEGMENTS) { 354062306a36Sopenharmony_ci f2fs_info(sbi, "Invalid segment count (%u)", segment_count); 354162306a36Sopenharmony_ci return -EFSCORRUPTED; 354262306a36Sopenharmony_ci } 354362306a36Sopenharmony_ci 354462306a36Sopenharmony_ci if (total_sections > segment_count_main || total_sections < 1 || 354562306a36Sopenharmony_ci segs_per_sec > segment_count || !segs_per_sec) { 354662306a36Sopenharmony_ci f2fs_info(sbi, "Invalid segment/section count (%u, %u x %u)", 354762306a36Sopenharmony_ci segment_count, total_sections, segs_per_sec); 354862306a36Sopenharmony_ci return -EFSCORRUPTED; 354962306a36Sopenharmony_ci } 355062306a36Sopenharmony_ci 355162306a36Sopenharmony_ci if (segment_count_main != total_sections * segs_per_sec) { 355262306a36Sopenharmony_ci f2fs_info(sbi, "Invalid segment/section count (%u != %u * %u)", 355362306a36Sopenharmony_ci segment_count_main, total_sections, segs_per_sec); 355462306a36Sopenharmony_ci return -EFSCORRUPTED; 355562306a36Sopenharmony_ci } 355662306a36Sopenharmony_ci 355762306a36Sopenharmony_ci if ((segment_count / segs_per_sec) < total_sections) { 355862306a36Sopenharmony_ci f2fs_info(sbi, "Small segment_count (%u < %u * %u)", 355962306a36Sopenharmony_ci segment_count, segs_per_sec, total_sections); 356062306a36Sopenharmony_ci return -EFSCORRUPTED; 356162306a36Sopenharmony_ci } 356262306a36Sopenharmony_ci 356362306a36Sopenharmony_ci if (segment_count > (le64_to_cpu(raw_super->block_count) >> 9)) { 356462306a36Sopenharmony_ci f2fs_info(sbi, "Wrong segment_count / block_count (%u > %llu)", 356562306a36Sopenharmony_ci segment_count, le64_to_cpu(raw_super->block_count)); 356662306a36Sopenharmony_ci return -EFSCORRUPTED; 356762306a36Sopenharmony_ci } 356862306a36Sopenharmony_ci 356962306a36Sopenharmony_ci if (RDEV(0).path[0]) { 357062306a36Sopenharmony_ci block_t dev_seg_count = le32_to_cpu(RDEV(0).total_segments); 357162306a36Sopenharmony_ci int i = 1; 357262306a36Sopenharmony_ci 357362306a36Sopenharmony_ci while (i < MAX_DEVICES && RDEV(i).path[0]) { 357462306a36Sopenharmony_ci dev_seg_count += le32_to_cpu(RDEV(i).total_segments); 357562306a36Sopenharmony_ci i++; 357662306a36Sopenharmony_ci } 357762306a36Sopenharmony_ci if (segment_count != dev_seg_count) { 357862306a36Sopenharmony_ci f2fs_info(sbi, "Segment count (%u) mismatch with total segments from devices (%u)", 357962306a36Sopenharmony_ci segment_count, dev_seg_count); 358062306a36Sopenharmony_ci return -EFSCORRUPTED; 358162306a36Sopenharmony_ci } 358262306a36Sopenharmony_ci } else { 358362306a36Sopenharmony_ci if (__F2FS_HAS_FEATURE(raw_super, F2FS_FEATURE_BLKZONED) && 358462306a36Sopenharmony_ci !bdev_is_zoned(sbi->sb->s_bdev)) { 358562306a36Sopenharmony_ci f2fs_info(sbi, "Zoned block device path is missing"); 358662306a36Sopenharmony_ci return -EFSCORRUPTED; 358762306a36Sopenharmony_ci } 358862306a36Sopenharmony_ci } 358962306a36Sopenharmony_ci 359062306a36Sopenharmony_ci if (secs_per_zone > total_sections || !secs_per_zone) { 359162306a36Sopenharmony_ci f2fs_info(sbi, "Wrong secs_per_zone / total_sections (%u, %u)", 359262306a36Sopenharmony_ci secs_per_zone, total_sections); 359362306a36Sopenharmony_ci return -EFSCORRUPTED; 359462306a36Sopenharmony_ci } 359562306a36Sopenharmony_ci if (le32_to_cpu(raw_super->extension_count) > F2FS_MAX_EXTENSION || 359662306a36Sopenharmony_ci raw_super->hot_ext_count > F2FS_MAX_EXTENSION || 359762306a36Sopenharmony_ci (le32_to_cpu(raw_super->extension_count) + 359862306a36Sopenharmony_ci raw_super->hot_ext_count) > F2FS_MAX_EXTENSION) { 359962306a36Sopenharmony_ci f2fs_info(sbi, "Corrupted extension count (%u + %u > %u)", 360062306a36Sopenharmony_ci le32_to_cpu(raw_super->extension_count), 360162306a36Sopenharmony_ci raw_super->hot_ext_count, 360262306a36Sopenharmony_ci F2FS_MAX_EXTENSION); 360362306a36Sopenharmony_ci return -EFSCORRUPTED; 360462306a36Sopenharmony_ci } 360562306a36Sopenharmony_ci 360662306a36Sopenharmony_ci if (le32_to_cpu(raw_super->cp_payload) >= 360762306a36Sopenharmony_ci (blocks_per_seg - F2FS_CP_PACKS - 360862306a36Sopenharmony_ci NR_CURSEG_PERSIST_TYPE)) { 360962306a36Sopenharmony_ci f2fs_info(sbi, "Insane cp_payload (%u >= %u)", 361062306a36Sopenharmony_ci le32_to_cpu(raw_super->cp_payload), 361162306a36Sopenharmony_ci blocks_per_seg - F2FS_CP_PACKS - 361262306a36Sopenharmony_ci NR_CURSEG_PERSIST_TYPE); 361362306a36Sopenharmony_ci return -EFSCORRUPTED; 361462306a36Sopenharmony_ci } 361562306a36Sopenharmony_ci 361662306a36Sopenharmony_ci /* check reserved ino info */ 361762306a36Sopenharmony_ci if (le32_to_cpu(raw_super->node_ino) != 1 || 361862306a36Sopenharmony_ci le32_to_cpu(raw_super->meta_ino) != 2 || 361962306a36Sopenharmony_ci le32_to_cpu(raw_super->root_ino) != 3) { 362062306a36Sopenharmony_ci f2fs_info(sbi, "Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)", 362162306a36Sopenharmony_ci le32_to_cpu(raw_super->node_ino), 362262306a36Sopenharmony_ci le32_to_cpu(raw_super->meta_ino), 362362306a36Sopenharmony_ci le32_to_cpu(raw_super->root_ino)); 362462306a36Sopenharmony_ci return -EFSCORRUPTED; 362562306a36Sopenharmony_ci } 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_ci /* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */ 362862306a36Sopenharmony_ci if (sanity_check_area_boundary(sbi, bh)) 362962306a36Sopenharmony_ci return -EFSCORRUPTED; 363062306a36Sopenharmony_ci 363162306a36Sopenharmony_ci return 0; 363262306a36Sopenharmony_ci} 363362306a36Sopenharmony_ci 363462306a36Sopenharmony_ciint f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi) 363562306a36Sopenharmony_ci{ 363662306a36Sopenharmony_ci unsigned int total, fsmeta; 363762306a36Sopenharmony_ci struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); 363862306a36Sopenharmony_ci struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); 363962306a36Sopenharmony_ci unsigned int ovp_segments, reserved_segments; 364062306a36Sopenharmony_ci unsigned int main_segs, blocks_per_seg; 364162306a36Sopenharmony_ci unsigned int sit_segs, nat_segs; 364262306a36Sopenharmony_ci unsigned int sit_bitmap_size, nat_bitmap_size; 364362306a36Sopenharmony_ci unsigned int log_blocks_per_seg; 364462306a36Sopenharmony_ci unsigned int segment_count_main; 364562306a36Sopenharmony_ci unsigned int cp_pack_start_sum, cp_payload; 364662306a36Sopenharmony_ci block_t user_block_count, valid_user_blocks; 364762306a36Sopenharmony_ci block_t avail_node_count, valid_node_count; 364862306a36Sopenharmony_ci unsigned int nat_blocks, nat_bits_bytes, nat_bits_blocks; 364962306a36Sopenharmony_ci int i, j; 365062306a36Sopenharmony_ci 365162306a36Sopenharmony_ci total = le32_to_cpu(raw_super->segment_count); 365262306a36Sopenharmony_ci fsmeta = le32_to_cpu(raw_super->segment_count_ckpt); 365362306a36Sopenharmony_ci sit_segs = le32_to_cpu(raw_super->segment_count_sit); 365462306a36Sopenharmony_ci fsmeta += sit_segs; 365562306a36Sopenharmony_ci nat_segs = le32_to_cpu(raw_super->segment_count_nat); 365662306a36Sopenharmony_ci fsmeta += nat_segs; 365762306a36Sopenharmony_ci fsmeta += le32_to_cpu(ckpt->rsvd_segment_count); 365862306a36Sopenharmony_ci fsmeta += le32_to_cpu(raw_super->segment_count_ssa); 365962306a36Sopenharmony_ci 366062306a36Sopenharmony_ci if (unlikely(fsmeta >= total)) 366162306a36Sopenharmony_ci return 1; 366262306a36Sopenharmony_ci 366362306a36Sopenharmony_ci ovp_segments = le32_to_cpu(ckpt->overprov_segment_count); 366462306a36Sopenharmony_ci reserved_segments = le32_to_cpu(ckpt->rsvd_segment_count); 366562306a36Sopenharmony_ci 366662306a36Sopenharmony_ci if (!f2fs_sb_has_readonly(sbi) && 366762306a36Sopenharmony_ci unlikely(fsmeta < F2FS_MIN_META_SEGMENTS || 366862306a36Sopenharmony_ci ovp_segments == 0 || reserved_segments == 0)) { 366962306a36Sopenharmony_ci f2fs_err(sbi, "Wrong layout: check mkfs.f2fs version"); 367062306a36Sopenharmony_ci return 1; 367162306a36Sopenharmony_ci } 367262306a36Sopenharmony_ci user_block_count = le64_to_cpu(ckpt->user_block_count); 367362306a36Sopenharmony_ci segment_count_main = le32_to_cpu(raw_super->segment_count_main) + 367462306a36Sopenharmony_ci (f2fs_sb_has_readonly(sbi) ? 1 : 0); 367562306a36Sopenharmony_ci log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg); 367662306a36Sopenharmony_ci if (!user_block_count || user_block_count >= 367762306a36Sopenharmony_ci segment_count_main << log_blocks_per_seg) { 367862306a36Sopenharmony_ci f2fs_err(sbi, "Wrong user_block_count: %u", 367962306a36Sopenharmony_ci user_block_count); 368062306a36Sopenharmony_ci return 1; 368162306a36Sopenharmony_ci } 368262306a36Sopenharmony_ci 368362306a36Sopenharmony_ci valid_user_blocks = le64_to_cpu(ckpt->valid_block_count); 368462306a36Sopenharmony_ci if (valid_user_blocks > user_block_count) { 368562306a36Sopenharmony_ci f2fs_err(sbi, "Wrong valid_user_blocks: %u, user_block_count: %u", 368662306a36Sopenharmony_ci valid_user_blocks, user_block_count); 368762306a36Sopenharmony_ci return 1; 368862306a36Sopenharmony_ci } 368962306a36Sopenharmony_ci 369062306a36Sopenharmony_ci valid_node_count = le32_to_cpu(ckpt->valid_node_count); 369162306a36Sopenharmony_ci avail_node_count = sbi->total_node_count - F2FS_RESERVED_NODE_NUM; 369262306a36Sopenharmony_ci if (valid_node_count > avail_node_count) { 369362306a36Sopenharmony_ci f2fs_err(sbi, "Wrong valid_node_count: %u, avail_node_count: %u", 369462306a36Sopenharmony_ci valid_node_count, avail_node_count); 369562306a36Sopenharmony_ci return 1; 369662306a36Sopenharmony_ci } 369762306a36Sopenharmony_ci 369862306a36Sopenharmony_ci main_segs = le32_to_cpu(raw_super->segment_count_main); 369962306a36Sopenharmony_ci blocks_per_seg = sbi->blocks_per_seg; 370062306a36Sopenharmony_ci 370162306a36Sopenharmony_ci for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { 370262306a36Sopenharmony_ci if (le32_to_cpu(ckpt->cur_node_segno[i]) >= main_segs || 370362306a36Sopenharmony_ci le16_to_cpu(ckpt->cur_node_blkoff[i]) >= blocks_per_seg) 370462306a36Sopenharmony_ci return 1; 370562306a36Sopenharmony_ci 370662306a36Sopenharmony_ci if (f2fs_sb_has_readonly(sbi)) 370762306a36Sopenharmony_ci goto check_data; 370862306a36Sopenharmony_ci 370962306a36Sopenharmony_ci for (j = i + 1; j < NR_CURSEG_NODE_TYPE; j++) { 371062306a36Sopenharmony_ci if (le32_to_cpu(ckpt->cur_node_segno[i]) == 371162306a36Sopenharmony_ci le32_to_cpu(ckpt->cur_node_segno[j])) { 371262306a36Sopenharmony_ci f2fs_err(sbi, "Node segment (%u, %u) has the same segno: %u", 371362306a36Sopenharmony_ci i, j, 371462306a36Sopenharmony_ci le32_to_cpu(ckpt->cur_node_segno[i])); 371562306a36Sopenharmony_ci return 1; 371662306a36Sopenharmony_ci } 371762306a36Sopenharmony_ci } 371862306a36Sopenharmony_ci } 371962306a36Sopenharmony_cicheck_data: 372062306a36Sopenharmony_ci for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) { 372162306a36Sopenharmony_ci if (le32_to_cpu(ckpt->cur_data_segno[i]) >= main_segs || 372262306a36Sopenharmony_ci le16_to_cpu(ckpt->cur_data_blkoff[i]) >= blocks_per_seg) 372362306a36Sopenharmony_ci return 1; 372462306a36Sopenharmony_ci 372562306a36Sopenharmony_ci if (f2fs_sb_has_readonly(sbi)) 372662306a36Sopenharmony_ci goto skip_cross; 372762306a36Sopenharmony_ci 372862306a36Sopenharmony_ci for (j = i + 1; j < NR_CURSEG_DATA_TYPE; j++) { 372962306a36Sopenharmony_ci if (le32_to_cpu(ckpt->cur_data_segno[i]) == 373062306a36Sopenharmony_ci le32_to_cpu(ckpt->cur_data_segno[j])) { 373162306a36Sopenharmony_ci f2fs_err(sbi, "Data segment (%u, %u) has the same segno: %u", 373262306a36Sopenharmony_ci i, j, 373362306a36Sopenharmony_ci le32_to_cpu(ckpt->cur_data_segno[i])); 373462306a36Sopenharmony_ci return 1; 373562306a36Sopenharmony_ci } 373662306a36Sopenharmony_ci } 373762306a36Sopenharmony_ci } 373862306a36Sopenharmony_ci for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { 373962306a36Sopenharmony_ci for (j = 0; j < NR_CURSEG_DATA_TYPE; j++) { 374062306a36Sopenharmony_ci if (le32_to_cpu(ckpt->cur_node_segno[i]) == 374162306a36Sopenharmony_ci le32_to_cpu(ckpt->cur_data_segno[j])) { 374262306a36Sopenharmony_ci f2fs_err(sbi, "Node segment (%u) and Data segment (%u) has the same segno: %u", 374362306a36Sopenharmony_ci i, j, 374462306a36Sopenharmony_ci le32_to_cpu(ckpt->cur_node_segno[i])); 374562306a36Sopenharmony_ci return 1; 374662306a36Sopenharmony_ci } 374762306a36Sopenharmony_ci } 374862306a36Sopenharmony_ci } 374962306a36Sopenharmony_ciskip_cross: 375062306a36Sopenharmony_ci sit_bitmap_size = le32_to_cpu(ckpt->sit_ver_bitmap_bytesize); 375162306a36Sopenharmony_ci nat_bitmap_size = le32_to_cpu(ckpt->nat_ver_bitmap_bytesize); 375262306a36Sopenharmony_ci 375362306a36Sopenharmony_ci if (sit_bitmap_size != ((sit_segs / 2) << log_blocks_per_seg) / 8 || 375462306a36Sopenharmony_ci nat_bitmap_size != ((nat_segs / 2) << log_blocks_per_seg) / 8) { 375562306a36Sopenharmony_ci f2fs_err(sbi, "Wrong bitmap size: sit: %u, nat:%u", 375662306a36Sopenharmony_ci sit_bitmap_size, nat_bitmap_size); 375762306a36Sopenharmony_ci return 1; 375862306a36Sopenharmony_ci } 375962306a36Sopenharmony_ci 376062306a36Sopenharmony_ci cp_pack_start_sum = __start_sum_addr(sbi); 376162306a36Sopenharmony_ci cp_payload = __cp_payload(sbi); 376262306a36Sopenharmony_ci if (cp_pack_start_sum < cp_payload + 1 || 376362306a36Sopenharmony_ci cp_pack_start_sum > blocks_per_seg - 1 - 376462306a36Sopenharmony_ci NR_CURSEG_PERSIST_TYPE) { 376562306a36Sopenharmony_ci f2fs_err(sbi, "Wrong cp_pack_start_sum: %u", 376662306a36Sopenharmony_ci cp_pack_start_sum); 376762306a36Sopenharmony_ci return 1; 376862306a36Sopenharmony_ci } 376962306a36Sopenharmony_ci 377062306a36Sopenharmony_ci if (__is_set_ckpt_flags(ckpt, CP_LARGE_NAT_BITMAP_FLAG) && 377162306a36Sopenharmony_ci le32_to_cpu(ckpt->checksum_offset) != CP_MIN_CHKSUM_OFFSET) { 377262306a36Sopenharmony_ci f2fs_warn(sbi, "using deprecated layout of large_nat_bitmap, " 377362306a36Sopenharmony_ci "please run fsck v1.13.0 or higher to repair, chksum_offset: %u, " 377462306a36Sopenharmony_ci "fixed with patch: \"f2fs-tools: relocate chksum_offset for large_nat_bitmap feature\"", 377562306a36Sopenharmony_ci le32_to_cpu(ckpt->checksum_offset)); 377662306a36Sopenharmony_ci return 1; 377762306a36Sopenharmony_ci } 377862306a36Sopenharmony_ci 377962306a36Sopenharmony_ci nat_blocks = nat_segs << log_blocks_per_seg; 378062306a36Sopenharmony_ci nat_bits_bytes = nat_blocks / BITS_PER_BYTE; 378162306a36Sopenharmony_ci nat_bits_blocks = F2FS_BLK_ALIGN((nat_bits_bytes << 1) + 8); 378262306a36Sopenharmony_ci if (__is_set_ckpt_flags(ckpt, CP_NAT_BITS_FLAG) && 378362306a36Sopenharmony_ci (cp_payload + F2FS_CP_PACKS + 378462306a36Sopenharmony_ci NR_CURSEG_PERSIST_TYPE + nat_bits_blocks >= blocks_per_seg)) { 378562306a36Sopenharmony_ci f2fs_warn(sbi, "Insane cp_payload: %u, nat_bits_blocks: %u)", 378662306a36Sopenharmony_ci cp_payload, nat_bits_blocks); 378762306a36Sopenharmony_ci return 1; 378862306a36Sopenharmony_ci } 378962306a36Sopenharmony_ci 379062306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(sbi))) { 379162306a36Sopenharmony_ci f2fs_err(sbi, "A bug case: need to run fsck"); 379262306a36Sopenharmony_ci return 1; 379362306a36Sopenharmony_ci } 379462306a36Sopenharmony_ci return 0; 379562306a36Sopenharmony_ci} 379662306a36Sopenharmony_ci 379762306a36Sopenharmony_cistatic void init_sb_info(struct f2fs_sb_info *sbi) 379862306a36Sopenharmony_ci{ 379962306a36Sopenharmony_ci struct f2fs_super_block *raw_super = sbi->raw_super; 380062306a36Sopenharmony_ci int i; 380162306a36Sopenharmony_ci 380262306a36Sopenharmony_ci sbi->log_sectors_per_block = 380362306a36Sopenharmony_ci le32_to_cpu(raw_super->log_sectors_per_block); 380462306a36Sopenharmony_ci sbi->log_blocksize = le32_to_cpu(raw_super->log_blocksize); 380562306a36Sopenharmony_ci sbi->blocksize = BIT(sbi->log_blocksize); 380662306a36Sopenharmony_ci sbi->log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg); 380762306a36Sopenharmony_ci sbi->blocks_per_seg = BIT(sbi->log_blocks_per_seg); 380862306a36Sopenharmony_ci sbi->segs_per_sec = le32_to_cpu(raw_super->segs_per_sec); 380962306a36Sopenharmony_ci sbi->secs_per_zone = le32_to_cpu(raw_super->secs_per_zone); 381062306a36Sopenharmony_ci sbi->total_sections = le32_to_cpu(raw_super->section_count); 381162306a36Sopenharmony_ci sbi->total_node_count = 381262306a36Sopenharmony_ci (le32_to_cpu(raw_super->segment_count_nat) / 2) 381362306a36Sopenharmony_ci * sbi->blocks_per_seg * NAT_ENTRY_PER_BLOCK; 381462306a36Sopenharmony_ci F2FS_ROOT_INO(sbi) = le32_to_cpu(raw_super->root_ino); 381562306a36Sopenharmony_ci F2FS_NODE_INO(sbi) = le32_to_cpu(raw_super->node_ino); 381662306a36Sopenharmony_ci F2FS_META_INO(sbi) = le32_to_cpu(raw_super->meta_ino); 381762306a36Sopenharmony_ci sbi->cur_victim_sec = NULL_SECNO; 381862306a36Sopenharmony_ci sbi->gc_mode = GC_NORMAL; 381962306a36Sopenharmony_ci sbi->next_victim_seg[BG_GC] = NULL_SEGNO; 382062306a36Sopenharmony_ci sbi->next_victim_seg[FG_GC] = NULL_SEGNO; 382162306a36Sopenharmony_ci sbi->max_victim_search = DEF_MAX_VICTIM_SEARCH; 382262306a36Sopenharmony_ci sbi->migration_granularity = sbi->segs_per_sec; 382362306a36Sopenharmony_ci sbi->seq_file_ra_mul = MIN_RA_MUL; 382462306a36Sopenharmony_ci sbi->max_fragment_chunk = DEF_FRAGMENT_SIZE; 382562306a36Sopenharmony_ci sbi->max_fragment_hole = DEF_FRAGMENT_SIZE; 382662306a36Sopenharmony_ci spin_lock_init(&sbi->gc_remaining_trials_lock); 382762306a36Sopenharmony_ci atomic64_set(&sbi->current_atomic_write, 0); 382862306a36Sopenharmony_ci 382962306a36Sopenharmony_ci sbi->dir_level = DEF_DIR_LEVEL; 383062306a36Sopenharmony_ci sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL; 383162306a36Sopenharmony_ci sbi->interval_time[REQ_TIME] = DEF_IDLE_INTERVAL; 383262306a36Sopenharmony_ci sbi->interval_time[DISCARD_TIME] = DEF_IDLE_INTERVAL; 383362306a36Sopenharmony_ci sbi->interval_time[GC_TIME] = DEF_IDLE_INTERVAL; 383462306a36Sopenharmony_ci sbi->interval_time[DISABLE_TIME] = DEF_DISABLE_INTERVAL; 383562306a36Sopenharmony_ci sbi->interval_time[UMOUNT_DISCARD_TIMEOUT] = 383662306a36Sopenharmony_ci DEF_UMOUNT_DISCARD_TIMEOUT; 383762306a36Sopenharmony_ci clear_sbi_flag(sbi, SBI_NEED_FSCK); 383862306a36Sopenharmony_ci 383962306a36Sopenharmony_ci for (i = 0; i < NR_COUNT_TYPE; i++) 384062306a36Sopenharmony_ci atomic_set(&sbi->nr_pages[i], 0); 384162306a36Sopenharmony_ci 384262306a36Sopenharmony_ci for (i = 0; i < META; i++) 384362306a36Sopenharmony_ci atomic_set(&sbi->wb_sync_req[i], 0); 384462306a36Sopenharmony_ci 384562306a36Sopenharmony_ci INIT_LIST_HEAD(&sbi->s_list); 384662306a36Sopenharmony_ci mutex_init(&sbi->umount_mutex); 384762306a36Sopenharmony_ci init_f2fs_rwsem(&sbi->io_order_lock); 384862306a36Sopenharmony_ci spin_lock_init(&sbi->cp_lock); 384962306a36Sopenharmony_ci 385062306a36Sopenharmony_ci sbi->dirty_device = 0; 385162306a36Sopenharmony_ci spin_lock_init(&sbi->dev_lock); 385262306a36Sopenharmony_ci 385362306a36Sopenharmony_ci init_f2fs_rwsem(&sbi->sb_lock); 385462306a36Sopenharmony_ci init_f2fs_rwsem(&sbi->pin_sem); 385562306a36Sopenharmony_ci} 385662306a36Sopenharmony_ci 385762306a36Sopenharmony_cistatic int init_percpu_info(struct f2fs_sb_info *sbi) 385862306a36Sopenharmony_ci{ 385962306a36Sopenharmony_ci int err; 386062306a36Sopenharmony_ci 386162306a36Sopenharmony_ci err = percpu_counter_init(&sbi->alloc_valid_block_count, 0, GFP_KERNEL); 386262306a36Sopenharmony_ci if (err) 386362306a36Sopenharmony_ci return err; 386462306a36Sopenharmony_ci 386562306a36Sopenharmony_ci err = percpu_counter_init(&sbi->rf_node_block_count, 0, GFP_KERNEL); 386662306a36Sopenharmony_ci if (err) 386762306a36Sopenharmony_ci goto err_valid_block; 386862306a36Sopenharmony_ci 386962306a36Sopenharmony_ci err = percpu_counter_init(&sbi->total_valid_inode_count, 0, 387062306a36Sopenharmony_ci GFP_KERNEL); 387162306a36Sopenharmony_ci if (err) 387262306a36Sopenharmony_ci goto err_node_block; 387362306a36Sopenharmony_ci return 0; 387462306a36Sopenharmony_ci 387562306a36Sopenharmony_cierr_node_block: 387662306a36Sopenharmony_ci percpu_counter_destroy(&sbi->rf_node_block_count); 387762306a36Sopenharmony_cierr_valid_block: 387862306a36Sopenharmony_ci percpu_counter_destroy(&sbi->alloc_valid_block_count); 387962306a36Sopenharmony_ci return err; 388062306a36Sopenharmony_ci} 388162306a36Sopenharmony_ci 388262306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED 388362306a36Sopenharmony_ci 388462306a36Sopenharmony_cistruct f2fs_report_zones_args { 388562306a36Sopenharmony_ci struct f2fs_sb_info *sbi; 388662306a36Sopenharmony_ci struct f2fs_dev_info *dev; 388762306a36Sopenharmony_ci}; 388862306a36Sopenharmony_ci 388962306a36Sopenharmony_cistatic int f2fs_report_zone_cb(struct blk_zone *zone, unsigned int idx, 389062306a36Sopenharmony_ci void *data) 389162306a36Sopenharmony_ci{ 389262306a36Sopenharmony_ci struct f2fs_report_zones_args *rz_args = data; 389362306a36Sopenharmony_ci block_t unusable_blocks = (zone->len - zone->capacity) >> 389462306a36Sopenharmony_ci F2FS_LOG_SECTORS_PER_BLOCK; 389562306a36Sopenharmony_ci 389662306a36Sopenharmony_ci if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL) 389762306a36Sopenharmony_ci return 0; 389862306a36Sopenharmony_ci 389962306a36Sopenharmony_ci set_bit(idx, rz_args->dev->blkz_seq); 390062306a36Sopenharmony_ci if (!rz_args->sbi->unusable_blocks_per_sec) { 390162306a36Sopenharmony_ci rz_args->sbi->unusable_blocks_per_sec = unusable_blocks; 390262306a36Sopenharmony_ci return 0; 390362306a36Sopenharmony_ci } 390462306a36Sopenharmony_ci if (rz_args->sbi->unusable_blocks_per_sec != unusable_blocks) { 390562306a36Sopenharmony_ci f2fs_err(rz_args->sbi, "F2FS supports single zone capacity\n"); 390662306a36Sopenharmony_ci return -EINVAL; 390762306a36Sopenharmony_ci } 390862306a36Sopenharmony_ci return 0; 390962306a36Sopenharmony_ci} 391062306a36Sopenharmony_ci 391162306a36Sopenharmony_cistatic int init_blkz_info(struct f2fs_sb_info *sbi, int devi) 391262306a36Sopenharmony_ci{ 391362306a36Sopenharmony_ci struct block_device *bdev = FDEV(devi).bdev; 391462306a36Sopenharmony_ci sector_t nr_sectors = bdev_nr_sectors(bdev); 391562306a36Sopenharmony_ci struct f2fs_report_zones_args rep_zone_arg; 391662306a36Sopenharmony_ci u64 zone_sectors; 391762306a36Sopenharmony_ci int ret; 391862306a36Sopenharmony_ci 391962306a36Sopenharmony_ci if (!f2fs_sb_has_blkzoned(sbi)) 392062306a36Sopenharmony_ci return 0; 392162306a36Sopenharmony_ci 392262306a36Sopenharmony_ci zone_sectors = bdev_zone_sectors(bdev); 392362306a36Sopenharmony_ci if (sbi->blocks_per_blkz && sbi->blocks_per_blkz != 392462306a36Sopenharmony_ci SECTOR_TO_BLOCK(zone_sectors)) 392562306a36Sopenharmony_ci return -EINVAL; 392662306a36Sopenharmony_ci sbi->blocks_per_blkz = SECTOR_TO_BLOCK(zone_sectors); 392762306a36Sopenharmony_ci FDEV(devi).nr_blkz = div_u64(SECTOR_TO_BLOCK(nr_sectors), 392862306a36Sopenharmony_ci sbi->blocks_per_blkz); 392962306a36Sopenharmony_ci if (nr_sectors & (zone_sectors - 1)) 393062306a36Sopenharmony_ci FDEV(devi).nr_blkz++; 393162306a36Sopenharmony_ci 393262306a36Sopenharmony_ci FDEV(devi).blkz_seq = f2fs_kvzalloc(sbi, 393362306a36Sopenharmony_ci BITS_TO_LONGS(FDEV(devi).nr_blkz) 393462306a36Sopenharmony_ci * sizeof(unsigned long), 393562306a36Sopenharmony_ci GFP_KERNEL); 393662306a36Sopenharmony_ci if (!FDEV(devi).blkz_seq) 393762306a36Sopenharmony_ci return -ENOMEM; 393862306a36Sopenharmony_ci 393962306a36Sopenharmony_ci rep_zone_arg.sbi = sbi; 394062306a36Sopenharmony_ci rep_zone_arg.dev = &FDEV(devi); 394162306a36Sopenharmony_ci 394262306a36Sopenharmony_ci ret = blkdev_report_zones(bdev, 0, BLK_ALL_ZONES, f2fs_report_zone_cb, 394362306a36Sopenharmony_ci &rep_zone_arg); 394462306a36Sopenharmony_ci if (ret < 0) 394562306a36Sopenharmony_ci return ret; 394662306a36Sopenharmony_ci return 0; 394762306a36Sopenharmony_ci} 394862306a36Sopenharmony_ci#endif 394962306a36Sopenharmony_ci 395062306a36Sopenharmony_ci/* 395162306a36Sopenharmony_ci * Read f2fs raw super block. 395262306a36Sopenharmony_ci * Because we have two copies of super block, so read both of them 395362306a36Sopenharmony_ci * to get the first valid one. If any one of them is broken, we pass 395462306a36Sopenharmony_ci * them recovery flag back to the caller. 395562306a36Sopenharmony_ci */ 395662306a36Sopenharmony_cistatic int read_raw_super_block(struct f2fs_sb_info *sbi, 395762306a36Sopenharmony_ci struct f2fs_super_block **raw_super, 395862306a36Sopenharmony_ci int *valid_super_block, int *recovery) 395962306a36Sopenharmony_ci{ 396062306a36Sopenharmony_ci struct super_block *sb = sbi->sb; 396162306a36Sopenharmony_ci int block; 396262306a36Sopenharmony_ci struct buffer_head *bh; 396362306a36Sopenharmony_ci struct f2fs_super_block *super; 396462306a36Sopenharmony_ci int err = 0; 396562306a36Sopenharmony_ci 396662306a36Sopenharmony_ci super = kzalloc(sizeof(struct f2fs_super_block), GFP_KERNEL); 396762306a36Sopenharmony_ci if (!super) 396862306a36Sopenharmony_ci return -ENOMEM; 396962306a36Sopenharmony_ci 397062306a36Sopenharmony_ci for (block = 0; block < 2; block++) { 397162306a36Sopenharmony_ci bh = sb_bread(sb, block); 397262306a36Sopenharmony_ci if (!bh) { 397362306a36Sopenharmony_ci f2fs_err(sbi, "Unable to read %dth superblock", 397462306a36Sopenharmony_ci block + 1); 397562306a36Sopenharmony_ci err = -EIO; 397662306a36Sopenharmony_ci *recovery = 1; 397762306a36Sopenharmony_ci continue; 397862306a36Sopenharmony_ci } 397962306a36Sopenharmony_ci 398062306a36Sopenharmony_ci /* sanity checking of raw super */ 398162306a36Sopenharmony_ci err = sanity_check_raw_super(sbi, bh); 398262306a36Sopenharmony_ci if (err) { 398362306a36Sopenharmony_ci f2fs_err(sbi, "Can't find valid F2FS filesystem in %dth superblock", 398462306a36Sopenharmony_ci block + 1); 398562306a36Sopenharmony_ci brelse(bh); 398662306a36Sopenharmony_ci *recovery = 1; 398762306a36Sopenharmony_ci continue; 398862306a36Sopenharmony_ci } 398962306a36Sopenharmony_ci 399062306a36Sopenharmony_ci if (!*raw_super) { 399162306a36Sopenharmony_ci memcpy(super, bh->b_data + F2FS_SUPER_OFFSET, 399262306a36Sopenharmony_ci sizeof(*super)); 399362306a36Sopenharmony_ci *valid_super_block = block; 399462306a36Sopenharmony_ci *raw_super = super; 399562306a36Sopenharmony_ci } 399662306a36Sopenharmony_ci brelse(bh); 399762306a36Sopenharmony_ci } 399862306a36Sopenharmony_ci 399962306a36Sopenharmony_ci /* No valid superblock */ 400062306a36Sopenharmony_ci if (!*raw_super) 400162306a36Sopenharmony_ci kfree(super); 400262306a36Sopenharmony_ci else 400362306a36Sopenharmony_ci err = 0; 400462306a36Sopenharmony_ci 400562306a36Sopenharmony_ci return err; 400662306a36Sopenharmony_ci} 400762306a36Sopenharmony_ci 400862306a36Sopenharmony_ciint f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover) 400962306a36Sopenharmony_ci{ 401062306a36Sopenharmony_ci struct buffer_head *bh; 401162306a36Sopenharmony_ci __u32 crc = 0; 401262306a36Sopenharmony_ci int err; 401362306a36Sopenharmony_ci 401462306a36Sopenharmony_ci if ((recover && f2fs_readonly(sbi->sb)) || 401562306a36Sopenharmony_ci f2fs_hw_is_readonly(sbi)) { 401662306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_NEED_SB_WRITE); 401762306a36Sopenharmony_ci return -EROFS; 401862306a36Sopenharmony_ci } 401962306a36Sopenharmony_ci 402062306a36Sopenharmony_ci /* we should update superblock crc here */ 402162306a36Sopenharmony_ci if (!recover && f2fs_sb_has_sb_chksum(sbi)) { 402262306a36Sopenharmony_ci crc = f2fs_crc32(sbi, F2FS_RAW_SUPER(sbi), 402362306a36Sopenharmony_ci offsetof(struct f2fs_super_block, crc)); 402462306a36Sopenharmony_ci F2FS_RAW_SUPER(sbi)->crc = cpu_to_le32(crc); 402562306a36Sopenharmony_ci } 402662306a36Sopenharmony_ci 402762306a36Sopenharmony_ci /* write back-up superblock first */ 402862306a36Sopenharmony_ci bh = sb_bread(sbi->sb, sbi->valid_super_block ? 0 : 1); 402962306a36Sopenharmony_ci if (!bh) 403062306a36Sopenharmony_ci return -EIO; 403162306a36Sopenharmony_ci err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi)); 403262306a36Sopenharmony_ci brelse(bh); 403362306a36Sopenharmony_ci 403462306a36Sopenharmony_ci /* if we are in recovery path, skip writing valid superblock */ 403562306a36Sopenharmony_ci if (recover || err) 403662306a36Sopenharmony_ci return err; 403762306a36Sopenharmony_ci 403862306a36Sopenharmony_ci /* write current valid superblock */ 403962306a36Sopenharmony_ci bh = sb_bread(sbi->sb, sbi->valid_super_block); 404062306a36Sopenharmony_ci if (!bh) 404162306a36Sopenharmony_ci return -EIO; 404262306a36Sopenharmony_ci err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi)); 404362306a36Sopenharmony_ci brelse(bh); 404462306a36Sopenharmony_ci return err; 404562306a36Sopenharmony_ci} 404662306a36Sopenharmony_ci 404762306a36Sopenharmony_cistatic void save_stop_reason(struct f2fs_sb_info *sbi, unsigned char reason) 404862306a36Sopenharmony_ci{ 404962306a36Sopenharmony_ci unsigned long flags; 405062306a36Sopenharmony_ci 405162306a36Sopenharmony_ci spin_lock_irqsave(&sbi->error_lock, flags); 405262306a36Sopenharmony_ci if (sbi->stop_reason[reason] < GENMASK(BITS_PER_BYTE - 1, 0)) 405362306a36Sopenharmony_ci sbi->stop_reason[reason]++; 405462306a36Sopenharmony_ci spin_unlock_irqrestore(&sbi->error_lock, flags); 405562306a36Sopenharmony_ci} 405662306a36Sopenharmony_ci 405762306a36Sopenharmony_cistatic void f2fs_record_stop_reason(struct f2fs_sb_info *sbi) 405862306a36Sopenharmony_ci{ 405962306a36Sopenharmony_ci struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); 406062306a36Sopenharmony_ci unsigned long flags; 406162306a36Sopenharmony_ci int err; 406262306a36Sopenharmony_ci 406362306a36Sopenharmony_ci f2fs_down_write(&sbi->sb_lock); 406462306a36Sopenharmony_ci 406562306a36Sopenharmony_ci spin_lock_irqsave(&sbi->error_lock, flags); 406662306a36Sopenharmony_ci if (sbi->error_dirty) { 406762306a36Sopenharmony_ci memcpy(F2FS_RAW_SUPER(sbi)->s_errors, sbi->errors, 406862306a36Sopenharmony_ci MAX_F2FS_ERRORS); 406962306a36Sopenharmony_ci sbi->error_dirty = false; 407062306a36Sopenharmony_ci } 407162306a36Sopenharmony_ci memcpy(raw_super->s_stop_reason, sbi->stop_reason, MAX_STOP_REASON); 407262306a36Sopenharmony_ci spin_unlock_irqrestore(&sbi->error_lock, flags); 407362306a36Sopenharmony_ci 407462306a36Sopenharmony_ci err = f2fs_commit_super(sbi, false); 407562306a36Sopenharmony_ci 407662306a36Sopenharmony_ci f2fs_up_write(&sbi->sb_lock); 407762306a36Sopenharmony_ci if (err) 407862306a36Sopenharmony_ci f2fs_err(sbi, "f2fs_commit_super fails to record err:%d", err); 407962306a36Sopenharmony_ci} 408062306a36Sopenharmony_ci 408162306a36Sopenharmony_civoid f2fs_save_errors(struct f2fs_sb_info *sbi, unsigned char flag) 408262306a36Sopenharmony_ci{ 408362306a36Sopenharmony_ci unsigned long flags; 408462306a36Sopenharmony_ci 408562306a36Sopenharmony_ci spin_lock_irqsave(&sbi->error_lock, flags); 408662306a36Sopenharmony_ci if (!test_bit(flag, (unsigned long *)sbi->errors)) { 408762306a36Sopenharmony_ci set_bit(flag, (unsigned long *)sbi->errors); 408862306a36Sopenharmony_ci sbi->error_dirty = true; 408962306a36Sopenharmony_ci } 409062306a36Sopenharmony_ci spin_unlock_irqrestore(&sbi->error_lock, flags); 409162306a36Sopenharmony_ci} 409262306a36Sopenharmony_ci 409362306a36Sopenharmony_cistatic bool f2fs_update_errors(struct f2fs_sb_info *sbi) 409462306a36Sopenharmony_ci{ 409562306a36Sopenharmony_ci unsigned long flags; 409662306a36Sopenharmony_ci bool need_update = false; 409762306a36Sopenharmony_ci 409862306a36Sopenharmony_ci spin_lock_irqsave(&sbi->error_lock, flags); 409962306a36Sopenharmony_ci if (sbi->error_dirty) { 410062306a36Sopenharmony_ci memcpy(F2FS_RAW_SUPER(sbi)->s_errors, sbi->errors, 410162306a36Sopenharmony_ci MAX_F2FS_ERRORS); 410262306a36Sopenharmony_ci sbi->error_dirty = false; 410362306a36Sopenharmony_ci need_update = true; 410462306a36Sopenharmony_ci } 410562306a36Sopenharmony_ci spin_unlock_irqrestore(&sbi->error_lock, flags); 410662306a36Sopenharmony_ci 410762306a36Sopenharmony_ci return need_update; 410862306a36Sopenharmony_ci} 410962306a36Sopenharmony_ci 411062306a36Sopenharmony_cistatic void f2fs_record_errors(struct f2fs_sb_info *sbi, unsigned char error) 411162306a36Sopenharmony_ci{ 411262306a36Sopenharmony_ci int err; 411362306a36Sopenharmony_ci 411462306a36Sopenharmony_ci f2fs_down_write(&sbi->sb_lock); 411562306a36Sopenharmony_ci 411662306a36Sopenharmony_ci if (!f2fs_update_errors(sbi)) 411762306a36Sopenharmony_ci goto out_unlock; 411862306a36Sopenharmony_ci 411962306a36Sopenharmony_ci err = f2fs_commit_super(sbi, false); 412062306a36Sopenharmony_ci if (err) 412162306a36Sopenharmony_ci f2fs_err(sbi, "f2fs_commit_super fails to record errors:%u, err:%d", 412262306a36Sopenharmony_ci error, err); 412362306a36Sopenharmony_ciout_unlock: 412462306a36Sopenharmony_ci f2fs_up_write(&sbi->sb_lock); 412562306a36Sopenharmony_ci} 412662306a36Sopenharmony_ci 412762306a36Sopenharmony_civoid f2fs_handle_error(struct f2fs_sb_info *sbi, unsigned char error) 412862306a36Sopenharmony_ci{ 412962306a36Sopenharmony_ci f2fs_save_errors(sbi, error); 413062306a36Sopenharmony_ci f2fs_record_errors(sbi, error); 413162306a36Sopenharmony_ci} 413262306a36Sopenharmony_ci 413362306a36Sopenharmony_civoid f2fs_handle_error_async(struct f2fs_sb_info *sbi, unsigned char error) 413462306a36Sopenharmony_ci{ 413562306a36Sopenharmony_ci f2fs_save_errors(sbi, error); 413662306a36Sopenharmony_ci 413762306a36Sopenharmony_ci if (!sbi->error_dirty) 413862306a36Sopenharmony_ci return; 413962306a36Sopenharmony_ci if (!test_bit(error, (unsigned long *)sbi->errors)) 414062306a36Sopenharmony_ci return; 414162306a36Sopenharmony_ci schedule_work(&sbi->s_error_work); 414262306a36Sopenharmony_ci} 414362306a36Sopenharmony_ci 414462306a36Sopenharmony_cistatic bool system_going_down(void) 414562306a36Sopenharmony_ci{ 414662306a36Sopenharmony_ci return system_state == SYSTEM_HALT || system_state == SYSTEM_POWER_OFF 414762306a36Sopenharmony_ci || system_state == SYSTEM_RESTART; 414862306a36Sopenharmony_ci} 414962306a36Sopenharmony_ci 415062306a36Sopenharmony_civoid f2fs_handle_critical_error(struct f2fs_sb_info *sbi, unsigned char reason, 415162306a36Sopenharmony_ci bool irq_context) 415262306a36Sopenharmony_ci{ 415362306a36Sopenharmony_ci struct super_block *sb = sbi->sb; 415462306a36Sopenharmony_ci bool shutdown = reason == STOP_CP_REASON_SHUTDOWN; 415562306a36Sopenharmony_ci bool continue_fs = !shutdown && 415662306a36Sopenharmony_ci F2FS_OPTION(sbi).errors == MOUNT_ERRORS_CONTINUE; 415762306a36Sopenharmony_ci 415862306a36Sopenharmony_ci set_ckpt_flags(sbi, CP_ERROR_FLAG); 415962306a36Sopenharmony_ci 416062306a36Sopenharmony_ci if (!f2fs_hw_is_readonly(sbi)) { 416162306a36Sopenharmony_ci save_stop_reason(sbi, reason); 416262306a36Sopenharmony_ci 416362306a36Sopenharmony_ci if (irq_context && !shutdown) 416462306a36Sopenharmony_ci schedule_work(&sbi->s_error_work); 416562306a36Sopenharmony_ci else 416662306a36Sopenharmony_ci f2fs_record_stop_reason(sbi); 416762306a36Sopenharmony_ci } 416862306a36Sopenharmony_ci 416962306a36Sopenharmony_ci /* 417062306a36Sopenharmony_ci * We force ERRORS_RO behavior when system is rebooting. Otherwise we 417162306a36Sopenharmony_ci * could panic during 'reboot -f' as the underlying device got already 417262306a36Sopenharmony_ci * disabled. 417362306a36Sopenharmony_ci */ 417462306a36Sopenharmony_ci if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_PANIC && 417562306a36Sopenharmony_ci !shutdown && !system_going_down() && 417662306a36Sopenharmony_ci !is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN)) 417762306a36Sopenharmony_ci panic("F2FS-fs (device %s): panic forced after error\n", 417862306a36Sopenharmony_ci sb->s_id); 417962306a36Sopenharmony_ci 418062306a36Sopenharmony_ci if (shutdown) 418162306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_IS_SHUTDOWN); 418262306a36Sopenharmony_ci 418362306a36Sopenharmony_ci /* continue filesystem operators if errors=continue */ 418462306a36Sopenharmony_ci if (continue_fs || f2fs_readonly(sb)) 418562306a36Sopenharmony_ci return; 418662306a36Sopenharmony_ci 418762306a36Sopenharmony_ci f2fs_warn(sbi, "Remounting filesystem read-only"); 418862306a36Sopenharmony_ci /* 418962306a36Sopenharmony_ci * Make sure updated value of ->s_mount_flags will be visible before 419062306a36Sopenharmony_ci * ->s_flags update 419162306a36Sopenharmony_ci */ 419262306a36Sopenharmony_ci smp_wmb(); 419362306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 419462306a36Sopenharmony_ci} 419562306a36Sopenharmony_ci 419662306a36Sopenharmony_cistatic void f2fs_record_error_work(struct work_struct *work) 419762306a36Sopenharmony_ci{ 419862306a36Sopenharmony_ci struct f2fs_sb_info *sbi = container_of(work, 419962306a36Sopenharmony_ci struct f2fs_sb_info, s_error_work); 420062306a36Sopenharmony_ci 420162306a36Sopenharmony_ci f2fs_record_stop_reason(sbi); 420262306a36Sopenharmony_ci} 420362306a36Sopenharmony_ci 420462306a36Sopenharmony_cistatic int f2fs_scan_devices(struct f2fs_sb_info *sbi) 420562306a36Sopenharmony_ci{ 420662306a36Sopenharmony_ci struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); 420762306a36Sopenharmony_ci unsigned int max_devices = MAX_DEVICES; 420862306a36Sopenharmony_ci unsigned int logical_blksize; 420962306a36Sopenharmony_ci blk_mode_t mode = sb_open_mode(sbi->sb->s_flags); 421062306a36Sopenharmony_ci int i; 421162306a36Sopenharmony_ci 421262306a36Sopenharmony_ci /* Initialize single device information */ 421362306a36Sopenharmony_ci if (!RDEV(0).path[0]) { 421462306a36Sopenharmony_ci if (!bdev_is_zoned(sbi->sb->s_bdev)) 421562306a36Sopenharmony_ci return 0; 421662306a36Sopenharmony_ci max_devices = 1; 421762306a36Sopenharmony_ci } 421862306a36Sopenharmony_ci 421962306a36Sopenharmony_ci /* 422062306a36Sopenharmony_ci * Initialize multiple devices information, or single 422162306a36Sopenharmony_ci * zoned block device information. 422262306a36Sopenharmony_ci */ 422362306a36Sopenharmony_ci sbi->devs = f2fs_kzalloc(sbi, 422462306a36Sopenharmony_ci array_size(max_devices, 422562306a36Sopenharmony_ci sizeof(struct f2fs_dev_info)), 422662306a36Sopenharmony_ci GFP_KERNEL); 422762306a36Sopenharmony_ci if (!sbi->devs) 422862306a36Sopenharmony_ci return -ENOMEM; 422962306a36Sopenharmony_ci 423062306a36Sopenharmony_ci logical_blksize = bdev_logical_block_size(sbi->sb->s_bdev); 423162306a36Sopenharmony_ci sbi->aligned_blksize = true; 423262306a36Sopenharmony_ci 423362306a36Sopenharmony_ci for (i = 0; i < max_devices; i++) { 423462306a36Sopenharmony_ci if (i == 0) 423562306a36Sopenharmony_ci FDEV(0).bdev = sbi->sb->s_bdev; 423662306a36Sopenharmony_ci else if (!RDEV(i).path[0]) 423762306a36Sopenharmony_ci break; 423862306a36Sopenharmony_ci 423962306a36Sopenharmony_ci if (max_devices > 1) { 424062306a36Sopenharmony_ci /* Multi-device mount */ 424162306a36Sopenharmony_ci memcpy(FDEV(i).path, RDEV(i).path, MAX_PATH_LEN); 424262306a36Sopenharmony_ci FDEV(i).total_segments = 424362306a36Sopenharmony_ci le32_to_cpu(RDEV(i).total_segments); 424462306a36Sopenharmony_ci if (i == 0) { 424562306a36Sopenharmony_ci FDEV(i).start_blk = 0; 424662306a36Sopenharmony_ci FDEV(i).end_blk = FDEV(i).start_blk + 424762306a36Sopenharmony_ci (FDEV(i).total_segments << 424862306a36Sopenharmony_ci sbi->log_blocks_per_seg) - 1 + 424962306a36Sopenharmony_ci le32_to_cpu(raw_super->segment0_blkaddr); 425062306a36Sopenharmony_ci } else { 425162306a36Sopenharmony_ci FDEV(i).start_blk = FDEV(i - 1).end_blk + 1; 425262306a36Sopenharmony_ci FDEV(i).end_blk = FDEV(i).start_blk + 425362306a36Sopenharmony_ci (FDEV(i).total_segments << 425462306a36Sopenharmony_ci sbi->log_blocks_per_seg) - 1; 425562306a36Sopenharmony_ci FDEV(i).bdev = blkdev_get_by_path(FDEV(i).path, 425662306a36Sopenharmony_ci mode, sbi->sb, NULL); 425762306a36Sopenharmony_ci } 425862306a36Sopenharmony_ci } 425962306a36Sopenharmony_ci if (IS_ERR(FDEV(i).bdev)) 426062306a36Sopenharmony_ci return PTR_ERR(FDEV(i).bdev); 426162306a36Sopenharmony_ci 426262306a36Sopenharmony_ci /* to release errored devices */ 426362306a36Sopenharmony_ci sbi->s_ndevs = i + 1; 426462306a36Sopenharmony_ci 426562306a36Sopenharmony_ci if (logical_blksize != bdev_logical_block_size(FDEV(i).bdev)) 426662306a36Sopenharmony_ci sbi->aligned_blksize = false; 426762306a36Sopenharmony_ci 426862306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED 426962306a36Sopenharmony_ci if (bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HM && 427062306a36Sopenharmony_ci !f2fs_sb_has_blkzoned(sbi)) { 427162306a36Sopenharmony_ci f2fs_err(sbi, "Zoned block device feature not enabled"); 427262306a36Sopenharmony_ci return -EINVAL; 427362306a36Sopenharmony_ci } 427462306a36Sopenharmony_ci if (bdev_zoned_model(FDEV(i).bdev) != BLK_ZONED_NONE) { 427562306a36Sopenharmony_ci if (init_blkz_info(sbi, i)) { 427662306a36Sopenharmony_ci f2fs_err(sbi, "Failed to initialize F2FS blkzone information"); 427762306a36Sopenharmony_ci return -EINVAL; 427862306a36Sopenharmony_ci } 427962306a36Sopenharmony_ci if (max_devices == 1) 428062306a36Sopenharmony_ci break; 428162306a36Sopenharmony_ci f2fs_info(sbi, "Mount Device [%2d]: %20s, %8u, %8x - %8x (zone: %s)", 428262306a36Sopenharmony_ci i, FDEV(i).path, 428362306a36Sopenharmony_ci FDEV(i).total_segments, 428462306a36Sopenharmony_ci FDEV(i).start_blk, FDEV(i).end_blk, 428562306a36Sopenharmony_ci bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HA ? 428662306a36Sopenharmony_ci "Host-aware" : "Host-managed"); 428762306a36Sopenharmony_ci continue; 428862306a36Sopenharmony_ci } 428962306a36Sopenharmony_ci#endif 429062306a36Sopenharmony_ci f2fs_info(sbi, "Mount Device [%2d]: %20s, %8u, %8x - %8x", 429162306a36Sopenharmony_ci i, FDEV(i).path, 429262306a36Sopenharmony_ci FDEV(i).total_segments, 429362306a36Sopenharmony_ci FDEV(i).start_blk, FDEV(i).end_blk); 429462306a36Sopenharmony_ci } 429562306a36Sopenharmony_ci f2fs_info(sbi, 429662306a36Sopenharmony_ci "IO Block Size: %8ld KB", F2FS_IO_SIZE_KB(sbi)); 429762306a36Sopenharmony_ci return 0; 429862306a36Sopenharmony_ci} 429962306a36Sopenharmony_ci 430062306a36Sopenharmony_cistatic int f2fs_setup_casefold(struct f2fs_sb_info *sbi) 430162306a36Sopenharmony_ci{ 430262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE) 430362306a36Sopenharmony_ci if (f2fs_sb_has_casefold(sbi) && !sbi->sb->s_encoding) { 430462306a36Sopenharmony_ci const struct f2fs_sb_encodings *encoding_info; 430562306a36Sopenharmony_ci struct unicode_map *encoding; 430662306a36Sopenharmony_ci __u16 encoding_flags; 430762306a36Sopenharmony_ci 430862306a36Sopenharmony_ci encoding_info = f2fs_sb_read_encoding(sbi->raw_super); 430962306a36Sopenharmony_ci if (!encoding_info) { 431062306a36Sopenharmony_ci f2fs_err(sbi, 431162306a36Sopenharmony_ci "Encoding requested by superblock is unknown"); 431262306a36Sopenharmony_ci return -EINVAL; 431362306a36Sopenharmony_ci } 431462306a36Sopenharmony_ci 431562306a36Sopenharmony_ci encoding_flags = le16_to_cpu(sbi->raw_super->s_encoding_flags); 431662306a36Sopenharmony_ci encoding = utf8_load(encoding_info->version); 431762306a36Sopenharmony_ci if (IS_ERR(encoding)) { 431862306a36Sopenharmony_ci f2fs_err(sbi, 431962306a36Sopenharmony_ci "can't mount with superblock charset: %s-%u.%u.%u " 432062306a36Sopenharmony_ci "not supported by the kernel. flags: 0x%x.", 432162306a36Sopenharmony_ci encoding_info->name, 432262306a36Sopenharmony_ci unicode_major(encoding_info->version), 432362306a36Sopenharmony_ci unicode_minor(encoding_info->version), 432462306a36Sopenharmony_ci unicode_rev(encoding_info->version), 432562306a36Sopenharmony_ci encoding_flags); 432662306a36Sopenharmony_ci return PTR_ERR(encoding); 432762306a36Sopenharmony_ci } 432862306a36Sopenharmony_ci f2fs_info(sbi, "Using encoding defined by superblock: " 432962306a36Sopenharmony_ci "%s-%u.%u.%u with flags 0x%hx", encoding_info->name, 433062306a36Sopenharmony_ci unicode_major(encoding_info->version), 433162306a36Sopenharmony_ci unicode_minor(encoding_info->version), 433262306a36Sopenharmony_ci unicode_rev(encoding_info->version), 433362306a36Sopenharmony_ci encoding_flags); 433462306a36Sopenharmony_ci 433562306a36Sopenharmony_ci sbi->sb->s_encoding = encoding; 433662306a36Sopenharmony_ci sbi->sb->s_encoding_flags = encoding_flags; 433762306a36Sopenharmony_ci } 433862306a36Sopenharmony_ci#else 433962306a36Sopenharmony_ci if (f2fs_sb_has_casefold(sbi)) { 434062306a36Sopenharmony_ci f2fs_err(sbi, "Filesystem with casefold feature cannot be mounted without CONFIG_UNICODE"); 434162306a36Sopenharmony_ci return -EINVAL; 434262306a36Sopenharmony_ci } 434362306a36Sopenharmony_ci#endif 434462306a36Sopenharmony_ci return 0; 434562306a36Sopenharmony_ci} 434662306a36Sopenharmony_ci 434762306a36Sopenharmony_cistatic void f2fs_tuning_parameters(struct f2fs_sb_info *sbi) 434862306a36Sopenharmony_ci{ 434962306a36Sopenharmony_ci /* adjust parameters according to the volume size */ 435062306a36Sopenharmony_ci if (MAIN_SEGS(sbi) <= SMALL_VOLUME_SEGMENTS) { 435162306a36Sopenharmony_ci if (f2fs_block_unit_discard(sbi)) 435262306a36Sopenharmony_ci SM_I(sbi)->dcc_info->discard_granularity = 435362306a36Sopenharmony_ci MIN_DISCARD_GRANULARITY; 435462306a36Sopenharmony_ci if (!f2fs_lfs_mode(sbi)) 435562306a36Sopenharmony_ci SM_I(sbi)->ipu_policy = BIT(F2FS_IPU_FORCE) | 435662306a36Sopenharmony_ci BIT(F2FS_IPU_HONOR_OPU_WRITE); 435762306a36Sopenharmony_ci } 435862306a36Sopenharmony_ci 435962306a36Sopenharmony_ci sbi->readdir_ra = true; 436062306a36Sopenharmony_ci} 436162306a36Sopenharmony_ci 436262306a36Sopenharmony_cistatic int f2fs_fill_super(struct super_block *sb, void *data, int silent) 436362306a36Sopenharmony_ci{ 436462306a36Sopenharmony_ci struct f2fs_sb_info *sbi; 436562306a36Sopenharmony_ci struct f2fs_super_block *raw_super; 436662306a36Sopenharmony_ci struct inode *root; 436762306a36Sopenharmony_ci int err; 436862306a36Sopenharmony_ci bool skip_recovery = false, need_fsck = false; 436962306a36Sopenharmony_ci char *options = NULL; 437062306a36Sopenharmony_ci int recovery, i, valid_super_block; 437162306a36Sopenharmony_ci struct curseg_info *seg_i; 437262306a36Sopenharmony_ci int retry_cnt = 1; 437362306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 437462306a36Sopenharmony_ci bool quota_enabled = false; 437562306a36Sopenharmony_ci#endif 437662306a36Sopenharmony_ci 437762306a36Sopenharmony_citry_onemore: 437862306a36Sopenharmony_ci err = -EINVAL; 437962306a36Sopenharmony_ci raw_super = NULL; 438062306a36Sopenharmony_ci valid_super_block = -1; 438162306a36Sopenharmony_ci recovery = 0; 438262306a36Sopenharmony_ci 438362306a36Sopenharmony_ci /* allocate memory for f2fs-specific super block info */ 438462306a36Sopenharmony_ci sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL); 438562306a36Sopenharmony_ci if (!sbi) 438662306a36Sopenharmony_ci return -ENOMEM; 438762306a36Sopenharmony_ci 438862306a36Sopenharmony_ci sbi->sb = sb; 438962306a36Sopenharmony_ci 439062306a36Sopenharmony_ci /* initialize locks within allocated memory */ 439162306a36Sopenharmony_ci init_f2fs_rwsem(&sbi->gc_lock); 439262306a36Sopenharmony_ci mutex_init(&sbi->writepages); 439362306a36Sopenharmony_ci init_f2fs_rwsem(&sbi->cp_global_sem); 439462306a36Sopenharmony_ci init_f2fs_rwsem(&sbi->node_write); 439562306a36Sopenharmony_ci init_f2fs_rwsem(&sbi->node_change); 439662306a36Sopenharmony_ci spin_lock_init(&sbi->stat_lock); 439762306a36Sopenharmony_ci init_f2fs_rwsem(&sbi->cp_rwsem); 439862306a36Sopenharmony_ci init_f2fs_rwsem(&sbi->quota_sem); 439962306a36Sopenharmony_ci init_waitqueue_head(&sbi->cp_wait); 440062306a36Sopenharmony_ci spin_lock_init(&sbi->error_lock); 440162306a36Sopenharmony_ci 440262306a36Sopenharmony_ci for (i = 0; i < NR_INODE_TYPE; i++) { 440362306a36Sopenharmony_ci INIT_LIST_HEAD(&sbi->inode_list[i]); 440462306a36Sopenharmony_ci spin_lock_init(&sbi->inode_lock[i]); 440562306a36Sopenharmony_ci } 440662306a36Sopenharmony_ci mutex_init(&sbi->flush_lock); 440762306a36Sopenharmony_ci 440862306a36Sopenharmony_ci /* Load the checksum driver */ 440962306a36Sopenharmony_ci sbi->s_chksum_driver = crypto_alloc_shash("crc32", 0, 0); 441062306a36Sopenharmony_ci if (IS_ERR(sbi->s_chksum_driver)) { 441162306a36Sopenharmony_ci f2fs_err(sbi, "Cannot load crc32 driver."); 441262306a36Sopenharmony_ci err = PTR_ERR(sbi->s_chksum_driver); 441362306a36Sopenharmony_ci sbi->s_chksum_driver = NULL; 441462306a36Sopenharmony_ci goto free_sbi; 441562306a36Sopenharmony_ci } 441662306a36Sopenharmony_ci 441762306a36Sopenharmony_ci /* set a block size */ 441862306a36Sopenharmony_ci if (unlikely(!sb_set_blocksize(sb, F2FS_BLKSIZE))) { 441962306a36Sopenharmony_ci f2fs_err(sbi, "unable to set blocksize"); 442062306a36Sopenharmony_ci goto free_sbi; 442162306a36Sopenharmony_ci } 442262306a36Sopenharmony_ci 442362306a36Sopenharmony_ci err = read_raw_super_block(sbi, &raw_super, &valid_super_block, 442462306a36Sopenharmony_ci &recovery); 442562306a36Sopenharmony_ci if (err) 442662306a36Sopenharmony_ci goto free_sbi; 442762306a36Sopenharmony_ci 442862306a36Sopenharmony_ci sb->s_fs_info = sbi; 442962306a36Sopenharmony_ci sbi->raw_super = raw_super; 443062306a36Sopenharmony_ci 443162306a36Sopenharmony_ci INIT_WORK(&sbi->s_error_work, f2fs_record_error_work); 443262306a36Sopenharmony_ci memcpy(sbi->errors, raw_super->s_errors, MAX_F2FS_ERRORS); 443362306a36Sopenharmony_ci memcpy(sbi->stop_reason, raw_super->s_stop_reason, MAX_STOP_REASON); 443462306a36Sopenharmony_ci 443562306a36Sopenharmony_ci /* precompute checksum seed for metadata */ 443662306a36Sopenharmony_ci if (f2fs_sb_has_inode_chksum(sbi)) 443762306a36Sopenharmony_ci sbi->s_chksum_seed = f2fs_chksum(sbi, ~0, raw_super->uuid, 443862306a36Sopenharmony_ci sizeof(raw_super->uuid)); 443962306a36Sopenharmony_ci 444062306a36Sopenharmony_ci default_options(sbi, false); 444162306a36Sopenharmony_ci /* parse mount options */ 444262306a36Sopenharmony_ci options = kstrdup((const char *)data, GFP_KERNEL); 444362306a36Sopenharmony_ci if (data && !options) { 444462306a36Sopenharmony_ci err = -ENOMEM; 444562306a36Sopenharmony_ci goto free_sb_buf; 444662306a36Sopenharmony_ci } 444762306a36Sopenharmony_ci 444862306a36Sopenharmony_ci err = parse_options(sb, options, false); 444962306a36Sopenharmony_ci if (err) 445062306a36Sopenharmony_ci goto free_options; 445162306a36Sopenharmony_ci 445262306a36Sopenharmony_ci sb->s_maxbytes = max_file_blocks(NULL) << 445362306a36Sopenharmony_ci le32_to_cpu(raw_super->log_blocksize); 445462306a36Sopenharmony_ci sb->s_max_links = F2FS_LINK_MAX; 445562306a36Sopenharmony_ci 445662306a36Sopenharmony_ci err = f2fs_setup_casefold(sbi); 445762306a36Sopenharmony_ci if (err) 445862306a36Sopenharmony_ci goto free_options; 445962306a36Sopenharmony_ci 446062306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 446162306a36Sopenharmony_ci sb->dq_op = &f2fs_quota_operations; 446262306a36Sopenharmony_ci sb->s_qcop = &f2fs_quotactl_ops; 446362306a36Sopenharmony_ci sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ; 446462306a36Sopenharmony_ci 446562306a36Sopenharmony_ci if (f2fs_sb_has_quota_ino(sbi)) { 446662306a36Sopenharmony_ci for (i = 0; i < MAXQUOTAS; i++) { 446762306a36Sopenharmony_ci if (f2fs_qf_ino(sbi->sb, i)) 446862306a36Sopenharmony_ci sbi->nquota_files++; 446962306a36Sopenharmony_ci } 447062306a36Sopenharmony_ci } 447162306a36Sopenharmony_ci#endif 447262306a36Sopenharmony_ci 447362306a36Sopenharmony_ci sb->s_op = &f2fs_sops; 447462306a36Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION 447562306a36Sopenharmony_ci sb->s_cop = &f2fs_cryptops; 447662306a36Sopenharmony_ci#endif 447762306a36Sopenharmony_ci#ifdef CONFIG_FS_VERITY 447862306a36Sopenharmony_ci sb->s_vop = &f2fs_verityops; 447962306a36Sopenharmony_ci#endif 448062306a36Sopenharmony_ci sb->s_xattr = f2fs_xattr_handlers; 448162306a36Sopenharmony_ci sb->s_export_op = &f2fs_export_ops; 448262306a36Sopenharmony_ci sb->s_magic = F2FS_SUPER_MAGIC; 448362306a36Sopenharmony_ci sb->s_time_gran = 1; 448462306a36Sopenharmony_ci sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | 448562306a36Sopenharmony_ci (test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0); 448662306a36Sopenharmony_ci memcpy(&sb->s_uuid, raw_super->uuid, sizeof(raw_super->uuid)); 448762306a36Sopenharmony_ci sb->s_iflags |= SB_I_CGROUPWB; 448862306a36Sopenharmony_ci 448962306a36Sopenharmony_ci /* init f2fs-specific super block info */ 449062306a36Sopenharmony_ci sbi->valid_super_block = valid_super_block; 449162306a36Sopenharmony_ci 449262306a36Sopenharmony_ci /* disallow all the data/node/meta page writes */ 449362306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_POR_DOING); 449462306a36Sopenharmony_ci 449562306a36Sopenharmony_ci err = f2fs_init_write_merge_io(sbi); 449662306a36Sopenharmony_ci if (err) 449762306a36Sopenharmony_ci goto free_bio_info; 449862306a36Sopenharmony_ci 449962306a36Sopenharmony_ci init_sb_info(sbi); 450062306a36Sopenharmony_ci 450162306a36Sopenharmony_ci err = f2fs_init_iostat(sbi); 450262306a36Sopenharmony_ci if (err) 450362306a36Sopenharmony_ci goto free_bio_info; 450462306a36Sopenharmony_ci 450562306a36Sopenharmony_ci err = init_percpu_info(sbi); 450662306a36Sopenharmony_ci if (err) 450762306a36Sopenharmony_ci goto free_iostat; 450862306a36Sopenharmony_ci 450962306a36Sopenharmony_ci if (F2FS_IO_ALIGNED(sbi)) { 451062306a36Sopenharmony_ci sbi->write_io_dummy = 451162306a36Sopenharmony_ci mempool_create_page_pool(2 * (F2FS_IO_SIZE(sbi) - 1), 0); 451262306a36Sopenharmony_ci if (!sbi->write_io_dummy) { 451362306a36Sopenharmony_ci err = -ENOMEM; 451462306a36Sopenharmony_ci goto free_percpu; 451562306a36Sopenharmony_ci } 451662306a36Sopenharmony_ci } 451762306a36Sopenharmony_ci 451862306a36Sopenharmony_ci /* init per sbi slab cache */ 451962306a36Sopenharmony_ci err = f2fs_init_xattr_caches(sbi); 452062306a36Sopenharmony_ci if (err) 452162306a36Sopenharmony_ci goto free_io_dummy; 452262306a36Sopenharmony_ci err = f2fs_init_page_array_cache(sbi); 452362306a36Sopenharmony_ci if (err) 452462306a36Sopenharmony_ci goto free_xattr_cache; 452562306a36Sopenharmony_ci 452662306a36Sopenharmony_ci /* get an inode for meta space */ 452762306a36Sopenharmony_ci sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi)); 452862306a36Sopenharmony_ci if (IS_ERR(sbi->meta_inode)) { 452962306a36Sopenharmony_ci f2fs_err(sbi, "Failed to read F2FS meta data inode"); 453062306a36Sopenharmony_ci err = PTR_ERR(sbi->meta_inode); 453162306a36Sopenharmony_ci goto free_page_array_cache; 453262306a36Sopenharmony_ci } 453362306a36Sopenharmony_ci 453462306a36Sopenharmony_ci err = f2fs_get_valid_checkpoint(sbi); 453562306a36Sopenharmony_ci if (err) { 453662306a36Sopenharmony_ci f2fs_err(sbi, "Failed to get valid F2FS checkpoint"); 453762306a36Sopenharmony_ci goto free_meta_inode; 453862306a36Sopenharmony_ci } 453962306a36Sopenharmony_ci 454062306a36Sopenharmony_ci if (__is_set_ckpt_flags(F2FS_CKPT(sbi), CP_QUOTA_NEED_FSCK_FLAG)) 454162306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); 454262306a36Sopenharmony_ci if (__is_set_ckpt_flags(F2FS_CKPT(sbi), CP_DISABLED_QUICK_FLAG)) { 454362306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_CP_DISABLED_QUICK); 454462306a36Sopenharmony_ci sbi->interval_time[DISABLE_TIME] = DEF_DISABLE_QUICK_INTERVAL; 454562306a36Sopenharmony_ci } 454662306a36Sopenharmony_ci 454762306a36Sopenharmony_ci if (__is_set_ckpt_flags(F2FS_CKPT(sbi), CP_FSCK_FLAG)) 454862306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_NEED_FSCK); 454962306a36Sopenharmony_ci 455062306a36Sopenharmony_ci /* Initialize device list */ 455162306a36Sopenharmony_ci err = f2fs_scan_devices(sbi); 455262306a36Sopenharmony_ci if (err) { 455362306a36Sopenharmony_ci f2fs_err(sbi, "Failed to find devices"); 455462306a36Sopenharmony_ci goto free_devices; 455562306a36Sopenharmony_ci } 455662306a36Sopenharmony_ci 455762306a36Sopenharmony_ci err = f2fs_init_post_read_wq(sbi); 455862306a36Sopenharmony_ci if (err) { 455962306a36Sopenharmony_ci f2fs_err(sbi, "Failed to initialize post read workqueue"); 456062306a36Sopenharmony_ci goto free_devices; 456162306a36Sopenharmony_ci } 456262306a36Sopenharmony_ci 456362306a36Sopenharmony_ci sbi->total_valid_node_count = 456462306a36Sopenharmony_ci le32_to_cpu(sbi->ckpt->valid_node_count); 456562306a36Sopenharmony_ci percpu_counter_set(&sbi->total_valid_inode_count, 456662306a36Sopenharmony_ci le32_to_cpu(sbi->ckpt->valid_inode_count)); 456762306a36Sopenharmony_ci sbi->user_block_count = le64_to_cpu(sbi->ckpt->user_block_count); 456862306a36Sopenharmony_ci sbi->total_valid_block_count = 456962306a36Sopenharmony_ci le64_to_cpu(sbi->ckpt->valid_block_count); 457062306a36Sopenharmony_ci sbi->last_valid_block_count = sbi->total_valid_block_count; 457162306a36Sopenharmony_ci sbi->reserved_blocks = 0; 457262306a36Sopenharmony_ci sbi->current_reserved_blocks = 0; 457362306a36Sopenharmony_ci limit_reserve_root(sbi); 457462306a36Sopenharmony_ci adjust_unusable_cap_perc(sbi); 457562306a36Sopenharmony_ci 457662306a36Sopenharmony_ci f2fs_init_extent_cache_info(sbi); 457762306a36Sopenharmony_ci 457862306a36Sopenharmony_ci f2fs_init_ino_entry_info(sbi); 457962306a36Sopenharmony_ci 458062306a36Sopenharmony_ci f2fs_init_fsync_node_info(sbi); 458162306a36Sopenharmony_ci 458262306a36Sopenharmony_ci /* setup checkpoint request control and start checkpoint issue thread */ 458362306a36Sopenharmony_ci f2fs_init_ckpt_req_control(sbi); 458462306a36Sopenharmony_ci if (!f2fs_readonly(sb) && !test_opt(sbi, DISABLE_CHECKPOINT) && 458562306a36Sopenharmony_ci test_opt(sbi, MERGE_CHECKPOINT)) { 458662306a36Sopenharmony_ci err = f2fs_start_ckpt_thread(sbi); 458762306a36Sopenharmony_ci if (err) { 458862306a36Sopenharmony_ci f2fs_err(sbi, 458962306a36Sopenharmony_ci "Failed to start F2FS issue_checkpoint_thread (%d)", 459062306a36Sopenharmony_ci err); 459162306a36Sopenharmony_ci goto stop_ckpt_thread; 459262306a36Sopenharmony_ci } 459362306a36Sopenharmony_ci } 459462306a36Sopenharmony_ci 459562306a36Sopenharmony_ci /* setup f2fs internal modules */ 459662306a36Sopenharmony_ci err = f2fs_build_segment_manager(sbi); 459762306a36Sopenharmony_ci if (err) { 459862306a36Sopenharmony_ci f2fs_err(sbi, "Failed to initialize F2FS segment manager (%d)", 459962306a36Sopenharmony_ci err); 460062306a36Sopenharmony_ci goto free_sm; 460162306a36Sopenharmony_ci } 460262306a36Sopenharmony_ci err = f2fs_build_node_manager(sbi); 460362306a36Sopenharmony_ci if (err) { 460462306a36Sopenharmony_ci f2fs_err(sbi, "Failed to initialize F2FS node manager (%d)", 460562306a36Sopenharmony_ci err); 460662306a36Sopenharmony_ci goto free_nm; 460762306a36Sopenharmony_ci } 460862306a36Sopenharmony_ci 460962306a36Sopenharmony_ci err = adjust_reserved_segment(sbi); 461062306a36Sopenharmony_ci if (err) 461162306a36Sopenharmony_ci goto free_nm; 461262306a36Sopenharmony_ci 461362306a36Sopenharmony_ci /* For write statistics */ 461462306a36Sopenharmony_ci sbi->sectors_written_start = f2fs_get_sectors_written(sbi); 461562306a36Sopenharmony_ci 461662306a36Sopenharmony_ci /* Read accumulated write IO statistics if exists */ 461762306a36Sopenharmony_ci seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE); 461862306a36Sopenharmony_ci if (__exist_node_summaries(sbi)) 461962306a36Sopenharmony_ci sbi->kbytes_written = 462062306a36Sopenharmony_ci le64_to_cpu(seg_i->journal->info.kbytes_written); 462162306a36Sopenharmony_ci 462262306a36Sopenharmony_ci f2fs_build_gc_manager(sbi); 462362306a36Sopenharmony_ci 462462306a36Sopenharmony_ci err = f2fs_build_stats(sbi); 462562306a36Sopenharmony_ci if (err) 462662306a36Sopenharmony_ci goto free_nm; 462762306a36Sopenharmony_ci 462862306a36Sopenharmony_ci /* get an inode for node space */ 462962306a36Sopenharmony_ci sbi->node_inode = f2fs_iget(sb, F2FS_NODE_INO(sbi)); 463062306a36Sopenharmony_ci if (IS_ERR(sbi->node_inode)) { 463162306a36Sopenharmony_ci f2fs_err(sbi, "Failed to read node inode"); 463262306a36Sopenharmony_ci err = PTR_ERR(sbi->node_inode); 463362306a36Sopenharmony_ci goto free_stats; 463462306a36Sopenharmony_ci } 463562306a36Sopenharmony_ci 463662306a36Sopenharmony_ci /* read root inode and dentry */ 463762306a36Sopenharmony_ci root = f2fs_iget(sb, F2FS_ROOT_INO(sbi)); 463862306a36Sopenharmony_ci if (IS_ERR(root)) { 463962306a36Sopenharmony_ci f2fs_err(sbi, "Failed to read root inode"); 464062306a36Sopenharmony_ci err = PTR_ERR(root); 464162306a36Sopenharmony_ci goto free_node_inode; 464262306a36Sopenharmony_ci } 464362306a36Sopenharmony_ci if (!S_ISDIR(root->i_mode) || !root->i_blocks || 464462306a36Sopenharmony_ci !root->i_size || !root->i_nlink) { 464562306a36Sopenharmony_ci iput(root); 464662306a36Sopenharmony_ci err = -EINVAL; 464762306a36Sopenharmony_ci goto free_node_inode; 464862306a36Sopenharmony_ci } 464962306a36Sopenharmony_ci 465062306a36Sopenharmony_ci sb->s_root = d_make_root(root); /* allocate root dentry */ 465162306a36Sopenharmony_ci if (!sb->s_root) { 465262306a36Sopenharmony_ci err = -ENOMEM; 465362306a36Sopenharmony_ci goto free_node_inode; 465462306a36Sopenharmony_ci } 465562306a36Sopenharmony_ci 465662306a36Sopenharmony_ci err = f2fs_init_compress_inode(sbi); 465762306a36Sopenharmony_ci if (err) 465862306a36Sopenharmony_ci goto free_root_inode; 465962306a36Sopenharmony_ci 466062306a36Sopenharmony_ci err = f2fs_register_sysfs(sbi); 466162306a36Sopenharmony_ci if (err) 466262306a36Sopenharmony_ci goto free_compress_inode; 466362306a36Sopenharmony_ci 466462306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 466562306a36Sopenharmony_ci /* Enable quota usage during mount */ 466662306a36Sopenharmony_ci if (f2fs_sb_has_quota_ino(sbi) && !f2fs_readonly(sb)) { 466762306a36Sopenharmony_ci err = f2fs_enable_quotas(sb); 466862306a36Sopenharmony_ci if (err) 466962306a36Sopenharmony_ci f2fs_err(sbi, "Cannot turn on quotas: error %d", err); 467062306a36Sopenharmony_ci } 467162306a36Sopenharmony_ci 467262306a36Sopenharmony_ci quota_enabled = f2fs_recover_quota_begin(sbi); 467362306a36Sopenharmony_ci#endif 467462306a36Sopenharmony_ci /* if there are any orphan inodes, free them */ 467562306a36Sopenharmony_ci err = f2fs_recover_orphan_inodes(sbi); 467662306a36Sopenharmony_ci if (err) 467762306a36Sopenharmony_ci goto free_meta; 467862306a36Sopenharmony_ci 467962306a36Sopenharmony_ci if (unlikely(is_set_ckpt_flags(sbi, CP_DISABLED_FLAG))) 468062306a36Sopenharmony_ci goto reset_checkpoint; 468162306a36Sopenharmony_ci 468262306a36Sopenharmony_ci /* recover fsynced data */ 468362306a36Sopenharmony_ci if (!test_opt(sbi, DISABLE_ROLL_FORWARD) && 468462306a36Sopenharmony_ci !test_opt(sbi, NORECOVERY)) { 468562306a36Sopenharmony_ci /* 468662306a36Sopenharmony_ci * mount should be failed, when device has readonly mode, and 468762306a36Sopenharmony_ci * previous checkpoint was not done by clean system shutdown. 468862306a36Sopenharmony_ci */ 468962306a36Sopenharmony_ci if (f2fs_hw_is_readonly(sbi)) { 469062306a36Sopenharmony_ci if (!is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) { 469162306a36Sopenharmony_ci err = f2fs_recover_fsync_data(sbi, true); 469262306a36Sopenharmony_ci if (err > 0) { 469362306a36Sopenharmony_ci err = -EROFS; 469462306a36Sopenharmony_ci f2fs_err(sbi, "Need to recover fsync data, but " 469562306a36Sopenharmony_ci "write access unavailable, please try " 469662306a36Sopenharmony_ci "mount w/ disable_roll_forward or norecovery"); 469762306a36Sopenharmony_ci } 469862306a36Sopenharmony_ci if (err < 0) 469962306a36Sopenharmony_ci goto free_meta; 470062306a36Sopenharmony_ci } 470162306a36Sopenharmony_ci f2fs_info(sbi, "write access unavailable, skipping recovery"); 470262306a36Sopenharmony_ci goto reset_checkpoint; 470362306a36Sopenharmony_ci } 470462306a36Sopenharmony_ci 470562306a36Sopenharmony_ci if (need_fsck) 470662306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_NEED_FSCK); 470762306a36Sopenharmony_ci 470862306a36Sopenharmony_ci if (skip_recovery) 470962306a36Sopenharmony_ci goto reset_checkpoint; 471062306a36Sopenharmony_ci 471162306a36Sopenharmony_ci err = f2fs_recover_fsync_data(sbi, false); 471262306a36Sopenharmony_ci if (err < 0) { 471362306a36Sopenharmony_ci if (err != -ENOMEM) 471462306a36Sopenharmony_ci skip_recovery = true; 471562306a36Sopenharmony_ci need_fsck = true; 471662306a36Sopenharmony_ci f2fs_err(sbi, "Cannot recover all fsync data errno=%d", 471762306a36Sopenharmony_ci err); 471862306a36Sopenharmony_ci goto free_meta; 471962306a36Sopenharmony_ci } 472062306a36Sopenharmony_ci } else { 472162306a36Sopenharmony_ci err = f2fs_recover_fsync_data(sbi, true); 472262306a36Sopenharmony_ci 472362306a36Sopenharmony_ci if (!f2fs_readonly(sb) && err > 0) { 472462306a36Sopenharmony_ci err = -EINVAL; 472562306a36Sopenharmony_ci f2fs_err(sbi, "Need to recover fsync data"); 472662306a36Sopenharmony_ci goto free_meta; 472762306a36Sopenharmony_ci } 472862306a36Sopenharmony_ci } 472962306a36Sopenharmony_ci 473062306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 473162306a36Sopenharmony_ci f2fs_recover_quota_end(sbi, quota_enabled); 473262306a36Sopenharmony_ci#endif 473362306a36Sopenharmony_ci 473462306a36Sopenharmony_ci /* 473562306a36Sopenharmony_ci * If the f2fs is not readonly and fsync data recovery succeeds, 473662306a36Sopenharmony_ci * check zoned block devices' write pointer consistency. 473762306a36Sopenharmony_ci */ 473862306a36Sopenharmony_ci if (!err && !f2fs_readonly(sb) && f2fs_sb_has_blkzoned(sbi)) { 473962306a36Sopenharmony_ci err = f2fs_check_write_pointer(sbi); 474062306a36Sopenharmony_ci if (err) 474162306a36Sopenharmony_ci goto free_meta; 474262306a36Sopenharmony_ci } 474362306a36Sopenharmony_ci 474462306a36Sopenharmony_cireset_checkpoint: 474562306a36Sopenharmony_ci f2fs_init_inmem_curseg(sbi); 474662306a36Sopenharmony_ci 474762306a36Sopenharmony_ci /* f2fs_recover_fsync_data() cleared this already */ 474862306a36Sopenharmony_ci clear_sbi_flag(sbi, SBI_POR_DOING); 474962306a36Sopenharmony_ci 475062306a36Sopenharmony_ci if (test_opt(sbi, DISABLE_CHECKPOINT)) { 475162306a36Sopenharmony_ci err = f2fs_disable_checkpoint(sbi); 475262306a36Sopenharmony_ci if (err) 475362306a36Sopenharmony_ci goto sync_free_meta; 475462306a36Sopenharmony_ci } else if (is_set_ckpt_flags(sbi, CP_DISABLED_FLAG)) { 475562306a36Sopenharmony_ci f2fs_enable_checkpoint(sbi); 475662306a36Sopenharmony_ci } 475762306a36Sopenharmony_ci 475862306a36Sopenharmony_ci /* 475962306a36Sopenharmony_ci * If filesystem is not mounted as read-only then 476062306a36Sopenharmony_ci * do start the gc_thread. 476162306a36Sopenharmony_ci */ 476262306a36Sopenharmony_ci if ((F2FS_OPTION(sbi).bggc_mode != BGGC_MODE_OFF || 476362306a36Sopenharmony_ci test_opt(sbi, GC_MERGE)) && !f2fs_readonly(sb)) { 476462306a36Sopenharmony_ci /* After POR, we can run background GC thread.*/ 476562306a36Sopenharmony_ci err = f2fs_start_gc_thread(sbi); 476662306a36Sopenharmony_ci if (err) 476762306a36Sopenharmony_ci goto sync_free_meta; 476862306a36Sopenharmony_ci } 476962306a36Sopenharmony_ci kvfree(options); 477062306a36Sopenharmony_ci 477162306a36Sopenharmony_ci /* recover broken superblock */ 477262306a36Sopenharmony_ci if (recovery) { 477362306a36Sopenharmony_ci err = f2fs_commit_super(sbi, true); 477462306a36Sopenharmony_ci f2fs_info(sbi, "Try to recover %dth superblock, ret: %d", 477562306a36Sopenharmony_ci sbi->valid_super_block ? 1 : 2, err); 477662306a36Sopenharmony_ci } 477762306a36Sopenharmony_ci 477862306a36Sopenharmony_ci f2fs_join_shrinker(sbi); 477962306a36Sopenharmony_ci 478062306a36Sopenharmony_ci f2fs_tuning_parameters(sbi); 478162306a36Sopenharmony_ci 478262306a36Sopenharmony_ci f2fs_notice(sbi, "Mounted with checkpoint version = %llx", 478362306a36Sopenharmony_ci cur_cp_version(F2FS_CKPT(sbi))); 478462306a36Sopenharmony_ci f2fs_update_time(sbi, CP_TIME); 478562306a36Sopenharmony_ci f2fs_update_time(sbi, REQ_TIME); 478662306a36Sopenharmony_ci clear_sbi_flag(sbi, SBI_CP_DISABLED_QUICK); 478762306a36Sopenharmony_ci return 0; 478862306a36Sopenharmony_ci 478962306a36Sopenharmony_cisync_free_meta: 479062306a36Sopenharmony_ci /* safe to flush all the data */ 479162306a36Sopenharmony_ci sync_filesystem(sbi->sb); 479262306a36Sopenharmony_ci retry_cnt = 0; 479362306a36Sopenharmony_ci 479462306a36Sopenharmony_cifree_meta: 479562306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 479662306a36Sopenharmony_ci f2fs_truncate_quota_inode_pages(sb); 479762306a36Sopenharmony_ci if (f2fs_sb_has_quota_ino(sbi) && !f2fs_readonly(sb)) 479862306a36Sopenharmony_ci f2fs_quota_off_umount(sbi->sb); 479962306a36Sopenharmony_ci#endif 480062306a36Sopenharmony_ci /* 480162306a36Sopenharmony_ci * Some dirty meta pages can be produced by f2fs_recover_orphan_inodes() 480262306a36Sopenharmony_ci * failed by EIO. Then, iput(node_inode) can trigger balance_fs_bg() 480362306a36Sopenharmony_ci * followed by f2fs_write_checkpoint() through f2fs_write_node_pages(), which 480462306a36Sopenharmony_ci * falls into an infinite loop in f2fs_sync_meta_pages(). 480562306a36Sopenharmony_ci */ 480662306a36Sopenharmony_ci truncate_inode_pages_final(META_MAPPING(sbi)); 480762306a36Sopenharmony_ci /* evict some inodes being cached by GC */ 480862306a36Sopenharmony_ci evict_inodes(sb); 480962306a36Sopenharmony_ci f2fs_unregister_sysfs(sbi); 481062306a36Sopenharmony_cifree_compress_inode: 481162306a36Sopenharmony_ci f2fs_destroy_compress_inode(sbi); 481262306a36Sopenharmony_cifree_root_inode: 481362306a36Sopenharmony_ci dput(sb->s_root); 481462306a36Sopenharmony_ci sb->s_root = NULL; 481562306a36Sopenharmony_cifree_node_inode: 481662306a36Sopenharmony_ci f2fs_release_ino_entry(sbi, true); 481762306a36Sopenharmony_ci truncate_inode_pages_final(NODE_MAPPING(sbi)); 481862306a36Sopenharmony_ci iput(sbi->node_inode); 481962306a36Sopenharmony_ci sbi->node_inode = NULL; 482062306a36Sopenharmony_cifree_stats: 482162306a36Sopenharmony_ci f2fs_destroy_stats(sbi); 482262306a36Sopenharmony_cifree_nm: 482362306a36Sopenharmony_ci /* stop discard thread before destroying node manager */ 482462306a36Sopenharmony_ci f2fs_stop_discard_thread(sbi); 482562306a36Sopenharmony_ci f2fs_destroy_node_manager(sbi); 482662306a36Sopenharmony_cifree_sm: 482762306a36Sopenharmony_ci f2fs_destroy_segment_manager(sbi); 482862306a36Sopenharmony_cistop_ckpt_thread: 482962306a36Sopenharmony_ci f2fs_stop_ckpt_thread(sbi); 483062306a36Sopenharmony_ci /* flush s_error_work before sbi destroy */ 483162306a36Sopenharmony_ci flush_work(&sbi->s_error_work); 483262306a36Sopenharmony_ci f2fs_destroy_post_read_wq(sbi); 483362306a36Sopenharmony_cifree_devices: 483462306a36Sopenharmony_ci destroy_device_list(sbi); 483562306a36Sopenharmony_ci kvfree(sbi->ckpt); 483662306a36Sopenharmony_cifree_meta_inode: 483762306a36Sopenharmony_ci make_bad_inode(sbi->meta_inode); 483862306a36Sopenharmony_ci iput(sbi->meta_inode); 483962306a36Sopenharmony_ci sbi->meta_inode = NULL; 484062306a36Sopenharmony_cifree_page_array_cache: 484162306a36Sopenharmony_ci f2fs_destroy_page_array_cache(sbi); 484262306a36Sopenharmony_cifree_xattr_cache: 484362306a36Sopenharmony_ci f2fs_destroy_xattr_caches(sbi); 484462306a36Sopenharmony_cifree_io_dummy: 484562306a36Sopenharmony_ci mempool_destroy(sbi->write_io_dummy); 484662306a36Sopenharmony_cifree_percpu: 484762306a36Sopenharmony_ci destroy_percpu_info(sbi); 484862306a36Sopenharmony_cifree_iostat: 484962306a36Sopenharmony_ci f2fs_destroy_iostat(sbi); 485062306a36Sopenharmony_cifree_bio_info: 485162306a36Sopenharmony_ci for (i = 0; i < NR_PAGE_TYPE; i++) 485262306a36Sopenharmony_ci kvfree(sbi->write_io[i]); 485362306a36Sopenharmony_ci 485462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE) 485562306a36Sopenharmony_ci utf8_unload(sb->s_encoding); 485662306a36Sopenharmony_ci sb->s_encoding = NULL; 485762306a36Sopenharmony_ci#endif 485862306a36Sopenharmony_cifree_options: 485962306a36Sopenharmony_ci#ifdef CONFIG_QUOTA 486062306a36Sopenharmony_ci for (i = 0; i < MAXQUOTAS; i++) 486162306a36Sopenharmony_ci kfree(F2FS_OPTION(sbi).s_qf_names[i]); 486262306a36Sopenharmony_ci#endif 486362306a36Sopenharmony_ci fscrypt_free_dummy_policy(&F2FS_OPTION(sbi).dummy_enc_policy); 486462306a36Sopenharmony_ci kvfree(options); 486562306a36Sopenharmony_cifree_sb_buf: 486662306a36Sopenharmony_ci kfree(raw_super); 486762306a36Sopenharmony_cifree_sbi: 486862306a36Sopenharmony_ci if (sbi->s_chksum_driver) 486962306a36Sopenharmony_ci crypto_free_shash(sbi->s_chksum_driver); 487062306a36Sopenharmony_ci kfree(sbi); 487162306a36Sopenharmony_ci 487262306a36Sopenharmony_ci /* give only one another chance */ 487362306a36Sopenharmony_ci if (retry_cnt > 0 && skip_recovery) { 487462306a36Sopenharmony_ci retry_cnt--; 487562306a36Sopenharmony_ci shrink_dcache_sb(sb); 487662306a36Sopenharmony_ci goto try_onemore; 487762306a36Sopenharmony_ci } 487862306a36Sopenharmony_ci return err; 487962306a36Sopenharmony_ci} 488062306a36Sopenharmony_ci 488162306a36Sopenharmony_cistatic struct dentry *f2fs_mount(struct file_system_type *fs_type, int flags, 488262306a36Sopenharmony_ci const char *dev_name, void *data) 488362306a36Sopenharmony_ci{ 488462306a36Sopenharmony_ci return mount_bdev(fs_type, flags, dev_name, data, f2fs_fill_super); 488562306a36Sopenharmony_ci} 488662306a36Sopenharmony_ci 488762306a36Sopenharmony_cistatic void kill_f2fs_super(struct super_block *sb) 488862306a36Sopenharmony_ci{ 488962306a36Sopenharmony_ci if (sb->s_root) { 489062306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_SB(sb); 489162306a36Sopenharmony_ci 489262306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_IS_CLOSE); 489362306a36Sopenharmony_ci f2fs_stop_gc_thread(sbi); 489462306a36Sopenharmony_ci f2fs_stop_discard_thread(sbi); 489562306a36Sopenharmony_ci 489662306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_COMPRESSION 489762306a36Sopenharmony_ci /* 489862306a36Sopenharmony_ci * latter evict_inode() can bypass checking and invalidating 489962306a36Sopenharmony_ci * compress inode cache. 490062306a36Sopenharmony_ci */ 490162306a36Sopenharmony_ci if (test_opt(sbi, COMPRESS_CACHE)) 490262306a36Sopenharmony_ci truncate_inode_pages_final(COMPRESS_MAPPING(sbi)); 490362306a36Sopenharmony_ci#endif 490462306a36Sopenharmony_ci 490562306a36Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_IS_DIRTY) || 490662306a36Sopenharmony_ci !is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) { 490762306a36Sopenharmony_ci struct cp_control cpc = { 490862306a36Sopenharmony_ci .reason = CP_UMOUNT, 490962306a36Sopenharmony_ci }; 491062306a36Sopenharmony_ci stat_inc_cp_call_count(sbi, TOTAL_CALL); 491162306a36Sopenharmony_ci f2fs_write_checkpoint(sbi, &cpc); 491262306a36Sopenharmony_ci } 491362306a36Sopenharmony_ci 491462306a36Sopenharmony_ci if (is_sbi_flag_set(sbi, SBI_IS_RECOVERED) && f2fs_readonly(sb)) 491562306a36Sopenharmony_ci sb->s_flags &= ~SB_RDONLY; 491662306a36Sopenharmony_ci } 491762306a36Sopenharmony_ci kill_block_super(sb); 491862306a36Sopenharmony_ci} 491962306a36Sopenharmony_ci 492062306a36Sopenharmony_cistatic struct file_system_type f2fs_fs_type = { 492162306a36Sopenharmony_ci .owner = THIS_MODULE, 492262306a36Sopenharmony_ci .name = "f2fs", 492362306a36Sopenharmony_ci .mount = f2fs_mount, 492462306a36Sopenharmony_ci .kill_sb = kill_f2fs_super, 492562306a36Sopenharmony_ci .fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP, 492662306a36Sopenharmony_ci}; 492762306a36Sopenharmony_ciMODULE_ALIAS_FS("f2fs"); 492862306a36Sopenharmony_ci 492962306a36Sopenharmony_cistatic int __init init_inodecache(void) 493062306a36Sopenharmony_ci{ 493162306a36Sopenharmony_ci f2fs_inode_cachep = kmem_cache_create("f2fs_inode_cache", 493262306a36Sopenharmony_ci sizeof(struct f2fs_inode_info), 0, 493362306a36Sopenharmony_ci SLAB_RECLAIM_ACCOUNT|SLAB_ACCOUNT, NULL); 493462306a36Sopenharmony_ci return f2fs_inode_cachep ? 0 : -ENOMEM; 493562306a36Sopenharmony_ci} 493662306a36Sopenharmony_ci 493762306a36Sopenharmony_cistatic void destroy_inodecache(void) 493862306a36Sopenharmony_ci{ 493962306a36Sopenharmony_ci /* 494062306a36Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 494162306a36Sopenharmony_ci * destroy cache. 494262306a36Sopenharmony_ci */ 494362306a36Sopenharmony_ci rcu_barrier(); 494462306a36Sopenharmony_ci kmem_cache_destroy(f2fs_inode_cachep); 494562306a36Sopenharmony_ci} 494662306a36Sopenharmony_ci 494762306a36Sopenharmony_cistatic int __init init_f2fs_fs(void) 494862306a36Sopenharmony_ci{ 494962306a36Sopenharmony_ci int err; 495062306a36Sopenharmony_ci 495162306a36Sopenharmony_ci if (PAGE_SIZE != F2FS_BLKSIZE) { 495262306a36Sopenharmony_ci printk("F2FS not supported on PAGE_SIZE(%lu) != %d\n", 495362306a36Sopenharmony_ci PAGE_SIZE, F2FS_BLKSIZE); 495462306a36Sopenharmony_ci return -EINVAL; 495562306a36Sopenharmony_ci } 495662306a36Sopenharmony_ci 495762306a36Sopenharmony_ci err = init_inodecache(); 495862306a36Sopenharmony_ci if (err) 495962306a36Sopenharmony_ci goto fail; 496062306a36Sopenharmony_ci err = f2fs_create_node_manager_caches(); 496162306a36Sopenharmony_ci if (err) 496262306a36Sopenharmony_ci goto free_inodecache; 496362306a36Sopenharmony_ci err = f2fs_create_segment_manager_caches(); 496462306a36Sopenharmony_ci if (err) 496562306a36Sopenharmony_ci goto free_node_manager_caches; 496662306a36Sopenharmony_ci err = f2fs_create_checkpoint_caches(); 496762306a36Sopenharmony_ci if (err) 496862306a36Sopenharmony_ci goto free_segment_manager_caches; 496962306a36Sopenharmony_ci err = f2fs_create_recovery_cache(); 497062306a36Sopenharmony_ci if (err) 497162306a36Sopenharmony_ci goto free_checkpoint_caches; 497262306a36Sopenharmony_ci err = f2fs_create_extent_cache(); 497362306a36Sopenharmony_ci if (err) 497462306a36Sopenharmony_ci goto free_recovery_cache; 497562306a36Sopenharmony_ci err = f2fs_create_garbage_collection_cache(); 497662306a36Sopenharmony_ci if (err) 497762306a36Sopenharmony_ci goto free_extent_cache; 497862306a36Sopenharmony_ci err = f2fs_init_sysfs(); 497962306a36Sopenharmony_ci if (err) 498062306a36Sopenharmony_ci goto free_garbage_collection_cache; 498162306a36Sopenharmony_ci err = register_shrinker(&f2fs_shrinker_info, "f2fs-shrinker"); 498262306a36Sopenharmony_ci if (err) 498362306a36Sopenharmony_ci goto free_sysfs; 498462306a36Sopenharmony_ci err = register_filesystem(&f2fs_fs_type); 498562306a36Sopenharmony_ci if (err) 498662306a36Sopenharmony_ci goto free_shrinker; 498762306a36Sopenharmony_ci f2fs_create_root_stats(); 498862306a36Sopenharmony_ci err = f2fs_init_post_read_processing(); 498962306a36Sopenharmony_ci if (err) 499062306a36Sopenharmony_ci goto free_root_stats; 499162306a36Sopenharmony_ci err = f2fs_init_iostat_processing(); 499262306a36Sopenharmony_ci if (err) 499362306a36Sopenharmony_ci goto free_post_read; 499462306a36Sopenharmony_ci err = f2fs_init_bio_entry_cache(); 499562306a36Sopenharmony_ci if (err) 499662306a36Sopenharmony_ci goto free_iostat; 499762306a36Sopenharmony_ci err = f2fs_init_bioset(); 499862306a36Sopenharmony_ci if (err) 499962306a36Sopenharmony_ci goto free_bio_entry_cache; 500062306a36Sopenharmony_ci err = f2fs_init_compress_mempool(); 500162306a36Sopenharmony_ci if (err) 500262306a36Sopenharmony_ci goto free_bioset; 500362306a36Sopenharmony_ci err = f2fs_init_compress_cache(); 500462306a36Sopenharmony_ci if (err) 500562306a36Sopenharmony_ci goto free_compress_mempool; 500662306a36Sopenharmony_ci err = f2fs_create_casefold_cache(); 500762306a36Sopenharmony_ci if (err) 500862306a36Sopenharmony_ci goto free_compress_cache; 500962306a36Sopenharmony_ci return 0; 501062306a36Sopenharmony_cifree_compress_cache: 501162306a36Sopenharmony_ci f2fs_destroy_compress_cache(); 501262306a36Sopenharmony_cifree_compress_mempool: 501362306a36Sopenharmony_ci f2fs_destroy_compress_mempool(); 501462306a36Sopenharmony_cifree_bioset: 501562306a36Sopenharmony_ci f2fs_destroy_bioset(); 501662306a36Sopenharmony_cifree_bio_entry_cache: 501762306a36Sopenharmony_ci f2fs_destroy_bio_entry_cache(); 501862306a36Sopenharmony_cifree_iostat: 501962306a36Sopenharmony_ci f2fs_destroy_iostat_processing(); 502062306a36Sopenharmony_cifree_post_read: 502162306a36Sopenharmony_ci f2fs_destroy_post_read_processing(); 502262306a36Sopenharmony_cifree_root_stats: 502362306a36Sopenharmony_ci f2fs_destroy_root_stats(); 502462306a36Sopenharmony_ci unregister_filesystem(&f2fs_fs_type); 502562306a36Sopenharmony_cifree_shrinker: 502662306a36Sopenharmony_ci unregister_shrinker(&f2fs_shrinker_info); 502762306a36Sopenharmony_cifree_sysfs: 502862306a36Sopenharmony_ci f2fs_exit_sysfs(); 502962306a36Sopenharmony_cifree_garbage_collection_cache: 503062306a36Sopenharmony_ci f2fs_destroy_garbage_collection_cache(); 503162306a36Sopenharmony_cifree_extent_cache: 503262306a36Sopenharmony_ci f2fs_destroy_extent_cache(); 503362306a36Sopenharmony_cifree_recovery_cache: 503462306a36Sopenharmony_ci f2fs_destroy_recovery_cache(); 503562306a36Sopenharmony_cifree_checkpoint_caches: 503662306a36Sopenharmony_ci f2fs_destroy_checkpoint_caches(); 503762306a36Sopenharmony_cifree_segment_manager_caches: 503862306a36Sopenharmony_ci f2fs_destroy_segment_manager_caches(); 503962306a36Sopenharmony_cifree_node_manager_caches: 504062306a36Sopenharmony_ci f2fs_destroy_node_manager_caches(); 504162306a36Sopenharmony_cifree_inodecache: 504262306a36Sopenharmony_ci destroy_inodecache(); 504362306a36Sopenharmony_cifail: 504462306a36Sopenharmony_ci return err; 504562306a36Sopenharmony_ci} 504662306a36Sopenharmony_ci 504762306a36Sopenharmony_cistatic void __exit exit_f2fs_fs(void) 504862306a36Sopenharmony_ci{ 504962306a36Sopenharmony_ci f2fs_destroy_casefold_cache(); 505062306a36Sopenharmony_ci f2fs_destroy_compress_cache(); 505162306a36Sopenharmony_ci f2fs_destroy_compress_mempool(); 505262306a36Sopenharmony_ci f2fs_destroy_bioset(); 505362306a36Sopenharmony_ci f2fs_destroy_bio_entry_cache(); 505462306a36Sopenharmony_ci f2fs_destroy_iostat_processing(); 505562306a36Sopenharmony_ci f2fs_destroy_post_read_processing(); 505662306a36Sopenharmony_ci f2fs_destroy_root_stats(); 505762306a36Sopenharmony_ci unregister_filesystem(&f2fs_fs_type); 505862306a36Sopenharmony_ci unregister_shrinker(&f2fs_shrinker_info); 505962306a36Sopenharmony_ci f2fs_exit_sysfs(); 506062306a36Sopenharmony_ci f2fs_destroy_garbage_collection_cache(); 506162306a36Sopenharmony_ci f2fs_destroy_extent_cache(); 506262306a36Sopenharmony_ci f2fs_destroy_recovery_cache(); 506362306a36Sopenharmony_ci f2fs_destroy_checkpoint_caches(); 506462306a36Sopenharmony_ci f2fs_destroy_segment_manager_caches(); 506562306a36Sopenharmony_ci f2fs_destroy_node_manager_caches(); 506662306a36Sopenharmony_ci destroy_inodecache(); 506762306a36Sopenharmony_ci} 506862306a36Sopenharmony_ci 506962306a36Sopenharmony_cimodule_init(init_f2fs_fs) 507062306a36Sopenharmony_cimodule_exit(exit_f2fs_fs) 507162306a36Sopenharmony_ci 507262306a36Sopenharmony_ciMODULE_AUTHOR("Samsung Electronics's Praesto Team"); 507362306a36Sopenharmony_ciMODULE_DESCRIPTION("Flash Friendly File System"); 507462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 507562306a36Sopenharmony_ciMODULE_SOFTDEP("pre: crc32"); 507662306a36Sopenharmony_ci 5077