17c1a000dSChao Yu // SPDX-License-Identifier: GPL-2.0
20a8165d7SJaegeuk Kim /*
3aff063e2SJaegeuk Kim * fs/f2fs/super.c
4aff063e2SJaegeuk Kim *
5aff063e2SJaegeuk Kim * Copyright (c) 2012 Samsung Electronics Co., Ltd.
6aff063e2SJaegeuk Kim * http://www.samsung.com/
7aff063e2SJaegeuk Kim */
8aff063e2SJaegeuk Kim #include <linux/module.h>
9aff063e2SJaegeuk Kim #include <linux/init.h>
10aff063e2SJaegeuk Kim #include <linux/fs.h>
11c5bca38dSEric Biggers #include <linux/fs_context.h>
124034247aSNeilBrown #include <linux/sched/mm.h>
13aff063e2SJaegeuk Kim #include <linux/statfs.h>
14aff063e2SJaegeuk Kim #include <linux/buffer_head.h>
15aff063e2SJaegeuk Kim #include <linux/kthread.h>
16aff063e2SJaegeuk Kim #include <linux/parser.h>
17aff063e2SJaegeuk Kim #include <linux/mount.h>
18aff063e2SJaegeuk Kim #include <linux/seq_file.h>
195e176d54SJaegeuk Kim #include <linux/proc_fs.h>
20aff063e2SJaegeuk Kim #include <linux/random.h>
21aff063e2SJaegeuk Kim #include <linux/exportfs.h>
22d3ee456dSNamjae Jeon #include <linux/blkdev.h>
230abd675eSChao Yu #include <linux/quotaops.h>
24aff063e2SJaegeuk Kim #include <linux/f2fs_fs.h>
25b59d0baeSNamjae Jeon #include <linux/sysfs.h>
264b2414d0SChao Yu #include <linux/quota.h>
275aba5430SDaniel Rosenberg #include <linux/unicode.h>
28c6a564ffSChristoph Hellwig #include <linux/part_stat.h>
293fde13f8SChao Yu #include <linux/zstd.h>
303fde13f8SChao Yu #include <linux/lz4.h>
31aff063e2SJaegeuk Kim
32aff063e2SJaegeuk Kim #include "f2fs.h"
33aff063e2SJaegeuk Kim #include "node.h"
345ec4e49fSJaegeuk Kim #include "segment.h"
35aff063e2SJaegeuk Kim #include "xattr.h"
36b59d0baeSNamjae Jeon #include "gc.h"
3752118743SDaeho Jeong #include "iostat.h"
38aff063e2SJaegeuk Kim
39a2a4a7e4SNamjae Jeon #define CREATE_TRACE_POINTS
40a2a4a7e4SNamjae Jeon #include <trace/events/f2fs.h>
41a2a4a7e4SNamjae Jeon
42aff063e2SJaegeuk Kim static struct kmem_cache *f2fs_inode_cachep;
43aff063e2SJaegeuk Kim
4473faec4dSJaegeuk Kim #ifdef CONFIG_F2FS_FAULT_INJECTION
452c63feadSJaegeuk Kim
4619880e6eSAlexey Dobriyan const char *f2fs_fault_name[FAULT_MAX] = {
472c63feadSJaegeuk Kim [FAULT_KMALLOC] = "kmalloc",
48628b3d14SChao Yu [FAULT_KVMALLOC] = "kvmalloc",
49c41f3cc3SJaegeuk Kim [FAULT_PAGE_ALLOC] = "page alloc",
5001eccef7SChao Yu [FAULT_PAGE_GET] = "page get",
51cb78942bSJaegeuk Kim [FAULT_ALLOC_NID] = "alloc nid",
52cb78942bSJaegeuk Kim [FAULT_ORPHAN] = "orphan",
53cb78942bSJaegeuk Kim [FAULT_BLOCK] = "no more block",
54cb78942bSJaegeuk Kim [FAULT_DIR_DEPTH] = "too big dir depth",
5553aa6bbfSJaegeuk Kim [FAULT_EVICT_INODE] = "evict_inode fail",
5614b44d23SJaegeuk Kim [FAULT_TRUNCATE] = "truncate fail",
576f5c2ed0SChao Yu [FAULT_READ_IO] = "read IO error",
580f348028SChao Yu [FAULT_CHECKPOINT] = "checkpoint error",
59b83dcfe6SChao Yu [FAULT_DISCARD] = "discard error",
606f5c2ed0SChao Yu [FAULT_WRITE_IO] = "write IO error",
6132410577SChao Yu [FAULT_SLAB_ALLOC] = "slab alloc",
6210a26878SChao Yu [FAULT_DQUOT_INIT] = "dquot initialize",
633e020389SChao Yu [FAULT_LOCK_OP] = "lock_op",
6418792e64SChao Yu [FAULT_BLKADDR] = "invalid blkaddr",
652c63feadSJaegeuk Kim };
6608796897SSheng Yong
f2fs_build_fault_attr(struct f2fs_sb_info * sbi,unsigned long rate,unsigned long type)6744958ca9SChao Yu int f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned long rate,
6844958ca9SChao Yu unsigned long type)
6908796897SSheng Yong {
7063189b78SChao Yu struct f2fs_fault_info *ffi = &F2FS_OPTION(sbi).fault_info;
711ecc0c5cSChao Yu
7208796897SSheng Yong if (rate) {
7344958ca9SChao Yu if (rate > INT_MAX)
7444958ca9SChao Yu return -EINVAL;
751ecc0c5cSChao Yu atomic_set(&ffi->inject_ops, 0);
7644958ca9SChao Yu ffi->inject_rate = (int)rate;
7708796897SSheng Yong }
78d494500aSChao Yu
7944958ca9SChao Yu if (type) {
8044958ca9SChao Yu if (type >= BIT(FAULT_MAX))
8144958ca9SChao Yu return -EINVAL;
8244958ca9SChao Yu ffi->inject_type = (unsigned int)type;
8344958ca9SChao Yu }
84d494500aSChao Yu
85d494500aSChao Yu if (!rate && !type)
86d494500aSChao Yu memset(ffi, 0, sizeof(struct f2fs_fault_info));
8744958ca9SChao Yu else
8844958ca9SChao Yu f2fs_info(sbi,
8944958ca9SChao Yu "build fault injection attr: rate: %lu, type: 0x%lx",
9044958ca9SChao Yu rate, type);
9144958ca9SChao Yu return 0;
9208796897SSheng Yong }
9373faec4dSJaegeuk Kim #endif
9473faec4dSJaegeuk Kim
952658e50dSJaegeuk Kim /* f2fs-wide shrinker description */
962658e50dSJaegeuk Kim static struct shrinker f2fs_shrinker_info = {
972658e50dSJaegeuk Kim .scan_objects = f2fs_shrink_scan,
982658e50dSJaegeuk Kim .count_objects = f2fs_shrink_count,
992658e50dSJaegeuk Kim .seeks = DEFAULT_SEEKS,
1002658e50dSJaegeuk Kim };
1012658e50dSJaegeuk Kim
102aff063e2SJaegeuk Kim enum {
103696c018cSNamjae Jeon Opt_gc_background,
104aff063e2SJaegeuk Kim Opt_disable_roll_forward,
1052d834bf9SJaegeuk Kim Opt_norecovery,
106aff063e2SJaegeuk Kim Opt_discard,
10764058be9SChao Yu Opt_nodiscard,
108aff063e2SJaegeuk Kim Opt_noheap,
1097a20b8a6SJaegeuk Kim Opt_heap,
1104058c511SKelly Anderson Opt_user_xattr,
111aff063e2SJaegeuk Kim Opt_nouser_xattr,
1124058c511SKelly Anderson Opt_acl,
113aff063e2SJaegeuk Kim Opt_noacl,
114aff063e2SJaegeuk Kim Opt_active_logs,
115aff063e2SJaegeuk Kim Opt_disable_ext_identify,
116444c580fSJaegeuk Kim Opt_inline_xattr,
11723cf7212SChao Yu Opt_noinline_xattr,
1186afc662eSChao Yu Opt_inline_xattr_size,
1198274de77SHuajun Li Opt_inline_data,
1205efd3c6fSChao Yu Opt_inline_dentry,
12197c1794aSChao Yu Opt_noinline_dentry,
1226b4afdd7SJaegeuk Kim Opt_flush_merge,
12369e9e427SJaegeuk Kim Opt_noflush_merge,
1246047de54SYangtao Li Opt_barrier,
1250f7b2abdSJaegeuk Kim Opt_nobarrier,
126d5053a34SJaegeuk Kim Opt_fastboot,
12789672159SChao Yu Opt_extent_cache,
1287daaea25SJaegeuk Kim Opt_noextent_cache,
12975342797SWanpeng Li Opt_noinline_data,
130343f40f0SChao Yu Opt_data_flush,
1317e65be49SJaegeuk Kim Opt_reserve_root,
1327c2e5963SJaegeuk Kim Opt_resgid,
1337c2e5963SJaegeuk Kim Opt_resuid,
13436abef4eSJaegeuk Kim Opt_mode,
13573faec4dSJaegeuk Kim Opt_fault_injection,
136d494500aSChao Yu Opt_fault_type,
1376d94c74aSJaegeuk Kim Opt_lazytime,
1386d94c74aSJaegeuk Kim Opt_nolazytime,
1394b2414d0SChao Yu Opt_quota,
1404b2414d0SChao Yu Opt_noquota,
1410abd675eSChao Yu Opt_usrquota,
1420abd675eSChao Yu Opt_grpquota,
1435c57132eSChao Yu Opt_prjquota,
1444b2414d0SChao Yu Opt_usrjquota,
1454b2414d0SChao Yu Opt_grpjquota,
1464b2414d0SChao Yu Opt_prjjquota,
1474b2414d0SChao Yu Opt_offusrjquota,
1484b2414d0SChao Yu Opt_offgrpjquota,
1494b2414d0SChao Yu Opt_offprjjquota,
1504b2414d0SChao Yu Opt_jqfmt_vfsold,
1514b2414d0SChao Yu Opt_jqfmt_vfsv0,
1524b2414d0SChao Yu Opt_jqfmt_vfsv1,
15307939627SJaegeuk Kim Opt_alloc,
15493cf93f1SJunling Zheng Opt_fsync,
155ff62af20SSheng Yong Opt_test_dummy_encryption,
15627aacd28SSatya Tangirala Opt_inlinecrypt,
1574d3aed70SDaniel Rosenberg Opt_checkpoint_disable,
1584d3aed70SDaniel Rosenberg Opt_checkpoint_disable_cap,
1594d3aed70SDaniel Rosenberg Opt_checkpoint_disable_cap_perc,
1604d3aed70SDaniel Rosenberg Opt_checkpoint_enable,
161261eeb9cSDaeho Jeong Opt_checkpoint_merge,
162261eeb9cSDaeho Jeong Opt_nocheckpoint_merge,
1634c8ff709SChao Yu Opt_compress_algorithm,
1644c8ff709SChao Yu Opt_compress_log_size,
1654c8ff709SChao Yu Opt_compress_extension,
166151b1982SFengnan Chang Opt_nocompress_extension,
167b28f047bSChao Yu Opt_compress_chksum,
168602a16d5SDaeho Jeong Opt_compress_mode,
1696ce19affSChao Yu Opt_compress_cache,
170093749e2SChao Yu Opt_atgc,
1715911d2d1SChao Yu Opt_gc_merge,
1725911d2d1SChao Yu Opt_nogc_merge,
1734f993264SChao Yu Opt_discard_unit,
1747a8fc586SDaeho Jeong Opt_memory_mode,
17571644dffSJaegeuk Kim Opt_age_extent_cache,
176b62e71beSChao Yu Opt_errors,
177aff063e2SJaegeuk Kim Opt_err,
178aff063e2SJaegeuk Kim };
179aff063e2SJaegeuk Kim
180aff063e2SJaegeuk Kim static match_table_t f2fs_tokens = {
181696c018cSNamjae Jeon {Opt_gc_background, "background_gc=%s"},
182aff063e2SJaegeuk Kim {Opt_disable_roll_forward, "disable_roll_forward"},
1832d834bf9SJaegeuk Kim {Opt_norecovery, "norecovery"},
184aff063e2SJaegeuk Kim {Opt_discard, "discard"},
18564058be9SChao Yu {Opt_nodiscard, "nodiscard"},
186aff063e2SJaegeuk Kim {Opt_noheap, "no_heap"},
1877a20b8a6SJaegeuk Kim {Opt_heap, "heap"},
1884058c511SKelly Anderson {Opt_user_xattr, "user_xattr"},
189aff063e2SJaegeuk Kim {Opt_nouser_xattr, "nouser_xattr"},
1904058c511SKelly Anderson {Opt_acl, "acl"},
191aff063e2SJaegeuk Kim {Opt_noacl, "noacl"},
192aff063e2SJaegeuk Kim {Opt_active_logs, "active_logs=%u"},
193aff063e2SJaegeuk Kim {Opt_disable_ext_identify, "disable_ext_identify"},
194444c580fSJaegeuk Kim {Opt_inline_xattr, "inline_xattr"},
19523cf7212SChao Yu {Opt_noinline_xattr, "noinline_xattr"},
1966afc662eSChao Yu {Opt_inline_xattr_size, "inline_xattr_size=%u"},
1978274de77SHuajun Li {Opt_inline_data, "inline_data"},
1985efd3c6fSChao Yu {Opt_inline_dentry, "inline_dentry"},
19997c1794aSChao Yu {Opt_noinline_dentry, "noinline_dentry"},
2006b4afdd7SJaegeuk Kim {Opt_flush_merge, "flush_merge"},
20169e9e427SJaegeuk Kim {Opt_noflush_merge, "noflush_merge"},
2026047de54SYangtao Li {Opt_barrier, "barrier"},
2030f7b2abdSJaegeuk Kim {Opt_nobarrier, "nobarrier"},
204d5053a34SJaegeuk Kim {Opt_fastboot, "fastboot"},
20589672159SChao Yu {Opt_extent_cache, "extent_cache"},
2067daaea25SJaegeuk Kim {Opt_noextent_cache, "noextent_cache"},
20775342797SWanpeng Li {Opt_noinline_data, "noinline_data"},
208343f40f0SChao Yu {Opt_data_flush, "data_flush"},
2097e65be49SJaegeuk Kim {Opt_reserve_root, "reserve_root=%u"},
2107c2e5963SJaegeuk Kim {Opt_resgid, "resgid=%u"},
2117c2e5963SJaegeuk Kim {Opt_resuid, "resuid=%u"},
21236abef4eSJaegeuk Kim {Opt_mode, "mode=%s"},
21373faec4dSJaegeuk Kim {Opt_fault_injection, "fault_injection=%u"},
214d494500aSChao Yu {Opt_fault_type, "fault_type=%u"},
2156d94c74aSJaegeuk Kim {Opt_lazytime, "lazytime"},
2166d94c74aSJaegeuk Kim {Opt_nolazytime, "nolazytime"},
2174b2414d0SChao Yu {Opt_quota, "quota"},
2184b2414d0SChao Yu {Opt_noquota, "noquota"},
2190abd675eSChao Yu {Opt_usrquota, "usrquota"},
2200abd675eSChao Yu {Opt_grpquota, "grpquota"},
2215c57132eSChao Yu {Opt_prjquota, "prjquota"},
2224b2414d0SChao Yu {Opt_usrjquota, "usrjquota=%s"},
2234b2414d0SChao Yu {Opt_grpjquota, "grpjquota=%s"},
2244b2414d0SChao Yu {Opt_prjjquota, "prjjquota=%s"},
2254b2414d0SChao Yu {Opt_offusrjquota, "usrjquota="},
2264b2414d0SChao Yu {Opt_offgrpjquota, "grpjquota="},
2274b2414d0SChao Yu {Opt_offprjjquota, "prjjquota="},
2284b2414d0SChao Yu {Opt_jqfmt_vfsold, "jqfmt=vfsold"},
2294b2414d0SChao Yu {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
2304b2414d0SChao Yu {Opt_jqfmt_vfsv1, "jqfmt=vfsv1"},
23107939627SJaegeuk Kim {Opt_alloc, "alloc_mode=%s"},
23293cf93f1SJunling Zheng {Opt_fsync, "fsync_mode=%s"},
233ed318a6cSEric Biggers {Opt_test_dummy_encryption, "test_dummy_encryption=%s"},
234ff62af20SSheng Yong {Opt_test_dummy_encryption, "test_dummy_encryption"},
23527aacd28SSatya Tangirala {Opt_inlinecrypt, "inlinecrypt"},
2364d3aed70SDaniel Rosenberg {Opt_checkpoint_disable, "checkpoint=disable"},
2374d3aed70SDaniel Rosenberg {Opt_checkpoint_disable_cap, "checkpoint=disable:%u"},
2384d3aed70SDaniel Rosenberg {Opt_checkpoint_disable_cap_perc, "checkpoint=disable:%u%%"},
2394d3aed70SDaniel Rosenberg {Opt_checkpoint_enable, "checkpoint=enable"},
240261eeb9cSDaeho Jeong {Opt_checkpoint_merge, "checkpoint_merge"},
241261eeb9cSDaeho Jeong {Opt_nocheckpoint_merge, "nocheckpoint_merge"},
2424c8ff709SChao Yu {Opt_compress_algorithm, "compress_algorithm=%s"},
2434c8ff709SChao Yu {Opt_compress_log_size, "compress_log_size=%u"},
2444c8ff709SChao Yu {Opt_compress_extension, "compress_extension=%s"},
245151b1982SFengnan Chang {Opt_nocompress_extension, "nocompress_extension=%s"},
246b28f047bSChao Yu {Opt_compress_chksum, "compress_chksum"},
247602a16d5SDaeho Jeong {Opt_compress_mode, "compress_mode=%s"},
2486ce19affSChao Yu {Opt_compress_cache, "compress_cache"},
249093749e2SChao Yu {Opt_atgc, "atgc"},
2505911d2d1SChao Yu {Opt_gc_merge, "gc_merge"},
2515911d2d1SChao Yu {Opt_nogc_merge, "nogc_merge"},
2524f993264SChao Yu {Opt_discard_unit, "discard_unit=%s"},
2537a8fc586SDaeho Jeong {Opt_memory_mode, "memory=%s"},
25471644dffSJaegeuk Kim {Opt_age_extent_cache, "age_extent_cache"},
255b62e71beSChao Yu {Opt_errors, "errors=%s"},
256aff063e2SJaegeuk Kim {Opt_err, NULL},
257aff063e2SJaegeuk Kim };
258aff063e2SJaegeuk Kim
f2fs_printk(struct f2fs_sb_info * sbi,bool limit_rate,const char * fmt,...)25942d48304SChao Yu void f2fs_printk(struct f2fs_sb_info *sbi, bool limit_rate,
26042d48304SChao Yu const char *fmt, ...)
261a07ef784SNamjae Jeon {
262a07ef784SNamjae Jeon struct va_format vaf;
263a07ef784SNamjae Jeon va_list args;
264dcbb4c10SJoe Perches int level;
265a07ef784SNamjae Jeon
266a07ef784SNamjae Jeon va_start(args, fmt);
267dcbb4c10SJoe Perches
268dcbb4c10SJoe Perches level = printk_get_level(fmt);
269dcbb4c10SJoe Perches vaf.fmt = printk_skip_level(fmt);
270a07ef784SNamjae Jeon vaf.va = &args;
27142d48304SChao Yu if (limit_rate)
27242d48304SChao Yu printk_ratelimited("%c%cF2FS-fs (%s): %pV\n",
27342d48304SChao Yu KERN_SOH_ASCII, level, sbi->sb->s_id, &vaf);
27442d48304SChao Yu else
275dcbb4c10SJoe Perches printk("%c%cF2FS-fs (%s): %pV\n",
276dcbb4c10SJoe Perches KERN_SOH_ASCII, level, sbi->sb->s_id, &vaf);
277dcbb4c10SJoe Perches
278a07ef784SNamjae Jeon va_end(args);
279a07ef784SNamjae Jeon }
280a07ef784SNamjae Jeon
2815298d4bfSChristoph Hellwig #if IS_ENABLED(CONFIG_UNICODE)
2825aba5430SDaniel Rosenberg static const struct f2fs_sb_encodings {
2835aba5430SDaniel Rosenberg __u16 magic;
2845aba5430SDaniel Rosenberg char *name;
28549bd03ccSChristoph Hellwig unsigned int version;
2865aba5430SDaniel Rosenberg } f2fs_sb_encoding_map[] = {
28749bd03ccSChristoph Hellwig {F2FS_ENC_UTF8_12_1, "utf8", UNICODE_AGE(12, 1, 0)},
2885aba5430SDaniel Rosenberg };
2895aba5430SDaniel Rosenberg
29086e80575SChristoph Hellwig static const struct f2fs_sb_encodings *
f2fs_sb_read_encoding(const struct f2fs_super_block * sb)29186e80575SChristoph Hellwig f2fs_sb_read_encoding(const struct f2fs_super_block *sb)
2925aba5430SDaniel Rosenberg {
2935aba5430SDaniel Rosenberg __u16 magic = le16_to_cpu(sb->s_encoding);
2945aba5430SDaniel Rosenberg int i;
2955aba5430SDaniel Rosenberg
2965aba5430SDaniel Rosenberg for (i = 0; i < ARRAY_SIZE(f2fs_sb_encoding_map); i++)
2975aba5430SDaniel Rosenberg if (magic == f2fs_sb_encoding_map[i].magic)
29886e80575SChristoph Hellwig return &f2fs_sb_encoding_map[i];
2995aba5430SDaniel Rosenberg
30086e80575SChristoph Hellwig return NULL;
3015aba5430SDaniel Rosenberg }
3024d9a2bb1SChao Yu
3034d9a2bb1SChao Yu struct kmem_cache *f2fs_cf_name_slab;
f2fs_create_casefold_cache(void)3044d9a2bb1SChao Yu static int __init f2fs_create_casefold_cache(void)
3054d9a2bb1SChao Yu {
3064d9a2bb1SChao Yu f2fs_cf_name_slab = f2fs_kmem_cache_create("f2fs_casefolded_name",
3074d9a2bb1SChao Yu F2FS_NAME_LEN);
308870af777SYangtao Li return f2fs_cf_name_slab ? 0 : -ENOMEM;
3094d9a2bb1SChao Yu }
3104d9a2bb1SChao Yu
f2fs_destroy_casefold_cache(void)3114d9a2bb1SChao Yu static void f2fs_destroy_casefold_cache(void)
3124d9a2bb1SChao Yu {
3134d9a2bb1SChao Yu kmem_cache_destroy(f2fs_cf_name_slab);
3144d9a2bb1SChao Yu }
3154d9a2bb1SChao Yu #else
f2fs_create_casefold_cache(void)3164d9a2bb1SChao Yu static int __init f2fs_create_casefold_cache(void) { return 0; }
f2fs_destroy_casefold_cache(void)3174d9a2bb1SChao Yu static void f2fs_destroy_casefold_cache(void) { }
3185aba5430SDaniel Rosenberg #endif
3195aba5430SDaniel Rosenberg
limit_reserve_root(struct f2fs_sb_info * sbi)3207e65be49SJaegeuk Kim static inline void limit_reserve_root(struct f2fs_sb_info *sbi)
3217e65be49SJaegeuk Kim {
322da35fe96SJaegeuk Kim block_t limit = min((sbi->user_block_count >> 3),
3239a9aecaaSDaniel Rosenberg sbi->user_block_count - sbi->reserved_blocks);
3247e65be49SJaegeuk Kim
325da35fe96SJaegeuk Kim /* limit is 12.5% */
32663189b78SChao Yu if (test_opt(sbi, RESERVE_ROOT) &&
32763189b78SChao Yu F2FS_OPTION(sbi).root_reserved_blocks > limit) {
32863189b78SChao Yu F2FS_OPTION(sbi).root_reserved_blocks = limit;
329dcbb4c10SJoe Perches f2fs_info(sbi, "Reduce reserved blocks for root = %u",
33063189b78SChao Yu F2FS_OPTION(sbi).root_reserved_blocks);
3317e65be49SJaegeuk Kim }
3327c2e5963SJaegeuk Kim if (!test_opt(sbi, RESERVE_ROOT) &&
33363189b78SChao Yu (!uid_eq(F2FS_OPTION(sbi).s_resuid,
3347c2e5963SJaegeuk Kim make_kuid(&init_user_ns, F2FS_DEF_RESUID)) ||
33563189b78SChao Yu !gid_eq(F2FS_OPTION(sbi).s_resgid,
3367c2e5963SJaegeuk Kim make_kgid(&init_user_ns, F2FS_DEF_RESGID))))
337dcbb4c10SJoe Perches f2fs_info(sbi, "Ignore s_resuid=%u, s_resgid=%u w/o reserve_root",
33863189b78SChao Yu from_kuid_munged(&init_user_ns,
33963189b78SChao Yu F2FS_OPTION(sbi).s_resuid),
34063189b78SChao Yu from_kgid_munged(&init_user_ns,
34163189b78SChao Yu F2FS_OPTION(sbi).s_resgid));
3427e65be49SJaegeuk Kim }
3437e65be49SJaegeuk Kim
adjust_unusable_cap_perc(struct f2fs_sb_info * sbi)3441ae18f71SJaegeuk Kim static inline void adjust_unusable_cap_perc(struct f2fs_sb_info *sbi)
3451ae18f71SJaegeuk Kim {
3461ae18f71SJaegeuk Kim if (!F2FS_OPTION(sbi).unusable_cap_perc)
3471ae18f71SJaegeuk Kim return;
3481ae18f71SJaegeuk Kim
3491ae18f71SJaegeuk Kim if (F2FS_OPTION(sbi).unusable_cap_perc == 100)
3501ae18f71SJaegeuk Kim F2FS_OPTION(sbi).unusable_cap = sbi->user_block_count;
3511ae18f71SJaegeuk Kim else
3521ae18f71SJaegeuk Kim F2FS_OPTION(sbi).unusable_cap = (sbi->user_block_count / 100) *
3531ae18f71SJaegeuk Kim F2FS_OPTION(sbi).unusable_cap_perc;
3541ae18f71SJaegeuk Kim
3551ae18f71SJaegeuk Kim f2fs_info(sbi, "Adjust unusable cap for checkpoint=disable = %u / %u%%",
3561ae18f71SJaegeuk Kim F2FS_OPTION(sbi).unusable_cap,
3571ae18f71SJaegeuk Kim F2FS_OPTION(sbi).unusable_cap_perc);
3581ae18f71SJaegeuk Kim }
3591ae18f71SJaegeuk Kim
init_once(void * foo)360aff063e2SJaegeuk Kim static void init_once(void *foo)
361aff063e2SJaegeuk Kim {
362aff063e2SJaegeuk Kim struct f2fs_inode_info *fi = (struct f2fs_inode_info *) foo;
363aff063e2SJaegeuk Kim
364aff063e2SJaegeuk Kim inode_init_once(&fi->vfs_inode);
365aff063e2SJaegeuk Kim }
366aff063e2SJaegeuk Kim
3674b2414d0SChao Yu #ifdef CONFIG_QUOTA
3684b2414d0SChao Yu static const char * const quotatypes[] = INITQFNAMES;
3694b2414d0SChao Yu #define QTYPE2NAME(t) (quotatypes[t])
f2fs_set_qf_name(struct super_block * sb,int qtype,substring_t * args)3704b2414d0SChao Yu static int f2fs_set_qf_name(struct super_block *sb, int qtype,
3714b2414d0SChao Yu substring_t *args)
3724b2414d0SChao Yu {
3734b2414d0SChao Yu struct f2fs_sb_info *sbi = F2FS_SB(sb);
3744b2414d0SChao Yu char *qname;
3754b2414d0SChao Yu int ret = -EINVAL;
3764b2414d0SChao Yu
37763189b78SChao Yu if (sb_any_quota_loaded(sb) && !F2FS_OPTION(sbi).s_qf_names[qtype]) {
378dcbb4c10SJoe Perches f2fs_err(sbi, "Cannot change journaled quota options when quota turned on");
3794b2414d0SChao Yu return -EINVAL;
3804b2414d0SChao Yu }
3817beb01f7SChao Yu if (f2fs_sb_has_quota_ino(sbi)) {
382dcbb4c10SJoe Perches f2fs_info(sbi, "QUOTA feature is enabled, so ignore qf_name");
383ea676733SJaegeuk Kim return 0;
384ea676733SJaegeuk Kim }
385ea676733SJaegeuk Kim
3864b2414d0SChao Yu qname = match_strdup(args);
3874b2414d0SChao Yu if (!qname) {
388dcbb4c10SJoe Perches f2fs_err(sbi, "Not enough memory for storing quotafile name");
389f365c6ccSChengguang Xu return -ENOMEM;
3904b2414d0SChao Yu }
39163189b78SChao Yu if (F2FS_OPTION(sbi).s_qf_names[qtype]) {
39263189b78SChao Yu if (strcmp(F2FS_OPTION(sbi).s_qf_names[qtype], qname) == 0)
3934b2414d0SChao Yu ret = 0;
3944b2414d0SChao Yu else
395dcbb4c10SJoe Perches f2fs_err(sbi, "%s quota file already specified",
3964b2414d0SChao Yu QTYPE2NAME(qtype));
3974b2414d0SChao Yu goto errout;
3984b2414d0SChao Yu }
3994b2414d0SChao Yu if (strchr(qname, '/')) {
400dcbb4c10SJoe Perches f2fs_err(sbi, "quotafile must be on filesystem root");
4014b2414d0SChao Yu goto errout;
4024b2414d0SChao Yu }
40363189b78SChao Yu F2FS_OPTION(sbi).s_qf_names[qtype] = qname;
4044b2414d0SChao Yu set_opt(sbi, QUOTA);
4054b2414d0SChao Yu return 0;
4064b2414d0SChao Yu errout:
407ba87a45cSWang Xiaojun kfree(qname);
4084b2414d0SChao Yu return ret;
4094b2414d0SChao Yu }
4104b2414d0SChao Yu
f2fs_clear_qf_name(struct super_block * sb,int qtype)4114b2414d0SChao Yu static int f2fs_clear_qf_name(struct super_block *sb, int qtype)
4124b2414d0SChao Yu {
4134b2414d0SChao Yu struct f2fs_sb_info *sbi = F2FS_SB(sb);
4144b2414d0SChao Yu
41563189b78SChao Yu if (sb_any_quota_loaded(sb) && F2FS_OPTION(sbi).s_qf_names[qtype]) {
416dcbb4c10SJoe Perches f2fs_err(sbi, "Cannot change journaled quota options when quota turned on");
4174b2414d0SChao Yu return -EINVAL;
4184b2414d0SChao Yu }
419ba87a45cSWang Xiaojun kfree(F2FS_OPTION(sbi).s_qf_names[qtype]);
42063189b78SChao Yu F2FS_OPTION(sbi).s_qf_names[qtype] = NULL;
4214b2414d0SChao Yu return 0;
4224b2414d0SChao Yu }
4234b2414d0SChao Yu
f2fs_check_quota_options(struct f2fs_sb_info * sbi)4244b2414d0SChao Yu static int f2fs_check_quota_options(struct f2fs_sb_info *sbi)
4254b2414d0SChao Yu {
4264b2414d0SChao Yu /*
4274b2414d0SChao Yu * We do the test below only for project quotas. 'usrquota' and
4284b2414d0SChao Yu * 'grpquota' mount options are allowed even without quota feature
4294b2414d0SChao Yu * to support legacy quotas in quota files.
4304b2414d0SChao Yu */
4317beb01f7SChao Yu if (test_opt(sbi, PRJQUOTA) && !f2fs_sb_has_project_quota(sbi)) {
432dcbb4c10SJoe Perches f2fs_err(sbi, "Project quota feature not enabled. Cannot enable project quota enforcement.");
4334b2414d0SChao Yu return -1;
4344b2414d0SChao Yu }
43563189b78SChao Yu if (F2FS_OPTION(sbi).s_qf_names[USRQUOTA] ||
43663189b78SChao Yu F2FS_OPTION(sbi).s_qf_names[GRPQUOTA] ||
43763189b78SChao Yu F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]) {
43863189b78SChao Yu if (test_opt(sbi, USRQUOTA) &&
43963189b78SChao Yu F2FS_OPTION(sbi).s_qf_names[USRQUOTA])
4404b2414d0SChao Yu clear_opt(sbi, USRQUOTA);
4414b2414d0SChao Yu
44263189b78SChao Yu if (test_opt(sbi, GRPQUOTA) &&
44363189b78SChao Yu F2FS_OPTION(sbi).s_qf_names[GRPQUOTA])
4444b2414d0SChao Yu clear_opt(sbi, GRPQUOTA);
4454b2414d0SChao Yu
44663189b78SChao Yu if (test_opt(sbi, PRJQUOTA) &&
44763189b78SChao Yu F2FS_OPTION(sbi).s_qf_names[PRJQUOTA])
4484b2414d0SChao Yu clear_opt(sbi, PRJQUOTA);
4494b2414d0SChao Yu
4504b2414d0SChao Yu if (test_opt(sbi, GRPQUOTA) || test_opt(sbi, USRQUOTA) ||
4514b2414d0SChao Yu test_opt(sbi, PRJQUOTA)) {
452dcbb4c10SJoe Perches f2fs_err(sbi, "old and new quota format mixing");
4534b2414d0SChao Yu return -1;
4544b2414d0SChao Yu }
4554b2414d0SChao Yu
45663189b78SChao Yu if (!F2FS_OPTION(sbi).s_jquota_fmt) {
457dcbb4c10SJoe Perches f2fs_err(sbi, "journaled quota format not specified");
4584b2414d0SChao Yu return -1;
4594b2414d0SChao Yu }
4604b2414d0SChao Yu }
461ea676733SJaegeuk Kim
4627beb01f7SChao Yu if (f2fs_sb_has_quota_ino(sbi) && F2FS_OPTION(sbi).s_jquota_fmt) {
463dcbb4c10SJoe Perches f2fs_info(sbi, "QUOTA feature is enabled, so ignore jquota_fmt");
46463189b78SChao Yu F2FS_OPTION(sbi).s_jquota_fmt = 0;
465ea676733SJaegeuk Kim }
4664b2414d0SChao Yu return 0;
4674b2414d0SChao Yu }
4684b2414d0SChao Yu #endif
4694b2414d0SChao Yu
f2fs_set_test_dummy_encryption(struct super_block * sb,const char * opt,const substring_t * arg,bool is_remount)470ed318a6cSEric Biggers static int f2fs_set_test_dummy_encryption(struct super_block *sb,
471ed318a6cSEric Biggers const char *opt,
472ed318a6cSEric Biggers const substring_t *arg,
473ed318a6cSEric Biggers bool is_remount)
474ed318a6cSEric Biggers {
475ed318a6cSEric Biggers struct f2fs_sb_info *sbi = F2FS_SB(sb);
476c5bca38dSEric Biggers struct fs_parameter param = {
477c5bca38dSEric Biggers .type = fs_value_is_string,
478c5bca38dSEric Biggers .string = arg->from ? arg->from : "",
479c5bca38dSEric Biggers };
480c5bca38dSEric Biggers struct fscrypt_dummy_policy *policy =
481c5bca38dSEric Biggers &F2FS_OPTION(sbi).dummy_enc_policy;
482ed318a6cSEric Biggers int err;
483ed318a6cSEric Biggers
484c5bca38dSEric Biggers if (!IS_ENABLED(CONFIG_FS_ENCRYPTION)) {
485c5bca38dSEric Biggers f2fs_warn(sbi, "test_dummy_encryption option not supported");
486c5bca38dSEric Biggers return -EINVAL;
487c5bca38dSEric Biggers }
488c5bca38dSEric Biggers
489ed318a6cSEric Biggers if (!f2fs_sb_has_encrypt(sbi)) {
490ed318a6cSEric Biggers f2fs_err(sbi, "Encrypt feature is off");
491ed318a6cSEric Biggers return -EINVAL;
492ed318a6cSEric Biggers }
493ed318a6cSEric Biggers
494ed318a6cSEric Biggers /*
495ed318a6cSEric Biggers * This mount option is just for testing, and it's not worthwhile to
496ed318a6cSEric Biggers * implement the extra complexity (e.g. RCU protection) that would be
497ed318a6cSEric Biggers * needed to allow it to be set or changed during remount. We do allow
498ed318a6cSEric Biggers * it to be specified during remount, but only if there is no change.
499ed318a6cSEric Biggers */
500c5bca38dSEric Biggers if (is_remount && !fscrypt_is_dummy_policy_set(policy)) {
501ed318a6cSEric Biggers f2fs_warn(sbi, "Can't set test_dummy_encryption on remount");
502ed318a6cSEric Biggers return -EINVAL;
503ed318a6cSEric Biggers }
504c5bca38dSEric Biggers
505c5bca38dSEric Biggers err = fscrypt_parse_test_dummy_encryption(¶m, policy);
506ed318a6cSEric Biggers if (err) {
507ed318a6cSEric Biggers if (err == -EEXIST)
508ed318a6cSEric Biggers f2fs_warn(sbi,
509ed318a6cSEric Biggers "Can't change test_dummy_encryption on remount");
510ed318a6cSEric Biggers else if (err == -EINVAL)
511ed318a6cSEric Biggers f2fs_warn(sbi, "Value of option \"%s\" is unrecognized",
512ed318a6cSEric Biggers opt);
513ed318a6cSEric Biggers else
514ed318a6cSEric Biggers f2fs_warn(sbi, "Error processing option \"%s\" [%d]",
515ed318a6cSEric Biggers opt, err);
516ed318a6cSEric Biggers return -EINVAL;
517ed318a6cSEric Biggers }
518ed318a6cSEric Biggers f2fs_warn(sbi, "Test dummy encryption mode enabled");
519ed318a6cSEric Biggers return 0;
520ed318a6cSEric Biggers }
521ed318a6cSEric Biggers
5223fde13f8SChao Yu #ifdef CONFIG_F2FS_FS_COMPRESSION
is_compress_extension_exist(struct f2fs_sb_info * sbi,const char * new_ext,bool is_ext)523afab82ecSChao Yu static bool is_compress_extension_exist(struct f2fs_sb_info *sbi,
524afab82ecSChao Yu const char *new_ext, bool is_ext)
525afab82ecSChao Yu {
526afab82ecSChao Yu unsigned char (*ext)[F2FS_EXTENSION_LEN];
527afab82ecSChao Yu int ext_cnt;
528afab82ecSChao Yu int i;
529afab82ecSChao Yu
530afab82ecSChao Yu if (is_ext) {
531afab82ecSChao Yu ext = F2FS_OPTION(sbi).extensions;
532afab82ecSChao Yu ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt;
533afab82ecSChao Yu } else {
534afab82ecSChao Yu ext = F2FS_OPTION(sbi).noextensions;
535afab82ecSChao Yu ext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt;
536afab82ecSChao Yu }
537afab82ecSChao Yu
538afab82ecSChao Yu for (i = 0; i < ext_cnt; i++) {
539afab82ecSChao Yu if (!strcasecmp(new_ext, ext[i]))
540afab82ecSChao Yu return true;
541afab82ecSChao Yu }
542afab82ecSChao Yu
543afab82ecSChao Yu return false;
544afab82ecSChao Yu }
545afab82ecSChao Yu
546151b1982SFengnan Chang /*
547151b1982SFengnan Chang * 1. The same extension name cannot not appear in both compress and non-compress extension
548151b1982SFengnan Chang * at the same time.
549151b1982SFengnan Chang * 2. If the compress extension specifies all files, the types specified by the non-compress
550151b1982SFengnan Chang * extension will be treated as special cases and will not be compressed.
551151b1982SFengnan Chang * 3. Don't allow the non-compress extension specifies all files.
552151b1982SFengnan Chang */
f2fs_test_compress_extension(struct f2fs_sb_info * sbi)553151b1982SFengnan Chang static int f2fs_test_compress_extension(struct f2fs_sb_info *sbi)
554151b1982SFengnan Chang {
555151b1982SFengnan Chang unsigned char (*ext)[F2FS_EXTENSION_LEN];
556151b1982SFengnan Chang unsigned char (*noext)[F2FS_EXTENSION_LEN];
557151b1982SFengnan Chang int ext_cnt, noext_cnt, index = 0, no_index = 0;
558151b1982SFengnan Chang
559151b1982SFengnan Chang ext = F2FS_OPTION(sbi).extensions;
560151b1982SFengnan Chang ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt;
561151b1982SFengnan Chang noext = F2FS_OPTION(sbi).noextensions;
562151b1982SFengnan Chang noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt;
563151b1982SFengnan Chang
564151b1982SFengnan Chang if (!noext_cnt)
565151b1982SFengnan Chang return 0;
566151b1982SFengnan Chang
567151b1982SFengnan Chang for (no_index = 0; no_index < noext_cnt; no_index++) {
568151b1982SFengnan Chang if (!strcasecmp("*", noext[no_index])) {
569151b1982SFengnan Chang f2fs_info(sbi, "Don't allow the nocompress extension specifies all files");
570151b1982SFengnan Chang return -EINVAL;
571151b1982SFengnan Chang }
572151b1982SFengnan Chang for (index = 0; index < ext_cnt; index++) {
573151b1982SFengnan Chang if (!strcasecmp(ext[index], noext[no_index])) {
574151b1982SFengnan Chang f2fs_info(sbi, "Don't allow the same extension %s appear in both compress and nocompress extension",
575151b1982SFengnan Chang ext[index]);
576151b1982SFengnan Chang return -EINVAL;
577151b1982SFengnan Chang }
578151b1982SFengnan Chang }
579151b1982SFengnan Chang }
580151b1982SFengnan Chang return 0;
581151b1982SFengnan Chang }
582151b1982SFengnan Chang
5833fde13f8SChao Yu #ifdef CONFIG_F2FS_FS_LZ4
f2fs_set_lz4hc_level(struct f2fs_sb_info * sbi,const char * str)5843fde13f8SChao Yu static int f2fs_set_lz4hc_level(struct f2fs_sb_info *sbi, const char *str)
5853fde13f8SChao Yu {
5863fde13f8SChao Yu #ifdef CONFIG_F2FS_FS_LZ4HC
5873fde13f8SChao Yu unsigned int level;
5883fde13f8SChao Yu
5893fde13f8SChao Yu if (strlen(str) == 3) {
590091a4dfbSChao Yu F2FS_OPTION(sbi).compress_level = 0;
5913fde13f8SChao Yu return 0;
5923fde13f8SChao Yu }
5933fde13f8SChao Yu
5943fde13f8SChao Yu str += 3;
5953fde13f8SChao Yu
5963fde13f8SChao Yu if (str[0] != ':') {
5973fde13f8SChao Yu f2fs_info(sbi, "wrong format, e.g. <alg_name>:<compr_level>");
5983fde13f8SChao Yu return -EINVAL;
5993fde13f8SChao Yu }
6003fde13f8SChao Yu if (kstrtouint(str + 1, 10, &level))
6013fde13f8SChao Yu return -EINVAL;
6023fde13f8SChao Yu
603c571fbb5SSheng Yong if (!f2fs_is_compress_level_valid(COMPRESS_LZ4, level)) {
6043fde13f8SChao Yu f2fs_info(sbi, "invalid lz4hc compress level: %d", level);
6053fde13f8SChao Yu return -EINVAL;
6063fde13f8SChao Yu }
6073fde13f8SChao Yu
6083fde13f8SChao Yu F2FS_OPTION(sbi).compress_level = level;
6093fde13f8SChao Yu return 0;
6103fde13f8SChao Yu #else
61100e120b5SJaegeuk Kim if (strlen(str) == 3) {
61200e120b5SJaegeuk Kim F2FS_OPTION(sbi).compress_level = 0;
61300e120b5SJaegeuk Kim return 0;
61400e120b5SJaegeuk Kim }
6153fde13f8SChao Yu f2fs_info(sbi, "kernel doesn't support lz4hc compression");
6163fde13f8SChao Yu return -EINVAL;
6173fde13f8SChao Yu #endif
6183fde13f8SChao Yu }
6193fde13f8SChao Yu #endif
6203fde13f8SChao Yu
6213fde13f8SChao Yu #ifdef CONFIG_F2FS_FS_ZSTD
f2fs_set_zstd_level(struct f2fs_sb_info * sbi,const char * str)6223fde13f8SChao Yu static int f2fs_set_zstd_level(struct f2fs_sb_info *sbi, const char *str)
6233fde13f8SChao Yu {
6249deb2010SChao Yu int level;
6253fde13f8SChao Yu int len = 4;
6263fde13f8SChao Yu
6273fde13f8SChao Yu if (strlen(str) == len) {
62800e120b5SJaegeuk Kim F2FS_OPTION(sbi).compress_level = F2FS_ZSTD_DEFAULT_CLEVEL;
6293fde13f8SChao Yu return 0;
6303fde13f8SChao Yu }
6313fde13f8SChao Yu
6323fde13f8SChao Yu str += len;
6333fde13f8SChao Yu
6343fde13f8SChao Yu if (str[0] != ':') {
6353fde13f8SChao Yu f2fs_info(sbi, "wrong format, e.g. <alg_name>:<compr_level>");
6363fde13f8SChao Yu return -EINVAL;
6373fde13f8SChao Yu }
6389deb2010SChao Yu if (kstrtoint(str + 1, 10, &level))
6393fde13f8SChao Yu return -EINVAL;
6403fde13f8SChao Yu
6419deb2010SChao Yu /* f2fs does not support negative compress level now */
6429deb2010SChao Yu if (level < 0) {
6439deb2010SChao Yu f2fs_info(sbi, "do not support negative compress level: %d", level);
6449deb2010SChao Yu return -ERANGE;
6459deb2010SChao Yu }
6469deb2010SChao Yu
647c571fbb5SSheng Yong if (!f2fs_is_compress_level_valid(COMPRESS_ZSTD, level)) {
6483fde13f8SChao Yu f2fs_info(sbi, "invalid zstd compress level: %d", level);
6493fde13f8SChao Yu return -EINVAL;
6503fde13f8SChao Yu }
6513fde13f8SChao Yu
6523fde13f8SChao Yu F2FS_OPTION(sbi).compress_level = level;
6533fde13f8SChao Yu return 0;
6543fde13f8SChao Yu }
6553fde13f8SChao Yu #endif
6563fde13f8SChao Yu #endif
6573fde13f8SChao Yu
parse_options(struct super_block * sb,char * options,bool is_remount)658ed318a6cSEric Biggers static int parse_options(struct super_block *sb, char *options, bool is_remount)
659696c018cSNamjae Jeon {
660696c018cSNamjae Jeon struct f2fs_sb_info *sbi = F2FS_SB(sb);
661696c018cSNamjae Jeon substring_t args[MAX_OPT_ARGS];
6621f0b067bSChao Yu #ifdef CONFIG_F2FS_FS_COMPRESSION
6634c8ff709SChao Yu unsigned char (*ext)[F2FS_EXTENSION_LEN];
664151b1982SFengnan Chang unsigned char (*noext)[F2FS_EXTENSION_LEN];
665151b1982SFengnan Chang int ext_cnt, noext_cnt;
6661f0b067bSChao Yu #endif
667696c018cSNamjae Jeon char *p, *name;
6681f0b067bSChao Yu int arg = 0;
6697c2e5963SJaegeuk Kim kuid_t uid;
6707c2e5963SJaegeuk Kim kgid_t gid;
6714b2414d0SChao Yu int ret;
672696c018cSNamjae Jeon
673696c018cSNamjae Jeon if (!options)
674a7d9fe3cSJaegeuk Kim goto default_check;
675696c018cSNamjae Jeon
676696c018cSNamjae Jeon while ((p = strsep(&options, ",")) != NULL) {
677696c018cSNamjae Jeon int token;
6785f029c04SYi Zhuang
679696c018cSNamjae Jeon if (!*p)
680696c018cSNamjae Jeon continue;
681696c018cSNamjae Jeon /*
682696c018cSNamjae Jeon * Initialize args struct so we know whether arg was
683696c018cSNamjae Jeon * found; some options take optional arguments.
684696c018cSNamjae Jeon */
685696c018cSNamjae Jeon args[0].to = args[0].from = NULL;
686696c018cSNamjae Jeon token = match_token(p, f2fs_tokens, args);
687696c018cSNamjae Jeon
688696c018cSNamjae Jeon switch (token) {
689696c018cSNamjae Jeon case Opt_gc_background:
690696c018cSNamjae Jeon name = match_strdup(&args[0]);
691696c018cSNamjae Jeon
692696c018cSNamjae Jeon if (!name)
693696c018cSNamjae Jeon return -ENOMEM;
6943c57f751SEric Biggers if (!strcmp(name, "on")) {
695bbbc34fdSChao Yu F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_ON;
6963c57f751SEric Biggers } else if (!strcmp(name, "off")) {
697bbbc34fdSChao Yu F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_OFF;
6983c57f751SEric Biggers } else if (!strcmp(name, "sync")) {
699bbbc34fdSChao Yu F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_SYNC;
7006aefd93bSJaegeuk Kim } else {
701ba87a45cSWang Xiaojun kfree(name);
702696c018cSNamjae Jeon return -EINVAL;
703696c018cSNamjae Jeon }
704ba87a45cSWang Xiaojun kfree(name);
705696c018cSNamjae Jeon break;
706696c018cSNamjae Jeon case Opt_disable_roll_forward:
707696c018cSNamjae Jeon set_opt(sbi, DISABLE_ROLL_FORWARD);
708696c018cSNamjae Jeon break;
7092d834bf9SJaegeuk Kim case Opt_norecovery:
7102d834bf9SJaegeuk Kim /* this option mounts f2fs with ro */
711a9117ecaSChao Yu set_opt(sbi, NORECOVERY);
7122d834bf9SJaegeuk Kim if (!f2fs_readonly(sb))
7132d834bf9SJaegeuk Kim return -EINVAL;
7142d834bf9SJaegeuk Kim break;
715696c018cSNamjae Jeon case Opt_discard:
716f7db8dd6SChao Yu if (!f2fs_hw_support_discard(sbi)) {
717f7db8dd6SChao Yu f2fs_warn(sbi, "device does not support discard");
718f7db8dd6SChao Yu break;
719f7db8dd6SChao Yu }
720696c018cSNamjae Jeon set_opt(sbi, DISCARD);
721696c018cSNamjae Jeon break;
72264058be9SChao Yu case Opt_nodiscard:
723f7db8dd6SChao Yu if (f2fs_hw_should_discard(sbi)) {
724dcbb4c10SJoe Perches f2fs_warn(sbi, "discard is required for zoned block devices");
72596ba2decSDamien Le Moal return -EINVAL;
72696ba2decSDamien Le Moal }
72764058be9SChao Yu clear_opt(sbi, DISCARD);
728487df616SDamien Le Moal break;
729696c018cSNamjae Jeon case Opt_noheap:
7307a20b8a6SJaegeuk Kim case Opt_heap:
731066cec37SJaegeuk Kim f2fs_warn(sbi, "heap/no_heap options were deprecated");
7327a20b8a6SJaegeuk Kim break;
733696c018cSNamjae Jeon #ifdef CONFIG_F2FS_FS_XATTR
7344058c511SKelly Anderson case Opt_user_xattr:
7354058c511SKelly Anderson set_opt(sbi, XATTR_USER);
7364058c511SKelly Anderson break;
737696c018cSNamjae Jeon case Opt_nouser_xattr:
738696c018cSNamjae Jeon clear_opt(sbi, XATTR_USER);
739696c018cSNamjae Jeon break;
740444c580fSJaegeuk Kim case Opt_inline_xattr:
741444c580fSJaegeuk Kim set_opt(sbi, INLINE_XATTR);
742444c580fSJaegeuk Kim break;
74323cf7212SChao Yu case Opt_noinline_xattr:
74423cf7212SChao Yu clear_opt(sbi, INLINE_XATTR);
74523cf7212SChao Yu break;
7466afc662eSChao Yu case Opt_inline_xattr_size:
7476afc662eSChao Yu if (args->from && match_int(args, &arg))
7486afc662eSChao Yu return -EINVAL;
7496afc662eSChao Yu set_opt(sbi, INLINE_XATTR_SIZE);
75063189b78SChao Yu F2FS_OPTION(sbi).inline_xattr_size = arg;
7516afc662eSChao Yu break;
752696c018cSNamjae Jeon #else
7534058c511SKelly Anderson case Opt_user_xattr:
754dcbb4c10SJoe Perches f2fs_info(sbi, "user_xattr options not supported");
7554058c511SKelly Anderson break;
756696c018cSNamjae Jeon case Opt_nouser_xattr:
757dcbb4c10SJoe Perches f2fs_info(sbi, "nouser_xattr options not supported");
758696c018cSNamjae Jeon break;
759444c580fSJaegeuk Kim case Opt_inline_xattr:
760dcbb4c10SJoe Perches f2fs_info(sbi, "inline_xattr options not supported");
761444c580fSJaegeuk Kim break;
76223cf7212SChao Yu case Opt_noinline_xattr:
763dcbb4c10SJoe Perches f2fs_info(sbi, "noinline_xattr options not supported");
76423cf7212SChao Yu break;
765696c018cSNamjae Jeon #endif
766696c018cSNamjae Jeon #ifdef CONFIG_F2FS_FS_POSIX_ACL
7674058c511SKelly Anderson case Opt_acl:
7684058c511SKelly Anderson set_opt(sbi, POSIX_ACL);
7694058c511SKelly Anderson break;
770696c018cSNamjae Jeon case Opt_noacl:
771696c018cSNamjae Jeon clear_opt(sbi, POSIX_ACL);
772696c018cSNamjae Jeon break;
773696c018cSNamjae Jeon #else
7744058c511SKelly Anderson case Opt_acl:
775dcbb4c10SJoe Perches f2fs_info(sbi, "acl options not supported");
7764058c511SKelly Anderson break;
777696c018cSNamjae Jeon case Opt_noacl:
778dcbb4c10SJoe Perches f2fs_info(sbi, "noacl options not supported");
779696c018cSNamjae Jeon break;
780696c018cSNamjae Jeon #endif
781696c018cSNamjae Jeon case Opt_active_logs:
782696c018cSNamjae Jeon if (args->from && match_int(args, &arg))
783696c018cSNamjae Jeon return -EINVAL;
784d0b9e42aSChao Yu if (arg != 2 && arg != 4 &&
785d0b9e42aSChao Yu arg != NR_CURSEG_PERSIST_TYPE)
786696c018cSNamjae Jeon return -EINVAL;
78763189b78SChao Yu F2FS_OPTION(sbi).active_logs = arg;
788696c018cSNamjae Jeon break;
789696c018cSNamjae Jeon case Opt_disable_ext_identify:
790696c018cSNamjae Jeon set_opt(sbi, DISABLE_EXT_IDENTIFY);
791696c018cSNamjae Jeon break;
7928274de77SHuajun Li case Opt_inline_data:
7938274de77SHuajun Li set_opt(sbi, INLINE_DATA);
7948274de77SHuajun Li break;
7955efd3c6fSChao Yu case Opt_inline_dentry:
7965efd3c6fSChao Yu set_opt(sbi, INLINE_DENTRY);
7975efd3c6fSChao Yu break;
79897c1794aSChao Yu case Opt_noinline_dentry:
79997c1794aSChao Yu clear_opt(sbi, INLINE_DENTRY);
80097c1794aSChao Yu break;
8016b4afdd7SJaegeuk Kim case Opt_flush_merge:
8026b4afdd7SJaegeuk Kim set_opt(sbi, FLUSH_MERGE);
8036b4afdd7SJaegeuk Kim break;
80469e9e427SJaegeuk Kim case Opt_noflush_merge:
80569e9e427SJaegeuk Kim clear_opt(sbi, FLUSH_MERGE);
80669e9e427SJaegeuk Kim break;
8070f7b2abdSJaegeuk Kim case Opt_nobarrier:
8080f7b2abdSJaegeuk Kim set_opt(sbi, NOBARRIER);
8090f7b2abdSJaegeuk Kim break;
8106047de54SYangtao Li case Opt_barrier:
8116047de54SYangtao Li clear_opt(sbi, NOBARRIER);
8126047de54SYangtao Li break;
813d5053a34SJaegeuk Kim case Opt_fastboot:
814d5053a34SJaegeuk Kim set_opt(sbi, FASTBOOT);
815d5053a34SJaegeuk Kim break;
81689672159SChao Yu case Opt_extent_cache:
81712607c1bSJaegeuk Kim set_opt(sbi, READ_EXTENT_CACHE);
81889672159SChao Yu break;
8197daaea25SJaegeuk Kim case Opt_noextent_cache:
82012607c1bSJaegeuk Kim clear_opt(sbi, READ_EXTENT_CACHE);
8217daaea25SJaegeuk Kim break;
82275342797SWanpeng Li case Opt_noinline_data:
82375342797SWanpeng Li clear_opt(sbi, INLINE_DATA);
82475342797SWanpeng Li break;
825343f40f0SChao Yu case Opt_data_flush:
826343f40f0SChao Yu set_opt(sbi, DATA_FLUSH);
827343f40f0SChao Yu break;
8287e65be49SJaegeuk Kim case Opt_reserve_root:
8297e65be49SJaegeuk Kim if (args->from && match_int(args, &arg))
8307e65be49SJaegeuk Kim return -EINVAL;
8317e65be49SJaegeuk Kim if (test_opt(sbi, RESERVE_ROOT)) {
832dcbb4c10SJoe Perches f2fs_info(sbi, "Preserve previous reserve_root=%u",
83363189b78SChao Yu F2FS_OPTION(sbi).root_reserved_blocks);
8347e65be49SJaegeuk Kim } else {
83563189b78SChao Yu F2FS_OPTION(sbi).root_reserved_blocks = arg;
8367e65be49SJaegeuk Kim set_opt(sbi, RESERVE_ROOT);
8377e65be49SJaegeuk Kim }
8387e65be49SJaegeuk Kim break;
8397c2e5963SJaegeuk Kim case Opt_resuid:
8407c2e5963SJaegeuk Kim if (args->from && match_int(args, &arg))
8417c2e5963SJaegeuk Kim return -EINVAL;
8427c2e5963SJaegeuk Kim uid = make_kuid(current_user_ns(), arg);
8437c2e5963SJaegeuk Kim if (!uid_valid(uid)) {
844dcbb4c10SJoe Perches f2fs_err(sbi, "Invalid uid value %d", arg);
8457c2e5963SJaegeuk Kim return -EINVAL;
8467c2e5963SJaegeuk Kim }
84763189b78SChao Yu F2FS_OPTION(sbi).s_resuid = uid;
8487c2e5963SJaegeuk Kim break;
8497c2e5963SJaegeuk Kim case Opt_resgid:
8507c2e5963SJaegeuk Kim if (args->from && match_int(args, &arg))
8517c2e5963SJaegeuk Kim return -EINVAL;
8527c2e5963SJaegeuk Kim gid = make_kgid(current_user_ns(), arg);
8537c2e5963SJaegeuk Kim if (!gid_valid(gid)) {
854dcbb4c10SJoe Perches f2fs_err(sbi, "Invalid gid value %d", arg);
8557c2e5963SJaegeuk Kim return -EINVAL;
8567c2e5963SJaegeuk Kim }
85763189b78SChao Yu F2FS_OPTION(sbi).s_resgid = gid;
8587c2e5963SJaegeuk Kim break;
85936abef4eSJaegeuk Kim case Opt_mode:
86036abef4eSJaegeuk Kim name = match_strdup(&args[0]);
86136abef4eSJaegeuk Kim
86236abef4eSJaegeuk Kim if (!name)
86336abef4eSJaegeuk Kim return -ENOMEM;
8643c57f751SEric Biggers if (!strcmp(name, "adaptive")) {
865b0332a0fSChao Yu F2FS_OPTION(sbi).fs_mode = FS_MODE_ADAPTIVE;
8663c57f751SEric Biggers } else if (!strcmp(name, "lfs")) {
867b0332a0fSChao Yu F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS;
8686691d940SDaeho Jeong } else if (!strcmp(name, "fragment:segment")) {
8696691d940SDaeho Jeong F2FS_OPTION(sbi).fs_mode = FS_MODE_FRAGMENT_SEG;
8706691d940SDaeho Jeong } else if (!strcmp(name, "fragment:block")) {
8716691d940SDaeho Jeong F2FS_OPTION(sbi).fs_mode = FS_MODE_FRAGMENT_BLK;
87236abef4eSJaegeuk Kim } else {
873ba87a45cSWang Xiaojun kfree(name);
87436abef4eSJaegeuk Kim return -EINVAL;
87536abef4eSJaegeuk Kim }
876ba87a45cSWang Xiaojun kfree(name);
87736abef4eSJaegeuk Kim break;
8784cb037ecSChengguang Xu #ifdef CONFIG_F2FS_FAULT_INJECTION
87973faec4dSJaegeuk Kim case Opt_fault_injection:
88073faec4dSJaegeuk Kim if (args->from && match_int(args, &arg))
88173faec4dSJaegeuk Kim return -EINVAL;
88244958ca9SChao Yu if (f2fs_build_fault_attr(sbi, arg,
88344958ca9SChao Yu F2FS_ALL_FAULT_TYPE))
88444958ca9SChao Yu return -EINVAL;
885d494500aSChao Yu set_opt(sbi, FAULT_INJECTION);
886d494500aSChao Yu break;
8874cb037ecSChengguang Xu
888d494500aSChao Yu case Opt_fault_type:
889d494500aSChao Yu if (args->from && match_int(args, &arg))
890d494500aSChao Yu return -EINVAL;
89144958ca9SChao Yu if (f2fs_build_fault_attr(sbi, 0, arg))
89244958ca9SChao Yu return -EINVAL;
8930cc0dec2SKaixu Xia set_opt(sbi, FAULT_INJECTION);
89473faec4dSJaegeuk Kim break;
8954cb037ecSChengguang Xu #else
8964cb037ecSChengguang Xu case Opt_fault_injection:
897dcbb4c10SJoe Perches f2fs_info(sbi, "fault_injection options not supported");
8984cb037ecSChengguang Xu break;
8994cb037ecSChengguang Xu
9004cb037ecSChengguang Xu case Opt_fault_type:
901dcbb4c10SJoe Perches f2fs_info(sbi, "fault_type options not supported");
9024cb037ecSChengguang Xu break;
9034cb037ecSChengguang Xu #endif
9046d94c74aSJaegeuk Kim case Opt_lazytime:
9051751e8a6SLinus Torvalds sb->s_flags |= SB_LAZYTIME;
9066d94c74aSJaegeuk Kim break;
9076d94c74aSJaegeuk Kim case Opt_nolazytime:
9081751e8a6SLinus Torvalds sb->s_flags &= ~SB_LAZYTIME;
9096d94c74aSJaegeuk Kim break;
9100abd675eSChao Yu #ifdef CONFIG_QUOTA
9114b2414d0SChao Yu case Opt_quota:
9120abd675eSChao Yu case Opt_usrquota:
9130abd675eSChao Yu set_opt(sbi, USRQUOTA);
9140abd675eSChao Yu break;
9150abd675eSChao Yu case Opt_grpquota:
9160abd675eSChao Yu set_opt(sbi, GRPQUOTA);
9170abd675eSChao Yu break;
9185c57132eSChao Yu case Opt_prjquota:
9195c57132eSChao Yu set_opt(sbi, PRJQUOTA);
9205c57132eSChao Yu break;
9214b2414d0SChao Yu case Opt_usrjquota:
9224b2414d0SChao Yu ret = f2fs_set_qf_name(sb, USRQUOTA, &args[0]);
9234b2414d0SChao Yu if (ret)
9244b2414d0SChao Yu return ret;
9254b2414d0SChao Yu break;
9264b2414d0SChao Yu case Opt_grpjquota:
9274b2414d0SChao Yu ret = f2fs_set_qf_name(sb, GRPQUOTA, &args[0]);
9284b2414d0SChao Yu if (ret)
9294b2414d0SChao Yu return ret;
9304b2414d0SChao Yu break;
9314b2414d0SChao Yu case Opt_prjjquota:
9324b2414d0SChao Yu ret = f2fs_set_qf_name(sb, PRJQUOTA, &args[0]);
9334b2414d0SChao Yu if (ret)
9344b2414d0SChao Yu return ret;
9354b2414d0SChao Yu break;
9364b2414d0SChao Yu case Opt_offusrjquota:
9374b2414d0SChao Yu ret = f2fs_clear_qf_name(sb, USRQUOTA);
9384b2414d0SChao Yu if (ret)
9394b2414d0SChao Yu return ret;
9404b2414d0SChao Yu break;
9414b2414d0SChao Yu case Opt_offgrpjquota:
9424b2414d0SChao Yu ret = f2fs_clear_qf_name(sb, GRPQUOTA);
9434b2414d0SChao Yu if (ret)
9444b2414d0SChao Yu return ret;
9454b2414d0SChao Yu break;
9464b2414d0SChao Yu case Opt_offprjjquota:
9474b2414d0SChao Yu ret = f2fs_clear_qf_name(sb, PRJQUOTA);
9484b2414d0SChao Yu if (ret)
9494b2414d0SChao Yu return ret;
9504b2414d0SChao Yu break;
9514b2414d0SChao Yu case Opt_jqfmt_vfsold:
95263189b78SChao Yu F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_OLD;
9534b2414d0SChao Yu break;
9544b2414d0SChao Yu case Opt_jqfmt_vfsv0:
95563189b78SChao Yu F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_V0;
9564b2414d0SChao Yu break;
9574b2414d0SChao Yu case Opt_jqfmt_vfsv1:
95863189b78SChao Yu F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_V1;
9594b2414d0SChao Yu break;
9604b2414d0SChao Yu case Opt_noquota:
9614b2414d0SChao Yu clear_opt(sbi, QUOTA);
9624b2414d0SChao Yu clear_opt(sbi, USRQUOTA);
9634b2414d0SChao Yu clear_opt(sbi, GRPQUOTA);
9644b2414d0SChao Yu clear_opt(sbi, PRJQUOTA);
9654b2414d0SChao Yu break;
9660abd675eSChao Yu #else
9674b2414d0SChao Yu case Opt_quota:
9680abd675eSChao Yu case Opt_usrquota:
9690abd675eSChao Yu case Opt_grpquota:
9705c57132eSChao Yu case Opt_prjquota:
9714b2414d0SChao Yu case Opt_usrjquota:
9724b2414d0SChao Yu case Opt_grpjquota:
9734b2414d0SChao Yu case Opt_prjjquota:
9744b2414d0SChao Yu case Opt_offusrjquota:
9754b2414d0SChao Yu case Opt_offgrpjquota:
9764b2414d0SChao Yu case Opt_offprjjquota:
9774b2414d0SChao Yu case Opt_jqfmt_vfsold:
9784b2414d0SChao Yu case Opt_jqfmt_vfsv0:
9794b2414d0SChao Yu case Opt_jqfmt_vfsv1:
9804b2414d0SChao Yu case Opt_noquota:
981dcbb4c10SJoe Perches f2fs_info(sbi, "quota operations not supported");
9820abd675eSChao Yu break;
9830abd675eSChao Yu #endif
98407939627SJaegeuk Kim case Opt_alloc:
98507939627SJaegeuk Kim name = match_strdup(&args[0]);
98607939627SJaegeuk Kim if (!name)
98707939627SJaegeuk Kim return -ENOMEM;
98807939627SJaegeuk Kim
9893c57f751SEric Biggers if (!strcmp(name, "default")) {
99063189b78SChao Yu F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT;
9913c57f751SEric Biggers } else if (!strcmp(name, "reuse")) {
99263189b78SChao Yu F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE;
99307939627SJaegeuk Kim } else {
994ba87a45cSWang Xiaojun kfree(name);
99507939627SJaegeuk Kim return -EINVAL;
99607939627SJaegeuk Kim }
997ba87a45cSWang Xiaojun kfree(name);
99807939627SJaegeuk Kim break;
99993cf93f1SJunling Zheng case Opt_fsync:
100093cf93f1SJunling Zheng name = match_strdup(&args[0]);
100193cf93f1SJunling Zheng if (!name)
100293cf93f1SJunling Zheng return -ENOMEM;
10033c57f751SEric Biggers if (!strcmp(name, "posix")) {
100463189b78SChao Yu F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX;
10053c57f751SEric Biggers } else if (!strcmp(name, "strict")) {
100663189b78SChao Yu F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_STRICT;
10073c57f751SEric Biggers } else if (!strcmp(name, "nobarrier")) {
1008d6290814SJaegeuk Kim F2FS_OPTION(sbi).fsync_mode =
1009d6290814SJaegeuk Kim FSYNC_MODE_NOBARRIER;
101093cf93f1SJunling Zheng } else {
1011ba87a45cSWang Xiaojun kfree(name);
101293cf93f1SJunling Zheng return -EINVAL;
101393cf93f1SJunling Zheng }
1014ba87a45cSWang Xiaojun kfree(name);
101593cf93f1SJunling Zheng break;
1016ff62af20SSheng Yong case Opt_test_dummy_encryption:
1017ed318a6cSEric Biggers ret = f2fs_set_test_dummy_encryption(sb, p, &args[0],
1018ed318a6cSEric Biggers is_remount);
1019ed318a6cSEric Biggers if (ret)
1020ed318a6cSEric Biggers return ret;
1021ff62af20SSheng Yong break;
102227aacd28SSatya Tangirala case Opt_inlinecrypt:
102327aacd28SSatya Tangirala #ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
102427aacd28SSatya Tangirala sb->s_flags |= SB_INLINECRYPT;
102527aacd28SSatya Tangirala #else
102627aacd28SSatya Tangirala f2fs_info(sbi, "inline encryption not supported");
102727aacd28SSatya Tangirala #endif
102827aacd28SSatya Tangirala break;
10294d3aed70SDaniel Rosenberg case Opt_checkpoint_disable_cap_perc:
10304d3aed70SDaniel Rosenberg if (args->from && match_int(args, &arg))
10314354994fSDaniel Rosenberg return -EINVAL;
10324d3aed70SDaniel Rosenberg if (arg < 0 || arg > 100)
10334d3aed70SDaniel Rosenberg return -EINVAL;
10341ae18f71SJaegeuk Kim F2FS_OPTION(sbi).unusable_cap_perc = arg;
10354d3aed70SDaniel Rosenberg set_opt(sbi, DISABLE_CHECKPOINT);
10364d3aed70SDaniel Rosenberg break;
10374d3aed70SDaniel Rosenberg case Opt_checkpoint_disable_cap:
10384d3aed70SDaniel Rosenberg if (args->from && match_int(args, &arg))
10394d3aed70SDaniel Rosenberg return -EINVAL;
10404d3aed70SDaniel Rosenberg F2FS_OPTION(sbi).unusable_cap = arg;
10414d3aed70SDaniel Rosenberg set_opt(sbi, DISABLE_CHECKPOINT);
10424d3aed70SDaniel Rosenberg break;
10434d3aed70SDaniel Rosenberg case Opt_checkpoint_disable:
10444d3aed70SDaniel Rosenberg set_opt(sbi, DISABLE_CHECKPOINT);
10454d3aed70SDaniel Rosenberg break;
10464d3aed70SDaniel Rosenberg case Opt_checkpoint_enable:
10474d3aed70SDaniel Rosenberg clear_opt(sbi, DISABLE_CHECKPOINT);
10484354994fSDaniel Rosenberg break;
1049261eeb9cSDaeho Jeong case Opt_checkpoint_merge:
1050261eeb9cSDaeho Jeong set_opt(sbi, MERGE_CHECKPOINT);
1051261eeb9cSDaeho Jeong break;
1052261eeb9cSDaeho Jeong case Opt_nocheckpoint_merge:
1053261eeb9cSDaeho Jeong clear_opt(sbi, MERGE_CHECKPOINT);
1054261eeb9cSDaeho Jeong break;
10551f0b067bSChao Yu #ifdef CONFIG_F2FS_FS_COMPRESSION
10564c8ff709SChao Yu case Opt_compress_algorithm:
10574c8ff709SChao Yu if (!f2fs_sb_has_compression(sbi)) {
105869c0dd29SChao Yu f2fs_info(sbi, "Image doesn't support compression");
105969c0dd29SChao Yu break;
10604c8ff709SChao Yu }
10614c8ff709SChao Yu name = match_strdup(&args[0]);
10624c8ff709SChao Yu if (!name)
10634c8ff709SChao Yu return -ENOMEM;
10643c57f751SEric Biggers if (!strcmp(name, "lzo")) {
106532be0e97SChao Yu #ifdef CONFIG_F2FS_FS_LZO
10663fde13f8SChao Yu F2FS_OPTION(sbi).compress_level = 0;
10674c8ff709SChao Yu F2FS_OPTION(sbi).compress_algorithm =
10684c8ff709SChao Yu COMPRESS_LZO;
106932be0e97SChao Yu #else
107032be0e97SChao Yu f2fs_info(sbi, "kernel doesn't support lzo compression");
107132be0e97SChao Yu #endif
10723fde13f8SChao Yu } else if (!strncmp(name, "lz4", 3)) {
107332be0e97SChao Yu #ifdef CONFIG_F2FS_FS_LZ4
10743fde13f8SChao Yu ret = f2fs_set_lz4hc_level(sbi, name);
10753fde13f8SChao Yu if (ret) {
10763fde13f8SChao Yu kfree(name);
10773fde13f8SChao Yu return -EINVAL;
10783fde13f8SChao Yu }
10794c8ff709SChao Yu F2FS_OPTION(sbi).compress_algorithm =
10804c8ff709SChao Yu COMPRESS_LZ4;
108132be0e97SChao Yu #else
108232be0e97SChao Yu f2fs_info(sbi, "kernel doesn't support lz4 compression");
108332be0e97SChao Yu #endif
10843fde13f8SChao Yu } else if (!strncmp(name, "zstd", 4)) {
108532be0e97SChao Yu #ifdef CONFIG_F2FS_FS_ZSTD
10863fde13f8SChao Yu ret = f2fs_set_zstd_level(sbi, name);
10873fde13f8SChao Yu if (ret) {
10883fde13f8SChao Yu kfree(name);
10893fde13f8SChao Yu return -EINVAL;
10903fde13f8SChao Yu }
109150cfa66fSChao Yu F2FS_OPTION(sbi).compress_algorithm =
109250cfa66fSChao Yu COMPRESS_ZSTD;
109332be0e97SChao Yu #else
109432be0e97SChao Yu f2fs_info(sbi, "kernel doesn't support zstd compression");
109532be0e97SChao Yu #endif
10966d92b201SChao Yu } else if (!strcmp(name, "lzo-rle")) {
109732be0e97SChao Yu #ifdef CONFIG_F2FS_FS_LZORLE
10983fde13f8SChao Yu F2FS_OPTION(sbi).compress_level = 0;
10996d92b201SChao Yu F2FS_OPTION(sbi).compress_algorithm =
11006d92b201SChao Yu COMPRESS_LZORLE;
110132be0e97SChao Yu #else
110232be0e97SChao Yu f2fs_info(sbi, "kernel doesn't support lzorle compression");
110332be0e97SChao Yu #endif
11044c8ff709SChao Yu } else {
11054c8ff709SChao Yu kfree(name);
11064c8ff709SChao Yu return -EINVAL;
11074c8ff709SChao Yu }
11084c8ff709SChao Yu kfree(name);
11094c8ff709SChao Yu break;
11104c8ff709SChao Yu case Opt_compress_log_size:
11114c8ff709SChao Yu if (!f2fs_sb_has_compression(sbi)) {
111269c0dd29SChao Yu f2fs_info(sbi, "Image doesn't support compression");
111369c0dd29SChao Yu break;
11144c8ff709SChao Yu }
11154c8ff709SChao Yu if (args->from && match_int(args, &arg))
11164c8ff709SChao Yu return -EINVAL;
11174c8ff709SChao Yu if (arg < MIN_COMPRESS_LOG_SIZE ||
11184c8ff709SChao Yu arg > MAX_COMPRESS_LOG_SIZE) {
11194c8ff709SChao Yu f2fs_err(sbi,
11204c8ff709SChao Yu "Compress cluster log size is out of range");
11214c8ff709SChao Yu return -EINVAL;
11224c8ff709SChao Yu }
11234c8ff709SChao Yu F2FS_OPTION(sbi).compress_log_size = arg;
11244c8ff709SChao Yu break;
11254c8ff709SChao Yu case Opt_compress_extension:
11264c8ff709SChao Yu if (!f2fs_sb_has_compression(sbi)) {
112769c0dd29SChao Yu f2fs_info(sbi, "Image doesn't support compression");
112869c0dd29SChao Yu break;
11294c8ff709SChao Yu }
11304c8ff709SChao Yu name = match_strdup(&args[0]);
11314c8ff709SChao Yu if (!name)
11324c8ff709SChao Yu return -ENOMEM;
11334c8ff709SChao Yu
11344c8ff709SChao Yu ext = F2FS_OPTION(sbi).extensions;
11354c8ff709SChao Yu ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt;
11364c8ff709SChao Yu
11374c8ff709SChao Yu if (strlen(name) >= F2FS_EXTENSION_LEN ||
11384c8ff709SChao Yu ext_cnt >= COMPRESS_EXT_NUM) {
11394c8ff709SChao Yu f2fs_err(sbi,
11404c8ff709SChao Yu "invalid extension length/number");
11414c8ff709SChao Yu kfree(name);
11424c8ff709SChao Yu return -EINVAL;
11434c8ff709SChao Yu }
11444c8ff709SChao Yu
1145afab82ecSChao Yu if (is_compress_extension_exist(sbi, name, true)) {
1146afab82ecSChao Yu kfree(name);
1147afab82ecSChao Yu break;
1148afab82ecSChao Yu }
1149afab82ecSChao Yu
11504c8ff709SChao Yu strcpy(ext[ext_cnt], name);
11514c8ff709SChao Yu F2FS_OPTION(sbi).compress_ext_cnt++;
11524c8ff709SChao Yu kfree(name);
11534c8ff709SChao Yu break;
1154151b1982SFengnan Chang case Opt_nocompress_extension:
1155151b1982SFengnan Chang if (!f2fs_sb_has_compression(sbi)) {
1156151b1982SFengnan Chang f2fs_info(sbi, "Image doesn't support compression");
1157151b1982SFengnan Chang break;
1158151b1982SFengnan Chang }
1159151b1982SFengnan Chang name = match_strdup(&args[0]);
1160151b1982SFengnan Chang if (!name)
1161151b1982SFengnan Chang return -ENOMEM;
1162151b1982SFengnan Chang
1163151b1982SFengnan Chang noext = F2FS_OPTION(sbi).noextensions;
1164151b1982SFengnan Chang noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt;
1165151b1982SFengnan Chang
1166151b1982SFengnan Chang if (strlen(name) >= F2FS_EXTENSION_LEN ||
1167151b1982SFengnan Chang noext_cnt >= COMPRESS_EXT_NUM) {
1168151b1982SFengnan Chang f2fs_err(sbi,
1169151b1982SFengnan Chang "invalid extension length/number");
1170151b1982SFengnan Chang kfree(name);
1171151b1982SFengnan Chang return -EINVAL;
1172151b1982SFengnan Chang }
1173151b1982SFengnan Chang
1174afab82ecSChao Yu if (is_compress_extension_exist(sbi, name, false)) {
1175afab82ecSChao Yu kfree(name);
1176afab82ecSChao Yu break;
1177afab82ecSChao Yu }
1178afab82ecSChao Yu
1179151b1982SFengnan Chang strcpy(noext[noext_cnt], name);
1180151b1982SFengnan Chang F2FS_OPTION(sbi).nocompress_ext_cnt++;
1181151b1982SFengnan Chang kfree(name);
1182151b1982SFengnan Chang break;
1183b28f047bSChao Yu case Opt_compress_chksum:
1184d4998b78SYangtao Li if (!f2fs_sb_has_compression(sbi)) {
1185d4998b78SYangtao Li f2fs_info(sbi, "Image doesn't support compression");
1186d4998b78SYangtao Li break;
1187d4998b78SYangtao Li }
1188b28f047bSChao Yu F2FS_OPTION(sbi).compress_chksum = true;
1189b28f047bSChao Yu break;
1190602a16d5SDaeho Jeong case Opt_compress_mode:
1191d4998b78SYangtao Li if (!f2fs_sb_has_compression(sbi)) {
1192d4998b78SYangtao Li f2fs_info(sbi, "Image doesn't support compression");
1193d4998b78SYangtao Li break;
1194d4998b78SYangtao Li }
1195602a16d5SDaeho Jeong name = match_strdup(&args[0]);
1196602a16d5SDaeho Jeong if (!name)
1197602a16d5SDaeho Jeong return -ENOMEM;
1198602a16d5SDaeho Jeong if (!strcmp(name, "fs")) {
1199602a16d5SDaeho Jeong F2FS_OPTION(sbi).compress_mode = COMPR_MODE_FS;
1200602a16d5SDaeho Jeong } else if (!strcmp(name, "user")) {
1201602a16d5SDaeho Jeong F2FS_OPTION(sbi).compress_mode = COMPR_MODE_USER;
1202602a16d5SDaeho Jeong } else {
1203602a16d5SDaeho Jeong kfree(name);
1204602a16d5SDaeho Jeong return -EINVAL;
1205602a16d5SDaeho Jeong }
1206602a16d5SDaeho Jeong kfree(name);
1207602a16d5SDaeho Jeong break;
12086ce19affSChao Yu case Opt_compress_cache:
1209d4998b78SYangtao Li if (!f2fs_sb_has_compression(sbi)) {
1210d4998b78SYangtao Li f2fs_info(sbi, "Image doesn't support compression");
1211d4998b78SYangtao Li break;
1212d4998b78SYangtao Li }
12136ce19affSChao Yu set_opt(sbi, COMPRESS_CACHE);
12146ce19affSChao Yu break;
12151f0b067bSChao Yu #else
12161f0b067bSChao Yu case Opt_compress_algorithm:
12171f0b067bSChao Yu case Opt_compress_log_size:
12181f0b067bSChao Yu case Opt_compress_extension:
1219151b1982SFengnan Chang case Opt_nocompress_extension:
1220b28f047bSChao Yu case Opt_compress_chksum:
1221602a16d5SDaeho Jeong case Opt_compress_mode:
12226ce19affSChao Yu case Opt_compress_cache:
12231f0b067bSChao Yu f2fs_info(sbi, "compression options not supported");
12241f0b067bSChao Yu break;
12251f0b067bSChao Yu #endif
1226093749e2SChao Yu case Opt_atgc:
1227093749e2SChao Yu set_opt(sbi, ATGC);
1228093749e2SChao Yu break;
12295911d2d1SChao Yu case Opt_gc_merge:
12305911d2d1SChao Yu set_opt(sbi, GC_MERGE);
12315911d2d1SChao Yu break;
12325911d2d1SChao Yu case Opt_nogc_merge:
12335911d2d1SChao Yu clear_opt(sbi, GC_MERGE);
12345911d2d1SChao Yu break;
12354f993264SChao Yu case Opt_discard_unit:
12364f993264SChao Yu name = match_strdup(&args[0]);
12374f993264SChao Yu if (!name)
12384f993264SChao Yu return -ENOMEM;
12394f993264SChao Yu if (!strcmp(name, "block")) {
12404f993264SChao Yu F2FS_OPTION(sbi).discard_unit =
12414f993264SChao Yu DISCARD_UNIT_BLOCK;
12424f993264SChao Yu } else if (!strcmp(name, "segment")) {
12434f993264SChao Yu F2FS_OPTION(sbi).discard_unit =
12444f993264SChao Yu DISCARD_UNIT_SEGMENT;
12454f993264SChao Yu } else if (!strcmp(name, "section")) {
12464f993264SChao Yu F2FS_OPTION(sbi).discard_unit =
12474f993264SChao Yu DISCARD_UNIT_SECTION;
12484f993264SChao Yu } else {
12494f993264SChao Yu kfree(name);
12504f993264SChao Yu return -EINVAL;
12514f993264SChao Yu }
12524f993264SChao Yu kfree(name);
12534f993264SChao Yu break;
12547a8fc586SDaeho Jeong case Opt_memory_mode:
12557a8fc586SDaeho Jeong name = match_strdup(&args[0]);
12567a8fc586SDaeho Jeong if (!name)
12577a8fc586SDaeho Jeong return -ENOMEM;
12587a8fc586SDaeho Jeong if (!strcmp(name, "normal")) {
12597a8fc586SDaeho Jeong F2FS_OPTION(sbi).memory_mode =
12607a8fc586SDaeho Jeong MEMORY_MODE_NORMAL;
12617a8fc586SDaeho Jeong } else if (!strcmp(name, "low")) {
12627a8fc586SDaeho Jeong F2FS_OPTION(sbi).memory_mode =
12637a8fc586SDaeho Jeong MEMORY_MODE_LOW;
12647a8fc586SDaeho Jeong } else {
12657a8fc586SDaeho Jeong kfree(name);
12667a8fc586SDaeho Jeong return -EINVAL;
12677a8fc586SDaeho Jeong }
12687a8fc586SDaeho Jeong kfree(name);
12697a8fc586SDaeho Jeong break;
127071644dffSJaegeuk Kim case Opt_age_extent_cache:
127171644dffSJaegeuk Kim set_opt(sbi, AGE_EXTENT_CACHE);
127271644dffSJaegeuk Kim break;
1273b62e71beSChao Yu case Opt_errors:
1274b62e71beSChao Yu name = match_strdup(&args[0]);
1275b62e71beSChao Yu if (!name)
1276b62e71beSChao Yu return -ENOMEM;
1277b62e71beSChao Yu if (!strcmp(name, "remount-ro")) {
1278b62e71beSChao Yu F2FS_OPTION(sbi).errors =
1279b62e71beSChao Yu MOUNT_ERRORS_READONLY;
1280b62e71beSChao Yu } else if (!strcmp(name, "continue")) {
1281b62e71beSChao Yu F2FS_OPTION(sbi).errors =
1282b62e71beSChao Yu MOUNT_ERRORS_CONTINUE;
1283b62e71beSChao Yu } else if (!strcmp(name, "panic")) {
1284b62e71beSChao Yu F2FS_OPTION(sbi).errors =
1285b62e71beSChao Yu MOUNT_ERRORS_PANIC;
1286b62e71beSChao Yu } else {
1287b62e71beSChao Yu kfree(name);
1288b62e71beSChao Yu return -EINVAL;
1289b62e71beSChao Yu }
1290b62e71beSChao Yu kfree(name);
1291b62e71beSChao Yu break;
1292696c018cSNamjae Jeon default:
1293dcbb4c10SJoe Perches f2fs_err(sbi, "Unrecognized mount option \"%s\" or missing value",
1294696c018cSNamjae Jeon p);
1295696c018cSNamjae Jeon return -EINVAL;
1296696c018cSNamjae Jeon }
1297696c018cSNamjae Jeon }
1298a7d9fe3cSJaegeuk Kim default_check:
12994b2414d0SChao Yu #ifdef CONFIG_QUOTA
13004b2414d0SChao Yu if (f2fs_check_quota_options(sbi))
13014b2414d0SChao Yu return -EINVAL;
130200960c2cSSheng Yong #else
13037beb01f7SChao Yu if (f2fs_sb_has_quota_ino(sbi) && !f2fs_readonly(sbi->sb)) {
1304dcbb4c10SJoe Perches f2fs_info(sbi, "Filesystem with quota feature cannot be mounted RDWR without CONFIG_QUOTA");
130500960c2cSSheng Yong return -EINVAL;
130600960c2cSSheng Yong }
13077beb01f7SChao Yu if (f2fs_sb_has_project_quota(sbi) && !f2fs_readonly(sbi->sb)) {
1308dcbb4c10SJoe Perches f2fs_err(sbi, "Filesystem with project quota feature cannot be mounted RDWR without CONFIG_QUOTA");
13094ddc1b28SChao Yu return -EINVAL;
13104ddc1b28SChao Yu }
13114b2414d0SChao Yu #endif
13125298d4bfSChristoph Hellwig #if !IS_ENABLED(CONFIG_UNICODE)
13135aba5430SDaniel Rosenberg if (f2fs_sb_has_casefold(sbi)) {
13145aba5430SDaniel Rosenberg f2fs_err(sbi,
13155aba5430SDaniel Rosenberg "Filesystem with casefold feature cannot be mounted without CONFIG_UNICODE");
13165aba5430SDaniel Rosenberg return -EINVAL;
13175aba5430SDaniel Rosenberg }
13185aba5430SDaniel Rosenberg #endif
1319d0660122SChao Yu /*
1320d0660122SChao Yu * The BLKZONED feature indicates that the drive was formatted with
1321d0660122SChao Yu * zone alignment optimization. This is optional for host-aware
1322d0660122SChao Yu * devices, but mandatory for host-managed zoned block devices.
1323d0660122SChao Yu */
1324d0660122SChao Yu if (f2fs_sb_has_blkzoned(sbi)) {
1325b5a711acSYangtao Li #ifdef CONFIG_BLK_DEV_ZONED
13264f993264SChao Yu if (F2FS_OPTION(sbi).discard_unit !=
13274f993264SChao Yu DISCARD_UNIT_SECTION) {
13284f993264SChao Yu f2fs_info(sbi, "Zoned block device doesn't need small discard, set discard_unit=section by default");
13294f993264SChao Yu F2FS_OPTION(sbi).discard_unit =
13304f993264SChao Yu DISCARD_UNIT_SECTION;
13314f993264SChao Yu }
13322bd4df8fSChunhai Guo
13332bd4df8fSChunhai Guo if (F2FS_OPTION(sbi).fs_mode != FS_MODE_LFS) {
13342bd4df8fSChunhai Guo f2fs_info(sbi, "Only lfs mode is allowed with zoned block device feature");
13352bd4df8fSChunhai Guo return -EINVAL;
13362bd4df8fSChunhai Guo }
1337b5a711acSYangtao Li #else
1338b5a711acSYangtao Li f2fs_err(sbi, "Zoned block device support is not enabled");
1339b5a711acSYangtao Li return -EINVAL;
1340b5a711acSYangtao Li #endif
13414f993264SChao Yu }
1342ec91538dSJaegeuk Kim
1343151b1982SFengnan Chang #ifdef CONFIG_F2FS_FS_COMPRESSION
1344151b1982SFengnan Chang if (f2fs_test_compress_extension(sbi)) {
1345151b1982SFengnan Chang f2fs_err(sbi, "invalid compress or nocompress extension");
1346151b1982SFengnan Chang return -EINVAL;
1347151b1982SFengnan Chang }
1348151b1982SFengnan Chang #endif
1349151b1982SFengnan Chang
13506afc662eSChao Yu if (test_opt(sbi, INLINE_XATTR_SIZE)) {
135170db5b04SJaegeuk Kim int min_size, max_size;
135270db5b04SJaegeuk Kim
13537beb01f7SChao Yu if (!f2fs_sb_has_extra_attr(sbi) ||
13547beb01f7SChao Yu !f2fs_sb_has_flexible_inline_xattr(sbi)) {
1355dcbb4c10SJoe Perches f2fs_err(sbi, "extra_attr or flexible_inline_xattr feature is off");
13564d817ae0SChao Yu return -EINVAL;
13574d817ae0SChao Yu }
13586afc662eSChao Yu if (!test_opt(sbi, INLINE_XATTR)) {
1359dcbb4c10SJoe Perches f2fs_err(sbi, "inline_xattr_size option should be set with inline_xattr option");
13606afc662eSChao Yu return -EINVAL;
13616afc662eSChao Yu }
136270db5b04SJaegeuk Kim
1363dde38c03SSheng Yong min_size = MIN_INLINE_XATTR_SIZE;
1364dd6c89b5SChao Yu max_size = MAX_INLINE_XATTR_SIZE;
136570db5b04SJaegeuk Kim
136670db5b04SJaegeuk Kim if (F2FS_OPTION(sbi).inline_xattr_size < min_size ||
136770db5b04SJaegeuk Kim F2FS_OPTION(sbi).inline_xattr_size > max_size) {
1368dcbb4c10SJoe Perches f2fs_err(sbi, "inline xattr size is out of range: %d ~ %d",
136970db5b04SJaegeuk Kim min_size, max_size);
13706afc662eSChao Yu return -EINVAL;
13716afc662eSChao Yu }
13726afc662eSChao Yu }
13730cdd3195SHyunchul Lee
1374b0332a0fSChao Yu if (test_opt(sbi, DISABLE_CHECKPOINT) && f2fs_lfs_mode(sbi)) {
1375c5bf8348SYangtao Li f2fs_err(sbi, "LFS is not compatible with checkpoint=disable");
13764354994fSDaniel Rosenberg return -EINVAL;
13774354994fSDaniel Rosenberg }
13784354994fSDaniel Rosenberg
137980dc113aSJaegeuk Kim if (test_opt(sbi, ATGC) && f2fs_lfs_mode(sbi)) {
1380c5bf8348SYangtao Li f2fs_err(sbi, "LFS is not compatible with ATGC");
138180dc113aSJaegeuk Kim return -EINVAL;
138280dc113aSJaegeuk Kim }
138380dc113aSJaegeuk Kim
1384ed8ac22bSYangtao Li if (f2fs_is_readonly(sbi) && test_opt(sbi, FLUSH_MERGE)) {
1385967eaad1SYangtao Li f2fs_err(sbi, "FLUSH_MERGE not compatible with readonly mode");
1386967eaad1SYangtao Li return -EINVAL;
1387967eaad1SYangtao Li }
1388967eaad1SYangtao Li
1389a7d9fe3cSJaegeuk Kim if (f2fs_sb_has_readonly(sbi) && !f2fs_readonly(sbi->sb)) {
1390a7d9fe3cSJaegeuk Kim f2fs_err(sbi, "Allow to mount readonly mode only");
1391a7d9fe3cSJaegeuk Kim return -EROFS;
1392a7d9fe3cSJaegeuk Kim }
1393696c018cSNamjae Jeon return 0;
1394696c018cSNamjae Jeon }
1395696c018cSNamjae Jeon
f2fs_alloc_inode(struct super_block * sb)1396aff063e2SJaegeuk Kim static struct inode *f2fs_alloc_inode(struct super_block *sb)
1397aff063e2SJaegeuk Kim {
1398aff063e2SJaegeuk Kim struct f2fs_inode_info *fi;
1399aff063e2SJaegeuk Kim
1400c40e15a9SYangtao Li if (time_to_inject(F2FS_SB(sb), FAULT_SLAB_ALLOC))
140165d3af64SMuchun Song return NULL;
140265d3af64SMuchun Song
140365d3af64SMuchun Song fi = alloc_inode_sb(sb, f2fs_inode_cachep, GFP_F2FS_ZERO);
1404aff063e2SJaegeuk Kim if (!fi)
1405aff063e2SJaegeuk Kim return NULL;
1406aff063e2SJaegeuk Kim
1407aff063e2SJaegeuk Kim init_once((void *) fi);
1408aff063e2SJaegeuk Kim
1409434720faSMasanari Iida /* Initialize f2fs-specific inode info */
1410204706c7SJaegeuk Kim atomic_set(&fi->dirty_pages, 0);
1411c2759ebaSDaeho Jeong atomic_set(&fi->i_compr_blocks, 0);
1412e4544b63STim Murray init_f2fs_rwsem(&fi->i_sem);
1413c10c9820SChao Yu spin_lock_init(&fi->i_size_lock);
14142710fd7eSChao Yu INIT_LIST_HEAD(&fi->dirty_list);
14150f18b462SJaegeuk Kim INIT_LIST_HEAD(&fi->gdirty_list);
1416e4544b63STim Murray init_f2fs_rwsem(&fi->i_gc_rwsem[READ]);
1417e4544b63STim Murray init_f2fs_rwsem(&fi->i_gc_rwsem[WRITE]);
1418e4544b63STim Murray init_f2fs_rwsem(&fi->i_xattr_sem);
1419aff063e2SJaegeuk Kim
1420ab9fa662SJaegeuk Kim /* Will be used by directory only */
1421ab9fa662SJaegeuk Kim fi->i_dir_level = F2FS_SB(sb)->dir_level;
1422f2470371SChao Yu
1423aff063e2SJaegeuk Kim return &fi->vfs_inode;
1424aff063e2SJaegeuk Kim }
1425aff063e2SJaegeuk Kim
f2fs_drop_inode(struct inode * inode)1426531ad7d5SJaegeuk Kim static int f2fs_drop_inode(struct inode *inode)
1427531ad7d5SJaegeuk Kim {
1428a8933b6bSChao Yu struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1429b8d96a30SHou Pengyang int ret;
1430a8933b6bSChao Yu
1431a8933b6bSChao Yu /*
1432a8933b6bSChao Yu * during filesystem shutdown, if checkpoint is disabled,
1433a8933b6bSChao Yu * drop useless meta/node dirty pages.
1434a8933b6bSChao Yu */
1435a8933b6bSChao Yu if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
1436a8933b6bSChao Yu if (inode->i_ino == F2FS_NODE_INO(sbi) ||
1437a8933b6bSChao Yu inode->i_ino == F2FS_META_INO(sbi)) {
1438a8933b6bSChao Yu trace_f2fs_drop_inode(inode, 1);
1439a8933b6bSChao Yu return 1;
1440a8933b6bSChao Yu }
1441a8933b6bSChao Yu }
1442a8933b6bSChao Yu
1443531ad7d5SJaegeuk Kim /*
1444531ad7d5SJaegeuk Kim * This is to avoid a deadlock condition like below.
1445531ad7d5SJaegeuk Kim * writeback_single_inode(inode)
1446531ad7d5SJaegeuk Kim * - f2fs_write_data_page
1447531ad7d5SJaegeuk Kim * - f2fs_gc -> iput -> evict
1448531ad7d5SJaegeuk Kim * - inode_wait_for_writeback(inode)
1449531ad7d5SJaegeuk Kim */
14500f18b462SJaegeuk Kim if ((!inode_unhashed(inode) && inode->i_state & I_SYNC)) {
145106e1bc05SJaegeuk Kim if (!inode->i_nlink && !is_bad_inode(inode)) {
14523e72f721SJaegeuk Kim /* to avoid evict_inode call simultaneously */
14533e72f721SJaegeuk Kim atomic_inc(&inode->i_count);
145406e1bc05SJaegeuk Kim spin_unlock(&inode->i_lock);
145506e1bc05SJaegeuk Kim
14563e72f721SJaegeuk Kim /* should remain fi->extent_tree for writepage */
14573e72f721SJaegeuk Kim f2fs_destroy_extent_node(inode);
14583e72f721SJaegeuk Kim
145906e1bc05SJaegeuk Kim sb_start_intwrite(inode->i_sb);
1460fc9581c8SJaegeuk Kim f2fs_i_size_write(inode, 0);
146106e1bc05SJaegeuk Kim
1462a0770e13Szhengliang f2fs_submit_merged_write_cond(F2FS_I_SB(inode),
1463a0770e13Szhengliang inode, NULL, 0, DATA);
1464a0770e13Szhengliang truncate_inode_pages_final(inode->i_mapping);
1465a0770e13Szhengliang
146606e1bc05SJaegeuk Kim if (F2FS_HAS_BLOCKS(inode))
14679a449e9cSJaegeuk Kim f2fs_truncate(inode);
146806e1bc05SJaegeuk Kim
146906e1bc05SJaegeuk Kim sb_end_intwrite(inode->i_sb);
147006e1bc05SJaegeuk Kim
147106e1bc05SJaegeuk Kim spin_lock(&inode->i_lock);
14723e72f721SJaegeuk Kim atomic_dec(&inode->i_count);
147306e1bc05SJaegeuk Kim }
1474b8d96a30SHou Pengyang trace_f2fs_drop_inode(inode, 0);
1475531ad7d5SJaegeuk Kim return 0;
147606e1bc05SJaegeuk Kim }
1477b8d96a30SHou Pengyang ret = generic_drop_inode(inode);
14788ce589c7SEric Biggers if (!ret)
14798ce589c7SEric Biggers ret = fscrypt_drop_inode(inode);
1480b8d96a30SHou Pengyang trace_f2fs_drop_inode(inode, ret);
1481b8d96a30SHou Pengyang return ret;
1482531ad7d5SJaegeuk Kim }
1483531ad7d5SJaegeuk Kim
f2fs_inode_dirtied(struct inode * inode,bool sync)14847c45729aSJaegeuk Kim int f2fs_inode_dirtied(struct inode *inode, bool sync)
1485b56ab837SJaegeuk Kim {
1486b56ab837SJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
14877c45729aSJaegeuk Kim int ret = 0;
1488b56ab837SJaegeuk Kim
1489b56ab837SJaegeuk Kim spin_lock(&sbi->inode_lock[DIRTY_META]);
1490b56ab837SJaegeuk Kim if (is_inode_flag_set(inode, FI_DIRTY_INODE)) {
14917c45729aSJaegeuk Kim ret = 1;
14927c45729aSJaegeuk Kim } else {
1493b56ab837SJaegeuk Kim set_inode_flag(inode, FI_DIRTY_INODE);
14947c45729aSJaegeuk Kim stat_inc_dirty_inode(sbi, DIRTY_META);
14957c45729aSJaegeuk Kim }
14967c45729aSJaegeuk Kim if (sync && list_empty(&F2FS_I(inode)->gdirty_list)) {
1497b56ab837SJaegeuk Kim list_add_tail(&F2FS_I(inode)->gdirty_list,
1498b56ab837SJaegeuk Kim &sbi->inode_list[DIRTY_META]);
1499b56ab837SJaegeuk Kim inc_page_count(sbi, F2FS_DIRTY_IMETA);
15007c45729aSJaegeuk Kim }
1501b56ab837SJaegeuk Kim spin_unlock(&sbi->inode_lock[DIRTY_META]);
15027c45729aSJaegeuk Kim return ret;
1503b56ab837SJaegeuk Kim }
1504b56ab837SJaegeuk Kim
f2fs_inode_synced(struct inode * inode)1505b56ab837SJaegeuk Kim void f2fs_inode_synced(struct inode *inode)
1506b56ab837SJaegeuk Kim {
1507b56ab837SJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1508b56ab837SJaegeuk Kim
1509b56ab837SJaegeuk Kim spin_lock(&sbi->inode_lock[DIRTY_META]);
1510b56ab837SJaegeuk Kim if (!is_inode_flag_set(inode, FI_DIRTY_INODE)) {
1511b56ab837SJaegeuk Kim spin_unlock(&sbi->inode_lock[DIRTY_META]);
1512b56ab837SJaegeuk Kim return;
1513b56ab837SJaegeuk Kim }
15147c45729aSJaegeuk Kim if (!list_empty(&F2FS_I(inode)->gdirty_list)) {
1515b56ab837SJaegeuk Kim list_del_init(&F2FS_I(inode)->gdirty_list);
15167c45729aSJaegeuk Kim dec_page_count(sbi, F2FS_DIRTY_IMETA);
15177c45729aSJaegeuk Kim }
1518b56ab837SJaegeuk Kim clear_inode_flag(inode, FI_DIRTY_INODE);
1519b56ab837SJaegeuk Kim clear_inode_flag(inode, FI_AUTO_RECOVER);
1520b56ab837SJaegeuk Kim stat_dec_dirty_inode(F2FS_I_SB(inode), DIRTY_META);
1521b56ab837SJaegeuk Kim spin_unlock(&sbi->inode_lock[DIRTY_META]);
1522b56ab837SJaegeuk Kim }
1523b56ab837SJaegeuk Kim
1524b3783873SJaegeuk Kim /*
1525b3783873SJaegeuk Kim * f2fs_dirty_inode() is called from __mark_inode_dirty()
1526b3783873SJaegeuk Kim *
1527b3783873SJaegeuk Kim * We should call set_dirty_inode to write the dirty inode through write_inode.
1528b3783873SJaegeuk Kim */
f2fs_dirty_inode(struct inode * inode,int flags)1529b3783873SJaegeuk Kim static void f2fs_dirty_inode(struct inode *inode, int flags)
1530b3783873SJaegeuk Kim {
15310f18b462SJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
15320f18b462SJaegeuk Kim
15330f18b462SJaegeuk Kim if (inode->i_ino == F2FS_NODE_INO(sbi) ||
15340f18b462SJaegeuk Kim inode->i_ino == F2FS_META_INO(sbi))
15350f18b462SJaegeuk Kim return;
15360f18b462SJaegeuk Kim
153726de9b11SJaegeuk Kim if (is_inode_flag_set(inode, FI_AUTO_RECOVER))
153826de9b11SJaegeuk Kim clear_inode_flag(inode, FI_AUTO_RECOVER);
153926de9b11SJaegeuk Kim
15407c45729aSJaegeuk Kim f2fs_inode_dirtied(inode, false);
1541b3783873SJaegeuk Kim }
1542b3783873SJaegeuk Kim
f2fs_free_inode(struct inode * inode)1543d01718a0SAl Viro static void f2fs_free_inode(struct inode *inode)
1544aff063e2SJaegeuk Kim {
15452c58d548SEric Biggers fscrypt_free_inode(inode);
1546aff063e2SJaegeuk Kim kmem_cache_free(f2fs_inode_cachep, F2FS_I(inode));
1547aff063e2SJaegeuk Kim }
1548aff063e2SJaegeuk Kim
destroy_percpu_info(struct f2fs_sb_info * sbi)1549523be8a6SJaegeuk Kim static void destroy_percpu_info(struct f2fs_sb_info *sbi)
1550523be8a6SJaegeuk Kim {
1551513c5f37SJaegeuk Kim percpu_counter_destroy(&sbi->total_valid_inode_count);
155247c8ebccSJaegeuk Kim percpu_counter_destroy(&sbi->rf_node_block_count);
155347c8ebccSJaegeuk Kim percpu_counter_destroy(&sbi->alloc_valid_block_count);
1554523be8a6SJaegeuk Kim }
1555523be8a6SJaegeuk Kim
destroy_device_list(struct f2fs_sb_info * sbi)15563c62be17SJaegeuk Kim static void destroy_device_list(struct f2fs_sb_info *sbi)
15573c62be17SJaegeuk Kim {
15583c62be17SJaegeuk Kim int i;
15593c62be17SJaegeuk Kim
15603c62be17SJaegeuk Kim for (i = 0; i < sbi->s_ndevs; i++) {
156151bf8d3cSChristoph Hellwig if (i > 0)
15622ea6f689SChristoph Hellwig blkdev_put(FDEV(i).bdev, sbi->sb);
15633c62be17SJaegeuk Kim #ifdef CONFIG_BLK_DEV_ZONED
156495175dafSDamien Le Moal kvfree(FDEV(i).blkz_seq);
15653c62be17SJaegeuk Kim #endif
15663c62be17SJaegeuk Kim }
15675222595dSJaegeuk Kim kvfree(sbi->devs);
15683c62be17SJaegeuk Kim }
15693c62be17SJaegeuk Kim
f2fs_put_super(struct super_block * sb)1570aff063e2SJaegeuk Kim static void f2fs_put_super(struct super_block *sb)
1571aff063e2SJaegeuk Kim {
1572aff063e2SJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(sb);
1573a398101aSChao Yu int i;
157420872584SChao Yu int err = 0;
1575b1c5ef26SYangtao Li bool done;
1576aff063e2SJaegeuk Kim
157799c787cfSLi Guifu /* unregister procfs/sysfs entries in advance to avoid race case */
157899c787cfSLi Guifu f2fs_unregister_sysfs(sbi);
157999c787cfSLi Guifu
15800abd675eSChao Yu f2fs_quota_off_umount(sb);
1581aff063e2SJaegeuk Kim
15822658e50dSJaegeuk Kim /* prevent remaining shrinker jobs */
15832658e50dSJaegeuk Kim mutex_lock(&sbi->umount_mutex);
15842658e50dSJaegeuk Kim
158585dc2f2cSJaegeuk Kim /*
1586261eeb9cSDaeho Jeong * flush all issued checkpoints and stop checkpoint issue thread.
1587261eeb9cSDaeho Jeong * after then, all checkpoints should be done by each process context.
1588261eeb9cSDaeho Jeong */
1589261eeb9cSDaeho Jeong f2fs_stop_ckpt_thread(sbi);
1590261eeb9cSDaeho Jeong
1591261eeb9cSDaeho Jeong /*
159285dc2f2cSJaegeuk Kim * We don't need to do checkpoint when superblock is clean.
159385dc2f2cSJaegeuk Kim * But, the previous checkpoint was not done by umount, it needs to do
159485dc2f2cSJaegeuk Kim * clean checkpoint again.
159585dc2f2cSJaegeuk Kim */
15964354994fSDaniel Rosenberg if ((is_sbi_flag_set(sbi, SBI_IS_DIRTY) ||
15974354994fSDaniel Rosenberg !is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG))) {
159875ab4cb8SJaegeuk Kim struct cp_control cpc = {
159975ab4cb8SJaegeuk Kim .reason = CP_UMOUNT,
160075ab4cb8SJaegeuk Kim };
1601eb61c2ccSChao Yu stat_inc_cp_call_count(sbi, TOTAL_CALL);
160220872584SChao Yu err = f2fs_write_checkpoint(sbi, &cpc);
160375ab4cb8SJaegeuk Kim }
1604aff063e2SJaegeuk Kim
16054e6a8d9bSJaegeuk Kim /* be sure to wait for any on-going discard commands */
1606b1c5ef26SYangtao Li done = f2fs_issue_discard_timeout(sbi);
1607b1c5ef26SYangtao Li if (f2fs_realtime_discard_enable(sbi) && !sbi->discard_blks && done) {
16081f43e2adSChao Yu struct cp_control cpc = {
16091f43e2adSChao Yu .reason = CP_UMOUNT | CP_TRIMMED,
16101f43e2adSChao Yu };
1611eb61c2ccSChao Yu stat_inc_cp_call_count(sbi, TOTAL_CALL);
161220872584SChao Yu err = f2fs_write_checkpoint(sbi, &cpc);
16131f43e2adSChao Yu }
16141f43e2adSChao Yu
1615cf779cabSJaegeuk Kim /*
1616cf779cabSJaegeuk Kim * normally superblock is clean, so we need to release this.
1617cf779cabSJaegeuk Kim * In addition, EIO will skip do checkpoint, we need this as well.
1618cf779cabSJaegeuk Kim */
16194d57b86dSChao Yu f2fs_release_ino_entry(sbi, true);
16206f12ac25SJaegeuk Kim
16212658e50dSJaegeuk Kim f2fs_leave_shrinker(sbi);
16222658e50dSJaegeuk Kim mutex_unlock(&sbi->umount_mutex);
16232658e50dSJaegeuk Kim
162417c19120SJaegeuk Kim /* our cp_error case, we can wait for any writeback page */
1625b9109b0eSJaegeuk Kim f2fs_flush_merged_writes(sbi);
162617c19120SJaegeuk Kim
1627bf22c3ccSSahitya Tummala f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA);
162850fa53ecSChao Yu
162910b2a6c0SChao Yu if (err || f2fs_cp_error(sbi)) {
163020872584SChao Yu truncate_inode_pages_final(NODE_MAPPING(sbi));
163120872584SChao Yu truncate_inode_pages_final(META_MAPPING(sbi));
163220872584SChao Yu }
163320872584SChao Yu
163420872584SChao Yu for (i = 0; i < NR_COUNT_TYPE; i++) {
163520872584SChao Yu if (!get_pages(sbi, i))
163620872584SChao Yu continue;
163720872584SChao Yu f2fs_err(sbi, "detect filesystem reference count leak during "
163820872584SChao Yu "umount, type: %d, count: %lld", i, get_pages(sbi, i));
163920872584SChao Yu f2fs_bug_on(sbi, 1);
164020872584SChao Yu }
164120872584SChao Yu
164250fa53ecSChao Yu f2fs_bug_on(sbi, sbi->fsync_node_num);
164350fa53ecSChao Yu
16446ce19affSChao Yu f2fs_destroy_compress_inode(sbi);
16456ce19affSChao Yu
1646aff063e2SJaegeuk Kim iput(sbi->node_inode);
16477c77bf7dSJaegeuk Kim sbi->node_inode = NULL;
16487c77bf7dSJaegeuk Kim
1649aff063e2SJaegeuk Kim iput(sbi->meta_inode);
16507c77bf7dSJaegeuk Kim sbi->meta_inode = NULL;
1651aff063e2SJaegeuk Kim
165260aa4d55SSahitya Tummala /*
165360aa4d55SSahitya Tummala * iput() can update stat information, if f2fs_write_checkpoint()
165460aa4d55SSahitya Tummala * above failed with error.
165560aa4d55SSahitya Tummala */
165660aa4d55SSahitya Tummala f2fs_destroy_stats(sbi);
165760aa4d55SSahitya Tummala
1658aff063e2SJaegeuk Kim /* destroy f2fs internal modules */
16594d57b86dSChao Yu f2fs_destroy_node_manager(sbi);
16604d57b86dSChao Yu f2fs_destroy_segment_manager(sbi);
1661aff063e2SJaegeuk Kim
1662b62e71beSChao Yu /* flush s_error_work before sbi destroy */
1663b62e71beSChao Yu flush_work(&sbi->s_error_work);
1664b62e71beSChao Yu
16654c8ff709SChao Yu f2fs_destroy_post_read_wq(sbi);
16664c8ff709SChao Yu
16675222595dSJaegeuk Kim kvfree(sbi->ckpt);
1668a398101aSChao Yu
1669aff063e2SJaegeuk Kim sb->s_fs_info = NULL;
167043b6573bSKeith Mok if (sbi->s_chksum_driver)
167143b6573bSKeith Mok crypto_free_shash(sbi->s_chksum_driver);
1672742532d1SDenis Efremov kfree(sbi->raw_super);
1673523be8a6SJaegeuk Kim
16743c62be17SJaegeuk Kim destroy_device_list(sbi);
167531083031SChao Yu f2fs_destroy_page_array_cache(sbi);
1676a999150fSChao Yu f2fs_destroy_xattr_caches(sbi);
16774b2414d0SChao Yu #ifdef CONFIG_QUOTA
16784b2414d0SChao Yu for (i = 0; i < MAXQUOTAS; i++)
1679ba87a45cSWang Xiaojun kfree(F2FS_OPTION(sbi).s_qf_names[i]);
16804b2414d0SChao Yu #endif
1681ac4acb1fSEric Biggers fscrypt_free_dummy_policy(&F2FS_OPTION(sbi).dummy_enc_policy);
1682523be8a6SJaegeuk Kim destroy_percpu_info(sbi);
1683a4b68176SDaeho Jeong f2fs_destroy_iostat(sbi);
1684a912b54dSJaegeuk Kim for (i = 0; i < NR_PAGE_TYPE; i++)
16855222595dSJaegeuk Kim kvfree(sbi->write_io[i]);
16865298d4bfSChristoph Hellwig #if IS_ENABLED(CONFIG_UNICODE)
1687eca4873eSDaniel Rosenberg utf8_unload(sb->s_encoding);
16885aba5430SDaniel Rosenberg #endif
1689742532d1SDenis Efremov kfree(sbi);
1690aff063e2SJaegeuk Kim }
1691aff063e2SJaegeuk Kim
f2fs_sync_fs(struct super_block * sb,int sync)1692aff063e2SJaegeuk Kim int f2fs_sync_fs(struct super_block *sb, int sync)
1693aff063e2SJaegeuk Kim {
1694aff063e2SJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(sb);
1695c34f42e2SChao Yu int err = 0;
1696aff063e2SJaegeuk Kim
16971f227a3eSJaegeuk Kim if (unlikely(f2fs_cp_error(sbi)))
16981f227a3eSJaegeuk Kim return 0;
16994354994fSDaniel Rosenberg if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
17004354994fSDaniel Rosenberg return 0;
17011f227a3eSJaegeuk Kim
1702a2a4a7e4SNamjae Jeon trace_f2fs_sync_fs(sb, sync);
1703a2a4a7e4SNamjae Jeon
17044b2414d0SChao Yu if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
17054b2414d0SChao Yu return -EAGAIN;
17064b2414d0SChao Yu
1707eb61c2ccSChao Yu if (sync) {
1708eb61c2ccSChao Yu stat_inc_cp_call_count(sbi, TOTAL_CALL);
1709261eeb9cSDaeho Jeong err = f2fs_issue_checkpoint(sbi);
1710eb61c2ccSChao Yu }
1711d5053a34SJaegeuk Kim
1712c34f42e2SChao Yu return err;
1713aff063e2SJaegeuk Kim }
1714aff063e2SJaegeuk Kim
f2fs_freeze(struct super_block * sb)1715d6212a5fSChangman Lee static int f2fs_freeze(struct super_block *sb)
1716d6212a5fSChangman Lee {
171777888c1eSJaegeuk Kim if (f2fs_readonly(sb))
1718d6212a5fSChangman Lee return 0;
1719d6212a5fSChangman Lee
1720b4b9d34cSJaegeuk Kim /* IO error happened before */
1721b4b9d34cSJaegeuk Kim if (unlikely(f2fs_cp_error(F2FS_SB(sb))))
1722b4b9d34cSJaegeuk Kim return -EIO;
1723b4b9d34cSJaegeuk Kim
1724b4b9d34cSJaegeuk Kim /* must be clean, since sync_filesystem() was already called */
1725b4b9d34cSJaegeuk Kim if (is_sbi_flag_set(F2FS_SB(sb), SBI_IS_DIRTY))
1726b4b9d34cSJaegeuk Kim return -EINVAL;
1727d50dfc0cSJaegeuk Kim
1728c7b58576SJaegeuk Kim /* Let's flush checkpoints and stop the thread. */
1729c7b58576SJaegeuk Kim f2fs_flush_ckpt_thread(F2FS_SB(sb));
1730ba900534SJaegeuk Kim
1731ba900534SJaegeuk Kim /* to avoid deadlock on f2fs_evict_inode->SB_FREEZE_FS */
1732ba900534SJaegeuk Kim set_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING);
1733b4b9d34cSJaegeuk Kim return 0;
1734d6212a5fSChangman Lee }
1735d6212a5fSChangman Lee
f2fs_unfreeze(struct super_block * sb)1736d6212a5fSChangman Lee static int f2fs_unfreeze(struct super_block *sb)
1737d6212a5fSChangman Lee {
1738ed24ab98SChao Yu struct f2fs_sb_info *sbi = F2FS_SB(sb);
1739ed24ab98SChao Yu
1740ed24ab98SChao Yu /*
1741ed24ab98SChao Yu * It will update discard_max_bytes of mounted lvm device to zero
1742ed24ab98SChao Yu * after creating snapshot on this lvm device, let's drop all
1743ed24ab98SChao Yu * remained discards.
1744ed24ab98SChao Yu * We don't need to disable real-time discard because discard_max_bytes
1745ed24ab98SChao Yu * will recover after removal of snapshot.
1746ed24ab98SChao Yu */
1747ed24ab98SChao Yu if (test_opt(sbi, DISCARD) && !f2fs_hw_support_discard(sbi))
1748ed24ab98SChao Yu f2fs_issue_discard_timeout(sbi);
1749ed24ab98SChao Yu
1750ba900534SJaegeuk Kim clear_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING);
1751d6212a5fSChangman Lee return 0;
1752d6212a5fSChangman Lee }
1753d6212a5fSChangman Lee
1754ddc34e32SChao Yu #ifdef CONFIG_QUOTA
f2fs_statfs_project(struct super_block * sb,kprojid_t projid,struct kstatfs * buf)1755ddc34e32SChao Yu static int f2fs_statfs_project(struct super_block *sb,
1756ddc34e32SChao Yu kprojid_t projid, struct kstatfs *buf)
1757ddc34e32SChao Yu {
1758ddc34e32SChao Yu struct kqid qid;
1759ddc34e32SChao Yu struct dquot *dquot;
1760ddc34e32SChao Yu u64 limit;
1761ddc34e32SChao Yu u64 curblock;
1762ddc34e32SChao Yu
1763ddc34e32SChao Yu qid = make_kqid_projid(projid);
1764ddc34e32SChao Yu dquot = dqget(sb, qid);
1765ddc34e32SChao Yu if (IS_ERR(dquot))
1766ddc34e32SChao Yu return PTR_ERR(dquot);
1767955ac6e5SSheng Yong spin_lock(&dquot->dq_dqb_lock);
1768ddc34e32SChao Yu
1769bf2cbd3cSChengguang Xu limit = min_not_zero(dquot->dq_dqb.dqb_bsoftlimit,
1770bf2cbd3cSChengguang Xu dquot->dq_dqb.dqb_bhardlimit);
1771acdf2172SChengguang Xu if (limit)
1772acdf2172SChengguang Xu limit >>= sb->s_blocksize_bits;
1773909110c0SChengguang Xu
1774ddc34e32SChao Yu if (limit && buf->f_blocks > limit) {
1775baaa7ebfSKonstantin Khlebnikov curblock = (dquot->dq_dqb.dqb_curspace +
1776baaa7ebfSKonstantin Khlebnikov dquot->dq_dqb.dqb_rsvspace) >> sb->s_blocksize_bits;
1777ddc34e32SChao Yu buf->f_blocks = limit;
1778ddc34e32SChao Yu buf->f_bfree = buf->f_bavail =
1779ddc34e32SChao Yu (buf->f_blocks > curblock) ?
1780ddc34e32SChao Yu (buf->f_blocks - curblock) : 0;
1781ddc34e32SChao Yu }
1782ddc34e32SChao Yu
1783bf2cbd3cSChengguang Xu limit = min_not_zero(dquot->dq_dqb.dqb_isoftlimit,
1784bf2cbd3cSChengguang Xu dquot->dq_dqb.dqb_ihardlimit);
1785909110c0SChengguang Xu
1786ddc34e32SChao Yu if (limit && buf->f_files > limit) {
1787ddc34e32SChao Yu buf->f_files = limit;
1788ddc34e32SChao Yu buf->f_ffree =
1789ddc34e32SChao Yu (buf->f_files > dquot->dq_dqb.dqb_curinodes) ?
1790ddc34e32SChao Yu (buf->f_files - dquot->dq_dqb.dqb_curinodes) : 0;
1791ddc34e32SChao Yu }
1792ddc34e32SChao Yu
1793955ac6e5SSheng Yong spin_unlock(&dquot->dq_dqb_lock);
1794ddc34e32SChao Yu dqput(dquot);
1795ddc34e32SChao Yu return 0;
1796ddc34e32SChao Yu }
1797ddc34e32SChao Yu #endif
1798ddc34e32SChao Yu
f2fs_statfs(struct dentry * dentry,struct kstatfs * buf)1799aff063e2SJaegeuk Kim static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
1800aff063e2SJaegeuk Kim {
1801aff063e2SJaegeuk Kim struct super_block *sb = dentry->d_sb;
1802aff063e2SJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(sb);
1803aff063e2SJaegeuk Kim u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
1804f66c027eSJaegeuk Kim block_t total_count, user_block_count, start_count;
18050cc091d0SJaegeuk Kim u64 avail_node_count;
18064de85145SNiels Dossche unsigned int total_valid_node_count;
1807aff063e2SJaegeuk Kim
1808aff063e2SJaegeuk Kim total_count = le64_to_cpu(sbi->raw_super->block_count);
1809aff063e2SJaegeuk Kim start_count = le32_to_cpu(sbi->raw_super->segment0_blkaddr);
1810aff063e2SJaegeuk Kim buf->f_type = F2FS_SUPER_MAGIC;
1811aff063e2SJaegeuk Kim buf->f_bsize = sbi->blocksize;
1812aff063e2SJaegeuk Kim
1813aff063e2SJaegeuk Kim buf->f_blocks = total_count - start_count;
18144de85145SNiels Dossche
18154de85145SNiels Dossche spin_lock(&sbi->stat_lock);
18164de85145SNiels Dossche
18174de85145SNiels Dossche user_block_count = sbi->user_block_count;
18184de85145SNiels Dossche total_valid_node_count = valid_node_count(sbi);
18194de85145SNiels Dossche avail_node_count = sbi->total_node_count - F2FS_RESERVED_NODE_NUM;
1820f66c027eSJaegeuk Kim buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
182180d42145SYunlong Song sbi->current_reserved_blocks;
1822c9c8ed50SChao Yu
18234354994fSDaniel Rosenberg if (unlikely(buf->f_bfree <= sbi->unusable_block_count))
18244354994fSDaniel Rosenberg buf->f_bfree = 0;
18254354994fSDaniel Rosenberg else
18264354994fSDaniel Rosenberg buf->f_bfree -= sbi->unusable_block_count;
1827c9c8ed50SChao Yu spin_unlock(&sbi->stat_lock);
18284354994fSDaniel Rosenberg
182963189b78SChao Yu if (buf->f_bfree > F2FS_OPTION(sbi).root_reserved_blocks)
183063189b78SChao Yu buf->f_bavail = buf->f_bfree -
183163189b78SChao Yu F2FS_OPTION(sbi).root_reserved_blocks;
18327e65be49SJaegeuk Kim else
18337e65be49SJaegeuk Kim buf->f_bavail = 0;
1834aff063e2SJaegeuk Kim
18350cc091d0SJaegeuk Kim if (avail_node_count > user_block_count) {
18360cc091d0SJaegeuk Kim buf->f_files = user_block_count;
18370cc091d0SJaegeuk Kim buf->f_ffree = buf->f_bavail;
18380cc091d0SJaegeuk Kim } else {
18390cc091d0SJaegeuk Kim buf->f_files = avail_node_count;
18404de85145SNiels Dossche buf->f_ffree = min(avail_node_count - total_valid_node_count,
1841b08b12d2SChao Yu buf->f_bavail);
18420cc091d0SJaegeuk Kim }
1843aff063e2SJaegeuk Kim
18445a20d339SJaegeuk Kim buf->f_namelen = F2FS_NAME_LEN;
18456d1349c7SAl Viro buf->f_fsid = u64_to_fsid(id);
1846aff063e2SJaegeuk Kim
1847ddc34e32SChao Yu #ifdef CONFIG_QUOTA
1848ddc34e32SChao Yu if (is_inode_flag_set(dentry->d_inode, FI_PROJ_INHERIT) &&
1849ddc34e32SChao Yu sb_has_quota_limits_enabled(sb, PRJQUOTA)) {
1850ddc34e32SChao Yu f2fs_statfs_project(sb, F2FS_I(dentry->d_inode)->i_projid, buf);
1851ddc34e32SChao Yu }
1852ddc34e32SChao Yu #endif
1853aff063e2SJaegeuk Kim return 0;
1854aff063e2SJaegeuk Kim }
1855aff063e2SJaegeuk Kim
f2fs_show_quota_options(struct seq_file * seq,struct super_block * sb)18564b2414d0SChao Yu static inline void f2fs_show_quota_options(struct seq_file *seq,
18574b2414d0SChao Yu struct super_block *sb)
18584b2414d0SChao Yu {
18594b2414d0SChao Yu #ifdef CONFIG_QUOTA
18604b2414d0SChao Yu struct f2fs_sb_info *sbi = F2FS_SB(sb);
18614b2414d0SChao Yu
186263189b78SChao Yu if (F2FS_OPTION(sbi).s_jquota_fmt) {
18634b2414d0SChao Yu char *fmtname = "";
18644b2414d0SChao Yu
186563189b78SChao Yu switch (F2FS_OPTION(sbi).s_jquota_fmt) {
18664b2414d0SChao Yu case QFMT_VFS_OLD:
18674b2414d0SChao Yu fmtname = "vfsold";
18684b2414d0SChao Yu break;
18694b2414d0SChao Yu case QFMT_VFS_V0:
18704b2414d0SChao Yu fmtname = "vfsv0";
18714b2414d0SChao Yu break;
18724b2414d0SChao Yu case QFMT_VFS_V1:
18734b2414d0SChao Yu fmtname = "vfsv1";
18744b2414d0SChao Yu break;
18754b2414d0SChao Yu }
18764b2414d0SChao Yu seq_printf(seq, ",jqfmt=%s", fmtname);
18774b2414d0SChao Yu }
18784b2414d0SChao Yu
187963189b78SChao Yu if (F2FS_OPTION(sbi).s_qf_names[USRQUOTA])
188063189b78SChao Yu seq_show_option(seq, "usrjquota",
188163189b78SChao Yu F2FS_OPTION(sbi).s_qf_names[USRQUOTA]);
18824b2414d0SChao Yu
188363189b78SChao Yu if (F2FS_OPTION(sbi).s_qf_names[GRPQUOTA])
188463189b78SChao Yu seq_show_option(seq, "grpjquota",
188563189b78SChao Yu F2FS_OPTION(sbi).s_qf_names[GRPQUOTA]);
18864b2414d0SChao Yu
188763189b78SChao Yu if (F2FS_OPTION(sbi).s_qf_names[PRJQUOTA])
188863189b78SChao Yu seq_show_option(seq, "prjjquota",
188963189b78SChao Yu F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]);
18904b2414d0SChao Yu #endif
18914b2414d0SChao Yu }
18924b2414d0SChao Yu
1893cd6ee739SChao Yu #ifdef CONFIG_F2FS_FS_COMPRESSION
f2fs_show_compress_options(struct seq_file * seq,struct super_block * sb)18944c8ff709SChao Yu static inline void f2fs_show_compress_options(struct seq_file *seq,
18954c8ff709SChao Yu struct super_block *sb)
18964c8ff709SChao Yu {
18974c8ff709SChao Yu struct f2fs_sb_info *sbi = F2FS_SB(sb);
18984c8ff709SChao Yu char *algtype = "";
18994c8ff709SChao Yu int i;
19004c8ff709SChao Yu
19014c8ff709SChao Yu if (!f2fs_sb_has_compression(sbi))
19024c8ff709SChao Yu return;
19034c8ff709SChao Yu
19044c8ff709SChao Yu switch (F2FS_OPTION(sbi).compress_algorithm) {
19054c8ff709SChao Yu case COMPRESS_LZO:
19064c8ff709SChao Yu algtype = "lzo";
19074c8ff709SChao Yu break;
19084c8ff709SChao Yu case COMPRESS_LZ4:
19094c8ff709SChao Yu algtype = "lz4";
19104c8ff709SChao Yu break;
191150cfa66fSChao Yu case COMPRESS_ZSTD:
191250cfa66fSChao Yu algtype = "zstd";
191350cfa66fSChao Yu break;
19146d92b201SChao Yu case COMPRESS_LZORLE:
19156d92b201SChao Yu algtype = "lzo-rle";
19166d92b201SChao Yu break;
19174c8ff709SChao Yu }
19184c8ff709SChao Yu seq_printf(seq, ",compress_algorithm=%s", algtype);
19194c8ff709SChao Yu
19203fde13f8SChao Yu if (F2FS_OPTION(sbi).compress_level)
19213fde13f8SChao Yu seq_printf(seq, ":%d", F2FS_OPTION(sbi).compress_level);
19223fde13f8SChao Yu
19234c8ff709SChao Yu seq_printf(seq, ",compress_log_size=%u",
19244c8ff709SChao Yu F2FS_OPTION(sbi).compress_log_size);
19254c8ff709SChao Yu
19264c8ff709SChao Yu for (i = 0; i < F2FS_OPTION(sbi).compress_ext_cnt; i++) {
19274c8ff709SChao Yu seq_printf(seq, ",compress_extension=%s",
19284c8ff709SChao Yu F2FS_OPTION(sbi).extensions[i]);
19294c8ff709SChao Yu }
1930b28f047bSChao Yu
1931151b1982SFengnan Chang for (i = 0; i < F2FS_OPTION(sbi).nocompress_ext_cnt; i++) {
1932151b1982SFengnan Chang seq_printf(seq, ",nocompress_extension=%s",
1933151b1982SFengnan Chang F2FS_OPTION(sbi).noextensions[i]);
1934151b1982SFengnan Chang }
1935151b1982SFengnan Chang
1936b28f047bSChao Yu if (F2FS_OPTION(sbi).compress_chksum)
1937b28f047bSChao Yu seq_puts(seq, ",compress_chksum");
1938602a16d5SDaeho Jeong
1939602a16d5SDaeho Jeong if (F2FS_OPTION(sbi).compress_mode == COMPR_MODE_FS)
1940602a16d5SDaeho Jeong seq_printf(seq, ",compress_mode=%s", "fs");
1941602a16d5SDaeho Jeong else if (F2FS_OPTION(sbi).compress_mode == COMPR_MODE_USER)
1942602a16d5SDaeho Jeong seq_printf(seq, ",compress_mode=%s", "user");
19436ce19affSChao Yu
19446ce19affSChao Yu if (test_opt(sbi, COMPRESS_CACHE))
19456ce19affSChao Yu seq_puts(seq, ",compress_cache");
19464c8ff709SChao Yu }
1947cd6ee739SChao Yu #endif
19484c8ff709SChao Yu
f2fs_show_options(struct seq_file * seq,struct dentry * root)1949aff063e2SJaegeuk Kim static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
1950aff063e2SJaegeuk Kim {
1951aff063e2SJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb);
1952aff063e2SJaegeuk Kim
1953bbbc34fdSChao Yu if (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_SYNC)
19546aefd93bSJaegeuk Kim seq_printf(seq, ",background_gc=%s", "sync");
1955bbbc34fdSChao Yu else if (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_ON)
19566aefd93bSJaegeuk Kim seq_printf(seq, ",background_gc=%s", "on");
1957bbbc34fdSChao Yu else if (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_OFF)
1958696c018cSNamjae Jeon seq_printf(seq, ",background_gc=%s", "off");
1959bbbc34fdSChao Yu
19605911d2d1SChao Yu if (test_opt(sbi, GC_MERGE))
19615911d2d1SChao Yu seq_puts(seq, ",gc_merge");
196204d7a7aeSYangtao Li else
196304d7a7aeSYangtao Li seq_puts(seq, ",nogc_merge");
19645911d2d1SChao Yu
1965aff063e2SJaegeuk Kim if (test_opt(sbi, DISABLE_ROLL_FORWARD))
1966aff063e2SJaegeuk Kim seq_puts(seq, ",disable_roll_forward");
1967a9117ecaSChao Yu if (test_opt(sbi, NORECOVERY))
1968a9117ecaSChao Yu seq_puts(seq, ",norecovery");
19692381a685SYangtao Li if (test_opt(sbi, DISCARD)) {
1970aff063e2SJaegeuk Kim seq_puts(seq, ",discard");
19712381a685SYangtao Li if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_BLOCK)
19722381a685SYangtao Li seq_printf(seq, ",discard_unit=%s", "block");
19732381a685SYangtao Li else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SEGMENT)
19742381a685SYangtao Li seq_printf(seq, ",discard_unit=%s", "segment");
19752381a685SYangtao Li else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SECTION)
19762381a685SYangtao Li seq_printf(seq, ",discard_unit=%s", "section");
19772381a685SYangtao Li } else {
197881621f97SSahitya Tummala seq_puts(seq, ",nodiscard");
19792381a685SYangtao Li }
1980aff063e2SJaegeuk Kim #ifdef CONFIG_F2FS_FS_XATTR
1981aff063e2SJaegeuk Kim if (test_opt(sbi, XATTR_USER))
1982aff063e2SJaegeuk Kim seq_puts(seq, ",user_xattr");
1983aff063e2SJaegeuk Kim else
1984aff063e2SJaegeuk Kim seq_puts(seq, ",nouser_xattr");
1985444c580fSJaegeuk Kim if (test_opt(sbi, INLINE_XATTR))
1986444c580fSJaegeuk Kim seq_puts(seq, ",inline_xattr");
198723cf7212SChao Yu else
198823cf7212SChao Yu seq_puts(seq, ",noinline_xattr");
19896afc662eSChao Yu if (test_opt(sbi, INLINE_XATTR_SIZE))
19906afc662eSChao Yu seq_printf(seq, ",inline_xattr_size=%u",
199163189b78SChao Yu F2FS_OPTION(sbi).inline_xattr_size);
1992aff063e2SJaegeuk Kim #endif
1993aff063e2SJaegeuk Kim #ifdef CONFIG_F2FS_FS_POSIX_ACL
1994aff063e2SJaegeuk Kim if (test_opt(sbi, POSIX_ACL))
1995aff063e2SJaegeuk Kim seq_puts(seq, ",acl");
1996aff063e2SJaegeuk Kim else
1997aff063e2SJaegeuk Kim seq_puts(seq, ",noacl");
1998aff063e2SJaegeuk Kim #endif
1999aff063e2SJaegeuk Kim if (test_opt(sbi, DISABLE_EXT_IDENTIFY))
2000aa43507fSAlejandro Martinez Ruiz seq_puts(seq, ",disable_ext_identify");
20018274de77SHuajun Li if (test_opt(sbi, INLINE_DATA))
20028274de77SHuajun Li seq_puts(seq, ",inline_data");
200375342797SWanpeng Li else
200475342797SWanpeng Li seq_puts(seq, ",noinline_data");
20055efd3c6fSChao Yu if (test_opt(sbi, INLINE_DENTRY))
20065efd3c6fSChao Yu seq_puts(seq, ",inline_dentry");
200797c1794aSChao Yu else
200897c1794aSChao Yu seq_puts(seq, ",noinline_dentry");
2009967eaad1SYangtao Li if (test_opt(sbi, FLUSH_MERGE))
20106b4afdd7SJaegeuk Kim seq_puts(seq, ",flush_merge");
2011967eaad1SYangtao Li else
2012967eaad1SYangtao Li seq_puts(seq, ",noflush_merge");
20130f7b2abdSJaegeuk Kim if (test_opt(sbi, NOBARRIER))
20140f7b2abdSJaegeuk Kim seq_puts(seq, ",nobarrier");
20156047de54SYangtao Li else
20166047de54SYangtao Li seq_puts(seq, ",barrier");
2017d5053a34SJaegeuk Kim if (test_opt(sbi, FASTBOOT))
2018d5053a34SJaegeuk Kim seq_puts(seq, ",fastboot");
201912607c1bSJaegeuk Kim if (test_opt(sbi, READ_EXTENT_CACHE))
202089672159SChao Yu seq_puts(seq, ",extent_cache");
20217daaea25SJaegeuk Kim else
20227daaea25SJaegeuk Kim seq_puts(seq, ",noextent_cache");
202371644dffSJaegeuk Kim if (test_opt(sbi, AGE_EXTENT_CACHE))
202471644dffSJaegeuk Kim seq_puts(seq, ",age_extent_cache");
2025343f40f0SChao Yu if (test_opt(sbi, DATA_FLUSH))
2026343f40f0SChao Yu seq_puts(seq, ",data_flush");
202736abef4eSJaegeuk Kim
202836abef4eSJaegeuk Kim seq_puts(seq, ",mode=");
2029b0332a0fSChao Yu if (F2FS_OPTION(sbi).fs_mode == FS_MODE_ADAPTIVE)
203036abef4eSJaegeuk Kim seq_puts(seq, "adaptive");
2031b0332a0fSChao Yu else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS)
203236abef4eSJaegeuk Kim seq_puts(seq, "lfs");
20336691d940SDaeho Jeong else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_SEG)
20346691d940SDaeho Jeong seq_puts(seq, "fragment:segment");
20356691d940SDaeho Jeong else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK)
20366691d940SDaeho Jeong seq_puts(seq, "fragment:block");
203763189b78SChao Yu seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs);
20387e65be49SJaegeuk Kim if (test_opt(sbi, RESERVE_ROOT))
20397c2e5963SJaegeuk Kim seq_printf(seq, ",reserve_root=%u,resuid=%u,resgid=%u",
204063189b78SChao Yu F2FS_OPTION(sbi).root_reserved_blocks,
204163189b78SChao Yu from_kuid_munged(&init_user_ns,
204263189b78SChao Yu F2FS_OPTION(sbi).s_resuid),
204363189b78SChao Yu from_kgid_munged(&init_user_ns,
204463189b78SChao Yu F2FS_OPTION(sbi).s_resgid));
20450cc0dec2SKaixu Xia #ifdef CONFIG_F2FS_FAULT_INJECTION
2046d494500aSChao Yu if (test_opt(sbi, FAULT_INJECTION)) {
204744529f89SChao Yu seq_printf(seq, ",fault_injection=%u",
204863189b78SChao Yu F2FS_OPTION(sbi).fault_info.inject_rate);
2049d494500aSChao Yu seq_printf(seq, ",fault_type=%u",
2050d494500aSChao Yu F2FS_OPTION(sbi).fault_info.inject_type);
2051d494500aSChao Yu }
20520cc0dec2SKaixu Xia #endif
20530abd675eSChao Yu #ifdef CONFIG_QUOTA
20544b2414d0SChao Yu if (test_opt(sbi, QUOTA))
20554b2414d0SChao Yu seq_puts(seq, ",quota");
20560abd675eSChao Yu if (test_opt(sbi, USRQUOTA))
20570abd675eSChao Yu seq_puts(seq, ",usrquota");
20580abd675eSChao Yu if (test_opt(sbi, GRPQUOTA))
20590abd675eSChao Yu seq_puts(seq, ",grpquota");
20605c57132eSChao Yu if (test_opt(sbi, PRJQUOTA))
20615c57132eSChao Yu seq_puts(seq, ",prjquota");
2062aff063e2SJaegeuk Kim #endif
20634b2414d0SChao Yu f2fs_show_quota_options(seq, sbi->sb);
2064ed318a6cSEric Biggers
2065ed318a6cSEric Biggers fscrypt_show_test_dummy_encryption(seq, ',', sbi->sb);
2066aff063e2SJaegeuk Kim
206727aacd28SSatya Tangirala if (sbi->sb->s_flags & SB_INLINECRYPT)
206827aacd28SSatya Tangirala seq_puts(seq, ",inlinecrypt");
206927aacd28SSatya Tangirala
207063189b78SChao Yu if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_DEFAULT)
207107939627SJaegeuk Kim seq_printf(seq, ",alloc_mode=%s", "default");
207263189b78SChao Yu else if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_REUSE)
207307939627SJaegeuk Kim seq_printf(seq, ",alloc_mode=%s", "reuse");
207493cf93f1SJunling Zheng
20754354994fSDaniel Rosenberg if (test_opt(sbi, DISABLE_CHECKPOINT))
20764d3aed70SDaniel Rosenberg seq_printf(seq, ",checkpoint=disable:%u",
20774d3aed70SDaniel Rosenberg F2FS_OPTION(sbi).unusable_cap);
2078261eeb9cSDaeho Jeong if (test_opt(sbi, MERGE_CHECKPOINT))
2079261eeb9cSDaeho Jeong seq_puts(seq, ",checkpoint_merge");
2080261eeb9cSDaeho Jeong else
2081261eeb9cSDaeho Jeong seq_puts(seq, ",nocheckpoint_merge");
208263189b78SChao Yu if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_POSIX)
208393cf93f1SJunling Zheng seq_printf(seq, ",fsync_mode=%s", "posix");
208463189b78SChao Yu else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT)
208593cf93f1SJunling Zheng seq_printf(seq, ",fsync_mode=%s", "strict");
2086dc132802SSahitya Tummala else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_NOBARRIER)
2087dc132802SSahitya Tummala seq_printf(seq, ",fsync_mode=%s", "nobarrier");
20884c8ff709SChao Yu
20891f0b067bSChao Yu #ifdef CONFIG_F2FS_FS_COMPRESSION
20904c8ff709SChao Yu f2fs_show_compress_options(seq, sbi->sb);
20911f0b067bSChao Yu #endif
2092093749e2SChao Yu
2093093749e2SChao Yu if (test_opt(sbi, ATGC))
2094093749e2SChao Yu seq_puts(seq, ",atgc");
20954f993264SChao Yu
20967a8fc586SDaeho Jeong if (F2FS_OPTION(sbi).memory_mode == MEMORY_MODE_NORMAL)
20977a8fc586SDaeho Jeong seq_printf(seq, ",memory=%s", "normal");
20987a8fc586SDaeho Jeong else if (F2FS_OPTION(sbi).memory_mode == MEMORY_MODE_LOW)
20997a8fc586SDaeho Jeong seq_printf(seq, ",memory=%s", "low");
21007a8fc586SDaeho Jeong
2101b62e71beSChao Yu if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_READONLY)
2102b62e71beSChao Yu seq_printf(seq, ",errors=%s", "remount-ro");
2103b62e71beSChao Yu else if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_CONTINUE)
2104b62e71beSChao Yu seq_printf(seq, ",errors=%s", "continue");
2105b62e71beSChao Yu else if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_PANIC)
2106b62e71beSChao Yu seq_printf(seq, ",errors=%s", "panic");
2107b62e71beSChao Yu
2108aff063e2SJaegeuk Kim return 0;
2109aff063e2SJaegeuk Kim }
2110aff063e2SJaegeuk Kim
default_options(struct f2fs_sb_info * sbi,bool remount)2111458c15dfSChao Yu static void default_options(struct f2fs_sb_info *sbi, bool remount)
2112498c5e9fSYunlei He {
2113498c5e9fSYunlei He /* init some FS parameters */
2114458c15dfSChao Yu if (!remount) {
2115458c15dfSChao Yu set_opt(sbi, READ_EXTENT_CACHE);
2116458c15dfSChao Yu clear_opt(sbi, DISABLE_CHECKPOINT);
2117458c15dfSChao Yu
2118458c15dfSChao Yu if (f2fs_hw_support_discard(sbi) || f2fs_hw_should_discard(sbi))
2119458c15dfSChao Yu set_opt(sbi, DISCARD);
2120458c15dfSChao Yu
2121458c15dfSChao Yu if (f2fs_sb_has_blkzoned(sbi))
2122458c15dfSChao Yu F2FS_OPTION(sbi).discard_unit = DISCARD_UNIT_SECTION;
2123458c15dfSChao Yu else
2124458c15dfSChao Yu F2FS_OPTION(sbi).discard_unit = DISCARD_UNIT_BLOCK;
2125458c15dfSChao Yu }
2126458c15dfSChao Yu
2127a7d9fe3cSJaegeuk Kim if (f2fs_sb_has_readonly(sbi))
2128a7d9fe3cSJaegeuk Kim F2FS_OPTION(sbi).active_logs = NR_CURSEG_RO_TYPE;
2129a7d9fe3cSJaegeuk Kim else
2130d0b9e42aSChao Yu F2FS_OPTION(sbi).active_logs = NR_CURSEG_PERSIST_TYPE;
2131a7d9fe3cSJaegeuk Kim
213263189b78SChao Yu F2FS_OPTION(sbi).inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
2133b7ad23ceSYuwei Guan if (le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count_main) <=
2134b7ad23ceSYuwei Guan SMALL_VOLUME_SEGMENTS)
2135b7ad23ceSYuwei Guan F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE;
2136b7ad23ceSYuwei Guan else
213763189b78SChao Yu F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT;
213863189b78SChao Yu F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX;
21390aa7e0f8SChao Yu F2FS_OPTION(sbi).s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID);
21400aa7e0f8SChao Yu F2FS_OPTION(sbi).s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID);
2141c2c14ca5SYangtao Li if (f2fs_sb_has_compression(sbi)) {
214291faa534SChao Yu F2FS_OPTION(sbi).compress_algorithm = COMPRESS_LZ4;
21434c8ff709SChao Yu F2FS_OPTION(sbi).compress_log_size = MIN_COMPRESS_LOG_SIZE;
21444c8ff709SChao Yu F2FS_OPTION(sbi).compress_ext_cnt = 0;
2145602a16d5SDaeho Jeong F2FS_OPTION(sbi).compress_mode = COMPR_MODE_FS;
2146c2c14ca5SYangtao Li }
2147bbbc34fdSChao Yu F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_ON;
21487a8fc586SDaeho Jeong F2FS_OPTION(sbi).memory_mode = MEMORY_MODE_NORMAL;
2149b62e71beSChao Yu F2FS_OPTION(sbi).errors = MOUNT_ERRORS_CONTINUE;
2150498c5e9fSYunlei He
215139133a50SChao Yu set_opt(sbi, INLINE_XATTR);
2152498c5e9fSYunlei He set_opt(sbi, INLINE_DATA);
215397c1794aSChao Yu set_opt(sbi, INLINE_DENTRY);
2154b5d15199SJaegeuk Kim set_opt(sbi, MERGE_CHECKPOINT);
21554d3aed70SDaniel Rosenberg F2FS_OPTION(sbi).unusable_cap = 0;
21561751e8a6SLinus Torvalds sbi->sb->s_flags |= SB_LAZYTIME;
2157ed8ac22bSYangtao Li if (!f2fs_is_readonly(sbi))
215869e9e427SJaegeuk Kim set_opt(sbi, FLUSH_MERGE);
2159458c15dfSChao Yu if (f2fs_sb_has_blkzoned(sbi))
2160b0332a0fSChao Yu F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS;
2161458c15dfSChao Yu else
2162b0332a0fSChao Yu F2FS_OPTION(sbi).fs_mode = FS_MODE_ADAPTIVE;
2163498c5e9fSYunlei He
2164498c5e9fSYunlei He #ifdef CONFIG_F2FS_FS_XATTR
2165498c5e9fSYunlei He set_opt(sbi, XATTR_USER);
2166498c5e9fSYunlei He #endif
2167498c5e9fSYunlei He #ifdef CONFIG_F2FS_FS_POSIX_ACL
2168498c5e9fSYunlei He set_opt(sbi, POSIX_ACL);
2169498c5e9fSYunlei He #endif
217036dbd328SChao Yu
2171d494500aSChao Yu f2fs_build_fault_attr(sbi, 0, 0);
2172498c5e9fSYunlei He }
2173498c5e9fSYunlei He
2174ea676733SJaegeuk Kim #ifdef CONFIG_QUOTA
2175ea676733SJaegeuk Kim static int f2fs_enable_quotas(struct super_block *sb);
2176ea676733SJaegeuk Kim #endif
21774354994fSDaniel Rosenberg
f2fs_disable_checkpoint(struct f2fs_sb_info * sbi)21784354994fSDaniel Rosenberg static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
21794354994fSDaniel Rosenberg {
2180812a9597SJaegeuk Kim unsigned int s_flags = sbi->sb->s_flags;
21814354994fSDaniel Rosenberg struct cp_control cpc;
21822880f47bSWeichao Guo unsigned int gc_mode = sbi->gc_mode;
2183812a9597SJaegeuk Kim int err = 0;
2184812a9597SJaegeuk Kim int ret;
21854d3aed70SDaniel Rosenberg block_t unusable;
21864354994fSDaniel Rosenberg
2187812a9597SJaegeuk Kim if (s_flags & SB_RDONLY) {
2188dcbb4c10SJoe Perches f2fs_err(sbi, "checkpoint=disable on readonly fs");
2189812a9597SJaegeuk Kim return -EINVAL;
2190812a9597SJaegeuk Kim }
21914354994fSDaniel Rosenberg sbi->sb->s_flags |= SB_ACTIVE;
21924354994fSDaniel Rosenberg
21932880f47bSWeichao Guo /* check if we need more GC first */
21942880f47bSWeichao Guo unusable = f2fs_get_unusable_blocks(sbi);
21952880f47bSWeichao Guo if (!f2fs_disable_cp_again(sbi, unusable))
21962880f47bSWeichao Guo goto skip_gc;
21972880f47bSWeichao Guo
21984354994fSDaniel Rosenberg f2fs_update_time(sbi, DISABLE_TIME);
21994354994fSDaniel Rosenberg
220098e92867SChao Yu sbi->gc_mode = GC_URGENT_HIGH;
220198e92867SChao Yu
22024354994fSDaniel Rosenberg while (!f2fs_time_over(sbi, DISABLE_TIME)) {
2203d147ea4aSJaegeuk Kim struct f2fs_gc_control gc_control = {
2204d147ea4aSJaegeuk Kim .victim_segno = NULL_SEGNO,
2205d147ea4aSJaegeuk Kim .init_gc_type = FG_GC,
2206d147ea4aSJaegeuk Kim .should_migrate_blocks = false,
2207c81d5baeSJaegeuk Kim .err_gc_skipped = true,
2208c81d5baeSJaegeuk Kim .nr_free_secs = 1 };
2209d147ea4aSJaegeuk Kim
2210e4544b63STim Murray f2fs_down_write(&sbi->gc_lock);
22119bf1dcbdSChao Yu stat_inc_gc_call_count(sbi, FOREGROUND);
2212d147ea4aSJaegeuk Kim err = f2fs_gc(sbi, &gc_control);
2213812a9597SJaegeuk Kim if (err == -ENODATA) {
2214812a9597SJaegeuk Kim err = 0;
22154354994fSDaniel Rosenberg break;
2216812a9597SJaegeuk Kim }
22178f31b466SJaegeuk Kim if (err && err != -EAGAIN)
2218812a9597SJaegeuk Kim break;
22194354994fSDaniel Rosenberg }
22204354994fSDaniel Rosenberg
2221812a9597SJaegeuk Kim ret = sync_filesystem(sbi->sb);
2222812a9597SJaegeuk Kim if (ret || err) {
2223812a9597SJaegeuk Kim err = ret ? ret : err;
2224812a9597SJaegeuk Kim goto restore_flag;
2225812a9597SJaegeuk Kim }
22264354994fSDaniel Rosenberg
22274d3aed70SDaniel Rosenberg unusable = f2fs_get_unusable_blocks(sbi);
22284d3aed70SDaniel Rosenberg if (f2fs_disable_cp_again(sbi, unusable)) {
2229812a9597SJaegeuk Kim err = -EAGAIN;
2230812a9597SJaegeuk Kim goto restore_flag;
2231812a9597SJaegeuk Kim }
22324354994fSDaniel Rosenberg
22332880f47bSWeichao Guo skip_gc:
2234e4544b63STim Murray f2fs_down_write(&sbi->gc_lock);
22354354994fSDaniel Rosenberg cpc.reason = CP_PAUSE;
22364354994fSDaniel Rosenberg set_sbi_flag(sbi, SBI_CP_DISABLED);
2237eb61c2ccSChao Yu stat_inc_cp_call_count(sbi, TOTAL_CALL);
2238896285adSChao Yu err = f2fs_write_checkpoint(sbi, &cpc);
2239896285adSChao Yu if (err)
2240896285adSChao Yu goto out_unlock;
22414354994fSDaniel Rosenberg
2242c9c8ed50SChao Yu spin_lock(&sbi->stat_lock);
22434d3aed70SDaniel Rosenberg sbi->unusable_block_count = unusable;
2244c9c8ed50SChao Yu spin_unlock(&sbi->stat_lock);
2245c9c8ed50SChao Yu
2246896285adSChao Yu out_unlock:
2247e4544b63STim Murray f2fs_up_write(&sbi->gc_lock);
2248812a9597SJaegeuk Kim restore_flag:
224998e92867SChao Yu sbi->gc_mode = gc_mode;
22507a88ddb5SChao Yu sbi->sb->s_flags = s_flags; /* Restore SB_RDONLY status */
2251812a9597SJaegeuk Kim return err;
22524354994fSDaniel Rosenberg }
22534354994fSDaniel Rosenberg
f2fs_enable_checkpoint(struct f2fs_sb_info * sbi)22544354994fSDaniel Rosenberg static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
22554354994fSDaniel Rosenberg {
2256dddd3d65SJaegeuk Kim int retry = DEFAULT_RETRY_IO_COUNT;
2257dddd3d65SJaegeuk Kim
2258b0ff4fe7SJaegeuk Kim /* we should flush all the data to keep data consistency */
2259dddd3d65SJaegeuk Kim do {
2260b0ff4fe7SJaegeuk Kim sync_inodes_sb(sbi->sb);
2261a64239d0SNeilBrown f2fs_io_schedule_timeout(DEFAULT_IO_TIMEOUT);
2262dddd3d65SJaegeuk Kim } while (get_pages(sbi, F2FS_DIRTY_DATA) && retry--);
2263dddd3d65SJaegeuk Kim
2264dddd3d65SJaegeuk Kim if (unlikely(retry < 0))
2265dddd3d65SJaegeuk Kim f2fs_warn(sbi, "checkpoint=enable has some unwritten data.");
2266b0ff4fe7SJaegeuk Kim
2267e4544b63STim Murray f2fs_down_write(&sbi->gc_lock);
22684354994fSDaniel Rosenberg f2fs_dirty_to_prefree(sbi);
22694354994fSDaniel Rosenberg
22704354994fSDaniel Rosenberg clear_sbi_flag(sbi, SBI_CP_DISABLED);
22714354994fSDaniel Rosenberg set_sbi_flag(sbi, SBI_IS_DIRTY);
2272e4544b63STim Murray f2fs_up_write(&sbi->gc_lock);
22734354994fSDaniel Rosenberg
22744354994fSDaniel Rosenberg f2fs_sync_fs(sbi->sb, 1);
22754f99484dSJaegeuk Kim
22764f99484dSJaegeuk Kim /* Let's ensure there's no pending checkpoint anymore */
22774f99484dSJaegeuk Kim f2fs_flush_ckpt_thread(sbi);
22784354994fSDaniel Rosenberg }
22794354994fSDaniel Rosenberg
f2fs_remount(struct super_block * sb,int * flags,char * data)2280696c018cSNamjae Jeon static int f2fs_remount(struct super_block *sb, int *flags, char *data)
2281696c018cSNamjae Jeon {
2282696c018cSNamjae Jeon struct f2fs_sb_info *sbi = F2FS_SB(sb);
2283696c018cSNamjae Jeon struct f2fs_mount_info org_mount_opt;
22840abd675eSChao Yu unsigned long old_sb_flags;
228563189b78SChao Yu int err;
22863fd97359SChao Yu bool need_restart_gc = false, need_stop_gc = false;
22873fd97359SChao Yu bool need_restart_ckpt = false, need_stop_ckpt = false;
22883fd97359SChao Yu bool need_restart_flush = false, need_stop_flush = false;
22894d674904SFengnan Chang bool need_restart_discard = false, need_stop_discard = false;
229012607c1bSJaegeuk Kim bool no_read_extent_cache = !test_opt(sbi, READ_EXTENT_CACHE);
229171644dffSJaegeuk Kim bool no_age_extent_cache = !test_opt(sbi, AGE_EXTENT_CACHE);
2292277afbdeSChao Yu bool enable_checkpoint = !test_opt(sbi, DISABLE_CHECKPOINT);
2293093749e2SChao Yu bool no_atgc = !test_opt(sbi, ATGC);
22944d674904SFengnan Chang bool no_discard = !test_opt(sbi, DISCARD);
22956ce19affSChao Yu bool no_compress_cache = !test_opt(sbi, COMPRESS_CACHE);
22964f993264SChao Yu bool block_unit_discard = f2fs_block_unit_discard(sbi);
22974b2414d0SChao Yu #ifdef CONFIG_QUOTA
22984b2414d0SChao Yu int i, j;
22994b2414d0SChao Yu #endif
2300696c018cSNamjae Jeon
2301696c018cSNamjae Jeon /*
2302696c018cSNamjae Jeon * Save the old mount options in case we
2303696c018cSNamjae Jeon * need to restore them.
2304696c018cSNamjae Jeon */
2305696c018cSNamjae Jeon org_mount_opt = sbi->mount_opt;
23060abd675eSChao Yu old_sb_flags = sb->s_flags;
2307696c018cSNamjae Jeon
23084b2414d0SChao Yu #ifdef CONFIG_QUOTA
230963189b78SChao Yu org_mount_opt.s_jquota_fmt = F2FS_OPTION(sbi).s_jquota_fmt;
23104b2414d0SChao Yu for (i = 0; i < MAXQUOTAS; i++) {
231163189b78SChao Yu if (F2FS_OPTION(sbi).s_qf_names[i]) {
231263189b78SChao Yu org_mount_opt.s_qf_names[i] =
231363189b78SChao Yu kstrdup(F2FS_OPTION(sbi).s_qf_names[i],
23144b2414d0SChao Yu GFP_KERNEL);
231563189b78SChao Yu if (!org_mount_opt.s_qf_names[i]) {
23164b2414d0SChao Yu for (j = 0; j < i; j++)
2317ba87a45cSWang Xiaojun kfree(org_mount_opt.s_qf_names[j]);
23184b2414d0SChao Yu return -ENOMEM;
23194b2414d0SChao Yu }
23204b2414d0SChao Yu } else {
232163189b78SChao Yu org_mount_opt.s_qf_names[i] = NULL;
23224b2414d0SChao Yu }
23234b2414d0SChao Yu }
23244b2414d0SChao Yu #endif
23254b2414d0SChao Yu
2326df728b0fSJaegeuk Kim /* recover superblocks we couldn't write due to previous RO mount */
23271751e8a6SLinus Torvalds if (!(*flags & SB_RDONLY) && is_sbi_flag_set(sbi, SBI_NEED_SB_WRITE)) {
2328df728b0fSJaegeuk Kim err = f2fs_commit_super(sbi, false);
2329dcbb4c10SJoe Perches f2fs_info(sbi, "Try to recover all the superblocks, ret: %d",
2330dcbb4c10SJoe Perches err);
2331df728b0fSJaegeuk Kim if (!err)
2332df728b0fSJaegeuk Kim clear_sbi_flag(sbi, SBI_NEED_SB_WRITE);
2333df728b0fSJaegeuk Kim }
2334df728b0fSJaegeuk Kim
2335458c15dfSChao Yu default_options(sbi, true);
233626666c8aSChao Yu
2337696c018cSNamjae Jeon /* parse mount options */
2338ed318a6cSEric Biggers err = parse_options(sb, data, true);
2339696c018cSNamjae Jeon if (err)
2340696c018cSNamjae Jeon goto restore_opts;
2341696c018cSNamjae Jeon
2342b62e71beSChao Yu /* flush outstanding errors before changing fs state */
2343b62e71beSChao Yu flush_work(&sbi->s_error_work);
2344b62e71beSChao Yu
2345696c018cSNamjae Jeon /*
2346696c018cSNamjae Jeon * Previous and new state of filesystem is RO,
2347876dc59eSGu Zheng * so skip checking GC and FLUSH_MERGE conditions.
2348696c018cSNamjae Jeon */
23491751e8a6SLinus Torvalds if (f2fs_readonly(sb) && (*flags & SB_RDONLY))
2350696c018cSNamjae Jeon goto skip;
2351696c018cSNamjae Jeon
2352d78dfefcSChao Yu if (f2fs_dev_is_readonly(sbi) && !(*flags & SB_RDONLY)) {
2353a7d9fe3cSJaegeuk Kim err = -EROFS;
2354a7d9fe3cSJaegeuk Kim goto restore_opts;
2355a7d9fe3cSJaegeuk Kim }
2356a7d9fe3cSJaegeuk Kim
2357ea676733SJaegeuk Kim #ifdef CONFIG_QUOTA
23581751e8a6SLinus Torvalds if (!f2fs_readonly(sb) && (*flags & SB_RDONLY)) {
23590abd675eSChao Yu err = dquot_suspend(sb, -1);
23600abd675eSChao Yu if (err < 0)
23610abd675eSChao Yu goto restore_opts;
23624354994fSDaniel Rosenberg } else if (f2fs_readonly(sb) && !(*flags & SB_RDONLY)) {
23630abd675eSChao Yu /* dquot_resume needs RW */
23641751e8a6SLinus Torvalds sb->s_flags &= ~SB_RDONLY;
2365ea676733SJaegeuk Kim if (sb_any_quota_suspended(sb)) {
23660abd675eSChao Yu dquot_resume(sb, -1);
23677beb01f7SChao Yu } else if (f2fs_sb_has_quota_ino(sbi)) {
2368ea676733SJaegeuk Kim err = f2fs_enable_quotas(sb);
2369ea676733SJaegeuk Kim if (err)
2370ea676733SJaegeuk Kim goto restore_opts;
23710abd675eSChao Yu }
2372ea676733SJaegeuk Kim }
2373ea676733SJaegeuk Kim #endif
2374c5bf8348SYangtao Li if (f2fs_lfs_mode(sbi) && !IS_F2FS_IPU_DISABLE(sbi)) {
2375c5bf8348SYangtao Li err = -EINVAL;
2376c5bf8348SYangtao Li f2fs_warn(sbi, "LFS is not compatible with IPU");
2377c5bf8348SYangtao Li goto restore_opts;
2378c5bf8348SYangtao Li }
2379c5bf8348SYangtao Li
2380093749e2SChao Yu /* disallow enable atgc dynamically */
2381093749e2SChao Yu if (no_atgc == !!test_opt(sbi, ATGC)) {
2382093749e2SChao Yu err = -EINVAL;
2383093749e2SChao Yu f2fs_warn(sbi, "switch atgc option is not allowed");
2384093749e2SChao Yu goto restore_opts;
2385093749e2SChao Yu }
2386093749e2SChao Yu
23879cd81ce3SChao Yu /* disallow enable/disable extent_cache dynamically */
238812607c1bSJaegeuk Kim if (no_read_extent_cache == !!test_opt(sbi, READ_EXTENT_CACHE)) {
23899cd81ce3SChao Yu err = -EINVAL;
2390dcbb4c10SJoe Perches f2fs_warn(sbi, "switch extent_cache option is not allowed");
23919cd81ce3SChao Yu goto restore_opts;
23929cd81ce3SChao Yu }
239371644dffSJaegeuk Kim /* disallow enable/disable age extent_cache dynamically */
239471644dffSJaegeuk Kim if (no_age_extent_cache == !!test_opt(sbi, AGE_EXTENT_CACHE)) {
239571644dffSJaegeuk Kim err = -EINVAL;
239671644dffSJaegeuk Kim f2fs_warn(sbi, "switch age_extent_cache option is not allowed");
239771644dffSJaegeuk Kim goto restore_opts;
239871644dffSJaegeuk Kim }
23999cd81ce3SChao Yu
24006ce19affSChao Yu if (no_compress_cache == !!test_opt(sbi, COMPRESS_CACHE)) {
24016ce19affSChao Yu err = -EINVAL;
24026ce19affSChao Yu f2fs_warn(sbi, "switch compress_cache option is not allowed");
24036ce19affSChao Yu goto restore_opts;
24046ce19affSChao Yu }
24056ce19affSChao Yu
24064f993264SChao Yu if (block_unit_discard != f2fs_block_unit_discard(sbi)) {
24074f993264SChao Yu err = -EINVAL;
24084f993264SChao Yu f2fs_warn(sbi, "switch discard_unit option is not allowed");
24094f993264SChao Yu goto restore_opts;
24104f993264SChao Yu }
24114f993264SChao Yu
24124354994fSDaniel Rosenberg if ((*flags & SB_RDONLY) && test_opt(sbi, DISABLE_CHECKPOINT)) {
24134354994fSDaniel Rosenberg err = -EINVAL;
2414dcbb4c10SJoe Perches f2fs_warn(sbi, "disabling checkpoint not compatible with read-only");
24154354994fSDaniel Rosenberg goto restore_opts;
24164354994fSDaniel Rosenberg }
24174354994fSDaniel Rosenberg
2418696c018cSNamjae Jeon /*
2419696c018cSNamjae Jeon * We stop the GC thread if FS is mounted as RO
2420696c018cSNamjae Jeon * or if background_gc = off is passed in mount
2421696c018cSNamjae Jeon * option. Also sync the filesystem.
2422696c018cSNamjae Jeon */
2423bbbc34fdSChao Yu if ((*flags & SB_RDONLY) ||
24245911d2d1SChao Yu (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_OFF &&
24255911d2d1SChao Yu !test_opt(sbi, GC_MERGE))) {
2426696c018cSNamjae Jeon if (sbi->gc_thread) {
24274d57b86dSChao Yu f2fs_stop_gc_thread(sbi);
2428876dc59eSGu Zheng need_restart_gc = true;
2429696c018cSNamjae Jeon }
2430aba291b3SChao Yu } else if (!sbi->gc_thread) {
24314d57b86dSChao Yu err = f2fs_start_gc_thread(sbi);
2432696c018cSNamjae Jeon if (err)
2433696c018cSNamjae Jeon goto restore_opts;
2434876dc59eSGu Zheng need_stop_gc = true;
2435876dc59eSGu Zheng }
2436876dc59eSGu Zheng
2437930e2607SJaegeuk Kim if (*flags & SB_RDONLY) {
2438faa0e55bSJaegeuk Kim sync_inodes_sb(sb);
2439faa0e55bSJaegeuk Kim
2440faa0e55bSJaegeuk Kim set_sbi_flag(sbi, SBI_IS_DIRTY);
2441faa0e55bSJaegeuk Kim set_sbi_flag(sbi, SBI_IS_CLOSE);
2442faa0e55bSJaegeuk Kim f2fs_sync_fs(sb, 1);
2443faa0e55bSJaegeuk Kim clear_sbi_flag(sbi, SBI_IS_CLOSE);
2444faa0e55bSJaegeuk Kim }
2445faa0e55bSJaegeuk Kim
24463f7070b0SChao Yu if ((*flags & SB_RDONLY) || test_opt(sbi, DISABLE_CHECKPOINT) ||
24473f7070b0SChao Yu !test_opt(sbi, MERGE_CHECKPOINT)) {
24483f7070b0SChao Yu f2fs_stop_ckpt_thread(sbi);
24493fd97359SChao Yu need_restart_ckpt = true;
24504354994fSDaniel Rosenberg } else {
24514f99484dSJaegeuk Kim /* Flush if the prevous checkpoint, if exists. */
24524f99484dSJaegeuk Kim f2fs_flush_ckpt_thread(sbi);
24534f99484dSJaegeuk Kim
2454261eeb9cSDaeho Jeong err = f2fs_start_ckpt_thread(sbi);
2455261eeb9cSDaeho Jeong if (err) {
2456261eeb9cSDaeho Jeong f2fs_err(sbi,
2457261eeb9cSDaeho Jeong "Failed to start F2FS issue_checkpoint_thread (%d)",
2458261eeb9cSDaeho Jeong err);
2459261eeb9cSDaeho Jeong goto restore_gc;
2460261eeb9cSDaeho Jeong }
24613fd97359SChao Yu need_stop_ckpt = true;
2462261eeb9cSDaeho Jeong }
2463261eeb9cSDaeho Jeong
2464876dc59eSGu Zheng /*
2465876dc59eSGu Zheng * We stop issue flush thread if FS is mounted as RO
2466876dc59eSGu Zheng * or if flush_merge is not passed in mount option.
2467876dc59eSGu Zheng */
24681751e8a6SLinus Torvalds if ((*flags & SB_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) {
24695eba8c5dSJaegeuk Kim clear_opt(sbi, FLUSH_MERGE);
24704d57b86dSChao Yu f2fs_destroy_flush_cmd_control(sbi, false);
24713fd97359SChao Yu need_restart_flush = true;
24725eba8c5dSJaegeuk Kim } else {
24734d57b86dSChao Yu err = f2fs_create_flush_cmd_control(sbi);
24742163d198SGu Zheng if (err)
24753fd97359SChao Yu goto restore_ckpt;
24763fd97359SChao Yu need_stop_flush = true;
2477876dc59eSGu Zheng }
24783fd97359SChao Yu
24794d674904SFengnan Chang if (no_discard == !!test_opt(sbi, DISCARD)) {
24804d674904SFengnan Chang if (test_opt(sbi, DISCARD)) {
24814d674904SFengnan Chang err = f2fs_start_discard_thread(sbi);
24824d674904SFengnan Chang if (err)
24834d674904SFengnan Chang goto restore_flush;
24844d674904SFengnan Chang need_stop_discard = true;
24854d674904SFengnan Chang } else {
24864d674904SFengnan Chang f2fs_stop_discard_thread(sbi);
24874d674904SFengnan Chang f2fs_issue_discard_timeout(sbi);
24884d674904SFengnan Chang need_restart_discard = true;
24894d674904SFengnan Chang }
24904d674904SFengnan Chang }
24914d674904SFengnan Chang
2492277afbdeSChao Yu if (enable_checkpoint == !!test_opt(sbi, DISABLE_CHECKPOINT)) {
24933fd97359SChao Yu if (test_opt(sbi, DISABLE_CHECKPOINT)) {
24943fd97359SChao Yu err = f2fs_disable_checkpoint(sbi);
24953fd97359SChao Yu if (err)
24964d674904SFengnan Chang goto restore_discard;
24973fd97359SChao Yu } else {
24983fd97359SChao Yu f2fs_enable_checkpoint(sbi);
24993fd97359SChao Yu }
25003fd97359SChao Yu }
25013fd97359SChao Yu
2502696c018cSNamjae Jeon skip:
25034b2414d0SChao Yu #ifdef CONFIG_QUOTA
25044b2414d0SChao Yu /* Release old quota file names */
25054b2414d0SChao Yu for (i = 0; i < MAXQUOTAS; i++)
2506ba87a45cSWang Xiaojun kfree(org_mount_opt.s_qf_names[i]);
25074b2414d0SChao Yu #endif
2508696c018cSNamjae Jeon /* Update the POSIXACL Flag */
25091751e8a6SLinus Torvalds sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
25101751e8a6SLinus Torvalds (test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0);
2511df728b0fSJaegeuk Kim
25127e65be49SJaegeuk Kim limit_reserve_root(sbi);
25131ae18f71SJaegeuk Kim adjust_unusable_cap_perc(sbi);
2514095680f2SJaegeuk Kim *flags = (*flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME);
2515696c018cSNamjae Jeon return 0;
25164d674904SFengnan Chang restore_discard:
25174d674904SFengnan Chang if (need_restart_discard) {
25184d674904SFengnan Chang if (f2fs_start_discard_thread(sbi))
25194d674904SFengnan Chang f2fs_warn(sbi, "discard has been stopped");
25204d674904SFengnan Chang } else if (need_stop_discard) {
25214d674904SFengnan Chang f2fs_stop_discard_thread(sbi);
25224d674904SFengnan Chang }
25233fd97359SChao Yu restore_flush:
25243fd97359SChao Yu if (need_restart_flush) {
25253fd97359SChao Yu if (f2fs_create_flush_cmd_control(sbi))
25263fd97359SChao Yu f2fs_warn(sbi, "background flush thread has stopped");
25273fd97359SChao Yu } else if (need_stop_flush) {
25283fd97359SChao Yu clear_opt(sbi, FLUSH_MERGE);
25293fd97359SChao Yu f2fs_destroy_flush_cmd_control(sbi, false);
25303fd97359SChao Yu }
25313fd97359SChao Yu restore_ckpt:
25323fd97359SChao Yu if (need_restart_ckpt) {
25333fd97359SChao Yu if (f2fs_start_ckpt_thread(sbi))
25343fd97359SChao Yu f2fs_warn(sbi, "background ckpt thread has stopped");
25353fd97359SChao Yu } else if (need_stop_ckpt) {
25363fd97359SChao Yu f2fs_stop_ckpt_thread(sbi);
25373fd97359SChao Yu }
2538876dc59eSGu Zheng restore_gc:
2539876dc59eSGu Zheng if (need_restart_gc) {
25404d57b86dSChao Yu if (f2fs_start_gc_thread(sbi))
2541dcbb4c10SJoe Perches f2fs_warn(sbi, "background gc thread has stopped");
2542876dc59eSGu Zheng } else if (need_stop_gc) {
25434d57b86dSChao Yu f2fs_stop_gc_thread(sbi);
2544876dc59eSGu Zheng }
2545696c018cSNamjae Jeon restore_opts:
25464b2414d0SChao Yu #ifdef CONFIG_QUOTA
254763189b78SChao Yu F2FS_OPTION(sbi).s_jquota_fmt = org_mount_opt.s_jquota_fmt;
25484b2414d0SChao Yu for (i = 0; i < MAXQUOTAS; i++) {
2549ba87a45cSWang Xiaojun kfree(F2FS_OPTION(sbi).s_qf_names[i]);
255063189b78SChao Yu F2FS_OPTION(sbi).s_qf_names[i] = org_mount_opt.s_qf_names[i];
25514b2414d0SChao Yu }
25524b2414d0SChao Yu #endif
2553696c018cSNamjae Jeon sbi->mount_opt = org_mount_opt;
25540abd675eSChao Yu sb->s_flags = old_sb_flags;
2555696c018cSNamjae Jeon return err;
2556696c018cSNamjae Jeon }
2557696c018cSNamjae Jeon
f2fs_shutdown(struct super_block * sb)2558f2971778SChao Yu static void f2fs_shutdown(struct super_block *sb)
2559f2971778SChao Yu {
2560fc18e655SChao Yu f2fs_do_shutdown(F2FS_SB(sb), F2FS_GOING_DOWN_NOSYNC, false, false);
2561f2971778SChao Yu }
2562f2971778SChao Yu
25630abd675eSChao Yu #ifdef CONFIG_QUOTA
f2fs_need_recovery(struct f2fs_sb_info * sbi)2564e1bb7d3dSChao Yu static bool f2fs_need_recovery(struct f2fs_sb_info *sbi)
2565e1bb7d3dSChao Yu {
2566e1bb7d3dSChao Yu /* need to recovery orphan */
2567e1bb7d3dSChao Yu if (is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG))
2568e1bb7d3dSChao Yu return true;
2569e1bb7d3dSChao Yu /* need to recovery data */
2570e1bb7d3dSChao Yu if (test_opt(sbi, DISABLE_ROLL_FORWARD))
2571e1bb7d3dSChao Yu return false;
2572e1bb7d3dSChao Yu if (test_opt(sbi, NORECOVERY))
2573e1bb7d3dSChao Yu return false;
2574e1bb7d3dSChao Yu return !is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG);
2575e1bb7d3dSChao Yu }
2576e1bb7d3dSChao Yu
f2fs_recover_quota_begin(struct f2fs_sb_info * sbi)2577e1bb7d3dSChao Yu static bool f2fs_recover_quota_begin(struct f2fs_sb_info *sbi)
2578e1bb7d3dSChao Yu {
2579e1bb7d3dSChao Yu bool readonly = f2fs_readonly(sbi->sb);
2580e1bb7d3dSChao Yu
2581e1bb7d3dSChao Yu if (!f2fs_need_recovery(sbi))
2582e1bb7d3dSChao Yu return false;
2583e1bb7d3dSChao Yu
2584e1bb7d3dSChao Yu /* it doesn't need to check f2fs_sb_has_readonly() */
2585e1bb7d3dSChao Yu if (f2fs_hw_is_readonly(sbi))
2586e1bb7d3dSChao Yu return false;
2587e1bb7d3dSChao Yu
2588e1bb7d3dSChao Yu if (readonly) {
2589e1bb7d3dSChao Yu sbi->sb->s_flags &= ~SB_RDONLY;
2590e1bb7d3dSChao Yu set_sbi_flag(sbi, SBI_IS_WRITABLE);
2591e1bb7d3dSChao Yu }
2592e1bb7d3dSChao Yu
2593e1bb7d3dSChao Yu /*
2594e1bb7d3dSChao Yu * Turn on quotas which were not enabled for read-only mounts if
2595e1bb7d3dSChao Yu * filesystem has quota feature, so that they are updated correctly.
2596e1bb7d3dSChao Yu */
2597e1bb7d3dSChao Yu return f2fs_enable_quota_files(sbi, readonly);
2598e1bb7d3dSChao Yu }
2599e1bb7d3dSChao Yu
f2fs_recover_quota_end(struct f2fs_sb_info * sbi,bool quota_enabled)2600e1bb7d3dSChao Yu static void f2fs_recover_quota_end(struct f2fs_sb_info *sbi,
2601e1bb7d3dSChao Yu bool quota_enabled)
2602e1bb7d3dSChao Yu {
2603e1bb7d3dSChao Yu if (quota_enabled)
2604e1bb7d3dSChao Yu f2fs_quota_off_umount(sbi->sb);
2605e1bb7d3dSChao Yu
2606e1bb7d3dSChao Yu if (is_sbi_flag_set(sbi, SBI_IS_WRITABLE)) {
2607e1bb7d3dSChao Yu clear_sbi_flag(sbi, SBI_IS_WRITABLE);
2608e1bb7d3dSChao Yu sbi->sb->s_flags |= SB_RDONLY;
2609e1bb7d3dSChao Yu }
2610e1bb7d3dSChao Yu }
2611e1bb7d3dSChao Yu
26120abd675eSChao Yu /* Read data from quotafile */
f2fs_quota_read(struct super_block * sb,int type,char * data,size_t len,loff_t off)26130abd675eSChao Yu static ssize_t f2fs_quota_read(struct super_block *sb, int type, char *data,
26140abd675eSChao Yu size_t len, loff_t off)
26150abd675eSChao Yu {
26160abd675eSChao Yu struct inode *inode = sb_dqopt(sb)->files[type];
26170abd675eSChao Yu struct address_space *mapping = inode->i_mapping;
26180abd675eSChao Yu block_t blkidx = F2FS_BYTES_TO_BLK(off);
26190abd675eSChao Yu int offset = off & (sb->s_blocksize - 1);
26200abd675eSChao Yu int tocopy;
26210abd675eSChao Yu size_t toread;
26220abd675eSChao Yu loff_t i_size = i_size_read(inode);
26230abd675eSChao Yu struct page *page;
26240abd675eSChao Yu
26250abd675eSChao Yu if (off > i_size)
26260abd675eSChao Yu return 0;
26270abd675eSChao Yu
26280abd675eSChao Yu if (off + len > i_size)
26290abd675eSChao Yu len = i_size - off;
26300abd675eSChao Yu toread = len;
26310abd675eSChao Yu while (toread > 0) {
26320abd675eSChao Yu tocopy = min_t(unsigned long, sb->s_blocksize - offset, toread);
26330abd675eSChao Yu repeat:
263402117b8aSRitesh Harjani page = read_cache_page_gfp(mapping, blkidx, GFP_NOFS);
26354e46a023SJaegeuk Kim if (IS_ERR(page)) {
26364e46a023SJaegeuk Kim if (PTR_ERR(page) == -ENOMEM) {
26374034247aSNeilBrown memalloc_retry_wait(GFP_NOFS);
26384e46a023SJaegeuk Kim goto repeat;
26394e46a023SJaegeuk Kim }
2640af033b2aSChao Yu set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR);
26410abd675eSChao Yu return PTR_ERR(page);
26424e46a023SJaegeuk Kim }
26430abd675eSChao Yu
26440abd675eSChao Yu lock_page(page);
26450abd675eSChao Yu
26460abd675eSChao Yu if (unlikely(page->mapping != mapping)) {
26470abd675eSChao Yu f2fs_put_page(page, 1);
26480abd675eSChao Yu goto repeat;
26490abd675eSChao Yu }
26500abd675eSChao Yu if (unlikely(!PageUptodate(page))) {
26510abd675eSChao Yu f2fs_put_page(page, 1);
2652af033b2aSChao Yu set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR);
26530abd675eSChao Yu return -EIO;
26540abd675eSChao Yu }
26550abd675eSChao Yu
2656b87846bdSEric Biggers memcpy_from_page(data, page, offset, tocopy);
26570abd675eSChao Yu f2fs_put_page(page, 1);
26580abd675eSChao Yu
26590abd675eSChao Yu offset = 0;
26600abd675eSChao Yu toread -= tocopy;
26610abd675eSChao Yu data += tocopy;
26620abd675eSChao Yu blkidx++;
26630abd675eSChao Yu }
26640abd675eSChao Yu return len;
26650abd675eSChao Yu }
26660abd675eSChao Yu
26670abd675eSChao Yu /* Write to quotafile */
f2fs_quota_write(struct super_block * sb,int type,const char * data,size_t len,loff_t off)26680abd675eSChao Yu static ssize_t f2fs_quota_write(struct super_block *sb, int type,
26690abd675eSChao Yu const char *data, size_t len, loff_t off)
26700abd675eSChao Yu {
26710abd675eSChao Yu struct inode *inode = sb_dqopt(sb)->files[type];
26720abd675eSChao Yu struct address_space *mapping = inode->i_mapping;
26730abd675eSChao Yu const struct address_space_operations *a_ops = mapping->a_ops;
26740abd675eSChao Yu int offset = off & (sb->s_blocksize - 1);
26750abd675eSChao Yu size_t towrite = len;
26760abd675eSChao Yu struct page *page;
267762f63eeaSChao Yu void *fsdata = NULL;
26780abd675eSChao Yu int err = 0;
26790abd675eSChao Yu int tocopy;
26800abd675eSChao Yu
26810abd675eSChao Yu while (towrite > 0) {
26820abd675eSChao Yu tocopy = min_t(unsigned long, sb->s_blocksize - offset,
26830abd675eSChao Yu towrite);
26844e46a023SJaegeuk Kim retry:
26859d6b0cd7SMatthew Wilcox (Oracle) err = a_ops->write_begin(NULL, mapping, off, tocopy,
268662f63eeaSChao Yu &page, &fsdata);
26874e46a023SJaegeuk Kim if (unlikely(err)) {
26884e46a023SJaegeuk Kim if (err == -ENOMEM) {
2689a64239d0SNeilBrown f2fs_io_schedule_timeout(DEFAULT_IO_TIMEOUT);
26904e46a023SJaegeuk Kim goto retry;
26914e46a023SJaegeuk Kim }
2692af033b2aSChao Yu set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR);
26930abd675eSChao Yu break;
26944e46a023SJaegeuk Kim }
26950abd675eSChao Yu
2696b87846bdSEric Biggers memcpy_to_page(page, offset, data, tocopy);
26970abd675eSChao Yu
26980abd675eSChao Yu a_ops->write_end(NULL, mapping, off, tocopy, tocopy,
269962f63eeaSChao Yu page, fsdata);
27000abd675eSChao Yu offset = 0;
27010abd675eSChao Yu towrite -= tocopy;
27020abd675eSChao Yu off += tocopy;
27030abd675eSChao Yu data += tocopy;
27040abd675eSChao Yu cond_resched();
27050abd675eSChao Yu }
27060abd675eSChao Yu
27070abd675eSChao Yu if (len == towrite)
27086e5b5d41SJaegeuk Kim return err;
2709c62ebd35SJeff Layton inode->i_mtime = inode_set_ctime_current(inode);
27100abd675eSChao Yu f2fs_mark_inode_dirty_sync(inode, false);
27110abd675eSChao Yu return len - towrite;
27120abd675eSChao Yu }
27130abd675eSChao Yu
f2fs_dquot_initialize(struct inode * inode)271410a26878SChao Yu int f2fs_dquot_initialize(struct inode *inode)
271510a26878SChao Yu {
2716c40e15a9SYangtao Li if (time_to_inject(F2FS_I_SB(inode), FAULT_DQUOT_INIT))
271710a26878SChao Yu return -ESRCH;
271810a26878SChao Yu
271910a26878SChao Yu return dquot_initialize(inode);
272010a26878SChao Yu }
272110a26878SChao Yu
f2fs_get_dquots(struct inode * inode)272242954c37SJan Kara static struct dquot __rcu **f2fs_get_dquots(struct inode *inode)
27230abd675eSChao Yu {
27240abd675eSChao Yu return F2FS_I(inode)->i_dquot;
27250abd675eSChao Yu }
27260abd675eSChao Yu
f2fs_get_reserved_space(struct inode * inode)27270abd675eSChao Yu static qsize_t *f2fs_get_reserved_space(struct inode *inode)
27280abd675eSChao Yu {
27290abd675eSChao Yu return &F2FS_I(inode)->i_reserved_quota;
27300abd675eSChao Yu }
27310abd675eSChao Yu
f2fs_quota_on_mount(struct f2fs_sb_info * sbi,int type)27324b2414d0SChao Yu static int f2fs_quota_on_mount(struct f2fs_sb_info *sbi, int type)
27334b2414d0SChao Yu {
2734af033b2aSChao Yu if (is_set_ckpt_flags(sbi, CP_QUOTA_NEED_FSCK_FLAG)) {
2735dcbb4c10SJoe Perches f2fs_err(sbi, "quota sysfile may be corrupted, skip loading it");
2736af033b2aSChao Yu return 0;
2737af033b2aSChao Yu }
2738af033b2aSChao Yu
273963189b78SChao Yu return dquot_quota_on_mount(sbi->sb, F2FS_OPTION(sbi).s_qf_names[type],
274063189b78SChao Yu F2FS_OPTION(sbi).s_jquota_fmt, type);
27414b2414d0SChao Yu }
27424b2414d0SChao Yu
f2fs_enable_quota_files(struct f2fs_sb_info * sbi,bool rdonly)2743ea676733SJaegeuk Kim int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly)
27444b2414d0SChao Yu {
2745ea676733SJaegeuk Kim int enabled = 0;
2746ea676733SJaegeuk Kim int i, err;
2747ea676733SJaegeuk Kim
27487beb01f7SChao Yu if (f2fs_sb_has_quota_ino(sbi) && rdonly) {
2749ea676733SJaegeuk Kim err = f2fs_enable_quotas(sbi->sb);
2750ea676733SJaegeuk Kim if (err) {
2751dcbb4c10SJoe Perches f2fs_err(sbi, "Cannot turn on quota_ino: %d", err);
2752ea676733SJaegeuk Kim return 0;
2753ea676733SJaegeuk Kim }
2754ea676733SJaegeuk Kim return 1;
2755ea676733SJaegeuk Kim }
27564b2414d0SChao Yu
27574b2414d0SChao Yu for (i = 0; i < MAXQUOTAS; i++) {
275863189b78SChao Yu if (F2FS_OPTION(sbi).s_qf_names[i]) {
2759ea676733SJaegeuk Kim err = f2fs_quota_on_mount(sbi, i);
2760ea676733SJaegeuk Kim if (!err) {
2761ea676733SJaegeuk Kim enabled = 1;
2762ea676733SJaegeuk Kim continue;
2763ea676733SJaegeuk Kim }
2764dcbb4c10SJoe Perches f2fs_err(sbi, "Cannot turn on quotas: %d on %d",
2765dcbb4c10SJoe Perches err, i);
27664b2414d0SChao Yu }
27674b2414d0SChao Yu }
2768ea676733SJaegeuk Kim return enabled;
2769ea676733SJaegeuk Kim }
2770ea676733SJaegeuk Kim
f2fs_quota_enable(struct super_block * sb,int type,int format_id,unsigned int flags)2771ea676733SJaegeuk Kim static int f2fs_quota_enable(struct super_block *sb, int type, int format_id,
2772ea676733SJaegeuk Kim unsigned int flags)
2773ea676733SJaegeuk Kim {
2774ea676733SJaegeuk Kim struct inode *qf_inode;
2775ea676733SJaegeuk Kim unsigned long qf_inum;
2776ccf3ff2bSChao Yu unsigned long qf_flag = F2FS_QUOTA_DEFAULT_FL;
2777ea676733SJaegeuk Kim int err;
2778ea676733SJaegeuk Kim
27797beb01f7SChao Yu BUG_ON(!f2fs_sb_has_quota_ino(F2FS_SB(sb)));
2780ea676733SJaegeuk Kim
2781ea676733SJaegeuk Kim qf_inum = f2fs_qf_ino(sb, type);
2782ea676733SJaegeuk Kim if (!qf_inum)
2783ea676733SJaegeuk Kim return -EPERM;
2784ea676733SJaegeuk Kim
2785ea676733SJaegeuk Kim qf_inode = f2fs_iget(sb, qf_inum);
2786ea676733SJaegeuk Kim if (IS_ERR(qf_inode)) {
2787dcbb4c10SJoe Perches f2fs_err(F2FS_SB(sb), "Bad quota inode %u:%lu", type, qf_inum);
2788ea676733SJaegeuk Kim return PTR_ERR(qf_inode);
2789ea676733SJaegeuk Kim }
2790ea676733SJaegeuk Kim
2791ea676733SJaegeuk Kim /* Don't account quota for quota files to avoid recursion */
279290b7c4b7SChao Yu inode_lock(qf_inode);
2793ea676733SJaegeuk Kim qf_inode->i_flags |= S_NOQUOTA;
279490b7c4b7SChao Yu
279590b7c4b7SChao Yu if ((F2FS_I(qf_inode)->i_flags & qf_flag) != qf_flag) {
279690b7c4b7SChao Yu F2FS_I(qf_inode)->i_flags |= qf_flag;
279790b7c4b7SChao Yu f2fs_set_inode_flags(qf_inode);
279890b7c4b7SChao Yu }
279990b7c4b7SChao Yu inode_unlock(qf_inode);
280090b7c4b7SChao Yu
28017212b95eSJan Kara err = dquot_load_quota_inode(qf_inode, type, format_id, flags);
2802ea676733SJaegeuk Kim iput(qf_inode);
2803ea676733SJaegeuk Kim return err;
2804ea676733SJaegeuk Kim }
2805ea676733SJaegeuk Kim
f2fs_enable_quotas(struct super_block * sb)2806ea676733SJaegeuk Kim static int f2fs_enable_quotas(struct super_block *sb)
2807ea676733SJaegeuk Kim {
2808dcbb4c10SJoe Perches struct f2fs_sb_info *sbi = F2FS_SB(sb);
2809ea676733SJaegeuk Kim int type, err = 0;
2810ea676733SJaegeuk Kim unsigned long qf_inum;
2811ea676733SJaegeuk Kim bool quota_mopt[MAXQUOTAS] = {
2812dcbb4c10SJoe Perches test_opt(sbi, USRQUOTA),
2813dcbb4c10SJoe Perches test_opt(sbi, GRPQUOTA),
2814dcbb4c10SJoe Perches test_opt(sbi, PRJQUOTA),
2815ea676733SJaegeuk Kim };
2816ea676733SJaegeuk Kim
2817af033b2aSChao Yu if (is_set_ckpt_flags(F2FS_SB(sb), CP_QUOTA_NEED_FSCK_FLAG)) {
2818dcbb4c10SJoe Perches f2fs_err(sbi, "quota file may be corrupted, skip loading it");
2819af033b2aSChao Yu return 0;
2820af033b2aSChao Yu }
2821af033b2aSChao Yu
2822af033b2aSChao Yu sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
2823af033b2aSChao Yu
2824ea676733SJaegeuk Kim for (type = 0; type < MAXQUOTAS; type++) {
2825ea676733SJaegeuk Kim qf_inum = f2fs_qf_ino(sb, type);
2826ea676733SJaegeuk Kim if (qf_inum) {
2827ea676733SJaegeuk Kim err = f2fs_quota_enable(sb, type, QFMT_VFS_V1,
2828ea676733SJaegeuk Kim DQUOT_USAGE_ENABLED |
2829ea676733SJaegeuk Kim (quota_mopt[type] ? DQUOT_LIMITS_ENABLED : 0));
2830ea676733SJaegeuk Kim if (err) {
2831dcbb4c10SJoe Perches f2fs_err(sbi, "Failed to enable quota tracking (type=%d, err=%d). Please run fsck to fix.",
2832dcbb4c10SJoe Perches type, err);
2833ea676733SJaegeuk Kim for (type--; type >= 0; type--)
2834ea676733SJaegeuk Kim dquot_quota_off(sb, type);
2835af033b2aSChao Yu set_sbi_flag(F2FS_SB(sb),
2836af033b2aSChao Yu SBI_QUOTA_NEED_REPAIR);
2837ea676733SJaegeuk Kim return err;
2838ea676733SJaegeuk Kim }
2839ea676733SJaegeuk Kim }
2840ea676733SJaegeuk Kim }
2841ea676733SJaegeuk Kim return 0;
28424b2414d0SChao Yu }
28434b2414d0SChao Yu
f2fs_quota_sync_file(struct f2fs_sb_info * sbi,int type)28449de71edeSChao Yu static int f2fs_quota_sync_file(struct f2fs_sb_info *sbi, int type)
28459de71edeSChao Yu {
28469de71edeSChao Yu struct quota_info *dqopt = sb_dqopt(sbi->sb);
28479de71edeSChao Yu struct address_space *mapping = dqopt->files[type]->i_mapping;
28489de71edeSChao Yu int ret = 0;
28499de71edeSChao Yu
28509de71edeSChao Yu ret = dquot_writeback_dquots(sbi->sb, type);
28519de71edeSChao Yu if (ret)
28529de71edeSChao Yu goto out;
28539de71edeSChao Yu
28549de71edeSChao Yu ret = filemap_fdatawrite(mapping);
28559de71edeSChao Yu if (ret)
28569de71edeSChao Yu goto out;
28579de71edeSChao Yu
28589de71edeSChao Yu /* if we are using journalled quota */
28599de71edeSChao Yu if (is_journalled_quota(sbi))
28609de71edeSChao Yu goto out;
28619de71edeSChao Yu
28629de71edeSChao Yu ret = filemap_fdatawait(mapping);
28639de71edeSChao Yu
28649de71edeSChao Yu truncate_inode_pages(&dqopt->files[type]->i_data, 0);
28659de71edeSChao Yu out:
28669de71edeSChao Yu if (ret)
28679de71edeSChao Yu set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
28689de71edeSChao Yu return ret;
28699de71edeSChao Yu }
28709de71edeSChao Yu
f2fs_quota_sync(struct super_block * sb,int type)2871af033b2aSChao Yu int f2fs_quota_sync(struct super_block *sb, int type)
28720abd675eSChao Yu {
2873af033b2aSChao Yu struct f2fs_sb_info *sbi = F2FS_SB(sb);
28740abd675eSChao Yu struct quota_info *dqopt = sb_dqopt(sb);
28750abd675eSChao Yu int cnt;
2876680af5b8SJuhyung Park int ret = 0;
28770abd675eSChao Yu
2878db6ec53bSJaegeuk Kim /*
28799de71edeSChao Yu * Now when everything is written we can discard the pagecache so
28809de71edeSChao Yu * that userspace sees the changes.
28819de71edeSChao Yu */
28829de71edeSChao Yu for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
28839de71edeSChao Yu
28849de71edeSChao Yu if (type != -1 && cnt != type)
28859de71edeSChao Yu continue;
28869de71edeSChao Yu
2887680af5b8SJuhyung Park if (!sb_has_quota_active(sb, cnt))
2888680af5b8SJuhyung Park continue;
28899de71edeSChao Yu
28906213f5d4SJaegeuk Kim if (!f2fs_sb_has_quota_ino(sbi))
28919de71edeSChao Yu inode_lock(dqopt->files[cnt]);
28929de71edeSChao Yu
28939de71edeSChao Yu /*
2894db6ec53bSJaegeuk Kim * do_quotactl
2895db6ec53bSJaegeuk Kim * f2fs_quota_sync
2896e4544b63STim Murray * f2fs_down_read(quota_sem)
2897db6ec53bSJaegeuk Kim * dquot_writeback_dquots()
2898db6ec53bSJaegeuk Kim * f2fs_dquot_commit
2899db6ec53bSJaegeuk Kim * block_operation
2900e4544b63STim Murray * f2fs_down_read(quota_sem)
2901db6ec53bSJaegeuk Kim */
2902db6ec53bSJaegeuk Kim f2fs_lock_op(sbi);
2903e4544b63STim Murray f2fs_down_read(&sbi->quota_sem);
29040abd675eSChao Yu
29059de71edeSChao Yu ret = f2fs_quota_sync_file(sbi, cnt);
2906af033b2aSChao Yu
2907e4544b63STim Murray f2fs_up_read(&sbi->quota_sem);
2908db6ec53bSJaegeuk Kim f2fs_unlock_op(sbi);
29099de71edeSChao Yu
29106213f5d4SJaegeuk Kim if (!f2fs_sb_has_quota_ino(sbi))
29119de71edeSChao Yu inode_unlock(dqopt->files[cnt]);
29129de71edeSChao Yu
29139de71edeSChao Yu if (ret)
29149de71edeSChao Yu break;
29159de71edeSChao Yu }
2916af033b2aSChao Yu return ret;
29170abd675eSChao Yu }
29180abd675eSChao Yu
f2fs_quota_on(struct super_block * sb,int type,int format_id,const struct path * path)29190abd675eSChao Yu static int f2fs_quota_on(struct super_block *sb, int type, int format_id,
29200abd675eSChao Yu const struct path *path)
29210abd675eSChao Yu {
29220abd675eSChao Yu struct inode *inode;
29230abd675eSChao Yu int err;
29240abd675eSChao Yu
2925fe973b06SChao Yu /* if quota sysfile exists, deny enabling quota with specific file */
2926fe973b06SChao Yu if (f2fs_sb_has_quota_ino(F2FS_SB(sb))) {
2927fe973b06SChao Yu f2fs_err(F2FS_SB(sb), "quota sysfile already exists");
2928fe973b06SChao Yu return -EBUSY;
2929fe973b06SChao Yu }
2930fe973b06SChao Yu
29315079e1c0SChao Yu if (path->dentry->d_sb != sb)
29325079e1c0SChao Yu return -EXDEV;
29335079e1c0SChao Yu
29349a20d391SChao Yu err = f2fs_quota_sync(sb, type);
29350abd675eSChao Yu if (err)
29360abd675eSChao Yu return err;
29370abd675eSChao Yu
29385079e1c0SChao Yu inode = d_inode(path->dentry);
29395079e1c0SChao Yu
29405079e1c0SChao Yu err = filemap_fdatawrite(inode->i_mapping);
29415079e1c0SChao Yu if (err)
29425079e1c0SChao Yu return err;
29435079e1c0SChao Yu
29445079e1c0SChao Yu err = filemap_fdatawait(inode->i_mapping);
29455079e1c0SChao Yu if (err)
29465079e1c0SChao Yu return err;
29475079e1c0SChao Yu
29480abd675eSChao Yu err = dquot_quota_on(sb, type, format_id, path);
29490abd675eSChao Yu if (err)
29500abd675eSChao Yu return err;
29510abd675eSChao Yu
29520abd675eSChao Yu inode_lock(inode);
2953ccf3ff2bSChao Yu F2FS_I(inode)->i_flags |= F2FS_QUOTA_DEFAULT_FL;
29549149a5ebSChao Yu f2fs_set_inode_flags(inode);
29550abd675eSChao Yu inode_unlock(inode);
29560abd675eSChao Yu f2fs_mark_inode_dirty_sync(inode, false);
29570abd675eSChao Yu
29580abd675eSChao Yu return 0;
29590abd675eSChao Yu }
29600abd675eSChao Yu
__f2fs_quota_off(struct super_block * sb,int type)2961fe973b06SChao Yu static int __f2fs_quota_off(struct super_block *sb, int type)
29620abd675eSChao Yu {
29630abd675eSChao Yu struct inode *inode = sb_dqopt(sb)->files[type];
29640abd675eSChao Yu int err;
29650abd675eSChao Yu
29660abd675eSChao Yu if (!inode || !igrab(inode))
29670abd675eSChao Yu return dquot_quota_off(sb, type);
29680abd675eSChao Yu
2969cda9cc59SYunlei He err = f2fs_quota_sync(sb, type);
2970cda9cc59SYunlei He if (err)
2971cda9cc59SYunlei He goto out_put;
29720abd675eSChao Yu
29730abd675eSChao Yu err = dquot_quota_off(sb, type);
29747beb01f7SChao Yu if (err || f2fs_sb_has_quota_ino(F2FS_SB(sb)))
29750abd675eSChao Yu goto out_put;
29760abd675eSChao Yu
29770abd675eSChao Yu inode_lock(inode);
2978ccf3ff2bSChao Yu F2FS_I(inode)->i_flags &= ~F2FS_QUOTA_DEFAULT_FL;
29799149a5ebSChao Yu f2fs_set_inode_flags(inode);
29800abd675eSChao Yu inode_unlock(inode);
29810abd675eSChao Yu f2fs_mark_inode_dirty_sync(inode, false);
29820abd675eSChao Yu out_put:
29830abd675eSChao Yu iput(inode);
29840abd675eSChao Yu return err;
29850abd675eSChao Yu }
29860abd675eSChao Yu
f2fs_quota_off(struct super_block * sb,int type)2987fe973b06SChao Yu static int f2fs_quota_off(struct super_block *sb, int type)
2988fe973b06SChao Yu {
2989fe973b06SChao Yu struct f2fs_sb_info *sbi = F2FS_SB(sb);
2990fe973b06SChao Yu int err;
2991fe973b06SChao Yu
2992fe973b06SChao Yu err = __f2fs_quota_off(sb, type);
2993fe973b06SChao Yu
2994fe973b06SChao Yu /*
2995fe973b06SChao Yu * quotactl can shutdown journalled quota, result in inconsistence
2996fe973b06SChao Yu * between quota record and fs data by following updates, tag the
2997fe973b06SChao Yu * flag to let fsck be aware of it.
2998fe973b06SChao Yu */
2999fe973b06SChao Yu if (is_journalled_quota(sbi))
3000fe973b06SChao Yu set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
3001fe973b06SChao Yu return err;
3002fe973b06SChao Yu }
3003fe973b06SChao Yu
f2fs_quota_off_umount(struct super_block * sb)30044b2414d0SChao Yu void f2fs_quota_off_umount(struct super_block *sb)
30050abd675eSChao Yu {
30060abd675eSChao Yu int type;
3007cda9cc59SYunlei He int err;
30080abd675eSChao Yu
3009cda9cc59SYunlei He for (type = 0; type < MAXQUOTAS; type++) {
3010fe973b06SChao Yu err = __f2fs_quota_off(sb, type);
3011cda9cc59SYunlei He if (err) {
3012cda9cc59SYunlei He int ret = dquot_quota_off(sb, type);
3013cda9cc59SYunlei He
3014dcbb4c10SJoe Perches f2fs_err(F2FS_SB(sb), "Fail to turn off disk quota (type: %d, err: %d, ret:%d), Please run fsck to fix it.",
3015dcbb4c10SJoe Perches type, err, ret);
3016af033b2aSChao Yu set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR);
3017cda9cc59SYunlei He }
3018cda9cc59SYunlei He }
30190e0667b6SJaegeuk Kim /*
30200e0667b6SJaegeuk Kim * In case of checkpoint=disable, we must flush quota blocks.
30210e0667b6SJaegeuk Kim * This can cause NULL exception for node_inode in end_io, since
30220e0667b6SJaegeuk Kim * put_super already dropped it.
30230e0667b6SJaegeuk Kim */
30240e0667b6SJaegeuk Kim sync_filesystem(sb);
30250abd675eSChao Yu }
30260abd675eSChao Yu
f2fs_truncate_quota_inode_pages(struct super_block * sb)302726b5a079SSheng Yong static void f2fs_truncate_quota_inode_pages(struct super_block *sb)
302826b5a079SSheng Yong {
302926b5a079SSheng Yong struct quota_info *dqopt = sb_dqopt(sb);
303026b5a079SSheng Yong int type;
303126b5a079SSheng Yong
303226b5a079SSheng Yong for (type = 0; type < MAXQUOTAS; type++) {
303326b5a079SSheng Yong if (!dqopt->files[type])
303426b5a079SSheng Yong continue;
303526b5a079SSheng Yong f2fs_inode_synced(dqopt->files[type]);
303626b5a079SSheng Yong }
303726b5a079SSheng Yong }
303826b5a079SSheng Yong
f2fs_dquot_commit(struct dquot * dquot)3039af033b2aSChao Yu static int f2fs_dquot_commit(struct dquot *dquot)
3040af033b2aSChao Yu {
3041db6ec53bSJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb);
3042af033b2aSChao Yu int ret;
3043af033b2aSChao Yu
3044e4544b63STim Murray f2fs_down_read_nested(&sbi->quota_sem, SINGLE_DEPTH_NESTING);
3045af033b2aSChao Yu ret = dquot_commit(dquot);
3046af033b2aSChao Yu if (ret < 0)
3047db6ec53bSJaegeuk Kim set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
3048e4544b63STim Murray f2fs_up_read(&sbi->quota_sem);
3049af033b2aSChao Yu return ret;
3050af033b2aSChao Yu }
3051af033b2aSChao Yu
f2fs_dquot_acquire(struct dquot * dquot)3052af033b2aSChao Yu static int f2fs_dquot_acquire(struct dquot *dquot)
3053af033b2aSChao Yu {
3054db6ec53bSJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb);
3055af033b2aSChao Yu int ret;
3056af033b2aSChao Yu
3057e4544b63STim Murray f2fs_down_read(&sbi->quota_sem);
3058af033b2aSChao Yu ret = dquot_acquire(dquot);
3059af033b2aSChao Yu if (ret < 0)
3060db6ec53bSJaegeuk Kim set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
3061e4544b63STim Murray f2fs_up_read(&sbi->quota_sem);
3062af033b2aSChao Yu return ret;
3063af033b2aSChao Yu }
3064af033b2aSChao Yu
f2fs_dquot_release(struct dquot * dquot)3065af033b2aSChao Yu static int f2fs_dquot_release(struct dquot *dquot)
3066af033b2aSChao Yu {
3067db6ec53bSJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb);
30682c4e0c52SJaegeuk Kim int ret = dquot_release(dquot);
3069af033b2aSChao Yu
3070af033b2aSChao Yu if (ret < 0)
3071db6ec53bSJaegeuk Kim set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
3072af033b2aSChao Yu return ret;
3073af033b2aSChao Yu }
3074af033b2aSChao Yu
f2fs_dquot_mark_dquot_dirty(struct dquot * dquot)3075af033b2aSChao Yu static int f2fs_dquot_mark_dquot_dirty(struct dquot *dquot)
3076af033b2aSChao Yu {
3077af033b2aSChao Yu struct super_block *sb = dquot->dq_sb;
3078af033b2aSChao Yu struct f2fs_sb_info *sbi = F2FS_SB(sb);
30792c4e0c52SJaegeuk Kim int ret = dquot_mark_dquot_dirty(dquot);
3080af033b2aSChao Yu
3081af033b2aSChao Yu /* if we are using journalled quota */
3082af033b2aSChao Yu if (is_journalled_quota(sbi))
3083af033b2aSChao Yu set_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH);
3084af033b2aSChao Yu
3085af033b2aSChao Yu return ret;
3086af033b2aSChao Yu }
3087af033b2aSChao Yu
f2fs_dquot_commit_info(struct super_block * sb,int type)3088af033b2aSChao Yu static int f2fs_dquot_commit_info(struct super_block *sb, int type)
3089af033b2aSChao Yu {
3090db6ec53bSJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(sb);
30912c4e0c52SJaegeuk Kim int ret = dquot_commit_info(sb, type);
3092af033b2aSChao Yu
3093af033b2aSChao Yu if (ret < 0)
3094db6ec53bSJaegeuk Kim set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
3095af033b2aSChao Yu return ret;
3096af033b2aSChao Yu }
309726b5a079SSheng Yong
f2fs_get_projid(struct inode * inode,kprojid_t * projid)309894b1e10eSWei Yongjun static int f2fs_get_projid(struct inode *inode, kprojid_t *projid)
30995c57132eSChao Yu {
31005c57132eSChao Yu *projid = F2FS_I(inode)->i_projid;
31015c57132eSChao Yu return 0;
31025c57132eSChao Yu }
31035c57132eSChao Yu
31040abd675eSChao Yu static const struct dquot_operations f2fs_quota_operations = {
31050abd675eSChao Yu .get_reserved_space = f2fs_get_reserved_space,
3106af033b2aSChao Yu .write_dquot = f2fs_dquot_commit,
3107af033b2aSChao Yu .acquire_dquot = f2fs_dquot_acquire,
3108af033b2aSChao Yu .release_dquot = f2fs_dquot_release,
3109af033b2aSChao Yu .mark_dirty = f2fs_dquot_mark_dquot_dirty,
3110af033b2aSChao Yu .write_info = f2fs_dquot_commit_info,
31110abd675eSChao Yu .alloc_dquot = dquot_alloc,
31120abd675eSChao Yu .destroy_dquot = dquot_destroy,
31135c57132eSChao Yu .get_projid = f2fs_get_projid,
31140abd675eSChao Yu .get_next_id = dquot_get_next_id,
31150abd675eSChao Yu };
31160abd675eSChao Yu
31170abd675eSChao Yu static const struct quotactl_ops f2fs_quotactl_ops = {
31180abd675eSChao Yu .quota_on = f2fs_quota_on,
31190abd675eSChao Yu .quota_off = f2fs_quota_off,
31200abd675eSChao Yu .quota_sync = f2fs_quota_sync,
31210abd675eSChao Yu .get_state = dquot_get_state,
31220abd675eSChao Yu .set_info = dquot_set_dqinfo,
31230abd675eSChao Yu .get_dqblk = dquot_get_dqblk,
31240abd675eSChao Yu .set_dqblk = dquot_set_dqblk,
31250abd675eSChao Yu .get_nextdqblk = dquot_get_next_dqblk,
31260abd675eSChao Yu };
31270abd675eSChao Yu #else
f2fs_dquot_initialize(struct inode * inode)312810a26878SChao Yu int f2fs_dquot_initialize(struct inode *inode)
312910a26878SChao Yu {
313010a26878SChao Yu return 0;
313110a26878SChao Yu }
313210a26878SChao Yu
f2fs_quota_sync(struct super_block * sb,int type)3133af033b2aSChao Yu int f2fs_quota_sync(struct super_block *sb, int type)
3134af033b2aSChao Yu {
3135af033b2aSChao Yu return 0;
3136af033b2aSChao Yu }
3137af033b2aSChao Yu
f2fs_quota_off_umount(struct super_block * sb)31384b2414d0SChao Yu void f2fs_quota_off_umount(struct super_block *sb)
31390abd675eSChao Yu {
31400abd675eSChao Yu }
31410abd675eSChao Yu #endif
31420abd675eSChao Yu
3143f62fc9f9SArvind Yadav static const struct super_operations f2fs_sops = {
3144aff063e2SJaegeuk Kim .alloc_inode = f2fs_alloc_inode,
3145d01718a0SAl Viro .free_inode = f2fs_free_inode,
3146531ad7d5SJaegeuk Kim .drop_inode = f2fs_drop_inode,
3147aff063e2SJaegeuk Kim .write_inode = f2fs_write_inode,
3148b3783873SJaegeuk Kim .dirty_inode = f2fs_dirty_inode,
3149aff063e2SJaegeuk Kim .show_options = f2fs_show_options,
31500abd675eSChao Yu #ifdef CONFIG_QUOTA
31510abd675eSChao Yu .quota_read = f2fs_quota_read,
31520abd675eSChao Yu .quota_write = f2fs_quota_write,
31530abd675eSChao Yu .get_dquots = f2fs_get_dquots,
31540abd675eSChao Yu #endif
3155aff063e2SJaegeuk Kim .evict_inode = f2fs_evict_inode,
3156aff063e2SJaegeuk Kim .put_super = f2fs_put_super,
3157aff063e2SJaegeuk Kim .sync_fs = f2fs_sync_fs,
3158d6212a5fSChangman Lee .freeze_fs = f2fs_freeze,
3159d6212a5fSChangman Lee .unfreeze_fs = f2fs_unfreeze,
3160aff063e2SJaegeuk Kim .statfs = f2fs_statfs,
3161696c018cSNamjae Jeon .remount_fs = f2fs_remount,
3162f2971778SChao Yu .shutdown = f2fs_shutdown,
3163aff063e2SJaegeuk Kim };
3164aff063e2SJaegeuk Kim
3165643fa961SChandan Rajendra #ifdef CONFIG_FS_ENCRYPTION
f2fs_get_context(struct inode * inode,void * ctx,size_t len)31660b81d077SJaegeuk Kim static int f2fs_get_context(struct inode *inode, void *ctx, size_t len)
31670b81d077SJaegeuk Kim {
31680b81d077SJaegeuk Kim return f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION,
31690b81d077SJaegeuk Kim F2FS_XATTR_NAME_ENCRYPTION_CONTEXT,
31700b81d077SJaegeuk Kim ctx, len, NULL);
31710b81d077SJaegeuk Kim }
31720b81d077SJaegeuk Kim
f2fs_set_context(struct inode * inode,const void * ctx,size_t len,void * fs_data)31730b81d077SJaegeuk Kim static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len,
31740b81d077SJaegeuk Kim void *fs_data)
31750b81d077SJaegeuk Kim {
3176b7c409deSSheng Yong struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
3177b7c409deSSheng Yong
3178b7c409deSSheng Yong /*
3179b7c409deSSheng Yong * Encrypting the root directory is not allowed because fsck
3180b7c409deSSheng Yong * expects lost+found directory to exist and remain unencrypted
3181b7c409deSSheng Yong * if LOST_FOUND feature is enabled.
3182b7c409deSSheng Yong *
3183b7c409deSSheng Yong */
31847beb01f7SChao Yu if (f2fs_sb_has_lost_found(sbi) &&
3185b7c409deSSheng Yong inode->i_ino == F2FS_ROOT_INO(sbi))
3186b7c409deSSheng Yong return -EPERM;
3187b7c409deSSheng Yong
31880b81d077SJaegeuk Kim return f2fs_setxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION,
31890b81d077SJaegeuk Kim F2FS_XATTR_NAME_ENCRYPTION_CONTEXT,
31900b81d077SJaegeuk Kim ctx, len, fs_data, XATTR_CREATE);
31910b81d077SJaegeuk Kim }
31920b81d077SJaegeuk Kim
f2fs_get_dummy_policy(struct super_block * sb)3193ac4acb1fSEric Biggers static const union fscrypt_policy *f2fs_get_dummy_policy(struct super_block *sb)
3194ff62af20SSheng Yong {
3195ac4acb1fSEric Biggers return F2FS_OPTION(F2FS_SB(sb)).dummy_enc_policy.policy;
3196ff62af20SSheng Yong }
3197ff62af20SSheng Yong
f2fs_has_stable_inodes(struct super_block * sb)31980eee17e3SEric Biggers static bool f2fs_has_stable_inodes(struct super_block *sb)
31990eee17e3SEric Biggers {
32000eee17e3SEric Biggers return true;
32010eee17e3SEric Biggers }
32020eee17e3SEric Biggers
f2fs_get_ino_and_lblk_bits(struct super_block * sb,int * ino_bits_ret,int * lblk_bits_ret)32030eee17e3SEric Biggers static void f2fs_get_ino_and_lblk_bits(struct super_block *sb,
32040eee17e3SEric Biggers int *ino_bits_ret, int *lblk_bits_ret)
32050eee17e3SEric Biggers {
32060eee17e3SEric Biggers *ino_bits_ret = 8 * sizeof(nid_t);
32070eee17e3SEric Biggers *lblk_bits_ret = 8 * sizeof(block_t);
32080eee17e3SEric Biggers }
32090eee17e3SEric Biggers
f2fs_get_devices(struct super_block * sb,unsigned int * num_devs)32100e91fc1eSChristoph Hellwig static struct block_device **f2fs_get_devices(struct super_block *sb,
32110e91fc1eSChristoph Hellwig unsigned int *num_devs)
321227aacd28SSatya Tangirala {
321327aacd28SSatya Tangirala struct f2fs_sb_info *sbi = F2FS_SB(sb);
32140e91fc1eSChristoph Hellwig struct block_device **devs;
321527aacd28SSatya Tangirala int i;
321627aacd28SSatya Tangirala
32170e91fc1eSChristoph Hellwig if (!f2fs_is_multi_device(sbi))
32180e91fc1eSChristoph Hellwig return NULL;
32190e91fc1eSChristoph Hellwig
32200e91fc1eSChristoph Hellwig devs = kmalloc_array(sbi->s_ndevs, sizeof(*devs), GFP_KERNEL);
32210e91fc1eSChristoph Hellwig if (!devs)
32220e91fc1eSChristoph Hellwig return ERR_PTR(-ENOMEM);
32230e91fc1eSChristoph Hellwig
322427aacd28SSatya Tangirala for (i = 0; i < sbi->s_ndevs; i++)
32250e91fc1eSChristoph Hellwig devs[i] = FDEV(i).bdev;
32260e91fc1eSChristoph Hellwig *num_devs = sbi->s_ndevs;
32270e91fc1eSChristoph Hellwig return devs;
322827aacd28SSatya Tangirala }
322927aacd28SSatya Tangirala
32306f69f0edSEric Biggers static const struct fscrypt_operations f2fs_cryptops = {
3231a5d431efSEric Biggers .key_prefix = "f2fs:",
32320b81d077SJaegeuk Kim .get_context = f2fs_get_context,
32330b81d077SJaegeuk Kim .set_context = f2fs_set_context,
3234ac4acb1fSEric Biggers .get_dummy_policy = f2fs_get_dummy_policy,
32350b81d077SJaegeuk Kim .empty_dir = f2fs_empty_dir,
32360eee17e3SEric Biggers .has_stable_inodes = f2fs_has_stable_inodes,
32370eee17e3SEric Biggers .get_ino_and_lblk_bits = f2fs_get_ino_and_lblk_bits,
323827aacd28SSatya Tangirala .get_devices = f2fs_get_devices,
32390b81d077SJaegeuk Kim };
32400b81d077SJaegeuk Kim #endif
32410b81d077SJaegeuk Kim
f2fs_nfs_get_inode(struct super_block * sb,u64 ino,u32 generation)3242aff063e2SJaegeuk Kim static struct inode *f2fs_nfs_get_inode(struct super_block *sb,
3243aff063e2SJaegeuk Kim u64 ino, u32 generation)
3244aff063e2SJaegeuk Kim {
3245aff063e2SJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(sb);
3246aff063e2SJaegeuk Kim struct inode *inode;
3247aff063e2SJaegeuk Kim
32484d57b86dSChao Yu if (f2fs_check_nid_range(sbi, ino))
3249910bb12dSChao Yu return ERR_PTR(-ESTALE);
3250aff063e2SJaegeuk Kim
3251aff063e2SJaegeuk Kim /*
3252aff063e2SJaegeuk Kim * f2fs_iget isn't quite right if the inode is currently unallocated!
3253aff063e2SJaegeuk Kim * However f2fs_iget currently does appropriate checks to handle stale
3254aff063e2SJaegeuk Kim * inodes so everything is OK.
3255aff063e2SJaegeuk Kim */
3256aff063e2SJaegeuk Kim inode = f2fs_iget(sb, ino);
3257aff063e2SJaegeuk Kim if (IS_ERR(inode))
3258aff063e2SJaegeuk Kim return ERR_CAST(inode);
32596bacf52fSJaegeuk Kim if (unlikely(generation && inode->i_generation != generation)) {
3260aff063e2SJaegeuk Kim /* we didn't find the right inode.. */
3261aff063e2SJaegeuk Kim iput(inode);
3262aff063e2SJaegeuk Kim return ERR_PTR(-ESTALE);
3263aff063e2SJaegeuk Kim }
3264aff063e2SJaegeuk Kim return inode;
3265aff063e2SJaegeuk Kim }
3266aff063e2SJaegeuk Kim
f2fs_fh_to_dentry(struct super_block * sb,struct fid * fid,int fh_len,int fh_type)3267aff063e2SJaegeuk Kim static struct dentry *f2fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
3268aff063e2SJaegeuk Kim int fh_len, int fh_type)
3269aff063e2SJaegeuk Kim {
3270aff063e2SJaegeuk Kim return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
3271aff063e2SJaegeuk Kim f2fs_nfs_get_inode);
3272aff063e2SJaegeuk Kim }
3273aff063e2SJaegeuk Kim
f2fs_fh_to_parent(struct super_block * sb,struct fid * fid,int fh_len,int fh_type)3274aff063e2SJaegeuk Kim static struct dentry *f2fs_fh_to_parent(struct super_block *sb, struct fid *fid,
3275aff063e2SJaegeuk Kim int fh_len, int fh_type)
3276aff063e2SJaegeuk Kim {
3277aff063e2SJaegeuk Kim return generic_fh_to_parent(sb, fid, fh_len, fh_type,
3278aff063e2SJaegeuk Kim f2fs_nfs_get_inode);
3279aff063e2SJaegeuk Kim }
3280aff063e2SJaegeuk Kim
3281aff063e2SJaegeuk Kim static const struct export_operations f2fs_export_ops = {
3282aff063e2SJaegeuk Kim .fh_to_dentry = f2fs_fh_to_dentry,
3283aff063e2SJaegeuk Kim .fh_to_parent = f2fs_fh_to_parent,
3284aff063e2SJaegeuk Kim .get_parent = f2fs_get_parent,
3285aff063e2SJaegeuk Kim };
3286aff063e2SJaegeuk Kim
max_file_blocks(struct inode * inode)32876d1451bfSChengguang Xu loff_t max_file_blocks(struct inode *inode)
3288aff063e2SJaegeuk Kim {
32897a2af766SChao Yu loff_t result = 0;
32906d1451bfSChengguang Xu loff_t leaf_count;
3291aff063e2SJaegeuk Kim
32927a2af766SChao Yu /*
32937a2af766SChao Yu * note: previously, result is equal to (DEF_ADDRS_PER_INODE -
32946afc662eSChao Yu * DEFAULT_INLINE_XATTR_ADDRS), but now f2fs try to reserve more
32957a2af766SChao Yu * space in inode.i_addr, it will be more safe to reassign
32967a2af766SChao Yu * result as zero.
32977a2af766SChao Yu */
32987a2af766SChao Yu
32996d1451bfSChengguang Xu if (inode && f2fs_compressed_file(inode))
33006d1451bfSChengguang Xu leaf_count = ADDRS_PER_BLOCK(inode);
33016d1451bfSChengguang Xu else
33026d1451bfSChengguang Xu leaf_count = DEF_ADDRS_PER_BLOCK;
33036d1451bfSChengguang Xu
3304aff063e2SJaegeuk Kim /* two direct node blocks */
3305aff063e2SJaegeuk Kim result += (leaf_count * 2);
3306aff063e2SJaegeuk Kim
3307aff063e2SJaegeuk Kim /* two indirect node blocks */
3308aff063e2SJaegeuk Kim leaf_count *= NIDS_PER_BLOCK;
3309aff063e2SJaegeuk Kim result += (leaf_count * 2);
3310aff063e2SJaegeuk Kim
3311aff063e2SJaegeuk Kim /* one double indirect node block */
3312aff063e2SJaegeuk Kim leaf_count *= NIDS_PER_BLOCK;
3313aff063e2SJaegeuk Kim result += leaf_count;
3314aff063e2SJaegeuk Kim
3315aff063e2SJaegeuk Kim return result;
3316aff063e2SJaegeuk Kim }
3317aff063e2SJaegeuk Kim
__f2fs_commit_super(struct buffer_head * bh,struct f2fs_super_block * super)3318fd694733SJaegeuk Kim static int __f2fs_commit_super(struct buffer_head *bh,
3319fd694733SJaegeuk Kim struct f2fs_super_block *super)
33209a59b62fSChao Yu {
3321fd694733SJaegeuk Kim lock_buffer(bh);
3322fd694733SJaegeuk Kim if (super)
3323fd694733SJaegeuk Kim memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super));
3324fd694733SJaegeuk Kim set_buffer_dirty(bh);
3325fd694733SJaegeuk Kim unlock_buffer(bh);
3326fd694733SJaegeuk Kim
3327fd694733SJaegeuk Kim /* it's rare case, we can do fua all the time */
33283adc5fcbSJan Kara return __sync_dirty_buffer(bh, REQ_SYNC | REQ_PREFLUSH | REQ_FUA);
3329fd694733SJaegeuk Kim }
3330fd694733SJaegeuk Kim
sanity_check_area_boundary(struct f2fs_sb_info * sbi,struct buffer_head * bh)3331df728b0fSJaegeuk Kim static inline bool sanity_check_area_boundary(struct f2fs_sb_info *sbi,
3332fd694733SJaegeuk Kim struct buffer_head *bh)
3333fd694733SJaegeuk Kim {
3334fd694733SJaegeuk Kim struct f2fs_super_block *raw_super = (struct f2fs_super_block *)
3335fd694733SJaegeuk Kim (bh->b_data + F2FS_SUPER_OFFSET);
3336df728b0fSJaegeuk Kim struct super_block *sb = sbi->sb;
33379a59b62fSChao Yu u32 segment0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr);
33389a59b62fSChao Yu u32 cp_blkaddr = le32_to_cpu(raw_super->cp_blkaddr);
33399a59b62fSChao Yu u32 sit_blkaddr = le32_to_cpu(raw_super->sit_blkaddr);
33409a59b62fSChao Yu u32 nat_blkaddr = le32_to_cpu(raw_super->nat_blkaddr);
33419a59b62fSChao Yu u32 ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr);
33429a59b62fSChao Yu u32 main_blkaddr = le32_to_cpu(raw_super->main_blkaddr);
33439a59b62fSChao Yu u32 segment_count_ckpt = le32_to_cpu(raw_super->segment_count_ckpt);
33449a59b62fSChao Yu u32 segment_count_sit = le32_to_cpu(raw_super->segment_count_sit);
33459a59b62fSChao Yu u32 segment_count_nat = le32_to_cpu(raw_super->segment_count_nat);
33469a59b62fSChao Yu u32 segment_count_ssa = le32_to_cpu(raw_super->segment_count_ssa);
33479a59b62fSChao Yu u32 segment_count_main = le32_to_cpu(raw_super->segment_count_main);
33489a59b62fSChao Yu u32 segment_count = le32_to_cpu(raw_super->segment_count);
33499a59b62fSChao Yu u32 log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
3350fd694733SJaegeuk Kim u64 main_end_blkaddr = main_blkaddr +
335156d86516SNikita Zhandarovich ((u64)segment_count_main << log_blocks_per_seg);
3352fd694733SJaegeuk Kim u64 seg_end_blkaddr = segment0_blkaddr +
335356d86516SNikita Zhandarovich ((u64)segment_count << log_blocks_per_seg);
33549a59b62fSChao Yu
33559a59b62fSChao Yu if (segment0_blkaddr != cp_blkaddr) {
3356dcbb4c10SJoe Perches f2fs_info(sbi, "Mismatch start address, segment0(%u) cp_blkaddr(%u)",
33579a59b62fSChao Yu segment0_blkaddr, cp_blkaddr);
33589a59b62fSChao Yu return true;
33599a59b62fSChao Yu }
33609a59b62fSChao Yu
33619a59b62fSChao Yu if (cp_blkaddr + (segment_count_ckpt << log_blocks_per_seg) !=
33629a59b62fSChao Yu sit_blkaddr) {
3363dcbb4c10SJoe Perches f2fs_info(sbi, "Wrong CP boundary, start(%u) end(%u) blocks(%u)",
33649a59b62fSChao Yu cp_blkaddr, sit_blkaddr,
33659a59b62fSChao Yu segment_count_ckpt << log_blocks_per_seg);
33669a59b62fSChao Yu return true;
33679a59b62fSChao Yu }
33689a59b62fSChao Yu
33699a59b62fSChao Yu if (sit_blkaddr + (segment_count_sit << log_blocks_per_seg) !=
33709a59b62fSChao Yu nat_blkaddr) {
3371dcbb4c10SJoe Perches f2fs_info(sbi, "Wrong SIT boundary, start(%u) end(%u) blocks(%u)",
33729a59b62fSChao Yu sit_blkaddr, nat_blkaddr,
33739a59b62fSChao Yu segment_count_sit << log_blocks_per_seg);
33749a59b62fSChao Yu return true;
33759a59b62fSChao Yu }
33769a59b62fSChao Yu
33779a59b62fSChao Yu if (nat_blkaddr + (segment_count_nat << log_blocks_per_seg) !=
33789a59b62fSChao Yu ssa_blkaddr) {
3379dcbb4c10SJoe Perches f2fs_info(sbi, "Wrong NAT boundary, start(%u) end(%u) blocks(%u)",
33809a59b62fSChao Yu nat_blkaddr, ssa_blkaddr,
33819a59b62fSChao Yu segment_count_nat << log_blocks_per_seg);
33829a59b62fSChao Yu return true;
33839a59b62fSChao Yu }
33849a59b62fSChao Yu
33859a59b62fSChao Yu if (ssa_blkaddr + (segment_count_ssa << log_blocks_per_seg) !=
33869a59b62fSChao Yu main_blkaddr) {
3387dcbb4c10SJoe Perches f2fs_info(sbi, "Wrong SSA boundary, start(%u) end(%u) blocks(%u)",
33889a59b62fSChao Yu ssa_blkaddr, main_blkaddr,
33899a59b62fSChao Yu segment_count_ssa << log_blocks_per_seg);
33909a59b62fSChao Yu return true;
33919a59b62fSChao Yu }
33929a59b62fSChao Yu
3393fd694733SJaegeuk Kim if (main_end_blkaddr > seg_end_blkaddr) {
3394d89f5891SWang Xiaojun f2fs_info(sbi, "Wrong MAIN_AREA boundary, start(%u) end(%llu) block(%u)",
3395d89f5891SWang Xiaojun main_blkaddr, seg_end_blkaddr,
33969a59b62fSChao Yu segment_count_main << log_blocks_per_seg);
33979a59b62fSChao Yu return true;
3398fd694733SJaegeuk Kim } else if (main_end_blkaddr < seg_end_blkaddr) {
3399fd694733SJaegeuk Kim int err = 0;
3400fd694733SJaegeuk Kim char *res;
34019a59b62fSChao Yu
3402fd694733SJaegeuk Kim /* fix in-memory information all the time */
3403fd694733SJaegeuk Kim raw_super->segment_count = cpu_to_le32((main_end_blkaddr -
3404fd694733SJaegeuk Kim segment0_blkaddr) >> log_blocks_per_seg);
3405fd694733SJaegeuk Kim
340668f0453dSChao Yu if (f2fs_readonly(sb) || f2fs_hw_is_readonly(sbi)) {
3407df728b0fSJaegeuk Kim set_sbi_flag(sbi, SBI_NEED_SB_WRITE);
3408fd694733SJaegeuk Kim res = "internally";
3409fd694733SJaegeuk Kim } else {
3410fd694733SJaegeuk Kim err = __f2fs_commit_super(bh, NULL);
3411fd694733SJaegeuk Kim res = err ? "failed" : "done";
3412fd694733SJaegeuk Kim }
3413d89f5891SWang Xiaojun f2fs_info(sbi, "Fix alignment : %s, start(%u) end(%llu) block(%u)",
3414d89f5891SWang Xiaojun res, main_blkaddr, seg_end_blkaddr,
3415fd694733SJaegeuk Kim segment_count_main << log_blocks_per_seg);
3416fd694733SJaegeuk Kim if (err)
3417fd694733SJaegeuk Kim return true;
3418fd694733SJaegeuk Kim }
34199a59b62fSChao Yu return false;
34209a59b62fSChao Yu }
34219a59b62fSChao Yu
sanity_check_raw_super(struct f2fs_sb_info * sbi,struct buffer_head * bh)3422df728b0fSJaegeuk Kim static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
3423fd694733SJaegeuk Kim struct buffer_head *bh)
3424aff063e2SJaegeuk Kim {
3425f99ba9adSWang Xiaojun block_t segment_count, segs_per_sec, secs_per_zone, segment_count_main;
34260cfe75c5SJaegeuk Kim block_t total_sections, blocks_per_seg;
3427fd694733SJaegeuk Kim struct f2fs_super_block *raw_super = (struct f2fs_super_block *)
3428fd694733SJaegeuk Kim (bh->b_data + F2FS_SUPER_OFFSET);
3429d440c52dSJunling Zheng size_t crc_offset = 0;
3430d440c52dSJunling Zheng __u32 crc = 0;
3431d440c52dSJunling Zheng
343238fb6d0eSIcenowy Zheng if (le32_to_cpu(raw_super->magic) != F2FS_SUPER_MAGIC) {
343338fb6d0eSIcenowy Zheng f2fs_info(sbi, "Magic Mismatch, valid(0x%x) - read(0x%x)",
343438fb6d0eSIcenowy Zheng F2FS_SUPER_MAGIC, le32_to_cpu(raw_super->magic));
343538fb6d0eSIcenowy Zheng return -EINVAL;
343638fb6d0eSIcenowy Zheng }
343738fb6d0eSIcenowy Zheng
3438d440c52dSJunling Zheng /* Check checksum_offset and crc in superblock */
34397beb01f7SChao Yu if (__F2FS_HAS_FEATURE(raw_super, F2FS_FEATURE_SB_CHKSUM)) {
3440d440c52dSJunling Zheng crc_offset = le32_to_cpu(raw_super->checksum_offset);
3441d440c52dSJunling Zheng if (crc_offset !=
3442d440c52dSJunling Zheng offsetof(struct f2fs_super_block, crc)) {
3443dcbb4c10SJoe Perches f2fs_info(sbi, "Invalid SB checksum offset: %zu",
3444d440c52dSJunling Zheng crc_offset);
344538fb6d0eSIcenowy Zheng return -EFSCORRUPTED;
3446d440c52dSJunling Zheng }
3447d440c52dSJunling Zheng crc = le32_to_cpu(raw_super->crc);
3448d440c52dSJunling Zheng if (!f2fs_crc_valid(sbi, crc, raw_super, crc_offset)) {
3449dcbb4c10SJoe Perches f2fs_info(sbi, "Invalid SB checksum value: %u", crc);
345038fb6d0eSIcenowy Zheng return -EFSCORRUPTED;
3451d440c52dSJunling Zheng }
3452d440c52dSJunling Zheng }
3453aff063e2SJaegeuk Kim
3454aff063e2SJaegeuk Kim /* Currently, support only 4KB block size */
3455e584bbe8SChao Yu if (le32_to_cpu(raw_super->log_blocksize) != F2FS_BLKSIZE_BITS) {
3456e584bbe8SChao Yu f2fs_info(sbi, "Invalid log_blocksize (%u), supports only %u",
3457e584bbe8SChao Yu le32_to_cpu(raw_super->log_blocksize),
3458e584bbe8SChao Yu F2FS_BLKSIZE_BITS);
345938fb6d0eSIcenowy Zheng return -EFSCORRUPTED;
3460a07ef784SNamjae Jeon }
34615c9b4692Smajianpeng
34629a59b62fSChao Yu /* check log blocks per segment */
34639a59b62fSChao Yu if (le32_to_cpu(raw_super->log_blocks_per_seg) != 9) {
3464dcbb4c10SJoe Perches f2fs_info(sbi, "Invalid log blocks per segment (%u)",
34659a59b62fSChao Yu le32_to_cpu(raw_super->log_blocks_per_seg));
346638fb6d0eSIcenowy Zheng return -EFSCORRUPTED;
34679a59b62fSChao Yu }
34689a59b62fSChao Yu
346955cf9cb6SChao Yu /* Currently, support 512/1024/2048/4096 bytes sector size */
347055cf9cb6SChao Yu if (le32_to_cpu(raw_super->log_sectorsize) >
347155cf9cb6SChao Yu F2FS_MAX_LOG_SECTOR_SIZE ||
347255cf9cb6SChao Yu le32_to_cpu(raw_super->log_sectorsize) <
347355cf9cb6SChao Yu F2FS_MIN_LOG_SECTOR_SIZE) {
3474dcbb4c10SJoe Perches f2fs_info(sbi, "Invalid log sectorsize (%u)",
347555cf9cb6SChao Yu le32_to_cpu(raw_super->log_sectorsize));
347638fb6d0eSIcenowy Zheng return -EFSCORRUPTED;
3477a07ef784SNamjae Jeon }
347855cf9cb6SChao Yu if (le32_to_cpu(raw_super->log_sectors_per_block) +
347955cf9cb6SChao Yu le32_to_cpu(raw_super->log_sectorsize) !=
348055cf9cb6SChao Yu F2FS_MAX_LOG_SECTOR_SIZE) {
3481dcbb4c10SJoe Perches f2fs_info(sbi, "Invalid log sectors per block(%u) log sectorsize(%u)",
348255cf9cb6SChao Yu le32_to_cpu(raw_super->log_sectors_per_block),
348355cf9cb6SChao Yu le32_to_cpu(raw_super->log_sectorsize));
348438fb6d0eSIcenowy Zheng return -EFSCORRUPTED;
3485a07ef784SNamjae Jeon }
34869a59b62fSChao Yu
34870cfe75c5SJaegeuk Kim segment_count = le32_to_cpu(raw_super->segment_count);
3488f99ba9adSWang Xiaojun segment_count_main = le32_to_cpu(raw_super->segment_count_main);
34890cfe75c5SJaegeuk Kim segs_per_sec = le32_to_cpu(raw_super->segs_per_sec);
34900cfe75c5SJaegeuk Kim secs_per_zone = le32_to_cpu(raw_super->secs_per_zone);
34910cfe75c5SJaegeuk Kim total_sections = le32_to_cpu(raw_super->section_count);
34920cfe75c5SJaegeuk Kim
34930cfe75c5SJaegeuk Kim /* blocks_per_seg should be 512, given the above check */
3494447286ebSYangtao Li blocks_per_seg = BIT(le32_to_cpu(raw_super->log_blocks_per_seg));
34950cfe75c5SJaegeuk Kim
34960cfe75c5SJaegeuk Kim if (segment_count > F2FS_MAX_SEGMENT ||
34970cfe75c5SJaegeuk Kim segment_count < F2FS_MIN_SEGMENTS) {
3498dcbb4c10SJoe Perches f2fs_info(sbi, "Invalid segment count (%u)", segment_count);
349938fb6d0eSIcenowy Zheng return -EFSCORRUPTED;
35000cfe75c5SJaegeuk Kim }
35010cfe75c5SJaegeuk Kim
3502f99ba9adSWang Xiaojun if (total_sections > segment_count_main || total_sections < 1 ||
35030cfe75c5SJaegeuk Kim segs_per_sec > segment_count || !segs_per_sec) {
3504dcbb4c10SJoe Perches f2fs_info(sbi, "Invalid segment/section count (%u, %u x %u)",
35050cfe75c5SJaegeuk Kim segment_count, total_sections, segs_per_sec);
350638fb6d0eSIcenowy Zheng return -EFSCORRUPTED;
35070cfe75c5SJaegeuk Kim }
35080cfe75c5SJaegeuk Kim
35093a22e9acSChao Yu if (segment_count_main != total_sections * segs_per_sec) {
35103a22e9acSChao Yu f2fs_info(sbi, "Invalid segment/section count (%u != %u * %u)",
35113a22e9acSChao Yu segment_count_main, total_sections, segs_per_sec);
35123a22e9acSChao Yu return -EFSCORRUPTED;
35133a22e9acSChao Yu }
35143a22e9acSChao Yu
35150cfe75c5SJaegeuk Kim if ((segment_count / segs_per_sec) < total_sections) {
3516dcbb4c10SJoe Perches f2fs_info(sbi, "Small segment_count (%u < %u * %u)",
35170cfe75c5SJaegeuk Kim segment_count, segs_per_sec, total_sections);
351838fb6d0eSIcenowy Zheng return -EFSCORRUPTED;
35190cfe75c5SJaegeuk Kim }
35200cfe75c5SJaegeuk Kim
352188960068SMartin Blumenstingl if (segment_count > (le64_to_cpu(raw_super->block_count) >> 9)) {
3522dcbb4c10SJoe Perches f2fs_info(sbi, "Wrong segment_count / block_count (%u > %llu)",
352388960068SMartin Blumenstingl segment_count, le64_to_cpu(raw_super->block_count));
352438fb6d0eSIcenowy Zheng return -EFSCORRUPTED;
35250cfe75c5SJaegeuk Kim }
35260cfe75c5SJaegeuk Kim
35279f701f6cSQiuyang Sun if (RDEV(0).path[0]) {
35289f701f6cSQiuyang Sun block_t dev_seg_count = le32_to_cpu(RDEV(0).total_segments);
35299f701f6cSQiuyang Sun int i = 1;
35309f701f6cSQiuyang Sun
35319f701f6cSQiuyang Sun while (i < MAX_DEVICES && RDEV(i).path[0]) {
35329f701f6cSQiuyang Sun dev_seg_count += le32_to_cpu(RDEV(i).total_segments);
35339f701f6cSQiuyang Sun i++;
35349f701f6cSQiuyang Sun }
35359f701f6cSQiuyang Sun if (segment_count != dev_seg_count) {
35369f701f6cSQiuyang Sun f2fs_info(sbi, "Segment count (%u) mismatch with total segments from devices (%u)",
35379f701f6cSQiuyang Sun segment_count, dev_seg_count);
35389f701f6cSQiuyang Sun return -EFSCORRUPTED;
35399f701f6cSQiuyang Sun }
354007eb1d69SChao Yu } else {
354107eb1d69SChao Yu if (__F2FS_HAS_FEATURE(raw_super, F2FS_FEATURE_BLKZONED) &&
354207eb1d69SChao Yu !bdev_is_zoned(sbi->sb->s_bdev)) {
354307eb1d69SChao Yu f2fs_info(sbi, "Zoned block device path is missing");
354407eb1d69SChao Yu return -EFSCORRUPTED;
354507eb1d69SChao Yu }
35469f701f6cSQiuyang Sun }
35479f701f6cSQiuyang Sun
354842bf546cSChao Yu if (secs_per_zone > total_sections || !secs_per_zone) {
3549dcbb4c10SJoe Perches f2fs_info(sbi, "Wrong secs_per_zone / total_sections (%u, %u)",
35500cfe75c5SJaegeuk Kim secs_per_zone, total_sections);
355138fb6d0eSIcenowy Zheng return -EFSCORRUPTED;
35520cfe75c5SJaegeuk Kim }
35530cfe75c5SJaegeuk Kim if (le32_to_cpu(raw_super->extension_count) > F2FS_MAX_EXTENSION ||
35540cfe75c5SJaegeuk Kim raw_super->hot_ext_count > F2FS_MAX_EXTENSION ||
35550cfe75c5SJaegeuk Kim (le32_to_cpu(raw_super->extension_count) +
35560cfe75c5SJaegeuk Kim raw_super->hot_ext_count) > F2FS_MAX_EXTENSION) {
3557dcbb4c10SJoe Perches f2fs_info(sbi, "Corrupted extension count (%u + %u > %u)",
35580cfe75c5SJaegeuk Kim le32_to_cpu(raw_super->extension_count),
35590cfe75c5SJaegeuk Kim raw_super->hot_ext_count,
35600cfe75c5SJaegeuk Kim F2FS_MAX_EXTENSION);
356138fb6d0eSIcenowy Zheng return -EFSCORRUPTED;
35620cfe75c5SJaegeuk Kim }
35630cfe75c5SJaegeuk Kim
356465ddf656SChao Yu if (le32_to_cpu(raw_super->cp_payload) >=
356565ddf656SChao Yu (blocks_per_seg - F2FS_CP_PACKS -
356665ddf656SChao Yu NR_CURSEG_PERSIST_TYPE)) {
356765ddf656SChao Yu f2fs_info(sbi, "Insane cp_payload (%u >= %u)",
35680cfe75c5SJaegeuk Kim le32_to_cpu(raw_super->cp_payload),
356965ddf656SChao Yu blocks_per_seg - F2FS_CP_PACKS -
357065ddf656SChao Yu NR_CURSEG_PERSIST_TYPE);
357138fb6d0eSIcenowy Zheng return -EFSCORRUPTED;
35720cfe75c5SJaegeuk Kim }
35730cfe75c5SJaegeuk Kim
35749a59b62fSChao Yu /* check reserved ino info */
35759a59b62fSChao Yu if (le32_to_cpu(raw_super->node_ino) != 1 ||
35769a59b62fSChao Yu le32_to_cpu(raw_super->meta_ino) != 2 ||
35779a59b62fSChao Yu le32_to_cpu(raw_super->root_ino) != 3) {
3578dcbb4c10SJoe Perches f2fs_info(sbi, "Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)",
35799a59b62fSChao Yu le32_to_cpu(raw_super->node_ino),
35809a59b62fSChao Yu le32_to_cpu(raw_super->meta_ino),
35819a59b62fSChao Yu le32_to_cpu(raw_super->root_ino));
358238fb6d0eSIcenowy Zheng return -EFSCORRUPTED;
35839a59b62fSChao Yu }
35849a59b62fSChao Yu
35859a59b62fSChao Yu /* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */
3586df728b0fSJaegeuk Kim if (sanity_check_area_boundary(sbi, bh))
358738fb6d0eSIcenowy Zheng return -EFSCORRUPTED;
35889a59b62fSChao Yu
3589aff063e2SJaegeuk Kim return 0;
3590aff063e2SJaegeuk Kim }
3591aff063e2SJaegeuk Kim
f2fs_sanity_check_ckpt(struct f2fs_sb_info * sbi)35924d57b86dSChao Yu int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
3593aff063e2SJaegeuk Kim {
3594aff063e2SJaegeuk Kim unsigned int total, fsmeta;
3595577e3495SJaegeuk Kim struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
3596577e3495SJaegeuk Kim struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
35972040fce8SJaegeuk Kim unsigned int ovp_segments, reserved_segments;
359815d3042aSJin Qian unsigned int main_segs, blocks_per_seg;
3599c77ec61cSChao Yu unsigned int sit_segs, nat_segs;
3600c77ec61cSChao Yu unsigned int sit_bitmap_size, nat_bitmap_size;
3601c77ec61cSChao Yu unsigned int log_blocks_per_seg;
36029dc956b2SChao Yu unsigned int segment_count_main;
3603e494c2f9SChao Yu unsigned int cp_pack_start_sum, cp_payload;
36047b63f72fSChao Yu block_t user_block_count, valid_user_blocks;
36057b63f72fSChao Yu block_t avail_node_count, valid_node_count;
360665ddf656SChao Yu unsigned int nat_blocks, nat_bits_bytes, nat_bits_blocks;
3607042be0f8SChao Yu int i, j;
3608aff063e2SJaegeuk Kim
3609aff063e2SJaegeuk Kim total = le32_to_cpu(raw_super->segment_count);
3610aff063e2SJaegeuk Kim fsmeta = le32_to_cpu(raw_super->segment_count_ckpt);
3611c77ec61cSChao Yu sit_segs = le32_to_cpu(raw_super->segment_count_sit);
3612c77ec61cSChao Yu fsmeta += sit_segs;
3613c77ec61cSChao Yu nat_segs = le32_to_cpu(raw_super->segment_count_nat);
3614c77ec61cSChao Yu fsmeta += nat_segs;
3615aff063e2SJaegeuk Kim fsmeta += le32_to_cpu(ckpt->rsvd_segment_count);
3616aff063e2SJaegeuk Kim fsmeta += le32_to_cpu(raw_super->segment_count_ssa);
3617aff063e2SJaegeuk Kim
36186bacf52fSJaegeuk Kim if (unlikely(fsmeta >= total))
3619aff063e2SJaegeuk Kim return 1;
3620577e3495SJaegeuk Kim
36212040fce8SJaegeuk Kim ovp_segments = le32_to_cpu(ckpt->overprov_segment_count);
36222040fce8SJaegeuk Kim reserved_segments = le32_to_cpu(ckpt->rsvd_segment_count);
36232040fce8SJaegeuk Kim
3624a7d9fe3cSJaegeuk Kim if (!f2fs_sb_has_readonly(sbi) &&
3625a7d9fe3cSJaegeuk Kim unlikely(fsmeta < F2FS_MIN_META_SEGMENTS ||
36262040fce8SJaegeuk Kim ovp_segments == 0 || reserved_segments == 0)) {
3627dcbb4c10SJoe Perches f2fs_err(sbi, "Wrong layout: check mkfs.f2fs version");
36282040fce8SJaegeuk Kim return 1;
36292040fce8SJaegeuk Kim }
36309dc956b2SChao Yu user_block_count = le64_to_cpu(ckpt->user_block_count);
3631a7d9fe3cSJaegeuk Kim segment_count_main = le32_to_cpu(raw_super->segment_count_main) +
3632a7d9fe3cSJaegeuk Kim (f2fs_sb_has_readonly(sbi) ? 1 : 0);
36339dc956b2SChao Yu log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
36349dc956b2SChao Yu if (!user_block_count || user_block_count >=
36359dc956b2SChao Yu segment_count_main << log_blocks_per_seg) {
3636dcbb4c10SJoe Perches f2fs_err(sbi, "Wrong user_block_count: %u",
3637dcbb4c10SJoe Perches user_block_count);
36389dc956b2SChao Yu return 1;
36399dc956b2SChao Yu }
36409dc956b2SChao Yu
36417b63f72fSChao Yu valid_user_blocks = le64_to_cpu(ckpt->valid_block_count);
36427b63f72fSChao Yu if (valid_user_blocks > user_block_count) {
3643dcbb4c10SJoe Perches f2fs_err(sbi, "Wrong valid_user_blocks: %u, user_block_count: %u",
36447b63f72fSChao Yu valid_user_blocks, user_block_count);
36457b63f72fSChao Yu return 1;
36467b63f72fSChao Yu }
36477b63f72fSChao Yu
36487b63f72fSChao Yu valid_node_count = le32_to_cpu(ckpt->valid_node_count);
364927cae0bcSChao Yu avail_node_count = sbi->total_node_count - F2FS_RESERVED_NODE_NUM;
36507b63f72fSChao Yu if (valid_node_count > avail_node_count) {
3651dcbb4c10SJoe Perches f2fs_err(sbi, "Wrong valid_node_count: %u, avail_node_count: %u",
36527b63f72fSChao Yu valid_node_count, avail_node_count);
36537b63f72fSChao Yu return 1;
36547b63f72fSChao Yu }
36557b63f72fSChao Yu
365615d3042aSJin Qian main_segs = le32_to_cpu(raw_super->segment_count_main);
3657f0248ba6SJaegeuk Kim blocks_per_seg = BLKS_PER_SEG(sbi);
365815d3042aSJin Qian
365915d3042aSJin Qian for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) {
366015d3042aSJin Qian if (le32_to_cpu(ckpt->cur_node_segno[i]) >= main_segs ||
366115d3042aSJin Qian le16_to_cpu(ckpt->cur_node_blkoff[i]) >= blocks_per_seg)
366215d3042aSJin Qian return 1;
3663a7d9fe3cSJaegeuk Kim
3664a7d9fe3cSJaegeuk Kim if (f2fs_sb_has_readonly(sbi))
3665a7d9fe3cSJaegeuk Kim goto check_data;
3666a7d9fe3cSJaegeuk Kim
3667042be0f8SChao Yu for (j = i + 1; j < NR_CURSEG_NODE_TYPE; j++) {
3668042be0f8SChao Yu if (le32_to_cpu(ckpt->cur_node_segno[i]) ==
3669042be0f8SChao Yu le32_to_cpu(ckpt->cur_node_segno[j])) {
3670dcbb4c10SJoe Perches f2fs_err(sbi, "Node segment (%u, %u) has the same segno: %u",
3671dcbb4c10SJoe Perches i, j,
3672042be0f8SChao Yu le32_to_cpu(ckpt->cur_node_segno[i]));
3673042be0f8SChao Yu return 1;
3674042be0f8SChao Yu }
3675042be0f8SChao Yu }
367615d3042aSJin Qian }
3677a7d9fe3cSJaegeuk Kim check_data:
367815d3042aSJin Qian for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) {
367915d3042aSJin Qian if (le32_to_cpu(ckpt->cur_data_segno[i]) >= main_segs ||
368015d3042aSJin Qian le16_to_cpu(ckpt->cur_data_blkoff[i]) >= blocks_per_seg)
368115d3042aSJin Qian return 1;
3682a7d9fe3cSJaegeuk Kim
3683a7d9fe3cSJaegeuk Kim if (f2fs_sb_has_readonly(sbi))
3684a7d9fe3cSJaegeuk Kim goto skip_cross;
3685a7d9fe3cSJaegeuk Kim
3686042be0f8SChao Yu for (j = i + 1; j < NR_CURSEG_DATA_TYPE; j++) {
3687042be0f8SChao Yu if (le32_to_cpu(ckpt->cur_data_segno[i]) ==
3688042be0f8SChao Yu le32_to_cpu(ckpt->cur_data_segno[j])) {
3689dcbb4c10SJoe Perches f2fs_err(sbi, "Data segment (%u, %u) has the same segno: %u",
3690dcbb4c10SJoe Perches i, j,
3691042be0f8SChao Yu le32_to_cpu(ckpt->cur_data_segno[i]));
3692042be0f8SChao Yu return 1;
3693042be0f8SChao Yu }
3694042be0f8SChao Yu }
3695042be0f8SChao Yu }
3696042be0f8SChao Yu for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) {
36971166c1f2SSurbhi Palande for (j = 0; j < NR_CURSEG_DATA_TYPE; j++) {
3698042be0f8SChao Yu if (le32_to_cpu(ckpt->cur_node_segno[i]) ==
3699042be0f8SChao Yu le32_to_cpu(ckpt->cur_data_segno[j])) {
37001166c1f2SSurbhi Palande f2fs_err(sbi, "Node segment (%u) and Data segment (%u) has the same segno: %u",
3701dcbb4c10SJoe Perches i, j,
3702042be0f8SChao Yu le32_to_cpu(ckpt->cur_node_segno[i]));
3703042be0f8SChao Yu return 1;
3704042be0f8SChao Yu }
3705042be0f8SChao Yu }
370615d3042aSJin Qian }
3707a7d9fe3cSJaegeuk Kim skip_cross:
3708c77ec61cSChao Yu sit_bitmap_size = le32_to_cpu(ckpt->sit_ver_bitmap_bytesize);
3709c77ec61cSChao Yu nat_bitmap_size = le32_to_cpu(ckpt->nat_ver_bitmap_bytesize);
3710c77ec61cSChao Yu
3711c77ec61cSChao Yu if (sit_bitmap_size != ((sit_segs / 2) << log_blocks_per_seg) / 8 ||
3712c77ec61cSChao Yu nat_bitmap_size != ((nat_segs / 2) << log_blocks_per_seg) / 8) {
3713dcbb4c10SJoe Perches f2fs_err(sbi, "Wrong bitmap size: sit: %u, nat:%u",
3714c77ec61cSChao Yu sit_bitmap_size, nat_bitmap_size);
3715c77ec61cSChao Yu return 1;
3716c77ec61cSChao Yu }
3717c77ec61cSChao Yu
3718e494c2f9SChao Yu cp_pack_start_sum = __start_sum_addr(sbi);
3719e494c2f9SChao Yu cp_payload = __cp_payload(sbi);
3720e494c2f9SChao Yu if (cp_pack_start_sum < cp_payload + 1 ||
3721e494c2f9SChao Yu cp_pack_start_sum > blocks_per_seg - 1 -
3722d0b9e42aSChao Yu NR_CURSEG_PERSIST_TYPE) {
3723dcbb4c10SJoe Perches f2fs_err(sbi, "Wrong cp_pack_start_sum: %u",
3724e494c2f9SChao Yu cp_pack_start_sum);
3725e494c2f9SChao Yu return 1;
3726e494c2f9SChao Yu }
3727e494c2f9SChao Yu
37285dae2d39SChao Yu if (__is_set_ckpt_flags(ckpt, CP_LARGE_NAT_BITMAP_FLAG) &&
37295dae2d39SChao Yu le32_to_cpu(ckpt->checksum_offset) != CP_MIN_CHKSUM_OFFSET) {
37302d008835SChao Yu f2fs_warn(sbi, "using deprecated layout of large_nat_bitmap, "
37312d008835SChao Yu "please run fsck v1.13.0 or higher to repair, chksum_offset: %u, "
37322d008835SChao Yu "fixed with patch: \"f2fs-tools: relocate chksum_offset for large_nat_bitmap feature\"",
37335dae2d39SChao Yu le32_to_cpu(ckpt->checksum_offset));
37345dae2d39SChao Yu return 1;
37355dae2d39SChao Yu }
37365dae2d39SChao Yu
373765ddf656SChao Yu nat_blocks = nat_segs << log_blocks_per_seg;
373865ddf656SChao Yu nat_bits_bytes = nat_blocks / BITS_PER_BYTE;
373965ddf656SChao Yu nat_bits_blocks = F2FS_BLK_ALIGN((nat_bits_bytes << 1) + 8);
374065ddf656SChao Yu if (__is_set_ckpt_flags(ckpt, CP_NAT_BITS_FLAG) &&
374165ddf656SChao Yu (cp_payload + F2FS_CP_PACKS +
374265ddf656SChao Yu NR_CURSEG_PERSIST_TYPE + nat_bits_blocks >= blocks_per_seg)) {
374365ddf656SChao Yu f2fs_warn(sbi, "Insane cp_payload: %u, nat_bits_blocks: %u)",
374465ddf656SChao Yu cp_payload, nat_bits_blocks);
3745ca98d721SChao Yu return 1;
374665ddf656SChao Yu }
374765ddf656SChao Yu
37481e968fdfSJaegeuk Kim if (unlikely(f2fs_cp_error(sbi))) {
3749dcbb4c10SJoe Perches f2fs_err(sbi, "A bug case: need to run fsck");
3750577e3495SJaegeuk Kim return 1;
3751577e3495SJaegeuk Kim }
3752aff063e2SJaegeuk Kim return 0;
3753aff063e2SJaegeuk Kim }
3754aff063e2SJaegeuk Kim
init_sb_info(struct f2fs_sb_info * sbi)3755aff063e2SJaegeuk Kim static void init_sb_info(struct f2fs_sb_info *sbi)
3756aff063e2SJaegeuk Kim {
3757aff063e2SJaegeuk Kim struct f2fs_super_block *raw_super = sbi->raw_super;
3758089842deSYunlong Song int i;
3759aff063e2SJaegeuk Kim
3760aff063e2SJaegeuk Kim sbi->log_sectors_per_block =
3761aff063e2SJaegeuk Kim le32_to_cpu(raw_super->log_sectors_per_block);
3762aff063e2SJaegeuk Kim sbi->log_blocksize = le32_to_cpu(raw_super->log_blocksize);
3763447286ebSYangtao Li sbi->blocksize = BIT(sbi->log_blocksize);
3764aff063e2SJaegeuk Kim sbi->log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
3765447286ebSYangtao Li sbi->blocks_per_seg = BIT(sbi->log_blocks_per_seg);
3766aff063e2SJaegeuk Kim sbi->segs_per_sec = le32_to_cpu(raw_super->segs_per_sec);
3767aff063e2SJaegeuk Kim sbi->secs_per_zone = le32_to_cpu(raw_super->secs_per_zone);
3768aff063e2SJaegeuk Kim sbi->total_sections = le32_to_cpu(raw_super->section_count);
3769aff063e2SJaegeuk Kim sbi->total_node_count =
3770f0248ba6SJaegeuk Kim ((le32_to_cpu(raw_super->segment_count_nat) / 2) *
3771f0248ba6SJaegeuk Kim NAT_ENTRY_PER_BLOCK) << sbi->log_blocks_per_seg;
3772b9ec1094SYangtao Li F2FS_ROOT_INO(sbi) = le32_to_cpu(raw_super->root_ino);
3773b9ec1094SYangtao Li F2FS_NODE_INO(sbi) = le32_to_cpu(raw_super->node_ino);
3774b9ec1094SYangtao Li F2FS_META_INO(sbi) = le32_to_cpu(raw_super->meta_ino);
37755ec4e49fSJaegeuk Kim sbi->cur_victim_sec = NULL_SECNO;
3776c86868bbSChao Yu sbi->gc_mode = GC_NORMAL;
3777e3080b01SChao Yu sbi->next_victim_seg[BG_GC] = NULL_SEGNO;
3778e3080b01SChao Yu sbi->next_victim_seg[FG_GC] = NULL_SEGNO;
3779b1c57c1cSJaegeuk Kim sbi->max_victim_search = DEF_MAX_VICTIM_SEARCH;
3780f0248ba6SJaegeuk Kim sbi->migration_granularity = SEGS_PER_SEC(sbi);
37810f6b56ecSDaeho Jeong sbi->seq_file_ra_mul = MIN_RA_MUL;
37826691d940SDaeho Jeong sbi->max_fragment_chunk = DEF_FRAGMENT_SIZE;
37836691d940SDaeho Jeong sbi->max_fragment_hole = DEF_FRAGMENT_SIZE;
3784e5a0db6aSYangtao Li spin_lock_init(&sbi->gc_remaining_trials_lock);
3785f8e2f32bSDaeho Jeong atomic64_set(&sbi->current_atomic_write, 0);
3786aff063e2SJaegeuk Kim
3787ab9fa662SJaegeuk Kim sbi->dir_level = DEF_DIR_LEVEL;
37886beceb54SJaegeuk Kim sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL;
3789d0239e1bSJaegeuk Kim sbi->interval_time[REQ_TIME] = DEF_IDLE_INTERVAL;
3790a7d10cf3SSahitya Tummala sbi->interval_time[DISCARD_TIME] = DEF_IDLE_INTERVAL;
3791a7d10cf3SSahitya Tummala sbi->interval_time[GC_TIME] = DEF_IDLE_INTERVAL;
37924354994fSDaniel Rosenberg sbi->interval_time[DISABLE_TIME] = DEF_DISABLE_INTERVAL;
379303f2c02dSJaegeuk Kim sbi->interval_time[UMOUNT_DISCARD_TIMEOUT] =
379403f2c02dSJaegeuk Kim DEF_UMOUNT_DISCARD_TIMEOUT;
3795caf0047eSChao Yu clear_sbi_flag(sbi, SBI_NEED_FSCK);
37962658e50dSJaegeuk Kim
379735782b23SJaegeuk Kim for (i = 0; i < NR_COUNT_TYPE; i++)
379835782b23SJaegeuk Kim atomic_set(&sbi->nr_pages[i], 0);
379935782b23SJaegeuk Kim
3800c29fd0c0SChao Yu for (i = 0; i < META; i++)
3801c29fd0c0SChao Yu atomic_set(&sbi->wb_sync_req[i], 0);
3802687de7f1SJaegeuk Kim
38032658e50dSJaegeuk Kim INIT_LIST_HEAD(&sbi->s_list);
38042658e50dSJaegeuk Kim mutex_init(&sbi->umount_mutex);
3805e4544b63STim Murray init_f2fs_rwsem(&sbi->io_order_lock);
3806aaec2b1dSChao Yu spin_lock_init(&sbi->cp_lock);
38071228b482SChao Yu
38081228b482SChao Yu sbi->dirty_device = 0;
38091228b482SChao Yu spin_lock_init(&sbi->dev_lock);
3810d0d3f1b3SChao Yu
3811e4544b63STim Murray init_f2fs_rwsem(&sbi->sb_lock);
3812e4544b63STim Murray init_f2fs_rwsem(&sbi->pin_sem);
3813aff063e2SJaegeuk Kim }
3814aff063e2SJaegeuk Kim
init_percpu_info(struct f2fs_sb_info * sbi)3815523be8a6SJaegeuk Kim static int init_percpu_info(struct f2fs_sb_info *sbi)
3816523be8a6SJaegeuk Kim {
381735782b23SJaegeuk Kim int err;
381841382ec4SJaegeuk Kim
3819513c5f37SJaegeuk Kim err = percpu_counter_init(&sbi->alloc_valid_block_count, 0, GFP_KERNEL);
3820513c5f37SJaegeuk Kim if (err)
3821513c5f37SJaegeuk Kim return err;
3822513c5f37SJaegeuk Kim
382347c8ebccSJaegeuk Kim err = percpu_counter_init(&sbi->rf_node_block_count, 0, GFP_KERNEL);
382447c8ebccSJaegeuk Kim if (err)
382547c8ebccSJaegeuk Kim goto err_valid_block;
382647c8ebccSJaegeuk Kim
38274a70e255SChao Yu err = percpu_counter_init(&sbi->total_valid_inode_count, 0,
382841382ec4SJaegeuk Kim GFP_KERNEL);
38294a70e255SChao Yu if (err)
383047c8ebccSJaegeuk Kim goto err_node_block;
383147c8ebccSJaegeuk Kim return 0;
38324a70e255SChao Yu
383347c8ebccSJaegeuk Kim err_node_block:
383447c8ebccSJaegeuk Kim percpu_counter_destroy(&sbi->rf_node_block_count);
383547c8ebccSJaegeuk Kim err_valid_block:
383647c8ebccSJaegeuk Kim percpu_counter_destroy(&sbi->alloc_valid_block_count);
38374a70e255SChao Yu return err;
3838523be8a6SJaegeuk Kim }
3839523be8a6SJaegeuk Kim
3840178053e2SDamien Le Moal #ifdef CONFIG_BLK_DEV_ZONED
3841de881df9SAravind Ramesh
3842de881df9SAravind Ramesh struct f2fs_report_zones_args {
3843b771aadcSJaegeuk Kim struct f2fs_sb_info *sbi;
3844de881df9SAravind Ramesh struct f2fs_dev_info *dev;
3845de881df9SAravind Ramesh };
3846de881df9SAravind Ramesh
f2fs_report_zone_cb(struct blk_zone * zone,unsigned int idx,void * data)3847d4100351SChristoph Hellwig static int f2fs_report_zone_cb(struct blk_zone *zone, unsigned int idx,
3848d4100351SChristoph Hellwig void *data)
3849d4100351SChristoph Hellwig {
3850de881df9SAravind Ramesh struct f2fs_report_zones_args *rz_args = data;
3851b771aadcSJaegeuk Kim block_t unusable_blocks = (zone->len - zone->capacity) >>
3852b771aadcSJaegeuk Kim F2FS_LOG_SECTORS_PER_BLOCK;
3853d4100351SChristoph Hellwig
3854de881df9SAravind Ramesh if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
3855de881df9SAravind Ramesh return 0;
3856de881df9SAravind Ramesh
3857de881df9SAravind Ramesh set_bit(idx, rz_args->dev->blkz_seq);
3858b771aadcSJaegeuk Kim if (!rz_args->sbi->unusable_blocks_per_sec) {
3859b771aadcSJaegeuk Kim rz_args->sbi->unusable_blocks_per_sec = unusable_blocks;
3860b771aadcSJaegeuk Kim return 0;
3861b771aadcSJaegeuk Kim }
3862b771aadcSJaegeuk Kim if (rz_args->sbi->unusable_blocks_per_sec != unusable_blocks) {
3863b771aadcSJaegeuk Kim f2fs_err(rz_args->sbi, "F2FS supports single zone capacity\n");
3864b771aadcSJaegeuk Kim return -EINVAL;
3865b771aadcSJaegeuk Kim }
3866d4100351SChristoph Hellwig return 0;
3867d4100351SChristoph Hellwig }
3868d4100351SChristoph Hellwig
init_blkz_info(struct f2fs_sb_info * sbi,int devi)38693c62be17SJaegeuk Kim static int init_blkz_info(struct f2fs_sb_info *sbi, int devi)
3870178053e2SDamien Le Moal {
38713c62be17SJaegeuk Kim struct block_device *bdev = FDEV(devi).bdev;
3872a782483cSChristoph Hellwig sector_t nr_sectors = bdev_nr_sectors(bdev);
3873de881df9SAravind Ramesh struct f2fs_report_zones_args rep_zone_arg;
3874d46db459SLuis Chamberlain u64 zone_sectors;
3875d4100351SChristoph Hellwig int ret;
3876178053e2SDamien Le Moal
38777beb01f7SChao Yu if (!f2fs_sb_has_blkzoned(sbi))
3878178053e2SDamien Le Moal return 0;
3879178053e2SDamien Le Moal
3880d46db459SLuis Chamberlain zone_sectors = bdev_zone_sectors(bdev);
38813c62be17SJaegeuk Kim if (sbi->blocks_per_blkz && sbi->blocks_per_blkz !=
3882d46db459SLuis Chamberlain SECTOR_TO_BLOCK(zone_sectors))
38833c62be17SJaegeuk Kim return -EINVAL;
3884d46db459SLuis Chamberlain sbi->blocks_per_blkz = SECTOR_TO_BLOCK(zone_sectors);
38852e2c6e9bSJaegeuk Kim FDEV(devi).nr_blkz = div_u64(SECTOR_TO_BLOCK(nr_sectors),
38862e2c6e9bSJaegeuk Kim sbi->blocks_per_blkz);
3887d46db459SLuis Chamberlain if (nr_sectors & (zone_sectors - 1))
38883c62be17SJaegeuk Kim FDEV(devi).nr_blkz++;
3889178053e2SDamien Le Moal
38900b6d4ca0SEric Biggers FDEV(devi).blkz_seq = f2fs_kvzalloc(sbi,
389195175dafSDamien Le Moal BITS_TO_LONGS(FDEV(devi).nr_blkz)
389295175dafSDamien Le Moal * sizeof(unsigned long),
38934e6aad29SChao Yu GFP_KERNEL);
389495175dafSDamien Le Moal if (!FDEV(devi).blkz_seq)
3895178053e2SDamien Le Moal return -ENOMEM;
3896178053e2SDamien Le Moal
3897b771aadcSJaegeuk Kim rep_zone_arg.sbi = sbi;
3898de881df9SAravind Ramesh rep_zone_arg.dev = &FDEV(devi);
3899de881df9SAravind Ramesh
3900d4100351SChristoph Hellwig ret = blkdev_report_zones(bdev, 0, BLK_ALL_ZONES, f2fs_report_zone_cb,
3901de881df9SAravind Ramesh &rep_zone_arg);
3902d4100351SChristoph Hellwig if (ret < 0)
3903d4100351SChristoph Hellwig return ret;
3904d4100351SChristoph Hellwig return 0;
3905178053e2SDamien Le Moal }
3906178053e2SDamien Le Moal #endif
3907178053e2SDamien Le Moal
39089076a75fSGu Zheng /*
39099076a75fSGu Zheng * Read f2fs raw super block.
39102b39e907SShawn Lin * Because we have two copies of super block, so read both of them
39112b39e907SShawn Lin * to get the first valid one. If any one of them is broken, we pass
39122b39e907SShawn Lin * them recovery flag back to the caller.
39139076a75fSGu Zheng */
read_raw_super_block(struct f2fs_sb_info * sbi,struct f2fs_super_block ** raw_super,int * valid_super_block,int * recovery)3914df728b0fSJaegeuk Kim static int read_raw_super_block(struct f2fs_sb_info *sbi,
391514d7e9deSmajianpeng struct f2fs_super_block **raw_super,
3916e8240f65SChao Yu int *valid_super_block, int *recovery)
391714d7e9deSmajianpeng {
3918df728b0fSJaegeuk Kim struct super_block *sb = sbi->sb;
39192b39e907SShawn Lin int block;
3920e8240f65SChao Yu struct buffer_head *bh;
3921fd694733SJaegeuk Kim struct f2fs_super_block *super;
3922da554e48Shujianyang int err = 0;
392314d7e9deSmajianpeng
3924b39f0de2SYunlei He super = kzalloc(sizeof(struct f2fs_super_block), GFP_KERNEL);
3925b39f0de2SYunlei He if (!super)
3926b39f0de2SYunlei He return -ENOMEM;
39272b39e907SShawn Lin
39282b39e907SShawn Lin for (block = 0; block < 2; block++) {
3929e8240f65SChao Yu bh = sb_bread(sb, block);
3930e8240f65SChao Yu if (!bh) {
3931dcbb4c10SJoe Perches f2fs_err(sbi, "Unable to read %dth superblock",
39329076a75fSGu Zheng block + 1);
3933da554e48Shujianyang err = -EIO;
3934ed352042SChengguang Xu via Linux-f2fs-devel *recovery = 1;
39352b39e907SShawn Lin continue;
39369076a75fSGu Zheng }
393714d7e9deSmajianpeng
393814d7e9deSmajianpeng /* sanity checking of raw super */
393938fb6d0eSIcenowy Zheng err = sanity_check_raw_super(sbi, bh);
394038fb6d0eSIcenowy Zheng if (err) {
3941dcbb4c10SJoe Perches f2fs_err(sbi, "Can't find valid F2FS filesystem in %dth superblock",
39426c311ec6SChris Fries block + 1);
39432b39e907SShawn Lin brelse(bh);
3944ed352042SChengguang Xu via Linux-f2fs-devel *recovery = 1;
39452b39e907SShawn Lin continue;
39469076a75fSGu Zheng }
39479076a75fSGu Zheng
3948da554e48Shujianyang if (!*raw_super) {
3949fd694733SJaegeuk Kim memcpy(super, bh->b_data + F2FS_SUPER_OFFSET,
3950fd694733SJaegeuk Kim sizeof(*super));
3951e8240f65SChao Yu *valid_super_block = block;
3952da554e48Shujianyang *raw_super = super;
3953da554e48Shujianyang }
3954e8240f65SChao Yu brelse(bh);
3955da554e48Shujianyang }
3956da554e48Shujianyang
3957da554e48Shujianyang /* No valid superblock */
39582b39e907SShawn Lin if (!*raw_super)
3959742532d1SDenis Efremov kfree(super);
39602b39e907SShawn Lin else
39612b39e907SShawn Lin err = 0;
3962da554e48Shujianyang
39632b39e907SShawn Lin return err;
39649076a75fSGu Zheng }
396514d7e9deSmajianpeng
f2fs_commit_super(struct f2fs_sb_info * sbi,bool recover)3966fd694733SJaegeuk Kim int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover)
396726d815adSJaegeuk Kim {
39685d909cdbSJaegeuk Kim struct buffer_head *bh;
3969d440c52dSJunling Zheng __u32 crc = 0;
397026d815adSJaegeuk Kim int err;
397126d815adSJaegeuk Kim
3972df728b0fSJaegeuk Kim if ((recover && f2fs_readonly(sbi->sb)) ||
397368f0453dSChao Yu f2fs_hw_is_readonly(sbi)) {
3974df728b0fSJaegeuk Kim set_sbi_flag(sbi, SBI_NEED_SB_WRITE);
3975f2353d7bSJaegeuk Kim return -EROFS;
3976df728b0fSJaegeuk Kim }
3977f2353d7bSJaegeuk Kim
3978d440c52dSJunling Zheng /* we should update superblock crc here */
39797beb01f7SChao Yu if (!recover && f2fs_sb_has_sb_chksum(sbi)) {
3980d440c52dSJunling Zheng crc = f2fs_crc32(sbi, F2FS_RAW_SUPER(sbi),
3981d440c52dSJunling Zheng offsetof(struct f2fs_super_block, crc));
3982d440c52dSJunling Zheng F2FS_RAW_SUPER(sbi)->crc = cpu_to_le32(crc);
3983d440c52dSJunling Zheng }
3984d440c52dSJunling Zheng
3985fd694733SJaegeuk Kim /* write back-up superblock first */
39860964fc1aSSheng Yong bh = sb_bread(sbi->sb, sbi->valid_super_block ? 0 : 1);
39875d909cdbSJaegeuk Kim if (!bh)
39885d909cdbSJaegeuk Kim return -EIO;
3989fd694733SJaegeuk Kim err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi));
39905d909cdbSJaegeuk Kim brelse(bh);
3991c5bda1c8SChao Yu
3992c5bda1c8SChao Yu /* if we are in recovery path, skip writing valid superblock */
3993c5bda1c8SChao Yu if (recover || err)
39945d909cdbSJaegeuk Kim return err;
399526d815adSJaegeuk Kim
3996e8240f65SChao Yu /* write current valid superblock */
39970964fc1aSSheng Yong bh = sb_bread(sbi->sb, sbi->valid_super_block);
3998fd694733SJaegeuk Kim if (!bh)
3999fd694733SJaegeuk Kim return -EIO;
4000fd694733SJaegeuk Kim err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi));
4001fd694733SJaegeuk Kim brelse(bh);
4002fd694733SJaegeuk Kim return err;
400326d815adSJaegeuk Kim }
400426d815adSJaegeuk Kim
save_stop_reason(struct f2fs_sb_info * sbi,unsigned char reason)4005b62e71beSChao Yu static void save_stop_reason(struct f2fs_sb_info *sbi, unsigned char reason)
4006b62e71beSChao Yu {
4007b62e71beSChao Yu unsigned long flags;
4008b62e71beSChao Yu
4009b62e71beSChao Yu spin_lock_irqsave(&sbi->error_lock, flags);
4010b62e71beSChao Yu if (sbi->stop_reason[reason] < GENMASK(BITS_PER_BYTE - 1, 0))
4011b62e71beSChao Yu sbi->stop_reason[reason]++;
4012b62e71beSChao Yu spin_unlock_irqrestore(&sbi->error_lock, flags);
4013b62e71beSChao Yu }
4014b62e71beSChao Yu
f2fs_record_stop_reason(struct f2fs_sb_info * sbi)4015b62e71beSChao Yu static void f2fs_record_stop_reason(struct f2fs_sb_info *sbi)
4016a9cfee0eSChao Yu {
4017a9cfee0eSChao Yu struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
4018b62e71beSChao Yu unsigned long flags;
4019a9cfee0eSChao Yu int err;
4020a9cfee0eSChao Yu
4021a9cfee0eSChao Yu f2fs_down_write(&sbi->sb_lock);
4022a9cfee0eSChao Yu
4023b62e71beSChao Yu spin_lock_irqsave(&sbi->error_lock, flags);
4024901c12d1SChao Yu if (sbi->error_dirty) {
4025901c12d1SChao Yu memcpy(F2FS_RAW_SUPER(sbi)->s_errors, sbi->errors,
4026901c12d1SChao Yu MAX_F2FS_ERRORS);
4027901c12d1SChao Yu sbi->error_dirty = false;
4028901c12d1SChao Yu }
4029b62e71beSChao Yu memcpy(raw_super->s_stop_reason, sbi->stop_reason, MAX_STOP_REASON);
4030b62e71beSChao Yu spin_unlock_irqrestore(&sbi->error_lock, flags);
4031a9cfee0eSChao Yu
4032a9cfee0eSChao Yu err = f2fs_commit_super(sbi, false);
4033b62e71beSChao Yu
403495fa90c9SChao Yu f2fs_up_write(&sbi->sb_lock);
4035b62e71beSChao Yu if (err)
4036b62e71beSChao Yu f2fs_err(sbi, "f2fs_commit_super fails to record err:%d", err);
403795fa90c9SChao Yu }
4038a9cfee0eSChao Yu
f2fs_save_errors(struct f2fs_sb_info * sbi,unsigned char flag)40391aa161e4SJaegeuk Kim void f2fs_save_errors(struct f2fs_sb_info *sbi, unsigned char flag)
404095fa90c9SChao Yu {
4041b62e71beSChao Yu unsigned long flags;
4042b62e71beSChao Yu
4043b62e71beSChao Yu spin_lock_irqsave(&sbi->error_lock, flags);
404495fa90c9SChao Yu if (!test_bit(flag, (unsigned long *)sbi->errors)) {
404595fa90c9SChao Yu set_bit(flag, (unsigned long *)sbi->errors);
404695fa90c9SChao Yu sbi->error_dirty = true;
404795fa90c9SChao Yu }
4048b62e71beSChao Yu spin_unlock_irqrestore(&sbi->error_lock, flags);
404995fa90c9SChao Yu }
405095fa90c9SChao Yu
f2fs_update_errors(struct f2fs_sb_info * sbi)405195fa90c9SChao Yu static bool f2fs_update_errors(struct f2fs_sb_info *sbi)
405295fa90c9SChao Yu {
4053b62e71beSChao Yu unsigned long flags;
405495fa90c9SChao Yu bool need_update = false;
405595fa90c9SChao Yu
4056b62e71beSChao Yu spin_lock_irqsave(&sbi->error_lock, flags);
405795fa90c9SChao Yu if (sbi->error_dirty) {
405895fa90c9SChao Yu memcpy(F2FS_RAW_SUPER(sbi)->s_errors, sbi->errors,
405995fa90c9SChao Yu MAX_F2FS_ERRORS);
406095fa90c9SChao Yu sbi->error_dirty = false;
406195fa90c9SChao Yu need_update = true;
406295fa90c9SChao Yu }
4063b62e71beSChao Yu spin_unlock_irqrestore(&sbi->error_lock, flags);
406495fa90c9SChao Yu
406595fa90c9SChao Yu return need_update;
406695fa90c9SChao Yu }
406795fa90c9SChao Yu
f2fs_record_errors(struct f2fs_sb_info * sbi,unsigned char error)4068901c12d1SChao Yu static void f2fs_record_errors(struct f2fs_sb_info *sbi, unsigned char error)
406995fa90c9SChao Yu {
407095fa90c9SChao Yu int err;
407195fa90c9SChao Yu
407295fa90c9SChao Yu f2fs_down_write(&sbi->sb_lock);
407395fa90c9SChao Yu
407495fa90c9SChao Yu if (!f2fs_update_errors(sbi))
407595fa90c9SChao Yu goto out_unlock;
407695fa90c9SChao Yu
407795fa90c9SChao Yu err = f2fs_commit_super(sbi, false);
407895fa90c9SChao Yu if (err)
407995fa90c9SChao Yu f2fs_err(sbi, "f2fs_commit_super fails to record errors:%u, err:%d",
408095fa90c9SChao Yu error, err);
408195fa90c9SChao Yu out_unlock:
4082a9cfee0eSChao Yu f2fs_up_write(&sbi->sb_lock);
4083a9cfee0eSChao Yu }
4084a9cfee0eSChao Yu
f2fs_handle_error(struct f2fs_sb_info * sbi,unsigned char error)4085901c12d1SChao Yu void f2fs_handle_error(struct f2fs_sb_info *sbi, unsigned char error)
4086901c12d1SChao Yu {
4087901c12d1SChao Yu f2fs_save_errors(sbi, error);
4088901c12d1SChao Yu f2fs_record_errors(sbi, error);
4089901c12d1SChao Yu }
4090901c12d1SChao Yu
f2fs_handle_error_async(struct f2fs_sb_info * sbi,unsigned char error)4091901c12d1SChao Yu void f2fs_handle_error_async(struct f2fs_sb_info *sbi, unsigned char error)
4092901c12d1SChao Yu {
4093901c12d1SChao Yu f2fs_save_errors(sbi, error);
4094901c12d1SChao Yu
4095901c12d1SChao Yu if (!sbi->error_dirty)
4096901c12d1SChao Yu return;
4097901c12d1SChao Yu if (!test_bit(error, (unsigned long *)sbi->errors))
4098901c12d1SChao Yu return;
4099901c12d1SChao Yu schedule_work(&sbi->s_error_work);
4100901c12d1SChao Yu }
4101901c12d1SChao Yu
system_going_down(void)4102b62e71beSChao Yu static bool system_going_down(void)
4103b62e71beSChao Yu {
4104b62e71beSChao Yu return system_state == SYSTEM_HALT || system_state == SYSTEM_POWER_OFF
4105b62e71beSChao Yu || system_state == SYSTEM_RESTART;
4106b62e71beSChao Yu }
4107b62e71beSChao Yu
f2fs_handle_critical_error(struct f2fs_sb_info * sbi,unsigned char reason)4108ecf4e678SChao Yu void f2fs_handle_critical_error(struct f2fs_sb_info *sbi, unsigned char reason)
4109b62e71beSChao Yu {
4110b62e71beSChao Yu struct super_block *sb = sbi->sb;
4111b62e71beSChao Yu bool shutdown = reason == STOP_CP_REASON_SHUTDOWN;
4112b62e71beSChao Yu bool continue_fs = !shutdown &&
4113b62e71beSChao Yu F2FS_OPTION(sbi).errors == MOUNT_ERRORS_CONTINUE;
4114b62e71beSChao Yu
4115b62e71beSChao Yu set_ckpt_flags(sbi, CP_ERROR_FLAG);
4116b62e71beSChao Yu
4117b62e71beSChao Yu if (!f2fs_hw_is_readonly(sbi)) {
4118b62e71beSChao Yu save_stop_reason(sbi, reason);
4119b62e71beSChao Yu
4120ecf4e678SChao Yu /*
4121ecf4e678SChao Yu * always create an asynchronous task to record stop_reason
4122ecf4e678SChao Yu * in order to avoid potential deadlock when running into
4123ecf4e678SChao Yu * f2fs_record_stop_reason() synchronously.
4124ecf4e678SChao Yu */
4125b62e71beSChao Yu schedule_work(&sbi->s_error_work);
4126b62e71beSChao Yu }
4127b62e71beSChao Yu
4128b62e71beSChao Yu /*
4129b62e71beSChao Yu * We force ERRORS_RO behavior when system is rebooting. Otherwise we
4130b62e71beSChao Yu * could panic during 'reboot -f' as the underlying device got already
4131b62e71beSChao Yu * disabled.
4132b62e71beSChao Yu */
4133b62e71beSChao Yu if (F2FS_OPTION(sbi).errors == MOUNT_ERRORS_PANIC &&
4134b62e71beSChao Yu !shutdown && !system_going_down() &&
4135b62e71beSChao Yu !is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN))
4136b62e71beSChao Yu panic("F2FS-fs (device %s): panic forced after error\n",
4137b62e71beSChao Yu sb->s_id);
4138b62e71beSChao Yu
4139b62e71beSChao Yu if (shutdown)
4140b62e71beSChao Yu set_sbi_flag(sbi, SBI_IS_SHUTDOWN);
4141b62e71beSChao Yu
41421036d3eaSJaegeuk Kim /*
41431036d3eaSJaegeuk Kim * Continue filesystem operators if errors=continue. Should not set
41441036d3eaSJaegeuk Kim * RO by shutdown, since RO bypasses thaw_super which can hang the
41451036d3eaSJaegeuk Kim * system.
41461036d3eaSJaegeuk Kim */
41471036d3eaSJaegeuk Kim if (continue_fs || f2fs_readonly(sb) || shutdown) {
41481036d3eaSJaegeuk Kim f2fs_warn(sbi, "Stopped filesystem due to reason: %d", reason);
4149b62e71beSChao Yu return;
41501036d3eaSJaegeuk Kim }
4151b62e71beSChao Yu
4152b62e71beSChao Yu f2fs_warn(sbi, "Remounting filesystem read-only");
4153649ec8b3SChao Yu
4154b62e71beSChao Yu /*
4155649ec8b3SChao Yu * We have already set CP_ERROR_FLAG flag to stop all updates
4156649ec8b3SChao Yu * to filesystem, so it doesn't need to set SB_RDONLY flag here
4157649ec8b3SChao Yu * because the flag should be set covered w/ sb->s_umount semaphore
4158649ec8b3SChao Yu * via remount procedure, otherwise, it will confuse code like
4159649ec8b3SChao Yu * freeze_super() which will lead to deadlocks and other problems.
4160b62e71beSChao Yu */
4161b62e71beSChao Yu }
4162b62e71beSChao Yu
f2fs_record_error_work(struct work_struct * work)4163b62e71beSChao Yu static void f2fs_record_error_work(struct work_struct *work)
4164b62e71beSChao Yu {
4165b62e71beSChao Yu struct f2fs_sb_info *sbi = container_of(work,
4166b62e71beSChao Yu struct f2fs_sb_info, s_error_work);
4167b62e71beSChao Yu
4168b62e71beSChao Yu f2fs_record_stop_reason(sbi);
4169b62e71beSChao Yu }
4170b62e71beSChao Yu
f2fs_scan_devices(struct f2fs_sb_info * sbi)41713c62be17SJaegeuk Kim static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
41723c62be17SJaegeuk Kim {
41733c62be17SJaegeuk Kim struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
41747bb3a371SMasato Suzuki unsigned int max_devices = MAX_DEVICES;
417571f2c820SChao Yu unsigned int logical_blksize;
417605bdb996SChristoph Hellwig blk_mode_t mode = sb_open_mode(sbi->sb->s_flags);
41773c62be17SJaegeuk Kim int i;
41783c62be17SJaegeuk Kim
41797bb3a371SMasato Suzuki /* Initialize single device information */
41807bb3a371SMasato Suzuki if (!RDEV(0).path[0]) {
41817bb3a371SMasato Suzuki if (!bdev_is_zoned(sbi->sb->s_bdev))
41823c62be17SJaegeuk Kim return 0;
41837bb3a371SMasato Suzuki max_devices = 1;
41843c62be17SJaegeuk Kim }
41853c62be17SJaegeuk Kim
41867bb3a371SMasato Suzuki /*
41877bb3a371SMasato Suzuki * Initialize multiple devices information, or single
41887bb3a371SMasato Suzuki * zoned block device information.
41897bb3a371SMasato Suzuki */
4190026f0507SKees Cook sbi->devs = f2fs_kzalloc(sbi,
4191026f0507SKees Cook array_size(max_devices,
4192026f0507SKees Cook sizeof(struct f2fs_dev_info)),
4193026f0507SKees Cook GFP_KERNEL);
41947bb3a371SMasato Suzuki if (!sbi->devs)
41957bb3a371SMasato Suzuki return -ENOMEM;
41967bb3a371SMasato Suzuki
419771f2c820SChao Yu logical_blksize = bdev_logical_block_size(sbi->sb->s_bdev);
419871f2c820SChao Yu sbi->aligned_blksize = true;
419971f2c820SChao Yu
42007bb3a371SMasato Suzuki for (i = 0; i < max_devices; i++) {
420151bf8d3cSChristoph Hellwig if (i == 0)
420251bf8d3cSChristoph Hellwig FDEV(0).bdev = sbi->sb->s_bdev;
420351bf8d3cSChristoph Hellwig else if (!RDEV(i).path[0])
42047bb3a371SMasato Suzuki break;
42057bb3a371SMasato Suzuki
420651bf8d3cSChristoph Hellwig if (max_devices > 1) {
42077bb3a371SMasato Suzuki /* Multi-device mount */
42083c62be17SJaegeuk Kim memcpy(FDEV(i).path, RDEV(i).path, MAX_PATH_LEN);
42097bb3a371SMasato Suzuki FDEV(i).total_segments =
42107bb3a371SMasato Suzuki le32_to_cpu(RDEV(i).total_segments);
42113c62be17SJaegeuk Kim if (i == 0) {
42123c62be17SJaegeuk Kim FDEV(i).start_blk = 0;
42133c62be17SJaegeuk Kim FDEV(i).end_blk = FDEV(i).start_blk +
42143c62be17SJaegeuk Kim (FDEV(i).total_segments <<
42153c62be17SJaegeuk Kim sbi->log_blocks_per_seg) - 1 +
42163c62be17SJaegeuk Kim le32_to_cpu(raw_super->segment0_blkaddr);
42173c62be17SJaegeuk Kim } else {
42183c62be17SJaegeuk Kim FDEV(i).start_blk = FDEV(i - 1).end_blk + 1;
42193c62be17SJaegeuk Kim FDEV(i).end_blk = FDEV(i).start_blk +
42203c62be17SJaegeuk Kim (FDEV(i).total_segments <<
42213c62be17SJaegeuk Kim sbi->log_blocks_per_seg) - 1;
422251bf8d3cSChristoph Hellwig FDEV(i).bdev = blkdev_get_by_path(FDEV(i).path,
422392901222SLinus Torvalds mode, sbi->sb, NULL);
42243c62be17SJaegeuk Kim }
42257bb3a371SMasato Suzuki }
42263c62be17SJaegeuk Kim if (IS_ERR(FDEV(i).bdev))
42273c62be17SJaegeuk Kim return PTR_ERR(FDEV(i).bdev);
42283c62be17SJaegeuk Kim
42293c62be17SJaegeuk Kim /* to release errored devices */
42303c62be17SJaegeuk Kim sbi->s_ndevs = i + 1;
42313c62be17SJaegeuk Kim
423271f2c820SChao Yu if (logical_blksize != bdev_logical_block_size(FDEV(i).bdev))
423371f2c820SChao Yu sbi->aligned_blksize = false;
423471f2c820SChao Yu
42353c62be17SJaegeuk Kim #ifdef CONFIG_BLK_DEV_ZONED
42363c62be17SJaegeuk Kim if (bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HM &&
42377beb01f7SChao Yu !f2fs_sb_has_blkzoned(sbi)) {
4238833dcd35SJoe Perches f2fs_err(sbi, "Zoned block device feature not enabled");
42393c62be17SJaegeuk Kim return -EINVAL;
42403c62be17SJaegeuk Kim }
42413c62be17SJaegeuk Kim if (bdev_zoned_model(FDEV(i).bdev) != BLK_ZONED_NONE) {
42423c62be17SJaegeuk Kim if (init_blkz_info(sbi, i)) {
4243dcbb4c10SJoe Perches f2fs_err(sbi, "Failed to initialize F2FS blkzone information");
42443c62be17SJaegeuk Kim return -EINVAL;
42453c62be17SJaegeuk Kim }
42467bb3a371SMasato Suzuki if (max_devices == 1)
42477bb3a371SMasato Suzuki break;
4248dcbb4c10SJoe Perches f2fs_info(sbi, "Mount Device [%2d]: %20s, %8u, %8x - %8x (zone: %s)",
42493c62be17SJaegeuk Kim i, FDEV(i).path,
42503c62be17SJaegeuk Kim FDEV(i).total_segments,
42513c62be17SJaegeuk Kim FDEV(i).start_blk, FDEV(i).end_blk,
42523c62be17SJaegeuk Kim bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HA ?
42533c62be17SJaegeuk Kim "Host-aware" : "Host-managed");
42543c62be17SJaegeuk Kim continue;
42553c62be17SJaegeuk Kim }
42563c62be17SJaegeuk Kim #endif
4257dcbb4c10SJoe Perches f2fs_info(sbi, "Mount Device [%2d]: %20s, %8u, %8x - %8x",
42583c62be17SJaegeuk Kim i, FDEV(i).path,
42593c62be17SJaegeuk Kim FDEV(i).total_segments,
42603c62be17SJaegeuk Kim FDEV(i).start_blk, FDEV(i).end_blk);
42613c62be17SJaegeuk Kim }
42623c62be17SJaegeuk Kim return 0;
42633c62be17SJaegeuk Kim }
42643c62be17SJaegeuk Kim
f2fs_setup_casefold(struct f2fs_sb_info * sbi)42655aba5430SDaniel Rosenberg static int f2fs_setup_casefold(struct f2fs_sb_info *sbi)
42665aba5430SDaniel Rosenberg {
42675298d4bfSChristoph Hellwig #if IS_ENABLED(CONFIG_UNICODE)
4268eca4873eSDaniel Rosenberg if (f2fs_sb_has_casefold(sbi) && !sbi->sb->s_encoding) {
42695aba5430SDaniel Rosenberg const struct f2fs_sb_encodings *encoding_info;
42705aba5430SDaniel Rosenberg struct unicode_map *encoding;
42715aba5430SDaniel Rosenberg __u16 encoding_flags;
42725aba5430SDaniel Rosenberg
427386e80575SChristoph Hellwig encoding_info = f2fs_sb_read_encoding(sbi->raw_super);
427486e80575SChristoph Hellwig if (!encoding_info) {
42755aba5430SDaniel Rosenberg f2fs_err(sbi,
42765aba5430SDaniel Rosenberg "Encoding requested by superblock is unknown");
42775aba5430SDaniel Rosenberg return -EINVAL;
42785aba5430SDaniel Rosenberg }
42795aba5430SDaniel Rosenberg
428086e80575SChristoph Hellwig encoding_flags = le16_to_cpu(sbi->raw_super->s_encoding_flags);
42815aba5430SDaniel Rosenberg encoding = utf8_load(encoding_info->version);
42825aba5430SDaniel Rosenberg if (IS_ERR(encoding)) {
42835aba5430SDaniel Rosenberg f2fs_err(sbi,
428449bd03ccSChristoph Hellwig "can't mount with superblock charset: %s-%u.%u.%u "
42855aba5430SDaniel Rosenberg "not supported by the kernel. flags: 0x%x.",
428649bd03ccSChristoph Hellwig encoding_info->name,
428749bd03ccSChristoph Hellwig unicode_major(encoding_info->version),
428849bd03ccSChristoph Hellwig unicode_minor(encoding_info->version),
428949bd03ccSChristoph Hellwig unicode_rev(encoding_info->version),
42905aba5430SDaniel Rosenberg encoding_flags);
42915aba5430SDaniel Rosenberg return PTR_ERR(encoding);
42925aba5430SDaniel Rosenberg }
42935aba5430SDaniel Rosenberg f2fs_info(sbi, "Using encoding defined by superblock: "
429449bd03ccSChristoph Hellwig "%s-%u.%u.%u with flags 0x%hx", encoding_info->name,
429549bd03ccSChristoph Hellwig unicode_major(encoding_info->version),
429649bd03ccSChristoph Hellwig unicode_minor(encoding_info->version),
429749bd03ccSChristoph Hellwig unicode_rev(encoding_info->version),
429849bd03ccSChristoph Hellwig encoding_flags);
42995aba5430SDaniel Rosenberg
4300eca4873eSDaniel Rosenberg sbi->sb->s_encoding = encoding;
4301eca4873eSDaniel Rosenberg sbi->sb->s_encoding_flags = encoding_flags;
43025aba5430SDaniel Rosenberg }
43035aba5430SDaniel Rosenberg #else
43045aba5430SDaniel Rosenberg if (f2fs_sb_has_casefold(sbi)) {
43055aba5430SDaniel Rosenberg f2fs_err(sbi, "Filesystem with casefold feature cannot be mounted without CONFIG_UNICODE");
43065aba5430SDaniel Rosenberg return -EINVAL;
43075aba5430SDaniel Rosenberg }
43085aba5430SDaniel Rosenberg #endif
43095aba5430SDaniel Rosenberg return 0;
43105aba5430SDaniel Rosenberg }
43115aba5430SDaniel Rosenberg
f2fs_tuning_parameters(struct f2fs_sb_info * sbi)431284b89e5dSJaegeuk Kim static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi)
431384b89e5dSJaegeuk Kim {
431484b89e5dSJaegeuk Kim /* adjust parameters according to the volume size */
4315777cd95bSYuwei Guan if (MAIN_SEGS(sbi) <= SMALL_VOLUME_SEGMENTS) {
43164f993264SChao Yu if (f2fs_block_unit_discard(sbi))
43171cd2e6d5SYangtao Li SM_I(sbi)->dcc_info->discard_granularity =
43181cd2e6d5SYangtao Li MIN_DISCARD_GRANULARITY;
4319c5bf8348SYangtao Li if (!f2fs_lfs_mode(sbi))
4320fdb7ccc3SYangtao Li SM_I(sbi)->ipu_policy = BIT(F2FS_IPU_FORCE) |
4321fdb7ccc3SYangtao Li BIT(F2FS_IPU_HONOR_OPU_WRITE);
432284b89e5dSJaegeuk Kim }
43234cac90d5SChao Yu
432466aee5aaSYuwei Guan sbi->readdir_ra = true;
432584b89e5dSJaegeuk Kim }
432684b89e5dSJaegeuk Kim
f2fs_fill_super(struct super_block * sb,void * data,int silent)4327aff063e2SJaegeuk Kim static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
4328aff063e2SJaegeuk Kim {
4329aff063e2SJaegeuk Kim struct f2fs_sb_info *sbi;
4330da554e48Shujianyang struct f2fs_super_block *raw_super;
4331aff063e2SJaegeuk Kim struct inode *root;
433299e3e858SSheng Yong int err;
4333aa2c8c43SChao Yu bool skip_recovery = false, need_fsck = false;
4334dabc4a5cSJaegeuk Kim char *options = NULL;
4335e8240f65SChao Yu int recovery, i, valid_super_block;
43368f1dbbbbSShuoran Liu struct curseg_info *seg_i;
4337aa2c8c43SChao Yu int retry_cnt = 1;
4338e1bb7d3dSChao Yu #ifdef CONFIG_QUOTA
4339e1bb7d3dSChao Yu bool quota_enabled = false;
4340e1bb7d3dSChao Yu #endif
4341aff063e2SJaegeuk Kim
4342ed2e621aSJaegeuk Kim try_onemore:
4343da554e48Shujianyang err = -EINVAL;
4344da554e48Shujianyang raw_super = NULL;
4345e8240f65SChao Yu valid_super_block = -1;
4346da554e48Shujianyang recovery = 0;
4347da554e48Shujianyang
4348aff063e2SJaegeuk Kim /* allocate memory for f2fs-specific super block info */
4349aff063e2SJaegeuk Kim sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL);
4350aff063e2SJaegeuk Kim if (!sbi)
4351aff063e2SJaegeuk Kim return -ENOMEM;
4352aff063e2SJaegeuk Kim
4353df728b0fSJaegeuk Kim sbi->sb = sb;
4354df728b0fSJaegeuk Kim
435592b4cf5bSTetsuo Handa /* initialize locks within allocated memory */
435692b4cf5bSTetsuo Handa init_f2fs_rwsem(&sbi->gc_lock);
435792b4cf5bSTetsuo Handa mutex_init(&sbi->writepages);
435892b4cf5bSTetsuo Handa init_f2fs_rwsem(&sbi->cp_global_sem);
435992b4cf5bSTetsuo Handa init_f2fs_rwsem(&sbi->node_write);
436092b4cf5bSTetsuo Handa init_f2fs_rwsem(&sbi->node_change);
436192b4cf5bSTetsuo Handa spin_lock_init(&sbi->stat_lock);
436292b4cf5bSTetsuo Handa init_f2fs_rwsem(&sbi->cp_rwsem);
436392b4cf5bSTetsuo Handa init_f2fs_rwsem(&sbi->quota_sem);
436492b4cf5bSTetsuo Handa init_waitqueue_head(&sbi->cp_wait);
436592b4cf5bSTetsuo Handa spin_lock_init(&sbi->error_lock);
436692b4cf5bSTetsuo Handa
436792b4cf5bSTetsuo Handa for (i = 0; i < NR_INODE_TYPE; i++) {
436892b4cf5bSTetsuo Handa INIT_LIST_HEAD(&sbi->inode_list[i]);
436992b4cf5bSTetsuo Handa spin_lock_init(&sbi->inode_lock[i]);
437092b4cf5bSTetsuo Handa }
437192b4cf5bSTetsuo Handa mutex_init(&sbi->flush_lock);
437292b4cf5bSTetsuo Handa
437343b6573bSKeith Mok /* Load the checksum driver */
437443b6573bSKeith Mok sbi->s_chksum_driver = crypto_alloc_shash("crc32", 0, 0);
437543b6573bSKeith Mok if (IS_ERR(sbi->s_chksum_driver)) {
4376dcbb4c10SJoe Perches f2fs_err(sbi, "Cannot load crc32 driver.");
437743b6573bSKeith Mok err = PTR_ERR(sbi->s_chksum_driver);
437843b6573bSKeith Mok sbi->s_chksum_driver = NULL;
437943b6573bSKeith Mok goto free_sbi;
438043b6573bSKeith Mok }
438143b6573bSKeith Mok
4382ff9234adSNamjae Jeon /* set a block size */
43836bacf52fSJaegeuk Kim if (unlikely(!sb_set_blocksize(sb, F2FS_BLKSIZE))) {
4384dcbb4c10SJoe Perches f2fs_err(sbi, "unable to set blocksize");
4385aff063e2SJaegeuk Kim goto free_sbi;
4386a07ef784SNamjae Jeon }
4387aff063e2SJaegeuk Kim
4388df728b0fSJaegeuk Kim err = read_raw_super_block(sbi, &raw_super, &valid_super_block,
4389e8240f65SChao Yu &recovery);
4390c0d39e65SNamjae Jeon if (err)
43919076a75fSGu Zheng goto free_sbi;
43929076a75fSGu Zheng
43935fb08372SGu Zheng sb->s_fs_info = sbi;
439452763a4bSJaegeuk Kim sbi->raw_super = raw_super;
439552763a4bSJaegeuk Kim
4396b62e71beSChao Yu INIT_WORK(&sbi->s_error_work, f2fs_record_error_work);
439792b4cf5bSTetsuo Handa memcpy(sbi->errors, raw_super->s_errors, MAX_F2FS_ERRORS);
4398b62e71beSChao Yu memcpy(sbi->stop_reason, raw_super->s_stop_reason, MAX_STOP_REASON);
439992b4cf5bSTetsuo Handa
4400704956ecSChao Yu /* precompute checksum seed for metadata */
44017beb01f7SChao Yu if (f2fs_sb_has_inode_chksum(sbi))
4402704956ecSChao Yu sbi->s_chksum_seed = f2fs_chksum(sbi, ~0, raw_super->uuid,
4403704956ecSChao Yu sizeof(raw_super->uuid));
4404704956ecSChao Yu
4405458c15dfSChao Yu default_options(sbi, false);
4406aff063e2SJaegeuk Kim /* parse mount options */
4407dabc4a5cSJaegeuk Kim options = kstrdup((const char *)data, GFP_KERNEL);
4408dabc4a5cSJaegeuk Kim if (data && !options) {
4409dabc4a5cSJaegeuk Kim err = -ENOMEM;
4410aff063e2SJaegeuk Kim goto free_sb_buf;
4411dabc4a5cSJaegeuk Kim }
4412dabc4a5cSJaegeuk Kim
4413ed318a6cSEric Biggers err = parse_options(sb, options, false);
4414dabc4a5cSJaegeuk Kim if (err)
4415dabc4a5cSJaegeuk Kim goto free_options;
4416aff063e2SJaegeuk Kim
44176d1451bfSChengguang Xu sb->s_maxbytes = max_file_blocks(NULL) <<
4418e0afc4d6SChao Yu le32_to_cpu(raw_super->log_blocksize);
4419aff063e2SJaegeuk Kim sb->s_max_links = F2FS_LINK_MAX;
4420aff063e2SJaegeuk Kim
44215aba5430SDaniel Rosenberg err = f2fs_setup_casefold(sbi);
44225aba5430SDaniel Rosenberg if (err)
44235aba5430SDaniel Rosenberg goto free_options;
44245aba5430SDaniel Rosenberg
44250abd675eSChao Yu #ifdef CONFIG_QUOTA
44260abd675eSChao Yu sb->dq_op = &f2fs_quota_operations;
44270abd675eSChao Yu sb->s_qcop = &f2fs_quotactl_ops;
44285c57132eSChao Yu sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ;
4429292c196aSChao Yu
44307beb01f7SChao Yu if (f2fs_sb_has_quota_ino(sbi)) {
4431292c196aSChao Yu for (i = 0; i < MAXQUOTAS; i++) {
4432292c196aSChao Yu if (f2fs_qf_ino(sbi->sb, i))
4433292c196aSChao Yu sbi->nquota_files++;
4434292c196aSChao Yu }
4435292c196aSChao Yu }
44360abd675eSChao Yu #endif
44370abd675eSChao Yu
4438aff063e2SJaegeuk Kim sb->s_op = &f2fs_sops;
4439643fa961SChandan Rajendra #ifdef CONFIG_FS_ENCRYPTION
44400b81d077SJaegeuk Kim sb->s_cop = &f2fs_cryptops;
4441ffcc4182SEric Biggers #endif
444295ae251fSEric Biggers #ifdef CONFIG_FS_VERITY
444395ae251fSEric Biggers sb->s_vop = &f2fs_verityops;
444495ae251fSEric Biggers #endif
4445aff063e2SJaegeuk Kim sb->s_xattr = f2fs_xattr_handlers;
4446aff063e2SJaegeuk Kim sb->s_export_op = &f2fs_export_ops;
4447aff063e2SJaegeuk Kim sb->s_magic = F2FS_SUPER_MAGIC;
4448aff063e2SJaegeuk Kim sb->s_time_gran = 1;
44491751e8a6SLinus Torvalds sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
44501751e8a6SLinus Torvalds (test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0);
445185787090SChristoph Hellwig memcpy(&sb->s_uuid, raw_super->uuid, sizeof(raw_super->uuid));
4452578c6478SYufen Yu sb->s_iflags |= SB_I_CGROUPWB;
4453aff063e2SJaegeuk Kim
4454aff063e2SJaegeuk Kim /* init f2fs-specific super block info */
4455e8240f65SChao Yu sbi->valid_super_block = valid_super_block;
4456315df839SJaegeuk Kim
4457315df839SJaegeuk Kim /* disallow all the data/node/meta page writes */
4458315df839SJaegeuk Kim set_sbi_flag(sbi, SBI_POR_DOING);
4459971767caSJaegeuk Kim
4460908ea654SYufen Yu err = f2fs_init_write_merge_io(sbi);
4461908ea654SYufen Yu if (err)
44620b2103e8SChao Yu goto free_bio_info;
4463971767caSJaegeuk Kim
4464aff063e2SJaegeuk Kim init_sb_info(sbi);
4465aff063e2SJaegeuk Kim
446652118743SDaeho Jeong err = f2fs_init_iostat(sbi);
4467523be8a6SJaegeuk Kim if (err)
4468d7997e63SChao Yu goto free_bio_info;
4469523be8a6SJaegeuk Kim
4470aff063e2SJaegeuk Kim err = init_percpu_info(sbi);
4471aff063e2SJaegeuk Kim if (err)
4472a4b68176SDaeho Jeong goto free_iostat;
4473aff063e2SJaegeuk Kim
4474a999150fSChao Yu /* init per sbi slab cache */
4475a999150fSChao Yu err = f2fs_init_xattr_caches(sbi);
4476a999150fSChao Yu if (err)
44775f8e5a09SJaegeuk Kim goto free_percpu;
447831083031SChao Yu err = f2fs_init_page_array_cache(sbi);
447931083031SChao Yu if (err)
448031083031SChao Yu goto free_xattr_cache;
4481a999150fSChao Yu
4482aff063e2SJaegeuk Kim /* get an inode for meta space */
4483aff063e2SJaegeuk Kim sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi));
4484aff063e2SJaegeuk Kim if (IS_ERR(sbi->meta_inode)) {
4485dcbb4c10SJoe Perches f2fs_err(sbi, "Failed to read F2FS meta data inode");
4486aff063e2SJaegeuk Kim err = PTR_ERR(sbi->meta_inode);
448731083031SChao Yu goto free_page_array_cache;
4488aff063e2SJaegeuk Kim }
4489aff063e2SJaegeuk Kim
44904d57b86dSChao Yu err = f2fs_get_valid_checkpoint(sbi);
4491a07ef784SNamjae Jeon if (err) {
4492dcbb4c10SJoe Perches f2fs_err(sbi, "Failed to get valid F2FS checkpoint");
4493aff063e2SJaegeuk Kim goto free_meta_inode;
4494a07ef784SNamjae Jeon }
4495aff063e2SJaegeuk Kim
4496af033b2aSChao Yu if (__is_set_ckpt_flags(F2FS_CKPT(sbi), CP_QUOTA_NEED_FSCK_FLAG))
4497af033b2aSChao Yu set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
4498db610a64SJaegeuk Kim if (__is_set_ckpt_flags(F2FS_CKPT(sbi), CP_DISABLED_QUICK_FLAG)) {
4499db610a64SJaegeuk Kim set_sbi_flag(sbi, SBI_CP_DISABLED_QUICK);
4500db610a64SJaegeuk Kim sbi->interval_time[DISABLE_TIME] = DEF_DISABLE_QUICK_INTERVAL;
4501db610a64SJaegeuk Kim }
4502af033b2aSChao Yu
450304f0b2eaSQiuyang Sun if (__is_set_ckpt_flags(F2FS_CKPT(sbi), CP_FSCK_FLAG))
450404f0b2eaSQiuyang Sun set_sbi_flag(sbi, SBI_NEED_FSCK);
450504f0b2eaSQiuyang Sun
45063c62be17SJaegeuk Kim /* Initialize device list */
45073c62be17SJaegeuk Kim err = f2fs_scan_devices(sbi);
45083c62be17SJaegeuk Kim if (err) {
4509dcbb4c10SJoe Perches f2fs_err(sbi, "Failed to find devices");
45103c62be17SJaegeuk Kim goto free_devices;
45113c62be17SJaegeuk Kim }
45123c62be17SJaegeuk Kim
45134c8ff709SChao Yu err = f2fs_init_post_read_wq(sbi);
45144c8ff709SChao Yu if (err) {
45154c8ff709SChao Yu f2fs_err(sbi, "Failed to initialize post read workqueue");
45164c8ff709SChao Yu goto free_devices;
45174c8ff709SChao Yu }
45184c8ff709SChao Yu
4519aff063e2SJaegeuk Kim sbi->total_valid_node_count =
4520aff063e2SJaegeuk Kim le32_to_cpu(sbi->ckpt->valid_node_count);
4521513c5f37SJaegeuk Kim percpu_counter_set(&sbi->total_valid_inode_count,
4522513c5f37SJaegeuk Kim le32_to_cpu(sbi->ckpt->valid_inode_count));
4523aff063e2SJaegeuk Kim sbi->user_block_count = le64_to_cpu(sbi->ckpt->user_block_count);
4524aff063e2SJaegeuk Kim sbi->total_valid_block_count =
4525aff063e2SJaegeuk Kim le64_to_cpu(sbi->ckpt->valid_block_count);
4526aff063e2SJaegeuk Kim sbi->last_valid_block_count = sbi->total_valid_block_count;
4527daeb433eSChao Yu sbi->reserved_blocks = 0;
452880d42145SYunlong Song sbi->current_reserved_blocks = 0;
45297e65be49SJaegeuk Kim limit_reserve_root(sbi);
45301ae18f71SJaegeuk Kim adjust_unusable_cap_perc(sbi);
453141382ec4SJaegeuk Kim
45324d57b86dSChao Yu f2fs_init_extent_cache_info(sbi);
45331dcc336bSChao Yu
45344d57b86dSChao Yu f2fs_init_ino_entry_info(sbi);
4535aff063e2SJaegeuk Kim
453650fa53ecSChao Yu f2fs_init_fsync_node_info(sbi);
453750fa53ecSChao Yu
4538261eeb9cSDaeho Jeong /* setup checkpoint request control and start checkpoint issue thread */
4539261eeb9cSDaeho Jeong f2fs_init_ckpt_req_control(sbi);
45403f7070b0SChao Yu if (!f2fs_readonly(sb) && !test_opt(sbi, DISABLE_CHECKPOINT) &&
4541261eeb9cSDaeho Jeong test_opt(sbi, MERGE_CHECKPOINT)) {
4542261eeb9cSDaeho Jeong err = f2fs_start_ckpt_thread(sbi);
4543261eeb9cSDaeho Jeong if (err) {
4544261eeb9cSDaeho Jeong f2fs_err(sbi,
4545261eeb9cSDaeho Jeong "Failed to start F2FS issue_checkpoint_thread (%d)",
4546261eeb9cSDaeho Jeong err);
4547261eeb9cSDaeho Jeong goto stop_ckpt_thread;
4548261eeb9cSDaeho Jeong }
4549261eeb9cSDaeho Jeong }
4550261eeb9cSDaeho Jeong
4551aff063e2SJaegeuk Kim /* setup f2fs internal modules */
45524d57b86dSChao Yu err = f2fs_build_segment_manager(sbi);
4553a07ef784SNamjae Jeon if (err) {
4554dcbb4c10SJoe Perches f2fs_err(sbi, "Failed to initialize F2FS segment manager (%d)",
4555dcbb4c10SJoe Perches err);
4556aff063e2SJaegeuk Kim goto free_sm;
4557a07ef784SNamjae Jeon }
45584d57b86dSChao Yu err = f2fs_build_node_manager(sbi);
4559a07ef784SNamjae Jeon if (err) {
4560dcbb4c10SJoe Perches f2fs_err(sbi, "Failed to initialize F2FS node manager (%d)",
4561dcbb4c10SJoe Perches err);
4562aff063e2SJaegeuk Kim goto free_nm;
4563a07ef784SNamjae Jeon }
4564aff063e2SJaegeuk Kim
45658f1dbbbbSShuoran Liu /* For write statistics */
45663a0a9cbcSChao Yu sbi->sectors_written_start = f2fs_get_sectors_written(sbi);
45678f1dbbbbSShuoran Liu
45688f1dbbbbSShuoran Liu /* Read accumulated write IO statistics if exists */
45698f1dbbbbSShuoran Liu seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE);
45708f1dbbbbSShuoran Liu if (__exist_node_summaries(sbi))
45718f1dbbbbSShuoran Liu sbi->kbytes_written =
4572b2dde6fcSShuoran Liu le64_to_cpu(seg_i->journal->info.kbytes_written);
45738f1dbbbbSShuoran Liu
45744d57b86dSChao Yu f2fs_build_gc_manager(sbi);
4575aff063e2SJaegeuk Kim
457660aa4d55SSahitya Tummala err = f2fs_build_stats(sbi);
457760aa4d55SSahitya Tummala if (err)
457860aa4d55SSahitya Tummala goto free_nm;
457960aa4d55SSahitya Tummala
4580aff063e2SJaegeuk Kim /* get an inode for node space */
4581aff063e2SJaegeuk Kim sbi->node_inode = f2fs_iget(sb, F2FS_NODE_INO(sbi));
4582aff063e2SJaegeuk Kim if (IS_ERR(sbi->node_inode)) {
4583dcbb4c10SJoe Perches f2fs_err(sbi, "Failed to read node inode");
4584aff063e2SJaegeuk Kim err = PTR_ERR(sbi->node_inode);
458560aa4d55SSahitya Tummala goto free_stats;
4586aff063e2SJaegeuk Kim }
4587aff063e2SJaegeuk Kim
4588aff063e2SJaegeuk Kim /* read root inode and dentry */
4589aff063e2SJaegeuk Kim root = f2fs_iget(sb, F2FS_ROOT_INO(sbi));
4590aff063e2SJaegeuk Kim if (IS_ERR(root)) {
4591dcbb4c10SJoe Perches f2fs_err(sbi, "Failed to read root inode");
4592aff063e2SJaegeuk Kim err = PTR_ERR(root);
459360aa4d55SSahitya Tummala goto free_node_inode;
4594aff063e2SJaegeuk Kim }
4595bcbfbd60SChao Yu if (!S_ISDIR(root->i_mode) || !root->i_blocks ||
4596bcbfbd60SChao Yu !root->i_size || !root->i_nlink) {
45979d847950SChao Yu iput(root);
45988f99a946SChao Yu err = -EINVAL;
459960aa4d55SSahitya Tummala goto free_node_inode;
46008f99a946SChao Yu }
4601aff063e2SJaegeuk Kim
4602aff063e2SJaegeuk Kim sb->s_root = d_make_root(root); /* allocate root dentry */
4603aff063e2SJaegeuk Kim if (!sb->s_root) {
4604aff063e2SJaegeuk Kim err = -ENOMEM;
4605025cdb16SChengguang Xu goto free_node_inode;
4606aff063e2SJaegeuk Kim }
4607aff063e2SJaegeuk Kim
46086ce19affSChao Yu err = f2fs_init_compress_inode(sbi);
4609b59d0baeSNamjae Jeon if (err)
4610a398101aSChao Yu goto free_root_inode;
4611b59d0baeSNamjae Jeon
46126ce19affSChao Yu err = f2fs_register_sysfs(sbi);
46136ce19affSChao Yu if (err)
46146ce19affSChao Yu goto free_compress_inode;
46156ce19affSChao Yu
4616ea676733SJaegeuk Kim #ifdef CONFIG_QUOTA
461776cf05d7SSheng Yong /* Enable quota usage during mount */
46187beb01f7SChao Yu if (f2fs_sb_has_quota_ino(sbi) && !f2fs_readonly(sb)) {
4619ea676733SJaegeuk Kim err = f2fs_enable_quotas(sb);
4620730746ceSJaegeuk Kim if (err)
4621dcbb4c10SJoe Perches f2fs_err(sbi, "Cannot turn on quotas: error %d", err);
4622ea676733SJaegeuk Kim }
4623e1bb7d3dSChao Yu
4624e1bb7d3dSChao Yu quota_enabled = f2fs_recover_quota_begin(sbi);
4625ea676733SJaegeuk Kim #endif
46267a88ddb5SChao Yu /* if there are any orphan inodes, free them */
46274d57b86dSChao Yu err = f2fs_recover_orphan_inodes(sbi);
46284b2414d0SChao Yu if (err)
4629ea676733SJaegeuk Kim goto free_meta;
46304b2414d0SChao Yu
46314354994fSDaniel Rosenberg if (unlikely(is_set_ckpt_flags(sbi, CP_DISABLED_FLAG)))
4632aa2c8c43SChao Yu goto reset_checkpoint;
46334354994fSDaniel Rosenberg
46346437d1b0SJaegeuk Kim /* recover fsynced data */
4635a9117ecaSChao Yu if (!test_opt(sbi, DISABLE_ROLL_FORWARD) &&
4636a9117ecaSChao Yu !test_opt(sbi, NORECOVERY)) {
4637081d78c2SJaegeuk Kim /*
4638081d78c2SJaegeuk Kim * mount should be failed, when device has readonly mode, and
4639081d78c2SJaegeuk Kim * previous checkpoint was not done by clean system shutdown.
4640081d78c2SJaegeuk Kim */
4641b61af314SChao Yu if (f2fs_hw_is_readonly(sbi)) {
464223738e74SChao Yu if (!is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) {
464323738e74SChao Yu err = f2fs_recover_fsync_data(sbi, true);
464423738e74SChao Yu if (err > 0) {
464523738e74SChao Yu err = -EROFS;
464623738e74SChao Yu f2fs_err(sbi, "Need to recover fsync data, but "
464723738e74SChao Yu "write access unavailable, please try "
464823738e74SChao Yu "mount w/ disable_roll_forward or norecovery");
464923738e74SChao Yu }
465023738e74SChao Yu if (err < 0)
465123738e74SChao Yu goto free_meta;
465223738e74SChao Yu }
4653dcbb4c10SJoe Perches f2fs_info(sbi, "write access unavailable, skipping recovery");
4654b61af314SChao Yu goto reset_checkpoint;
4655b61af314SChao Yu }
46562adc3505SChao Yu
46572adc3505SChao Yu if (need_fsck)
46582adc3505SChao Yu set_sbi_flag(sbi, SBI_NEED_FSCK);
46592adc3505SChao Yu
4660aa2c8c43SChao Yu if (skip_recovery)
4661aa2c8c43SChao Yu goto reset_checkpoint;
4662a468f0efSJaegeuk Kim
46634d57b86dSChao Yu err = f2fs_recover_fsync_data(sbi, false);
46646781eabbSJaegeuk Kim if (err < 0) {
4665aa2c8c43SChao Yu if (err != -ENOMEM)
4666aa2c8c43SChao Yu skip_recovery = true;
46672adc3505SChao Yu need_fsck = true;
4668dcbb4c10SJoe Perches f2fs_err(sbi, "Cannot recover all fsync data errno=%d",
4669dcbb4c10SJoe Perches err);
46704b2414d0SChao Yu goto free_meta;
4671ed2e621aSJaegeuk Kim }
46726781eabbSJaegeuk Kim } else {
46734d57b86dSChao Yu err = f2fs_recover_fsync_data(sbi, true);
46746781eabbSJaegeuk Kim
46756781eabbSJaegeuk Kim if (!f2fs_readonly(sb) && err > 0) {
46766781eabbSJaegeuk Kim err = -EINVAL;
4677dcbb4c10SJoe Perches f2fs_err(sbi, "Need to recover fsync data");
4678ea676733SJaegeuk Kim goto free_meta;
46796437d1b0SJaegeuk Kim }
46806781eabbSJaegeuk Kim }
4681d508c94eSShin'ichiro Kawasaki
4682e1bb7d3dSChao Yu #ifdef CONFIG_QUOTA
4683e1bb7d3dSChao Yu f2fs_recover_quota_end(sbi, quota_enabled);
4684e1bb7d3dSChao Yu #endif
4685e1bb7d3dSChao Yu
4686d508c94eSShin'ichiro Kawasaki /*
4687d508c94eSShin'ichiro Kawasaki * If the f2fs is not readonly and fsync data recovery succeeds,
4688d508c94eSShin'ichiro Kawasaki * check zoned block devices' write pointer consistency.
4689d508c94eSShin'ichiro Kawasaki */
4690d508c94eSShin'ichiro Kawasaki if (!err && !f2fs_readonly(sb) && f2fs_sb_has_blkzoned(sbi)) {
4691d508c94eSShin'ichiro Kawasaki err = f2fs_check_write_pointer(sbi);
4692d508c94eSShin'ichiro Kawasaki if (err)
4693d508c94eSShin'ichiro Kawasaki goto free_meta;
4694d508c94eSShin'ichiro Kawasaki }
4695d508c94eSShin'ichiro Kawasaki
4696aa2c8c43SChao Yu reset_checkpoint:
4697093749e2SChao Yu f2fs_init_inmem_curseg(sbi);
4698093749e2SChao Yu
46994d57b86dSChao Yu /* f2fs_recover_fsync_data() cleared this already */
4700315df839SJaegeuk Kim clear_sbi_flag(sbi, SBI_POR_DOING);
47016437d1b0SJaegeuk Kim
47024354994fSDaniel Rosenberg if (test_opt(sbi, DISABLE_CHECKPOINT)) {
47034354994fSDaniel Rosenberg err = f2fs_disable_checkpoint(sbi);
47044354994fSDaniel Rosenberg if (err)
4705812a9597SJaegeuk Kim goto sync_free_meta;
47064354994fSDaniel Rosenberg } else if (is_set_ckpt_flags(sbi, CP_DISABLED_FLAG)) {
47074354994fSDaniel Rosenberg f2fs_enable_checkpoint(sbi);
47084354994fSDaniel Rosenberg }
47094354994fSDaniel Rosenberg
47106437d1b0SJaegeuk Kim /*
47116437d1b0SJaegeuk Kim * If filesystem is not mounted as read-only then
47126437d1b0SJaegeuk Kim * do start the gc_thread.
47136437d1b0SJaegeuk Kim */
47145911d2d1SChao Yu if ((F2FS_OPTION(sbi).bggc_mode != BGGC_MODE_OFF ||
47155911d2d1SChao Yu test_opt(sbi, GC_MERGE)) && !f2fs_readonly(sb)) {
47166437d1b0SJaegeuk Kim /* After POR, we can run background GC thread.*/
47174d57b86dSChao Yu err = f2fs_start_gc_thread(sbi);
47186437d1b0SJaegeuk Kim if (err)
4719812a9597SJaegeuk Kim goto sync_free_meta;
47206437d1b0SJaegeuk Kim }
47215222595dSJaegeuk Kim kvfree(options);
4722da554e48Shujianyang
4723da554e48Shujianyang /* recover broken superblock */
4724f2353d7bSJaegeuk Kim if (recovery) {
472541214b3cSChao Yu err = f2fs_commit_super(sbi, true);
4726dcbb4c10SJoe Perches f2fs_info(sbi, "Try to recover %dth superblock, ret: %d",
472741214b3cSChao Yu sbi->valid_super_block ? 1 : 2, err);
4728da554e48Shujianyang }
4729da554e48Shujianyang
4730bae01edaSChao Yu f2fs_join_shrinker(sbi);
4731bae01edaSChao Yu
473284b89e5dSJaegeuk Kim f2fs_tuning_parameters(sbi);
473384b89e5dSJaegeuk Kim
4734dcbb4c10SJoe Perches f2fs_notice(sbi, "Mounted with checkpoint version = %llx",
47351200abb2SJaegeuk Kim cur_cp_version(F2FS_CKPT(sbi)));
47366beceb54SJaegeuk Kim f2fs_update_time(sbi, CP_TIME);
4737d0239e1bSJaegeuk Kim f2fs_update_time(sbi, REQ_TIME);
4738db610a64SJaegeuk Kim clear_sbi_flag(sbi, SBI_CP_DISABLED_QUICK);
4739aff063e2SJaegeuk Kim return 0;
47406437d1b0SJaegeuk Kim
4741812a9597SJaegeuk Kim sync_free_meta:
4742812a9597SJaegeuk Kim /* safe to flush all the data */
4743812a9597SJaegeuk Kim sync_filesystem(sbi->sb);
4744aa2c8c43SChao Yu retry_cnt = 0;
4745812a9597SJaegeuk Kim
47464b2414d0SChao Yu free_meta:
4747ea676733SJaegeuk Kim #ifdef CONFIG_QUOTA
474826b5a079SSheng Yong f2fs_truncate_quota_inode_pages(sb);
47497beb01f7SChao Yu if (f2fs_sb_has_quota_ino(sbi) && !f2fs_readonly(sb))
4750ea676733SJaegeuk Kim f2fs_quota_off_umount(sbi->sb);
4751ea676733SJaegeuk Kim #endif
47524b2414d0SChao Yu /*
47534d57b86dSChao Yu * Some dirty meta pages can be produced by f2fs_recover_orphan_inodes()
47544b2414d0SChao Yu * failed by EIO. Then, iput(node_inode) can trigger balance_fs_bg()
47554d57b86dSChao Yu * followed by f2fs_write_checkpoint() through f2fs_write_node_pages(), which
47564d57b86dSChao Yu * falls into an infinite loop in f2fs_sync_meta_pages().
47574b2414d0SChao Yu */
47584b2414d0SChao Yu truncate_inode_pages_final(META_MAPPING(sbi));
4759812a9597SJaegeuk Kim /* evict some inodes being cached by GC */
4760812a9597SJaegeuk Kim evict_inodes(sb);
4761dc6b2055SJaegeuk Kim f2fs_unregister_sysfs(sbi);
47626ce19affSChao Yu free_compress_inode:
47636ce19affSChao Yu f2fs_destroy_compress_inode(sbi);
4764aff063e2SJaegeuk Kim free_root_inode:
4765aff063e2SJaegeuk Kim dput(sb->s_root);
4766aff063e2SJaegeuk Kim sb->s_root = NULL;
4767bae01edaSChao Yu free_node_inode:
47684d57b86dSChao Yu f2fs_release_ino_entry(sbi, true);
4769bae01edaSChao Yu truncate_inode_pages_final(NODE_MAPPING(sbi));
4770bae01edaSChao Yu iput(sbi->node_inode);
47717c77bf7dSJaegeuk Kim sbi->node_inode = NULL;
477260aa4d55SSahitya Tummala free_stats:
477360aa4d55SSahitya Tummala f2fs_destroy_stats(sbi);
4774aff063e2SJaegeuk Kim free_nm:
47755429c9dbSDongliang Mu /* stop discard thread before destroying node manager */
47765429c9dbSDongliang Mu f2fs_stop_discard_thread(sbi);
47774d57b86dSChao Yu f2fs_destroy_node_manager(sbi);
4778aff063e2SJaegeuk Kim free_sm:
47794d57b86dSChao Yu f2fs_destroy_segment_manager(sbi);
4780261eeb9cSDaeho Jeong stop_ckpt_thread:
4781261eeb9cSDaeho Jeong f2fs_stop_ckpt_thread(sbi);
4782b62e71beSChao Yu /* flush s_error_work before sbi destroy */
4783b62e71beSChao Yu flush_work(&sbi->s_error_work);
47847b02b220SChao Yu f2fs_destroy_post_read_wq(sbi);
47853c62be17SJaegeuk Kim free_devices:
47863c62be17SJaegeuk Kim destroy_device_list(sbi);
47875222595dSJaegeuk Kim kvfree(sbi->ckpt);
4788aff063e2SJaegeuk Kim free_meta_inode:
4789aff063e2SJaegeuk Kim make_bad_inode(sbi->meta_inode);
4790aff063e2SJaegeuk Kim iput(sbi->meta_inode);
47917c77bf7dSJaegeuk Kim sbi->meta_inode = NULL;
479231083031SChao Yu free_page_array_cache:
479331083031SChao Yu f2fs_destroy_page_array_cache(sbi);
4794a999150fSChao Yu free_xattr_cache:
4795a999150fSChao Yu f2fs_destroy_xattr_caches(sbi);
4796d7997e63SChao Yu free_percpu:
4797d7997e63SChao Yu destroy_percpu_info(sbi);
4798a4b68176SDaeho Jeong free_iostat:
4799a4b68176SDaeho Jeong f2fs_destroy_iostat(sbi);
4800d7997e63SChao Yu free_bio_info:
4801a912b54dSJaegeuk Kim for (i = 0; i < NR_PAGE_TYPE; i++)
48025222595dSJaegeuk Kim kvfree(sbi->write_io[i]);
48035aba5430SDaniel Rosenberg
48045298d4bfSChristoph Hellwig #if IS_ENABLED(CONFIG_UNICODE)
4805eca4873eSDaniel Rosenberg utf8_unload(sb->s_encoding);
480689ff6005SHyeongseok Kim sb->s_encoding = NULL;
48075aba5430SDaniel Rosenberg #endif
4808d7997e63SChao Yu free_options:
48094b2414d0SChao Yu #ifdef CONFIG_QUOTA
48104b2414d0SChao Yu for (i = 0; i < MAXQUOTAS; i++)
4811ba87a45cSWang Xiaojun kfree(F2FS_OPTION(sbi).s_qf_names[i]);
48124b2414d0SChao Yu #endif
4813ac4acb1fSEric Biggers fscrypt_free_dummy_policy(&F2FS_OPTION(sbi).dummy_enc_policy);
48145222595dSJaegeuk Kim kvfree(options);
4815aff063e2SJaegeuk Kim free_sb_buf:
4816742532d1SDenis Efremov kfree(raw_super);
4817aff063e2SJaegeuk Kim free_sbi:
481843b6573bSKeith Mok if (sbi->s_chksum_driver)
481943b6573bSKeith Mok crypto_free_shash(sbi->s_chksum_driver);
4820742532d1SDenis Efremov kfree(sbi);
4821ed2e621aSJaegeuk Kim
4822ed2e621aSJaegeuk Kim /* give only one another chance */
4823aa2c8c43SChao Yu if (retry_cnt > 0 && skip_recovery) {
4824aa2c8c43SChao Yu retry_cnt--;
4825ed2e621aSJaegeuk Kim shrink_dcache_sb(sb);
4826ed2e621aSJaegeuk Kim goto try_onemore;
4827ed2e621aSJaegeuk Kim }
4828aff063e2SJaegeuk Kim return err;
4829aff063e2SJaegeuk Kim }
4830aff063e2SJaegeuk Kim
f2fs_mount(struct file_system_type * fs_type,int flags,const char * dev_name,void * data)4831aff063e2SJaegeuk Kim static struct dentry *f2fs_mount(struct file_system_type *fs_type, int flags,
4832aff063e2SJaegeuk Kim const char *dev_name, void *data)
4833aff063e2SJaegeuk Kim {
4834aff063e2SJaegeuk Kim return mount_bdev(fs_type, flags, dev_name, data, f2fs_fill_super);
4835aff063e2SJaegeuk Kim }
4836aff063e2SJaegeuk Kim
kill_f2fs_super(struct super_block * sb)483730a5537fSJaegeuk Kim static void kill_f2fs_super(struct super_block *sb)
483830a5537fSJaegeuk Kim {
4839cce13252SChao Yu if (sb->s_root) {
48401cb50f87SJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(sb);
48411cb50f87SJaegeuk Kim
48421cb50f87SJaegeuk Kim set_sbi_flag(sbi, SBI_IS_CLOSE);
48431cb50f87SJaegeuk Kim f2fs_stop_gc_thread(sbi);
48441cb50f87SJaegeuk Kim f2fs_stop_discard_thread(sbi);
48451cb50f87SJaegeuk Kim
48466ce19affSChao Yu #ifdef CONFIG_F2FS_FS_COMPRESSION
48476ce19affSChao Yu /*
48486ce19affSChao Yu * latter evict_inode() can bypass checking and invalidating
48496ce19affSChao Yu * compress inode cache.
48506ce19affSChao Yu */
48516ce19affSChao Yu if (test_opt(sbi, COMPRESS_CACHE))
48526ce19affSChao Yu truncate_inode_pages_final(COMPRESS_MAPPING(sbi));
48536ce19affSChao Yu #endif
48546ce19affSChao Yu
48551cb50f87SJaegeuk Kim if (is_sbi_flag_set(sbi, SBI_IS_DIRTY) ||
48561cb50f87SJaegeuk Kim !is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) {
48571cb50f87SJaegeuk Kim struct cp_control cpc = {
48581cb50f87SJaegeuk Kim .reason = CP_UMOUNT,
48591cb50f87SJaegeuk Kim };
4860eb61c2ccSChao Yu stat_inc_cp_call_count(sbi, TOTAL_CALL);
48611cb50f87SJaegeuk Kim f2fs_write_checkpoint(sbi, &cpc);
48621cb50f87SJaegeuk Kim }
48631378752bSChao Yu
48641378752bSChao Yu if (is_sbi_flag_set(sbi, SBI_IS_RECOVERED) && f2fs_readonly(sb))
48651378752bSChao Yu sb->s_flags &= ~SB_RDONLY;
4866cce13252SChao Yu }
486730a5537fSJaegeuk Kim kill_block_super(sb);
486830a5537fSJaegeuk Kim }
486930a5537fSJaegeuk Kim
4870aff063e2SJaegeuk Kim static struct file_system_type f2fs_fs_type = {
4871aff063e2SJaegeuk Kim .owner = THIS_MODULE,
4872aff063e2SJaegeuk Kim .name = "f2fs",
4873aff063e2SJaegeuk Kim .mount = f2fs_mount,
487430a5537fSJaegeuk Kim .kill_sb = kill_f2fs_super,
4875984fc4e7SChao Yu .fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
4876aff063e2SJaegeuk Kim };
48777f78e035SEric W. Biederman MODULE_ALIAS_FS("f2fs");
4878aff063e2SJaegeuk Kim
init_inodecache(void)48796e6093a8SNamjae Jeon static int __init init_inodecache(void)
4880aff063e2SJaegeuk Kim {
48815d097056SVladimir Davydov f2fs_inode_cachep = kmem_cache_create("f2fs_inode_cache",
48825d097056SVladimir Davydov sizeof(struct f2fs_inode_info), 0,
48835d097056SVladimir Davydov SLAB_RECLAIM_ACCOUNT|SLAB_ACCOUNT, NULL);
4884870af777SYangtao Li return f2fs_inode_cachep ? 0 : -ENOMEM;
4885aff063e2SJaegeuk Kim }
4886aff063e2SJaegeuk Kim
destroy_inodecache(void)4887aff063e2SJaegeuk Kim static void destroy_inodecache(void)
4888aff063e2SJaegeuk Kim {
4889aff063e2SJaegeuk Kim /*
4890aff063e2SJaegeuk Kim * Make sure all delayed rcu free inodes are flushed before we
4891aff063e2SJaegeuk Kim * destroy cache.
4892aff063e2SJaegeuk Kim */
4893aff063e2SJaegeuk Kim rcu_barrier();
4894aff063e2SJaegeuk Kim kmem_cache_destroy(f2fs_inode_cachep);
4895aff063e2SJaegeuk Kim }
4896aff063e2SJaegeuk Kim
init_f2fs_fs(void)4897aff063e2SJaegeuk Kim static int __init init_f2fs_fs(void)
4898aff063e2SJaegeuk Kim {
4899aff063e2SJaegeuk Kim int err;
4900aff063e2SJaegeuk Kim
49014071e67cSAnatoly Pugachev if (PAGE_SIZE != F2FS_BLKSIZE) {
49024071e67cSAnatoly Pugachev printk("F2FS not supported on PAGE_SIZE(%lu) != %d\n",
49034071e67cSAnatoly Pugachev PAGE_SIZE, F2FS_BLKSIZE);
49044071e67cSAnatoly Pugachev return -EINVAL;
49054071e67cSAnatoly Pugachev }
49064071e67cSAnatoly Pugachev
4907aff063e2SJaegeuk Kim err = init_inodecache();
4908aff063e2SJaegeuk Kim if (err)
4909aff063e2SJaegeuk Kim goto fail;
49104d57b86dSChao Yu err = f2fs_create_node_manager_caches();
4911aff063e2SJaegeuk Kim if (err)
49129890ff3fSZhao Hongjiang goto free_inodecache;
49134d57b86dSChao Yu err = f2fs_create_segment_manager_caches();
4914aff063e2SJaegeuk Kim if (err)
49159890ff3fSZhao Hongjiang goto free_node_manager_caches;
49164d57b86dSChao Yu err = f2fs_create_checkpoint_caches();
4917aff063e2SJaegeuk Kim if (err)
491806292073SChao Yu goto free_segment_manager_caches;
4919cad83c96SChao Yu err = f2fs_create_recovery_cache();
49201dcc336bSChao Yu if (err)
49211dcc336bSChao Yu goto free_checkpoint_caches;
4922cad83c96SChao Yu err = f2fs_create_extent_cache();
4923cad83c96SChao Yu if (err)
4924cad83c96SChao Yu goto free_recovery_cache;
4925093749e2SChao Yu err = f2fs_create_garbage_collection_cache();
4926a398101aSChao Yu if (err)
49271dcc336bSChao Yu goto free_extent_cache;
4928093749e2SChao Yu err = f2fs_init_sysfs();
4929093749e2SChao Yu if (err)
4930093749e2SChao Yu goto free_garbage_collection_cache;
4931e33c267aSRoman Gushchin err = register_shrinker(&f2fs_shrinker_info, "f2fs-shrinker");
4932cfc4d971SJaegeuk Kim if (err)
4933a398101aSChao Yu goto free_sysfs;
493421acc07dSGreg Kroah-Hartman f2fs_create_root_stats();
49356dbb1796SEric Biggers err = f2fs_init_post_read_processing();
49366dbb1796SEric Biggers if (err)
49376dbb1796SEric Biggers goto free_root_stats;
4938a4b68176SDaeho Jeong err = f2fs_init_iostat_processing();
49390b20fcecSChao Yu if (err)
49400b20fcecSChao Yu goto free_post_read;
4941a4b68176SDaeho Jeong err = f2fs_init_bio_entry_cache();
4942a4b68176SDaeho Jeong if (err)
4943a4b68176SDaeho Jeong goto free_iostat;
4944f543805fSChao Yu err = f2fs_init_bioset();
4945f543805fSChao Yu if (err)
4946db8dcd25SColin Ian King goto free_bio_entry_cache;
49475e6bbde9SChao Yu err = f2fs_init_compress_mempool();
49485e6bbde9SChao Yu if (err)
49495e6bbde9SChao Yu goto free_bioset;
4950c68d6c88SChao Yu err = f2fs_init_compress_cache();
4951c68d6c88SChao Yu if (err)
4952c68d6c88SChao Yu goto free_compress_mempool;
49534d9a2bb1SChao Yu err = f2fs_create_casefold_cache();
49544d9a2bb1SChao Yu if (err)
49554d9a2bb1SChao Yu goto free_compress_cache;
4956*8dddc12dSYe Bin err = register_filesystem(&f2fs_fs_type);
4957*8dddc12dSYe Bin if (err)
4958*8dddc12dSYe Bin goto free_casefold_cache;
49599890ff3fSZhao Hongjiang return 0;
4960*8dddc12dSYe Bin free_casefold_cache:
4961*8dddc12dSYe Bin f2fs_destroy_casefold_cache();
49624d9a2bb1SChao Yu free_compress_cache:
49634d9a2bb1SChao Yu f2fs_destroy_compress_cache();
4964c68d6c88SChao Yu free_compress_mempool:
4965c68d6c88SChao Yu f2fs_destroy_compress_mempool();
49665e6bbde9SChao Yu free_bioset:
49675e6bbde9SChao Yu f2fs_destroy_bioset();
4968db8dcd25SColin Ian King free_bio_entry_cache:
4969f543805fSChao Yu f2fs_destroy_bio_entry_cache();
4970a4b68176SDaeho Jeong free_iostat:
4971a4b68176SDaeho Jeong f2fs_destroy_iostat_processing();
49720b20fcecSChao Yu free_post_read:
49730b20fcecSChao Yu f2fs_destroy_post_read_processing();
49746dbb1796SEric Biggers free_root_stats:
49756dbb1796SEric Biggers f2fs_destroy_root_stats();
49762658e50dSJaegeuk Kim unregister_shrinker(&f2fs_shrinker_info);
4977a398101aSChao Yu free_sysfs:
4978dc6b2055SJaegeuk Kim f2fs_exit_sysfs();
4979093749e2SChao Yu free_garbage_collection_cache:
4980093749e2SChao Yu f2fs_destroy_garbage_collection_cache();
49811dcc336bSChao Yu free_extent_cache:
49824d57b86dSChao Yu f2fs_destroy_extent_cache();
4983cad83c96SChao Yu free_recovery_cache:
4984cad83c96SChao Yu f2fs_destroy_recovery_cache();
49859890ff3fSZhao Hongjiang free_checkpoint_caches:
49864d57b86dSChao Yu f2fs_destroy_checkpoint_caches();
49877fd9e544SJaegeuk Kim free_segment_manager_caches:
49884d57b86dSChao Yu f2fs_destroy_segment_manager_caches();
49899890ff3fSZhao Hongjiang free_node_manager_caches:
49904d57b86dSChao Yu f2fs_destroy_node_manager_caches();
49919890ff3fSZhao Hongjiang free_inodecache:
49929890ff3fSZhao Hongjiang destroy_inodecache();
4993aff063e2SJaegeuk Kim fail:
4994aff063e2SJaegeuk Kim return err;
4995aff063e2SJaegeuk Kim }
4996aff063e2SJaegeuk Kim
exit_f2fs_fs(void)4997aff063e2SJaegeuk Kim static void __exit exit_f2fs_fs(void)
4998aff063e2SJaegeuk Kim {
4999*8dddc12dSYe Bin unregister_filesystem(&f2fs_fs_type);
50004d9a2bb1SChao Yu f2fs_destroy_casefold_cache();
5001c68d6c88SChao Yu f2fs_destroy_compress_cache();
50025e6bbde9SChao Yu f2fs_destroy_compress_mempool();
5003f543805fSChao Yu f2fs_destroy_bioset();
50040b20fcecSChao Yu f2fs_destroy_bio_entry_cache();
5005a4b68176SDaeho Jeong f2fs_destroy_iostat_processing();
50066dbb1796SEric Biggers f2fs_destroy_post_read_processing();
50074589d25dSNamjae Jeon f2fs_destroy_root_stats();
5008b8bef79dSTiezhu Yang unregister_shrinker(&f2fs_shrinker_info);
5009dc6b2055SJaegeuk Kim f2fs_exit_sysfs();
5010093749e2SChao Yu f2fs_destroy_garbage_collection_cache();
50114d57b86dSChao Yu f2fs_destroy_extent_cache();
5012cad83c96SChao Yu f2fs_destroy_recovery_cache();
50134d57b86dSChao Yu f2fs_destroy_checkpoint_caches();
50144d57b86dSChao Yu f2fs_destroy_segment_manager_caches();
50154d57b86dSChao Yu f2fs_destroy_node_manager_caches();
5016aff063e2SJaegeuk Kim destroy_inodecache();
5017aff063e2SJaegeuk Kim }
5018aff063e2SJaegeuk Kim
5019aff063e2SJaegeuk Kim module_init(init_f2fs_fs)
5020aff063e2SJaegeuk Kim module_exit(exit_f2fs_fs)
5021aff063e2SJaegeuk Kim
5022aff063e2SJaegeuk Kim MODULE_AUTHOR("Samsung Electronics's Praesto Team");
5023aff063e2SJaegeuk Kim MODULE_DESCRIPTION("Flash Friendly File System");
5024aff063e2SJaegeuk Kim MODULE_LICENSE("GPL");
50250dd57178SChao Yu MODULE_SOFTDEP("pre: crc32");
5026b4b9d34cSJaegeuk Kim
5027