162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/fs/ext4/super.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 1992, 1993, 1994, 1995
662306a36Sopenharmony_ci * Remy Card (card@masi.ibp.fr)
762306a36Sopenharmony_ci * Laboratoire MASI - Institut Blaise Pascal
862306a36Sopenharmony_ci * Universite Pierre et Marie Curie (Paris VI)
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *  from
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *  linux/fs/minix/inode.c
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *  Copyright (C) 1991, 1992  Linus Torvalds
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci *  Big-endian to little-endian byte-swapping/bitmaps by
1762306a36Sopenharmony_ci *        David S. Miller (davem@caip.rutgers.edu), 1995
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/string.h>
2262306a36Sopenharmony_ci#include <linux/fs.h>
2362306a36Sopenharmony_ci#include <linux/time.h>
2462306a36Sopenharmony_ci#include <linux/vmalloc.h>
2562306a36Sopenharmony_ci#include <linux/slab.h>
2662306a36Sopenharmony_ci#include <linux/init.h>
2762306a36Sopenharmony_ci#include <linux/blkdev.h>
2862306a36Sopenharmony_ci#include <linux/backing-dev.h>
2962306a36Sopenharmony_ci#include <linux/parser.h>
3062306a36Sopenharmony_ci#include <linux/buffer_head.h>
3162306a36Sopenharmony_ci#include <linux/exportfs.h>
3262306a36Sopenharmony_ci#include <linux/vfs.h>
3362306a36Sopenharmony_ci#include <linux/random.h>
3462306a36Sopenharmony_ci#include <linux/mount.h>
3562306a36Sopenharmony_ci#include <linux/namei.h>
3662306a36Sopenharmony_ci#include <linux/quotaops.h>
3762306a36Sopenharmony_ci#include <linux/seq_file.h>
3862306a36Sopenharmony_ci#include <linux/ctype.h>
3962306a36Sopenharmony_ci#include <linux/log2.h>
4062306a36Sopenharmony_ci#include <linux/crc16.h>
4162306a36Sopenharmony_ci#include <linux/dax.h>
4262306a36Sopenharmony_ci#include <linux/uaccess.h>
4362306a36Sopenharmony_ci#include <linux/iversion.h>
4462306a36Sopenharmony_ci#include <linux/unicode.h>
4562306a36Sopenharmony_ci#include <linux/part_stat.h>
4662306a36Sopenharmony_ci#include <linux/kthread.h>
4762306a36Sopenharmony_ci#include <linux/freezer.h>
4862306a36Sopenharmony_ci#include <linux/fsnotify.h>
4962306a36Sopenharmony_ci#include <linux/fs_context.h>
5062306a36Sopenharmony_ci#include <linux/fs_parser.h>
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#include "ext4.h"
5362306a36Sopenharmony_ci#include "ext4_extents.h"	/* Needed for trace points definition */
5462306a36Sopenharmony_ci#include "ext4_jbd2.h"
5562306a36Sopenharmony_ci#include "xattr.h"
5662306a36Sopenharmony_ci#include "acl.h"
5762306a36Sopenharmony_ci#include "mballoc.h"
5862306a36Sopenharmony_ci#include "fsmap.h"
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define CREATE_TRACE_POINTS
6162306a36Sopenharmony_ci#include <trace/events/ext4.h>
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic struct ext4_lazy_init *ext4_li_info;
6462306a36Sopenharmony_cistatic DEFINE_MUTEX(ext4_li_mtx);
6562306a36Sopenharmony_cistatic struct ratelimit_state ext4_mount_msg_ratelimit;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic int ext4_load_journal(struct super_block *, struct ext4_super_block *,
6862306a36Sopenharmony_ci			     unsigned long journal_devnum);
6962306a36Sopenharmony_cistatic int ext4_show_options(struct seq_file *seq, struct dentry *root);
7062306a36Sopenharmony_cistatic void ext4_update_super(struct super_block *sb);
7162306a36Sopenharmony_cistatic int ext4_commit_super(struct super_block *sb);
7262306a36Sopenharmony_cistatic int ext4_mark_recovery_complete(struct super_block *sb,
7362306a36Sopenharmony_ci					struct ext4_super_block *es);
7462306a36Sopenharmony_cistatic int ext4_clear_journal_err(struct super_block *sb,
7562306a36Sopenharmony_ci				  struct ext4_super_block *es);
7662306a36Sopenharmony_cistatic int ext4_sync_fs(struct super_block *sb, int wait);
7762306a36Sopenharmony_cistatic int ext4_statfs(struct dentry *dentry, struct kstatfs *buf);
7862306a36Sopenharmony_cistatic int ext4_unfreeze(struct super_block *sb);
7962306a36Sopenharmony_cistatic int ext4_freeze(struct super_block *sb);
8062306a36Sopenharmony_cistatic inline int ext2_feature_set_ok(struct super_block *sb);
8162306a36Sopenharmony_cistatic inline int ext3_feature_set_ok(struct super_block *sb);
8262306a36Sopenharmony_cistatic void ext4_destroy_lazyinit_thread(void);
8362306a36Sopenharmony_cistatic void ext4_unregister_li_request(struct super_block *sb);
8462306a36Sopenharmony_cistatic void ext4_clear_request_list(void);
8562306a36Sopenharmony_cistatic struct inode *ext4_get_journal_inode(struct super_block *sb,
8662306a36Sopenharmony_ci					    unsigned int journal_inum);
8762306a36Sopenharmony_cistatic int ext4_validate_options(struct fs_context *fc);
8862306a36Sopenharmony_cistatic int ext4_check_opt_consistency(struct fs_context *fc,
8962306a36Sopenharmony_ci				      struct super_block *sb);
9062306a36Sopenharmony_cistatic void ext4_apply_options(struct fs_context *fc, struct super_block *sb);
9162306a36Sopenharmony_cistatic int ext4_parse_param(struct fs_context *fc, struct fs_parameter *param);
9262306a36Sopenharmony_cistatic int ext4_get_tree(struct fs_context *fc);
9362306a36Sopenharmony_cistatic int ext4_reconfigure(struct fs_context *fc);
9462306a36Sopenharmony_cistatic void ext4_fc_free(struct fs_context *fc);
9562306a36Sopenharmony_cistatic int ext4_init_fs_context(struct fs_context *fc);
9662306a36Sopenharmony_cistatic void ext4_kill_sb(struct super_block *sb);
9762306a36Sopenharmony_cistatic const struct fs_parameter_spec ext4_param_specs[];
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/*
10062306a36Sopenharmony_ci * Lock ordering
10162306a36Sopenharmony_ci *
10262306a36Sopenharmony_ci * page fault path:
10362306a36Sopenharmony_ci * mmap_lock -> sb_start_pagefault -> invalidate_lock (r) -> transaction start
10462306a36Sopenharmony_ci *   -> page lock -> i_data_sem (rw)
10562306a36Sopenharmony_ci *
10662306a36Sopenharmony_ci * buffered write path:
10762306a36Sopenharmony_ci * sb_start_write -> i_mutex -> mmap_lock
10862306a36Sopenharmony_ci * sb_start_write -> i_mutex -> transaction start -> page lock ->
10962306a36Sopenharmony_ci *   i_data_sem (rw)
11062306a36Sopenharmony_ci *
11162306a36Sopenharmony_ci * truncate:
11262306a36Sopenharmony_ci * sb_start_write -> i_mutex -> invalidate_lock (w) -> i_mmap_rwsem (w) ->
11362306a36Sopenharmony_ci *   page lock
11462306a36Sopenharmony_ci * sb_start_write -> i_mutex -> invalidate_lock (w) -> transaction start ->
11562306a36Sopenharmony_ci *   i_data_sem (rw)
11662306a36Sopenharmony_ci *
11762306a36Sopenharmony_ci * direct IO:
11862306a36Sopenharmony_ci * sb_start_write -> i_mutex -> mmap_lock
11962306a36Sopenharmony_ci * sb_start_write -> i_mutex -> transaction start -> i_data_sem (rw)
12062306a36Sopenharmony_ci *
12162306a36Sopenharmony_ci * writepages:
12262306a36Sopenharmony_ci * transaction start -> page lock(s) -> i_data_sem (rw)
12362306a36Sopenharmony_ci */
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic const struct fs_context_operations ext4_context_ops = {
12662306a36Sopenharmony_ci	.parse_param	= ext4_parse_param,
12762306a36Sopenharmony_ci	.get_tree	= ext4_get_tree,
12862306a36Sopenharmony_ci	.reconfigure	= ext4_reconfigure,
12962306a36Sopenharmony_ci	.free		= ext4_fc_free,
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci#if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT2)
13462306a36Sopenharmony_cistatic struct file_system_type ext2_fs_type = {
13562306a36Sopenharmony_ci	.owner			= THIS_MODULE,
13662306a36Sopenharmony_ci	.name			= "ext2",
13762306a36Sopenharmony_ci	.init_fs_context	= ext4_init_fs_context,
13862306a36Sopenharmony_ci	.parameters		= ext4_param_specs,
13962306a36Sopenharmony_ci	.kill_sb		= ext4_kill_sb,
14062306a36Sopenharmony_ci	.fs_flags		= FS_REQUIRES_DEV,
14162306a36Sopenharmony_ci};
14262306a36Sopenharmony_ciMODULE_ALIAS_FS("ext2");
14362306a36Sopenharmony_ciMODULE_ALIAS("ext2");
14462306a36Sopenharmony_ci#define IS_EXT2_SB(sb) ((sb)->s_type == &ext2_fs_type)
14562306a36Sopenharmony_ci#else
14662306a36Sopenharmony_ci#define IS_EXT2_SB(sb) (0)
14762306a36Sopenharmony_ci#endif
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic struct file_system_type ext3_fs_type = {
15162306a36Sopenharmony_ci	.owner			= THIS_MODULE,
15262306a36Sopenharmony_ci	.name			= "ext3",
15362306a36Sopenharmony_ci	.init_fs_context	= ext4_init_fs_context,
15462306a36Sopenharmony_ci	.parameters		= ext4_param_specs,
15562306a36Sopenharmony_ci	.kill_sb		= ext4_kill_sb,
15662306a36Sopenharmony_ci	.fs_flags		= FS_REQUIRES_DEV,
15762306a36Sopenharmony_ci};
15862306a36Sopenharmony_ciMODULE_ALIAS_FS("ext3");
15962306a36Sopenharmony_ciMODULE_ALIAS("ext3");
16062306a36Sopenharmony_ci#define IS_EXT3_SB(sb) ((sb)->s_type == &ext3_fs_type)
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic inline void __ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags,
16462306a36Sopenharmony_ci				  bh_end_io_t *end_io)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	/*
16762306a36Sopenharmony_ci	 * buffer's verified bit is no longer valid after reading from
16862306a36Sopenharmony_ci	 * disk again due to write out error, clear it to make sure we
16962306a36Sopenharmony_ci	 * recheck the buffer contents.
17062306a36Sopenharmony_ci	 */
17162306a36Sopenharmony_ci	clear_buffer_verified(bh);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	bh->b_end_io = end_io ? end_io : end_buffer_read_sync;
17462306a36Sopenharmony_ci	get_bh(bh);
17562306a36Sopenharmony_ci	submit_bh(REQ_OP_READ | op_flags, bh);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_civoid ext4_read_bh_nowait(struct buffer_head *bh, blk_opf_t op_flags,
17962306a36Sopenharmony_ci			 bh_end_io_t *end_io)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	BUG_ON(!buffer_locked(bh));
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (ext4_buffer_uptodate(bh)) {
18462306a36Sopenharmony_ci		unlock_buffer(bh);
18562306a36Sopenharmony_ci		return;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci	__ext4_read_bh(bh, op_flags, end_io);
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ciint ext4_read_bh(struct buffer_head *bh, blk_opf_t op_flags, bh_end_io_t *end_io)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	BUG_ON(!buffer_locked(bh));
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	if (ext4_buffer_uptodate(bh)) {
19562306a36Sopenharmony_ci		unlock_buffer(bh);
19662306a36Sopenharmony_ci		return 0;
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	__ext4_read_bh(bh, op_flags, end_io);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	wait_on_buffer(bh);
20262306a36Sopenharmony_ci	if (buffer_uptodate(bh))
20362306a36Sopenharmony_ci		return 0;
20462306a36Sopenharmony_ci	return -EIO;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ciint ext4_read_bh_lock(struct buffer_head *bh, blk_opf_t op_flags, bool wait)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	lock_buffer(bh);
21062306a36Sopenharmony_ci	if (!wait) {
21162306a36Sopenharmony_ci		ext4_read_bh_nowait(bh, op_flags, NULL);
21262306a36Sopenharmony_ci		return 0;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci	return ext4_read_bh(bh, op_flags, NULL);
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/*
21862306a36Sopenharmony_ci * This works like __bread_gfp() except it uses ERR_PTR for error
21962306a36Sopenharmony_ci * returns.  Currently with sb_bread it's impossible to distinguish
22062306a36Sopenharmony_ci * between ENOMEM and EIO situations (since both result in a NULL
22162306a36Sopenharmony_ci * return.
22262306a36Sopenharmony_ci */
22362306a36Sopenharmony_cistatic struct buffer_head *__ext4_sb_bread_gfp(struct super_block *sb,
22462306a36Sopenharmony_ci					       sector_t block,
22562306a36Sopenharmony_ci					       blk_opf_t op_flags, gfp_t gfp)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct buffer_head *bh;
22862306a36Sopenharmony_ci	int ret;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	bh = sb_getblk_gfp(sb, block, gfp);
23162306a36Sopenharmony_ci	if (bh == NULL)
23262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
23362306a36Sopenharmony_ci	if (ext4_buffer_uptodate(bh))
23462306a36Sopenharmony_ci		return bh;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	ret = ext4_read_bh_lock(bh, REQ_META | op_flags, true);
23762306a36Sopenharmony_ci	if (ret) {
23862306a36Sopenharmony_ci		put_bh(bh);
23962306a36Sopenharmony_ci		return ERR_PTR(ret);
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci	return bh;
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistruct buffer_head *ext4_sb_bread(struct super_block *sb, sector_t block,
24562306a36Sopenharmony_ci				   blk_opf_t op_flags)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	return __ext4_sb_bread_gfp(sb, block, op_flags, __GFP_MOVABLE);
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistruct buffer_head *ext4_sb_bread_unmovable(struct super_block *sb,
25162306a36Sopenharmony_ci					    sector_t block)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	return __ext4_sb_bread_gfp(sb, block, 0, 0);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_civoid ext4_sb_breadahead_unmovable(struct super_block *sb, sector_t block)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	struct buffer_head *bh = sb_getblk_gfp(sb, block, 0);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	if (likely(bh)) {
26162306a36Sopenharmony_ci		if (trylock_buffer(bh))
26262306a36Sopenharmony_ci			ext4_read_bh_nowait(bh, REQ_RAHEAD, NULL);
26362306a36Sopenharmony_ci		brelse(bh);
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int ext4_verify_csum_type(struct super_block *sb,
26862306a36Sopenharmony_ci				 struct ext4_super_block *es)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	if (!ext4_has_feature_metadata_csum(sb))
27162306a36Sopenharmony_ci		return 1;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return es->s_checksum_type == EXT4_CRC32C_CHKSUM;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci__le32 ext4_superblock_csum(struct super_block *sb,
27762306a36Sopenharmony_ci			    struct ext4_super_block *es)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
28062306a36Sopenharmony_ci	int offset = offsetof(struct ext4_super_block, s_checksum);
28162306a36Sopenharmony_ci	__u32 csum;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	csum = ext4_chksum(sbi, ~0, (char *)es, offset);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	return cpu_to_le32(csum);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic int ext4_superblock_csum_verify(struct super_block *sb,
28962306a36Sopenharmony_ci				       struct ext4_super_block *es)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	if (!ext4_has_metadata_csum(sb))
29262306a36Sopenharmony_ci		return 1;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	return es->s_checksum == ext4_superblock_csum(sb, es);
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_civoid ext4_superblock_csum_set(struct super_block *sb)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct ext4_super_block *es = EXT4_SB(sb)->s_es;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (!ext4_has_metadata_csum(sb))
30262306a36Sopenharmony_ci		return;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	es->s_checksum = ext4_superblock_csum(sb, es);
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ciext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
30862306a36Sopenharmony_ci			       struct ext4_group_desc *bg)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	return le32_to_cpu(bg->bg_block_bitmap_lo) |
31162306a36Sopenharmony_ci		(EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
31262306a36Sopenharmony_ci		 (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0);
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ciext4_fsblk_t ext4_inode_bitmap(struct super_block *sb,
31662306a36Sopenharmony_ci			       struct ext4_group_desc *bg)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	return le32_to_cpu(bg->bg_inode_bitmap_lo) |
31962306a36Sopenharmony_ci		(EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
32062306a36Sopenharmony_ci		 (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0);
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ciext4_fsblk_t ext4_inode_table(struct super_block *sb,
32462306a36Sopenharmony_ci			      struct ext4_group_desc *bg)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	return le32_to_cpu(bg->bg_inode_table_lo) |
32762306a36Sopenharmony_ci		(EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
32862306a36Sopenharmony_ci		 (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0);
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci__u32 ext4_free_group_clusters(struct super_block *sb,
33262306a36Sopenharmony_ci			       struct ext4_group_desc *bg)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	return le16_to_cpu(bg->bg_free_blocks_count_lo) |
33562306a36Sopenharmony_ci		(EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
33662306a36Sopenharmony_ci		 (__u32)le16_to_cpu(bg->bg_free_blocks_count_hi) << 16 : 0);
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci__u32 ext4_free_inodes_count(struct super_block *sb,
34062306a36Sopenharmony_ci			      struct ext4_group_desc *bg)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	return le16_to_cpu(bg->bg_free_inodes_count_lo) |
34362306a36Sopenharmony_ci		(EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
34462306a36Sopenharmony_ci		 (__u32)le16_to_cpu(bg->bg_free_inodes_count_hi) << 16 : 0);
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci__u32 ext4_used_dirs_count(struct super_block *sb,
34862306a36Sopenharmony_ci			      struct ext4_group_desc *bg)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	return le16_to_cpu(bg->bg_used_dirs_count_lo) |
35162306a36Sopenharmony_ci		(EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
35262306a36Sopenharmony_ci		 (__u32)le16_to_cpu(bg->bg_used_dirs_count_hi) << 16 : 0);
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci__u32 ext4_itable_unused_count(struct super_block *sb,
35662306a36Sopenharmony_ci			      struct ext4_group_desc *bg)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	return le16_to_cpu(bg->bg_itable_unused_lo) |
35962306a36Sopenharmony_ci		(EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
36062306a36Sopenharmony_ci		 (__u32)le16_to_cpu(bg->bg_itable_unused_hi) << 16 : 0);
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_civoid ext4_block_bitmap_set(struct super_block *sb,
36462306a36Sopenharmony_ci			   struct ext4_group_desc *bg, ext4_fsblk_t blk)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	bg->bg_block_bitmap_lo = cpu_to_le32((u32)blk);
36762306a36Sopenharmony_ci	if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
36862306a36Sopenharmony_ci		bg->bg_block_bitmap_hi = cpu_to_le32(blk >> 32);
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_civoid ext4_inode_bitmap_set(struct super_block *sb,
37262306a36Sopenharmony_ci			   struct ext4_group_desc *bg, ext4_fsblk_t blk)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	bg->bg_inode_bitmap_lo  = cpu_to_le32((u32)blk);
37562306a36Sopenharmony_ci	if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
37662306a36Sopenharmony_ci		bg->bg_inode_bitmap_hi = cpu_to_le32(blk >> 32);
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_civoid ext4_inode_table_set(struct super_block *sb,
38062306a36Sopenharmony_ci			  struct ext4_group_desc *bg, ext4_fsblk_t blk)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	bg->bg_inode_table_lo = cpu_to_le32((u32)blk);
38362306a36Sopenharmony_ci	if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
38462306a36Sopenharmony_ci		bg->bg_inode_table_hi = cpu_to_le32(blk >> 32);
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_civoid ext4_free_group_clusters_set(struct super_block *sb,
38862306a36Sopenharmony_ci				  struct ext4_group_desc *bg, __u32 count)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	bg->bg_free_blocks_count_lo = cpu_to_le16((__u16)count);
39162306a36Sopenharmony_ci	if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
39262306a36Sopenharmony_ci		bg->bg_free_blocks_count_hi = cpu_to_le16(count >> 16);
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_civoid ext4_free_inodes_set(struct super_block *sb,
39662306a36Sopenharmony_ci			  struct ext4_group_desc *bg, __u32 count)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	bg->bg_free_inodes_count_lo = cpu_to_le16((__u16)count);
39962306a36Sopenharmony_ci	if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
40062306a36Sopenharmony_ci		bg->bg_free_inodes_count_hi = cpu_to_le16(count >> 16);
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_civoid ext4_used_dirs_set(struct super_block *sb,
40462306a36Sopenharmony_ci			  struct ext4_group_desc *bg, __u32 count)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	bg->bg_used_dirs_count_lo = cpu_to_le16((__u16)count);
40762306a36Sopenharmony_ci	if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
40862306a36Sopenharmony_ci		bg->bg_used_dirs_count_hi = cpu_to_le16(count >> 16);
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_civoid ext4_itable_unused_set(struct super_block *sb,
41262306a36Sopenharmony_ci			  struct ext4_group_desc *bg, __u32 count)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	bg->bg_itable_unused_lo = cpu_to_le16((__u16)count);
41562306a36Sopenharmony_ci	if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
41662306a36Sopenharmony_ci		bg->bg_itable_unused_hi = cpu_to_le16(count >> 16);
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic void __ext4_update_tstamp(__le32 *lo, __u8 *hi, time64_t now)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	now = clamp_val(now, 0, (1ull << 40) - 1);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	*lo = cpu_to_le32(lower_32_bits(now));
42462306a36Sopenharmony_ci	*hi = upper_32_bits(now);
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic time64_t __ext4_get_tstamp(__le32 *lo, __u8 *hi)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	return ((time64_t)(*hi) << 32) + le32_to_cpu(*lo);
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci#define ext4_update_tstamp(es, tstamp) \
43262306a36Sopenharmony_ci	__ext4_update_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi, \
43362306a36Sopenharmony_ci			     ktime_get_real_seconds())
43462306a36Sopenharmony_ci#define ext4_get_tstamp(es, tstamp) \
43562306a36Sopenharmony_ci	__ext4_get_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi)
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci#define EXT4_SB_REFRESH_INTERVAL_SEC (3600) /* seconds (1 hour) */
43862306a36Sopenharmony_ci#define EXT4_SB_REFRESH_INTERVAL_KB (16384) /* kilobytes (16MB) */
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci/*
44162306a36Sopenharmony_ci * The ext4_maybe_update_superblock() function checks and updates the
44262306a36Sopenharmony_ci * superblock if needed.
44362306a36Sopenharmony_ci *
44462306a36Sopenharmony_ci * This function is designed to update the on-disk superblock only under
44562306a36Sopenharmony_ci * certain conditions to prevent excessive disk writes and unnecessary
44662306a36Sopenharmony_ci * waking of the disk from sleep. The superblock will be updated if:
44762306a36Sopenharmony_ci * 1. More than an hour has passed since the last superblock update, and
44862306a36Sopenharmony_ci * 2. More than 16MB have been written since the last superblock update.
44962306a36Sopenharmony_ci *
45062306a36Sopenharmony_ci * @sb: The superblock
45162306a36Sopenharmony_ci */
45262306a36Sopenharmony_cistatic void ext4_maybe_update_superblock(struct super_block *sb)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
45562306a36Sopenharmony_ci	struct ext4_super_block *es = sbi->s_es;
45662306a36Sopenharmony_ci	journal_t *journal = sbi->s_journal;
45762306a36Sopenharmony_ci	time64_t now;
45862306a36Sopenharmony_ci	__u64 last_update;
45962306a36Sopenharmony_ci	__u64 lifetime_write_kbytes;
46062306a36Sopenharmony_ci	__u64 diff_size;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	if (sb_rdonly(sb) || !(sb->s_flags & SB_ACTIVE) ||
46362306a36Sopenharmony_ci	    !journal || (journal->j_flags & JBD2_UNMOUNT))
46462306a36Sopenharmony_ci		return;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	now = ktime_get_real_seconds();
46762306a36Sopenharmony_ci	last_update = ext4_get_tstamp(es, s_wtime);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	if (likely(now - last_update < EXT4_SB_REFRESH_INTERVAL_SEC))
47062306a36Sopenharmony_ci		return;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	lifetime_write_kbytes = sbi->s_kbytes_written +
47362306a36Sopenharmony_ci		((part_stat_read(sb->s_bdev, sectors[STAT_WRITE]) -
47462306a36Sopenharmony_ci		  sbi->s_sectors_written_start) >> 1);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	/* Get the number of kilobytes not written to disk to account
47762306a36Sopenharmony_ci	 * for statistics and compare with a multiple of 16 MB. This
47862306a36Sopenharmony_ci	 * is used to determine when the next superblock commit should
47962306a36Sopenharmony_ci	 * occur (i.e. not more often than once per 16MB if there was
48062306a36Sopenharmony_ci	 * less written in an hour).
48162306a36Sopenharmony_ci	 */
48262306a36Sopenharmony_ci	diff_size = lifetime_write_kbytes - le64_to_cpu(es->s_kbytes_written);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	if (diff_size > EXT4_SB_REFRESH_INTERVAL_KB)
48562306a36Sopenharmony_ci		schedule_work(&EXT4_SB(sb)->s_sb_upd_work);
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci/*
48962306a36Sopenharmony_ci * The del_gendisk() function uninitializes the disk-specific data
49062306a36Sopenharmony_ci * structures, including the bdi structure, without telling anyone
49162306a36Sopenharmony_ci * else.  Once this happens, any attempt to call mark_buffer_dirty()
49262306a36Sopenharmony_ci * (for example, by ext4_commit_super), will cause a kernel OOPS.
49362306a36Sopenharmony_ci * This is a kludge to prevent these oops until we can put in a proper
49462306a36Sopenharmony_ci * hook in del_gendisk() to inform the VFS and file system layers.
49562306a36Sopenharmony_ci */
49662306a36Sopenharmony_cistatic int block_device_ejected(struct super_block *sb)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	struct inode *bd_inode = sb->s_bdev->bd_inode;
49962306a36Sopenharmony_ci	struct backing_dev_info *bdi = inode_to_bdi(bd_inode);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	return bdi->dev == NULL;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	struct super_block		*sb = journal->j_private;
50762306a36Sopenharmony_ci	struct ext4_sb_info		*sbi = EXT4_SB(sb);
50862306a36Sopenharmony_ci	int				error = is_journal_aborted(journal);
50962306a36Sopenharmony_ci	struct ext4_journal_cb_entry	*jce;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	BUG_ON(txn->t_state == T_FINISHED);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	ext4_process_freed_data(sb, txn->t_tid);
51462306a36Sopenharmony_ci	ext4_maybe_update_superblock(sb);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	spin_lock(&sbi->s_md_lock);
51762306a36Sopenharmony_ci	while (!list_empty(&txn->t_private_list)) {
51862306a36Sopenharmony_ci		jce = list_entry(txn->t_private_list.next,
51962306a36Sopenharmony_ci				 struct ext4_journal_cb_entry, jce_list);
52062306a36Sopenharmony_ci		list_del_init(&jce->jce_list);
52162306a36Sopenharmony_ci		spin_unlock(&sbi->s_md_lock);
52262306a36Sopenharmony_ci		jce->jce_func(sb, jce, error);
52362306a36Sopenharmony_ci		spin_lock(&sbi->s_md_lock);
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci	spin_unlock(&sbi->s_md_lock);
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci/*
52962306a36Sopenharmony_ci * This writepage callback for write_cache_pages()
53062306a36Sopenharmony_ci * takes care of a few cases after page cleaning.
53162306a36Sopenharmony_ci *
53262306a36Sopenharmony_ci * write_cache_pages() already checks for dirty pages
53362306a36Sopenharmony_ci * and calls clear_page_dirty_for_io(), which we want,
53462306a36Sopenharmony_ci * to write protect the pages.
53562306a36Sopenharmony_ci *
53662306a36Sopenharmony_ci * However, we may have to redirty a page (see below.)
53762306a36Sopenharmony_ci */
53862306a36Sopenharmony_cistatic int ext4_journalled_writepage_callback(struct folio *folio,
53962306a36Sopenharmony_ci					      struct writeback_control *wbc,
54062306a36Sopenharmony_ci					      void *data)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	transaction_t *transaction = (transaction_t *) data;
54362306a36Sopenharmony_ci	struct buffer_head *bh, *head;
54462306a36Sopenharmony_ci	struct journal_head *jh;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	bh = head = folio_buffers(folio);
54762306a36Sopenharmony_ci	do {
54862306a36Sopenharmony_ci		/*
54962306a36Sopenharmony_ci		 * We have to redirty a page in these cases:
55062306a36Sopenharmony_ci		 * 1) If buffer is dirty, it means the page was dirty because it
55162306a36Sopenharmony_ci		 * contains a buffer that needs checkpointing. So the dirty bit
55262306a36Sopenharmony_ci		 * needs to be preserved so that checkpointing writes the buffer
55362306a36Sopenharmony_ci		 * properly.
55462306a36Sopenharmony_ci		 * 2) If buffer is not part of the committing transaction
55562306a36Sopenharmony_ci		 * (we may have just accidentally come across this buffer because
55662306a36Sopenharmony_ci		 * inode range tracking is not exact) or if the currently running
55762306a36Sopenharmony_ci		 * transaction already contains this buffer as well, dirty bit
55862306a36Sopenharmony_ci		 * needs to be preserved so that the buffer gets writeprotected
55962306a36Sopenharmony_ci		 * properly on running transaction's commit.
56062306a36Sopenharmony_ci		 */
56162306a36Sopenharmony_ci		jh = bh2jh(bh);
56262306a36Sopenharmony_ci		if (buffer_dirty(bh) ||
56362306a36Sopenharmony_ci		    (jh && (jh->b_transaction != transaction ||
56462306a36Sopenharmony_ci			    jh->b_next_transaction))) {
56562306a36Sopenharmony_ci			folio_redirty_for_writepage(wbc, folio);
56662306a36Sopenharmony_ci			goto out;
56762306a36Sopenharmony_ci		}
56862306a36Sopenharmony_ci	} while ((bh = bh->b_this_page) != head);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ciout:
57162306a36Sopenharmony_ci	return AOP_WRITEPAGE_ACTIVATE;
57262306a36Sopenharmony_ci}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_cistatic int ext4_journalled_submit_inode_data_buffers(struct jbd2_inode *jinode)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	struct address_space *mapping = jinode->i_vfs_inode->i_mapping;
57762306a36Sopenharmony_ci	struct writeback_control wbc = {
57862306a36Sopenharmony_ci		.sync_mode =  WB_SYNC_ALL,
57962306a36Sopenharmony_ci		.nr_to_write = LONG_MAX,
58062306a36Sopenharmony_ci		.range_start = jinode->i_dirty_start,
58162306a36Sopenharmony_ci		.range_end = jinode->i_dirty_end,
58262306a36Sopenharmony_ci        };
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	return write_cache_pages(mapping, &wbc,
58562306a36Sopenharmony_ci				 ext4_journalled_writepage_callback,
58662306a36Sopenharmony_ci				 jinode->i_transaction);
58762306a36Sopenharmony_ci}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_cistatic int ext4_journal_submit_inode_data_buffers(struct jbd2_inode *jinode)
59062306a36Sopenharmony_ci{
59162306a36Sopenharmony_ci	int ret;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (ext4_should_journal_data(jinode->i_vfs_inode))
59462306a36Sopenharmony_ci		ret = ext4_journalled_submit_inode_data_buffers(jinode);
59562306a36Sopenharmony_ci	else
59662306a36Sopenharmony_ci		ret = ext4_normal_submit_inode_data_buffers(jinode);
59762306a36Sopenharmony_ci	return ret;
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic int ext4_journal_finish_inode_data_buffers(struct jbd2_inode *jinode)
60162306a36Sopenharmony_ci{
60262306a36Sopenharmony_ci	int ret = 0;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (!ext4_should_journal_data(jinode->i_vfs_inode))
60562306a36Sopenharmony_ci		ret = jbd2_journal_finish_inode_data_buffers(jinode);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	return ret;
60862306a36Sopenharmony_ci}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cistatic bool system_going_down(void)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	return system_state == SYSTEM_HALT || system_state == SYSTEM_POWER_OFF
61362306a36Sopenharmony_ci		|| system_state == SYSTEM_RESTART;
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cistruct ext4_err_translation {
61762306a36Sopenharmony_ci	int code;
61862306a36Sopenharmony_ci	int errno;
61962306a36Sopenharmony_ci};
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci#define EXT4_ERR_TRANSLATE(err) { .code = EXT4_ERR_##err, .errno = err }
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic struct ext4_err_translation err_translation[] = {
62462306a36Sopenharmony_ci	EXT4_ERR_TRANSLATE(EIO),
62562306a36Sopenharmony_ci	EXT4_ERR_TRANSLATE(ENOMEM),
62662306a36Sopenharmony_ci	EXT4_ERR_TRANSLATE(EFSBADCRC),
62762306a36Sopenharmony_ci	EXT4_ERR_TRANSLATE(EFSCORRUPTED),
62862306a36Sopenharmony_ci	EXT4_ERR_TRANSLATE(ENOSPC),
62962306a36Sopenharmony_ci	EXT4_ERR_TRANSLATE(ENOKEY),
63062306a36Sopenharmony_ci	EXT4_ERR_TRANSLATE(EROFS),
63162306a36Sopenharmony_ci	EXT4_ERR_TRANSLATE(EFBIG),
63262306a36Sopenharmony_ci	EXT4_ERR_TRANSLATE(EEXIST),
63362306a36Sopenharmony_ci	EXT4_ERR_TRANSLATE(ERANGE),
63462306a36Sopenharmony_ci	EXT4_ERR_TRANSLATE(EOVERFLOW),
63562306a36Sopenharmony_ci	EXT4_ERR_TRANSLATE(EBUSY),
63662306a36Sopenharmony_ci	EXT4_ERR_TRANSLATE(ENOTDIR),
63762306a36Sopenharmony_ci	EXT4_ERR_TRANSLATE(ENOTEMPTY),
63862306a36Sopenharmony_ci	EXT4_ERR_TRANSLATE(ESHUTDOWN),
63962306a36Sopenharmony_ci	EXT4_ERR_TRANSLATE(EFAULT),
64062306a36Sopenharmony_ci};
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_cistatic int ext4_errno_to_code(int errno)
64362306a36Sopenharmony_ci{
64462306a36Sopenharmony_ci	int i;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(err_translation); i++)
64762306a36Sopenharmony_ci		if (err_translation[i].errno == errno)
64862306a36Sopenharmony_ci			return err_translation[i].code;
64962306a36Sopenharmony_ci	return EXT4_ERR_UNKNOWN;
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_cistatic void save_error_info(struct super_block *sb, int error,
65362306a36Sopenharmony_ci			    __u32 ino, __u64 block,
65462306a36Sopenharmony_ci			    const char *func, unsigned int line)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	/* We default to EFSCORRUPTED error... */
65962306a36Sopenharmony_ci	if (error == 0)
66062306a36Sopenharmony_ci		error = EFSCORRUPTED;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	spin_lock(&sbi->s_error_lock);
66362306a36Sopenharmony_ci	sbi->s_add_error_count++;
66462306a36Sopenharmony_ci	sbi->s_last_error_code = error;
66562306a36Sopenharmony_ci	sbi->s_last_error_line = line;
66662306a36Sopenharmony_ci	sbi->s_last_error_ino = ino;
66762306a36Sopenharmony_ci	sbi->s_last_error_block = block;
66862306a36Sopenharmony_ci	sbi->s_last_error_func = func;
66962306a36Sopenharmony_ci	sbi->s_last_error_time = ktime_get_real_seconds();
67062306a36Sopenharmony_ci	if (!sbi->s_first_error_time) {
67162306a36Sopenharmony_ci		sbi->s_first_error_code = error;
67262306a36Sopenharmony_ci		sbi->s_first_error_line = line;
67362306a36Sopenharmony_ci		sbi->s_first_error_ino = ino;
67462306a36Sopenharmony_ci		sbi->s_first_error_block = block;
67562306a36Sopenharmony_ci		sbi->s_first_error_func = func;
67662306a36Sopenharmony_ci		sbi->s_first_error_time = sbi->s_last_error_time;
67762306a36Sopenharmony_ci	}
67862306a36Sopenharmony_ci	spin_unlock(&sbi->s_error_lock);
67962306a36Sopenharmony_ci}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci/* Deal with the reporting of failure conditions on a filesystem such as
68262306a36Sopenharmony_ci * inconsistencies detected or read IO failures.
68362306a36Sopenharmony_ci *
68462306a36Sopenharmony_ci * On ext2, we can store the error state of the filesystem in the
68562306a36Sopenharmony_ci * superblock.  That is not possible on ext4, because we may have other
68662306a36Sopenharmony_ci * write ordering constraints on the superblock which prevent us from
68762306a36Sopenharmony_ci * writing it out straight away; and given that the journal is about to
68862306a36Sopenharmony_ci * be aborted, we can't rely on the current, or future, transactions to
68962306a36Sopenharmony_ci * write out the superblock safely.
69062306a36Sopenharmony_ci *
69162306a36Sopenharmony_ci * We'll just use the jbd2_journal_abort() error code to record an error in
69262306a36Sopenharmony_ci * the journal instead.  On recovery, the journal will complain about
69362306a36Sopenharmony_ci * that error until we've noted it down and cleared it.
69462306a36Sopenharmony_ci *
69562306a36Sopenharmony_ci * If force_ro is set, we unconditionally force the filesystem into an
69662306a36Sopenharmony_ci * ABORT|READONLY state, unless the error response on the fs has been set to
69762306a36Sopenharmony_ci * panic in which case we take the easy way out and panic immediately. This is
69862306a36Sopenharmony_ci * used to deal with unrecoverable failures such as journal IO errors or ENOMEM
69962306a36Sopenharmony_ci * at a critical moment in log management.
70062306a36Sopenharmony_ci */
70162306a36Sopenharmony_cistatic void ext4_handle_error(struct super_block *sb, bool force_ro, int error,
70262306a36Sopenharmony_ci			      __u32 ino, __u64 block,
70362306a36Sopenharmony_ci			      const char *func, unsigned int line)
70462306a36Sopenharmony_ci{
70562306a36Sopenharmony_ci	journal_t *journal = EXT4_SB(sb)->s_journal;
70662306a36Sopenharmony_ci	bool continue_fs = !force_ro && test_opt(sb, ERRORS_CONT);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
70962306a36Sopenharmony_ci	if (test_opt(sb, WARN_ON_ERROR))
71062306a36Sopenharmony_ci		WARN_ON_ONCE(1);
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	if (!continue_fs && !sb_rdonly(sb)) {
71362306a36Sopenharmony_ci		set_bit(EXT4_FLAGS_SHUTDOWN, &EXT4_SB(sb)->s_ext4_flags);
71462306a36Sopenharmony_ci		if (journal)
71562306a36Sopenharmony_ci			jbd2_journal_abort(journal, -EIO);
71662306a36Sopenharmony_ci	}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	if (!bdev_read_only(sb->s_bdev)) {
71962306a36Sopenharmony_ci		save_error_info(sb, error, ino, block, func, line);
72062306a36Sopenharmony_ci		/*
72162306a36Sopenharmony_ci		 * In case the fs should keep running, we need to writeout
72262306a36Sopenharmony_ci		 * superblock through the journal. Due to lock ordering
72362306a36Sopenharmony_ci		 * constraints, it may not be safe to do it right here so we
72462306a36Sopenharmony_ci		 * defer superblock flushing to a workqueue.
72562306a36Sopenharmony_ci		 */
72662306a36Sopenharmony_ci		if (continue_fs && journal)
72762306a36Sopenharmony_ci			schedule_work(&EXT4_SB(sb)->s_sb_upd_work);
72862306a36Sopenharmony_ci		else
72962306a36Sopenharmony_ci			ext4_commit_super(sb);
73062306a36Sopenharmony_ci	}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	/*
73362306a36Sopenharmony_ci	 * We force ERRORS_RO behavior when system is rebooting. Otherwise we
73462306a36Sopenharmony_ci	 * could panic during 'reboot -f' as the underlying device got already
73562306a36Sopenharmony_ci	 * disabled.
73662306a36Sopenharmony_ci	 */
73762306a36Sopenharmony_ci	if (test_opt(sb, ERRORS_PANIC) && !system_going_down()) {
73862306a36Sopenharmony_ci		panic("EXT4-fs (device %s): panic forced after error\n",
73962306a36Sopenharmony_ci			sb->s_id);
74062306a36Sopenharmony_ci	}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	if (sb_rdonly(sb) || continue_fs)
74362306a36Sopenharmony_ci		return;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
74662306a36Sopenharmony_ci	/*
74762306a36Sopenharmony_ci	 * Make sure updated value of ->s_mount_flags will be visible before
74862306a36Sopenharmony_ci	 * ->s_flags update
74962306a36Sopenharmony_ci	 */
75062306a36Sopenharmony_ci	smp_wmb();
75162306a36Sopenharmony_ci	sb->s_flags |= SB_RDONLY;
75262306a36Sopenharmony_ci}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_cistatic void update_super_work(struct work_struct *work)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	struct ext4_sb_info *sbi = container_of(work, struct ext4_sb_info,
75762306a36Sopenharmony_ci						s_sb_upd_work);
75862306a36Sopenharmony_ci	journal_t *journal = sbi->s_journal;
75962306a36Sopenharmony_ci	handle_t *handle;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	/*
76262306a36Sopenharmony_ci	 * If the journal is still running, we have to write out superblock
76362306a36Sopenharmony_ci	 * through the journal to avoid collisions of other journalled sb
76462306a36Sopenharmony_ci	 * updates.
76562306a36Sopenharmony_ci	 *
76662306a36Sopenharmony_ci	 * We use directly jbd2 functions here to avoid recursing back into
76762306a36Sopenharmony_ci	 * ext4 error handling code during handling of previous errors.
76862306a36Sopenharmony_ci	 */
76962306a36Sopenharmony_ci	if (!sb_rdonly(sbi->s_sb) && journal) {
77062306a36Sopenharmony_ci		struct buffer_head *sbh = sbi->s_sbh;
77162306a36Sopenharmony_ci		bool call_notify_err = false;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci		handle = jbd2_journal_start(journal, 1);
77462306a36Sopenharmony_ci		if (IS_ERR(handle))
77562306a36Sopenharmony_ci			goto write_directly;
77662306a36Sopenharmony_ci		if (jbd2_journal_get_write_access(handle, sbh)) {
77762306a36Sopenharmony_ci			jbd2_journal_stop(handle);
77862306a36Sopenharmony_ci			goto write_directly;
77962306a36Sopenharmony_ci		}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci		if (sbi->s_add_error_count > 0)
78262306a36Sopenharmony_ci			call_notify_err = true;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci		ext4_update_super(sbi->s_sb);
78562306a36Sopenharmony_ci		if (buffer_write_io_error(sbh) || !buffer_uptodate(sbh)) {
78662306a36Sopenharmony_ci			ext4_msg(sbi->s_sb, KERN_ERR, "previous I/O error to "
78762306a36Sopenharmony_ci				 "superblock detected");
78862306a36Sopenharmony_ci			clear_buffer_write_io_error(sbh);
78962306a36Sopenharmony_ci			set_buffer_uptodate(sbh);
79062306a36Sopenharmony_ci		}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci		if (jbd2_journal_dirty_metadata(handle, sbh)) {
79362306a36Sopenharmony_ci			jbd2_journal_stop(handle);
79462306a36Sopenharmony_ci			goto write_directly;
79562306a36Sopenharmony_ci		}
79662306a36Sopenharmony_ci		jbd2_journal_stop(handle);
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci		if (call_notify_err)
79962306a36Sopenharmony_ci			ext4_notify_error_sysfs(sbi);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci		return;
80262306a36Sopenharmony_ci	}
80362306a36Sopenharmony_ciwrite_directly:
80462306a36Sopenharmony_ci	/*
80562306a36Sopenharmony_ci	 * Write through journal failed. Write sb directly to get error info
80662306a36Sopenharmony_ci	 * out and hope for the best.
80762306a36Sopenharmony_ci	 */
80862306a36Sopenharmony_ci	ext4_commit_super(sbi->s_sb);
80962306a36Sopenharmony_ci	ext4_notify_error_sysfs(sbi);
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci#define ext4_error_ratelimit(sb)					\
81362306a36Sopenharmony_ci		___ratelimit(&(EXT4_SB(sb)->s_err_ratelimit_state),	\
81462306a36Sopenharmony_ci			     "EXT4-fs error")
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_civoid __ext4_error(struct super_block *sb, const char *function,
81762306a36Sopenharmony_ci		  unsigned int line, bool force_ro, int error, __u64 block,
81862306a36Sopenharmony_ci		  const char *fmt, ...)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	struct va_format vaf;
82162306a36Sopenharmony_ci	va_list args;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	if (unlikely(ext4_forced_shutdown(sb)))
82462306a36Sopenharmony_ci		return;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	trace_ext4_error(sb, function, line);
82762306a36Sopenharmony_ci	if (ext4_error_ratelimit(sb)) {
82862306a36Sopenharmony_ci		va_start(args, fmt);
82962306a36Sopenharmony_ci		vaf.fmt = fmt;
83062306a36Sopenharmony_ci		vaf.va = &args;
83162306a36Sopenharmony_ci		printk(KERN_CRIT
83262306a36Sopenharmony_ci		       "EXT4-fs error (device %s): %s:%d: comm %s: %pV\n",
83362306a36Sopenharmony_ci		       sb->s_id, function, line, current->comm, &vaf);
83462306a36Sopenharmony_ci		va_end(args);
83562306a36Sopenharmony_ci	}
83662306a36Sopenharmony_ci	fsnotify_sb_error(sb, NULL, error ? error : EFSCORRUPTED);
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	ext4_handle_error(sb, force_ro, error, 0, block, function, line);
83962306a36Sopenharmony_ci}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_civoid __ext4_error_inode(struct inode *inode, const char *function,
84262306a36Sopenharmony_ci			unsigned int line, ext4_fsblk_t block, int error,
84362306a36Sopenharmony_ci			const char *fmt, ...)
84462306a36Sopenharmony_ci{
84562306a36Sopenharmony_ci	va_list args;
84662306a36Sopenharmony_ci	struct va_format vaf;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	if (unlikely(ext4_forced_shutdown(inode->i_sb)))
84962306a36Sopenharmony_ci		return;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	trace_ext4_error(inode->i_sb, function, line);
85262306a36Sopenharmony_ci	if (ext4_error_ratelimit(inode->i_sb)) {
85362306a36Sopenharmony_ci		va_start(args, fmt);
85462306a36Sopenharmony_ci		vaf.fmt = fmt;
85562306a36Sopenharmony_ci		vaf.va = &args;
85662306a36Sopenharmony_ci		if (block)
85762306a36Sopenharmony_ci			printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: "
85862306a36Sopenharmony_ci			       "inode #%lu: block %llu: comm %s: %pV\n",
85962306a36Sopenharmony_ci			       inode->i_sb->s_id, function, line, inode->i_ino,
86062306a36Sopenharmony_ci			       block, current->comm, &vaf);
86162306a36Sopenharmony_ci		else
86262306a36Sopenharmony_ci			printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: "
86362306a36Sopenharmony_ci			       "inode #%lu: comm %s: %pV\n",
86462306a36Sopenharmony_ci			       inode->i_sb->s_id, function, line, inode->i_ino,
86562306a36Sopenharmony_ci			       current->comm, &vaf);
86662306a36Sopenharmony_ci		va_end(args);
86762306a36Sopenharmony_ci	}
86862306a36Sopenharmony_ci	fsnotify_sb_error(inode->i_sb, inode, error ? error : EFSCORRUPTED);
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	ext4_handle_error(inode->i_sb, false, error, inode->i_ino, block,
87162306a36Sopenharmony_ci			  function, line);
87262306a36Sopenharmony_ci}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_civoid __ext4_error_file(struct file *file, const char *function,
87562306a36Sopenharmony_ci		       unsigned int line, ext4_fsblk_t block,
87662306a36Sopenharmony_ci		       const char *fmt, ...)
87762306a36Sopenharmony_ci{
87862306a36Sopenharmony_ci	va_list args;
87962306a36Sopenharmony_ci	struct va_format vaf;
88062306a36Sopenharmony_ci	struct inode *inode = file_inode(file);
88162306a36Sopenharmony_ci	char pathname[80], *path;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	if (unlikely(ext4_forced_shutdown(inode->i_sb)))
88462306a36Sopenharmony_ci		return;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	trace_ext4_error(inode->i_sb, function, line);
88762306a36Sopenharmony_ci	if (ext4_error_ratelimit(inode->i_sb)) {
88862306a36Sopenharmony_ci		path = file_path(file, pathname, sizeof(pathname));
88962306a36Sopenharmony_ci		if (IS_ERR(path))
89062306a36Sopenharmony_ci			path = "(unknown)";
89162306a36Sopenharmony_ci		va_start(args, fmt);
89262306a36Sopenharmony_ci		vaf.fmt = fmt;
89362306a36Sopenharmony_ci		vaf.va = &args;
89462306a36Sopenharmony_ci		if (block)
89562306a36Sopenharmony_ci			printk(KERN_CRIT
89662306a36Sopenharmony_ci			       "EXT4-fs error (device %s): %s:%d: inode #%lu: "
89762306a36Sopenharmony_ci			       "block %llu: comm %s: path %s: %pV\n",
89862306a36Sopenharmony_ci			       inode->i_sb->s_id, function, line, inode->i_ino,
89962306a36Sopenharmony_ci			       block, current->comm, path, &vaf);
90062306a36Sopenharmony_ci		else
90162306a36Sopenharmony_ci			printk(KERN_CRIT
90262306a36Sopenharmony_ci			       "EXT4-fs error (device %s): %s:%d: inode #%lu: "
90362306a36Sopenharmony_ci			       "comm %s: path %s: %pV\n",
90462306a36Sopenharmony_ci			       inode->i_sb->s_id, function, line, inode->i_ino,
90562306a36Sopenharmony_ci			       current->comm, path, &vaf);
90662306a36Sopenharmony_ci		va_end(args);
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci	fsnotify_sb_error(inode->i_sb, inode, EFSCORRUPTED);
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	ext4_handle_error(inode->i_sb, false, EFSCORRUPTED, inode->i_ino, block,
91162306a36Sopenharmony_ci			  function, line);
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ciconst char *ext4_decode_error(struct super_block *sb, int errno,
91562306a36Sopenharmony_ci			      char nbuf[16])
91662306a36Sopenharmony_ci{
91762306a36Sopenharmony_ci	char *errstr = NULL;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	switch (errno) {
92062306a36Sopenharmony_ci	case -EFSCORRUPTED:
92162306a36Sopenharmony_ci		errstr = "Corrupt filesystem";
92262306a36Sopenharmony_ci		break;
92362306a36Sopenharmony_ci	case -EFSBADCRC:
92462306a36Sopenharmony_ci		errstr = "Filesystem failed CRC";
92562306a36Sopenharmony_ci		break;
92662306a36Sopenharmony_ci	case -EIO:
92762306a36Sopenharmony_ci		errstr = "IO failure";
92862306a36Sopenharmony_ci		break;
92962306a36Sopenharmony_ci	case -ENOMEM:
93062306a36Sopenharmony_ci		errstr = "Out of memory";
93162306a36Sopenharmony_ci		break;
93262306a36Sopenharmony_ci	case -EROFS:
93362306a36Sopenharmony_ci		if (!sb || (EXT4_SB(sb)->s_journal &&
93462306a36Sopenharmony_ci			    EXT4_SB(sb)->s_journal->j_flags & JBD2_ABORT))
93562306a36Sopenharmony_ci			errstr = "Journal has aborted";
93662306a36Sopenharmony_ci		else
93762306a36Sopenharmony_ci			errstr = "Readonly filesystem";
93862306a36Sopenharmony_ci		break;
93962306a36Sopenharmony_ci	default:
94062306a36Sopenharmony_ci		/* If the caller passed in an extra buffer for unknown
94162306a36Sopenharmony_ci		 * errors, textualise them now.  Else we just return
94262306a36Sopenharmony_ci		 * NULL. */
94362306a36Sopenharmony_ci		if (nbuf) {
94462306a36Sopenharmony_ci			/* Check for truncated error codes... */
94562306a36Sopenharmony_ci			if (snprintf(nbuf, 16, "error %d", -errno) >= 0)
94662306a36Sopenharmony_ci				errstr = nbuf;
94762306a36Sopenharmony_ci		}
94862306a36Sopenharmony_ci		break;
94962306a36Sopenharmony_ci	}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	return errstr;
95262306a36Sopenharmony_ci}
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci/* __ext4_std_error decodes expected errors from journaling functions
95562306a36Sopenharmony_ci * automatically and invokes the appropriate error response.  */
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_civoid __ext4_std_error(struct super_block *sb, const char *function,
95862306a36Sopenharmony_ci		      unsigned int line, int errno)
95962306a36Sopenharmony_ci{
96062306a36Sopenharmony_ci	char nbuf[16];
96162306a36Sopenharmony_ci	const char *errstr;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	if (unlikely(ext4_forced_shutdown(sb)))
96462306a36Sopenharmony_ci		return;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	/* Special case: if the error is EROFS, and we're not already
96762306a36Sopenharmony_ci	 * inside a transaction, then there's really no point in logging
96862306a36Sopenharmony_ci	 * an error. */
96962306a36Sopenharmony_ci	if (errno == -EROFS && journal_current_handle() == NULL && sb_rdonly(sb))
97062306a36Sopenharmony_ci		return;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	if (ext4_error_ratelimit(sb)) {
97362306a36Sopenharmony_ci		errstr = ext4_decode_error(sb, errno, nbuf);
97462306a36Sopenharmony_ci		printk(KERN_CRIT "EXT4-fs error (device %s) in %s:%d: %s\n",
97562306a36Sopenharmony_ci		       sb->s_id, function, line, errstr);
97662306a36Sopenharmony_ci	}
97762306a36Sopenharmony_ci	fsnotify_sb_error(sb, NULL, errno ? errno : EFSCORRUPTED);
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	ext4_handle_error(sb, false, -errno, 0, 0, function, line);
98062306a36Sopenharmony_ci}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_civoid __ext4_msg(struct super_block *sb,
98362306a36Sopenharmony_ci		const char *prefix, const char *fmt, ...)
98462306a36Sopenharmony_ci{
98562306a36Sopenharmony_ci	struct va_format vaf;
98662306a36Sopenharmony_ci	va_list args;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	if (sb) {
98962306a36Sopenharmony_ci		atomic_inc(&EXT4_SB(sb)->s_msg_count);
99062306a36Sopenharmony_ci		if (!___ratelimit(&(EXT4_SB(sb)->s_msg_ratelimit_state),
99162306a36Sopenharmony_ci				  "EXT4-fs"))
99262306a36Sopenharmony_ci			return;
99362306a36Sopenharmony_ci	}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	va_start(args, fmt);
99662306a36Sopenharmony_ci	vaf.fmt = fmt;
99762306a36Sopenharmony_ci	vaf.va = &args;
99862306a36Sopenharmony_ci	if (sb)
99962306a36Sopenharmony_ci		printk("%sEXT4-fs (%s): %pV\n", prefix, sb->s_id, &vaf);
100062306a36Sopenharmony_ci	else
100162306a36Sopenharmony_ci		printk("%sEXT4-fs: %pV\n", prefix, &vaf);
100262306a36Sopenharmony_ci	va_end(args);
100362306a36Sopenharmony_ci}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_cistatic int ext4_warning_ratelimit(struct super_block *sb)
100662306a36Sopenharmony_ci{
100762306a36Sopenharmony_ci	atomic_inc(&EXT4_SB(sb)->s_warning_count);
100862306a36Sopenharmony_ci	return ___ratelimit(&(EXT4_SB(sb)->s_warning_ratelimit_state),
100962306a36Sopenharmony_ci			    "EXT4-fs warning");
101062306a36Sopenharmony_ci}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_civoid __ext4_warning(struct super_block *sb, const char *function,
101362306a36Sopenharmony_ci		    unsigned int line, const char *fmt, ...)
101462306a36Sopenharmony_ci{
101562306a36Sopenharmony_ci	struct va_format vaf;
101662306a36Sopenharmony_ci	va_list args;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	if (!ext4_warning_ratelimit(sb))
101962306a36Sopenharmony_ci		return;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	va_start(args, fmt);
102262306a36Sopenharmony_ci	vaf.fmt = fmt;
102362306a36Sopenharmony_ci	vaf.va = &args;
102462306a36Sopenharmony_ci	printk(KERN_WARNING "EXT4-fs warning (device %s): %s:%d: %pV\n",
102562306a36Sopenharmony_ci	       sb->s_id, function, line, &vaf);
102662306a36Sopenharmony_ci	va_end(args);
102762306a36Sopenharmony_ci}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_civoid __ext4_warning_inode(const struct inode *inode, const char *function,
103062306a36Sopenharmony_ci			  unsigned int line, const char *fmt, ...)
103162306a36Sopenharmony_ci{
103262306a36Sopenharmony_ci	struct va_format vaf;
103362306a36Sopenharmony_ci	va_list args;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	if (!ext4_warning_ratelimit(inode->i_sb))
103662306a36Sopenharmony_ci		return;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	va_start(args, fmt);
103962306a36Sopenharmony_ci	vaf.fmt = fmt;
104062306a36Sopenharmony_ci	vaf.va = &args;
104162306a36Sopenharmony_ci	printk(KERN_WARNING "EXT4-fs warning (device %s): %s:%d: "
104262306a36Sopenharmony_ci	       "inode #%lu: comm %s: %pV\n", inode->i_sb->s_id,
104362306a36Sopenharmony_ci	       function, line, inode->i_ino, current->comm, &vaf);
104462306a36Sopenharmony_ci	va_end(args);
104562306a36Sopenharmony_ci}
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_civoid __ext4_grp_locked_error(const char *function, unsigned int line,
104862306a36Sopenharmony_ci			     struct super_block *sb, ext4_group_t grp,
104962306a36Sopenharmony_ci			     unsigned long ino, ext4_fsblk_t block,
105062306a36Sopenharmony_ci			     const char *fmt, ...)
105162306a36Sopenharmony_ci__releases(bitlock)
105262306a36Sopenharmony_ci__acquires(bitlock)
105362306a36Sopenharmony_ci{
105462306a36Sopenharmony_ci	struct va_format vaf;
105562306a36Sopenharmony_ci	va_list args;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	if (unlikely(ext4_forced_shutdown(sb)))
105862306a36Sopenharmony_ci		return;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	trace_ext4_error(sb, function, line);
106162306a36Sopenharmony_ci	if (ext4_error_ratelimit(sb)) {
106262306a36Sopenharmony_ci		va_start(args, fmt);
106362306a36Sopenharmony_ci		vaf.fmt = fmt;
106462306a36Sopenharmony_ci		vaf.va = &args;
106562306a36Sopenharmony_ci		printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: group %u, ",
106662306a36Sopenharmony_ci		       sb->s_id, function, line, grp);
106762306a36Sopenharmony_ci		if (ino)
106862306a36Sopenharmony_ci			printk(KERN_CONT "inode %lu: ", ino);
106962306a36Sopenharmony_ci		if (block)
107062306a36Sopenharmony_ci			printk(KERN_CONT "block %llu:",
107162306a36Sopenharmony_ci			       (unsigned long long) block);
107262306a36Sopenharmony_ci		printk(KERN_CONT "%pV\n", &vaf);
107362306a36Sopenharmony_ci		va_end(args);
107462306a36Sopenharmony_ci	}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	if (test_opt(sb, ERRORS_CONT)) {
107762306a36Sopenharmony_ci		if (test_opt(sb, WARN_ON_ERROR))
107862306a36Sopenharmony_ci			WARN_ON_ONCE(1);
107962306a36Sopenharmony_ci		EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
108062306a36Sopenharmony_ci		if (!bdev_read_only(sb->s_bdev)) {
108162306a36Sopenharmony_ci			save_error_info(sb, EFSCORRUPTED, ino, block, function,
108262306a36Sopenharmony_ci					line);
108362306a36Sopenharmony_ci			schedule_work(&EXT4_SB(sb)->s_sb_upd_work);
108462306a36Sopenharmony_ci		}
108562306a36Sopenharmony_ci		return;
108662306a36Sopenharmony_ci	}
108762306a36Sopenharmony_ci	ext4_unlock_group(sb, grp);
108862306a36Sopenharmony_ci	ext4_handle_error(sb, false, EFSCORRUPTED, ino, block, function, line);
108962306a36Sopenharmony_ci	/*
109062306a36Sopenharmony_ci	 * We only get here in the ERRORS_RO case; relocking the group
109162306a36Sopenharmony_ci	 * may be dangerous, but nothing bad will happen since the
109262306a36Sopenharmony_ci	 * filesystem will have already been marked read/only and the
109362306a36Sopenharmony_ci	 * journal has been aborted.  We return 1 as a hint to callers
109462306a36Sopenharmony_ci	 * who might what to use the return value from
109562306a36Sopenharmony_ci	 * ext4_grp_locked_error() to distinguish between the
109662306a36Sopenharmony_ci	 * ERRORS_CONT and ERRORS_RO case, and perhaps return more
109762306a36Sopenharmony_ci	 * aggressively from the ext4 function in question, with a
109862306a36Sopenharmony_ci	 * more appropriate error code.
109962306a36Sopenharmony_ci	 */
110062306a36Sopenharmony_ci	ext4_lock_group(sb, grp);
110162306a36Sopenharmony_ci	return;
110262306a36Sopenharmony_ci}
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_civoid ext4_mark_group_bitmap_corrupted(struct super_block *sb,
110562306a36Sopenharmony_ci				     ext4_group_t group,
110662306a36Sopenharmony_ci				     unsigned int flags)
110762306a36Sopenharmony_ci{
110862306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
110962306a36Sopenharmony_ci	struct ext4_group_info *grp = ext4_get_group_info(sb, group);
111062306a36Sopenharmony_ci	struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL);
111162306a36Sopenharmony_ci	int ret;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	if (!grp || !gdp)
111462306a36Sopenharmony_ci		return;
111562306a36Sopenharmony_ci	if (flags & EXT4_GROUP_INFO_BBITMAP_CORRUPT) {
111662306a36Sopenharmony_ci		ret = ext4_test_and_set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT,
111762306a36Sopenharmony_ci					    &grp->bb_state);
111862306a36Sopenharmony_ci		if (!ret)
111962306a36Sopenharmony_ci			percpu_counter_sub(&sbi->s_freeclusters_counter,
112062306a36Sopenharmony_ci					   grp->bb_free);
112162306a36Sopenharmony_ci	}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	if (flags & EXT4_GROUP_INFO_IBITMAP_CORRUPT) {
112462306a36Sopenharmony_ci		ret = ext4_test_and_set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT,
112562306a36Sopenharmony_ci					    &grp->bb_state);
112662306a36Sopenharmony_ci		if (!ret && gdp) {
112762306a36Sopenharmony_ci			int count;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci			count = ext4_free_inodes_count(sb, gdp);
113062306a36Sopenharmony_ci			percpu_counter_sub(&sbi->s_freeinodes_counter,
113162306a36Sopenharmony_ci					   count);
113262306a36Sopenharmony_ci		}
113362306a36Sopenharmony_ci	}
113462306a36Sopenharmony_ci}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_civoid ext4_update_dynamic_rev(struct super_block *sb)
113762306a36Sopenharmony_ci{
113862306a36Sopenharmony_ci	struct ext4_super_block *es = EXT4_SB(sb)->s_es;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	if (le32_to_cpu(es->s_rev_level) > EXT4_GOOD_OLD_REV)
114162306a36Sopenharmony_ci		return;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	ext4_warning(sb,
114462306a36Sopenharmony_ci		     "updating to rev %d because of new feature flag, "
114562306a36Sopenharmony_ci		     "running e2fsck is recommended",
114662306a36Sopenharmony_ci		     EXT4_DYNAMIC_REV);
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	es->s_first_ino = cpu_to_le32(EXT4_GOOD_OLD_FIRST_INO);
114962306a36Sopenharmony_ci	es->s_inode_size = cpu_to_le16(EXT4_GOOD_OLD_INODE_SIZE);
115062306a36Sopenharmony_ci	es->s_rev_level = cpu_to_le32(EXT4_DYNAMIC_REV);
115162306a36Sopenharmony_ci	/* leave es->s_feature_*compat flags alone */
115262306a36Sopenharmony_ci	/* es->s_uuid will be set by e2fsck if empty */
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	/*
115562306a36Sopenharmony_ci	 * The rest of the superblock fields should be zero, and if not it
115662306a36Sopenharmony_ci	 * means they are likely already in use, so leave them alone.  We
115762306a36Sopenharmony_ci	 * can leave it up to e2fsck to clean up any inconsistencies there.
115862306a36Sopenharmony_ci	 */
115962306a36Sopenharmony_ci}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_cistatic inline struct inode *orphan_list_entry(struct list_head *l)
116262306a36Sopenharmony_ci{
116362306a36Sopenharmony_ci	return &list_entry(l, struct ext4_inode_info, i_orphan)->vfs_inode;
116462306a36Sopenharmony_ci}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_cistatic void dump_orphan_list(struct super_block *sb, struct ext4_sb_info *sbi)
116762306a36Sopenharmony_ci{
116862306a36Sopenharmony_ci	struct list_head *l;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	ext4_msg(sb, KERN_ERR, "sb orphan head is %d",
117162306a36Sopenharmony_ci		 le32_to_cpu(sbi->s_es->s_last_orphan));
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	printk(KERN_ERR "sb_info orphan list:\n");
117462306a36Sopenharmony_ci	list_for_each(l, &sbi->s_orphan) {
117562306a36Sopenharmony_ci		struct inode *inode = orphan_list_entry(l);
117662306a36Sopenharmony_ci		printk(KERN_ERR "  "
117762306a36Sopenharmony_ci		       "inode %s:%lu at %p: mode %o, nlink %d, next %d\n",
117862306a36Sopenharmony_ci		       inode->i_sb->s_id, inode->i_ino, inode,
117962306a36Sopenharmony_ci		       inode->i_mode, inode->i_nlink,
118062306a36Sopenharmony_ci		       NEXT_ORPHAN(inode));
118162306a36Sopenharmony_ci	}
118262306a36Sopenharmony_ci}
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
118562306a36Sopenharmony_cistatic int ext4_quota_off(struct super_block *sb, int type);
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_cistatic inline void ext4_quotas_off(struct super_block *sb, int type)
118862306a36Sopenharmony_ci{
118962306a36Sopenharmony_ci	BUG_ON(type > EXT4_MAXQUOTAS);
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	/* Use our quota_off function to clear inode flags etc. */
119262306a36Sopenharmony_ci	for (type--; type >= 0; type--)
119362306a36Sopenharmony_ci		ext4_quota_off(sb, type);
119462306a36Sopenharmony_ci}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci/*
119762306a36Sopenharmony_ci * This is a helper function which is used in the mount/remount
119862306a36Sopenharmony_ci * codepaths (which holds s_umount) to fetch the quota file name.
119962306a36Sopenharmony_ci */
120062306a36Sopenharmony_cistatic inline char *get_qf_name(struct super_block *sb,
120162306a36Sopenharmony_ci				struct ext4_sb_info *sbi,
120262306a36Sopenharmony_ci				int type)
120362306a36Sopenharmony_ci{
120462306a36Sopenharmony_ci	return rcu_dereference_protected(sbi->s_qf_names[type],
120562306a36Sopenharmony_ci					 lockdep_is_held(&sb->s_umount));
120662306a36Sopenharmony_ci}
120762306a36Sopenharmony_ci#else
120862306a36Sopenharmony_cistatic inline void ext4_quotas_off(struct super_block *sb, int type)
120962306a36Sopenharmony_ci{
121062306a36Sopenharmony_ci}
121162306a36Sopenharmony_ci#endif
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_cistatic int ext4_percpu_param_init(struct ext4_sb_info *sbi)
121462306a36Sopenharmony_ci{
121562306a36Sopenharmony_ci	ext4_fsblk_t block;
121662306a36Sopenharmony_ci	int err;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	block = ext4_count_free_clusters(sbi->s_sb);
121962306a36Sopenharmony_ci	ext4_free_blocks_count_set(sbi->s_es, EXT4_C2B(sbi, block));
122062306a36Sopenharmony_ci	err = percpu_counter_init(&sbi->s_freeclusters_counter, block,
122162306a36Sopenharmony_ci				  GFP_KERNEL);
122262306a36Sopenharmony_ci	if (!err) {
122362306a36Sopenharmony_ci		unsigned long freei = ext4_count_free_inodes(sbi->s_sb);
122462306a36Sopenharmony_ci		sbi->s_es->s_free_inodes_count = cpu_to_le32(freei);
122562306a36Sopenharmony_ci		err = percpu_counter_init(&sbi->s_freeinodes_counter, freei,
122662306a36Sopenharmony_ci					  GFP_KERNEL);
122762306a36Sopenharmony_ci	}
122862306a36Sopenharmony_ci	if (!err)
122962306a36Sopenharmony_ci		err = percpu_counter_init(&sbi->s_dirs_counter,
123062306a36Sopenharmony_ci					  ext4_count_dirs(sbi->s_sb), GFP_KERNEL);
123162306a36Sopenharmony_ci	if (!err)
123262306a36Sopenharmony_ci		err = percpu_counter_init(&sbi->s_dirtyclusters_counter, 0,
123362306a36Sopenharmony_ci					  GFP_KERNEL);
123462306a36Sopenharmony_ci	if (!err)
123562306a36Sopenharmony_ci		err = percpu_counter_init(&sbi->s_sra_exceeded_retry_limit, 0,
123662306a36Sopenharmony_ci					  GFP_KERNEL);
123762306a36Sopenharmony_ci	if (!err)
123862306a36Sopenharmony_ci		err = percpu_init_rwsem(&sbi->s_writepages_rwsem);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	if (err)
124162306a36Sopenharmony_ci		ext4_msg(sbi->s_sb, KERN_ERR, "insufficient memory");
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	return err;
124462306a36Sopenharmony_ci}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_cistatic void ext4_percpu_param_destroy(struct ext4_sb_info *sbi)
124762306a36Sopenharmony_ci{
124862306a36Sopenharmony_ci	percpu_counter_destroy(&sbi->s_freeclusters_counter);
124962306a36Sopenharmony_ci	percpu_counter_destroy(&sbi->s_freeinodes_counter);
125062306a36Sopenharmony_ci	percpu_counter_destroy(&sbi->s_dirs_counter);
125162306a36Sopenharmony_ci	percpu_counter_destroy(&sbi->s_dirtyclusters_counter);
125262306a36Sopenharmony_ci	percpu_counter_destroy(&sbi->s_sra_exceeded_retry_limit);
125362306a36Sopenharmony_ci	percpu_free_rwsem(&sbi->s_writepages_rwsem);
125462306a36Sopenharmony_ci}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_cistatic void ext4_group_desc_free(struct ext4_sb_info *sbi)
125762306a36Sopenharmony_ci{
125862306a36Sopenharmony_ci	struct buffer_head **group_desc;
125962306a36Sopenharmony_ci	int i;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	rcu_read_lock();
126262306a36Sopenharmony_ci	group_desc = rcu_dereference(sbi->s_group_desc);
126362306a36Sopenharmony_ci	for (i = 0; i < sbi->s_gdb_count; i++)
126462306a36Sopenharmony_ci		brelse(group_desc[i]);
126562306a36Sopenharmony_ci	kvfree(group_desc);
126662306a36Sopenharmony_ci	rcu_read_unlock();
126762306a36Sopenharmony_ci}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_cistatic void ext4_flex_groups_free(struct ext4_sb_info *sbi)
127062306a36Sopenharmony_ci{
127162306a36Sopenharmony_ci	struct flex_groups **flex_groups;
127262306a36Sopenharmony_ci	int i;
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	rcu_read_lock();
127562306a36Sopenharmony_ci	flex_groups = rcu_dereference(sbi->s_flex_groups);
127662306a36Sopenharmony_ci	if (flex_groups) {
127762306a36Sopenharmony_ci		for (i = 0; i < sbi->s_flex_groups_allocated; i++)
127862306a36Sopenharmony_ci			kvfree(flex_groups[i]);
127962306a36Sopenharmony_ci		kvfree(flex_groups);
128062306a36Sopenharmony_ci	}
128162306a36Sopenharmony_ci	rcu_read_unlock();
128262306a36Sopenharmony_ci}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_cistatic void ext4_put_super(struct super_block *sb)
128562306a36Sopenharmony_ci{
128662306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
128762306a36Sopenharmony_ci	struct ext4_super_block *es = sbi->s_es;
128862306a36Sopenharmony_ci	int aborted = 0;
128962306a36Sopenharmony_ci	int err;
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	/*
129262306a36Sopenharmony_ci	 * Unregister sysfs before destroying jbd2 journal.
129362306a36Sopenharmony_ci	 * Since we could still access attr_journal_task attribute via sysfs
129462306a36Sopenharmony_ci	 * path which could have sbi->s_journal->j_task as NULL
129562306a36Sopenharmony_ci	 * Unregister sysfs before flush sbi->s_sb_upd_work.
129662306a36Sopenharmony_ci	 * Since user may read /proc/fs/ext4/xx/mb_groups during umount, If
129762306a36Sopenharmony_ci	 * read metadata verify failed then will queue error work.
129862306a36Sopenharmony_ci	 * update_super_work will call start_this_handle may trigger
129962306a36Sopenharmony_ci	 * BUG_ON.
130062306a36Sopenharmony_ci	 */
130162306a36Sopenharmony_ci	ext4_unregister_sysfs(sb);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	if (___ratelimit(&ext4_mount_msg_ratelimit, "EXT4-fs unmount"))
130462306a36Sopenharmony_ci		ext4_msg(sb, KERN_INFO, "unmounting filesystem %pU.",
130562306a36Sopenharmony_ci			 &sb->s_uuid);
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	ext4_unregister_li_request(sb);
130862306a36Sopenharmony_ci	ext4_quotas_off(sb, EXT4_MAXQUOTAS);
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	flush_work(&sbi->s_sb_upd_work);
131162306a36Sopenharmony_ci	destroy_workqueue(sbi->rsv_conversion_wq);
131262306a36Sopenharmony_ci	ext4_release_orphan_info(sb);
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	if (sbi->s_journal) {
131562306a36Sopenharmony_ci		aborted = is_journal_aborted(sbi->s_journal);
131662306a36Sopenharmony_ci		err = jbd2_journal_destroy(sbi->s_journal);
131762306a36Sopenharmony_ci		sbi->s_journal = NULL;
131862306a36Sopenharmony_ci		if ((err < 0) && !aborted) {
131962306a36Sopenharmony_ci			ext4_abort(sb, -err, "Couldn't clean up the journal");
132062306a36Sopenharmony_ci		}
132162306a36Sopenharmony_ci	}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	ext4_es_unregister_shrinker(sbi);
132462306a36Sopenharmony_ci	timer_shutdown_sync(&sbi->s_err_report);
132562306a36Sopenharmony_ci	ext4_release_system_zone(sb);
132662306a36Sopenharmony_ci	ext4_mb_release(sb);
132762306a36Sopenharmony_ci	ext4_ext_release(sb);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	if (!sb_rdonly(sb) && !aborted) {
133062306a36Sopenharmony_ci		ext4_clear_feature_journal_needs_recovery(sb);
133162306a36Sopenharmony_ci		ext4_clear_feature_orphan_present(sb);
133262306a36Sopenharmony_ci		es->s_state = cpu_to_le16(sbi->s_mount_state);
133362306a36Sopenharmony_ci	}
133462306a36Sopenharmony_ci	if (!sb_rdonly(sb))
133562306a36Sopenharmony_ci		ext4_commit_super(sb);
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	ext4_group_desc_free(sbi);
133862306a36Sopenharmony_ci	ext4_flex_groups_free(sbi);
133962306a36Sopenharmony_ci	ext4_percpu_param_destroy(sbi);
134062306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
134162306a36Sopenharmony_ci	for (int i = 0; i < EXT4_MAXQUOTAS; i++)
134262306a36Sopenharmony_ci		kfree(get_qf_name(sb, sbi, i));
134362306a36Sopenharmony_ci#endif
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	/* Debugging code just in case the in-memory inode orphan list
134662306a36Sopenharmony_ci	 * isn't empty.  The on-disk one can be non-empty if we've
134762306a36Sopenharmony_ci	 * detected an error and taken the fs readonly, but the
134862306a36Sopenharmony_ci	 * in-memory list had better be clean by this point. */
134962306a36Sopenharmony_ci	if (!list_empty(&sbi->s_orphan))
135062306a36Sopenharmony_ci		dump_orphan_list(sb, sbi);
135162306a36Sopenharmony_ci	ASSERT(list_empty(&sbi->s_orphan));
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	sync_blockdev(sb->s_bdev);
135462306a36Sopenharmony_ci	invalidate_bdev(sb->s_bdev);
135562306a36Sopenharmony_ci	if (sbi->s_journal_bdev) {
135662306a36Sopenharmony_ci		/*
135762306a36Sopenharmony_ci		 * Invalidate the journal device's buffers.  We don't want them
135862306a36Sopenharmony_ci		 * floating about in memory - the physical journal device may
135962306a36Sopenharmony_ci		 * hotswapped, and it breaks the `ro-after' testing code.
136062306a36Sopenharmony_ci		 */
136162306a36Sopenharmony_ci		sync_blockdev(sbi->s_journal_bdev);
136262306a36Sopenharmony_ci		invalidate_bdev(sbi->s_journal_bdev);
136362306a36Sopenharmony_ci	}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	ext4_xattr_destroy_cache(sbi->s_ea_inode_cache);
136662306a36Sopenharmony_ci	sbi->s_ea_inode_cache = NULL;
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	ext4_xattr_destroy_cache(sbi->s_ea_block_cache);
136962306a36Sopenharmony_ci	sbi->s_ea_block_cache = NULL;
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	ext4_stop_mmpd(sbi);
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	brelse(sbi->s_sbh);
137462306a36Sopenharmony_ci	sb->s_fs_info = NULL;
137562306a36Sopenharmony_ci	/*
137662306a36Sopenharmony_ci	 * Now that we are completely done shutting down the
137762306a36Sopenharmony_ci	 * superblock, we need to actually destroy the kobject.
137862306a36Sopenharmony_ci	 */
137962306a36Sopenharmony_ci	kobject_put(&sbi->s_kobj);
138062306a36Sopenharmony_ci	wait_for_completion(&sbi->s_kobj_unregister);
138162306a36Sopenharmony_ci	if (sbi->s_chksum_driver)
138262306a36Sopenharmony_ci		crypto_free_shash(sbi->s_chksum_driver);
138362306a36Sopenharmony_ci	kfree(sbi->s_blockgroup_lock);
138462306a36Sopenharmony_ci	fs_put_dax(sbi->s_daxdev, NULL);
138562306a36Sopenharmony_ci	fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy);
138662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE)
138762306a36Sopenharmony_ci	utf8_unload(sb->s_encoding);
138862306a36Sopenharmony_ci#endif
138962306a36Sopenharmony_ci	kfree(sbi);
139062306a36Sopenharmony_ci}
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_cistatic struct kmem_cache *ext4_inode_cachep;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci/*
139562306a36Sopenharmony_ci * Called inside transaction, so use GFP_NOFS
139662306a36Sopenharmony_ci */
139762306a36Sopenharmony_cistatic struct inode *ext4_alloc_inode(struct super_block *sb)
139862306a36Sopenharmony_ci{
139962306a36Sopenharmony_ci	struct ext4_inode_info *ei;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	ei = alloc_inode_sb(sb, ext4_inode_cachep, GFP_NOFS);
140262306a36Sopenharmony_ci	if (!ei)
140362306a36Sopenharmony_ci		return NULL;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	inode_set_iversion(&ei->vfs_inode, 1);
140662306a36Sopenharmony_ci	ei->i_flags = 0;
140762306a36Sopenharmony_ci	spin_lock_init(&ei->i_raw_lock);
140862306a36Sopenharmony_ci	ei->i_prealloc_node = RB_ROOT;
140962306a36Sopenharmony_ci	atomic_set(&ei->i_prealloc_active, 0);
141062306a36Sopenharmony_ci	rwlock_init(&ei->i_prealloc_lock);
141162306a36Sopenharmony_ci	ext4_es_init_tree(&ei->i_es_tree);
141262306a36Sopenharmony_ci	rwlock_init(&ei->i_es_lock);
141362306a36Sopenharmony_ci	INIT_LIST_HEAD(&ei->i_es_list);
141462306a36Sopenharmony_ci	ei->i_es_all_nr = 0;
141562306a36Sopenharmony_ci	ei->i_es_shk_nr = 0;
141662306a36Sopenharmony_ci	ei->i_es_shrink_lblk = 0;
141762306a36Sopenharmony_ci	ei->i_reserved_data_blocks = 0;
141862306a36Sopenharmony_ci	spin_lock_init(&(ei->i_block_reservation_lock));
141962306a36Sopenharmony_ci	ext4_init_pending_tree(&ei->i_pending_tree);
142062306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
142162306a36Sopenharmony_ci	ei->i_reserved_quota = 0;
142262306a36Sopenharmony_ci	memset(&ei->i_dquot, 0, sizeof(ei->i_dquot));
142362306a36Sopenharmony_ci#endif
142462306a36Sopenharmony_ci	ei->jinode = NULL;
142562306a36Sopenharmony_ci	INIT_LIST_HEAD(&ei->i_rsv_conversion_list);
142662306a36Sopenharmony_ci	spin_lock_init(&ei->i_completed_io_lock);
142762306a36Sopenharmony_ci	ei->i_sync_tid = 0;
142862306a36Sopenharmony_ci	ei->i_datasync_tid = 0;
142962306a36Sopenharmony_ci	atomic_set(&ei->i_unwritten, 0);
143062306a36Sopenharmony_ci	INIT_WORK(&ei->i_rsv_conversion_work, ext4_end_io_rsv_work);
143162306a36Sopenharmony_ci	ext4_fc_init_inode(&ei->vfs_inode);
143262306a36Sopenharmony_ci	mutex_init(&ei->i_fc_lock);
143362306a36Sopenharmony_ci	return &ei->vfs_inode;
143462306a36Sopenharmony_ci}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_cistatic int ext4_drop_inode(struct inode *inode)
143762306a36Sopenharmony_ci{
143862306a36Sopenharmony_ci	int drop = generic_drop_inode(inode);
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	if (!drop)
144162306a36Sopenharmony_ci		drop = fscrypt_drop_inode(inode);
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	trace_ext4_drop_inode(inode, drop);
144462306a36Sopenharmony_ci	return drop;
144562306a36Sopenharmony_ci}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_cistatic void ext4_free_in_core_inode(struct inode *inode)
144862306a36Sopenharmony_ci{
144962306a36Sopenharmony_ci	fscrypt_free_inode(inode);
145062306a36Sopenharmony_ci	if (!list_empty(&(EXT4_I(inode)->i_fc_list))) {
145162306a36Sopenharmony_ci		pr_warn("%s: inode %ld still in fc list",
145262306a36Sopenharmony_ci			__func__, inode->i_ino);
145362306a36Sopenharmony_ci	}
145462306a36Sopenharmony_ci	kmem_cache_free(ext4_inode_cachep, EXT4_I(inode));
145562306a36Sopenharmony_ci}
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_cistatic void ext4_destroy_inode(struct inode *inode)
145862306a36Sopenharmony_ci{
145962306a36Sopenharmony_ci	if (!list_empty(&(EXT4_I(inode)->i_orphan))) {
146062306a36Sopenharmony_ci		ext4_msg(inode->i_sb, KERN_ERR,
146162306a36Sopenharmony_ci			 "Inode %lu (%p): orphan list check failed!",
146262306a36Sopenharmony_ci			 inode->i_ino, EXT4_I(inode));
146362306a36Sopenharmony_ci		print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 4,
146462306a36Sopenharmony_ci				EXT4_I(inode), sizeof(struct ext4_inode_info),
146562306a36Sopenharmony_ci				true);
146662306a36Sopenharmony_ci		dump_stack();
146762306a36Sopenharmony_ci	}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	if (EXT4_I(inode)->i_reserved_data_blocks)
147062306a36Sopenharmony_ci		ext4_msg(inode->i_sb, KERN_ERR,
147162306a36Sopenharmony_ci			 "Inode %lu (%p): i_reserved_data_blocks (%u) not cleared!",
147262306a36Sopenharmony_ci			 inode->i_ino, EXT4_I(inode),
147362306a36Sopenharmony_ci			 EXT4_I(inode)->i_reserved_data_blocks);
147462306a36Sopenharmony_ci}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_cistatic void ext4_shutdown(struct super_block *sb)
147762306a36Sopenharmony_ci{
147862306a36Sopenharmony_ci       ext4_force_shutdown(sb, EXT4_GOING_FLAGS_NOLOGFLUSH);
147962306a36Sopenharmony_ci}
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_cistatic void init_once(void *foo)
148262306a36Sopenharmony_ci{
148362306a36Sopenharmony_ci	struct ext4_inode_info *ei = foo;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	INIT_LIST_HEAD(&ei->i_orphan);
148662306a36Sopenharmony_ci	init_rwsem(&ei->xattr_sem);
148762306a36Sopenharmony_ci	init_rwsem(&ei->i_data_sem);
148862306a36Sopenharmony_ci	inode_init_once(&ei->vfs_inode);
148962306a36Sopenharmony_ci	ext4_fc_init_inode(&ei->vfs_inode);
149062306a36Sopenharmony_ci}
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_cistatic int __init init_inodecache(void)
149362306a36Sopenharmony_ci{
149462306a36Sopenharmony_ci	ext4_inode_cachep = kmem_cache_create_usercopy("ext4_inode_cache",
149562306a36Sopenharmony_ci				sizeof(struct ext4_inode_info), 0,
149662306a36Sopenharmony_ci				(SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|
149762306a36Sopenharmony_ci					SLAB_ACCOUNT),
149862306a36Sopenharmony_ci				offsetof(struct ext4_inode_info, i_data),
149962306a36Sopenharmony_ci				sizeof_field(struct ext4_inode_info, i_data),
150062306a36Sopenharmony_ci				init_once);
150162306a36Sopenharmony_ci	if (ext4_inode_cachep == NULL)
150262306a36Sopenharmony_ci		return -ENOMEM;
150362306a36Sopenharmony_ci	return 0;
150462306a36Sopenharmony_ci}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_cistatic void destroy_inodecache(void)
150762306a36Sopenharmony_ci{
150862306a36Sopenharmony_ci	/*
150962306a36Sopenharmony_ci	 * Make sure all delayed rcu free inodes are flushed before we
151062306a36Sopenharmony_ci	 * destroy cache.
151162306a36Sopenharmony_ci	 */
151262306a36Sopenharmony_ci	rcu_barrier();
151362306a36Sopenharmony_ci	kmem_cache_destroy(ext4_inode_cachep);
151462306a36Sopenharmony_ci}
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_civoid ext4_clear_inode(struct inode *inode)
151762306a36Sopenharmony_ci{
151862306a36Sopenharmony_ci	ext4_fc_del(inode);
151962306a36Sopenharmony_ci	invalidate_inode_buffers(inode);
152062306a36Sopenharmony_ci	clear_inode(inode);
152162306a36Sopenharmony_ci	ext4_discard_preallocations(inode, 0);
152262306a36Sopenharmony_ci	ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);
152362306a36Sopenharmony_ci	dquot_drop(inode);
152462306a36Sopenharmony_ci	if (EXT4_I(inode)->jinode) {
152562306a36Sopenharmony_ci		jbd2_journal_release_jbd_inode(EXT4_JOURNAL(inode),
152662306a36Sopenharmony_ci					       EXT4_I(inode)->jinode);
152762306a36Sopenharmony_ci		jbd2_free_inode(EXT4_I(inode)->jinode);
152862306a36Sopenharmony_ci		EXT4_I(inode)->jinode = NULL;
152962306a36Sopenharmony_ci	}
153062306a36Sopenharmony_ci	fscrypt_put_encryption_info(inode);
153162306a36Sopenharmony_ci	fsverity_cleanup_inode(inode);
153262306a36Sopenharmony_ci}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_cistatic struct inode *ext4_nfs_get_inode(struct super_block *sb,
153562306a36Sopenharmony_ci					u64 ino, u32 generation)
153662306a36Sopenharmony_ci{
153762306a36Sopenharmony_ci	struct inode *inode;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	/*
154062306a36Sopenharmony_ci	 * Currently we don't know the generation for parent directory, so
154162306a36Sopenharmony_ci	 * a generation of 0 means "accept any"
154262306a36Sopenharmony_ci	 */
154362306a36Sopenharmony_ci	inode = ext4_iget(sb, ino, EXT4_IGET_HANDLE);
154462306a36Sopenharmony_ci	if (IS_ERR(inode))
154562306a36Sopenharmony_ci		return ERR_CAST(inode);
154662306a36Sopenharmony_ci	if (generation && inode->i_generation != generation) {
154762306a36Sopenharmony_ci		iput(inode);
154862306a36Sopenharmony_ci		return ERR_PTR(-ESTALE);
154962306a36Sopenharmony_ci	}
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	return inode;
155262306a36Sopenharmony_ci}
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_cistatic struct dentry *ext4_fh_to_dentry(struct super_block *sb, struct fid *fid,
155562306a36Sopenharmony_ci					int fh_len, int fh_type)
155662306a36Sopenharmony_ci{
155762306a36Sopenharmony_ci	return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
155862306a36Sopenharmony_ci				    ext4_nfs_get_inode);
155962306a36Sopenharmony_ci}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_cistatic struct dentry *ext4_fh_to_parent(struct super_block *sb, struct fid *fid,
156262306a36Sopenharmony_ci					int fh_len, int fh_type)
156362306a36Sopenharmony_ci{
156462306a36Sopenharmony_ci	return generic_fh_to_parent(sb, fid, fh_len, fh_type,
156562306a36Sopenharmony_ci				    ext4_nfs_get_inode);
156662306a36Sopenharmony_ci}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_cistatic int ext4_nfs_commit_metadata(struct inode *inode)
156962306a36Sopenharmony_ci{
157062306a36Sopenharmony_ci	struct writeback_control wbc = {
157162306a36Sopenharmony_ci		.sync_mode = WB_SYNC_ALL
157262306a36Sopenharmony_ci	};
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	trace_ext4_nfs_commit_metadata(inode);
157562306a36Sopenharmony_ci	return ext4_write_inode(inode, &wbc);
157662306a36Sopenharmony_ci}
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
157962306a36Sopenharmony_cistatic const char * const quotatypes[] = INITQFNAMES;
158062306a36Sopenharmony_ci#define QTYPE2NAME(t) (quotatypes[t])
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_cistatic int ext4_write_dquot(struct dquot *dquot);
158362306a36Sopenharmony_cistatic int ext4_acquire_dquot(struct dquot *dquot);
158462306a36Sopenharmony_cistatic int ext4_release_dquot(struct dquot *dquot);
158562306a36Sopenharmony_cistatic int ext4_mark_dquot_dirty(struct dquot *dquot);
158662306a36Sopenharmony_cistatic int ext4_write_info(struct super_block *sb, int type);
158762306a36Sopenharmony_cistatic int ext4_quota_on(struct super_block *sb, int type, int format_id,
158862306a36Sopenharmony_ci			 const struct path *path);
158962306a36Sopenharmony_cistatic ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
159062306a36Sopenharmony_ci			       size_t len, loff_t off);
159162306a36Sopenharmony_cistatic ssize_t ext4_quota_write(struct super_block *sb, int type,
159262306a36Sopenharmony_ci				const char *data, size_t len, loff_t off);
159362306a36Sopenharmony_cistatic int ext4_quota_enable(struct super_block *sb, int type, int format_id,
159462306a36Sopenharmony_ci			     unsigned int flags);
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_cistatic struct dquot __rcu **ext4_get_dquots(struct inode *inode)
159762306a36Sopenharmony_ci{
159862306a36Sopenharmony_ci	return EXT4_I(inode)->i_dquot;
159962306a36Sopenharmony_ci}
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_cistatic const struct dquot_operations ext4_quota_operations = {
160262306a36Sopenharmony_ci	.get_reserved_space	= ext4_get_reserved_space,
160362306a36Sopenharmony_ci	.write_dquot		= ext4_write_dquot,
160462306a36Sopenharmony_ci	.acquire_dquot		= ext4_acquire_dquot,
160562306a36Sopenharmony_ci	.release_dquot		= ext4_release_dquot,
160662306a36Sopenharmony_ci	.mark_dirty		= ext4_mark_dquot_dirty,
160762306a36Sopenharmony_ci	.write_info		= ext4_write_info,
160862306a36Sopenharmony_ci	.alloc_dquot		= dquot_alloc,
160962306a36Sopenharmony_ci	.destroy_dquot		= dquot_destroy,
161062306a36Sopenharmony_ci	.get_projid		= ext4_get_projid,
161162306a36Sopenharmony_ci	.get_inode_usage	= ext4_get_inode_usage,
161262306a36Sopenharmony_ci	.get_next_id		= dquot_get_next_id,
161362306a36Sopenharmony_ci};
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_cistatic const struct quotactl_ops ext4_qctl_operations = {
161662306a36Sopenharmony_ci	.quota_on	= ext4_quota_on,
161762306a36Sopenharmony_ci	.quota_off	= ext4_quota_off,
161862306a36Sopenharmony_ci	.quota_sync	= dquot_quota_sync,
161962306a36Sopenharmony_ci	.get_state	= dquot_get_state,
162062306a36Sopenharmony_ci	.set_info	= dquot_set_dqinfo,
162162306a36Sopenharmony_ci	.get_dqblk	= dquot_get_dqblk,
162262306a36Sopenharmony_ci	.set_dqblk	= dquot_set_dqblk,
162362306a36Sopenharmony_ci	.get_nextdqblk	= dquot_get_next_dqblk,
162462306a36Sopenharmony_ci};
162562306a36Sopenharmony_ci#endif
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_cistatic const struct super_operations ext4_sops = {
162862306a36Sopenharmony_ci	.alloc_inode	= ext4_alloc_inode,
162962306a36Sopenharmony_ci	.free_inode	= ext4_free_in_core_inode,
163062306a36Sopenharmony_ci	.destroy_inode	= ext4_destroy_inode,
163162306a36Sopenharmony_ci	.write_inode	= ext4_write_inode,
163262306a36Sopenharmony_ci	.dirty_inode	= ext4_dirty_inode,
163362306a36Sopenharmony_ci	.drop_inode	= ext4_drop_inode,
163462306a36Sopenharmony_ci	.evict_inode	= ext4_evict_inode,
163562306a36Sopenharmony_ci	.put_super	= ext4_put_super,
163662306a36Sopenharmony_ci	.sync_fs	= ext4_sync_fs,
163762306a36Sopenharmony_ci	.freeze_fs	= ext4_freeze,
163862306a36Sopenharmony_ci	.unfreeze_fs	= ext4_unfreeze,
163962306a36Sopenharmony_ci	.statfs		= ext4_statfs,
164062306a36Sopenharmony_ci	.show_options	= ext4_show_options,
164162306a36Sopenharmony_ci	.shutdown	= ext4_shutdown,
164262306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
164362306a36Sopenharmony_ci	.quota_read	= ext4_quota_read,
164462306a36Sopenharmony_ci	.quota_write	= ext4_quota_write,
164562306a36Sopenharmony_ci	.get_dquots	= ext4_get_dquots,
164662306a36Sopenharmony_ci#endif
164762306a36Sopenharmony_ci};
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_cistatic const struct export_operations ext4_export_ops = {
165062306a36Sopenharmony_ci	.fh_to_dentry = ext4_fh_to_dentry,
165162306a36Sopenharmony_ci	.fh_to_parent = ext4_fh_to_parent,
165262306a36Sopenharmony_ci	.get_parent = ext4_get_parent,
165362306a36Sopenharmony_ci	.commit_metadata = ext4_nfs_commit_metadata,
165462306a36Sopenharmony_ci};
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_cienum {
165762306a36Sopenharmony_ci	Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
165862306a36Sopenharmony_ci	Opt_resgid, Opt_resuid, Opt_sb,
165962306a36Sopenharmony_ci	Opt_nouid32, Opt_debug, Opt_removed,
166062306a36Sopenharmony_ci	Opt_user_xattr, Opt_acl,
166162306a36Sopenharmony_ci	Opt_auto_da_alloc, Opt_noauto_da_alloc, Opt_noload,
166262306a36Sopenharmony_ci	Opt_commit, Opt_min_batch_time, Opt_max_batch_time, Opt_journal_dev,
166362306a36Sopenharmony_ci	Opt_journal_path, Opt_journal_checksum, Opt_journal_async_commit,
166462306a36Sopenharmony_ci	Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
166562306a36Sopenharmony_ci	Opt_data_err_abort, Opt_data_err_ignore, Opt_test_dummy_encryption,
166662306a36Sopenharmony_ci	Opt_inlinecrypt,
166762306a36Sopenharmony_ci	Opt_usrjquota, Opt_grpjquota, Opt_quota,
166862306a36Sopenharmony_ci	Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
166962306a36Sopenharmony_ci	Opt_usrquota, Opt_grpquota, Opt_prjquota,
167062306a36Sopenharmony_ci	Opt_dax, Opt_dax_always, Opt_dax_inode, Opt_dax_never,
167162306a36Sopenharmony_ci	Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_warn_on_error,
167262306a36Sopenharmony_ci	Opt_nowarn_on_error, Opt_mblk_io_submit, Opt_debug_want_extra_isize,
167362306a36Sopenharmony_ci	Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,
167462306a36Sopenharmony_ci	Opt_inode_readahead_blks, Opt_journal_ioprio,
167562306a36Sopenharmony_ci	Opt_dioread_nolock, Opt_dioread_lock,
167662306a36Sopenharmony_ci	Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
167762306a36Sopenharmony_ci	Opt_max_dir_size_kb, Opt_nojournal_checksum, Opt_nombcache,
167862306a36Sopenharmony_ci	Opt_no_prefetch_block_bitmaps, Opt_mb_optimize_scan,
167962306a36Sopenharmony_ci	Opt_errors, Opt_data, Opt_data_err, Opt_jqfmt, Opt_dax_type,
168062306a36Sopenharmony_ci#ifdef CONFIG_EXT4_DEBUG
168162306a36Sopenharmony_ci	Opt_fc_debug_max_replay, Opt_fc_debug_force
168262306a36Sopenharmony_ci#endif
168362306a36Sopenharmony_ci};
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_cistatic const struct constant_table ext4_param_errors[] = {
168662306a36Sopenharmony_ci	{"continue",	EXT4_MOUNT_ERRORS_CONT},
168762306a36Sopenharmony_ci	{"panic",	EXT4_MOUNT_ERRORS_PANIC},
168862306a36Sopenharmony_ci	{"remount-ro",	EXT4_MOUNT_ERRORS_RO},
168962306a36Sopenharmony_ci	{}
169062306a36Sopenharmony_ci};
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_cistatic const struct constant_table ext4_param_data[] = {
169362306a36Sopenharmony_ci	{"journal",	EXT4_MOUNT_JOURNAL_DATA},
169462306a36Sopenharmony_ci	{"ordered",	EXT4_MOUNT_ORDERED_DATA},
169562306a36Sopenharmony_ci	{"writeback",	EXT4_MOUNT_WRITEBACK_DATA},
169662306a36Sopenharmony_ci	{}
169762306a36Sopenharmony_ci};
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_cistatic const struct constant_table ext4_param_data_err[] = {
170062306a36Sopenharmony_ci	{"abort",	Opt_data_err_abort},
170162306a36Sopenharmony_ci	{"ignore",	Opt_data_err_ignore},
170262306a36Sopenharmony_ci	{}
170362306a36Sopenharmony_ci};
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_cistatic const struct constant_table ext4_param_jqfmt[] = {
170662306a36Sopenharmony_ci	{"vfsold",	QFMT_VFS_OLD},
170762306a36Sopenharmony_ci	{"vfsv0",	QFMT_VFS_V0},
170862306a36Sopenharmony_ci	{"vfsv1",	QFMT_VFS_V1},
170962306a36Sopenharmony_ci	{}
171062306a36Sopenharmony_ci};
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_cistatic const struct constant_table ext4_param_dax[] = {
171362306a36Sopenharmony_ci	{"always",	Opt_dax_always},
171462306a36Sopenharmony_ci	{"inode",	Opt_dax_inode},
171562306a36Sopenharmony_ci	{"never",	Opt_dax_never},
171662306a36Sopenharmony_ci	{}
171762306a36Sopenharmony_ci};
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci/* String parameter that allows empty argument */
172062306a36Sopenharmony_ci#define fsparam_string_empty(NAME, OPT) \
172162306a36Sopenharmony_ci	__fsparam(fs_param_is_string, NAME, OPT, fs_param_can_be_empty, NULL)
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci/*
172462306a36Sopenharmony_ci * Mount option specification
172562306a36Sopenharmony_ci * We don't use fsparam_flag_no because of the way we set the
172662306a36Sopenharmony_ci * options and the way we show them in _ext4_show_options(). To
172762306a36Sopenharmony_ci * keep the changes to a minimum, let's keep the negative options
172862306a36Sopenharmony_ci * separate for now.
172962306a36Sopenharmony_ci */
173062306a36Sopenharmony_cistatic const struct fs_parameter_spec ext4_param_specs[] = {
173162306a36Sopenharmony_ci	fsparam_flag	("bsddf",		Opt_bsd_df),
173262306a36Sopenharmony_ci	fsparam_flag	("minixdf",		Opt_minix_df),
173362306a36Sopenharmony_ci	fsparam_flag	("grpid",		Opt_grpid),
173462306a36Sopenharmony_ci	fsparam_flag	("bsdgroups",		Opt_grpid),
173562306a36Sopenharmony_ci	fsparam_flag	("nogrpid",		Opt_nogrpid),
173662306a36Sopenharmony_ci	fsparam_flag	("sysvgroups",		Opt_nogrpid),
173762306a36Sopenharmony_ci	fsparam_u32	("resgid",		Opt_resgid),
173862306a36Sopenharmony_ci	fsparam_u32	("resuid",		Opt_resuid),
173962306a36Sopenharmony_ci	fsparam_u32	("sb",			Opt_sb),
174062306a36Sopenharmony_ci	fsparam_enum	("errors",		Opt_errors, ext4_param_errors),
174162306a36Sopenharmony_ci	fsparam_flag	("nouid32",		Opt_nouid32),
174262306a36Sopenharmony_ci	fsparam_flag	("debug",		Opt_debug),
174362306a36Sopenharmony_ci	fsparam_flag	("oldalloc",		Opt_removed),
174462306a36Sopenharmony_ci	fsparam_flag	("orlov",		Opt_removed),
174562306a36Sopenharmony_ci	fsparam_flag	("user_xattr",		Opt_user_xattr),
174662306a36Sopenharmony_ci	fsparam_flag	("acl",			Opt_acl),
174762306a36Sopenharmony_ci	fsparam_flag	("norecovery",		Opt_noload),
174862306a36Sopenharmony_ci	fsparam_flag	("noload",		Opt_noload),
174962306a36Sopenharmony_ci	fsparam_flag	("bh",			Opt_removed),
175062306a36Sopenharmony_ci	fsparam_flag	("nobh",		Opt_removed),
175162306a36Sopenharmony_ci	fsparam_u32	("commit",		Opt_commit),
175262306a36Sopenharmony_ci	fsparam_u32	("min_batch_time",	Opt_min_batch_time),
175362306a36Sopenharmony_ci	fsparam_u32	("max_batch_time",	Opt_max_batch_time),
175462306a36Sopenharmony_ci	fsparam_u32	("journal_dev",		Opt_journal_dev),
175562306a36Sopenharmony_ci	fsparam_bdev	("journal_path",	Opt_journal_path),
175662306a36Sopenharmony_ci	fsparam_flag	("journal_checksum",	Opt_journal_checksum),
175762306a36Sopenharmony_ci	fsparam_flag	("nojournal_checksum",	Opt_nojournal_checksum),
175862306a36Sopenharmony_ci	fsparam_flag	("journal_async_commit",Opt_journal_async_commit),
175962306a36Sopenharmony_ci	fsparam_flag	("abort",		Opt_abort),
176062306a36Sopenharmony_ci	fsparam_enum	("data",		Opt_data, ext4_param_data),
176162306a36Sopenharmony_ci	fsparam_enum	("data_err",		Opt_data_err,
176262306a36Sopenharmony_ci						ext4_param_data_err),
176362306a36Sopenharmony_ci	fsparam_string_empty
176462306a36Sopenharmony_ci			("usrjquota",		Opt_usrjquota),
176562306a36Sopenharmony_ci	fsparam_string_empty
176662306a36Sopenharmony_ci			("grpjquota",		Opt_grpjquota),
176762306a36Sopenharmony_ci	fsparam_enum	("jqfmt",		Opt_jqfmt, ext4_param_jqfmt),
176862306a36Sopenharmony_ci	fsparam_flag	("grpquota",		Opt_grpquota),
176962306a36Sopenharmony_ci	fsparam_flag	("quota",		Opt_quota),
177062306a36Sopenharmony_ci	fsparam_flag	("noquota",		Opt_noquota),
177162306a36Sopenharmony_ci	fsparam_flag	("usrquota",		Opt_usrquota),
177262306a36Sopenharmony_ci	fsparam_flag	("prjquota",		Opt_prjquota),
177362306a36Sopenharmony_ci	fsparam_flag	("barrier",		Opt_barrier),
177462306a36Sopenharmony_ci	fsparam_u32	("barrier",		Opt_barrier),
177562306a36Sopenharmony_ci	fsparam_flag	("nobarrier",		Opt_nobarrier),
177662306a36Sopenharmony_ci	fsparam_flag	("i_version",		Opt_removed),
177762306a36Sopenharmony_ci	fsparam_flag	("dax",			Opt_dax),
177862306a36Sopenharmony_ci	fsparam_enum	("dax",			Opt_dax_type, ext4_param_dax),
177962306a36Sopenharmony_ci	fsparam_u32	("stripe",		Opt_stripe),
178062306a36Sopenharmony_ci	fsparam_flag	("delalloc",		Opt_delalloc),
178162306a36Sopenharmony_ci	fsparam_flag	("nodelalloc",		Opt_nodelalloc),
178262306a36Sopenharmony_ci	fsparam_flag	("warn_on_error",	Opt_warn_on_error),
178362306a36Sopenharmony_ci	fsparam_flag	("nowarn_on_error",	Opt_nowarn_on_error),
178462306a36Sopenharmony_ci	fsparam_u32	("debug_want_extra_isize",
178562306a36Sopenharmony_ci						Opt_debug_want_extra_isize),
178662306a36Sopenharmony_ci	fsparam_flag	("mblk_io_submit",	Opt_removed),
178762306a36Sopenharmony_ci	fsparam_flag	("nomblk_io_submit",	Opt_removed),
178862306a36Sopenharmony_ci	fsparam_flag	("block_validity",	Opt_block_validity),
178962306a36Sopenharmony_ci	fsparam_flag	("noblock_validity",	Opt_noblock_validity),
179062306a36Sopenharmony_ci	fsparam_u32	("inode_readahead_blks",
179162306a36Sopenharmony_ci						Opt_inode_readahead_blks),
179262306a36Sopenharmony_ci	fsparam_u32	("journal_ioprio",	Opt_journal_ioprio),
179362306a36Sopenharmony_ci	fsparam_u32	("auto_da_alloc",	Opt_auto_da_alloc),
179462306a36Sopenharmony_ci	fsparam_flag	("auto_da_alloc",	Opt_auto_da_alloc),
179562306a36Sopenharmony_ci	fsparam_flag	("noauto_da_alloc",	Opt_noauto_da_alloc),
179662306a36Sopenharmony_ci	fsparam_flag	("dioread_nolock",	Opt_dioread_nolock),
179762306a36Sopenharmony_ci	fsparam_flag	("nodioread_nolock",	Opt_dioread_lock),
179862306a36Sopenharmony_ci	fsparam_flag	("dioread_lock",	Opt_dioread_lock),
179962306a36Sopenharmony_ci	fsparam_flag	("discard",		Opt_discard),
180062306a36Sopenharmony_ci	fsparam_flag	("nodiscard",		Opt_nodiscard),
180162306a36Sopenharmony_ci	fsparam_u32	("init_itable",		Opt_init_itable),
180262306a36Sopenharmony_ci	fsparam_flag	("init_itable",		Opt_init_itable),
180362306a36Sopenharmony_ci	fsparam_flag	("noinit_itable",	Opt_noinit_itable),
180462306a36Sopenharmony_ci#ifdef CONFIG_EXT4_DEBUG
180562306a36Sopenharmony_ci	fsparam_flag	("fc_debug_force",	Opt_fc_debug_force),
180662306a36Sopenharmony_ci	fsparam_u32	("fc_debug_max_replay",	Opt_fc_debug_max_replay),
180762306a36Sopenharmony_ci#endif
180862306a36Sopenharmony_ci	fsparam_u32	("max_dir_size_kb",	Opt_max_dir_size_kb),
180962306a36Sopenharmony_ci	fsparam_flag	("test_dummy_encryption",
181062306a36Sopenharmony_ci						Opt_test_dummy_encryption),
181162306a36Sopenharmony_ci	fsparam_string	("test_dummy_encryption",
181262306a36Sopenharmony_ci						Opt_test_dummy_encryption),
181362306a36Sopenharmony_ci	fsparam_flag	("inlinecrypt",		Opt_inlinecrypt),
181462306a36Sopenharmony_ci	fsparam_flag	("nombcache",		Opt_nombcache),
181562306a36Sopenharmony_ci	fsparam_flag	("no_mbcache",		Opt_nombcache),	/* for backward compatibility */
181662306a36Sopenharmony_ci	fsparam_flag	("prefetch_block_bitmaps",
181762306a36Sopenharmony_ci						Opt_removed),
181862306a36Sopenharmony_ci	fsparam_flag	("no_prefetch_block_bitmaps",
181962306a36Sopenharmony_ci						Opt_no_prefetch_block_bitmaps),
182062306a36Sopenharmony_ci	fsparam_s32	("mb_optimize_scan",	Opt_mb_optimize_scan),
182162306a36Sopenharmony_ci	fsparam_string	("check",		Opt_removed),	/* mount option from ext2/3 */
182262306a36Sopenharmony_ci	fsparam_flag	("nocheck",		Opt_removed),	/* mount option from ext2/3 */
182362306a36Sopenharmony_ci	fsparam_flag	("reservation",		Opt_removed),	/* mount option from ext2/3 */
182462306a36Sopenharmony_ci	fsparam_flag	("noreservation",	Opt_removed),	/* mount option from ext2/3 */
182562306a36Sopenharmony_ci	fsparam_u32	("journal",		Opt_removed),	/* mount option from ext2/3 */
182662306a36Sopenharmony_ci	{}
182762306a36Sopenharmony_ci};
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci#define DEFAULT_JOURNAL_IOPRIO (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 3))
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci#define MOPT_SET	0x0001
183262306a36Sopenharmony_ci#define MOPT_CLEAR	0x0002
183362306a36Sopenharmony_ci#define MOPT_NOSUPPORT	0x0004
183462306a36Sopenharmony_ci#define MOPT_EXPLICIT	0x0008
183562306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
183662306a36Sopenharmony_ci#define MOPT_Q		0
183762306a36Sopenharmony_ci#define MOPT_QFMT	0x0010
183862306a36Sopenharmony_ci#else
183962306a36Sopenharmony_ci#define MOPT_Q		MOPT_NOSUPPORT
184062306a36Sopenharmony_ci#define MOPT_QFMT	MOPT_NOSUPPORT
184162306a36Sopenharmony_ci#endif
184262306a36Sopenharmony_ci#define MOPT_NO_EXT2	0x0020
184362306a36Sopenharmony_ci#define MOPT_NO_EXT3	0x0040
184462306a36Sopenharmony_ci#define MOPT_EXT4_ONLY	(MOPT_NO_EXT2 | MOPT_NO_EXT3)
184562306a36Sopenharmony_ci#define MOPT_SKIP	0x0080
184662306a36Sopenharmony_ci#define	MOPT_2		0x0100
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_cistatic const struct mount_opts {
184962306a36Sopenharmony_ci	int	token;
185062306a36Sopenharmony_ci	int	mount_opt;
185162306a36Sopenharmony_ci	int	flags;
185262306a36Sopenharmony_ci} ext4_mount_opts[] = {
185362306a36Sopenharmony_ci	{Opt_minix_df, EXT4_MOUNT_MINIX_DF, MOPT_SET},
185462306a36Sopenharmony_ci	{Opt_bsd_df, EXT4_MOUNT_MINIX_DF, MOPT_CLEAR},
185562306a36Sopenharmony_ci	{Opt_grpid, EXT4_MOUNT_GRPID, MOPT_SET},
185662306a36Sopenharmony_ci	{Opt_nogrpid, EXT4_MOUNT_GRPID, MOPT_CLEAR},
185762306a36Sopenharmony_ci	{Opt_block_validity, EXT4_MOUNT_BLOCK_VALIDITY, MOPT_SET},
185862306a36Sopenharmony_ci	{Opt_noblock_validity, EXT4_MOUNT_BLOCK_VALIDITY, MOPT_CLEAR},
185962306a36Sopenharmony_ci	{Opt_dioread_nolock, EXT4_MOUNT_DIOREAD_NOLOCK,
186062306a36Sopenharmony_ci	 MOPT_EXT4_ONLY | MOPT_SET},
186162306a36Sopenharmony_ci	{Opt_dioread_lock, EXT4_MOUNT_DIOREAD_NOLOCK,
186262306a36Sopenharmony_ci	 MOPT_EXT4_ONLY | MOPT_CLEAR},
186362306a36Sopenharmony_ci	{Opt_discard, EXT4_MOUNT_DISCARD, MOPT_SET},
186462306a36Sopenharmony_ci	{Opt_nodiscard, EXT4_MOUNT_DISCARD, MOPT_CLEAR},
186562306a36Sopenharmony_ci	{Opt_delalloc, EXT4_MOUNT_DELALLOC,
186662306a36Sopenharmony_ci	 MOPT_EXT4_ONLY | MOPT_SET | MOPT_EXPLICIT},
186762306a36Sopenharmony_ci	{Opt_nodelalloc, EXT4_MOUNT_DELALLOC,
186862306a36Sopenharmony_ci	 MOPT_EXT4_ONLY | MOPT_CLEAR},
186962306a36Sopenharmony_ci	{Opt_warn_on_error, EXT4_MOUNT_WARN_ON_ERROR, MOPT_SET},
187062306a36Sopenharmony_ci	{Opt_nowarn_on_error, EXT4_MOUNT_WARN_ON_ERROR, MOPT_CLEAR},
187162306a36Sopenharmony_ci	{Opt_commit, 0, MOPT_NO_EXT2},
187262306a36Sopenharmony_ci	{Opt_nojournal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM,
187362306a36Sopenharmony_ci	 MOPT_EXT4_ONLY | MOPT_CLEAR},
187462306a36Sopenharmony_ci	{Opt_journal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM,
187562306a36Sopenharmony_ci	 MOPT_EXT4_ONLY | MOPT_SET | MOPT_EXPLICIT},
187662306a36Sopenharmony_ci	{Opt_journal_async_commit, (EXT4_MOUNT_JOURNAL_ASYNC_COMMIT |
187762306a36Sopenharmony_ci				    EXT4_MOUNT_JOURNAL_CHECKSUM),
187862306a36Sopenharmony_ci	 MOPT_EXT4_ONLY | MOPT_SET | MOPT_EXPLICIT},
187962306a36Sopenharmony_ci	{Opt_noload, EXT4_MOUNT_NOLOAD, MOPT_NO_EXT2 | MOPT_SET},
188062306a36Sopenharmony_ci	{Opt_data_err, EXT4_MOUNT_DATA_ERR_ABORT, MOPT_NO_EXT2},
188162306a36Sopenharmony_ci	{Opt_barrier, EXT4_MOUNT_BARRIER, MOPT_SET},
188262306a36Sopenharmony_ci	{Opt_nobarrier, EXT4_MOUNT_BARRIER, MOPT_CLEAR},
188362306a36Sopenharmony_ci	{Opt_noauto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_SET},
188462306a36Sopenharmony_ci	{Opt_auto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_CLEAR},
188562306a36Sopenharmony_ci	{Opt_noinit_itable, EXT4_MOUNT_INIT_INODE_TABLE, MOPT_CLEAR},
188662306a36Sopenharmony_ci	{Opt_dax_type, 0, MOPT_EXT4_ONLY},
188762306a36Sopenharmony_ci	{Opt_journal_dev, 0, MOPT_NO_EXT2},
188862306a36Sopenharmony_ci	{Opt_journal_path, 0, MOPT_NO_EXT2},
188962306a36Sopenharmony_ci	{Opt_journal_ioprio, 0, MOPT_NO_EXT2},
189062306a36Sopenharmony_ci	{Opt_data, 0, MOPT_NO_EXT2},
189162306a36Sopenharmony_ci	{Opt_user_xattr, EXT4_MOUNT_XATTR_USER, MOPT_SET},
189262306a36Sopenharmony_ci#ifdef CONFIG_EXT4_FS_POSIX_ACL
189362306a36Sopenharmony_ci	{Opt_acl, EXT4_MOUNT_POSIX_ACL, MOPT_SET},
189462306a36Sopenharmony_ci#else
189562306a36Sopenharmony_ci	{Opt_acl, 0, MOPT_NOSUPPORT},
189662306a36Sopenharmony_ci#endif
189762306a36Sopenharmony_ci	{Opt_nouid32, EXT4_MOUNT_NO_UID32, MOPT_SET},
189862306a36Sopenharmony_ci	{Opt_debug, EXT4_MOUNT_DEBUG, MOPT_SET},
189962306a36Sopenharmony_ci	{Opt_quota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA, MOPT_SET | MOPT_Q},
190062306a36Sopenharmony_ci	{Opt_usrquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA,
190162306a36Sopenharmony_ci							MOPT_SET | MOPT_Q},
190262306a36Sopenharmony_ci	{Opt_grpquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_GRPQUOTA,
190362306a36Sopenharmony_ci							MOPT_SET | MOPT_Q},
190462306a36Sopenharmony_ci	{Opt_prjquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_PRJQUOTA,
190562306a36Sopenharmony_ci							MOPT_SET | MOPT_Q},
190662306a36Sopenharmony_ci	{Opt_noquota, (EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA |
190762306a36Sopenharmony_ci		       EXT4_MOUNT_GRPQUOTA | EXT4_MOUNT_PRJQUOTA),
190862306a36Sopenharmony_ci							MOPT_CLEAR | MOPT_Q},
190962306a36Sopenharmony_ci	{Opt_usrjquota, 0, MOPT_Q},
191062306a36Sopenharmony_ci	{Opt_grpjquota, 0, MOPT_Q},
191162306a36Sopenharmony_ci	{Opt_jqfmt, 0, MOPT_QFMT},
191262306a36Sopenharmony_ci	{Opt_nombcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET},
191362306a36Sopenharmony_ci	{Opt_no_prefetch_block_bitmaps, EXT4_MOUNT_NO_PREFETCH_BLOCK_BITMAPS,
191462306a36Sopenharmony_ci	 MOPT_SET},
191562306a36Sopenharmony_ci#ifdef CONFIG_EXT4_DEBUG
191662306a36Sopenharmony_ci	{Opt_fc_debug_force, EXT4_MOUNT2_JOURNAL_FAST_COMMIT,
191762306a36Sopenharmony_ci	 MOPT_SET | MOPT_2 | MOPT_EXT4_ONLY},
191862306a36Sopenharmony_ci#endif
191962306a36Sopenharmony_ci	{Opt_abort, EXT4_MOUNT2_ABORT, MOPT_SET | MOPT_2},
192062306a36Sopenharmony_ci	{Opt_err, 0, 0}
192162306a36Sopenharmony_ci};
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE)
192462306a36Sopenharmony_cistatic const struct ext4_sb_encodings {
192562306a36Sopenharmony_ci	__u16 magic;
192662306a36Sopenharmony_ci	char *name;
192762306a36Sopenharmony_ci	unsigned int version;
192862306a36Sopenharmony_ci} ext4_sb_encoding_map[] = {
192962306a36Sopenharmony_ci	{EXT4_ENC_UTF8_12_1, "utf8", UNICODE_AGE(12, 1, 0)},
193062306a36Sopenharmony_ci};
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_cistatic const struct ext4_sb_encodings *
193362306a36Sopenharmony_ciext4_sb_read_encoding(const struct ext4_super_block *es)
193462306a36Sopenharmony_ci{
193562306a36Sopenharmony_ci	__u16 magic = le16_to_cpu(es->s_encoding);
193662306a36Sopenharmony_ci	int i;
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ext4_sb_encoding_map); i++)
193962306a36Sopenharmony_ci		if (magic == ext4_sb_encoding_map[i].magic)
194062306a36Sopenharmony_ci			return &ext4_sb_encoding_map[i];
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	return NULL;
194362306a36Sopenharmony_ci}
194462306a36Sopenharmony_ci#endif
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci#define EXT4_SPEC_JQUOTA			(1 <<  0)
194762306a36Sopenharmony_ci#define EXT4_SPEC_JQFMT				(1 <<  1)
194862306a36Sopenharmony_ci#define EXT4_SPEC_DATAJ				(1 <<  2)
194962306a36Sopenharmony_ci#define EXT4_SPEC_SB_BLOCK			(1 <<  3)
195062306a36Sopenharmony_ci#define EXT4_SPEC_JOURNAL_DEV			(1 <<  4)
195162306a36Sopenharmony_ci#define EXT4_SPEC_JOURNAL_IOPRIO		(1 <<  5)
195262306a36Sopenharmony_ci#define EXT4_SPEC_s_want_extra_isize		(1 <<  7)
195362306a36Sopenharmony_ci#define EXT4_SPEC_s_max_batch_time		(1 <<  8)
195462306a36Sopenharmony_ci#define EXT4_SPEC_s_min_batch_time		(1 <<  9)
195562306a36Sopenharmony_ci#define EXT4_SPEC_s_inode_readahead_blks	(1 << 10)
195662306a36Sopenharmony_ci#define EXT4_SPEC_s_li_wait_mult		(1 << 11)
195762306a36Sopenharmony_ci#define EXT4_SPEC_s_max_dir_size_kb		(1 << 12)
195862306a36Sopenharmony_ci#define EXT4_SPEC_s_stripe			(1 << 13)
195962306a36Sopenharmony_ci#define EXT4_SPEC_s_resuid			(1 << 14)
196062306a36Sopenharmony_ci#define EXT4_SPEC_s_resgid			(1 << 15)
196162306a36Sopenharmony_ci#define EXT4_SPEC_s_commit_interval		(1 << 16)
196262306a36Sopenharmony_ci#define EXT4_SPEC_s_fc_debug_max_replay		(1 << 17)
196362306a36Sopenharmony_ci#define EXT4_SPEC_s_sb_block			(1 << 18)
196462306a36Sopenharmony_ci#define EXT4_SPEC_mb_optimize_scan		(1 << 19)
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_cistruct ext4_fs_context {
196762306a36Sopenharmony_ci	char		*s_qf_names[EXT4_MAXQUOTAS];
196862306a36Sopenharmony_ci	struct fscrypt_dummy_policy dummy_enc_policy;
196962306a36Sopenharmony_ci	int		s_jquota_fmt;	/* Format of quota to use */
197062306a36Sopenharmony_ci#ifdef CONFIG_EXT4_DEBUG
197162306a36Sopenharmony_ci	int s_fc_debug_max_replay;
197262306a36Sopenharmony_ci#endif
197362306a36Sopenharmony_ci	unsigned short	qname_spec;
197462306a36Sopenharmony_ci	unsigned long	vals_s_flags;	/* Bits to set in s_flags */
197562306a36Sopenharmony_ci	unsigned long	mask_s_flags;	/* Bits changed in s_flags */
197662306a36Sopenharmony_ci	unsigned long	journal_devnum;
197762306a36Sopenharmony_ci	unsigned long	s_commit_interval;
197862306a36Sopenharmony_ci	unsigned long	s_stripe;
197962306a36Sopenharmony_ci	unsigned int	s_inode_readahead_blks;
198062306a36Sopenharmony_ci	unsigned int	s_want_extra_isize;
198162306a36Sopenharmony_ci	unsigned int	s_li_wait_mult;
198262306a36Sopenharmony_ci	unsigned int	s_max_dir_size_kb;
198362306a36Sopenharmony_ci	unsigned int	journal_ioprio;
198462306a36Sopenharmony_ci	unsigned int	vals_s_mount_opt;
198562306a36Sopenharmony_ci	unsigned int	mask_s_mount_opt;
198662306a36Sopenharmony_ci	unsigned int	vals_s_mount_opt2;
198762306a36Sopenharmony_ci	unsigned int	mask_s_mount_opt2;
198862306a36Sopenharmony_ci	unsigned int	opt_flags;	/* MOPT flags */
198962306a36Sopenharmony_ci	unsigned int	spec;
199062306a36Sopenharmony_ci	u32		s_max_batch_time;
199162306a36Sopenharmony_ci	u32		s_min_batch_time;
199262306a36Sopenharmony_ci	kuid_t		s_resuid;
199362306a36Sopenharmony_ci	kgid_t		s_resgid;
199462306a36Sopenharmony_ci	ext4_fsblk_t	s_sb_block;
199562306a36Sopenharmony_ci};
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_cistatic void ext4_fc_free(struct fs_context *fc)
199862306a36Sopenharmony_ci{
199962306a36Sopenharmony_ci	struct ext4_fs_context *ctx = fc->fs_private;
200062306a36Sopenharmony_ci	int i;
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	if (!ctx)
200362306a36Sopenharmony_ci		return;
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	for (i = 0; i < EXT4_MAXQUOTAS; i++)
200662306a36Sopenharmony_ci		kfree(ctx->s_qf_names[i]);
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	fscrypt_free_dummy_policy(&ctx->dummy_enc_policy);
200962306a36Sopenharmony_ci	kfree(ctx);
201062306a36Sopenharmony_ci}
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ciint ext4_init_fs_context(struct fs_context *fc)
201362306a36Sopenharmony_ci{
201462306a36Sopenharmony_ci	struct ext4_fs_context *ctx;
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	ctx = kzalloc(sizeof(struct ext4_fs_context), GFP_KERNEL);
201762306a36Sopenharmony_ci	if (!ctx)
201862306a36Sopenharmony_ci		return -ENOMEM;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	fc->fs_private = ctx;
202162306a36Sopenharmony_ci	fc->ops = &ext4_context_ops;
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	return 0;
202462306a36Sopenharmony_ci}
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
202762306a36Sopenharmony_ci/*
202862306a36Sopenharmony_ci * Note the name of the specified quota file.
202962306a36Sopenharmony_ci */
203062306a36Sopenharmony_cistatic int note_qf_name(struct fs_context *fc, int qtype,
203162306a36Sopenharmony_ci		       struct fs_parameter *param)
203262306a36Sopenharmony_ci{
203362306a36Sopenharmony_ci	struct ext4_fs_context *ctx = fc->fs_private;
203462306a36Sopenharmony_ci	char *qname;
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_ci	if (param->size < 1) {
203762306a36Sopenharmony_ci		ext4_msg(NULL, KERN_ERR, "Missing quota name");
203862306a36Sopenharmony_ci		return -EINVAL;
203962306a36Sopenharmony_ci	}
204062306a36Sopenharmony_ci	if (strchr(param->string, '/')) {
204162306a36Sopenharmony_ci		ext4_msg(NULL, KERN_ERR,
204262306a36Sopenharmony_ci			 "quotafile must be on filesystem root");
204362306a36Sopenharmony_ci		return -EINVAL;
204462306a36Sopenharmony_ci	}
204562306a36Sopenharmony_ci	if (ctx->s_qf_names[qtype]) {
204662306a36Sopenharmony_ci		if (strcmp(ctx->s_qf_names[qtype], param->string) != 0) {
204762306a36Sopenharmony_ci			ext4_msg(NULL, KERN_ERR,
204862306a36Sopenharmony_ci				 "%s quota file already specified",
204962306a36Sopenharmony_ci				 QTYPE2NAME(qtype));
205062306a36Sopenharmony_ci			return -EINVAL;
205162306a36Sopenharmony_ci		}
205262306a36Sopenharmony_ci		return 0;
205362306a36Sopenharmony_ci	}
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	qname = kmemdup_nul(param->string, param->size, GFP_KERNEL);
205662306a36Sopenharmony_ci	if (!qname) {
205762306a36Sopenharmony_ci		ext4_msg(NULL, KERN_ERR,
205862306a36Sopenharmony_ci			 "Not enough memory for storing quotafile name");
205962306a36Sopenharmony_ci		return -ENOMEM;
206062306a36Sopenharmony_ci	}
206162306a36Sopenharmony_ci	ctx->s_qf_names[qtype] = qname;
206262306a36Sopenharmony_ci	ctx->qname_spec |= 1 << qtype;
206362306a36Sopenharmony_ci	ctx->spec |= EXT4_SPEC_JQUOTA;
206462306a36Sopenharmony_ci	return 0;
206562306a36Sopenharmony_ci}
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci/*
206862306a36Sopenharmony_ci * Clear the name of the specified quota file.
206962306a36Sopenharmony_ci */
207062306a36Sopenharmony_cistatic int unnote_qf_name(struct fs_context *fc, int qtype)
207162306a36Sopenharmony_ci{
207262306a36Sopenharmony_ci	struct ext4_fs_context *ctx = fc->fs_private;
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	if (ctx->s_qf_names[qtype])
207562306a36Sopenharmony_ci		kfree(ctx->s_qf_names[qtype]);
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	ctx->s_qf_names[qtype] = NULL;
207862306a36Sopenharmony_ci	ctx->qname_spec |= 1 << qtype;
207962306a36Sopenharmony_ci	ctx->spec |= EXT4_SPEC_JQUOTA;
208062306a36Sopenharmony_ci	return 0;
208162306a36Sopenharmony_ci}
208262306a36Sopenharmony_ci#endif
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_cistatic int ext4_parse_test_dummy_encryption(const struct fs_parameter *param,
208562306a36Sopenharmony_ci					    struct ext4_fs_context *ctx)
208662306a36Sopenharmony_ci{
208762306a36Sopenharmony_ci	int err;
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_FS_ENCRYPTION)) {
209062306a36Sopenharmony_ci		ext4_msg(NULL, KERN_WARNING,
209162306a36Sopenharmony_ci			 "test_dummy_encryption option not supported");
209262306a36Sopenharmony_ci		return -EINVAL;
209362306a36Sopenharmony_ci	}
209462306a36Sopenharmony_ci	err = fscrypt_parse_test_dummy_encryption(param,
209562306a36Sopenharmony_ci						  &ctx->dummy_enc_policy);
209662306a36Sopenharmony_ci	if (err == -EINVAL) {
209762306a36Sopenharmony_ci		ext4_msg(NULL, KERN_WARNING,
209862306a36Sopenharmony_ci			 "Value of option \"%s\" is unrecognized", param->key);
209962306a36Sopenharmony_ci	} else if (err == -EEXIST) {
210062306a36Sopenharmony_ci		ext4_msg(NULL, KERN_WARNING,
210162306a36Sopenharmony_ci			 "Conflicting test_dummy_encryption options");
210262306a36Sopenharmony_ci		return -EINVAL;
210362306a36Sopenharmony_ci	}
210462306a36Sopenharmony_ci	return err;
210562306a36Sopenharmony_ci}
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci#define EXT4_SET_CTX(name)						\
210862306a36Sopenharmony_cistatic inline void ctx_set_##name(struct ext4_fs_context *ctx,		\
210962306a36Sopenharmony_ci				  unsigned long flag)			\
211062306a36Sopenharmony_ci{									\
211162306a36Sopenharmony_ci	ctx->mask_s_##name |= flag;					\
211262306a36Sopenharmony_ci	ctx->vals_s_##name |= flag;					\
211362306a36Sopenharmony_ci}
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci#define EXT4_CLEAR_CTX(name)						\
211662306a36Sopenharmony_cistatic inline void ctx_clear_##name(struct ext4_fs_context *ctx,	\
211762306a36Sopenharmony_ci				    unsigned long flag)			\
211862306a36Sopenharmony_ci{									\
211962306a36Sopenharmony_ci	ctx->mask_s_##name |= flag;					\
212062306a36Sopenharmony_ci	ctx->vals_s_##name &= ~flag;					\
212162306a36Sopenharmony_ci}
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci#define EXT4_TEST_CTX(name)						\
212462306a36Sopenharmony_cistatic inline unsigned long						\
212562306a36Sopenharmony_cictx_test_##name(struct ext4_fs_context *ctx, unsigned long flag)	\
212662306a36Sopenharmony_ci{									\
212762306a36Sopenharmony_ci	return (ctx->vals_s_##name & flag);				\
212862306a36Sopenharmony_ci}
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ciEXT4_SET_CTX(flags); /* set only */
213162306a36Sopenharmony_ciEXT4_SET_CTX(mount_opt);
213262306a36Sopenharmony_ciEXT4_CLEAR_CTX(mount_opt);
213362306a36Sopenharmony_ciEXT4_TEST_CTX(mount_opt);
213462306a36Sopenharmony_ciEXT4_SET_CTX(mount_opt2);
213562306a36Sopenharmony_ciEXT4_CLEAR_CTX(mount_opt2);
213662306a36Sopenharmony_ciEXT4_TEST_CTX(mount_opt2);
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_cistatic int ext4_parse_param(struct fs_context *fc, struct fs_parameter *param)
213962306a36Sopenharmony_ci{
214062306a36Sopenharmony_ci	struct ext4_fs_context *ctx = fc->fs_private;
214162306a36Sopenharmony_ci	struct fs_parse_result result;
214262306a36Sopenharmony_ci	const struct mount_opts *m;
214362306a36Sopenharmony_ci	int is_remount;
214462306a36Sopenharmony_ci	kuid_t uid;
214562306a36Sopenharmony_ci	kgid_t gid;
214662306a36Sopenharmony_ci	int token;
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	token = fs_parse(fc, ext4_param_specs, param, &result);
214962306a36Sopenharmony_ci	if (token < 0)
215062306a36Sopenharmony_ci		return token;
215162306a36Sopenharmony_ci	is_remount = fc->purpose == FS_CONTEXT_FOR_RECONFIGURE;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	for (m = ext4_mount_opts; m->token != Opt_err; m++)
215462306a36Sopenharmony_ci		if (token == m->token)
215562306a36Sopenharmony_ci			break;
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	ctx->opt_flags |= m->flags;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	if (m->flags & MOPT_EXPLICIT) {
216062306a36Sopenharmony_ci		if (m->mount_opt & EXT4_MOUNT_DELALLOC) {
216162306a36Sopenharmony_ci			ctx_set_mount_opt2(ctx, EXT4_MOUNT2_EXPLICIT_DELALLOC);
216262306a36Sopenharmony_ci		} else if (m->mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) {
216362306a36Sopenharmony_ci			ctx_set_mount_opt2(ctx,
216462306a36Sopenharmony_ci				       EXT4_MOUNT2_EXPLICIT_JOURNAL_CHECKSUM);
216562306a36Sopenharmony_ci		} else
216662306a36Sopenharmony_ci			return -EINVAL;
216762306a36Sopenharmony_ci	}
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	if (m->flags & MOPT_NOSUPPORT) {
217062306a36Sopenharmony_ci		ext4_msg(NULL, KERN_ERR, "%s option not supported",
217162306a36Sopenharmony_ci			 param->key);
217262306a36Sopenharmony_ci		return 0;
217362306a36Sopenharmony_ci	}
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	switch (token) {
217662306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
217762306a36Sopenharmony_ci	case Opt_usrjquota:
217862306a36Sopenharmony_ci		if (!*param->string)
217962306a36Sopenharmony_ci			return unnote_qf_name(fc, USRQUOTA);
218062306a36Sopenharmony_ci		else
218162306a36Sopenharmony_ci			return note_qf_name(fc, USRQUOTA, param);
218262306a36Sopenharmony_ci	case Opt_grpjquota:
218362306a36Sopenharmony_ci		if (!*param->string)
218462306a36Sopenharmony_ci			return unnote_qf_name(fc, GRPQUOTA);
218562306a36Sopenharmony_ci		else
218662306a36Sopenharmony_ci			return note_qf_name(fc, GRPQUOTA, param);
218762306a36Sopenharmony_ci#endif
218862306a36Sopenharmony_ci	case Opt_sb:
218962306a36Sopenharmony_ci		if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
219062306a36Sopenharmony_ci			ext4_msg(NULL, KERN_WARNING,
219162306a36Sopenharmony_ci				 "Ignoring %s option on remount", param->key);
219262306a36Sopenharmony_ci		} else {
219362306a36Sopenharmony_ci			ctx->s_sb_block = result.uint_32;
219462306a36Sopenharmony_ci			ctx->spec |= EXT4_SPEC_s_sb_block;
219562306a36Sopenharmony_ci		}
219662306a36Sopenharmony_ci		return 0;
219762306a36Sopenharmony_ci	case Opt_removed:
219862306a36Sopenharmony_ci		ext4_msg(NULL, KERN_WARNING, "Ignoring removed %s option",
219962306a36Sopenharmony_ci			 param->key);
220062306a36Sopenharmony_ci		return 0;
220162306a36Sopenharmony_ci	case Opt_inlinecrypt:
220262306a36Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT
220362306a36Sopenharmony_ci		ctx_set_flags(ctx, SB_INLINECRYPT);
220462306a36Sopenharmony_ci#else
220562306a36Sopenharmony_ci		ext4_msg(NULL, KERN_ERR, "inline encryption not supported");
220662306a36Sopenharmony_ci#endif
220762306a36Sopenharmony_ci		return 0;
220862306a36Sopenharmony_ci	case Opt_errors:
220962306a36Sopenharmony_ci		ctx_clear_mount_opt(ctx, EXT4_MOUNT_ERRORS_MASK);
221062306a36Sopenharmony_ci		ctx_set_mount_opt(ctx, result.uint_32);
221162306a36Sopenharmony_ci		return 0;
221262306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
221362306a36Sopenharmony_ci	case Opt_jqfmt:
221462306a36Sopenharmony_ci		ctx->s_jquota_fmt = result.uint_32;
221562306a36Sopenharmony_ci		ctx->spec |= EXT4_SPEC_JQFMT;
221662306a36Sopenharmony_ci		return 0;
221762306a36Sopenharmony_ci#endif
221862306a36Sopenharmony_ci	case Opt_data:
221962306a36Sopenharmony_ci		ctx_clear_mount_opt(ctx, EXT4_MOUNT_DATA_FLAGS);
222062306a36Sopenharmony_ci		ctx_set_mount_opt(ctx, result.uint_32);
222162306a36Sopenharmony_ci		ctx->spec |= EXT4_SPEC_DATAJ;
222262306a36Sopenharmony_ci		return 0;
222362306a36Sopenharmony_ci	case Opt_commit:
222462306a36Sopenharmony_ci		if (result.uint_32 == 0)
222562306a36Sopenharmony_ci			result.uint_32 = JBD2_DEFAULT_MAX_COMMIT_AGE;
222662306a36Sopenharmony_ci		else if (result.uint_32 > INT_MAX / HZ) {
222762306a36Sopenharmony_ci			ext4_msg(NULL, KERN_ERR,
222862306a36Sopenharmony_ci				 "Invalid commit interval %d, "
222962306a36Sopenharmony_ci				 "must be smaller than %d",
223062306a36Sopenharmony_ci				 result.uint_32, INT_MAX / HZ);
223162306a36Sopenharmony_ci			return -EINVAL;
223262306a36Sopenharmony_ci		}
223362306a36Sopenharmony_ci		ctx->s_commit_interval = HZ * result.uint_32;
223462306a36Sopenharmony_ci		ctx->spec |= EXT4_SPEC_s_commit_interval;
223562306a36Sopenharmony_ci		return 0;
223662306a36Sopenharmony_ci	case Opt_debug_want_extra_isize:
223762306a36Sopenharmony_ci		if ((result.uint_32 & 1) || (result.uint_32 < 4)) {
223862306a36Sopenharmony_ci			ext4_msg(NULL, KERN_ERR,
223962306a36Sopenharmony_ci				 "Invalid want_extra_isize %d", result.uint_32);
224062306a36Sopenharmony_ci			return -EINVAL;
224162306a36Sopenharmony_ci		}
224262306a36Sopenharmony_ci		ctx->s_want_extra_isize = result.uint_32;
224362306a36Sopenharmony_ci		ctx->spec |= EXT4_SPEC_s_want_extra_isize;
224462306a36Sopenharmony_ci		return 0;
224562306a36Sopenharmony_ci	case Opt_max_batch_time:
224662306a36Sopenharmony_ci		ctx->s_max_batch_time = result.uint_32;
224762306a36Sopenharmony_ci		ctx->spec |= EXT4_SPEC_s_max_batch_time;
224862306a36Sopenharmony_ci		return 0;
224962306a36Sopenharmony_ci	case Opt_min_batch_time:
225062306a36Sopenharmony_ci		ctx->s_min_batch_time = result.uint_32;
225162306a36Sopenharmony_ci		ctx->spec |= EXT4_SPEC_s_min_batch_time;
225262306a36Sopenharmony_ci		return 0;
225362306a36Sopenharmony_ci	case Opt_inode_readahead_blks:
225462306a36Sopenharmony_ci		if (result.uint_32 &&
225562306a36Sopenharmony_ci		    (result.uint_32 > (1 << 30) ||
225662306a36Sopenharmony_ci		     !is_power_of_2(result.uint_32))) {
225762306a36Sopenharmony_ci			ext4_msg(NULL, KERN_ERR,
225862306a36Sopenharmony_ci				 "EXT4-fs: inode_readahead_blks must be "
225962306a36Sopenharmony_ci				 "0 or a power of 2 smaller than 2^31");
226062306a36Sopenharmony_ci			return -EINVAL;
226162306a36Sopenharmony_ci		}
226262306a36Sopenharmony_ci		ctx->s_inode_readahead_blks = result.uint_32;
226362306a36Sopenharmony_ci		ctx->spec |= EXT4_SPEC_s_inode_readahead_blks;
226462306a36Sopenharmony_ci		return 0;
226562306a36Sopenharmony_ci	case Opt_init_itable:
226662306a36Sopenharmony_ci		ctx_set_mount_opt(ctx, EXT4_MOUNT_INIT_INODE_TABLE);
226762306a36Sopenharmony_ci		ctx->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT;
226862306a36Sopenharmony_ci		if (param->type == fs_value_is_string)
226962306a36Sopenharmony_ci			ctx->s_li_wait_mult = result.uint_32;
227062306a36Sopenharmony_ci		ctx->spec |= EXT4_SPEC_s_li_wait_mult;
227162306a36Sopenharmony_ci		return 0;
227262306a36Sopenharmony_ci	case Opt_max_dir_size_kb:
227362306a36Sopenharmony_ci		ctx->s_max_dir_size_kb = result.uint_32;
227462306a36Sopenharmony_ci		ctx->spec |= EXT4_SPEC_s_max_dir_size_kb;
227562306a36Sopenharmony_ci		return 0;
227662306a36Sopenharmony_ci#ifdef CONFIG_EXT4_DEBUG
227762306a36Sopenharmony_ci	case Opt_fc_debug_max_replay:
227862306a36Sopenharmony_ci		ctx->s_fc_debug_max_replay = result.uint_32;
227962306a36Sopenharmony_ci		ctx->spec |= EXT4_SPEC_s_fc_debug_max_replay;
228062306a36Sopenharmony_ci		return 0;
228162306a36Sopenharmony_ci#endif
228262306a36Sopenharmony_ci	case Opt_stripe:
228362306a36Sopenharmony_ci		ctx->s_stripe = result.uint_32;
228462306a36Sopenharmony_ci		ctx->spec |= EXT4_SPEC_s_stripe;
228562306a36Sopenharmony_ci		return 0;
228662306a36Sopenharmony_ci	case Opt_resuid:
228762306a36Sopenharmony_ci		uid = make_kuid(current_user_ns(), result.uint_32);
228862306a36Sopenharmony_ci		if (!uid_valid(uid)) {
228962306a36Sopenharmony_ci			ext4_msg(NULL, KERN_ERR, "Invalid uid value %d",
229062306a36Sopenharmony_ci				 result.uint_32);
229162306a36Sopenharmony_ci			return -EINVAL;
229262306a36Sopenharmony_ci		}
229362306a36Sopenharmony_ci		ctx->s_resuid = uid;
229462306a36Sopenharmony_ci		ctx->spec |= EXT4_SPEC_s_resuid;
229562306a36Sopenharmony_ci		return 0;
229662306a36Sopenharmony_ci	case Opt_resgid:
229762306a36Sopenharmony_ci		gid = make_kgid(current_user_ns(), result.uint_32);
229862306a36Sopenharmony_ci		if (!gid_valid(gid)) {
229962306a36Sopenharmony_ci			ext4_msg(NULL, KERN_ERR, "Invalid gid value %d",
230062306a36Sopenharmony_ci				 result.uint_32);
230162306a36Sopenharmony_ci			return -EINVAL;
230262306a36Sopenharmony_ci		}
230362306a36Sopenharmony_ci		ctx->s_resgid = gid;
230462306a36Sopenharmony_ci		ctx->spec |= EXT4_SPEC_s_resgid;
230562306a36Sopenharmony_ci		return 0;
230662306a36Sopenharmony_ci	case Opt_journal_dev:
230762306a36Sopenharmony_ci		if (is_remount) {
230862306a36Sopenharmony_ci			ext4_msg(NULL, KERN_ERR,
230962306a36Sopenharmony_ci				 "Cannot specify journal on remount");
231062306a36Sopenharmony_ci			return -EINVAL;
231162306a36Sopenharmony_ci		}
231262306a36Sopenharmony_ci		ctx->journal_devnum = result.uint_32;
231362306a36Sopenharmony_ci		ctx->spec |= EXT4_SPEC_JOURNAL_DEV;
231462306a36Sopenharmony_ci		return 0;
231562306a36Sopenharmony_ci	case Opt_journal_path:
231662306a36Sopenharmony_ci	{
231762306a36Sopenharmony_ci		struct inode *journal_inode;
231862306a36Sopenharmony_ci		struct path path;
231962306a36Sopenharmony_ci		int error;
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci		if (is_remount) {
232262306a36Sopenharmony_ci			ext4_msg(NULL, KERN_ERR,
232362306a36Sopenharmony_ci				 "Cannot specify journal on remount");
232462306a36Sopenharmony_ci			return -EINVAL;
232562306a36Sopenharmony_ci		}
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci		error = fs_lookup_param(fc, param, 1, LOOKUP_FOLLOW, &path);
232862306a36Sopenharmony_ci		if (error) {
232962306a36Sopenharmony_ci			ext4_msg(NULL, KERN_ERR, "error: could not find "
233062306a36Sopenharmony_ci				 "journal device path");
233162306a36Sopenharmony_ci			return -EINVAL;
233262306a36Sopenharmony_ci		}
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci		journal_inode = d_inode(path.dentry);
233562306a36Sopenharmony_ci		ctx->journal_devnum = new_encode_dev(journal_inode->i_rdev);
233662306a36Sopenharmony_ci		ctx->spec |= EXT4_SPEC_JOURNAL_DEV;
233762306a36Sopenharmony_ci		path_put(&path);
233862306a36Sopenharmony_ci		return 0;
233962306a36Sopenharmony_ci	}
234062306a36Sopenharmony_ci	case Opt_journal_ioprio:
234162306a36Sopenharmony_ci		if (result.uint_32 > 7) {
234262306a36Sopenharmony_ci			ext4_msg(NULL, KERN_ERR, "Invalid journal IO priority"
234362306a36Sopenharmony_ci				 " (must be 0-7)");
234462306a36Sopenharmony_ci			return -EINVAL;
234562306a36Sopenharmony_ci		}
234662306a36Sopenharmony_ci		ctx->journal_ioprio =
234762306a36Sopenharmony_ci			IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, result.uint_32);
234862306a36Sopenharmony_ci		ctx->spec |= EXT4_SPEC_JOURNAL_IOPRIO;
234962306a36Sopenharmony_ci		return 0;
235062306a36Sopenharmony_ci	case Opt_test_dummy_encryption:
235162306a36Sopenharmony_ci		return ext4_parse_test_dummy_encryption(param, ctx);
235262306a36Sopenharmony_ci	case Opt_dax:
235362306a36Sopenharmony_ci	case Opt_dax_type:
235462306a36Sopenharmony_ci#ifdef CONFIG_FS_DAX
235562306a36Sopenharmony_ci	{
235662306a36Sopenharmony_ci		int type = (token == Opt_dax) ?
235762306a36Sopenharmony_ci			   Opt_dax : result.uint_32;
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci		switch (type) {
236062306a36Sopenharmony_ci		case Opt_dax:
236162306a36Sopenharmony_ci		case Opt_dax_always:
236262306a36Sopenharmony_ci			ctx_set_mount_opt(ctx, EXT4_MOUNT_DAX_ALWAYS);
236362306a36Sopenharmony_ci			ctx_clear_mount_opt2(ctx, EXT4_MOUNT2_DAX_NEVER);
236462306a36Sopenharmony_ci			break;
236562306a36Sopenharmony_ci		case Opt_dax_never:
236662306a36Sopenharmony_ci			ctx_set_mount_opt2(ctx, EXT4_MOUNT2_DAX_NEVER);
236762306a36Sopenharmony_ci			ctx_clear_mount_opt(ctx, EXT4_MOUNT_DAX_ALWAYS);
236862306a36Sopenharmony_ci			break;
236962306a36Sopenharmony_ci		case Opt_dax_inode:
237062306a36Sopenharmony_ci			ctx_clear_mount_opt(ctx, EXT4_MOUNT_DAX_ALWAYS);
237162306a36Sopenharmony_ci			ctx_clear_mount_opt2(ctx, EXT4_MOUNT2_DAX_NEVER);
237262306a36Sopenharmony_ci			/* Strictly for printing options */
237362306a36Sopenharmony_ci			ctx_set_mount_opt2(ctx, EXT4_MOUNT2_DAX_INODE);
237462306a36Sopenharmony_ci			break;
237562306a36Sopenharmony_ci		}
237662306a36Sopenharmony_ci		return 0;
237762306a36Sopenharmony_ci	}
237862306a36Sopenharmony_ci#else
237962306a36Sopenharmony_ci		ext4_msg(NULL, KERN_INFO, "dax option not supported");
238062306a36Sopenharmony_ci		return -EINVAL;
238162306a36Sopenharmony_ci#endif
238262306a36Sopenharmony_ci	case Opt_data_err:
238362306a36Sopenharmony_ci		if (result.uint_32 == Opt_data_err_abort)
238462306a36Sopenharmony_ci			ctx_set_mount_opt(ctx, m->mount_opt);
238562306a36Sopenharmony_ci		else if (result.uint_32 == Opt_data_err_ignore)
238662306a36Sopenharmony_ci			ctx_clear_mount_opt(ctx, m->mount_opt);
238762306a36Sopenharmony_ci		return 0;
238862306a36Sopenharmony_ci	case Opt_mb_optimize_scan:
238962306a36Sopenharmony_ci		if (result.int_32 == 1) {
239062306a36Sopenharmony_ci			ctx_set_mount_opt2(ctx, EXT4_MOUNT2_MB_OPTIMIZE_SCAN);
239162306a36Sopenharmony_ci			ctx->spec |= EXT4_SPEC_mb_optimize_scan;
239262306a36Sopenharmony_ci		} else if (result.int_32 == 0) {
239362306a36Sopenharmony_ci			ctx_clear_mount_opt2(ctx, EXT4_MOUNT2_MB_OPTIMIZE_SCAN);
239462306a36Sopenharmony_ci			ctx->spec |= EXT4_SPEC_mb_optimize_scan;
239562306a36Sopenharmony_ci		} else {
239662306a36Sopenharmony_ci			ext4_msg(NULL, KERN_WARNING,
239762306a36Sopenharmony_ci				 "mb_optimize_scan should be set to 0 or 1.");
239862306a36Sopenharmony_ci			return -EINVAL;
239962306a36Sopenharmony_ci		}
240062306a36Sopenharmony_ci		return 0;
240162306a36Sopenharmony_ci	}
240262306a36Sopenharmony_ci
240362306a36Sopenharmony_ci	/*
240462306a36Sopenharmony_ci	 * At this point we should only be getting options requiring MOPT_SET,
240562306a36Sopenharmony_ci	 * or MOPT_CLEAR. Anything else is a bug
240662306a36Sopenharmony_ci	 */
240762306a36Sopenharmony_ci	if (m->token == Opt_err) {
240862306a36Sopenharmony_ci		ext4_msg(NULL, KERN_WARNING, "buggy handling of option %s",
240962306a36Sopenharmony_ci			 param->key);
241062306a36Sopenharmony_ci		WARN_ON(1);
241162306a36Sopenharmony_ci		return -EINVAL;
241262306a36Sopenharmony_ci	}
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	else {
241562306a36Sopenharmony_ci		unsigned int set = 0;
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci		if ((param->type == fs_value_is_flag) ||
241862306a36Sopenharmony_ci		    result.uint_32 > 0)
241962306a36Sopenharmony_ci			set = 1;
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci		if (m->flags & MOPT_CLEAR)
242262306a36Sopenharmony_ci			set = !set;
242362306a36Sopenharmony_ci		else if (unlikely(!(m->flags & MOPT_SET))) {
242462306a36Sopenharmony_ci			ext4_msg(NULL, KERN_WARNING,
242562306a36Sopenharmony_ci				 "buggy handling of option %s",
242662306a36Sopenharmony_ci				 param->key);
242762306a36Sopenharmony_ci			WARN_ON(1);
242862306a36Sopenharmony_ci			return -EINVAL;
242962306a36Sopenharmony_ci		}
243062306a36Sopenharmony_ci		if (m->flags & MOPT_2) {
243162306a36Sopenharmony_ci			if (set != 0)
243262306a36Sopenharmony_ci				ctx_set_mount_opt2(ctx, m->mount_opt);
243362306a36Sopenharmony_ci			else
243462306a36Sopenharmony_ci				ctx_clear_mount_opt2(ctx, m->mount_opt);
243562306a36Sopenharmony_ci		} else {
243662306a36Sopenharmony_ci			if (set != 0)
243762306a36Sopenharmony_ci				ctx_set_mount_opt(ctx, m->mount_opt);
243862306a36Sopenharmony_ci			else
243962306a36Sopenharmony_ci				ctx_clear_mount_opt(ctx, m->mount_opt);
244062306a36Sopenharmony_ci		}
244162306a36Sopenharmony_ci	}
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci	return 0;
244462306a36Sopenharmony_ci}
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_cistatic int parse_options(struct fs_context *fc, char *options)
244762306a36Sopenharmony_ci{
244862306a36Sopenharmony_ci	struct fs_parameter param;
244962306a36Sopenharmony_ci	int ret;
245062306a36Sopenharmony_ci	char *key;
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	if (!options)
245362306a36Sopenharmony_ci		return 0;
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_ci	while ((key = strsep(&options, ",")) != NULL) {
245662306a36Sopenharmony_ci		if (*key) {
245762306a36Sopenharmony_ci			size_t v_len = 0;
245862306a36Sopenharmony_ci			char *value = strchr(key, '=');
245962306a36Sopenharmony_ci
246062306a36Sopenharmony_ci			param.type = fs_value_is_flag;
246162306a36Sopenharmony_ci			param.string = NULL;
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci			if (value) {
246462306a36Sopenharmony_ci				if (value == key)
246562306a36Sopenharmony_ci					continue;
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci				*value++ = 0;
246862306a36Sopenharmony_ci				v_len = strlen(value);
246962306a36Sopenharmony_ci				param.string = kmemdup_nul(value, v_len,
247062306a36Sopenharmony_ci							   GFP_KERNEL);
247162306a36Sopenharmony_ci				if (!param.string)
247262306a36Sopenharmony_ci					return -ENOMEM;
247362306a36Sopenharmony_ci				param.type = fs_value_is_string;
247462306a36Sopenharmony_ci			}
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci			param.key = key;
247762306a36Sopenharmony_ci			param.size = v_len;
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci			ret = ext4_parse_param(fc, &param);
248062306a36Sopenharmony_ci			if (param.string)
248162306a36Sopenharmony_ci				kfree(param.string);
248262306a36Sopenharmony_ci			if (ret < 0)
248362306a36Sopenharmony_ci				return ret;
248462306a36Sopenharmony_ci		}
248562306a36Sopenharmony_ci	}
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_ci	ret = ext4_validate_options(fc);
248862306a36Sopenharmony_ci	if (ret < 0)
248962306a36Sopenharmony_ci		return ret;
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_ci	return 0;
249262306a36Sopenharmony_ci}
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_cistatic int parse_apply_sb_mount_options(struct super_block *sb,
249562306a36Sopenharmony_ci					struct ext4_fs_context *m_ctx)
249662306a36Sopenharmony_ci{
249762306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
249862306a36Sopenharmony_ci	char *s_mount_opts = NULL;
249962306a36Sopenharmony_ci	struct ext4_fs_context *s_ctx = NULL;
250062306a36Sopenharmony_ci	struct fs_context *fc = NULL;
250162306a36Sopenharmony_ci	int ret = -ENOMEM;
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci	if (!sbi->s_es->s_mount_opts[0])
250462306a36Sopenharmony_ci		return 0;
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci	s_mount_opts = kstrndup(sbi->s_es->s_mount_opts,
250762306a36Sopenharmony_ci				sizeof(sbi->s_es->s_mount_opts),
250862306a36Sopenharmony_ci				GFP_KERNEL);
250962306a36Sopenharmony_ci	if (!s_mount_opts)
251062306a36Sopenharmony_ci		return ret;
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	fc = kzalloc(sizeof(struct fs_context), GFP_KERNEL);
251362306a36Sopenharmony_ci	if (!fc)
251462306a36Sopenharmony_ci		goto out_free;
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci	s_ctx = kzalloc(sizeof(struct ext4_fs_context), GFP_KERNEL);
251762306a36Sopenharmony_ci	if (!s_ctx)
251862306a36Sopenharmony_ci		goto out_free;
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	fc->fs_private = s_ctx;
252162306a36Sopenharmony_ci	fc->s_fs_info = sbi;
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci	ret = parse_options(fc, s_mount_opts);
252462306a36Sopenharmony_ci	if (ret < 0)
252562306a36Sopenharmony_ci		goto parse_failed;
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	ret = ext4_check_opt_consistency(fc, sb);
252862306a36Sopenharmony_ci	if (ret < 0) {
252962306a36Sopenharmony_ciparse_failed:
253062306a36Sopenharmony_ci		ext4_msg(sb, KERN_WARNING,
253162306a36Sopenharmony_ci			 "failed to parse options in superblock: %s",
253262306a36Sopenharmony_ci			 s_mount_opts);
253362306a36Sopenharmony_ci		ret = 0;
253462306a36Sopenharmony_ci		goto out_free;
253562306a36Sopenharmony_ci	}
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	if (s_ctx->spec & EXT4_SPEC_JOURNAL_DEV)
253862306a36Sopenharmony_ci		m_ctx->journal_devnum = s_ctx->journal_devnum;
253962306a36Sopenharmony_ci	if (s_ctx->spec & EXT4_SPEC_JOURNAL_IOPRIO)
254062306a36Sopenharmony_ci		m_ctx->journal_ioprio = s_ctx->journal_ioprio;
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	ext4_apply_options(fc, sb);
254362306a36Sopenharmony_ci	ret = 0;
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ciout_free:
254662306a36Sopenharmony_ci	if (fc) {
254762306a36Sopenharmony_ci		ext4_fc_free(fc);
254862306a36Sopenharmony_ci		kfree(fc);
254962306a36Sopenharmony_ci	}
255062306a36Sopenharmony_ci	kfree(s_mount_opts);
255162306a36Sopenharmony_ci	return ret;
255262306a36Sopenharmony_ci}
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_cistatic void ext4_apply_quota_options(struct fs_context *fc,
255562306a36Sopenharmony_ci				     struct super_block *sb)
255662306a36Sopenharmony_ci{
255762306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
255862306a36Sopenharmony_ci	bool quota_feature = ext4_has_feature_quota(sb);
255962306a36Sopenharmony_ci	struct ext4_fs_context *ctx = fc->fs_private;
256062306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
256162306a36Sopenharmony_ci	char *qname;
256262306a36Sopenharmony_ci	int i;
256362306a36Sopenharmony_ci
256462306a36Sopenharmony_ci	if (quota_feature)
256562306a36Sopenharmony_ci		return;
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci	if (ctx->spec & EXT4_SPEC_JQUOTA) {
256862306a36Sopenharmony_ci		for (i = 0; i < EXT4_MAXQUOTAS; i++) {
256962306a36Sopenharmony_ci			if (!(ctx->qname_spec & (1 << i)))
257062306a36Sopenharmony_ci				continue;
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_ci			qname = ctx->s_qf_names[i]; /* May be NULL */
257362306a36Sopenharmony_ci			if (qname)
257462306a36Sopenharmony_ci				set_opt(sb, QUOTA);
257562306a36Sopenharmony_ci			ctx->s_qf_names[i] = NULL;
257662306a36Sopenharmony_ci			qname = rcu_replace_pointer(sbi->s_qf_names[i], qname,
257762306a36Sopenharmony_ci						lockdep_is_held(&sb->s_umount));
257862306a36Sopenharmony_ci			if (qname)
257962306a36Sopenharmony_ci				kfree_rcu_mightsleep(qname);
258062306a36Sopenharmony_ci		}
258162306a36Sopenharmony_ci	}
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	if (ctx->spec & EXT4_SPEC_JQFMT)
258462306a36Sopenharmony_ci		sbi->s_jquota_fmt = ctx->s_jquota_fmt;
258562306a36Sopenharmony_ci#endif
258662306a36Sopenharmony_ci}
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci/*
258962306a36Sopenharmony_ci * Check quota settings consistency.
259062306a36Sopenharmony_ci */
259162306a36Sopenharmony_cistatic int ext4_check_quota_consistency(struct fs_context *fc,
259262306a36Sopenharmony_ci					struct super_block *sb)
259362306a36Sopenharmony_ci{
259462306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
259562306a36Sopenharmony_ci	struct ext4_fs_context *ctx = fc->fs_private;
259662306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
259762306a36Sopenharmony_ci	bool quota_feature = ext4_has_feature_quota(sb);
259862306a36Sopenharmony_ci	bool quota_loaded = sb_any_quota_loaded(sb);
259962306a36Sopenharmony_ci	bool usr_qf_name, grp_qf_name, usrquota, grpquota;
260062306a36Sopenharmony_ci	int quota_flags, i;
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci	/*
260362306a36Sopenharmony_ci	 * We do the test below only for project quotas. 'usrquota' and
260462306a36Sopenharmony_ci	 * 'grpquota' mount options are allowed even without quota feature
260562306a36Sopenharmony_ci	 * to support legacy quotas in quota files.
260662306a36Sopenharmony_ci	 */
260762306a36Sopenharmony_ci	if (ctx_test_mount_opt(ctx, EXT4_MOUNT_PRJQUOTA) &&
260862306a36Sopenharmony_ci	    !ext4_has_feature_project(sb)) {
260962306a36Sopenharmony_ci		ext4_msg(NULL, KERN_ERR, "Project quota feature not enabled. "
261062306a36Sopenharmony_ci			 "Cannot enable project quota enforcement.");
261162306a36Sopenharmony_ci		return -EINVAL;
261262306a36Sopenharmony_ci	}
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	quota_flags = EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA |
261562306a36Sopenharmony_ci		      EXT4_MOUNT_GRPQUOTA | EXT4_MOUNT_PRJQUOTA;
261662306a36Sopenharmony_ci	if (quota_loaded &&
261762306a36Sopenharmony_ci	    ctx->mask_s_mount_opt & quota_flags &&
261862306a36Sopenharmony_ci	    !ctx_test_mount_opt(ctx, quota_flags))
261962306a36Sopenharmony_ci		goto err_quota_change;
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci	if (ctx->spec & EXT4_SPEC_JQUOTA) {
262262306a36Sopenharmony_ci
262362306a36Sopenharmony_ci		for (i = 0; i < EXT4_MAXQUOTAS; i++) {
262462306a36Sopenharmony_ci			if (!(ctx->qname_spec & (1 << i)))
262562306a36Sopenharmony_ci				continue;
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci			if (quota_loaded &&
262862306a36Sopenharmony_ci			    !!sbi->s_qf_names[i] != !!ctx->s_qf_names[i])
262962306a36Sopenharmony_ci				goto err_jquota_change;
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci			if (sbi->s_qf_names[i] && ctx->s_qf_names[i] &&
263262306a36Sopenharmony_ci			    strcmp(get_qf_name(sb, sbi, i),
263362306a36Sopenharmony_ci				   ctx->s_qf_names[i]) != 0)
263462306a36Sopenharmony_ci				goto err_jquota_specified;
263562306a36Sopenharmony_ci		}
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci		if (quota_feature) {
263862306a36Sopenharmony_ci			ext4_msg(NULL, KERN_INFO,
263962306a36Sopenharmony_ci				 "Journaled quota options ignored when "
264062306a36Sopenharmony_ci				 "QUOTA feature is enabled");
264162306a36Sopenharmony_ci			return 0;
264262306a36Sopenharmony_ci		}
264362306a36Sopenharmony_ci	}
264462306a36Sopenharmony_ci
264562306a36Sopenharmony_ci	if (ctx->spec & EXT4_SPEC_JQFMT) {
264662306a36Sopenharmony_ci		if (sbi->s_jquota_fmt != ctx->s_jquota_fmt && quota_loaded)
264762306a36Sopenharmony_ci			goto err_jquota_change;
264862306a36Sopenharmony_ci		if (quota_feature) {
264962306a36Sopenharmony_ci			ext4_msg(NULL, KERN_INFO, "Quota format mount options "
265062306a36Sopenharmony_ci				 "ignored when QUOTA feature is enabled");
265162306a36Sopenharmony_ci			return 0;
265262306a36Sopenharmony_ci		}
265362306a36Sopenharmony_ci	}
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci	/* Make sure we don't mix old and new quota format */
265662306a36Sopenharmony_ci	usr_qf_name = (get_qf_name(sb, sbi, USRQUOTA) ||
265762306a36Sopenharmony_ci		       ctx->s_qf_names[USRQUOTA]);
265862306a36Sopenharmony_ci	grp_qf_name = (get_qf_name(sb, sbi, GRPQUOTA) ||
265962306a36Sopenharmony_ci		       ctx->s_qf_names[GRPQUOTA]);
266062306a36Sopenharmony_ci
266162306a36Sopenharmony_ci	usrquota = (ctx_test_mount_opt(ctx, EXT4_MOUNT_USRQUOTA) ||
266262306a36Sopenharmony_ci		    test_opt(sb, USRQUOTA));
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	grpquota = (ctx_test_mount_opt(ctx, EXT4_MOUNT_GRPQUOTA) ||
266562306a36Sopenharmony_ci		    test_opt(sb, GRPQUOTA));
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	if (usr_qf_name) {
266862306a36Sopenharmony_ci		ctx_clear_mount_opt(ctx, EXT4_MOUNT_USRQUOTA);
266962306a36Sopenharmony_ci		usrquota = false;
267062306a36Sopenharmony_ci	}
267162306a36Sopenharmony_ci	if (grp_qf_name) {
267262306a36Sopenharmony_ci		ctx_clear_mount_opt(ctx, EXT4_MOUNT_GRPQUOTA);
267362306a36Sopenharmony_ci		grpquota = false;
267462306a36Sopenharmony_ci	}
267562306a36Sopenharmony_ci
267662306a36Sopenharmony_ci	if (usr_qf_name || grp_qf_name) {
267762306a36Sopenharmony_ci		if (usrquota || grpquota) {
267862306a36Sopenharmony_ci			ext4_msg(NULL, KERN_ERR, "old and new quota "
267962306a36Sopenharmony_ci				 "format mixing");
268062306a36Sopenharmony_ci			return -EINVAL;
268162306a36Sopenharmony_ci		}
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci		if (!(ctx->spec & EXT4_SPEC_JQFMT || sbi->s_jquota_fmt)) {
268462306a36Sopenharmony_ci			ext4_msg(NULL, KERN_ERR, "journaled quota format "
268562306a36Sopenharmony_ci				 "not specified");
268662306a36Sopenharmony_ci			return -EINVAL;
268762306a36Sopenharmony_ci		}
268862306a36Sopenharmony_ci	}
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci	return 0;
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_cierr_quota_change:
269362306a36Sopenharmony_ci	ext4_msg(NULL, KERN_ERR,
269462306a36Sopenharmony_ci		 "Cannot change quota options when quota turned on");
269562306a36Sopenharmony_ci	return -EINVAL;
269662306a36Sopenharmony_cierr_jquota_change:
269762306a36Sopenharmony_ci	ext4_msg(NULL, KERN_ERR, "Cannot change journaled quota "
269862306a36Sopenharmony_ci		 "options when quota turned on");
269962306a36Sopenharmony_ci	return -EINVAL;
270062306a36Sopenharmony_cierr_jquota_specified:
270162306a36Sopenharmony_ci	ext4_msg(NULL, KERN_ERR, "%s quota file already specified",
270262306a36Sopenharmony_ci		 QTYPE2NAME(i));
270362306a36Sopenharmony_ci	return -EINVAL;
270462306a36Sopenharmony_ci#else
270562306a36Sopenharmony_ci	return 0;
270662306a36Sopenharmony_ci#endif
270762306a36Sopenharmony_ci}
270862306a36Sopenharmony_ci
270962306a36Sopenharmony_cistatic int ext4_check_test_dummy_encryption(const struct fs_context *fc,
271062306a36Sopenharmony_ci					    struct super_block *sb)
271162306a36Sopenharmony_ci{
271262306a36Sopenharmony_ci	const struct ext4_fs_context *ctx = fc->fs_private;
271362306a36Sopenharmony_ci	const struct ext4_sb_info *sbi = EXT4_SB(sb);
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_ci	if (!fscrypt_is_dummy_policy_set(&ctx->dummy_enc_policy))
271662306a36Sopenharmony_ci		return 0;
271762306a36Sopenharmony_ci
271862306a36Sopenharmony_ci	if (!ext4_has_feature_encrypt(sb)) {
271962306a36Sopenharmony_ci		ext4_msg(NULL, KERN_WARNING,
272062306a36Sopenharmony_ci			 "test_dummy_encryption requires encrypt feature");
272162306a36Sopenharmony_ci		return -EINVAL;
272262306a36Sopenharmony_ci	}
272362306a36Sopenharmony_ci	/*
272462306a36Sopenharmony_ci	 * This mount option is just for testing, and it's not worthwhile to
272562306a36Sopenharmony_ci	 * implement the extra complexity (e.g. RCU protection) that would be
272662306a36Sopenharmony_ci	 * needed to allow it to be set or changed during remount.  We do allow
272762306a36Sopenharmony_ci	 * it to be specified during remount, but only if there is no change.
272862306a36Sopenharmony_ci	 */
272962306a36Sopenharmony_ci	if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
273062306a36Sopenharmony_ci		if (fscrypt_dummy_policies_equal(&sbi->s_dummy_enc_policy,
273162306a36Sopenharmony_ci						 &ctx->dummy_enc_policy))
273262306a36Sopenharmony_ci			return 0;
273362306a36Sopenharmony_ci		ext4_msg(NULL, KERN_WARNING,
273462306a36Sopenharmony_ci			 "Can't set or change test_dummy_encryption on remount");
273562306a36Sopenharmony_ci		return -EINVAL;
273662306a36Sopenharmony_ci	}
273762306a36Sopenharmony_ci	/* Also make sure s_mount_opts didn't contain a conflicting value. */
273862306a36Sopenharmony_ci	if (fscrypt_is_dummy_policy_set(&sbi->s_dummy_enc_policy)) {
273962306a36Sopenharmony_ci		if (fscrypt_dummy_policies_equal(&sbi->s_dummy_enc_policy,
274062306a36Sopenharmony_ci						 &ctx->dummy_enc_policy))
274162306a36Sopenharmony_ci			return 0;
274262306a36Sopenharmony_ci		ext4_msg(NULL, KERN_WARNING,
274362306a36Sopenharmony_ci			 "Conflicting test_dummy_encryption options");
274462306a36Sopenharmony_ci		return -EINVAL;
274562306a36Sopenharmony_ci	}
274662306a36Sopenharmony_ci	return 0;
274762306a36Sopenharmony_ci}
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_cistatic void ext4_apply_test_dummy_encryption(struct ext4_fs_context *ctx,
275062306a36Sopenharmony_ci					     struct super_block *sb)
275162306a36Sopenharmony_ci{
275262306a36Sopenharmony_ci	if (!fscrypt_is_dummy_policy_set(&ctx->dummy_enc_policy) ||
275362306a36Sopenharmony_ci	    /* if already set, it was already verified to be the same */
275462306a36Sopenharmony_ci	    fscrypt_is_dummy_policy_set(&EXT4_SB(sb)->s_dummy_enc_policy))
275562306a36Sopenharmony_ci		return;
275662306a36Sopenharmony_ci	EXT4_SB(sb)->s_dummy_enc_policy = ctx->dummy_enc_policy;
275762306a36Sopenharmony_ci	memset(&ctx->dummy_enc_policy, 0, sizeof(ctx->dummy_enc_policy));
275862306a36Sopenharmony_ci	ext4_msg(sb, KERN_WARNING, "Test dummy encryption mode enabled");
275962306a36Sopenharmony_ci}
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_cistatic int ext4_check_opt_consistency(struct fs_context *fc,
276262306a36Sopenharmony_ci				      struct super_block *sb)
276362306a36Sopenharmony_ci{
276462306a36Sopenharmony_ci	struct ext4_fs_context *ctx = fc->fs_private;
276562306a36Sopenharmony_ci	struct ext4_sb_info *sbi = fc->s_fs_info;
276662306a36Sopenharmony_ci	int is_remount = fc->purpose == FS_CONTEXT_FOR_RECONFIGURE;
276762306a36Sopenharmony_ci	int err;
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_ci	if ((ctx->opt_flags & MOPT_NO_EXT2) && IS_EXT2_SB(sb)) {
277062306a36Sopenharmony_ci		ext4_msg(NULL, KERN_ERR,
277162306a36Sopenharmony_ci			 "Mount option(s) incompatible with ext2");
277262306a36Sopenharmony_ci		return -EINVAL;
277362306a36Sopenharmony_ci	}
277462306a36Sopenharmony_ci	if ((ctx->opt_flags & MOPT_NO_EXT3) && IS_EXT3_SB(sb)) {
277562306a36Sopenharmony_ci		ext4_msg(NULL, KERN_ERR,
277662306a36Sopenharmony_ci			 "Mount option(s) incompatible with ext3");
277762306a36Sopenharmony_ci		return -EINVAL;
277862306a36Sopenharmony_ci	}
277962306a36Sopenharmony_ci
278062306a36Sopenharmony_ci	if (ctx->s_want_extra_isize >
278162306a36Sopenharmony_ci	    (sbi->s_inode_size - EXT4_GOOD_OLD_INODE_SIZE)) {
278262306a36Sopenharmony_ci		ext4_msg(NULL, KERN_ERR,
278362306a36Sopenharmony_ci			 "Invalid want_extra_isize %d",
278462306a36Sopenharmony_ci			 ctx->s_want_extra_isize);
278562306a36Sopenharmony_ci		return -EINVAL;
278662306a36Sopenharmony_ci	}
278762306a36Sopenharmony_ci
278862306a36Sopenharmony_ci	if (ctx_test_mount_opt(ctx, EXT4_MOUNT_DIOREAD_NOLOCK)) {
278962306a36Sopenharmony_ci		int blocksize =
279062306a36Sopenharmony_ci			BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size);
279162306a36Sopenharmony_ci		if (blocksize < PAGE_SIZE)
279262306a36Sopenharmony_ci			ext4_msg(NULL, KERN_WARNING, "Warning: mounting with an "
279362306a36Sopenharmony_ci				 "experimental mount option 'dioread_nolock' "
279462306a36Sopenharmony_ci				 "for blocksize < PAGE_SIZE");
279562306a36Sopenharmony_ci	}
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci	err = ext4_check_test_dummy_encryption(fc, sb);
279862306a36Sopenharmony_ci	if (err)
279962306a36Sopenharmony_ci		return err;
280062306a36Sopenharmony_ci
280162306a36Sopenharmony_ci	if ((ctx->spec & EXT4_SPEC_DATAJ) && is_remount) {
280262306a36Sopenharmony_ci		if (!sbi->s_journal) {
280362306a36Sopenharmony_ci			ext4_msg(NULL, KERN_WARNING,
280462306a36Sopenharmony_ci				 "Remounting file system with no journal "
280562306a36Sopenharmony_ci				 "so ignoring journalled data option");
280662306a36Sopenharmony_ci			ctx_clear_mount_opt(ctx, EXT4_MOUNT_DATA_FLAGS);
280762306a36Sopenharmony_ci		} else if (ctx_test_mount_opt(ctx, EXT4_MOUNT_DATA_FLAGS) !=
280862306a36Sopenharmony_ci			   test_opt(sb, DATA_FLAGS)) {
280962306a36Sopenharmony_ci			ext4_msg(NULL, KERN_ERR, "Cannot change data mode "
281062306a36Sopenharmony_ci				 "on remount");
281162306a36Sopenharmony_ci			return -EINVAL;
281262306a36Sopenharmony_ci		}
281362306a36Sopenharmony_ci	}
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci	if (is_remount) {
281662306a36Sopenharmony_ci		if (ctx_test_mount_opt(ctx, EXT4_MOUNT_DAX_ALWAYS) &&
281762306a36Sopenharmony_ci		    (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)) {
281862306a36Sopenharmony_ci			ext4_msg(NULL, KERN_ERR, "can't mount with "
281962306a36Sopenharmony_ci				 "both data=journal and dax");
282062306a36Sopenharmony_ci			return -EINVAL;
282162306a36Sopenharmony_ci		}
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_ci		if (ctx_test_mount_opt(ctx, EXT4_MOUNT_DAX_ALWAYS) &&
282462306a36Sopenharmony_ci		    (!(sbi->s_mount_opt & EXT4_MOUNT_DAX_ALWAYS) ||
282562306a36Sopenharmony_ci		     (sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_NEVER))) {
282662306a36Sopenharmony_cifail_dax_change_remount:
282762306a36Sopenharmony_ci			ext4_msg(NULL, KERN_ERR, "can't change "
282862306a36Sopenharmony_ci				 "dax mount option while remounting");
282962306a36Sopenharmony_ci			return -EINVAL;
283062306a36Sopenharmony_ci		} else if (ctx_test_mount_opt2(ctx, EXT4_MOUNT2_DAX_NEVER) &&
283162306a36Sopenharmony_ci			 (!(sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_NEVER) ||
283262306a36Sopenharmony_ci			  (sbi->s_mount_opt & EXT4_MOUNT_DAX_ALWAYS))) {
283362306a36Sopenharmony_ci			goto fail_dax_change_remount;
283462306a36Sopenharmony_ci		} else if (ctx_test_mount_opt2(ctx, EXT4_MOUNT2_DAX_INODE) &&
283562306a36Sopenharmony_ci			   ((sbi->s_mount_opt & EXT4_MOUNT_DAX_ALWAYS) ||
283662306a36Sopenharmony_ci			    (sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_NEVER) ||
283762306a36Sopenharmony_ci			    !(sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_INODE))) {
283862306a36Sopenharmony_ci			goto fail_dax_change_remount;
283962306a36Sopenharmony_ci		}
284062306a36Sopenharmony_ci	}
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_ci	return ext4_check_quota_consistency(fc, sb);
284362306a36Sopenharmony_ci}
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_cistatic void ext4_apply_options(struct fs_context *fc, struct super_block *sb)
284662306a36Sopenharmony_ci{
284762306a36Sopenharmony_ci	struct ext4_fs_context *ctx = fc->fs_private;
284862306a36Sopenharmony_ci	struct ext4_sb_info *sbi = fc->s_fs_info;
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	sbi->s_mount_opt &= ~ctx->mask_s_mount_opt;
285162306a36Sopenharmony_ci	sbi->s_mount_opt |= ctx->vals_s_mount_opt;
285262306a36Sopenharmony_ci	sbi->s_mount_opt2 &= ~ctx->mask_s_mount_opt2;
285362306a36Sopenharmony_ci	sbi->s_mount_opt2 |= ctx->vals_s_mount_opt2;
285462306a36Sopenharmony_ci	sb->s_flags &= ~ctx->mask_s_flags;
285562306a36Sopenharmony_ci	sb->s_flags |= ctx->vals_s_flags;
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_ci#define APPLY(X) ({ if (ctx->spec & EXT4_SPEC_##X) sbi->X = ctx->X; })
285862306a36Sopenharmony_ci	APPLY(s_commit_interval);
285962306a36Sopenharmony_ci	APPLY(s_stripe);
286062306a36Sopenharmony_ci	APPLY(s_max_batch_time);
286162306a36Sopenharmony_ci	APPLY(s_min_batch_time);
286262306a36Sopenharmony_ci	APPLY(s_want_extra_isize);
286362306a36Sopenharmony_ci	APPLY(s_inode_readahead_blks);
286462306a36Sopenharmony_ci	APPLY(s_max_dir_size_kb);
286562306a36Sopenharmony_ci	APPLY(s_li_wait_mult);
286662306a36Sopenharmony_ci	APPLY(s_resgid);
286762306a36Sopenharmony_ci	APPLY(s_resuid);
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci#ifdef CONFIG_EXT4_DEBUG
287062306a36Sopenharmony_ci	APPLY(s_fc_debug_max_replay);
287162306a36Sopenharmony_ci#endif
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	ext4_apply_quota_options(fc, sb);
287462306a36Sopenharmony_ci	ext4_apply_test_dummy_encryption(ctx, sb);
287562306a36Sopenharmony_ci}
287662306a36Sopenharmony_ci
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_cistatic int ext4_validate_options(struct fs_context *fc)
287962306a36Sopenharmony_ci{
288062306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
288162306a36Sopenharmony_ci	struct ext4_fs_context *ctx = fc->fs_private;
288262306a36Sopenharmony_ci	char *usr_qf_name, *grp_qf_name;
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci	usr_qf_name = ctx->s_qf_names[USRQUOTA];
288562306a36Sopenharmony_ci	grp_qf_name = ctx->s_qf_names[GRPQUOTA];
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	if (usr_qf_name || grp_qf_name) {
288862306a36Sopenharmony_ci		if (ctx_test_mount_opt(ctx, EXT4_MOUNT_USRQUOTA) && usr_qf_name)
288962306a36Sopenharmony_ci			ctx_clear_mount_opt(ctx, EXT4_MOUNT_USRQUOTA);
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_ci		if (ctx_test_mount_opt(ctx, EXT4_MOUNT_GRPQUOTA) && grp_qf_name)
289262306a36Sopenharmony_ci			ctx_clear_mount_opt(ctx, EXT4_MOUNT_GRPQUOTA);
289362306a36Sopenharmony_ci
289462306a36Sopenharmony_ci		if (ctx_test_mount_opt(ctx, EXT4_MOUNT_USRQUOTA) ||
289562306a36Sopenharmony_ci		    ctx_test_mount_opt(ctx, EXT4_MOUNT_GRPQUOTA)) {
289662306a36Sopenharmony_ci			ext4_msg(NULL, KERN_ERR, "old and new quota "
289762306a36Sopenharmony_ci				 "format mixing");
289862306a36Sopenharmony_ci			return -EINVAL;
289962306a36Sopenharmony_ci		}
290062306a36Sopenharmony_ci	}
290162306a36Sopenharmony_ci#endif
290262306a36Sopenharmony_ci	return 1;
290362306a36Sopenharmony_ci}
290462306a36Sopenharmony_ci
290562306a36Sopenharmony_cistatic inline void ext4_show_quota_options(struct seq_file *seq,
290662306a36Sopenharmony_ci					   struct super_block *sb)
290762306a36Sopenharmony_ci{
290862306a36Sopenharmony_ci#if defined(CONFIG_QUOTA)
290962306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
291062306a36Sopenharmony_ci	char *usr_qf_name, *grp_qf_name;
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_ci	if (sbi->s_jquota_fmt) {
291362306a36Sopenharmony_ci		char *fmtname = "";
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci		switch (sbi->s_jquota_fmt) {
291662306a36Sopenharmony_ci		case QFMT_VFS_OLD:
291762306a36Sopenharmony_ci			fmtname = "vfsold";
291862306a36Sopenharmony_ci			break;
291962306a36Sopenharmony_ci		case QFMT_VFS_V0:
292062306a36Sopenharmony_ci			fmtname = "vfsv0";
292162306a36Sopenharmony_ci			break;
292262306a36Sopenharmony_ci		case QFMT_VFS_V1:
292362306a36Sopenharmony_ci			fmtname = "vfsv1";
292462306a36Sopenharmony_ci			break;
292562306a36Sopenharmony_ci		}
292662306a36Sopenharmony_ci		seq_printf(seq, ",jqfmt=%s", fmtname);
292762306a36Sopenharmony_ci	}
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci	rcu_read_lock();
293062306a36Sopenharmony_ci	usr_qf_name = rcu_dereference(sbi->s_qf_names[USRQUOTA]);
293162306a36Sopenharmony_ci	grp_qf_name = rcu_dereference(sbi->s_qf_names[GRPQUOTA]);
293262306a36Sopenharmony_ci	if (usr_qf_name)
293362306a36Sopenharmony_ci		seq_show_option(seq, "usrjquota", usr_qf_name);
293462306a36Sopenharmony_ci	if (grp_qf_name)
293562306a36Sopenharmony_ci		seq_show_option(seq, "grpjquota", grp_qf_name);
293662306a36Sopenharmony_ci	rcu_read_unlock();
293762306a36Sopenharmony_ci#endif
293862306a36Sopenharmony_ci}
293962306a36Sopenharmony_ci
294062306a36Sopenharmony_cistatic const char *token2str(int token)
294162306a36Sopenharmony_ci{
294262306a36Sopenharmony_ci	const struct fs_parameter_spec *spec;
294362306a36Sopenharmony_ci
294462306a36Sopenharmony_ci	for (spec = ext4_param_specs; spec->name != NULL; spec++)
294562306a36Sopenharmony_ci		if (spec->opt == token && !spec->type)
294662306a36Sopenharmony_ci			break;
294762306a36Sopenharmony_ci	return spec->name;
294862306a36Sopenharmony_ci}
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_ci/*
295162306a36Sopenharmony_ci * Show an option if
295262306a36Sopenharmony_ci *  - it's set to a non-default value OR
295362306a36Sopenharmony_ci *  - if the per-sb default is different from the global default
295462306a36Sopenharmony_ci */
295562306a36Sopenharmony_cistatic int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
295662306a36Sopenharmony_ci			      int nodefs)
295762306a36Sopenharmony_ci{
295862306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
295962306a36Sopenharmony_ci	struct ext4_super_block *es = sbi->s_es;
296062306a36Sopenharmony_ci	int def_errors;
296162306a36Sopenharmony_ci	const struct mount_opts *m;
296262306a36Sopenharmony_ci	char sep = nodefs ? '\n' : ',';
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci#define SEQ_OPTS_PUTS(str) seq_printf(seq, "%c" str, sep)
296562306a36Sopenharmony_ci#define SEQ_OPTS_PRINT(str, arg) seq_printf(seq, "%c" str, sep, arg)
296662306a36Sopenharmony_ci
296762306a36Sopenharmony_ci	if (sbi->s_sb_block != 1)
296862306a36Sopenharmony_ci		SEQ_OPTS_PRINT("sb=%llu", sbi->s_sb_block);
296962306a36Sopenharmony_ci
297062306a36Sopenharmony_ci	for (m = ext4_mount_opts; m->token != Opt_err; m++) {
297162306a36Sopenharmony_ci		int want_set = m->flags & MOPT_SET;
297262306a36Sopenharmony_ci		int opt_2 = m->flags & MOPT_2;
297362306a36Sopenharmony_ci		unsigned int mount_opt, def_mount_opt;
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_ci		if (((m->flags & (MOPT_SET|MOPT_CLEAR)) == 0) ||
297662306a36Sopenharmony_ci		    m->flags & MOPT_SKIP)
297762306a36Sopenharmony_ci			continue;
297862306a36Sopenharmony_ci
297962306a36Sopenharmony_ci		if (opt_2) {
298062306a36Sopenharmony_ci			mount_opt = sbi->s_mount_opt2;
298162306a36Sopenharmony_ci			def_mount_opt = sbi->s_def_mount_opt2;
298262306a36Sopenharmony_ci		} else {
298362306a36Sopenharmony_ci			mount_opt = sbi->s_mount_opt;
298462306a36Sopenharmony_ci			def_mount_opt = sbi->s_def_mount_opt;
298562306a36Sopenharmony_ci		}
298662306a36Sopenharmony_ci		/* skip if same as the default */
298762306a36Sopenharmony_ci		if (!nodefs && !(m->mount_opt & (mount_opt ^ def_mount_opt)))
298862306a36Sopenharmony_ci			continue;
298962306a36Sopenharmony_ci		/* select Opt_noFoo vs Opt_Foo */
299062306a36Sopenharmony_ci		if ((want_set &&
299162306a36Sopenharmony_ci		     (mount_opt & m->mount_opt) != m->mount_opt) ||
299262306a36Sopenharmony_ci		    (!want_set && (mount_opt & m->mount_opt)))
299362306a36Sopenharmony_ci			continue;
299462306a36Sopenharmony_ci		SEQ_OPTS_PRINT("%s", token2str(m->token));
299562306a36Sopenharmony_ci	}
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci	if (nodefs || !uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT4_DEF_RESUID)) ||
299862306a36Sopenharmony_ci	    le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID)
299962306a36Sopenharmony_ci		SEQ_OPTS_PRINT("resuid=%u",
300062306a36Sopenharmony_ci				from_kuid_munged(&init_user_ns, sbi->s_resuid));
300162306a36Sopenharmony_ci	if (nodefs || !gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT4_DEF_RESGID)) ||
300262306a36Sopenharmony_ci	    le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID)
300362306a36Sopenharmony_ci		SEQ_OPTS_PRINT("resgid=%u",
300462306a36Sopenharmony_ci				from_kgid_munged(&init_user_ns, sbi->s_resgid));
300562306a36Sopenharmony_ci	def_errors = nodefs ? -1 : le16_to_cpu(es->s_errors);
300662306a36Sopenharmony_ci	if (test_opt(sb, ERRORS_RO) && def_errors != EXT4_ERRORS_RO)
300762306a36Sopenharmony_ci		SEQ_OPTS_PUTS("errors=remount-ro");
300862306a36Sopenharmony_ci	if (test_opt(sb, ERRORS_CONT) && def_errors != EXT4_ERRORS_CONTINUE)
300962306a36Sopenharmony_ci		SEQ_OPTS_PUTS("errors=continue");
301062306a36Sopenharmony_ci	if (test_opt(sb, ERRORS_PANIC) && def_errors != EXT4_ERRORS_PANIC)
301162306a36Sopenharmony_ci		SEQ_OPTS_PUTS("errors=panic");
301262306a36Sopenharmony_ci	if (nodefs || sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ)
301362306a36Sopenharmony_ci		SEQ_OPTS_PRINT("commit=%lu", sbi->s_commit_interval / HZ);
301462306a36Sopenharmony_ci	if (nodefs || sbi->s_min_batch_time != EXT4_DEF_MIN_BATCH_TIME)
301562306a36Sopenharmony_ci		SEQ_OPTS_PRINT("min_batch_time=%u", sbi->s_min_batch_time);
301662306a36Sopenharmony_ci	if (nodefs || sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME)
301762306a36Sopenharmony_ci		SEQ_OPTS_PRINT("max_batch_time=%u", sbi->s_max_batch_time);
301862306a36Sopenharmony_ci	if (nodefs || sbi->s_stripe)
301962306a36Sopenharmony_ci		SEQ_OPTS_PRINT("stripe=%lu", sbi->s_stripe);
302062306a36Sopenharmony_ci	if (nodefs || EXT4_MOUNT_DATA_FLAGS &
302162306a36Sopenharmony_ci			(sbi->s_mount_opt ^ sbi->s_def_mount_opt)) {
302262306a36Sopenharmony_ci		if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
302362306a36Sopenharmony_ci			SEQ_OPTS_PUTS("data=journal");
302462306a36Sopenharmony_ci		else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
302562306a36Sopenharmony_ci			SEQ_OPTS_PUTS("data=ordered");
302662306a36Sopenharmony_ci		else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
302762306a36Sopenharmony_ci			SEQ_OPTS_PUTS("data=writeback");
302862306a36Sopenharmony_ci	}
302962306a36Sopenharmony_ci	if (nodefs ||
303062306a36Sopenharmony_ci	    sbi->s_inode_readahead_blks != EXT4_DEF_INODE_READAHEAD_BLKS)
303162306a36Sopenharmony_ci		SEQ_OPTS_PRINT("inode_readahead_blks=%u",
303262306a36Sopenharmony_ci			       sbi->s_inode_readahead_blks);
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_ci	if (test_opt(sb, INIT_INODE_TABLE) && (nodefs ||
303562306a36Sopenharmony_ci		       (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT)))
303662306a36Sopenharmony_ci		SEQ_OPTS_PRINT("init_itable=%u", sbi->s_li_wait_mult);
303762306a36Sopenharmony_ci	if (nodefs || sbi->s_max_dir_size_kb)
303862306a36Sopenharmony_ci		SEQ_OPTS_PRINT("max_dir_size_kb=%u", sbi->s_max_dir_size_kb);
303962306a36Sopenharmony_ci	if (test_opt(sb, DATA_ERR_ABORT))
304062306a36Sopenharmony_ci		SEQ_OPTS_PUTS("data_err=abort");
304162306a36Sopenharmony_ci
304262306a36Sopenharmony_ci	fscrypt_show_test_dummy_encryption(seq, sep, sb);
304362306a36Sopenharmony_ci
304462306a36Sopenharmony_ci	if (sb->s_flags & SB_INLINECRYPT)
304562306a36Sopenharmony_ci		SEQ_OPTS_PUTS("inlinecrypt");
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ci	if (test_opt(sb, DAX_ALWAYS)) {
304862306a36Sopenharmony_ci		if (IS_EXT2_SB(sb))
304962306a36Sopenharmony_ci			SEQ_OPTS_PUTS("dax");
305062306a36Sopenharmony_ci		else
305162306a36Sopenharmony_ci			SEQ_OPTS_PUTS("dax=always");
305262306a36Sopenharmony_ci	} else if (test_opt2(sb, DAX_NEVER)) {
305362306a36Sopenharmony_ci		SEQ_OPTS_PUTS("dax=never");
305462306a36Sopenharmony_ci	} else if (test_opt2(sb, DAX_INODE)) {
305562306a36Sopenharmony_ci		SEQ_OPTS_PUTS("dax=inode");
305662306a36Sopenharmony_ci	}
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci	if (sbi->s_groups_count >= MB_DEFAULT_LINEAR_SCAN_THRESHOLD &&
305962306a36Sopenharmony_ci			!test_opt2(sb, MB_OPTIMIZE_SCAN)) {
306062306a36Sopenharmony_ci		SEQ_OPTS_PUTS("mb_optimize_scan=0");
306162306a36Sopenharmony_ci	} else if (sbi->s_groups_count < MB_DEFAULT_LINEAR_SCAN_THRESHOLD &&
306262306a36Sopenharmony_ci			test_opt2(sb, MB_OPTIMIZE_SCAN)) {
306362306a36Sopenharmony_ci		SEQ_OPTS_PUTS("mb_optimize_scan=1");
306462306a36Sopenharmony_ci	}
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci	ext4_show_quota_options(seq, sb);
306762306a36Sopenharmony_ci	return 0;
306862306a36Sopenharmony_ci}
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_cistatic int ext4_show_options(struct seq_file *seq, struct dentry *root)
307162306a36Sopenharmony_ci{
307262306a36Sopenharmony_ci	return _ext4_show_options(seq, root->d_sb, 0);
307362306a36Sopenharmony_ci}
307462306a36Sopenharmony_ci
307562306a36Sopenharmony_ciint ext4_seq_options_show(struct seq_file *seq, void *offset)
307662306a36Sopenharmony_ci{
307762306a36Sopenharmony_ci	struct super_block *sb = seq->private;
307862306a36Sopenharmony_ci	int rc;
307962306a36Sopenharmony_ci
308062306a36Sopenharmony_ci	seq_puts(seq, sb_rdonly(sb) ? "ro" : "rw");
308162306a36Sopenharmony_ci	rc = _ext4_show_options(seq, sb, 1);
308262306a36Sopenharmony_ci	seq_puts(seq, "\n");
308362306a36Sopenharmony_ci	return rc;
308462306a36Sopenharmony_ci}
308562306a36Sopenharmony_ci
308662306a36Sopenharmony_cistatic int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
308762306a36Sopenharmony_ci			    int read_only)
308862306a36Sopenharmony_ci{
308962306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
309062306a36Sopenharmony_ci	int err = 0;
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_ci	if (le32_to_cpu(es->s_rev_level) > EXT4_MAX_SUPP_REV) {
309362306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "revision level too high, "
309462306a36Sopenharmony_ci			 "forcing read-only mode");
309562306a36Sopenharmony_ci		err = -EROFS;
309662306a36Sopenharmony_ci		goto done;
309762306a36Sopenharmony_ci	}
309862306a36Sopenharmony_ci	if (read_only)
309962306a36Sopenharmony_ci		goto done;
310062306a36Sopenharmony_ci	if (!(sbi->s_mount_state & EXT4_VALID_FS))
310162306a36Sopenharmony_ci		ext4_msg(sb, KERN_WARNING, "warning: mounting unchecked fs, "
310262306a36Sopenharmony_ci			 "running e2fsck is recommended");
310362306a36Sopenharmony_ci	else if (sbi->s_mount_state & EXT4_ERROR_FS)
310462306a36Sopenharmony_ci		ext4_msg(sb, KERN_WARNING,
310562306a36Sopenharmony_ci			 "warning: mounting fs with errors, "
310662306a36Sopenharmony_ci			 "running e2fsck is recommended");
310762306a36Sopenharmony_ci	else if ((__s16) le16_to_cpu(es->s_max_mnt_count) > 0 &&
310862306a36Sopenharmony_ci		 le16_to_cpu(es->s_mnt_count) >=
310962306a36Sopenharmony_ci		 (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count))
311062306a36Sopenharmony_ci		ext4_msg(sb, KERN_WARNING,
311162306a36Sopenharmony_ci			 "warning: maximal mount count reached, "
311262306a36Sopenharmony_ci			 "running e2fsck is recommended");
311362306a36Sopenharmony_ci	else if (le32_to_cpu(es->s_checkinterval) &&
311462306a36Sopenharmony_ci		 (ext4_get_tstamp(es, s_lastcheck) +
311562306a36Sopenharmony_ci		  le32_to_cpu(es->s_checkinterval) <= ktime_get_real_seconds()))
311662306a36Sopenharmony_ci		ext4_msg(sb, KERN_WARNING,
311762306a36Sopenharmony_ci			 "warning: checktime reached, "
311862306a36Sopenharmony_ci			 "running e2fsck is recommended");
311962306a36Sopenharmony_ci	if (!sbi->s_journal)
312062306a36Sopenharmony_ci		es->s_state &= cpu_to_le16(~EXT4_VALID_FS);
312162306a36Sopenharmony_ci	if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
312262306a36Sopenharmony_ci		es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT);
312362306a36Sopenharmony_ci	le16_add_cpu(&es->s_mnt_count, 1);
312462306a36Sopenharmony_ci	ext4_update_tstamp(es, s_mtime);
312562306a36Sopenharmony_ci	if (sbi->s_journal) {
312662306a36Sopenharmony_ci		ext4_set_feature_journal_needs_recovery(sb);
312762306a36Sopenharmony_ci		if (ext4_has_feature_orphan_file(sb))
312862306a36Sopenharmony_ci			ext4_set_feature_orphan_present(sb);
312962306a36Sopenharmony_ci	}
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	err = ext4_commit_super(sb);
313262306a36Sopenharmony_cidone:
313362306a36Sopenharmony_ci	if (test_opt(sb, DEBUG))
313462306a36Sopenharmony_ci		printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%u, "
313562306a36Sopenharmony_ci				"bpg=%lu, ipg=%lu, mo=%04x, mo2=%04x]\n",
313662306a36Sopenharmony_ci			sb->s_blocksize,
313762306a36Sopenharmony_ci			sbi->s_groups_count,
313862306a36Sopenharmony_ci			EXT4_BLOCKS_PER_GROUP(sb),
313962306a36Sopenharmony_ci			EXT4_INODES_PER_GROUP(sb),
314062306a36Sopenharmony_ci			sbi->s_mount_opt, sbi->s_mount_opt2);
314162306a36Sopenharmony_ci	return err;
314262306a36Sopenharmony_ci}
314362306a36Sopenharmony_ci
314462306a36Sopenharmony_ciint ext4_alloc_flex_bg_array(struct super_block *sb, ext4_group_t ngroup)
314562306a36Sopenharmony_ci{
314662306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
314762306a36Sopenharmony_ci	struct flex_groups **old_groups, **new_groups;
314862306a36Sopenharmony_ci	int size, i, j;
314962306a36Sopenharmony_ci
315062306a36Sopenharmony_ci	if (!sbi->s_log_groups_per_flex)
315162306a36Sopenharmony_ci		return 0;
315262306a36Sopenharmony_ci
315362306a36Sopenharmony_ci	size = ext4_flex_group(sbi, ngroup - 1) + 1;
315462306a36Sopenharmony_ci	if (size <= sbi->s_flex_groups_allocated)
315562306a36Sopenharmony_ci		return 0;
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ci	new_groups = kvzalloc(roundup_pow_of_two(size *
315862306a36Sopenharmony_ci			      sizeof(*sbi->s_flex_groups)), GFP_KERNEL);
315962306a36Sopenharmony_ci	if (!new_groups) {
316062306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR,
316162306a36Sopenharmony_ci			 "not enough memory for %d flex group pointers", size);
316262306a36Sopenharmony_ci		return -ENOMEM;
316362306a36Sopenharmony_ci	}
316462306a36Sopenharmony_ci	for (i = sbi->s_flex_groups_allocated; i < size; i++) {
316562306a36Sopenharmony_ci		new_groups[i] = kvzalloc(roundup_pow_of_two(
316662306a36Sopenharmony_ci					 sizeof(struct flex_groups)),
316762306a36Sopenharmony_ci					 GFP_KERNEL);
316862306a36Sopenharmony_ci		if (!new_groups[i]) {
316962306a36Sopenharmony_ci			for (j = sbi->s_flex_groups_allocated; j < i; j++)
317062306a36Sopenharmony_ci				kvfree(new_groups[j]);
317162306a36Sopenharmony_ci			kvfree(new_groups);
317262306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR,
317362306a36Sopenharmony_ci				 "not enough memory for %d flex groups", size);
317462306a36Sopenharmony_ci			return -ENOMEM;
317562306a36Sopenharmony_ci		}
317662306a36Sopenharmony_ci	}
317762306a36Sopenharmony_ci	rcu_read_lock();
317862306a36Sopenharmony_ci	old_groups = rcu_dereference(sbi->s_flex_groups);
317962306a36Sopenharmony_ci	if (old_groups)
318062306a36Sopenharmony_ci		memcpy(new_groups, old_groups,
318162306a36Sopenharmony_ci		       (sbi->s_flex_groups_allocated *
318262306a36Sopenharmony_ci			sizeof(struct flex_groups *)));
318362306a36Sopenharmony_ci	rcu_read_unlock();
318462306a36Sopenharmony_ci	rcu_assign_pointer(sbi->s_flex_groups, new_groups);
318562306a36Sopenharmony_ci	sbi->s_flex_groups_allocated = size;
318662306a36Sopenharmony_ci	if (old_groups)
318762306a36Sopenharmony_ci		ext4_kvfree_array_rcu(old_groups);
318862306a36Sopenharmony_ci	return 0;
318962306a36Sopenharmony_ci}
319062306a36Sopenharmony_ci
319162306a36Sopenharmony_cistatic int ext4_fill_flex_info(struct super_block *sb)
319262306a36Sopenharmony_ci{
319362306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
319462306a36Sopenharmony_ci	struct ext4_group_desc *gdp = NULL;
319562306a36Sopenharmony_ci	struct flex_groups *fg;
319662306a36Sopenharmony_ci	ext4_group_t flex_group;
319762306a36Sopenharmony_ci	int i, err;
319862306a36Sopenharmony_ci
319962306a36Sopenharmony_ci	sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex;
320062306a36Sopenharmony_ci	if (sbi->s_log_groups_per_flex < 1 || sbi->s_log_groups_per_flex > 31) {
320162306a36Sopenharmony_ci		sbi->s_log_groups_per_flex = 0;
320262306a36Sopenharmony_ci		return 1;
320362306a36Sopenharmony_ci	}
320462306a36Sopenharmony_ci
320562306a36Sopenharmony_ci	err = ext4_alloc_flex_bg_array(sb, sbi->s_groups_count);
320662306a36Sopenharmony_ci	if (err)
320762306a36Sopenharmony_ci		goto failed;
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ci	for (i = 0; i < sbi->s_groups_count; i++) {
321062306a36Sopenharmony_ci		gdp = ext4_get_group_desc(sb, i, NULL);
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_ci		flex_group = ext4_flex_group(sbi, i);
321362306a36Sopenharmony_ci		fg = sbi_array_rcu_deref(sbi, s_flex_groups, flex_group);
321462306a36Sopenharmony_ci		atomic_add(ext4_free_inodes_count(sb, gdp), &fg->free_inodes);
321562306a36Sopenharmony_ci		atomic64_add(ext4_free_group_clusters(sb, gdp),
321662306a36Sopenharmony_ci			     &fg->free_clusters);
321762306a36Sopenharmony_ci		atomic_add(ext4_used_dirs_count(sb, gdp), &fg->used_dirs);
321862306a36Sopenharmony_ci	}
321962306a36Sopenharmony_ci
322062306a36Sopenharmony_ci	return 1;
322162306a36Sopenharmony_cifailed:
322262306a36Sopenharmony_ci	return 0;
322362306a36Sopenharmony_ci}
322462306a36Sopenharmony_ci
322562306a36Sopenharmony_cistatic __le16 ext4_group_desc_csum(struct super_block *sb, __u32 block_group,
322662306a36Sopenharmony_ci				   struct ext4_group_desc *gdp)
322762306a36Sopenharmony_ci{
322862306a36Sopenharmony_ci	int offset = offsetof(struct ext4_group_desc, bg_checksum);
322962306a36Sopenharmony_ci	__u16 crc = 0;
323062306a36Sopenharmony_ci	__le32 le_group = cpu_to_le32(block_group);
323162306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
323262306a36Sopenharmony_ci
323362306a36Sopenharmony_ci	if (ext4_has_metadata_csum(sbi->s_sb)) {
323462306a36Sopenharmony_ci		/* Use new metadata_csum algorithm */
323562306a36Sopenharmony_ci		__u32 csum32;
323662306a36Sopenharmony_ci		__u16 dummy_csum = 0;
323762306a36Sopenharmony_ci
323862306a36Sopenharmony_ci		csum32 = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&le_group,
323962306a36Sopenharmony_ci				     sizeof(le_group));
324062306a36Sopenharmony_ci		csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp, offset);
324162306a36Sopenharmony_ci		csum32 = ext4_chksum(sbi, csum32, (__u8 *)&dummy_csum,
324262306a36Sopenharmony_ci				     sizeof(dummy_csum));
324362306a36Sopenharmony_ci		offset += sizeof(dummy_csum);
324462306a36Sopenharmony_ci		if (offset < sbi->s_desc_size)
324562306a36Sopenharmony_ci			csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp + offset,
324662306a36Sopenharmony_ci					     sbi->s_desc_size - offset);
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_ci		crc = csum32 & 0xFFFF;
324962306a36Sopenharmony_ci		goto out;
325062306a36Sopenharmony_ci	}
325162306a36Sopenharmony_ci
325262306a36Sopenharmony_ci	/* old crc16 code */
325362306a36Sopenharmony_ci	if (!ext4_has_feature_gdt_csum(sb))
325462306a36Sopenharmony_ci		return 0;
325562306a36Sopenharmony_ci
325662306a36Sopenharmony_ci	crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
325762306a36Sopenharmony_ci	crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
325862306a36Sopenharmony_ci	crc = crc16(crc, (__u8 *)gdp, offset);
325962306a36Sopenharmony_ci	offset += sizeof(gdp->bg_checksum); /* skip checksum */
326062306a36Sopenharmony_ci	/* for checksum of struct ext4_group_desc do the rest...*/
326162306a36Sopenharmony_ci	if (ext4_has_feature_64bit(sb) && offset < sbi->s_desc_size)
326262306a36Sopenharmony_ci		crc = crc16(crc, (__u8 *)gdp + offset,
326362306a36Sopenharmony_ci			    sbi->s_desc_size - offset);
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_ciout:
326662306a36Sopenharmony_ci	return cpu_to_le16(crc);
326762306a36Sopenharmony_ci}
326862306a36Sopenharmony_ci
326962306a36Sopenharmony_ciint ext4_group_desc_csum_verify(struct super_block *sb, __u32 block_group,
327062306a36Sopenharmony_ci				struct ext4_group_desc *gdp)
327162306a36Sopenharmony_ci{
327262306a36Sopenharmony_ci	if (ext4_has_group_desc_csum(sb) &&
327362306a36Sopenharmony_ci	    (gdp->bg_checksum != ext4_group_desc_csum(sb, block_group, gdp)))
327462306a36Sopenharmony_ci		return 0;
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci	return 1;
327762306a36Sopenharmony_ci}
327862306a36Sopenharmony_ci
327962306a36Sopenharmony_civoid ext4_group_desc_csum_set(struct super_block *sb, __u32 block_group,
328062306a36Sopenharmony_ci			      struct ext4_group_desc *gdp)
328162306a36Sopenharmony_ci{
328262306a36Sopenharmony_ci	if (!ext4_has_group_desc_csum(sb))
328362306a36Sopenharmony_ci		return;
328462306a36Sopenharmony_ci	gdp->bg_checksum = ext4_group_desc_csum(sb, block_group, gdp);
328562306a36Sopenharmony_ci}
328662306a36Sopenharmony_ci
328762306a36Sopenharmony_ci/* Called at mount-time, super-block is locked */
328862306a36Sopenharmony_cistatic int ext4_check_descriptors(struct super_block *sb,
328962306a36Sopenharmony_ci				  ext4_fsblk_t sb_block,
329062306a36Sopenharmony_ci				  ext4_group_t *first_not_zeroed)
329162306a36Sopenharmony_ci{
329262306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
329362306a36Sopenharmony_ci	ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
329462306a36Sopenharmony_ci	ext4_fsblk_t last_block;
329562306a36Sopenharmony_ci	ext4_fsblk_t last_bg_block = sb_block + ext4_bg_num_gdb(sb, 0);
329662306a36Sopenharmony_ci	ext4_fsblk_t block_bitmap;
329762306a36Sopenharmony_ci	ext4_fsblk_t inode_bitmap;
329862306a36Sopenharmony_ci	ext4_fsblk_t inode_table;
329962306a36Sopenharmony_ci	int flexbg_flag = 0;
330062306a36Sopenharmony_ci	ext4_group_t i, grp = sbi->s_groups_count;
330162306a36Sopenharmony_ci
330262306a36Sopenharmony_ci	if (ext4_has_feature_flex_bg(sb))
330362306a36Sopenharmony_ci		flexbg_flag = 1;
330462306a36Sopenharmony_ci
330562306a36Sopenharmony_ci	ext4_debug("Checking group descriptors");
330662306a36Sopenharmony_ci
330762306a36Sopenharmony_ci	for (i = 0; i < sbi->s_groups_count; i++) {
330862306a36Sopenharmony_ci		struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL);
330962306a36Sopenharmony_ci
331062306a36Sopenharmony_ci		if (i == sbi->s_groups_count - 1 || flexbg_flag)
331162306a36Sopenharmony_ci			last_block = ext4_blocks_count(sbi->s_es) - 1;
331262306a36Sopenharmony_ci		else
331362306a36Sopenharmony_ci			last_block = first_block +
331462306a36Sopenharmony_ci				(EXT4_BLOCKS_PER_GROUP(sb) - 1);
331562306a36Sopenharmony_ci
331662306a36Sopenharmony_ci		if ((grp == sbi->s_groups_count) &&
331762306a36Sopenharmony_ci		   !(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)))
331862306a36Sopenharmony_ci			grp = i;
331962306a36Sopenharmony_ci
332062306a36Sopenharmony_ci		block_bitmap = ext4_block_bitmap(sb, gdp);
332162306a36Sopenharmony_ci		if (block_bitmap == sb_block) {
332262306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
332362306a36Sopenharmony_ci				 "Block bitmap for group %u overlaps "
332462306a36Sopenharmony_ci				 "superblock", i);
332562306a36Sopenharmony_ci			if (!sb_rdonly(sb))
332662306a36Sopenharmony_ci				return 0;
332762306a36Sopenharmony_ci		}
332862306a36Sopenharmony_ci		if (block_bitmap >= sb_block + 1 &&
332962306a36Sopenharmony_ci		    block_bitmap <= last_bg_block) {
333062306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
333162306a36Sopenharmony_ci				 "Block bitmap for group %u overlaps "
333262306a36Sopenharmony_ci				 "block group descriptors", i);
333362306a36Sopenharmony_ci			if (!sb_rdonly(sb))
333462306a36Sopenharmony_ci				return 0;
333562306a36Sopenharmony_ci		}
333662306a36Sopenharmony_ci		if (block_bitmap < first_block || block_bitmap > last_block) {
333762306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
333862306a36Sopenharmony_ci			       "Block bitmap for group %u not in group "
333962306a36Sopenharmony_ci			       "(block %llu)!", i, block_bitmap);
334062306a36Sopenharmony_ci			return 0;
334162306a36Sopenharmony_ci		}
334262306a36Sopenharmony_ci		inode_bitmap = ext4_inode_bitmap(sb, gdp);
334362306a36Sopenharmony_ci		if (inode_bitmap == sb_block) {
334462306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
334562306a36Sopenharmony_ci				 "Inode bitmap for group %u overlaps "
334662306a36Sopenharmony_ci				 "superblock", i);
334762306a36Sopenharmony_ci			if (!sb_rdonly(sb))
334862306a36Sopenharmony_ci				return 0;
334962306a36Sopenharmony_ci		}
335062306a36Sopenharmony_ci		if (inode_bitmap >= sb_block + 1 &&
335162306a36Sopenharmony_ci		    inode_bitmap <= last_bg_block) {
335262306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
335362306a36Sopenharmony_ci				 "Inode bitmap for group %u overlaps "
335462306a36Sopenharmony_ci				 "block group descriptors", i);
335562306a36Sopenharmony_ci			if (!sb_rdonly(sb))
335662306a36Sopenharmony_ci				return 0;
335762306a36Sopenharmony_ci		}
335862306a36Sopenharmony_ci		if (inode_bitmap < first_block || inode_bitmap > last_block) {
335962306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
336062306a36Sopenharmony_ci			       "Inode bitmap for group %u not in group "
336162306a36Sopenharmony_ci			       "(block %llu)!", i, inode_bitmap);
336262306a36Sopenharmony_ci			return 0;
336362306a36Sopenharmony_ci		}
336462306a36Sopenharmony_ci		inode_table = ext4_inode_table(sb, gdp);
336562306a36Sopenharmony_ci		if (inode_table == sb_block) {
336662306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
336762306a36Sopenharmony_ci				 "Inode table for group %u overlaps "
336862306a36Sopenharmony_ci				 "superblock", i);
336962306a36Sopenharmony_ci			if (!sb_rdonly(sb))
337062306a36Sopenharmony_ci				return 0;
337162306a36Sopenharmony_ci		}
337262306a36Sopenharmony_ci		if (inode_table >= sb_block + 1 &&
337362306a36Sopenharmony_ci		    inode_table <= last_bg_block) {
337462306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
337562306a36Sopenharmony_ci				 "Inode table for group %u overlaps "
337662306a36Sopenharmony_ci				 "block group descriptors", i);
337762306a36Sopenharmony_ci			if (!sb_rdonly(sb))
337862306a36Sopenharmony_ci				return 0;
337962306a36Sopenharmony_ci		}
338062306a36Sopenharmony_ci		if (inode_table < first_block ||
338162306a36Sopenharmony_ci		    inode_table + sbi->s_itb_per_group - 1 > last_block) {
338262306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
338362306a36Sopenharmony_ci			       "Inode table for group %u not in group "
338462306a36Sopenharmony_ci			       "(block %llu)!", i, inode_table);
338562306a36Sopenharmony_ci			return 0;
338662306a36Sopenharmony_ci		}
338762306a36Sopenharmony_ci		ext4_lock_group(sb, i);
338862306a36Sopenharmony_ci		if (!ext4_group_desc_csum_verify(sb, i, gdp)) {
338962306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
339062306a36Sopenharmony_ci				 "Checksum for group %u failed (%u!=%u)",
339162306a36Sopenharmony_ci				 i, le16_to_cpu(ext4_group_desc_csum(sb, i,
339262306a36Sopenharmony_ci				     gdp)), le16_to_cpu(gdp->bg_checksum));
339362306a36Sopenharmony_ci			if (!sb_rdonly(sb)) {
339462306a36Sopenharmony_ci				ext4_unlock_group(sb, i);
339562306a36Sopenharmony_ci				return 0;
339662306a36Sopenharmony_ci			}
339762306a36Sopenharmony_ci		}
339862306a36Sopenharmony_ci		ext4_unlock_group(sb, i);
339962306a36Sopenharmony_ci		if (!flexbg_flag)
340062306a36Sopenharmony_ci			first_block += EXT4_BLOCKS_PER_GROUP(sb);
340162306a36Sopenharmony_ci	}
340262306a36Sopenharmony_ci	if (NULL != first_not_zeroed)
340362306a36Sopenharmony_ci		*first_not_zeroed = grp;
340462306a36Sopenharmony_ci	return 1;
340562306a36Sopenharmony_ci}
340662306a36Sopenharmony_ci
340762306a36Sopenharmony_ci/*
340862306a36Sopenharmony_ci * Maximal extent format file size.
340962306a36Sopenharmony_ci * Resulting logical blkno at s_maxbytes must fit in our on-disk
341062306a36Sopenharmony_ci * extent format containers, within a sector_t, and within i_blocks
341162306a36Sopenharmony_ci * in the vfs.  ext4 inode has 48 bits of i_block in fsblock units,
341262306a36Sopenharmony_ci * so that won't be a limiting factor.
341362306a36Sopenharmony_ci *
341462306a36Sopenharmony_ci * However there is other limiting factor. We do store extents in the form
341562306a36Sopenharmony_ci * of starting block and length, hence the resulting length of the extent
341662306a36Sopenharmony_ci * covering maximum file size must fit into on-disk format containers as
341762306a36Sopenharmony_ci * well. Given that length is always by 1 unit bigger than max unit (because
341862306a36Sopenharmony_ci * we count 0 as well) we have to lower the s_maxbytes by one fs block.
341962306a36Sopenharmony_ci *
342062306a36Sopenharmony_ci * Note, this does *not* consider any metadata overhead for vfs i_blocks.
342162306a36Sopenharmony_ci */
342262306a36Sopenharmony_cistatic loff_t ext4_max_size(int blkbits, int has_huge_files)
342362306a36Sopenharmony_ci{
342462306a36Sopenharmony_ci	loff_t res;
342562306a36Sopenharmony_ci	loff_t upper_limit = MAX_LFS_FILESIZE;
342662306a36Sopenharmony_ci
342762306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(blkcnt_t) < sizeof(u64));
342862306a36Sopenharmony_ci
342962306a36Sopenharmony_ci	if (!has_huge_files) {
343062306a36Sopenharmony_ci		upper_limit = (1LL << 32) - 1;
343162306a36Sopenharmony_ci
343262306a36Sopenharmony_ci		/* total blocks in file system block size */
343362306a36Sopenharmony_ci		upper_limit >>= (blkbits - 9);
343462306a36Sopenharmony_ci		upper_limit <<= blkbits;
343562306a36Sopenharmony_ci	}
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci	/*
343862306a36Sopenharmony_ci	 * 32-bit extent-start container, ee_block. We lower the maxbytes
343962306a36Sopenharmony_ci	 * by one fs block, so ee_len can cover the extent of maximum file
344062306a36Sopenharmony_ci	 * size
344162306a36Sopenharmony_ci	 */
344262306a36Sopenharmony_ci	res = (1LL << 32) - 1;
344362306a36Sopenharmony_ci	res <<= blkbits;
344462306a36Sopenharmony_ci
344562306a36Sopenharmony_ci	/* Sanity check against vm- & vfs- imposed limits */
344662306a36Sopenharmony_ci	if (res > upper_limit)
344762306a36Sopenharmony_ci		res = upper_limit;
344862306a36Sopenharmony_ci
344962306a36Sopenharmony_ci	return res;
345062306a36Sopenharmony_ci}
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_ci/*
345362306a36Sopenharmony_ci * Maximal bitmap file size.  There is a direct, and {,double-,triple-}indirect
345462306a36Sopenharmony_ci * block limit, and also a limit of (2^48 - 1) 512-byte sectors in i_blocks.
345562306a36Sopenharmony_ci * We need to be 1 filesystem block less than the 2^48 sector limit.
345662306a36Sopenharmony_ci */
345762306a36Sopenharmony_cistatic loff_t ext4_max_bitmap_size(int bits, int has_huge_files)
345862306a36Sopenharmony_ci{
345962306a36Sopenharmony_ci	loff_t upper_limit, res = EXT4_NDIR_BLOCKS;
346062306a36Sopenharmony_ci	int meta_blocks;
346162306a36Sopenharmony_ci	unsigned int ppb = 1 << (bits - 2);
346262306a36Sopenharmony_ci
346362306a36Sopenharmony_ci	/*
346462306a36Sopenharmony_ci	 * This is calculated to be the largest file size for a dense, block
346562306a36Sopenharmony_ci	 * mapped file such that the file's total number of 512-byte sectors,
346662306a36Sopenharmony_ci	 * including data and all indirect blocks, does not exceed (2^48 - 1).
346762306a36Sopenharmony_ci	 *
346862306a36Sopenharmony_ci	 * __u32 i_blocks_lo and _u16 i_blocks_high represent the total
346962306a36Sopenharmony_ci	 * number of 512-byte sectors of the file.
347062306a36Sopenharmony_ci	 */
347162306a36Sopenharmony_ci	if (!has_huge_files) {
347262306a36Sopenharmony_ci		/*
347362306a36Sopenharmony_ci		 * !has_huge_files or implies that the inode i_block field
347462306a36Sopenharmony_ci		 * represents total file blocks in 2^32 512-byte sectors ==
347562306a36Sopenharmony_ci		 * size of vfs inode i_blocks * 8
347662306a36Sopenharmony_ci		 */
347762306a36Sopenharmony_ci		upper_limit = (1LL << 32) - 1;
347862306a36Sopenharmony_ci
347962306a36Sopenharmony_ci		/* total blocks in file system block size */
348062306a36Sopenharmony_ci		upper_limit >>= (bits - 9);
348162306a36Sopenharmony_ci
348262306a36Sopenharmony_ci	} else {
348362306a36Sopenharmony_ci		/*
348462306a36Sopenharmony_ci		 * We use 48 bit ext4_inode i_blocks
348562306a36Sopenharmony_ci		 * With EXT4_HUGE_FILE_FL set the i_blocks
348662306a36Sopenharmony_ci		 * represent total number of blocks in
348762306a36Sopenharmony_ci		 * file system block size
348862306a36Sopenharmony_ci		 */
348962306a36Sopenharmony_ci		upper_limit = (1LL << 48) - 1;
349062306a36Sopenharmony_ci
349162306a36Sopenharmony_ci	}
349262306a36Sopenharmony_ci
349362306a36Sopenharmony_ci	/* Compute how many blocks we can address by block tree */
349462306a36Sopenharmony_ci	res += ppb;
349562306a36Sopenharmony_ci	res += ppb * ppb;
349662306a36Sopenharmony_ci	res += ((loff_t)ppb) * ppb * ppb;
349762306a36Sopenharmony_ci	/* Compute how many metadata blocks are needed */
349862306a36Sopenharmony_ci	meta_blocks = 1;
349962306a36Sopenharmony_ci	meta_blocks += 1 + ppb;
350062306a36Sopenharmony_ci	meta_blocks += 1 + ppb + ppb * ppb;
350162306a36Sopenharmony_ci	/* Does block tree limit file size? */
350262306a36Sopenharmony_ci	if (res + meta_blocks <= upper_limit)
350362306a36Sopenharmony_ci		goto check_lfs;
350462306a36Sopenharmony_ci
350562306a36Sopenharmony_ci	res = upper_limit;
350662306a36Sopenharmony_ci	/* How many metadata blocks are needed for addressing upper_limit? */
350762306a36Sopenharmony_ci	upper_limit -= EXT4_NDIR_BLOCKS;
350862306a36Sopenharmony_ci	/* indirect blocks */
350962306a36Sopenharmony_ci	meta_blocks = 1;
351062306a36Sopenharmony_ci	upper_limit -= ppb;
351162306a36Sopenharmony_ci	/* double indirect blocks */
351262306a36Sopenharmony_ci	if (upper_limit < ppb * ppb) {
351362306a36Sopenharmony_ci		meta_blocks += 1 + DIV_ROUND_UP_ULL(upper_limit, ppb);
351462306a36Sopenharmony_ci		res -= meta_blocks;
351562306a36Sopenharmony_ci		goto check_lfs;
351662306a36Sopenharmony_ci	}
351762306a36Sopenharmony_ci	meta_blocks += 1 + ppb;
351862306a36Sopenharmony_ci	upper_limit -= ppb * ppb;
351962306a36Sopenharmony_ci	/* tripple indirect blocks for the rest */
352062306a36Sopenharmony_ci	meta_blocks += 1 + DIV_ROUND_UP_ULL(upper_limit, ppb) +
352162306a36Sopenharmony_ci		DIV_ROUND_UP_ULL(upper_limit, ppb*ppb);
352262306a36Sopenharmony_ci	res -= meta_blocks;
352362306a36Sopenharmony_cicheck_lfs:
352462306a36Sopenharmony_ci	res <<= bits;
352562306a36Sopenharmony_ci	if (res > MAX_LFS_FILESIZE)
352662306a36Sopenharmony_ci		res = MAX_LFS_FILESIZE;
352762306a36Sopenharmony_ci
352862306a36Sopenharmony_ci	return res;
352962306a36Sopenharmony_ci}
353062306a36Sopenharmony_ci
353162306a36Sopenharmony_cistatic ext4_fsblk_t descriptor_loc(struct super_block *sb,
353262306a36Sopenharmony_ci				   ext4_fsblk_t logical_sb_block, int nr)
353362306a36Sopenharmony_ci{
353462306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
353562306a36Sopenharmony_ci	ext4_group_t bg, first_meta_bg;
353662306a36Sopenharmony_ci	int has_super = 0;
353762306a36Sopenharmony_ci
353862306a36Sopenharmony_ci	first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
353962306a36Sopenharmony_ci
354062306a36Sopenharmony_ci	if (!ext4_has_feature_meta_bg(sb) || nr < first_meta_bg)
354162306a36Sopenharmony_ci		return logical_sb_block + nr + 1;
354262306a36Sopenharmony_ci	bg = sbi->s_desc_per_block * nr;
354362306a36Sopenharmony_ci	if (ext4_bg_has_super(sb, bg))
354462306a36Sopenharmony_ci		has_super = 1;
354562306a36Sopenharmony_ci
354662306a36Sopenharmony_ci	/*
354762306a36Sopenharmony_ci	 * If we have a meta_bg fs with 1k blocks, group 0's GDT is at
354862306a36Sopenharmony_ci	 * block 2, not 1.  If s_first_data_block == 0 (bigalloc is enabled
354962306a36Sopenharmony_ci	 * on modern mke2fs or blksize > 1k on older mke2fs) then we must
355062306a36Sopenharmony_ci	 * compensate.
355162306a36Sopenharmony_ci	 */
355262306a36Sopenharmony_ci	if (sb->s_blocksize == 1024 && nr == 0 &&
355362306a36Sopenharmony_ci	    le32_to_cpu(sbi->s_es->s_first_data_block) == 0)
355462306a36Sopenharmony_ci		has_super++;
355562306a36Sopenharmony_ci
355662306a36Sopenharmony_ci	return (has_super + ext4_group_first_block_no(sb, bg));
355762306a36Sopenharmony_ci}
355862306a36Sopenharmony_ci
355962306a36Sopenharmony_ci/**
356062306a36Sopenharmony_ci * ext4_get_stripe_size: Get the stripe size.
356162306a36Sopenharmony_ci * @sbi: In memory super block info
356262306a36Sopenharmony_ci *
356362306a36Sopenharmony_ci * If we have specified it via mount option, then
356462306a36Sopenharmony_ci * use the mount option value. If the value specified at mount time is
356562306a36Sopenharmony_ci * greater than the blocks per group use the super block value.
356662306a36Sopenharmony_ci * If the super block value is greater than blocks per group return 0.
356762306a36Sopenharmony_ci * Allocator needs it be less than blocks per group.
356862306a36Sopenharmony_ci *
356962306a36Sopenharmony_ci */
357062306a36Sopenharmony_cistatic unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi)
357162306a36Sopenharmony_ci{
357262306a36Sopenharmony_ci	unsigned long stride = le16_to_cpu(sbi->s_es->s_raid_stride);
357362306a36Sopenharmony_ci	unsigned long stripe_width =
357462306a36Sopenharmony_ci			le32_to_cpu(sbi->s_es->s_raid_stripe_width);
357562306a36Sopenharmony_ci	int ret;
357662306a36Sopenharmony_ci
357762306a36Sopenharmony_ci	if (sbi->s_stripe && sbi->s_stripe <= sbi->s_blocks_per_group)
357862306a36Sopenharmony_ci		ret = sbi->s_stripe;
357962306a36Sopenharmony_ci	else if (stripe_width && stripe_width <= sbi->s_blocks_per_group)
358062306a36Sopenharmony_ci		ret = stripe_width;
358162306a36Sopenharmony_ci	else if (stride && stride <= sbi->s_blocks_per_group)
358262306a36Sopenharmony_ci		ret = stride;
358362306a36Sopenharmony_ci	else
358462306a36Sopenharmony_ci		ret = 0;
358562306a36Sopenharmony_ci
358662306a36Sopenharmony_ci	/*
358762306a36Sopenharmony_ci	 * If the stripe width is 1, this makes no sense and
358862306a36Sopenharmony_ci	 * we set it to 0 to turn off stripe handling code.
358962306a36Sopenharmony_ci	 */
359062306a36Sopenharmony_ci	if (ret <= 1)
359162306a36Sopenharmony_ci		ret = 0;
359262306a36Sopenharmony_ci
359362306a36Sopenharmony_ci	return ret;
359462306a36Sopenharmony_ci}
359562306a36Sopenharmony_ci
359662306a36Sopenharmony_ci/*
359762306a36Sopenharmony_ci * Check whether this filesystem can be mounted based on
359862306a36Sopenharmony_ci * the features present and the RDONLY/RDWR mount requested.
359962306a36Sopenharmony_ci * Returns 1 if this filesystem can be mounted as requested,
360062306a36Sopenharmony_ci * 0 if it cannot be.
360162306a36Sopenharmony_ci */
360262306a36Sopenharmony_ciint ext4_feature_set_ok(struct super_block *sb, int readonly)
360362306a36Sopenharmony_ci{
360462306a36Sopenharmony_ci	if (ext4_has_unknown_ext4_incompat_features(sb)) {
360562306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR,
360662306a36Sopenharmony_ci			"Couldn't mount because of "
360762306a36Sopenharmony_ci			"unsupported optional features (%x)",
360862306a36Sopenharmony_ci			(le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_incompat) &
360962306a36Sopenharmony_ci			~EXT4_FEATURE_INCOMPAT_SUPP));
361062306a36Sopenharmony_ci		return 0;
361162306a36Sopenharmony_ci	}
361262306a36Sopenharmony_ci
361362306a36Sopenharmony_ci#if !IS_ENABLED(CONFIG_UNICODE)
361462306a36Sopenharmony_ci	if (ext4_has_feature_casefold(sb)) {
361562306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR,
361662306a36Sopenharmony_ci			 "Filesystem with casefold feature cannot be "
361762306a36Sopenharmony_ci			 "mounted without CONFIG_UNICODE");
361862306a36Sopenharmony_ci		return 0;
361962306a36Sopenharmony_ci	}
362062306a36Sopenharmony_ci#endif
362162306a36Sopenharmony_ci
362262306a36Sopenharmony_ci	if (readonly)
362362306a36Sopenharmony_ci		return 1;
362462306a36Sopenharmony_ci
362562306a36Sopenharmony_ci	if (ext4_has_feature_readonly(sb)) {
362662306a36Sopenharmony_ci		ext4_msg(sb, KERN_INFO, "filesystem is read-only");
362762306a36Sopenharmony_ci		sb->s_flags |= SB_RDONLY;
362862306a36Sopenharmony_ci		return 1;
362962306a36Sopenharmony_ci	}
363062306a36Sopenharmony_ci
363162306a36Sopenharmony_ci	/* Check that feature set is OK for a read-write mount */
363262306a36Sopenharmony_ci	if (ext4_has_unknown_ext4_ro_compat_features(sb)) {
363362306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "couldn't mount RDWR because of "
363462306a36Sopenharmony_ci			 "unsupported optional features (%x)",
363562306a36Sopenharmony_ci			 (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_ro_compat) &
363662306a36Sopenharmony_ci				~EXT4_FEATURE_RO_COMPAT_SUPP));
363762306a36Sopenharmony_ci		return 0;
363862306a36Sopenharmony_ci	}
363962306a36Sopenharmony_ci	if (ext4_has_feature_bigalloc(sb) && !ext4_has_feature_extents(sb)) {
364062306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR,
364162306a36Sopenharmony_ci			 "Can't support bigalloc feature without "
364262306a36Sopenharmony_ci			 "extents feature\n");
364362306a36Sopenharmony_ci		return 0;
364462306a36Sopenharmony_ci	}
364562306a36Sopenharmony_ci
364662306a36Sopenharmony_ci#if !IS_ENABLED(CONFIG_QUOTA) || !IS_ENABLED(CONFIG_QFMT_V2)
364762306a36Sopenharmony_ci	if (!readonly && (ext4_has_feature_quota(sb) ||
364862306a36Sopenharmony_ci			  ext4_has_feature_project(sb))) {
364962306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR,
365062306a36Sopenharmony_ci			 "The kernel was not built with CONFIG_QUOTA and CONFIG_QFMT_V2");
365162306a36Sopenharmony_ci		return 0;
365262306a36Sopenharmony_ci	}
365362306a36Sopenharmony_ci#endif  /* CONFIG_QUOTA */
365462306a36Sopenharmony_ci	return 1;
365562306a36Sopenharmony_ci}
365662306a36Sopenharmony_ci
365762306a36Sopenharmony_ci/*
365862306a36Sopenharmony_ci * This function is called once a day if we have errors logged
365962306a36Sopenharmony_ci * on the file system
366062306a36Sopenharmony_ci */
366162306a36Sopenharmony_cistatic void print_daily_error_info(struct timer_list *t)
366262306a36Sopenharmony_ci{
366362306a36Sopenharmony_ci	struct ext4_sb_info *sbi = from_timer(sbi, t, s_err_report);
366462306a36Sopenharmony_ci	struct super_block *sb = sbi->s_sb;
366562306a36Sopenharmony_ci	struct ext4_super_block *es = sbi->s_es;
366662306a36Sopenharmony_ci
366762306a36Sopenharmony_ci	if (es->s_error_count)
366862306a36Sopenharmony_ci		/* fsck newer than v1.41.13 is needed to clean this condition. */
366962306a36Sopenharmony_ci		ext4_msg(sb, KERN_NOTICE, "error count since last fsck: %u",
367062306a36Sopenharmony_ci			 le32_to_cpu(es->s_error_count));
367162306a36Sopenharmony_ci	if (es->s_first_error_time) {
367262306a36Sopenharmony_ci		printk(KERN_NOTICE "EXT4-fs (%s): initial error at time %llu: %.*s:%d",
367362306a36Sopenharmony_ci		       sb->s_id,
367462306a36Sopenharmony_ci		       ext4_get_tstamp(es, s_first_error_time),
367562306a36Sopenharmony_ci		       (int) sizeof(es->s_first_error_func),
367662306a36Sopenharmony_ci		       es->s_first_error_func,
367762306a36Sopenharmony_ci		       le32_to_cpu(es->s_first_error_line));
367862306a36Sopenharmony_ci		if (es->s_first_error_ino)
367962306a36Sopenharmony_ci			printk(KERN_CONT ": inode %u",
368062306a36Sopenharmony_ci			       le32_to_cpu(es->s_first_error_ino));
368162306a36Sopenharmony_ci		if (es->s_first_error_block)
368262306a36Sopenharmony_ci			printk(KERN_CONT ": block %llu", (unsigned long long)
368362306a36Sopenharmony_ci			       le64_to_cpu(es->s_first_error_block));
368462306a36Sopenharmony_ci		printk(KERN_CONT "\n");
368562306a36Sopenharmony_ci	}
368662306a36Sopenharmony_ci	if (es->s_last_error_time) {
368762306a36Sopenharmony_ci		printk(KERN_NOTICE "EXT4-fs (%s): last error at time %llu: %.*s:%d",
368862306a36Sopenharmony_ci		       sb->s_id,
368962306a36Sopenharmony_ci		       ext4_get_tstamp(es, s_last_error_time),
369062306a36Sopenharmony_ci		       (int) sizeof(es->s_last_error_func),
369162306a36Sopenharmony_ci		       es->s_last_error_func,
369262306a36Sopenharmony_ci		       le32_to_cpu(es->s_last_error_line));
369362306a36Sopenharmony_ci		if (es->s_last_error_ino)
369462306a36Sopenharmony_ci			printk(KERN_CONT ": inode %u",
369562306a36Sopenharmony_ci			       le32_to_cpu(es->s_last_error_ino));
369662306a36Sopenharmony_ci		if (es->s_last_error_block)
369762306a36Sopenharmony_ci			printk(KERN_CONT ": block %llu", (unsigned long long)
369862306a36Sopenharmony_ci			       le64_to_cpu(es->s_last_error_block));
369962306a36Sopenharmony_ci		printk(KERN_CONT "\n");
370062306a36Sopenharmony_ci	}
370162306a36Sopenharmony_ci	mod_timer(&sbi->s_err_report, jiffies + 24*60*60*HZ);  /* Once a day */
370262306a36Sopenharmony_ci}
370362306a36Sopenharmony_ci
370462306a36Sopenharmony_ci/* Find next suitable group and run ext4_init_inode_table */
370562306a36Sopenharmony_cistatic int ext4_run_li_request(struct ext4_li_request *elr)
370662306a36Sopenharmony_ci{
370762306a36Sopenharmony_ci	struct ext4_group_desc *gdp = NULL;
370862306a36Sopenharmony_ci	struct super_block *sb = elr->lr_super;
370962306a36Sopenharmony_ci	ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
371062306a36Sopenharmony_ci	ext4_group_t group = elr->lr_next_group;
371162306a36Sopenharmony_ci	unsigned int prefetch_ios = 0;
371262306a36Sopenharmony_ci	int ret = 0;
371362306a36Sopenharmony_ci	int nr = EXT4_SB(sb)->s_mb_prefetch;
371462306a36Sopenharmony_ci	u64 start_time;
371562306a36Sopenharmony_ci
371662306a36Sopenharmony_ci	if (elr->lr_mode == EXT4_LI_MODE_PREFETCH_BBITMAP) {
371762306a36Sopenharmony_ci		elr->lr_next_group = ext4_mb_prefetch(sb, group, nr, &prefetch_ios);
371862306a36Sopenharmony_ci		ext4_mb_prefetch_fini(sb, elr->lr_next_group, nr);
371962306a36Sopenharmony_ci		trace_ext4_prefetch_bitmaps(sb, group, elr->lr_next_group, nr);
372062306a36Sopenharmony_ci		if (group >= elr->lr_next_group) {
372162306a36Sopenharmony_ci			ret = 1;
372262306a36Sopenharmony_ci			if (elr->lr_first_not_zeroed != ngroups &&
372362306a36Sopenharmony_ci			    !sb_rdonly(sb) && test_opt(sb, INIT_INODE_TABLE)) {
372462306a36Sopenharmony_ci				elr->lr_next_group = elr->lr_first_not_zeroed;
372562306a36Sopenharmony_ci				elr->lr_mode = EXT4_LI_MODE_ITABLE;
372662306a36Sopenharmony_ci				ret = 0;
372762306a36Sopenharmony_ci			}
372862306a36Sopenharmony_ci		}
372962306a36Sopenharmony_ci		return ret;
373062306a36Sopenharmony_ci	}
373162306a36Sopenharmony_ci
373262306a36Sopenharmony_ci	for (; group < ngroups; group++) {
373362306a36Sopenharmony_ci		gdp = ext4_get_group_desc(sb, group, NULL);
373462306a36Sopenharmony_ci		if (!gdp) {
373562306a36Sopenharmony_ci			ret = 1;
373662306a36Sopenharmony_ci			break;
373762306a36Sopenharmony_ci		}
373862306a36Sopenharmony_ci
373962306a36Sopenharmony_ci		if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)))
374062306a36Sopenharmony_ci			break;
374162306a36Sopenharmony_ci	}
374262306a36Sopenharmony_ci
374362306a36Sopenharmony_ci	if (group >= ngroups)
374462306a36Sopenharmony_ci		ret = 1;
374562306a36Sopenharmony_ci
374662306a36Sopenharmony_ci	if (!ret) {
374762306a36Sopenharmony_ci		start_time = ktime_get_real_ns();
374862306a36Sopenharmony_ci		ret = ext4_init_inode_table(sb, group,
374962306a36Sopenharmony_ci					    elr->lr_timeout ? 0 : 1);
375062306a36Sopenharmony_ci		trace_ext4_lazy_itable_init(sb, group);
375162306a36Sopenharmony_ci		if (elr->lr_timeout == 0) {
375262306a36Sopenharmony_ci			elr->lr_timeout = nsecs_to_jiffies((ktime_get_real_ns() - start_time) *
375362306a36Sopenharmony_ci				EXT4_SB(elr->lr_super)->s_li_wait_mult);
375462306a36Sopenharmony_ci		}
375562306a36Sopenharmony_ci		elr->lr_next_sched = jiffies + elr->lr_timeout;
375662306a36Sopenharmony_ci		elr->lr_next_group = group + 1;
375762306a36Sopenharmony_ci	}
375862306a36Sopenharmony_ci	return ret;
375962306a36Sopenharmony_ci}
376062306a36Sopenharmony_ci
376162306a36Sopenharmony_ci/*
376262306a36Sopenharmony_ci * Remove lr_request from the list_request and free the
376362306a36Sopenharmony_ci * request structure. Should be called with li_list_mtx held
376462306a36Sopenharmony_ci */
376562306a36Sopenharmony_cistatic void ext4_remove_li_request(struct ext4_li_request *elr)
376662306a36Sopenharmony_ci{
376762306a36Sopenharmony_ci	if (!elr)
376862306a36Sopenharmony_ci		return;
376962306a36Sopenharmony_ci
377062306a36Sopenharmony_ci	list_del(&elr->lr_request);
377162306a36Sopenharmony_ci	EXT4_SB(elr->lr_super)->s_li_request = NULL;
377262306a36Sopenharmony_ci	kfree(elr);
377362306a36Sopenharmony_ci}
377462306a36Sopenharmony_ci
377562306a36Sopenharmony_cistatic void ext4_unregister_li_request(struct super_block *sb)
377662306a36Sopenharmony_ci{
377762306a36Sopenharmony_ci	mutex_lock(&ext4_li_mtx);
377862306a36Sopenharmony_ci	if (!ext4_li_info) {
377962306a36Sopenharmony_ci		mutex_unlock(&ext4_li_mtx);
378062306a36Sopenharmony_ci		return;
378162306a36Sopenharmony_ci	}
378262306a36Sopenharmony_ci
378362306a36Sopenharmony_ci	mutex_lock(&ext4_li_info->li_list_mtx);
378462306a36Sopenharmony_ci	ext4_remove_li_request(EXT4_SB(sb)->s_li_request);
378562306a36Sopenharmony_ci	mutex_unlock(&ext4_li_info->li_list_mtx);
378662306a36Sopenharmony_ci	mutex_unlock(&ext4_li_mtx);
378762306a36Sopenharmony_ci}
378862306a36Sopenharmony_ci
378962306a36Sopenharmony_cistatic struct task_struct *ext4_lazyinit_task;
379062306a36Sopenharmony_ci
379162306a36Sopenharmony_ci/*
379262306a36Sopenharmony_ci * This is the function where ext4lazyinit thread lives. It walks
379362306a36Sopenharmony_ci * through the request list searching for next scheduled filesystem.
379462306a36Sopenharmony_ci * When such a fs is found, run the lazy initialization request
379562306a36Sopenharmony_ci * (ext4_rn_li_request) and keep track of the time spend in this
379662306a36Sopenharmony_ci * function. Based on that time we compute next schedule time of
379762306a36Sopenharmony_ci * the request. When walking through the list is complete, compute
379862306a36Sopenharmony_ci * next waking time and put itself into sleep.
379962306a36Sopenharmony_ci */
380062306a36Sopenharmony_cistatic int ext4_lazyinit_thread(void *arg)
380162306a36Sopenharmony_ci{
380262306a36Sopenharmony_ci	struct ext4_lazy_init *eli = arg;
380362306a36Sopenharmony_ci	struct list_head *pos, *n;
380462306a36Sopenharmony_ci	struct ext4_li_request *elr;
380562306a36Sopenharmony_ci	unsigned long next_wakeup, cur;
380662306a36Sopenharmony_ci
380762306a36Sopenharmony_ci	BUG_ON(NULL == eli);
380862306a36Sopenharmony_ci	set_freezable();
380962306a36Sopenharmony_ci
381062306a36Sopenharmony_cicont_thread:
381162306a36Sopenharmony_ci	while (true) {
381262306a36Sopenharmony_ci		next_wakeup = MAX_JIFFY_OFFSET;
381362306a36Sopenharmony_ci
381462306a36Sopenharmony_ci		mutex_lock(&eli->li_list_mtx);
381562306a36Sopenharmony_ci		if (list_empty(&eli->li_request_list)) {
381662306a36Sopenharmony_ci			mutex_unlock(&eli->li_list_mtx);
381762306a36Sopenharmony_ci			goto exit_thread;
381862306a36Sopenharmony_ci		}
381962306a36Sopenharmony_ci		list_for_each_safe(pos, n, &eli->li_request_list) {
382062306a36Sopenharmony_ci			int err = 0;
382162306a36Sopenharmony_ci			int progress = 0;
382262306a36Sopenharmony_ci			elr = list_entry(pos, struct ext4_li_request,
382362306a36Sopenharmony_ci					 lr_request);
382462306a36Sopenharmony_ci
382562306a36Sopenharmony_ci			if (time_before(jiffies, elr->lr_next_sched)) {
382662306a36Sopenharmony_ci				if (time_before(elr->lr_next_sched, next_wakeup))
382762306a36Sopenharmony_ci					next_wakeup = elr->lr_next_sched;
382862306a36Sopenharmony_ci				continue;
382962306a36Sopenharmony_ci			}
383062306a36Sopenharmony_ci			if (down_read_trylock(&elr->lr_super->s_umount)) {
383162306a36Sopenharmony_ci				if (sb_start_write_trylock(elr->lr_super)) {
383262306a36Sopenharmony_ci					progress = 1;
383362306a36Sopenharmony_ci					/*
383462306a36Sopenharmony_ci					 * We hold sb->s_umount, sb can not
383562306a36Sopenharmony_ci					 * be removed from the list, it is
383662306a36Sopenharmony_ci					 * now safe to drop li_list_mtx
383762306a36Sopenharmony_ci					 */
383862306a36Sopenharmony_ci					mutex_unlock(&eli->li_list_mtx);
383962306a36Sopenharmony_ci					err = ext4_run_li_request(elr);
384062306a36Sopenharmony_ci					sb_end_write(elr->lr_super);
384162306a36Sopenharmony_ci					mutex_lock(&eli->li_list_mtx);
384262306a36Sopenharmony_ci					n = pos->next;
384362306a36Sopenharmony_ci				}
384462306a36Sopenharmony_ci				up_read((&elr->lr_super->s_umount));
384562306a36Sopenharmony_ci			}
384662306a36Sopenharmony_ci			/* error, remove the lazy_init job */
384762306a36Sopenharmony_ci			if (err) {
384862306a36Sopenharmony_ci				ext4_remove_li_request(elr);
384962306a36Sopenharmony_ci				continue;
385062306a36Sopenharmony_ci			}
385162306a36Sopenharmony_ci			if (!progress) {
385262306a36Sopenharmony_ci				elr->lr_next_sched = jiffies +
385362306a36Sopenharmony_ci					get_random_u32_below(EXT4_DEF_LI_MAX_START_DELAY * HZ);
385462306a36Sopenharmony_ci			}
385562306a36Sopenharmony_ci			if (time_before(elr->lr_next_sched, next_wakeup))
385662306a36Sopenharmony_ci				next_wakeup = elr->lr_next_sched;
385762306a36Sopenharmony_ci		}
385862306a36Sopenharmony_ci		mutex_unlock(&eli->li_list_mtx);
385962306a36Sopenharmony_ci
386062306a36Sopenharmony_ci		try_to_freeze();
386162306a36Sopenharmony_ci
386262306a36Sopenharmony_ci		cur = jiffies;
386362306a36Sopenharmony_ci		if ((time_after_eq(cur, next_wakeup)) ||
386462306a36Sopenharmony_ci		    (MAX_JIFFY_OFFSET == next_wakeup)) {
386562306a36Sopenharmony_ci			cond_resched();
386662306a36Sopenharmony_ci			continue;
386762306a36Sopenharmony_ci		}
386862306a36Sopenharmony_ci
386962306a36Sopenharmony_ci		schedule_timeout_interruptible(next_wakeup - cur);
387062306a36Sopenharmony_ci
387162306a36Sopenharmony_ci		if (kthread_should_stop()) {
387262306a36Sopenharmony_ci			ext4_clear_request_list();
387362306a36Sopenharmony_ci			goto exit_thread;
387462306a36Sopenharmony_ci		}
387562306a36Sopenharmony_ci	}
387662306a36Sopenharmony_ci
387762306a36Sopenharmony_ciexit_thread:
387862306a36Sopenharmony_ci	/*
387962306a36Sopenharmony_ci	 * It looks like the request list is empty, but we need
388062306a36Sopenharmony_ci	 * to check it under the li_list_mtx lock, to prevent any
388162306a36Sopenharmony_ci	 * additions into it, and of course we should lock ext4_li_mtx
388262306a36Sopenharmony_ci	 * to atomically free the list and ext4_li_info, because at
388362306a36Sopenharmony_ci	 * this point another ext4 filesystem could be registering
388462306a36Sopenharmony_ci	 * new one.
388562306a36Sopenharmony_ci	 */
388662306a36Sopenharmony_ci	mutex_lock(&ext4_li_mtx);
388762306a36Sopenharmony_ci	mutex_lock(&eli->li_list_mtx);
388862306a36Sopenharmony_ci	if (!list_empty(&eli->li_request_list)) {
388962306a36Sopenharmony_ci		mutex_unlock(&eli->li_list_mtx);
389062306a36Sopenharmony_ci		mutex_unlock(&ext4_li_mtx);
389162306a36Sopenharmony_ci		goto cont_thread;
389262306a36Sopenharmony_ci	}
389362306a36Sopenharmony_ci	mutex_unlock(&eli->li_list_mtx);
389462306a36Sopenharmony_ci	kfree(ext4_li_info);
389562306a36Sopenharmony_ci	ext4_li_info = NULL;
389662306a36Sopenharmony_ci	mutex_unlock(&ext4_li_mtx);
389762306a36Sopenharmony_ci
389862306a36Sopenharmony_ci	return 0;
389962306a36Sopenharmony_ci}
390062306a36Sopenharmony_ci
390162306a36Sopenharmony_cistatic void ext4_clear_request_list(void)
390262306a36Sopenharmony_ci{
390362306a36Sopenharmony_ci	struct list_head *pos, *n;
390462306a36Sopenharmony_ci	struct ext4_li_request *elr;
390562306a36Sopenharmony_ci
390662306a36Sopenharmony_ci	mutex_lock(&ext4_li_info->li_list_mtx);
390762306a36Sopenharmony_ci	list_for_each_safe(pos, n, &ext4_li_info->li_request_list) {
390862306a36Sopenharmony_ci		elr = list_entry(pos, struct ext4_li_request,
390962306a36Sopenharmony_ci				 lr_request);
391062306a36Sopenharmony_ci		ext4_remove_li_request(elr);
391162306a36Sopenharmony_ci	}
391262306a36Sopenharmony_ci	mutex_unlock(&ext4_li_info->li_list_mtx);
391362306a36Sopenharmony_ci}
391462306a36Sopenharmony_ci
391562306a36Sopenharmony_cistatic int ext4_run_lazyinit_thread(void)
391662306a36Sopenharmony_ci{
391762306a36Sopenharmony_ci	ext4_lazyinit_task = kthread_run(ext4_lazyinit_thread,
391862306a36Sopenharmony_ci					 ext4_li_info, "ext4lazyinit");
391962306a36Sopenharmony_ci	if (IS_ERR(ext4_lazyinit_task)) {
392062306a36Sopenharmony_ci		int err = PTR_ERR(ext4_lazyinit_task);
392162306a36Sopenharmony_ci		ext4_clear_request_list();
392262306a36Sopenharmony_ci		kfree(ext4_li_info);
392362306a36Sopenharmony_ci		ext4_li_info = NULL;
392462306a36Sopenharmony_ci		printk(KERN_CRIT "EXT4-fs: error %d creating inode table "
392562306a36Sopenharmony_ci				 "initialization thread\n",
392662306a36Sopenharmony_ci				 err);
392762306a36Sopenharmony_ci		return err;
392862306a36Sopenharmony_ci	}
392962306a36Sopenharmony_ci	ext4_li_info->li_state |= EXT4_LAZYINIT_RUNNING;
393062306a36Sopenharmony_ci	return 0;
393162306a36Sopenharmony_ci}
393262306a36Sopenharmony_ci
393362306a36Sopenharmony_ci/*
393462306a36Sopenharmony_ci * Check whether it make sense to run itable init. thread or not.
393562306a36Sopenharmony_ci * If there is at least one uninitialized inode table, return
393662306a36Sopenharmony_ci * corresponding group number, else the loop goes through all
393762306a36Sopenharmony_ci * groups and return total number of groups.
393862306a36Sopenharmony_ci */
393962306a36Sopenharmony_cistatic ext4_group_t ext4_has_uninit_itable(struct super_block *sb)
394062306a36Sopenharmony_ci{
394162306a36Sopenharmony_ci	ext4_group_t group, ngroups = EXT4_SB(sb)->s_groups_count;
394262306a36Sopenharmony_ci	struct ext4_group_desc *gdp = NULL;
394362306a36Sopenharmony_ci
394462306a36Sopenharmony_ci	if (!ext4_has_group_desc_csum(sb))
394562306a36Sopenharmony_ci		return ngroups;
394662306a36Sopenharmony_ci
394762306a36Sopenharmony_ci	for (group = 0; group < ngroups; group++) {
394862306a36Sopenharmony_ci		gdp = ext4_get_group_desc(sb, group, NULL);
394962306a36Sopenharmony_ci		if (!gdp)
395062306a36Sopenharmony_ci			continue;
395162306a36Sopenharmony_ci
395262306a36Sopenharmony_ci		if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)))
395362306a36Sopenharmony_ci			break;
395462306a36Sopenharmony_ci	}
395562306a36Sopenharmony_ci
395662306a36Sopenharmony_ci	return group;
395762306a36Sopenharmony_ci}
395862306a36Sopenharmony_ci
395962306a36Sopenharmony_cistatic int ext4_li_info_new(void)
396062306a36Sopenharmony_ci{
396162306a36Sopenharmony_ci	struct ext4_lazy_init *eli = NULL;
396262306a36Sopenharmony_ci
396362306a36Sopenharmony_ci	eli = kzalloc(sizeof(*eli), GFP_KERNEL);
396462306a36Sopenharmony_ci	if (!eli)
396562306a36Sopenharmony_ci		return -ENOMEM;
396662306a36Sopenharmony_ci
396762306a36Sopenharmony_ci	INIT_LIST_HEAD(&eli->li_request_list);
396862306a36Sopenharmony_ci	mutex_init(&eli->li_list_mtx);
396962306a36Sopenharmony_ci
397062306a36Sopenharmony_ci	eli->li_state |= EXT4_LAZYINIT_QUIT;
397162306a36Sopenharmony_ci
397262306a36Sopenharmony_ci	ext4_li_info = eli;
397362306a36Sopenharmony_ci
397462306a36Sopenharmony_ci	return 0;
397562306a36Sopenharmony_ci}
397662306a36Sopenharmony_ci
397762306a36Sopenharmony_cistatic struct ext4_li_request *ext4_li_request_new(struct super_block *sb,
397862306a36Sopenharmony_ci					    ext4_group_t start)
397962306a36Sopenharmony_ci{
398062306a36Sopenharmony_ci	struct ext4_li_request *elr;
398162306a36Sopenharmony_ci
398262306a36Sopenharmony_ci	elr = kzalloc(sizeof(*elr), GFP_KERNEL);
398362306a36Sopenharmony_ci	if (!elr)
398462306a36Sopenharmony_ci		return NULL;
398562306a36Sopenharmony_ci
398662306a36Sopenharmony_ci	elr->lr_super = sb;
398762306a36Sopenharmony_ci	elr->lr_first_not_zeroed = start;
398862306a36Sopenharmony_ci	if (test_opt(sb, NO_PREFETCH_BLOCK_BITMAPS)) {
398962306a36Sopenharmony_ci		elr->lr_mode = EXT4_LI_MODE_ITABLE;
399062306a36Sopenharmony_ci		elr->lr_next_group = start;
399162306a36Sopenharmony_ci	} else {
399262306a36Sopenharmony_ci		elr->lr_mode = EXT4_LI_MODE_PREFETCH_BBITMAP;
399362306a36Sopenharmony_ci	}
399462306a36Sopenharmony_ci
399562306a36Sopenharmony_ci	/*
399662306a36Sopenharmony_ci	 * Randomize first schedule time of the request to
399762306a36Sopenharmony_ci	 * spread the inode table initialization requests
399862306a36Sopenharmony_ci	 * better.
399962306a36Sopenharmony_ci	 */
400062306a36Sopenharmony_ci	elr->lr_next_sched = jiffies + get_random_u32_below(EXT4_DEF_LI_MAX_START_DELAY * HZ);
400162306a36Sopenharmony_ci	return elr;
400262306a36Sopenharmony_ci}
400362306a36Sopenharmony_ci
400462306a36Sopenharmony_ciint ext4_register_li_request(struct super_block *sb,
400562306a36Sopenharmony_ci			     ext4_group_t first_not_zeroed)
400662306a36Sopenharmony_ci{
400762306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
400862306a36Sopenharmony_ci	struct ext4_li_request *elr = NULL;
400962306a36Sopenharmony_ci	ext4_group_t ngroups = sbi->s_groups_count;
401062306a36Sopenharmony_ci	int ret = 0;
401162306a36Sopenharmony_ci
401262306a36Sopenharmony_ci	mutex_lock(&ext4_li_mtx);
401362306a36Sopenharmony_ci	if (sbi->s_li_request != NULL) {
401462306a36Sopenharmony_ci		/*
401562306a36Sopenharmony_ci		 * Reset timeout so it can be computed again, because
401662306a36Sopenharmony_ci		 * s_li_wait_mult might have changed.
401762306a36Sopenharmony_ci		 */
401862306a36Sopenharmony_ci		sbi->s_li_request->lr_timeout = 0;
401962306a36Sopenharmony_ci		goto out;
402062306a36Sopenharmony_ci	}
402162306a36Sopenharmony_ci
402262306a36Sopenharmony_ci	if (sb_rdonly(sb) ||
402362306a36Sopenharmony_ci	    (test_opt(sb, NO_PREFETCH_BLOCK_BITMAPS) &&
402462306a36Sopenharmony_ci	     (first_not_zeroed == ngroups || !test_opt(sb, INIT_INODE_TABLE))))
402562306a36Sopenharmony_ci		goto out;
402662306a36Sopenharmony_ci
402762306a36Sopenharmony_ci	elr = ext4_li_request_new(sb, first_not_zeroed);
402862306a36Sopenharmony_ci	if (!elr) {
402962306a36Sopenharmony_ci		ret = -ENOMEM;
403062306a36Sopenharmony_ci		goto out;
403162306a36Sopenharmony_ci	}
403262306a36Sopenharmony_ci
403362306a36Sopenharmony_ci	if (NULL == ext4_li_info) {
403462306a36Sopenharmony_ci		ret = ext4_li_info_new();
403562306a36Sopenharmony_ci		if (ret)
403662306a36Sopenharmony_ci			goto out;
403762306a36Sopenharmony_ci	}
403862306a36Sopenharmony_ci
403962306a36Sopenharmony_ci	mutex_lock(&ext4_li_info->li_list_mtx);
404062306a36Sopenharmony_ci	list_add(&elr->lr_request, &ext4_li_info->li_request_list);
404162306a36Sopenharmony_ci	mutex_unlock(&ext4_li_info->li_list_mtx);
404262306a36Sopenharmony_ci
404362306a36Sopenharmony_ci	sbi->s_li_request = elr;
404462306a36Sopenharmony_ci	/*
404562306a36Sopenharmony_ci	 * set elr to NULL here since it has been inserted to
404662306a36Sopenharmony_ci	 * the request_list and the removal and free of it is
404762306a36Sopenharmony_ci	 * handled by ext4_clear_request_list from now on.
404862306a36Sopenharmony_ci	 */
404962306a36Sopenharmony_ci	elr = NULL;
405062306a36Sopenharmony_ci
405162306a36Sopenharmony_ci	if (!(ext4_li_info->li_state & EXT4_LAZYINIT_RUNNING)) {
405262306a36Sopenharmony_ci		ret = ext4_run_lazyinit_thread();
405362306a36Sopenharmony_ci		if (ret)
405462306a36Sopenharmony_ci			goto out;
405562306a36Sopenharmony_ci	}
405662306a36Sopenharmony_ciout:
405762306a36Sopenharmony_ci	mutex_unlock(&ext4_li_mtx);
405862306a36Sopenharmony_ci	if (ret)
405962306a36Sopenharmony_ci		kfree(elr);
406062306a36Sopenharmony_ci	return ret;
406162306a36Sopenharmony_ci}
406262306a36Sopenharmony_ci
406362306a36Sopenharmony_ci/*
406462306a36Sopenharmony_ci * We do not need to lock anything since this is called on
406562306a36Sopenharmony_ci * module unload.
406662306a36Sopenharmony_ci */
406762306a36Sopenharmony_cistatic void ext4_destroy_lazyinit_thread(void)
406862306a36Sopenharmony_ci{
406962306a36Sopenharmony_ci	/*
407062306a36Sopenharmony_ci	 * If thread exited earlier
407162306a36Sopenharmony_ci	 * there's nothing to be done.
407262306a36Sopenharmony_ci	 */
407362306a36Sopenharmony_ci	if (!ext4_li_info || !ext4_lazyinit_task)
407462306a36Sopenharmony_ci		return;
407562306a36Sopenharmony_ci
407662306a36Sopenharmony_ci	kthread_stop(ext4_lazyinit_task);
407762306a36Sopenharmony_ci}
407862306a36Sopenharmony_ci
407962306a36Sopenharmony_cistatic int set_journal_csum_feature_set(struct super_block *sb)
408062306a36Sopenharmony_ci{
408162306a36Sopenharmony_ci	int ret = 1;
408262306a36Sopenharmony_ci	int compat, incompat;
408362306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
408462306a36Sopenharmony_ci
408562306a36Sopenharmony_ci	if (ext4_has_metadata_csum(sb)) {
408662306a36Sopenharmony_ci		/* journal checksum v3 */
408762306a36Sopenharmony_ci		compat = 0;
408862306a36Sopenharmony_ci		incompat = JBD2_FEATURE_INCOMPAT_CSUM_V3;
408962306a36Sopenharmony_ci	} else {
409062306a36Sopenharmony_ci		/* journal checksum v1 */
409162306a36Sopenharmony_ci		compat = JBD2_FEATURE_COMPAT_CHECKSUM;
409262306a36Sopenharmony_ci		incompat = 0;
409362306a36Sopenharmony_ci	}
409462306a36Sopenharmony_ci
409562306a36Sopenharmony_ci	jbd2_journal_clear_features(sbi->s_journal,
409662306a36Sopenharmony_ci			JBD2_FEATURE_COMPAT_CHECKSUM, 0,
409762306a36Sopenharmony_ci			JBD2_FEATURE_INCOMPAT_CSUM_V3 |
409862306a36Sopenharmony_ci			JBD2_FEATURE_INCOMPAT_CSUM_V2);
409962306a36Sopenharmony_ci	if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
410062306a36Sopenharmony_ci		ret = jbd2_journal_set_features(sbi->s_journal,
410162306a36Sopenharmony_ci				compat, 0,
410262306a36Sopenharmony_ci				JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT |
410362306a36Sopenharmony_ci				incompat);
410462306a36Sopenharmony_ci	} else if (test_opt(sb, JOURNAL_CHECKSUM)) {
410562306a36Sopenharmony_ci		ret = jbd2_journal_set_features(sbi->s_journal,
410662306a36Sopenharmony_ci				compat, 0,
410762306a36Sopenharmony_ci				incompat);
410862306a36Sopenharmony_ci		jbd2_journal_clear_features(sbi->s_journal, 0, 0,
410962306a36Sopenharmony_ci				JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT);
411062306a36Sopenharmony_ci	} else {
411162306a36Sopenharmony_ci		jbd2_journal_clear_features(sbi->s_journal, 0, 0,
411262306a36Sopenharmony_ci				JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT);
411362306a36Sopenharmony_ci	}
411462306a36Sopenharmony_ci
411562306a36Sopenharmony_ci	return ret;
411662306a36Sopenharmony_ci}
411762306a36Sopenharmony_ci
411862306a36Sopenharmony_ci/*
411962306a36Sopenharmony_ci * Note: calculating the overhead so we can be compatible with
412062306a36Sopenharmony_ci * historical BSD practice is quite difficult in the face of
412162306a36Sopenharmony_ci * clusters/bigalloc.  This is because multiple metadata blocks from
412262306a36Sopenharmony_ci * different block group can end up in the same allocation cluster.
412362306a36Sopenharmony_ci * Calculating the exact overhead in the face of clustered allocation
412462306a36Sopenharmony_ci * requires either O(all block bitmaps) in memory or O(number of block
412562306a36Sopenharmony_ci * groups**2) in time.  We will still calculate the superblock for
412662306a36Sopenharmony_ci * older file systems --- and if we come across with a bigalloc file
412762306a36Sopenharmony_ci * system with zero in s_overhead_clusters the estimate will be close to
412862306a36Sopenharmony_ci * correct especially for very large cluster sizes --- but for newer
412962306a36Sopenharmony_ci * file systems, it's better to calculate this figure once at mkfs
413062306a36Sopenharmony_ci * time, and store it in the superblock.  If the superblock value is
413162306a36Sopenharmony_ci * present (even for non-bigalloc file systems), we will use it.
413262306a36Sopenharmony_ci */
413362306a36Sopenharmony_cistatic int count_overhead(struct super_block *sb, ext4_group_t grp,
413462306a36Sopenharmony_ci			  char *buf)
413562306a36Sopenharmony_ci{
413662306a36Sopenharmony_ci	struct ext4_sb_info	*sbi = EXT4_SB(sb);
413762306a36Sopenharmony_ci	struct ext4_group_desc	*gdp;
413862306a36Sopenharmony_ci	ext4_fsblk_t		first_block, last_block, b;
413962306a36Sopenharmony_ci	ext4_group_t		i, ngroups = ext4_get_groups_count(sb);
414062306a36Sopenharmony_ci	int			s, j, count = 0;
414162306a36Sopenharmony_ci	int			has_super = ext4_bg_has_super(sb, grp);
414262306a36Sopenharmony_ci
414362306a36Sopenharmony_ci	if (!ext4_has_feature_bigalloc(sb))
414462306a36Sopenharmony_ci		return (has_super + ext4_bg_num_gdb(sb, grp) +
414562306a36Sopenharmony_ci			(has_super ? le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) : 0) +
414662306a36Sopenharmony_ci			sbi->s_itb_per_group + 2);
414762306a36Sopenharmony_ci
414862306a36Sopenharmony_ci	first_block = le32_to_cpu(sbi->s_es->s_first_data_block) +
414962306a36Sopenharmony_ci		(grp * EXT4_BLOCKS_PER_GROUP(sb));
415062306a36Sopenharmony_ci	last_block = first_block + EXT4_BLOCKS_PER_GROUP(sb) - 1;
415162306a36Sopenharmony_ci	for (i = 0; i < ngroups; i++) {
415262306a36Sopenharmony_ci		gdp = ext4_get_group_desc(sb, i, NULL);
415362306a36Sopenharmony_ci		b = ext4_block_bitmap(sb, gdp);
415462306a36Sopenharmony_ci		if (b >= first_block && b <= last_block) {
415562306a36Sopenharmony_ci			ext4_set_bit(EXT4_B2C(sbi, b - first_block), buf);
415662306a36Sopenharmony_ci			count++;
415762306a36Sopenharmony_ci		}
415862306a36Sopenharmony_ci		b = ext4_inode_bitmap(sb, gdp);
415962306a36Sopenharmony_ci		if (b >= first_block && b <= last_block) {
416062306a36Sopenharmony_ci			ext4_set_bit(EXT4_B2C(sbi, b - first_block), buf);
416162306a36Sopenharmony_ci			count++;
416262306a36Sopenharmony_ci		}
416362306a36Sopenharmony_ci		b = ext4_inode_table(sb, gdp);
416462306a36Sopenharmony_ci		if (b >= first_block && b + sbi->s_itb_per_group <= last_block)
416562306a36Sopenharmony_ci			for (j = 0; j < sbi->s_itb_per_group; j++, b++) {
416662306a36Sopenharmony_ci				int c = EXT4_B2C(sbi, b - first_block);
416762306a36Sopenharmony_ci				ext4_set_bit(c, buf);
416862306a36Sopenharmony_ci				count++;
416962306a36Sopenharmony_ci			}
417062306a36Sopenharmony_ci		if (i != grp)
417162306a36Sopenharmony_ci			continue;
417262306a36Sopenharmony_ci		s = 0;
417362306a36Sopenharmony_ci		if (ext4_bg_has_super(sb, grp)) {
417462306a36Sopenharmony_ci			ext4_set_bit(s++, buf);
417562306a36Sopenharmony_ci			count++;
417662306a36Sopenharmony_ci		}
417762306a36Sopenharmony_ci		j = ext4_bg_num_gdb(sb, grp);
417862306a36Sopenharmony_ci		if (s + j > EXT4_BLOCKS_PER_GROUP(sb)) {
417962306a36Sopenharmony_ci			ext4_error(sb, "Invalid number of block group "
418062306a36Sopenharmony_ci				   "descriptor blocks: %d", j);
418162306a36Sopenharmony_ci			j = EXT4_BLOCKS_PER_GROUP(sb) - s;
418262306a36Sopenharmony_ci		}
418362306a36Sopenharmony_ci		count += j;
418462306a36Sopenharmony_ci		for (; j > 0; j--)
418562306a36Sopenharmony_ci			ext4_set_bit(EXT4_B2C(sbi, s++), buf);
418662306a36Sopenharmony_ci	}
418762306a36Sopenharmony_ci	if (!count)
418862306a36Sopenharmony_ci		return 0;
418962306a36Sopenharmony_ci	return EXT4_CLUSTERS_PER_GROUP(sb) -
419062306a36Sopenharmony_ci		ext4_count_free(buf, EXT4_CLUSTERS_PER_GROUP(sb) / 8);
419162306a36Sopenharmony_ci}
419262306a36Sopenharmony_ci
419362306a36Sopenharmony_ci/*
419462306a36Sopenharmony_ci * Compute the overhead and stash it in sbi->s_overhead
419562306a36Sopenharmony_ci */
419662306a36Sopenharmony_ciint ext4_calculate_overhead(struct super_block *sb)
419762306a36Sopenharmony_ci{
419862306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
419962306a36Sopenharmony_ci	struct ext4_super_block *es = sbi->s_es;
420062306a36Sopenharmony_ci	struct inode *j_inode;
420162306a36Sopenharmony_ci	unsigned int j_blocks, j_inum = le32_to_cpu(es->s_journal_inum);
420262306a36Sopenharmony_ci	ext4_group_t i, ngroups = ext4_get_groups_count(sb);
420362306a36Sopenharmony_ci	ext4_fsblk_t overhead = 0;
420462306a36Sopenharmony_ci	char *buf = (char *) get_zeroed_page(GFP_NOFS);
420562306a36Sopenharmony_ci
420662306a36Sopenharmony_ci	if (!buf)
420762306a36Sopenharmony_ci		return -ENOMEM;
420862306a36Sopenharmony_ci
420962306a36Sopenharmony_ci	/*
421062306a36Sopenharmony_ci	 * Compute the overhead (FS structures).  This is constant
421162306a36Sopenharmony_ci	 * for a given filesystem unless the number of block groups
421262306a36Sopenharmony_ci	 * changes so we cache the previous value until it does.
421362306a36Sopenharmony_ci	 */
421462306a36Sopenharmony_ci
421562306a36Sopenharmony_ci	/*
421662306a36Sopenharmony_ci	 * All of the blocks before first_data_block are overhead
421762306a36Sopenharmony_ci	 */
421862306a36Sopenharmony_ci	overhead = EXT4_B2C(sbi, le32_to_cpu(es->s_first_data_block));
421962306a36Sopenharmony_ci
422062306a36Sopenharmony_ci	/*
422162306a36Sopenharmony_ci	 * Add the overhead found in each block group
422262306a36Sopenharmony_ci	 */
422362306a36Sopenharmony_ci	for (i = 0; i < ngroups; i++) {
422462306a36Sopenharmony_ci		int blks;
422562306a36Sopenharmony_ci
422662306a36Sopenharmony_ci		blks = count_overhead(sb, i, buf);
422762306a36Sopenharmony_ci		overhead += blks;
422862306a36Sopenharmony_ci		if (blks)
422962306a36Sopenharmony_ci			memset(buf, 0, PAGE_SIZE);
423062306a36Sopenharmony_ci		cond_resched();
423162306a36Sopenharmony_ci	}
423262306a36Sopenharmony_ci
423362306a36Sopenharmony_ci	/*
423462306a36Sopenharmony_ci	 * Add the internal journal blocks whether the journal has been
423562306a36Sopenharmony_ci	 * loaded or not
423662306a36Sopenharmony_ci	 */
423762306a36Sopenharmony_ci	if (sbi->s_journal && !sbi->s_journal_bdev)
423862306a36Sopenharmony_ci		overhead += EXT4_NUM_B2C(sbi, sbi->s_journal->j_total_len);
423962306a36Sopenharmony_ci	else if (ext4_has_feature_journal(sb) && !sbi->s_journal && j_inum) {
424062306a36Sopenharmony_ci		/* j_inum for internal journal is non-zero */
424162306a36Sopenharmony_ci		j_inode = ext4_get_journal_inode(sb, j_inum);
424262306a36Sopenharmony_ci		if (!IS_ERR(j_inode)) {
424362306a36Sopenharmony_ci			j_blocks = j_inode->i_size >> sb->s_blocksize_bits;
424462306a36Sopenharmony_ci			overhead += EXT4_NUM_B2C(sbi, j_blocks);
424562306a36Sopenharmony_ci			iput(j_inode);
424662306a36Sopenharmony_ci		} else {
424762306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "can't get journal size");
424862306a36Sopenharmony_ci		}
424962306a36Sopenharmony_ci	}
425062306a36Sopenharmony_ci	sbi->s_overhead = overhead;
425162306a36Sopenharmony_ci	smp_wmb();
425262306a36Sopenharmony_ci	free_page((unsigned long) buf);
425362306a36Sopenharmony_ci	return 0;
425462306a36Sopenharmony_ci}
425562306a36Sopenharmony_ci
425662306a36Sopenharmony_cistatic void ext4_set_resv_clusters(struct super_block *sb)
425762306a36Sopenharmony_ci{
425862306a36Sopenharmony_ci	ext4_fsblk_t resv_clusters;
425962306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
426062306a36Sopenharmony_ci
426162306a36Sopenharmony_ci	/*
426262306a36Sopenharmony_ci	 * There's no need to reserve anything when we aren't using extents.
426362306a36Sopenharmony_ci	 * The space estimates are exact, there are no unwritten extents,
426462306a36Sopenharmony_ci	 * hole punching doesn't need new metadata... This is needed especially
426562306a36Sopenharmony_ci	 * to keep ext2/3 backward compatibility.
426662306a36Sopenharmony_ci	 */
426762306a36Sopenharmony_ci	if (!ext4_has_feature_extents(sb))
426862306a36Sopenharmony_ci		return;
426962306a36Sopenharmony_ci	/*
427062306a36Sopenharmony_ci	 * By default we reserve 2% or 4096 clusters, whichever is smaller.
427162306a36Sopenharmony_ci	 * This should cover the situations where we can not afford to run
427262306a36Sopenharmony_ci	 * out of space like for example punch hole, or converting
427362306a36Sopenharmony_ci	 * unwritten extents in delalloc path. In most cases such
427462306a36Sopenharmony_ci	 * allocation would require 1, or 2 blocks, higher numbers are
427562306a36Sopenharmony_ci	 * very rare.
427662306a36Sopenharmony_ci	 */
427762306a36Sopenharmony_ci	resv_clusters = (ext4_blocks_count(sbi->s_es) >>
427862306a36Sopenharmony_ci			 sbi->s_cluster_bits);
427962306a36Sopenharmony_ci
428062306a36Sopenharmony_ci	do_div(resv_clusters, 50);
428162306a36Sopenharmony_ci	resv_clusters = min_t(ext4_fsblk_t, resv_clusters, 4096);
428262306a36Sopenharmony_ci
428362306a36Sopenharmony_ci	atomic64_set(&sbi->s_resv_clusters, resv_clusters);
428462306a36Sopenharmony_ci}
428562306a36Sopenharmony_ci
428662306a36Sopenharmony_cistatic const char *ext4_quota_mode(struct super_block *sb)
428762306a36Sopenharmony_ci{
428862306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
428962306a36Sopenharmony_ci	if (!ext4_quota_capable(sb))
429062306a36Sopenharmony_ci		return "none";
429162306a36Sopenharmony_ci
429262306a36Sopenharmony_ci	if (EXT4_SB(sb)->s_journal && ext4_is_quota_journalled(sb))
429362306a36Sopenharmony_ci		return "journalled";
429462306a36Sopenharmony_ci	else
429562306a36Sopenharmony_ci		return "writeback";
429662306a36Sopenharmony_ci#else
429762306a36Sopenharmony_ci	return "disabled";
429862306a36Sopenharmony_ci#endif
429962306a36Sopenharmony_ci}
430062306a36Sopenharmony_ci
430162306a36Sopenharmony_cistatic void ext4_setup_csum_trigger(struct super_block *sb,
430262306a36Sopenharmony_ci				    enum ext4_journal_trigger_type type,
430362306a36Sopenharmony_ci				    void (*trigger)(
430462306a36Sopenharmony_ci					struct jbd2_buffer_trigger_type *type,
430562306a36Sopenharmony_ci					struct buffer_head *bh,
430662306a36Sopenharmony_ci					void *mapped_data,
430762306a36Sopenharmony_ci					size_t size))
430862306a36Sopenharmony_ci{
430962306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
431062306a36Sopenharmony_ci
431162306a36Sopenharmony_ci	sbi->s_journal_triggers[type].sb = sb;
431262306a36Sopenharmony_ci	sbi->s_journal_triggers[type].tr_triggers.t_frozen = trigger;
431362306a36Sopenharmony_ci}
431462306a36Sopenharmony_ci
431562306a36Sopenharmony_cistatic void ext4_free_sbi(struct ext4_sb_info *sbi)
431662306a36Sopenharmony_ci{
431762306a36Sopenharmony_ci	if (!sbi)
431862306a36Sopenharmony_ci		return;
431962306a36Sopenharmony_ci
432062306a36Sopenharmony_ci	kfree(sbi->s_blockgroup_lock);
432162306a36Sopenharmony_ci	fs_put_dax(sbi->s_daxdev, NULL);
432262306a36Sopenharmony_ci	kfree(sbi);
432362306a36Sopenharmony_ci}
432462306a36Sopenharmony_ci
432562306a36Sopenharmony_cistatic struct ext4_sb_info *ext4_alloc_sbi(struct super_block *sb)
432662306a36Sopenharmony_ci{
432762306a36Sopenharmony_ci	struct ext4_sb_info *sbi;
432862306a36Sopenharmony_ci
432962306a36Sopenharmony_ci	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
433062306a36Sopenharmony_ci	if (!sbi)
433162306a36Sopenharmony_ci		return NULL;
433262306a36Sopenharmony_ci
433362306a36Sopenharmony_ci	sbi->s_daxdev = fs_dax_get_by_bdev(sb->s_bdev, &sbi->s_dax_part_off,
433462306a36Sopenharmony_ci					   NULL, NULL);
433562306a36Sopenharmony_ci
433662306a36Sopenharmony_ci	sbi->s_blockgroup_lock =
433762306a36Sopenharmony_ci		kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
433862306a36Sopenharmony_ci
433962306a36Sopenharmony_ci	if (!sbi->s_blockgroup_lock)
434062306a36Sopenharmony_ci		goto err_out;
434162306a36Sopenharmony_ci
434262306a36Sopenharmony_ci	sb->s_fs_info = sbi;
434362306a36Sopenharmony_ci	sbi->s_sb = sb;
434462306a36Sopenharmony_ci	return sbi;
434562306a36Sopenharmony_cierr_out:
434662306a36Sopenharmony_ci	fs_put_dax(sbi->s_daxdev, NULL);
434762306a36Sopenharmony_ci	kfree(sbi);
434862306a36Sopenharmony_ci	return NULL;
434962306a36Sopenharmony_ci}
435062306a36Sopenharmony_ci
435162306a36Sopenharmony_cistatic void ext4_set_def_opts(struct super_block *sb,
435262306a36Sopenharmony_ci			      struct ext4_super_block *es)
435362306a36Sopenharmony_ci{
435462306a36Sopenharmony_ci	unsigned long def_mount_opts;
435562306a36Sopenharmony_ci
435662306a36Sopenharmony_ci	/* Set defaults before we parse the mount options */
435762306a36Sopenharmony_ci	def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
435862306a36Sopenharmony_ci	set_opt(sb, INIT_INODE_TABLE);
435962306a36Sopenharmony_ci	if (def_mount_opts & EXT4_DEFM_DEBUG)
436062306a36Sopenharmony_ci		set_opt(sb, DEBUG);
436162306a36Sopenharmony_ci	if (def_mount_opts & EXT4_DEFM_BSDGROUPS)
436262306a36Sopenharmony_ci		set_opt(sb, GRPID);
436362306a36Sopenharmony_ci	if (def_mount_opts & EXT4_DEFM_UID16)
436462306a36Sopenharmony_ci		set_opt(sb, NO_UID32);
436562306a36Sopenharmony_ci	/* xattr user namespace & acls are now defaulted on */
436662306a36Sopenharmony_ci	set_opt(sb, XATTR_USER);
436762306a36Sopenharmony_ci#ifdef CONFIG_EXT4_FS_POSIX_ACL
436862306a36Sopenharmony_ci	set_opt(sb, POSIX_ACL);
436962306a36Sopenharmony_ci#endif
437062306a36Sopenharmony_ci	if (ext4_has_feature_fast_commit(sb))
437162306a36Sopenharmony_ci		set_opt2(sb, JOURNAL_FAST_COMMIT);
437262306a36Sopenharmony_ci	/* don't forget to enable journal_csum when metadata_csum is enabled. */
437362306a36Sopenharmony_ci	if (ext4_has_metadata_csum(sb))
437462306a36Sopenharmony_ci		set_opt(sb, JOURNAL_CHECKSUM);
437562306a36Sopenharmony_ci
437662306a36Sopenharmony_ci	if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_DATA)
437762306a36Sopenharmony_ci		set_opt(sb, JOURNAL_DATA);
437862306a36Sopenharmony_ci	else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_ORDERED)
437962306a36Sopenharmony_ci		set_opt(sb, ORDERED_DATA);
438062306a36Sopenharmony_ci	else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_WBACK)
438162306a36Sopenharmony_ci		set_opt(sb, WRITEBACK_DATA);
438262306a36Sopenharmony_ci
438362306a36Sopenharmony_ci	if (le16_to_cpu(es->s_errors) == EXT4_ERRORS_PANIC)
438462306a36Sopenharmony_ci		set_opt(sb, ERRORS_PANIC);
438562306a36Sopenharmony_ci	else if (le16_to_cpu(es->s_errors) == EXT4_ERRORS_CONTINUE)
438662306a36Sopenharmony_ci		set_opt(sb, ERRORS_CONT);
438762306a36Sopenharmony_ci	else
438862306a36Sopenharmony_ci		set_opt(sb, ERRORS_RO);
438962306a36Sopenharmony_ci	/* block_validity enabled by default; disable with noblock_validity */
439062306a36Sopenharmony_ci	set_opt(sb, BLOCK_VALIDITY);
439162306a36Sopenharmony_ci	if (def_mount_opts & EXT4_DEFM_DISCARD)
439262306a36Sopenharmony_ci		set_opt(sb, DISCARD);
439362306a36Sopenharmony_ci
439462306a36Sopenharmony_ci	if ((def_mount_opts & EXT4_DEFM_NOBARRIER) == 0)
439562306a36Sopenharmony_ci		set_opt(sb, BARRIER);
439662306a36Sopenharmony_ci
439762306a36Sopenharmony_ci	/*
439862306a36Sopenharmony_ci	 * enable delayed allocation by default
439962306a36Sopenharmony_ci	 * Use -o nodelalloc to turn it off
440062306a36Sopenharmony_ci	 */
440162306a36Sopenharmony_ci	if (!IS_EXT3_SB(sb) && !IS_EXT2_SB(sb) &&
440262306a36Sopenharmony_ci	    ((def_mount_opts & EXT4_DEFM_NODELALLOC) == 0))
440362306a36Sopenharmony_ci		set_opt(sb, DELALLOC);
440462306a36Sopenharmony_ci
440562306a36Sopenharmony_ci	if (sb->s_blocksize == PAGE_SIZE)
440662306a36Sopenharmony_ci		set_opt(sb, DIOREAD_NOLOCK);
440762306a36Sopenharmony_ci}
440862306a36Sopenharmony_ci
440962306a36Sopenharmony_cistatic int ext4_handle_clustersize(struct super_block *sb)
441062306a36Sopenharmony_ci{
441162306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
441262306a36Sopenharmony_ci	struct ext4_super_block *es = sbi->s_es;
441362306a36Sopenharmony_ci	int clustersize;
441462306a36Sopenharmony_ci
441562306a36Sopenharmony_ci	/* Handle clustersize */
441662306a36Sopenharmony_ci	clustersize = BLOCK_SIZE << le32_to_cpu(es->s_log_cluster_size);
441762306a36Sopenharmony_ci	if (ext4_has_feature_bigalloc(sb)) {
441862306a36Sopenharmony_ci		if (clustersize < sb->s_blocksize) {
441962306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR,
442062306a36Sopenharmony_ci				 "cluster size (%d) smaller than "
442162306a36Sopenharmony_ci				 "block size (%lu)", clustersize, sb->s_blocksize);
442262306a36Sopenharmony_ci			return -EINVAL;
442362306a36Sopenharmony_ci		}
442462306a36Sopenharmony_ci		sbi->s_cluster_bits = le32_to_cpu(es->s_log_cluster_size) -
442562306a36Sopenharmony_ci			le32_to_cpu(es->s_log_block_size);
442662306a36Sopenharmony_ci		sbi->s_clusters_per_group =
442762306a36Sopenharmony_ci			le32_to_cpu(es->s_clusters_per_group);
442862306a36Sopenharmony_ci		if (sbi->s_clusters_per_group > sb->s_blocksize * 8) {
442962306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR,
443062306a36Sopenharmony_ci				 "#clusters per group too big: %lu",
443162306a36Sopenharmony_ci				 sbi->s_clusters_per_group);
443262306a36Sopenharmony_ci			return -EINVAL;
443362306a36Sopenharmony_ci		}
443462306a36Sopenharmony_ci		if (sbi->s_blocks_per_group !=
443562306a36Sopenharmony_ci		    (sbi->s_clusters_per_group * (clustersize / sb->s_blocksize))) {
443662306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "blocks per group (%lu) and "
443762306a36Sopenharmony_ci				 "clusters per group (%lu) inconsistent",
443862306a36Sopenharmony_ci				 sbi->s_blocks_per_group,
443962306a36Sopenharmony_ci				 sbi->s_clusters_per_group);
444062306a36Sopenharmony_ci			return -EINVAL;
444162306a36Sopenharmony_ci		}
444262306a36Sopenharmony_ci	} else {
444362306a36Sopenharmony_ci		if (clustersize != sb->s_blocksize) {
444462306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR,
444562306a36Sopenharmony_ci				 "fragment/cluster size (%d) != "
444662306a36Sopenharmony_ci				 "block size (%lu)", clustersize, sb->s_blocksize);
444762306a36Sopenharmony_ci			return -EINVAL;
444862306a36Sopenharmony_ci		}
444962306a36Sopenharmony_ci		if (sbi->s_blocks_per_group > sb->s_blocksize * 8) {
445062306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR,
445162306a36Sopenharmony_ci				 "#blocks per group too big: %lu",
445262306a36Sopenharmony_ci				 sbi->s_blocks_per_group);
445362306a36Sopenharmony_ci			return -EINVAL;
445462306a36Sopenharmony_ci		}
445562306a36Sopenharmony_ci		sbi->s_clusters_per_group = sbi->s_blocks_per_group;
445662306a36Sopenharmony_ci		sbi->s_cluster_bits = 0;
445762306a36Sopenharmony_ci	}
445862306a36Sopenharmony_ci	sbi->s_cluster_ratio = clustersize / sb->s_blocksize;
445962306a36Sopenharmony_ci
446062306a36Sopenharmony_ci	/* Do we have standard group size of clustersize * 8 blocks ? */
446162306a36Sopenharmony_ci	if (sbi->s_blocks_per_group == clustersize << 3)
446262306a36Sopenharmony_ci		set_opt2(sb, STD_GROUP_SIZE);
446362306a36Sopenharmony_ci
446462306a36Sopenharmony_ci	return 0;
446562306a36Sopenharmony_ci}
446662306a36Sopenharmony_ci
446762306a36Sopenharmony_cistatic void ext4_fast_commit_init(struct super_block *sb)
446862306a36Sopenharmony_ci{
446962306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
447062306a36Sopenharmony_ci
447162306a36Sopenharmony_ci	/* Initialize fast commit stuff */
447262306a36Sopenharmony_ci	atomic_set(&sbi->s_fc_subtid, 0);
447362306a36Sopenharmony_ci	INIT_LIST_HEAD(&sbi->s_fc_q[FC_Q_MAIN]);
447462306a36Sopenharmony_ci	INIT_LIST_HEAD(&sbi->s_fc_q[FC_Q_STAGING]);
447562306a36Sopenharmony_ci	INIT_LIST_HEAD(&sbi->s_fc_dentry_q[FC_Q_MAIN]);
447662306a36Sopenharmony_ci	INIT_LIST_HEAD(&sbi->s_fc_dentry_q[FC_Q_STAGING]);
447762306a36Sopenharmony_ci	sbi->s_fc_bytes = 0;
447862306a36Sopenharmony_ci	ext4_clear_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
447962306a36Sopenharmony_ci	sbi->s_fc_ineligible_tid = 0;
448062306a36Sopenharmony_ci	spin_lock_init(&sbi->s_fc_lock);
448162306a36Sopenharmony_ci	memset(&sbi->s_fc_stats, 0, sizeof(sbi->s_fc_stats));
448262306a36Sopenharmony_ci	sbi->s_fc_replay_state.fc_regions = NULL;
448362306a36Sopenharmony_ci	sbi->s_fc_replay_state.fc_regions_size = 0;
448462306a36Sopenharmony_ci	sbi->s_fc_replay_state.fc_regions_used = 0;
448562306a36Sopenharmony_ci	sbi->s_fc_replay_state.fc_regions_valid = 0;
448662306a36Sopenharmony_ci	sbi->s_fc_replay_state.fc_modified_inodes = NULL;
448762306a36Sopenharmony_ci	sbi->s_fc_replay_state.fc_modified_inodes_size = 0;
448862306a36Sopenharmony_ci	sbi->s_fc_replay_state.fc_modified_inodes_used = 0;
448962306a36Sopenharmony_ci}
449062306a36Sopenharmony_ci
449162306a36Sopenharmony_cistatic int ext4_inode_info_init(struct super_block *sb,
449262306a36Sopenharmony_ci				struct ext4_super_block *es)
449362306a36Sopenharmony_ci{
449462306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
449562306a36Sopenharmony_ci
449662306a36Sopenharmony_ci	if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) {
449762306a36Sopenharmony_ci		sbi->s_inode_size = EXT4_GOOD_OLD_INODE_SIZE;
449862306a36Sopenharmony_ci		sbi->s_first_ino = EXT4_GOOD_OLD_FIRST_INO;
449962306a36Sopenharmony_ci	} else {
450062306a36Sopenharmony_ci		sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
450162306a36Sopenharmony_ci		sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
450262306a36Sopenharmony_ci		if (sbi->s_first_ino < EXT4_GOOD_OLD_FIRST_INO) {
450362306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "invalid first ino: %u",
450462306a36Sopenharmony_ci				 sbi->s_first_ino);
450562306a36Sopenharmony_ci			return -EINVAL;
450662306a36Sopenharmony_ci		}
450762306a36Sopenharmony_ci		if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) ||
450862306a36Sopenharmony_ci		    (!is_power_of_2(sbi->s_inode_size)) ||
450962306a36Sopenharmony_ci		    (sbi->s_inode_size > sb->s_blocksize)) {
451062306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR,
451162306a36Sopenharmony_ci			       "unsupported inode size: %d",
451262306a36Sopenharmony_ci			       sbi->s_inode_size);
451362306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "blocksize: %lu", sb->s_blocksize);
451462306a36Sopenharmony_ci			return -EINVAL;
451562306a36Sopenharmony_ci		}
451662306a36Sopenharmony_ci		/*
451762306a36Sopenharmony_ci		 * i_atime_extra is the last extra field available for
451862306a36Sopenharmony_ci		 * [acm]times in struct ext4_inode. Checking for that
451962306a36Sopenharmony_ci		 * field should suffice to ensure we have extra space
452062306a36Sopenharmony_ci		 * for all three.
452162306a36Sopenharmony_ci		 */
452262306a36Sopenharmony_ci		if (sbi->s_inode_size >= offsetof(struct ext4_inode, i_atime_extra) +
452362306a36Sopenharmony_ci			sizeof(((struct ext4_inode *)0)->i_atime_extra)) {
452462306a36Sopenharmony_ci			sb->s_time_gran = 1;
452562306a36Sopenharmony_ci			sb->s_time_max = EXT4_EXTRA_TIMESTAMP_MAX;
452662306a36Sopenharmony_ci		} else {
452762306a36Sopenharmony_ci			sb->s_time_gran = NSEC_PER_SEC;
452862306a36Sopenharmony_ci			sb->s_time_max = EXT4_NON_EXTRA_TIMESTAMP_MAX;
452962306a36Sopenharmony_ci		}
453062306a36Sopenharmony_ci		sb->s_time_min = EXT4_TIMESTAMP_MIN;
453162306a36Sopenharmony_ci	}
453262306a36Sopenharmony_ci
453362306a36Sopenharmony_ci	if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
453462306a36Sopenharmony_ci		sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
453562306a36Sopenharmony_ci			EXT4_GOOD_OLD_INODE_SIZE;
453662306a36Sopenharmony_ci		if (ext4_has_feature_extra_isize(sb)) {
453762306a36Sopenharmony_ci			unsigned v, max = (sbi->s_inode_size -
453862306a36Sopenharmony_ci					   EXT4_GOOD_OLD_INODE_SIZE);
453962306a36Sopenharmony_ci
454062306a36Sopenharmony_ci			v = le16_to_cpu(es->s_want_extra_isize);
454162306a36Sopenharmony_ci			if (v > max) {
454262306a36Sopenharmony_ci				ext4_msg(sb, KERN_ERR,
454362306a36Sopenharmony_ci					 "bad s_want_extra_isize: %d", v);
454462306a36Sopenharmony_ci				return -EINVAL;
454562306a36Sopenharmony_ci			}
454662306a36Sopenharmony_ci			if (sbi->s_want_extra_isize < v)
454762306a36Sopenharmony_ci				sbi->s_want_extra_isize = v;
454862306a36Sopenharmony_ci
454962306a36Sopenharmony_ci			v = le16_to_cpu(es->s_min_extra_isize);
455062306a36Sopenharmony_ci			if (v > max) {
455162306a36Sopenharmony_ci				ext4_msg(sb, KERN_ERR,
455262306a36Sopenharmony_ci					 "bad s_min_extra_isize: %d", v);
455362306a36Sopenharmony_ci				return -EINVAL;
455462306a36Sopenharmony_ci			}
455562306a36Sopenharmony_ci			if (sbi->s_want_extra_isize < v)
455662306a36Sopenharmony_ci				sbi->s_want_extra_isize = v;
455762306a36Sopenharmony_ci		}
455862306a36Sopenharmony_ci	}
455962306a36Sopenharmony_ci
456062306a36Sopenharmony_ci	return 0;
456162306a36Sopenharmony_ci}
456262306a36Sopenharmony_ci
456362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE)
456462306a36Sopenharmony_cistatic int ext4_encoding_init(struct super_block *sb, struct ext4_super_block *es)
456562306a36Sopenharmony_ci{
456662306a36Sopenharmony_ci	const struct ext4_sb_encodings *encoding_info;
456762306a36Sopenharmony_ci	struct unicode_map *encoding;
456862306a36Sopenharmony_ci	__u16 encoding_flags = le16_to_cpu(es->s_encoding_flags);
456962306a36Sopenharmony_ci
457062306a36Sopenharmony_ci	if (!ext4_has_feature_casefold(sb) || sb->s_encoding)
457162306a36Sopenharmony_ci		return 0;
457262306a36Sopenharmony_ci
457362306a36Sopenharmony_ci	encoding_info = ext4_sb_read_encoding(es);
457462306a36Sopenharmony_ci	if (!encoding_info) {
457562306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR,
457662306a36Sopenharmony_ci			"Encoding requested by superblock is unknown");
457762306a36Sopenharmony_ci		return -EINVAL;
457862306a36Sopenharmony_ci	}
457962306a36Sopenharmony_ci
458062306a36Sopenharmony_ci	encoding = utf8_load(encoding_info->version);
458162306a36Sopenharmony_ci	if (IS_ERR(encoding)) {
458262306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR,
458362306a36Sopenharmony_ci			"can't mount with superblock charset: %s-%u.%u.%u "
458462306a36Sopenharmony_ci			"not supported by the kernel. flags: 0x%x.",
458562306a36Sopenharmony_ci			encoding_info->name,
458662306a36Sopenharmony_ci			unicode_major(encoding_info->version),
458762306a36Sopenharmony_ci			unicode_minor(encoding_info->version),
458862306a36Sopenharmony_ci			unicode_rev(encoding_info->version),
458962306a36Sopenharmony_ci			encoding_flags);
459062306a36Sopenharmony_ci		return -EINVAL;
459162306a36Sopenharmony_ci	}
459262306a36Sopenharmony_ci	ext4_msg(sb, KERN_INFO,"Using encoding defined by superblock: "
459362306a36Sopenharmony_ci		"%s-%u.%u.%u with flags 0x%hx", encoding_info->name,
459462306a36Sopenharmony_ci		unicode_major(encoding_info->version),
459562306a36Sopenharmony_ci		unicode_minor(encoding_info->version),
459662306a36Sopenharmony_ci		unicode_rev(encoding_info->version),
459762306a36Sopenharmony_ci		encoding_flags);
459862306a36Sopenharmony_ci
459962306a36Sopenharmony_ci	sb->s_encoding = encoding;
460062306a36Sopenharmony_ci	sb->s_encoding_flags = encoding_flags;
460162306a36Sopenharmony_ci
460262306a36Sopenharmony_ci	return 0;
460362306a36Sopenharmony_ci}
460462306a36Sopenharmony_ci#else
460562306a36Sopenharmony_cistatic inline int ext4_encoding_init(struct super_block *sb, struct ext4_super_block *es)
460662306a36Sopenharmony_ci{
460762306a36Sopenharmony_ci	return 0;
460862306a36Sopenharmony_ci}
460962306a36Sopenharmony_ci#endif
461062306a36Sopenharmony_ci
461162306a36Sopenharmony_cistatic int ext4_init_metadata_csum(struct super_block *sb, struct ext4_super_block *es)
461262306a36Sopenharmony_ci{
461362306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
461462306a36Sopenharmony_ci
461562306a36Sopenharmony_ci	/* Warn if metadata_csum and gdt_csum are both set. */
461662306a36Sopenharmony_ci	if (ext4_has_feature_metadata_csum(sb) &&
461762306a36Sopenharmony_ci	    ext4_has_feature_gdt_csum(sb))
461862306a36Sopenharmony_ci		ext4_warning(sb, "metadata_csum and uninit_bg are "
461962306a36Sopenharmony_ci			     "redundant flags; please run fsck.");
462062306a36Sopenharmony_ci
462162306a36Sopenharmony_ci	/* Check for a known checksum algorithm */
462262306a36Sopenharmony_ci	if (!ext4_verify_csum_type(sb, es)) {
462362306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "VFS: Found ext4 filesystem with "
462462306a36Sopenharmony_ci			 "unknown checksum algorithm.");
462562306a36Sopenharmony_ci		return -EINVAL;
462662306a36Sopenharmony_ci	}
462762306a36Sopenharmony_ci	ext4_setup_csum_trigger(sb, EXT4_JTR_ORPHAN_FILE,
462862306a36Sopenharmony_ci				ext4_orphan_file_block_trigger);
462962306a36Sopenharmony_ci
463062306a36Sopenharmony_ci	/* Load the checksum driver */
463162306a36Sopenharmony_ci	sbi->s_chksum_driver = crypto_alloc_shash("crc32c", 0, 0);
463262306a36Sopenharmony_ci	if (IS_ERR(sbi->s_chksum_driver)) {
463362306a36Sopenharmony_ci		int ret = PTR_ERR(sbi->s_chksum_driver);
463462306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "Cannot load crc32c driver.");
463562306a36Sopenharmony_ci		sbi->s_chksum_driver = NULL;
463662306a36Sopenharmony_ci		return ret;
463762306a36Sopenharmony_ci	}
463862306a36Sopenharmony_ci
463962306a36Sopenharmony_ci	/* Check superblock checksum */
464062306a36Sopenharmony_ci	if (!ext4_superblock_csum_verify(sb, es)) {
464162306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "VFS: Found ext4 filesystem with "
464262306a36Sopenharmony_ci			 "invalid superblock checksum.  Run e2fsck?");
464362306a36Sopenharmony_ci		return -EFSBADCRC;
464462306a36Sopenharmony_ci	}
464562306a36Sopenharmony_ci
464662306a36Sopenharmony_ci	/* Precompute checksum seed for all metadata */
464762306a36Sopenharmony_ci	if (ext4_has_feature_csum_seed(sb))
464862306a36Sopenharmony_ci		sbi->s_csum_seed = le32_to_cpu(es->s_checksum_seed);
464962306a36Sopenharmony_ci	else if (ext4_has_metadata_csum(sb) || ext4_has_feature_ea_inode(sb))
465062306a36Sopenharmony_ci		sbi->s_csum_seed = ext4_chksum(sbi, ~0, es->s_uuid,
465162306a36Sopenharmony_ci					       sizeof(es->s_uuid));
465262306a36Sopenharmony_ci	return 0;
465362306a36Sopenharmony_ci}
465462306a36Sopenharmony_ci
465562306a36Sopenharmony_cistatic int ext4_check_feature_compatibility(struct super_block *sb,
465662306a36Sopenharmony_ci					    struct ext4_super_block *es,
465762306a36Sopenharmony_ci					    int silent)
465862306a36Sopenharmony_ci{
465962306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
466062306a36Sopenharmony_ci
466162306a36Sopenharmony_ci	if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV &&
466262306a36Sopenharmony_ci	    (ext4_has_compat_features(sb) ||
466362306a36Sopenharmony_ci	     ext4_has_ro_compat_features(sb) ||
466462306a36Sopenharmony_ci	     ext4_has_incompat_features(sb)))
466562306a36Sopenharmony_ci		ext4_msg(sb, KERN_WARNING,
466662306a36Sopenharmony_ci		       "feature flags set on rev 0 fs, "
466762306a36Sopenharmony_ci		       "running e2fsck is recommended");
466862306a36Sopenharmony_ci
466962306a36Sopenharmony_ci	if (es->s_creator_os == cpu_to_le32(EXT4_OS_HURD)) {
467062306a36Sopenharmony_ci		set_opt2(sb, HURD_COMPAT);
467162306a36Sopenharmony_ci		if (ext4_has_feature_64bit(sb)) {
467262306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR,
467362306a36Sopenharmony_ci				 "The Hurd can't support 64-bit file systems");
467462306a36Sopenharmony_ci			return -EINVAL;
467562306a36Sopenharmony_ci		}
467662306a36Sopenharmony_ci
467762306a36Sopenharmony_ci		/*
467862306a36Sopenharmony_ci		 * ea_inode feature uses l_i_version field which is not
467962306a36Sopenharmony_ci		 * available in HURD_COMPAT mode.
468062306a36Sopenharmony_ci		 */
468162306a36Sopenharmony_ci		if (ext4_has_feature_ea_inode(sb)) {
468262306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR,
468362306a36Sopenharmony_ci				 "ea_inode feature is not supported for Hurd");
468462306a36Sopenharmony_ci			return -EINVAL;
468562306a36Sopenharmony_ci		}
468662306a36Sopenharmony_ci	}
468762306a36Sopenharmony_ci
468862306a36Sopenharmony_ci	if (IS_EXT2_SB(sb)) {
468962306a36Sopenharmony_ci		if (ext2_feature_set_ok(sb))
469062306a36Sopenharmony_ci			ext4_msg(sb, KERN_INFO, "mounting ext2 file system "
469162306a36Sopenharmony_ci				 "using the ext4 subsystem");
469262306a36Sopenharmony_ci		else {
469362306a36Sopenharmony_ci			/*
469462306a36Sopenharmony_ci			 * If we're probing be silent, if this looks like
469562306a36Sopenharmony_ci			 * it's actually an ext[34] filesystem.
469662306a36Sopenharmony_ci			 */
469762306a36Sopenharmony_ci			if (silent && ext4_feature_set_ok(sb, sb_rdonly(sb)))
469862306a36Sopenharmony_ci				return -EINVAL;
469962306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "couldn't mount as ext2 due "
470062306a36Sopenharmony_ci				 "to feature incompatibilities");
470162306a36Sopenharmony_ci			return -EINVAL;
470262306a36Sopenharmony_ci		}
470362306a36Sopenharmony_ci	}
470462306a36Sopenharmony_ci
470562306a36Sopenharmony_ci	if (IS_EXT3_SB(sb)) {
470662306a36Sopenharmony_ci		if (ext3_feature_set_ok(sb))
470762306a36Sopenharmony_ci			ext4_msg(sb, KERN_INFO, "mounting ext3 file system "
470862306a36Sopenharmony_ci				 "using the ext4 subsystem");
470962306a36Sopenharmony_ci		else {
471062306a36Sopenharmony_ci			/*
471162306a36Sopenharmony_ci			 * If we're probing be silent, if this looks like
471262306a36Sopenharmony_ci			 * it's actually an ext4 filesystem.
471362306a36Sopenharmony_ci			 */
471462306a36Sopenharmony_ci			if (silent && ext4_feature_set_ok(sb, sb_rdonly(sb)))
471562306a36Sopenharmony_ci				return -EINVAL;
471662306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "couldn't mount as ext3 due "
471762306a36Sopenharmony_ci				 "to feature incompatibilities");
471862306a36Sopenharmony_ci			return -EINVAL;
471962306a36Sopenharmony_ci		}
472062306a36Sopenharmony_ci	}
472162306a36Sopenharmony_ci
472262306a36Sopenharmony_ci	/*
472362306a36Sopenharmony_ci	 * Check feature flags regardless of the revision level, since we
472462306a36Sopenharmony_ci	 * previously didn't change the revision level when setting the flags,
472562306a36Sopenharmony_ci	 * so there is a chance incompat flags are set on a rev 0 filesystem.
472662306a36Sopenharmony_ci	 */
472762306a36Sopenharmony_ci	if (!ext4_feature_set_ok(sb, (sb_rdonly(sb))))
472862306a36Sopenharmony_ci		return -EINVAL;
472962306a36Sopenharmony_ci
473062306a36Sopenharmony_ci	if (sbi->s_daxdev) {
473162306a36Sopenharmony_ci		if (sb->s_blocksize == PAGE_SIZE)
473262306a36Sopenharmony_ci			set_bit(EXT4_FLAGS_BDEV_IS_DAX, &sbi->s_ext4_flags);
473362306a36Sopenharmony_ci		else
473462306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "unsupported blocksize for DAX\n");
473562306a36Sopenharmony_ci	}
473662306a36Sopenharmony_ci
473762306a36Sopenharmony_ci	if (sbi->s_mount_opt & EXT4_MOUNT_DAX_ALWAYS) {
473862306a36Sopenharmony_ci		if (ext4_has_feature_inline_data(sb)) {
473962306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "Cannot use DAX on a filesystem"
474062306a36Sopenharmony_ci					" that may contain inline data");
474162306a36Sopenharmony_ci			return -EINVAL;
474262306a36Sopenharmony_ci		}
474362306a36Sopenharmony_ci		if (!test_bit(EXT4_FLAGS_BDEV_IS_DAX, &sbi->s_ext4_flags)) {
474462306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR,
474562306a36Sopenharmony_ci				"DAX unsupported by block device.");
474662306a36Sopenharmony_ci			return -EINVAL;
474762306a36Sopenharmony_ci		}
474862306a36Sopenharmony_ci	}
474962306a36Sopenharmony_ci
475062306a36Sopenharmony_ci	if (ext4_has_feature_encrypt(sb) && es->s_encryption_level) {
475162306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "Unsupported encryption level %d",
475262306a36Sopenharmony_ci			 es->s_encryption_level);
475362306a36Sopenharmony_ci		return -EINVAL;
475462306a36Sopenharmony_ci	}
475562306a36Sopenharmony_ci
475662306a36Sopenharmony_ci	return 0;
475762306a36Sopenharmony_ci}
475862306a36Sopenharmony_ci
475962306a36Sopenharmony_cistatic int ext4_check_geometry(struct super_block *sb,
476062306a36Sopenharmony_ci			       struct ext4_super_block *es)
476162306a36Sopenharmony_ci{
476262306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
476362306a36Sopenharmony_ci	__u64 blocks_count;
476462306a36Sopenharmony_ci	int err;
476562306a36Sopenharmony_ci
476662306a36Sopenharmony_ci	if (le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) > (sb->s_blocksize / 4)) {
476762306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR,
476862306a36Sopenharmony_ci			 "Number of reserved GDT blocks insanely large: %d",
476962306a36Sopenharmony_ci			 le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks));
477062306a36Sopenharmony_ci		return -EINVAL;
477162306a36Sopenharmony_ci	}
477262306a36Sopenharmony_ci	/*
477362306a36Sopenharmony_ci	 * Test whether we have more sectors than will fit in sector_t,
477462306a36Sopenharmony_ci	 * and whether the max offset is addressable by the page cache.
477562306a36Sopenharmony_ci	 */
477662306a36Sopenharmony_ci	err = generic_check_addressable(sb->s_blocksize_bits,
477762306a36Sopenharmony_ci					ext4_blocks_count(es));
477862306a36Sopenharmony_ci	if (err) {
477962306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "filesystem"
478062306a36Sopenharmony_ci			 " too large to mount safely on this system");
478162306a36Sopenharmony_ci		return err;
478262306a36Sopenharmony_ci	}
478362306a36Sopenharmony_ci
478462306a36Sopenharmony_ci	/* check blocks count against device size */
478562306a36Sopenharmony_ci	blocks_count = sb_bdev_nr_blocks(sb);
478662306a36Sopenharmony_ci	if (blocks_count && ext4_blocks_count(es) > blocks_count) {
478762306a36Sopenharmony_ci		ext4_msg(sb, KERN_WARNING, "bad geometry: block count %llu "
478862306a36Sopenharmony_ci		       "exceeds size of device (%llu blocks)",
478962306a36Sopenharmony_ci		       ext4_blocks_count(es), blocks_count);
479062306a36Sopenharmony_ci		return -EINVAL;
479162306a36Sopenharmony_ci	}
479262306a36Sopenharmony_ci
479362306a36Sopenharmony_ci	/*
479462306a36Sopenharmony_ci	 * It makes no sense for the first data block to be beyond the end
479562306a36Sopenharmony_ci	 * of the filesystem.
479662306a36Sopenharmony_ci	 */
479762306a36Sopenharmony_ci	if (le32_to_cpu(es->s_first_data_block) >= ext4_blocks_count(es)) {
479862306a36Sopenharmony_ci		ext4_msg(sb, KERN_WARNING, "bad geometry: first data "
479962306a36Sopenharmony_ci			 "block %u is beyond end of filesystem (%llu)",
480062306a36Sopenharmony_ci			 le32_to_cpu(es->s_first_data_block),
480162306a36Sopenharmony_ci			 ext4_blocks_count(es));
480262306a36Sopenharmony_ci		return -EINVAL;
480362306a36Sopenharmony_ci	}
480462306a36Sopenharmony_ci	if ((es->s_first_data_block == 0) && (es->s_log_block_size == 0) &&
480562306a36Sopenharmony_ci	    (sbi->s_cluster_ratio == 1)) {
480662306a36Sopenharmony_ci		ext4_msg(sb, KERN_WARNING, "bad geometry: first data "
480762306a36Sopenharmony_ci			 "block is 0 with a 1k block and cluster size");
480862306a36Sopenharmony_ci		return -EINVAL;
480962306a36Sopenharmony_ci	}
481062306a36Sopenharmony_ci
481162306a36Sopenharmony_ci	blocks_count = (ext4_blocks_count(es) -
481262306a36Sopenharmony_ci			le32_to_cpu(es->s_first_data_block) +
481362306a36Sopenharmony_ci			EXT4_BLOCKS_PER_GROUP(sb) - 1);
481462306a36Sopenharmony_ci	do_div(blocks_count, EXT4_BLOCKS_PER_GROUP(sb));
481562306a36Sopenharmony_ci	if (blocks_count > ((uint64_t)1<<32) - EXT4_DESC_PER_BLOCK(sb)) {
481662306a36Sopenharmony_ci		ext4_msg(sb, KERN_WARNING, "groups count too large: %llu "
481762306a36Sopenharmony_ci		       "(block count %llu, first data block %u, "
481862306a36Sopenharmony_ci		       "blocks per group %lu)", blocks_count,
481962306a36Sopenharmony_ci		       ext4_blocks_count(es),
482062306a36Sopenharmony_ci		       le32_to_cpu(es->s_first_data_block),
482162306a36Sopenharmony_ci		       EXT4_BLOCKS_PER_GROUP(sb));
482262306a36Sopenharmony_ci		return -EINVAL;
482362306a36Sopenharmony_ci	}
482462306a36Sopenharmony_ci	sbi->s_groups_count = blocks_count;
482562306a36Sopenharmony_ci	sbi->s_blockfile_groups = min_t(ext4_group_t, sbi->s_groups_count,
482662306a36Sopenharmony_ci			(EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb)));
482762306a36Sopenharmony_ci	if (((u64)sbi->s_groups_count * sbi->s_inodes_per_group) !=
482862306a36Sopenharmony_ci	    le32_to_cpu(es->s_inodes_count)) {
482962306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "inodes count not valid: %u vs %llu",
483062306a36Sopenharmony_ci			 le32_to_cpu(es->s_inodes_count),
483162306a36Sopenharmony_ci			 ((u64)sbi->s_groups_count * sbi->s_inodes_per_group));
483262306a36Sopenharmony_ci		return -EINVAL;
483362306a36Sopenharmony_ci	}
483462306a36Sopenharmony_ci
483562306a36Sopenharmony_ci	return 0;
483662306a36Sopenharmony_ci}
483762306a36Sopenharmony_ci
483862306a36Sopenharmony_cistatic int ext4_group_desc_init(struct super_block *sb,
483962306a36Sopenharmony_ci				struct ext4_super_block *es,
484062306a36Sopenharmony_ci				ext4_fsblk_t logical_sb_block,
484162306a36Sopenharmony_ci				ext4_group_t *first_not_zeroed)
484262306a36Sopenharmony_ci{
484362306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
484462306a36Sopenharmony_ci	unsigned int db_count;
484562306a36Sopenharmony_ci	ext4_fsblk_t block;
484662306a36Sopenharmony_ci	int i;
484762306a36Sopenharmony_ci
484862306a36Sopenharmony_ci	db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) /
484962306a36Sopenharmony_ci		   EXT4_DESC_PER_BLOCK(sb);
485062306a36Sopenharmony_ci	if (ext4_has_feature_meta_bg(sb)) {
485162306a36Sopenharmony_ci		if (le32_to_cpu(es->s_first_meta_bg) > db_count) {
485262306a36Sopenharmony_ci			ext4_msg(sb, KERN_WARNING,
485362306a36Sopenharmony_ci				 "first meta block group too large: %u "
485462306a36Sopenharmony_ci				 "(group descriptor block count %u)",
485562306a36Sopenharmony_ci				 le32_to_cpu(es->s_first_meta_bg), db_count);
485662306a36Sopenharmony_ci			return -EINVAL;
485762306a36Sopenharmony_ci		}
485862306a36Sopenharmony_ci	}
485962306a36Sopenharmony_ci	rcu_assign_pointer(sbi->s_group_desc,
486062306a36Sopenharmony_ci			   kvmalloc_array(db_count,
486162306a36Sopenharmony_ci					  sizeof(struct buffer_head *),
486262306a36Sopenharmony_ci					  GFP_KERNEL));
486362306a36Sopenharmony_ci	if (sbi->s_group_desc == NULL) {
486462306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "not enough memory");
486562306a36Sopenharmony_ci		return -ENOMEM;
486662306a36Sopenharmony_ci	}
486762306a36Sopenharmony_ci
486862306a36Sopenharmony_ci	bgl_lock_init(sbi->s_blockgroup_lock);
486962306a36Sopenharmony_ci
487062306a36Sopenharmony_ci	/* Pre-read the descriptors into the buffer cache */
487162306a36Sopenharmony_ci	for (i = 0; i < db_count; i++) {
487262306a36Sopenharmony_ci		block = descriptor_loc(sb, logical_sb_block, i);
487362306a36Sopenharmony_ci		ext4_sb_breadahead_unmovable(sb, block);
487462306a36Sopenharmony_ci	}
487562306a36Sopenharmony_ci
487662306a36Sopenharmony_ci	for (i = 0; i < db_count; i++) {
487762306a36Sopenharmony_ci		struct buffer_head *bh;
487862306a36Sopenharmony_ci
487962306a36Sopenharmony_ci		block = descriptor_loc(sb, logical_sb_block, i);
488062306a36Sopenharmony_ci		bh = ext4_sb_bread_unmovable(sb, block);
488162306a36Sopenharmony_ci		if (IS_ERR(bh)) {
488262306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR,
488362306a36Sopenharmony_ci			       "can't read group descriptor %d", i);
488462306a36Sopenharmony_ci			sbi->s_gdb_count = i;
488562306a36Sopenharmony_ci			return PTR_ERR(bh);
488662306a36Sopenharmony_ci		}
488762306a36Sopenharmony_ci		rcu_read_lock();
488862306a36Sopenharmony_ci		rcu_dereference(sbi->s_group_desc)[i] = bh;
488962306a36Sopenharmony_ci		rcu_read_unlock();
489062306a36Sopenharmony_ci	}
489162306a36Sopenharmony_ci	sbi->s_gdb_count = db_count;
489262306a36Sopenharmony_ci	if (!ext4_check_descriptors(sb, logical_sb_block, first_not_zeroed)) {
489362306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "group descriptors corrupted!");
489462306a36Sopenharmony_ci		return -EFSCORRUPTED;
489562306a36Sopenharmony_ci	}
489662306a36Sopenharmony_ci
489762306a36Sopenharmony_ci	return 0;
489862306a36Sopenharmony_ci}
489962306a36Sopenharmony_ci
490062306a36Sopenharmony_cistatic int ext4_load_and_init_journal(struct super_block *sb,
490162306a36Sopenharmony_ci				      struct ext4_super_block *es,
490262306a36Sopenharmony_ci				      struct ext4_fs_context *ctx)
490362306a36Sopenharmony_ci{
490462306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
490562306a36Sopenharmony_ci	int err;
490662306a36Sopenharmony_ci
490762306a36Sopenharmony_ci	err = ext4_load_journal(sb, es, ctx->journal_devnum);
490862306a36Sopenharmony_ci	if (err)
490962306a36Sopenharmony_ci		return err;
491062306a36Sopenharmony_ci
491162306a36Sopenharmony_ci	if (ext4_has_feature_64bit(sb) &&
491262306a36Sopenharmony_ci	    !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0,
491362306a36Sopenharmony_ci				       JBD2_FEATURE_INCOMPAT_64BIT)) {
491462306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "Failed to set 64-bit journal feature");
491562306a36Sopenharmony_ci		goto out;
491662306a36Sopenharmony_ci	}
491762306a36Sopenharmony_ci
491862306a36Sopenharmony_ci	if (!set_journal_csum_feature_set(sb)) {
491962306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "Failed to set journal checksum "
492062306a36Sopenharmony_ci			 "feature set");
492162306a36Sopenharmony_ci		goto out;
492262306a36Sopenharmony_ci	}
492362306a36Sopenharmony_ci
492462306a36Sopenharmony_ci	if (test_opt2(sb, JOURNAL_FAST_COMMIT) &&
492562306a36Sopenharmony_ci		!jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0,
492662306a36Sopenharmony_ci					  JBD2_FEATURE_INCOMPAT_FAST_COMMIT)) {
492762306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR,
492862306a36Sopenharmony_ci			"Failed to set fast commit journal feature");
492962306a36Sopenharmony_ci		goto out;
493062306a36Sopenharmony_ci	}
493162306a36Sopenharmony_ci
493262306a36Sopenharmony_ci	/* We have now updated the journal if required, so we can
493362306a36Sopenharmony_ci	 * validate the data journaling mode. */
493462306a36Sopenharmony_ci	switch (test_opt(sb, DATA_FLAGS)) {
493562306a36Sopenharmony_ci	case 0:
493662306a36Sopenharmony_ci		/* No mode set, assume a default based on the journal
493762306a36Sopenharmony_ci		 * capabilities: ORDERED_DATA if the journal can
493862306a36Sopenharmony_ci		 * cope, else JOURNAL_DATA
493962306a36Sopenharmony_ci		 */
494062306a36Sopenharmony_ci		if (jbd2_journal_check_available_features
494162306a36Sopenharmony_ci		    (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)) {
494262306a36Sopenharmony_ci			set_opt(sb, ORDERED_DATA);
494362306a36Sopenharmony_ci			sbi->s_def_mount_opt |= EXT4_MOUNT_ORDERED_DATA;
494462306a36Sopenharmony_ci		} else {
494562306a36Sopenharmony_ci			set_opt(sb, JOURNAL_DATA);
494662306a36Sopenharmony_ci			sbi->s_def_mount_opt |= EXT4_MOUNT_JOURNAL_DATA;
494762306a36Sopenharmony_ci		}
494862306a36Sopenharmony_ci		break;
494962306a36Sopenharmony_ci
495062306a36Sopenharmony_ci	case EXT4_MOUNT_ORDERED_DATA:
495162306a36Sopenharmony_ci	case EXT4_MOUNT_WRITEBACK_DATA:
495262306a36Sopenharmony_ci		if (!jbd2_journal_check_available_features
495362306a36Sopenharmony_ci		    (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)) {
495462306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "Journal does not support "
495562306a36Sopenharmony_ci			       "requested data journaling mode");
495662306a36Sopenharmony_ci			goto out;
495762306a36Sopenharmony_ci		}
495862306a36Sopenharmony_ci		break;
495962306a36Sopenharmony_ci	default:
496062306a36Sopenharmony_ci		break;
496162306a36Sopenharmony_ci	}
496262306a36Sopenharmony_ci
496362306a36Sopenharmony_ci	if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA &&
496462306a36Sopenharmony_ci	    test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
496562306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "can't mount with "
496662306a36Sopenharmony_ci			"journal_async_commit in data=ordered mode");
496762306a36Sopenharmony_ci		goto out;
496862306a36Sopenharmony_ci	}
496962306a36Sopenharmony_ci
497062306a36Sopenharmony_ci	set_task_ioprio(sbi->s_journal->j_task, ctx->journal_ioprio);
497162306a36Sopenharmony_ci
497262306a36Sopenharmony_ci	sbi->s_journal->j_submit_inode_data_buffers =
497362306a36Sopenharmony_ci		ext4_journal_submit_inode_data_buffers;
497462306a36Sopenharmony_ci	sbi->s_journal->j_finish_inode_data_buffers =
497562306a36Sopenharmony_ci		ext4_journal_finish_inode_data_buffers;
497662306a36Sopenharmony_ci
497762306a36Sopenharmony_ci	return 0;
497862306a36Sopenharmony_ci
497962306a36Sopenharmony_ciout:
498062306a36Sopenharmony_ci	/* flush s_sb_upd_work before destroying the journal. */
498162306a36Sopenharmony_ci	flush_work(&sbi->s_sb_upd_work);
498262306a36Sopenharmony_ci	jbd2_journal_destroy(sbi->s_journal);
498362306a36Sopenharmony_ci	sbi->s_journal = NULL;
498462306a36Sopenharmony_ci	return -EINVAL;
498562306a36Sopenharmony_ci}
498662306a36Sopenharmony_ci
498762306a36Sopenharmony_cistatic int ext4_check_journal_data_mode(struct super_block *sb)
498862306a36Sopenharmony_ci{
498962306a36Sopenharmony_ci	if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
499062306a36Sopenharmony_ci		printk_once(KERN_WARNING "EXT4-fs: Warning: mounting with "
499162306a36Sopenharmony_ci			    "data=journal disables delayed allocation, "
499262306a36Sopenharmony_ci			    "dioread_nolock, O_DIRECT and fast_commit support!\n");
499362306a36Sopenharmony_ci		/* can't mount with both data=journal and dioread_nolock. */
499462306a36Sopenharmony_ci		clear_opt(sb, DIOREAD_NOLOCK);
499562306a36Sopenharmony_ci		clear_opt2(sb, JOURNAL_FAST_COMMIT);
499662306a36Sopenharmony_ci		if (test_opt2(sb, EXPLICIT_DELALLOC)) {
499762306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "can't mount with "
499862306a36Sopenharmony_ci				 "both data=journal and delalloc");
499962306a36Sopenharmony_ci			return -EINVAL;
500062306a36Sopenharmony_ci		}
500162306a36Sopenharmony_ci		if (test_opt(sb, DAX_ALWAYS)) {
500262306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "can't mount with "
500362306a36Sopenharmony_ci				 "both data=journal and dax");
500462306a36Sopenharmony_ci			return -EINVAL;
500562306a36Sopenharmony_ci		}
500662306a36Sopenharmony_ci		if (ext4_has_feature_encrypt(sb)) {
500762306a36Sopenharmony_ci			ext4_msg(sb, KERN_WARNING,
500862306a36Sopenharmony_ci				 "encrypted files will use data=ordered "
500962306a36Sopenharmony_ci				 "instead of data journaling mode");
501062306a36Sopenharmony_ci		}
501162306a36Sopenharmony_ci		if (test_opt(sb, DELALLOC))
501262306a36Sopenharmony_ci			clear_opt(sb, DELALLOC);
501362306a36Sopenharmony_ci	} else {
501462306a36Sopenharmony_ci		sb->s_iflags |= SB_I_CGROUPWB;
501562306a36Sopenharmony_ci	}
501662306a36Sopenharmony_ci
501762306a36Sopenharmony_ci	return 0;
501862306a36Sopenharmony_ci}
501962306a36Sopenharmony_ci
502062306a36Sopenharmony_cistatic int ext4_load_super(struct super_block *sb, ext4_fsblk_t *lsb,
502162306a36Sopenharmony_ci			   int silent)
502262306a36Sopenharmony_ci{
502362306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
502462306a36Sopenharmony_ci	struct ext4_super_block *es;
502562306a36Sopenharmony_ci	ext4_fsblk_t logical_sb_block;
502662306a36Sopenharmony_ci	unsigned long offset = 0;
502762306a36Sopenharmony_ci	struct buffer_head *bh;
502862306a36Sopenharmony_ci	int ret = -EINVAL;
502962306a36Sopenharmony_ci	int blocksize;
503062306a36Sopenharmony_ci
503162306a36Sopenharmony_ci	blocksize = sb_min_blocksize(sb, EXT4_MIN_BLOCK_SIZE);
503262306a36Sopenharmony_ci	if (!blocksize) {
503362306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "unable to set blocksize");
503462306a36Sopenharmony_ci		return -EINVAL;
503562306a36Sopenharmony_ci	}
503662306a36Sopenharmony_ci
503762306a36Sopenharmony_ci	/*
503862306a36Sopenharmony_ci	 * The ext4 superblock will not be buffer aligned for other than 1kB
503962306a36Sopenharmony_ci	 * block sizes.  We need to calculate the offset from buffer start.
504062306a36Sopenharmony_ci	 */
504162306a36Sopenharmony_ci	if (blocksize != EXT4_MIN_BLOCK_SIZE) {
504262306a36Sopenharmony_ci		logical_sb_block = sbi->s_sb_block * EXT4_MIN_BLOCK_SIZE;
504362306a36Sopenharmony_ci		offset = do_div(logical_sb_block, blocksize);
504462306a36Sopenharmony_ci	} else {
504562306a36Sopenharmony_ci		logical_sb_block = sbi->s_sb_block;
504662306a36Sopenharmony_ci	}
504762306a36Sopenharmony_ci
504862306a36Sopenharmony_ci	bh = ext4_sb_bread_unmovable(sb, logical_sb_block);
504962306a36Sopenharmony_ci	if (IS_ERR(bh)) {
505062306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "unable to read superblock");
505162306a36Sopenharmony_ci		return PTR_ERR(bh);
505262306a36Sopenharmony_ci	}
505362306a36Sopenharmony_ci	/*
505462306a36Sopenharmony_ci	 * Note: s_es must be initialized as soon as possible because
505562306a36Sopenharmony_ci	 *       some ext4 macro-instructions depend on its value
505662306a36Sopenharmony_ci	 */
505762306a36Sopenharmony_ci	es = (struct ext4_super_block *) (bh->b_data + offset);
505862306a36Sopenharmony_ci	sbi->s_es = es;
505962306a36Sopenharmony_ci	sb->s_magic = le16_to_cpu(es->s_magic);
506062306a36Sopenharmony_ci	if (sb->s_magic != EXT4_SUPER_MAGIC) {
506162306a36Sopenharmony_ci		if (!silent)
506262306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "VFS: Can't find ext4 filesystem");
506362306a36Sopenharmony_ci		goto out;
506462306a36Sopenharmony_ci	}
506562306a36Sopenharmony_ci
506662306a36Sopenharmony_ci	if (le32_to_cpu(es->s_log_block_size) >
506762306a36Sopenharmony_ci	    (EXT4_MAX_BLOCK_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) {
506862306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR,
506962306a36Sopenharmony_ci			 "Invalid log block size: %u",
507062306a36Sopenharmony_ci			 le32_to_cpu(es->s_log_block_size));
507162306a36Sopenharmony_ci		goto out;
507262306a36Sopenharmony_ci	}
507362306a36Sopenharmony_ci	if (le32_to_cpu(es->s_log_cluster_size) >
507462306a36Sopenharmony_ci	    (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) {
507562306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR,
507662306a36Sopenharmony_ci			 "Invalid log cluster size: %u",
507762306a36Sopenharmony_ci			 le32_to_cpu(es->s_log_cluster_size));
507862306a36Sopenharmony_ci		goto out;
507962306a36Sopenharmony_ci	}
508062306a36Sopenharmony_ci
508162306a36Sopenharmony_ci	blocksize = EXT4_MIN_BLOCK_SIZE << le32_to_cpu(es->s_log_block_size);
508262306a36Sopenharmony_ci
508362306a36Sopenharmony_ci	/*
508462306a36Sopenharmony_ci	 * If the default block size is not the same as the real block size,
508562306a36Sopenharmony_ci	 * we need to reload it.
508662306a36Sopenharmony_ci	 */
508762306a36Sopenharmony_ci	if (sb->s_blocksize == blocksize) {
508862306a36Sopenharmony_ci		*lsb = logical_sb_block;
508962306a36Sopenharmony_ci		sbi->s_sbh = bh;
509062306a36Sopenharmony_ci		return 0;
509162306a36Sopenharmony_ci	}
509262306a36Sopenharmony_ci
509362306a36Sopenharmony_ci	/*
509462306a36Sopenharmony_ci	 * bh must be released before kill_bdev(), otherwise
509562306a36Sopenharmony_ci	 * it won't be freed and its page also. kill_bdev()
509662306a36Sopenharmony_ci	 * is called by sb_set_blocksize().
509762306a36Sopenharmony_ci	 */
509862306a36Sopenharmony_ci	brelse(bh);
509962306a36Sopenharmony_ci	/* Validate the filesystem blocksize */
510062306a36Sopenharmony_ci	if (!sb_set_blocksize(sb, blocksize)) {
510162306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "bad block size %d",
510262306a36Sopenharmony_ci				blocksize);
510362306a36Sopenharmony_ci		bh = NULL;
510462306a36Sopenharmony_ci		goto out;
510562306a36Sopenharmony_ci	}
510662306a36Sopenharmony_ci
510762306a36Sopenharmony_ci	logical_sb_block = sbi->s_sb_block * EXT4_MIN_BLOCK_SIZE;
510862306a36Sopenharmony_ci	offset = do_div(logical_sb_block, blocksize);
510962306a36Sopenharmony_ci	bh = ext4_sb_bread_unmovable(sb, logical_sb_block);
511062306a36Sopenharmony_ci	if (IS_ERR(bh)) {
511162306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "Can't read superblock on 2nd try");
511262306a36Sopenharmony_ci		ret = PTR_ERR(bh);
511362306a36Sopenharmony_ci		bh = NULL;
511462306a36Sopenharmony_ci		goto out;
511562306a36Sopenharmony_ci	}
511662306a36Sopenharmony_ci	es = (struct ext4_super_block *)(bh->b_data + offset);
511762306a36Sopenharmony_ci	sbi->s_es = es;
511862306a36Sopenharmony_ci	if (es->s_magic != cpu_to_le16(EXT4_SUPER_MAGIC)) {
511962306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "Magic mismatch, very weird!");
512062306a36Sopenharmony_ci		goto out;
512162306a36Sopenharmony_ci	}
512262306a36Sopenharmony_ci	*lsb = logical_sb_block;
512362306a36Sopenharmony_ci	sbi->s_sbh = bh;
512462306a36Sopenharmony_ci	return 0;
512562306a36Sopenharmony_ciout:
512662306a36Sopenharmony_ci	brelse(bh);
512762306a36Sopenharmony_ci	return ret;
512862306a36Sopenharmony_ci}
512962306a36Sopenharmony_ci
513062306a36Sopenharmony_cistatic void ext4_hash_info_init(struct super_block *sb)
513162306a36Sopenharmony_ci{
513262306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
513362306a36Sopenharmony_ci	struct ext4_super_block *es = sbi->s_es;
513462306a36Sopenharmony_ci	unsigned int i;
513562306a36Sopenharmony_ci
513662306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
513762306a36Sopenharmony_ci		sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
513862306a36Sopenharmony_ci
513962306a36Sopenharmony_ci	sbi->s_def_hash_version = es->s_def_hash_version;
514062306a36Sopenharmony_ci	if (ext4_has_feature_dir_index(sb)) {
514162306a36Sopenharmony_ci		i = le32_to_cpu(es->s_flags);
514262306a36Sopenharmony_ci		if (i & EXT2_FLAGS_UNSIGNED_HASH)
514362306a36Sopenharmony_ci			sbi->s_hash_unsigned = 3;
514462306a36Sopenharmony_ci		else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) {
514562306a36Sopenharmony_ci#ifdef __CHAR_UNSIGNED__
514662306a36Sopenharmony_ci			if (!sb_rdonly(sb))
514762306a36Sopenharmony_ci				es->s_flags |=
514862306a36Sopenharmony_ci					cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH);
514962306a36Sopenharmony_ci			sbi->s_hash_unsigned = 3;
515062306a36Sopenharmony_ci#else
515162306a36Sopenharmony_ci			if (!sb_rdonly(sb))
515262306a36Sopenharmony_ci				es->s_flags |=
515362306a36Sopenharmony_ci					cpu_to_le32(EXT2_FLAGS_SIGNED_HASH);
515462306a36Sopenharmony_ci#endif
515562306a36Sopenharmony_ci		}
515662306a36Sopenharmony_ci	}
515762306a36Sopenharmony_ci}
515862306a36Sopenharmony_ci
515962306a36Sopenharmony_cistatic int ext4_block_group_meta_init(struct super_block *sb, int silent)
516062306a36Sopenharmony_ci{
516162306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
516262306a36Sopenharmony_ci	struct ext4_super_block *es = sbi->s_es;
516362306a36Sopenharmony_ci	int has_huge_files;
516462306a36Sopenharmony_ci
516562306a36Sopenharmony_ci	has_huge_files = ext4_has_feature_huge_file(sb);
516662306a36Sopenharmony_ci	sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits,
516762306a36Sopenharmony_ci						      has_huge_files);
516862306a36Sopenharmony_ci	sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits, has_huge_files);
516962306a36Sopenharmony_ci
517062306a36Sopenharmony_ci	sbi->s_desc_size = le16_to_cpu(es->s_desc_size);
517162306a36Sopenharmony_ci	if (ext4_has_feature_64bit(sb)) {
517262306a36Sopenharmony_ci		if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE_64BIT ||
517362306a36Sopenharmony_ci		    sbi->s_desc_size > EXT4_MAX_DESC_SIZE ||
517462306a36Sopenharmony_ci		    !is_power_of_2(sbi->s_desc_size)) {
517562306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR,
517662306a36Sopenharmony_ci			       "unsupported descriptor size %lu",
517762306a36Sopenharmony_ci			       sbi->s_desc_size);
517862306a36Sopenharmony_ci			return -EINVAL;
517962306a36Sopenharmony_ci		}
518062306a36Sopenharmony_ci	} else
518162306a36Sopenharmony_ci		sbi->s_desc_size = EXT4_MIN_DESC_SIZE;
518262306a36Sopenharmony_ci
518362306a36Sopenharmony_ci	sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
518462306a36Sopenharmony_ci	sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);
518562306a36Sopenharmony_ci
518662306a36Sopenharmony_ci	sbi->s_inodes_per_block = sb->s_blocksize / EXT4_INODE_SIZE(sb);
518762306a36Sopenharmony_ci	if (sbi->s_inodes_per_block == 0 || sbi->s_blocks_per_group == 0) {
518862306a36Sopenharmony_ci		if (!silent)
518962306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "VFS: Can't find ext4 filesystem");
519062306a36Sopenharmony_ci		return -EINVAL;
519162306a36Sopenharmony_ci	}
519262306a36Sopenharmony_ci	if (sbi->s_inodes_per_group < sbi->s_inodes_per_block ||
519362306a36Sopenharmony_ci	    sbi->s_inodes_per_group > sb->s_blocksize * 8) {
519462306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "invalid inodes per group: %lu\n",
519562306a36Sopenharmony_ci			 sbi->s_inodes_per_group);
519662306a36Sopenharmony_ci		return -EINVAL;
519762306a36Sopenharmony_ci	}
519862306a36Sopenharmony_ci	sbi->s_itb_per_group = sbi->s_inodes_per_group /
519962306a36Sopenharmony_ci					sbi->s_inodes_per_block;
520062306a36Sopenharmony_ci	sbi->s_desc_per_block = sb->s_blocksize / EXT4_DESC_SIZE(sb);
520162306a36Sopenharmony_ci	sbi->s_mount_state = le16_to_cpu(es->s_state) & ~EXT4_FC_REPLAY;
520262306a36Sopenharmony_ci	sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb));
520362306a36Sopenharmony_ci	sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb));
520462306a36Sopenharmony_ci
520562306a36Sopenharmony_ci	return 0;
520662306a36Sopenharmony_ci}
520762306a36Sopenharmony_ci
520862306a36Sopenharmony_cistatic int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
520962306a36Sopenharmony_ci{
521062306a36Sopenharmony_ci	struct ext4_super_block *es = NULL;
521162306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
521262306a36Sopenharmony_ci	ext4_fsblk_t logical_sb_block;
521362306a36Sopenharmony_ci	struct inode *root;
521462306a36Sopenharmony_ci	int needs_recovery;
521562306a36Sopenharmony_ci	int err;
521662306a36Sopenharmony_ci	ext4_group_t first_not_zeroed;
521762306a36Sopenharmony_ci	struct ext4_fs_context *ctx = fc->fs_private;
521862306a36Sopenharmony_ci	int silent = fc->sb_flags & SB_SILENT;
521962306a36Sopenharmony_ci
522062306a36Sopenharmony_ci	/* Set defaults for the variables that will be set during parsing */
522162306a36Sopenharmony_ci	if (!(ctx->spec & EXT4_SPEC_JOURNAL_IOPRIO))
522262306a36Sopenharmony_ci		ctx->journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
522362306a36Sopenharmony_ci
522462306a36Sopenharmony_ci	sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
522562306a36Sopenharmony_ci	sbi->s_sectors_written_start =
522662306a36Sopenharmony_ci		part_stat_read(sb->s_bdev, sectors[STAT_WRITE]);
522762306a36Sopenharmony_ci
522862306a36Sopenharmony_ci	err = ext4_load_super(sb, &logical_sb_block, silent);
522962306a36Sopenharmony_ci	if (err)
523062306a36Sopenharmony_ci		goto out_fail;
523162306a36Sopenharmony_ci
523262306a36Sopenharmony_ci	es = sbi->s_es;
523362306a36Sopenharmony_ci	sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written);
523462306a36Sopenharmony_ci
523562306a36Sopenharmony_ci	err = ext4_init_metadata_csum(sb, es);
523662306a36Sopenharmony_ci	if (err)
523762306a36Sopenharmony_ci		goto failed_mount;
523862306a36Sopenharmony_ci
523962306a36Sopenharmony_ci	ext4_set_def_opts(sb, es);
524062306a36Sopenharmony_ci
524162306a36Sopenharmony_ci	sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid));
524262306a36Sopenharmony_ci	sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid));
524362306a36Sopenharmony_ci	sbi->s_commit_interval = JBD2_DEFAULT_MAX_COMMIT_AGE * HZ;
524462306a36Sopenharmony_ci	sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME;
524562306a36Sopenharmony_ci	sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME;
524662306a36Sopenharmony_ci
524762306a36Sopenharmony_ci	/*
524862306a36Sopenharmony_ci	 * set default s_li_wait_mult for lazyinit, for the case there is
524962306a36Sopenharmony_ci	 * no mount option specified.
525062306a36Sopenharmony_ci	 */
525162306a36Sopenharmony_ci	sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT;
525262306a36Sopenharmony_ci
525362306a36Sopenharmony_ci	err = ext4_inode_info_init(sb, es);
525462306a36Sopenharmony_ci	if (err)
525562306a36Sopenharmony_ci		goto failed_mount;
525662306a36Sopenharmony_ci
525762306a36Sopenharmony_ci	err = parse_apply_sb_mount_options(sb, ctx);
525862306a36Sopenharmony_ci	if (err < 0)
525962306a36Sopenharmony_ci		goto failed_mount;
526062306a36Sopenharmony_ci
526162306a36Sopenharmony_ci	sbi->s_def_mount_opt = sbi->s_mount_opt;
526262306a36Sopenharmony_ci	sbi->s_def_mount_opt2 = sbi->s_mount_opt2;
526362306a36Sopenharmony_ci
526462306a36Sopenharmony_ci	err = ext4_check_opt_consistency(fc, sb);
526562306a36Sopenharmony_ci	if (err < 0)
526662306a36Sopenharmony_ci		goto failed_mount;
526762306a36Sopenharmony_ci
526862306a36Sopenharmony_ci	ext4_apply_options(fc, sb);
526962306a36Sopenharmony_ci
527062306a36Sopenharmony_ci	err = ext4_encoding_init(sb, es);
527162306a36Sopenharmony_ci	if (err)
527262306a36Sopenharmony_ci		goto failed_mount;
527362306a36Sopenharmony_ci
527462306a36Sopenharmony_ci	err = ext4_check_journal_data_mode(sb);
527562306a36Sopenharmony_ci	if (err)
527662306a36Sopenharmony_ci		goto failed_mount;
527762306a36Sopenharmony_ci
527862306a36Sopenharmony_ci	sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
527962306a36Sopenharmony_ci		(test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0);
528062306a36Sopenharmony_ci
528162306a36Sopenharmony_ci	/* i_version is always enabled now */
528262306a36Sopenharmony_ci	sb->s_flags |= SB_I_VERSION;
528362306a36Sopenharmony_ci
528462306a36Sopenharmony_ci	err = ext4_check_feature_compatibility(sb, es, silent);
528562306a36Sopenharmony_ci	if (err)
528662306a36Sopenharmony_ci		goto failed_mount;
528762306a36Sopenharmony_ci
528862306a36Sopenharmony_ci	err = ext4_block_group_meta_init(sb, silent);
528962306a36Sopenharmony_ci	if (err)
529062306a36Sopenharmony_ci		goto failed_mount;
529162306a36Sopenharmony_ci
529262306a36Sopenharmony_ci	ext4_hash_info_init(sb);
529362306a36Sopenharmony_ci
529462306a36Sopenharmony_ci	err = ext4_handle_clustersize(sb);
529562306a36Sopenharmony_ci	if (err)
529662306a36Sopenharmony_ci		goto failed_mount;
529762306a36Sopenharmony_ci
529862306a36Sopenharmony_ci	err = ext4_check_geometry(sb, es);
529962306a36Sopenharmony_ci	if (err)
530062306a36Sopenharmony_ci		goto failed_mount;
530162306a36Sopenharmony_ci
530262306a36Sopenharmony_ci	timer_setup(&sbi->s_err_report, print_daily_error_info, 0);
530362306a36Sopenharmony_ci	spin_lock_init(&sbi->s_error_lock);
530462306a36Sopenharmony_ci	INIT_WORK(&sbi->s_sb_upd_work, update_super_work);
530562306a36Sopenharmony_ci
530662306a36Sopenharmony_ci	err = ext4_group_desc_init(sb, es, logical_sb_block, &first_not_zeroed);
530762306a36Sopenharmony_ci	if (err)
530862306a36Sopenharmony_ci		goto failed_mount3;
530962306a36Sopenharmony_ci
531062306a36Sopenharmony_ci	err = ext4_es_register_shrinker(sbi);
531162306a36Sopenharmony_ci	if (err)
531262306a36Sopenharmony_ci		goto failed_mount3;
531362306a36Sopenharmony_ci
531462306a36Sopenharmony_ci	sbi->s_stripe = ext4_get_stripe_size(sbi);
531562306a36Sopenharmony_ci	/*
531662306a36Sopenharmony_ci	 * It's hard to get stripe aligned blocks if stripe is not aligned with
531762306a36Sopenharmony_ci	 * cluster, just disable stripe and alert user to simpfy code and avoid
531862306a36Sopenharmony_ci	 * stripe aligned allocation which will rarely successes.
531962306a36Sopenharmony_ci	 */
532062306a36Sopenharmony_ci	if (sbi->s_stripe > 0 && sbi->s_cluster_ratio > 1 &&
532162306a36Sopenharmony_ci	    sbi->s_stripe % sbi->s_cluster_ratio != 0) {
532262306a36Sopenharmony_ci		ext4_msg(sb, KERN_WARNING,
532362306a36Sopenharmony_ci			 "stripe (%lu) is not aligned with cluster size (%u), "
532462306a36Sopenharmony_ci			 "stripe is disabled",
532562306a36Sopenharmony_ci			 sbi->s_stripe, sbi->s_cluster_ratio);
532662306a36Sopenharmony_ci		sbi->s_stripe = 0;
532762306a36Sopenharmony_ci	}
532862306a36Sopenharmony_ci	sbi->s_extent_max_zeroout_kb = 32;
532962306a36Sopenharmony_ci
533062306a36Sopenharmony_ci	/*
533162306a36Sopenharmony_ci	 * set up enough so that it can read an inode
533262306a36Sopenharmony_ci	 */
533362306a36Sopenharmony_ci	sb->s_op = &ext4_sops;
533462306a36Sopenharmony_ci	sb->s_export_op = &ext4_export_ops;
533562306a36Sopenharmony_ci	sb->s_xattr = ext4_xattr_handlers;
533662306a36Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION
533762306a36Sopenharmony_ci	sb->s_cop = &ext4_cryptops;
533862306a36Sopenharmony_ci#endif
533962306a36Sopenharmony_ci#ifdef CONFIG_FS_VERITY
534062306a36Sopenharmony_ci	sb->s_vop = &ext4_verityops;
534162306a36Sopenharmony_ci#endif
534262306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
534362306a36Sopenharmony_ci	sb->dq_op = &ext4_quota_operations;
534462306a36Sopenharmony_ci	if (ext4_has_feature_quota(sb))
534562306a36Sopenharmony_ci		sb->s_qcop = &dquot_quotactl_sysfile_ops;
534662306a36Sopenharmony_ci	else
534762306a36Sopenharmony_ci		sb->s_qcop = &ext4_qctl_operations;
534862306a36Sopenharmony_ci	sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ;
534962306a36Sopenharmony_ci#endif
535062306a36Sopenharmony_ci	memcpy(&sb->s_uuid, es->s_uuid, sizeof(es->s_uuid));
535162306a36Sopenharmony_ci
535262306a36Sopenharmony_ci	INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
535362306a36Sopenharmony_ci	mutex_init(&sbi->s_orphan_lock);
535462306a36Sopenharmony_ci
535562306a36Sopenharmony_ci	ext4_fast_commit_init(sb);
535662306a36Sopenharmony_ci
535762306a36Sopenharmony_ci	sb->s_root = NULL;
535862306a36Sopenharmony_ci
535962306a36Sopenharmony_ci	needs_recovery = (es->s_last_orphan != 0 ||
536062306a36Sopenharmony_ci			  ext4_has_feature_orphan_present(sb) ||
536162306a36Sopenharmony_ci			  ext4_has_feature_journal_needs_recovery(sb));
536262306a36Sopenharmony_ci
536362306a36Sopenharmony_ci	if (ext4_has_feature_mmp(sb) && !sb_rdonly(sb)) {
536462306a36Sopenharmony_ci		err = ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block));
536562306a36Sopenharmony_ci		if (err)
536662306a36Sopenharmony_ci			goto failed_mount3a;
536762306a36Sopenharmony_ci	}
536862306a36Sopenharmony_ci
536962306a36Sopenharmony_ci	err = -EINVAL;
537062306a36Sopenharmony_ci	/*
537162306a36Sopenharmony_ci	 * The first inode we look at is the journal inode.  Don't try
537262306a36Sopenharmony_ci	 * root first: it may be modified in the journal!
537362306a36Sopenharmony_ci	 */
537462306a36Sopenharmony_ci	if (!test_opt(sb, NOLOAD) && ext4_has_feature_journal(sb)) {
537562306a36Sopenharmony_ci		err = ext4_load_and_init_journal(sb, es, ctx);
537662306a36Sopenharmony_ci		if (err)
537762306a36Sopenharmony_ci			goto failed_mount3a;
537862306a36Sopenharmony_ci	} else if (test_opt(sb, NOLOAD) && !sb_rdonly(sb) &&
537962306a36Sopenharmony_ci		   ext4_has_feature_journal_needs_recovery(sb)) {
538062306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "required journal recovery "
538162306a36Sopenharmony_ci		       "suppressed and not mounted read-only");
538262306a36Sopenharmony_ci		goto failed_mount3a;
538362306a36Sopenharmony_ci	} else {
538462306a36Sopenharmony_ci		/* Nojournal mode, all journal mount options are illegal */
538562306a36Sopenharmony_ci		if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
538662306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "can't mount with "
538762306a36Sopenharmony_ci				 "journal_async_commit, fs mounted w/o journal");
538862306a36Sopenharmony_ci			goto failed_mount3a;
538962306a36Sopenharmony_ci		}
539062306a36Sopenharmony_ci
539162306a36Sopenharmony_ci		if (test_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM)) {
539262306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "can't mount with "
539362306a36Sopenharmony_ci				 "journal_checksum, fs mounted w/o journal");
539462306a36Sopenharmony_ci			goto failed_mount3a;
539562306a36Sopenharmony_ci		}
539662306a36Sopenharmony_ci		if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) {
539762306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "can't mount with "
539862306a36Sopenharmony_ci				 "commit=%lu, fs mounted w/o journal",
539962306a36Sopenharmony_ci				 sbi->s_commit_interval / HZ);
540062306a36Sopenharmony_ci			goto failed_mount3a;
540162306a36Sopenharmony_ci		}
540262306a36Sopenharmony_ci		if (EXT4_MOUNT_DATA_FLAGS &
540362306a36Sopenharmony_ci		    (sbi->s_mount_opt ^ sbi->s_def_mount_opt)) {
540462306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "can't mount with "
540562306a36Sopenharmony_ci				 "data=, fs mounted w/o journal");
540662306a36Sopenharmony_ci			goto failed_mount3a;
540762306a36Sopenharmony_ci		}
540862306a36Sopenharmony_ci		sbi->s_def_mount_opt &= ~EXT4_MOUNT_JOURNAL_CHECKSUM;
540962306a36Sopenharmony_ci		clear_opt(sb, JOURNAL_CHECKSUM);
541062306a36Sopenharmony_ci		clear_opt(sb, DATA_FLAGS);
541162306a36Sopenharmony_ci		clear_opt2(sb, JOURNAL_FAST_COMMIT);
541262306a36Sopenharmony_ci		sbi->s_journal = NULL;
541362306a36Sopenharmony_ci		needs_recovery = 0;
541462306a36Sopenharmony_ci	}
541562306a36Sopenharmony_ci
541662306a36Sopenharmony_ci	if (!test_opt(sb, NO_MBCACHE)) {
541762306a36Sopenharmony_ci		sbi->s_ea_block_cache = ext4_xattr_create_cache();
541862306a36Sopenharmony_ci		if (!sbi->s_ea_block_cache) {
541962306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR,
542062306a36Sopenharmony_ci				 "Failed to create ea_block_cache");
542162306a36Sopenharmony_ci			err = -EINVAL;
542262306a36Sopenharmony_ci			goto failed_mount_wq;
542362306a36Sopenharmony_ci		}
542462306a36Sopenharmony_ci
542562306a36Sopenharmony_ci		if (ext4_has_feature_ea_inode(sb)) {
542662306a36Sopenharmony_ci			sbi->s_ea_inode_cache = ext4_xattr_create_cache();
542762306a36Sopenharmony_ci			if (!sbi->s_ea_inode_cache) {
542862306a36Sopenharmony_ci				ext4_msg(sb, KERN_ERR,
542962306a36Sopenharmony_ci					 "Failed to create ea_inode_cache");
543062306a36Sopenharmony_ci				err = -EINVAL;
543162306a36Sopenharmony_ci				goto failed_mount_wq;
543262306a36Sopenharmony_ci			}
543362306a36Sopenharmony_ci		}
543462306a36Sopenharmony_ci	}
543562306a36Sopenharmony_ci
543662306a36Sopenharmony_ci	/*
543762306a36Sopenharmony_ci	 * Get the # of file system overhead blocks from the
543862306a36Sopenharmony_ci	 * superblock if present.
543962306a36Sopenharmony_ci	 */
544062306a36Sopenharmony_ci	sbi->s_overhead = le32_to_cpu(es->s_overhead_clusters);
544162306a36Sopenharmony_ci	/* ignore the precalculated value if it is ridiculous */
544262306a36Sopenharmony_ci	if (sbi->s_overhead > ext4_blocks_count(es))
544362306a36Sopenharmony_ci		sbi->s_overhead = 0;
544462306a36Sopenharmony_ci	/*
544562306a36Sopenharmony_ci	 * If the bigalloc feature is not enabled recalculating the
544662306a36Sopenharmony_ci	 * overhead doesn't take long, so we might as well just redo
544762306a36Sopenharmony_ci	 * it to make sure we are using the correct value.
544862306a36Sopenharmony_ci	 */
544962306a36Sopenharmony_ci	if (!ext4_has_feature_bigalloc(sb))
545062306a36Sopenharmony_ci		sbi->s_overhead = 0;
545162306a36Sopenharmony_ci	if (sbi->s_overhead == 0) {
545262306a36Sopenharmony_ci		err = ext4_calculate_overhead(sb);
545362306a36Sopenharmony_ci		if (err)
545462306a36Sopenharmony_ci			goto failed_mount_wq;
545562306a36Sopenharmony_ci	}
545662306a36Sopenharmony_ci
545762306a36Sopenharmony_ci	/*
545862306a36Sopenharmony_ci	 * The maximum number of concurrent works can be high and
545962306a36Sopenharmony_ci	 * concurrency isn't really necessary.  Limit it to 1.
546062306a36Sopenharmony_ci	 */
546162306a36Sopenharmony_ci	EXT4_SB(sb)->rsv_conversion_wq =
546262306a36Sopenharmony_ci		alloc_workqueue("ext4-rsv-conversion", WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
546362306a36Sopenharmony_ci	if (!EXT4_SB(sb)->rsv_conversion_wq) {
546462306a36Sopenharmony_ci		printk(KERN_ERR "EXT4-fs: failed to create workqueue\n");
546562306a36Sopenharmony_ci		err = -ENOMEM;
546662306a36Sopenharmony_ci		goto failed_mount4;
546762306a36Sopenharmony_ci	}
546862306a36Sopenharmony_ci
546962306a36Sopenharmony_ci	/*
547062306a36Sopenharmony_ci	 * The jbd2_journal_load will have done any necessary log recovery,
547162306a36Sopenharmony_ci	 * so we can safely mount the rest of the filesystem now.
547262306a36Sopenharmony_ci	 */
547362306a36Sopenharmony_ci
547462306a36Sopenharmony_ci	root = ext4_iget(sb, EXT4_ROOT_INO, EXT4_IGET_SPECIAL);
547562306a36Sopenharmony_ci	if (IS_ERR(root)) {
547662306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "get root inode failed");
547762306a36Sopenharmony_ci		err = PTR_ERR(root);
547862306a36Sopenharmony_ci		root = NULL;
547962306a36Sopenharmony_ci		goto failed_mount4;
548062306a36Sopenharmony_ci	}
548162306a36Sopenharmony_ci	if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
548262306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "corrupt root inode, run e2fsck");
548362306a36Sopenharmony_ci		iput(root);
548462306a36Sopenharmony_ci		err = -EFSCORRUPTED;
548562306a36Sopenharmony_ci		goto failed_mount4;
548662306a36Sopenharmony_ci	}
548762306a36Sopenharmony_ci
548862306a36Sopenharmony_ci	sb->s_root = d_make_root(root);
548962306a36Sopenharmony_ci	if (!sb->s_root) {
549062306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "get root dentry failed");
549162306a36Sopenharmony_ci		err = -ENOMEM;
549262306a36Sopenharmony_ci		goto failed_mount4;
549362306a36Sopenharmony_ci	}
549462306a36Sopenharmony_ci
549562306a36Sopenharmony_ci	err = ext4_setup_super(sb, es, sb_rdonly(sb));
549662306a36Sopenharmony_ci	if (err == -EROFS) {
549762306a36Sopenharmony_ci		sb->s_flags |= SB_RDONLY;
549862306a36Sopenharmony_ci	} else if (err)
549962306a36Sopenharmony_ci		goto failed_mount4a;
550062306a36Sopenharmony_ci
550162306a36Sopenharmony_ci	ext4_set_resv_clusters(sb);
550262306a36Sopenharmony_ci
550362306a36Sopenharmony_ci	if (test_opt(sb, BLOCK_VALIDITY)) {
550462306a36Sopenharmony_ci		err = ext4_setup_system_zone(sb);
550562306a36Sopenharmony_ci		if (err) {
550662306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "failed to initialize system "
550762306a36Sopenharmony_ci				 "zone (%d)", err);
550862306a36Sopenharmony_ci			goto failed_mount4a;
550962306a36Sopenharmony_ci		}
551062306a36Sopenharmony_ci	}
551162306a36Sopenharmony_ci	ext4_fc_replay_cleanup(sb);
551262306a36Sopenharmony_ci
551362306a36Sopenharmony_ci	ext4_ext_init(sb);
551462306a36Sopenharmony_ci
551562306a36Sopenharmony_ci	/*
551662306a36Sopenharmony_ci	 * Enable optimize_scan if number of groups is > threshold. This can be
551762306a36Sopenharmony_ci	 * turned off by passing "mb_optimize_scan=0". This can also be
551862306a36Sopenharmony_ci	 * turned on forcefully by passing "mb_optimize_scan=1".
551962306a36Sopenharmony_ci	 */
552062306a36Sopenharmony_ci	if (!(ctx->spec & EXT4_SPEC_mb_optimize_scan)) {
552162306a36Sopenharmony_ci		if (sbi->s_groups_count >= MB_DEFAULT_LINEAR_SCAN_THRESHOLD)
552262306a36Sopenharmony_ci			set_opt2(sb, MB_OPTIMIZE_SCAN);
552362306a36Sopenharmony_ci		else
552462306a36Sopenharmony_ci			clear_opt2(sb, MB_OPTIMIZE_SCAN);
552562306a36Sopenharmony_ci	}
552662306a36Sopenharmony_ci
552762306a36Sopenharmony_ci	err = ext4_mb_init(sb);
552862306a36Sopenharmony_ci	if (err) {
552962306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "failed to initialize mballoc (%d)",
553062306a36Sopenharmony_ci			 err);
553162306a36Sopenharmony_ci		goto failed_mount5;
553262306a36Sopenharmony_ci	}
553362306a36Sopenharmony_ci
553462306a36Sopenharmony_ci	/*
553562306a36Sopenharmony_ci	 * We can only set up the journal commit callback once
553662306a36Sopenharmony_ci	 * mballoc is initialized
553762306a36Sopenharmony_ci	 */
553862306a36Sopenharmony_ci	if (sbi->s_journal)
553962306a36Sopenharmony_ci		sbi->s_journal->j_commit_callback =
554062306a36Sopenharmony_ci			ext4_journal_commit_callback;
554162306a36Sopenharmony_ci
554262306a36Sopenharmony_ci	err = ext4_percpu_param_init(sbi);
554362306a36Sopenharmony_ci	if (err)
554462306a36Sopenharmony_ci		goto failed_mount6;
554562306a36Sopenharmony_ci
554662306a36Sopenharmony_ci	if (ext4_has_feature_flex_bg(sb))
554762306a36Sopenharmony_ci		if (!ext4_fill_flex_info(sb)) {
554862306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR,
554962306a36Sopenharmony_ci			       "unable to initialize "
555062306a36Sopenharmony_ci			       "flex_bg meta info!");
555162306a36Sopenharmony_ci			err = -ENOMEM;
555262306a36Sopenharmony_ci			goto failed_mount6;
555362306a36Sopenharmony_ci		}
555462306a36Sopenharmony_ci
555562306a36Sopenharmony_ci	err = ext4_register_li_request(sb, first_not_zeroed);
555662306a36Sopenharmony_ci	if (err)
555762306a36Sopenharmony_ci		goto failed_mount6;
555862306a36Sopenharmony_ci
555962306a36Sopenharmony_ci	err = ext4_register_sysfs(sb);
556062306a36Sopenharmony_ci	if (err)
556162306a36Sopenharmony_ci		goto failed_mount7;
556262306a36Sopenharmony_ci
556362306a36Sopenharmony_ci	err = ext4_init_orphan_info(sb);
556462306a36Sopenharmony_ci	if (err)
556562306a36Sopenharmony_ci		goto failed_mount8;
556662306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
556762306a36Sopenharmony_ci	/* Enable quota usage during mount. */
556862306a36Sopenharmony_ci	if (ext4_has_feature_quota(sb) && !sb_rdonly(sb)) {
556962306a36Sopenharmony_ci		err = ext4_enable_quotas(sb);
557062306a36Sopenharmony_ci		if (err)
557162306a36Sopenharmony_ci			goto failed_mount9;
557262306a36Sopenharmony_ci	}
557362306a36Sopenharmony_ci#endif  /* CONFIG_QUOTA */
557462306a36Sopenharmony_ci
557562306a36Sopenharmony_ci	/*
557662306a36Sopenharmony_ci	 * Save the original bdev mapping's wb_err value which could be
557762306a36Sopenharmony_ci	 * used to detect the metadata async write error.
557862306a36Sopenharmony_ci	 */
557962306a36Sopenharmony_ci	spin_lock_init(&sbi->s_bdev_wb_lock);
558062306a36Sopenharmony_ci	errseq_check_and_advance(&sb->s_bdev->bd_inode->i_mapping->wb_err,
558162306a36Sopenharmony_ci				 &sbi->s_bdev_wb_err);
558262306a36Sopenharmony_ci	EXT4_SB(sb)->s_mount_state |= EXT4_ORPHAN_FS;
558362306a36Sopenharmony_ci	ext4_orphan_cleanup(sb, es);
558462306a36Sopenharmony_ci	EXT4_SB(sb)->s_mount_state &= ~EXT4_ORPHAN_FS;
558562306a36Sopenharmony_ci	/*
558662306a36Sopenharmony_ci	 * Update the checksum after updating free space/inode counters and
558762306a36Sopenharmony_ci	 * ext4_orphan_cleanup. Otherwise the superblock can have an incorrect
558862306a36Sopenharmony_ci	 * checksum in the buffer cache until it is written out and
558962306a36Sopenharmony_ci	 * e2fsprogs programs trying to open a file system immediately
559062306a36Sopenharmony_ci	 * after it is mounted can fail.
559162306a36Sopenharmony_ci	 */
559262306a36Sopenharmony_ci	ext4_superblock_csum_set(sb);
559362306a36Sopenharmony_ci	if (needs_recovery) {
559462306a36Sopenharmony_ci		ext4_msg(sb, KERN_INFO, "recovery complete");
559562306a36Sopenharmony_ci		err = ext4_mark_recovery_complete(sb, es);
559662306a36Sopenharmony_ci		if (err)
559762306a36Sopenharmony_ci			goto failed_mount10;
559862306a36Sopenharmony_ci	}
559962306a36Sopenharmony_ci
560062306a36Sopenharmony_ci	if (test_opt(sb, DISCARD) && !bdev_max_discard_sectors(sb->s_bdev))
560162306a36Sopenharmony_ci		ext4_msg(sb, KERN_WARNING,
560262306a36Sopenharmony_ci			 "mounting with \"discard\" option, but the device does not support discard");
560362306a36Sopenharmony_ci
560462306a36Sopenharmony_ci	if (es->s_error_count)
560562306a36Sopenharmony_ci		mod_timer(&sbi->s_err_report, jiffies + 300*HZ); /* 5 minutes */
560662306a36Sopenharmony_ci
560762306a36Sopenharmony_ci	/* Enable message ratelimiting. Default is 10 messages per 5 secs. */
560862306a36Sopenharmony_ci	ratelimit_state_init(&sbi->s_err_ratelimit_state, 5 * HZ, 10);
560962306a36Sopenharmony_ci	ratelimit_state_init(&sbi->s_warning_ratelimit_state, 5 * HZ, 10);
561062306a36Sopenharmony_ci	ratelimit_state_init(&sbi->s_msg_ratelimit_state, 5 * HZ, 10);
561162306a36Sopenharmony_ci	atomic_set(&sbi->s_warning_count, 0);
561262306a36Sopenharmony_ci	atomic_set(&sbi->s_msg_count, 0);
561362306a36Sopenharmony_ci
561462306a36Sopenharmony_ci	return 0;
561562306a36Sopenharmony_ci
561662306a36Sopenharmony_cifailed_mount10:
561762306a36Sopenharmony_ci	ext4_quotas_off(sb, EXT4_MAXQUOTAS);
561862306a36Sopenharmony_cifailed_mount9: __maybe_unused
561962306a36Sopenharmony_ci	ext4_release_orphan_info(sb);
562062306a36Sopenharmony_cifailed_mount8:
562162306a36Sopenharmony_ci	ext4_unregister_sysfs(sb);
562262306a36Sopenharmony_ci	kobject_put(&sbi->s_kobj);
562362306a36Sopenharmony_cifailed_mount7:
562462306a36Sopenharmony_ci	ext4_unregister_li_request(sb);
562562306a36Sopenharmony_cifailed_mount6:
562662306a36Sopenharmony_ci	ext4_mb_release(sb);
562762306a36Sopenharmony_ci	ext4_flex_groups_free(sbi);
562862306a36Sopenharmony_ci	ext4_percpu_param_destroy(sbi);
562962306a36Sopenharmony_cifailed_mount5:
563062306a36Sopenharmony_ci	ext4_ext_release(sb);
563162306a36Sopenharmony_ci	ext4_release_system_zone(sb);
563262306a36Sopenharmony_cifailed_mount4a:
563362306a36Sopenharmony_ci	dput(sb->s_root);
563462306a36Sopenharmony_ci	sb->s_root = NULL;
563562306a36Sopenharmony_cifailed_mount4:
563662306a36Sopenharmony_ci	ext4_msg(sb, KERN_ERR, "mount failed");
563762306a36Sopenharmony_ci	if (EXT4_SB(sb)->rsv_conversion_wq)
563862306a36Sopenharmony_ci		destroy_workqueue(EXT4_SB(sb)->rsv_conversion_wq);
563962306a36Sopenharmony_cifailed_mount_wq:
564062306a36Sopenharmony_ci	ext4_xattr_destroy_cache(sbi->s_ea_inode_cache);
564162306a36Sopenharmony_ci	sbi->s_ea_inode_cache = NULL;
564262306a36Sopenharmony_ci
564362306a36Sopenharmony_ci	ext4_xattr_destroy_cache(sbi->s_ea_block_cache);
564462306a36Sopenharmony_ci	sbi->s_ea_block_cache = NULL;
564562306a36Sopenharmony_ci
564662306a36Sopenharmony_ci	if (sbi->s_journal) {
564762306a36Sopenharmony_ci		/* flush s_sb_upd_work before journal destroy. */
564862306a36Sopenharmony_ci		flush_work(&sbi->s_sb_upd_work);
564962306a36Sopenharmony_ci		jbd2_journal_destroy(sbi->s_journal);
565062306a36Sopenharmony_ci		sbi->s_journal = NULL;
565162306a36Sopenharmony_ci	}
565262306a36Sopenharmony_cifailed_mount3a:
565362306a36Sopenharmony_ci	ext4_es_unregister_shrinker(sbi);
565462306a36Sopenharmony_cifailed_mount3:
565562306a36Sopenharmony_ci	/* flush s_sb_upd_work before sbi destroy */
565662306a36Sopenharmony_ci	flush_work(&sbi->s_sb_upd_work);
565762306a36Sopenharmony_ci	del_timer_sync(&sbi->s_err_report);
565862306a36Sopenharmony_ci	ext4_stop_mmpd(sbi);
565962306a36Sopenharmony_ci	ext4_group_desc_free(sbi);
566062306a36Sopenharmony_cifailed_mount:
566162306a36Sopenharmony_ci	if (sbi->s_chksum_driver)
566262306a36Sopenharmony_ci		crypto_free_shash(sbi->s_chksum_driver);
566362306a36Sopenharmony_ci
566462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE)
566562306a36Sopenharmony_ci	utf8_unload(sb->s_encoding);
566662306a36Sopenharmony_ci#endif
566762306a36Sopenharmony_ci
566862306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
566962306a36Sopenharmony_ci	for (unsigned int i = 0; i < EXT4_MAXQUOTAS; i++)
567062306a36Sopenharmony_ci		kfree(get_qf_name(sb, sbi, i));
567162306a36Sopenharmony_ci#endif
567262306a36Sopenharmony_ci	fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy);
567362306a36Sopenharmony_ci	brelse(sbi->s_sbh);
567462306a36Sopenharmony_ci	if (sbi->s_journal_bdev) {
567562306a36Sopenharmony_ci		invalidate_bdev(sbi->s_journal_bdev);
567662306a36Sopenharmony_ci		blkdev_put(sbi->s_journal_bdev, sb);
567762306a36Sopenharmony_ci	}
567862306a36Sopenharmony_ciout_fail:
567962306a36Sopenharmony_ci	invalidate_bdev(sb->s_bdev);
568062306a36Sopenharmony_ci	sb->s_fs_info = NULL;
568162306a36Sopenharmony_ci	return err;
568262306a36Sopenharmony_ci}
568362306a36Sopenharmony_ci
568462306a36Sopenharmony_cistatic int ext4_fill_super(struct super_block *sb, struct fs_context *fc)
568562306a36Sopenharmony_ci{
568662306a36Sopenharmony_ci	struct ext4_fs_context *ctx = fc->fs_private;
568762306a36Sopenharmony_ci	struct ext4_sb_info *sbi;
568862306a36Sopenharmony_ci	const char *descr;
568962306a36Sopenharmony_ci	int ret;
569062306a36Sopenharmony_ci
569162306a36Sopenharmony_ci	sbi = ext4_alloc_sbi(sb);
569262306a36Sopenharmony_ci	if (!sbi)
569362306a36Sopenharmony_ci		return -ENOMEM;
569462306a36Sopenharmony_ci
569562306a36Sopenharmony_ci	fc->s_fs_info = sbi;
569662306a36Sopenharmony_ci
569762306a36Sopenharmony_ci	/* Cleanup superblock name */
569862306a36Sopenharmony_ci	strreplace(sb->s_id, '/', '!');
569962306a36Sopenharmony_ci
570062306a36Sopenharmony_ci	sbi->s_sb_block = 1;	/* Default super block location */
570162306a36Sopenharmony_ci	if (ctx->spec & EXT4_SPEC_s_sb_block)
570262306a36Sopenharmony_ci		sbi->s_sb_block = ctx->s_sb_block;
570362306a36Sopenharmony_ci
570462306a36Sopenharmony_ci	ret = __ext4_fill_super(fc, sb);
570562306a36Sopenharmony_ci	if (ret < 0)
570662306a36Sopenharmony_ci		goto free_sbi;
570762306a36Sopenharmony_ci
570862306a36Sopenharmony_ci	if (sbi->s_journal) {
570962306a36Sopenharmony_ci		if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
571062306a36Sopenharmony_ci			descr = " journalled data mode";
571162306a36Sopenharmony_ci		else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
571262306a36Sopenharmony_ci			descr = " ordered data mode";
571362306a36Sopenharmony_ci		else
571462306a36Sopenharmony_ci			descr = " writeback data mode";
571562306a36Sopenharmony_ci	} else
571662306a36Sopenharmony_ci		descr = "out journal";
571762306a36Sopenharmony_ci
571862306a36Sopenharmony_ci	if (___ratelimit(&ext4_mount_msg_ratelimit, "EXT4-fs mount"))
571962306a36Sopenharmony_ci		ext4_msg(sb, KERN_INFO, "mounted filesystem %pU %s with%s. "
572062306a36Sopenharmony_ci			 "Quota mode: %s.", &sb->s_uuid,
572162306a36Sopenharmony_ci			 sb_rdonly(sb) ? "ro" : "r/w", descr,
572262306a36Sopenharmony_ci			 ext4_quota_mode(sb));
572362306a36Sopenharmony_ci
572462306a36Sopenharmony_ci	/* Update the s_overhead_clusters if necessary */
572562306a36Sopenharmony_ci	ext4_update_overhead(sb, false);
572662306a36Sopenharmony_ci	return 0;
572762306a36Sopenharmony_ci
572862306a36Sopenharmony_cifree_sbi:
572962306a36Sopenharmony_ci	ext4_free_sbi(sbi);
573062306a36Sopenharmony_ci	fc->s_fs_info = NULL;
573162306a36Sopenharmony_ci	return ret;
573262306a36Sopenharmony_ci}
573362306a36Sopenharmony_ci
573462306a36Sopenharmony_cistatic int ext4_get_tree(struct fs_context *fc)
573562306a36Sopenharmony_ci{
573662306a36Sopenharmony_ci	return get_tree_bdev(fc, ext4_fill_super);
573762306a36Sopenharmony_ci}
573862306a36Sopenharmony_ci
573962306a36Sopenharmony_ci/*
574062306a36Sopenharmony_ci * Setup any per-fs journal parameters now.  We'll do this both on
574162306a36Sopenharmony_ci * initial mount, once the journal has been initialised but before we've
574262306a36Sopenharmony_ci * done any recovery; and again on any subsequent remount.
574362306a36Sopenharmony_ci */
574462306a36Sopenharmony_cistatic void ext4_init_journal_params(struct super_block *sb, journal_t *journal)
574562306a36Sopenharmony_ci{
574662306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
574762306a36Sopenharmony_ci
574862306a36Sopenharmony_ci	journal->j_commit_interval = sbi->s_commit_interval;
574962306a36Sopenharmony_ci	journal->j_min_batch_time = sbi->s_min_batch_time;
575062306a36Sopenharmony_ci	journal->j_max_batch_time = sbi->s_max_batch_time;
575162306a36Sopenharmony_ci	ext4_fc_init(sb, journal);
575262306a36Sopenharmony_ci
575362306a36Sopenharmony_ci	write_lock(&journal->j_state_lock);
575462306a36Sopenharmony_ci	if (test_opt(sb, BARRIER))
575562306a36Sopenharmony_ci		journal->j_flags |= JBD2_BARRIER;
575662306a36Sopenharmony_ci	else
575762306a36Sopenharmony_ci		journal->j_flags &= ~JBD2_BARRIER;
575862306a36Sopenharmony_ci	if (test_opt(sb, DATA_ERR_ABORT))
575962306a36Sopenharmony_ci		journal->j_flags |= JBD2_ABORT_ON_SYNCDATA_ERR;
576062306a36Sopenharmony_ci	else
576162306a36Sopenharmony_ci		journal->j_flags &= ~JBD2_ABORT_ON_SYNCDATA_ERR;
576262306a36Sopenharmony_ci	/*
576362306a36Sopenharmony_ci	 * Always enable journal cycle record option, letting the journal
576462306a36Sopenharmony_ci	 * records log transactions continuously between each mount.
576562306a36Sopenharmony_ci	 */
576662306a36Sopenharmony_ci	journal->j_flags |= JBD2_CYCLE_RECORD;
576762306a36Sopenharmony_ci	write_unlock(&journal->j_state_lock);
576862306a36Sopenharmony_ci}
576962306a36Sopenharmony_ci
577062306a36Sopenharmony_cistatic struct inode *ext4_get_journal_inode(struct super_block *sb,
577162306a36Sopenharmony_ci					     unsigned int journal_inum)
577262306a36Sopenharmony_ci{
577362306a36Sopenharmony_ci	struct inode *journal_inode;
577462306a36Sopenharmony_ci
577562306a36Sopenharmony_ci	/*
577662306a36Sopenharmony_ci	 * Test for the existence of a valid inode on disk.  Bad things
577762306a36Sopenharmony_ci	 * happen if we iget() an unused inode, as the subsequent iput()
577862306a36Sopenharmony_ci	 * will try to delete it.
577962306a36Sopenharmony_ci	 */
578062306a36Sopenharmony_ci	journal_inode = ext4_iget(sb, journal_inum, EXT4_IGET_SPECIAL);
578162306a36Sopenharmony_ci	if (IS_ERR(journal_inode)) {
578262306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "no journal found");
578362306a36Sopenharmony_ci		return ERR_CAST(journal_inode);
578462306a36Sopenharmony_ci	}
578562306a36Sopenharmony_ci	if (!journal_inode->i_nlink) {
578662306a36Sopenharmony_ci		make_bad_inode(journal_inode);
578762306a36Sopenharmony_ci		iput(journal_inode);
578862306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "journal inode is deleted");
578962306a36Sopenharmony_ci		return ERR_PTR(-EFSCORRUPTED);
579062306a36Sopenharmony_ci	}
579162306a36Sopenharmony_ci	if (!S_ISREG(journal_inode->i_mode) || IS_ENCRYPTED(journal_inode)) {
579262306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "invalid journal inode");
579362306a36Sopenharmony_ci		iput(journal_inode);
579462306a36Sopenharmony_ci		return ERR_PTR(-EFSCORRUPTED);
579562306a36Sopenharmony_ci	}
579662306a36Sopenharmony_ci
579762306a36Sopenharmony_ci	ext4_debug("Journal inode found at %p: %lld bytes\n",
579862306a36Sopenharmony_ci		  journal_inode, journal_inode->i_size);
579962306a36Sopenharmony_ci	return journal_inode;
580062306a36Sopenharmony_ci}
580162306a36Sopenharmony_ci
580262306a36Sopenharmony_cistatic int ext4_journal_bmap(journal_t *journal, sector_t *block)
580362306a36Sopenharmony_ci{
580462306a36Sopenharmony_ci	struct ext4_map_blocks map;
580562306a36Sopenharmony_ci	int ret;
580662306a36Sopenharmony_ci
580762306a36Sopenharmony_ci	if (journal->j_inode == NULL)
580862306a36Sopenharmony_ci		return 0;
580962306a36Sopenharmony_ci
581062306a36Sopenharmony_ci	map.m_lblk = *block;
581162306a36Sopenharmony_ci	map.m_len = 1;
581262306a36Sopenharmony_ci	ret = ext4_map_blocks(NULL, journal->j_inode, &map, 0);
581362306a36Sopenharmony_ci	if (ret <= 0) {
581462306a36Sopenharmony_ci		ext4_msg(journal->j_inode->i_sb, KERN_CRIT,
581562306a36Sopenharmony_ci			 "journal bmap failed: block %llu ret %d\n",
581662306a36Sopenharmony_ci			 *block, ret);
581762306a36Sopenharmony_ci		jbd2_journal_abort(journal, ret ? ret : -EIO);
581862306a36Sopenharmony_ci		return ret;
581962306a36Sopenharmony_ci	}
582062306a36Sopenharmony_ci	*block = map.m_pblk;
582162306a36Sopenharmony_ci	return 0;
582262306a36Sopenharmony_ci}
582362306a36Sopenharmony_ci
582462306a36Sopenharmony_cistatic journal_t *ext4_open_inode_journal(struct super_block *sb,
582562306a36Sopenharmony_ci					  unsigned int journal_inum)
582662306a36Sopenharmony_ci{
582762306a36Sopenharmony_ci	struct inode *journal_inode;
582862306a36Sopenharmony_ci	journal_t *journal;
582962306a36Sopenharmony_ci
583062306a36Sopenharmony_ci	journal_inode = ext4_get_journal_inode(sb, journal_inum);
583162306a36Sopenharmony_ci	if (IS_ERR(journal_inode))
583262306a36Sopenharmony_ci		return ERR_CAST(journal_inode);
583362306a36Sopenharmony_ci
583462306a36Sopenharmony_ci	journal = jbd2_journal_init_inode(journal_inode);
583562306a36Sopenharmony_ci	if (IS_ERR(journal)) {
583662306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "Could not load journal inode");
583762306a36Sopenharmony_ci		iput(journal_inode);
583862306a36Sopenharmony_ci		return ERR_CAST(journal);
583962306a36Sopenharmony_ci	}
584062306a36Sopenharmony_ci	journal->j_private = sb;
584162306a36Sopenharmony_ci	journal->j_bmap = ext4_journal_bmap;
584262306a36Sopenharmony_ci	ext4_init_journal_params(sb, journal);
584362306a36Sopenharmony_ci	return journal;
584462306a36Sopenharmony_ci}
584562306a36Sopenharmony_ci
584662306a36Sopenharmony_cistatic struct block_device *ext4_get_journal_blkdev(struct super_block *sb,
584762306a36Sopenharmony_ci					dev_t j_dev, ext4_fsblk_t *j_start,
584862306a36Sopenharmony_ci					ext4_fsblk_t *j_len)
584962306a36Sopenharmony_ci{
585062306a36Sopenharmony_ci	struct buffer_head *bh;
585162306a36Sopenharmony_ci	struct block_device *bdev;
585262306a36Sopenharmony_ci	int hblock, blocksize;
585362306a36Sopenharmony_ci	ext4_fsblk_t sb_block;
585462306a36Sopenharmony_ci	unsigned long offset;
585562306a36Sopenharmony_ci	struct ext4_super_block *es;
585662306a36Sopenharmony_ci	int errno;
585762306a36Sopenharmony_ci
585862306a36Sopenharmony_ci	/* see get_tree_bdev why this is needed and safe */
585962306a36Sopenharmony_ci	up_write(&sb->s_umount);
586062306a36Sopenharmony_ci	bdev = blkdev_get_by_dev(j_dev, BLK_OPEN_READ | BLK_OPEN_WRITE, sb,
586162306a36Sopenharmony_ci				 &fs_holder_ops);
586262306a36Sopenharmony_ci	down_write(&sb->s_umount);
586362306a36Sopenharmony_ci	if (IS_ERR(bdev)) {
586462306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR,
586562306a36Sopenharmony_ci			 "failed to open journal device unknown-block(%u,%u) %ld",
586662306a36Sopenharmony_ci			 MAJOR(j_dev), MINOR(j_dev), PTR_ERR(bdev));
586762306a36Sopenharmony_ci		return ERR_CAST(bdev);
586862306a36Sopenharmony_ci	}
586962306a36Sopenharmony_ci
587062306a36Sopenharmony_ci	blocksize = sb->s_blocksize;
587162306a36Sopenharmony_ci	hblock = bdev_logical_block_size(bdev);
587262306a36Sopenharmony_ci	if (blocksize < hblock) {
587362306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR,
587462306a36Sopenharmony_ci			"blocksize too small for journal device");
587562306a36Sopenharmony_ci		errno = -EINVAL;
587662306a36Sopenharmony_ci		goto out_bdev;
587762306a36Sopenharmony_ci	}
587862306a36Sopenharmony_ci
587962306a36Sopenharmony_ci	sb_block = EXT4_MIN_BLOCK_SIZE / blocksize;
588062306a36Sopenharmony_ci	offset = EXT4_MIN_BLOCK_SIZE % blocksize;
588162306a36Sopenharmony_ci	set_blocksize(bdev, blocksize);
588262306a36Sopenharmony_ci	bh = __bread(bdev, sb_block, blocksize);
588362306a36Sopenharmony_ci	if (!bh) {
588462306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "couldn't read superblock of "
588562306a36Sopenharmony_ci		       "external journal");
588662306a36Sopenharmony_ci		errno = -EINVAL;
588762306a36Sopenharmony_ci		goto out_bdev;
588862306a36Sopenharmony_ci	}
588962306a36Sopenharmony_ci
589062306a36Sopenharmony_ci	es = (struct ext4_super_block *) (bh->b_data + offset);
589162306a36Sopenharmony_ci	if ((le16_to_cpu(es->s_magic) != EXT4_SUPER_MAGIC) ||
589262306a36Sopenharmony_ci	    !(le32_to_cpu(es->s_feature_incompat) &
589362306a36Sopenharmony_ci	      EXT4_FEATURE_INCOMPAT_JOURNAL_DEV)) {
589462306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "external journal has bad superblock");
589562306a36Sopenharmony_ci		errno = -EFSCORRUPTED;
589662306a36Sopenharmony_ci		goto out_bh;
589762306a36Sopenharmony_ci	}
589862306a36Sopenharmony_ci
589962306a36Sopenharmony_ci	if ((le32_to_cpu(es->s_feature_ro_compat) &
590062306a36Sopenharmony_ci	     EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
590162306a36Sopenharmony_ci	    es->s_checksum != ext4_superblock_csum(sb, es)) {
590262306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "external journal has corrupt superblock");
590362306a36Sopenharmony_ci		errno = -EFSCORRUPTED;
590462306a36Sopenharmony_ci		goto out_bh;
590562306a36Sopenharmony_ci	}
590662306a36Sopenharmony_ci
590762306a36Sopenharmony_ci	if (memcmp(EXT4_SB(sb)->s_es->s_journal_uuid, es->s_uuid, 16)) {
590862306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "journal UUID does not match");
590962306a36Sopenharmony_ci		errno = -EFSCORRUPTED;
591062306a36Sopenharmony_ci		goto out_bh;
591162306a36Sopenharmony_ci	}
591262306a36Sopenharmony_ci
591362306a36Sopenharmony_ci	*j_start = sb_block + 1;
591462306a36Sopenharmony_ci	*j_len = ext4_blocks_count(es);
591562306a36Sopenharmony_ci	brelse(bh);
591662306a36Sopenharmony_ci	return bdev;
591762306a36Sopenharmony_ci
591862306a36Sopenharmony_ciout_bh:
591962306a36Sopenharmony_ci	brelse(bh);
592062306a36Sopenharmony_ciout_bdev:
592162306a36Sopenharmony_ci	blkdev_put(bdev, sb);
592262306a36Sopenharmony_ci	return ERR_PTR(errno);
592362306a36Sopenharmony_ci}
592462306a36Sopenharmony_ci
592562306a36Sopenharmony_cistatic journal_t *ext4_open_dev_journal(struct super_block *sb,
592662306a36Sopenharmony_ci					dev_t j_dev)
592762306a36Sopenharmony_ci{
592862306a36Sopenharmony_ci	journal_t *journal;
592962306a36Sopenharmony_ci	ext4_fsblk_t j_start;
593062306a36Sopenharmony_ci	ext4_fsblk_t j_len;
593162306a36Sopenharmony_ci	struct block_device *journal_bdev;
593262306a36Sopenharmony_ci	int errno = 0;
593362306a36Sopenharmony_ci
593462306a36Sopenharmony_ci	journal_bdev = ext4_get_journal_blkdev(sb, j_dev, &j_start, &j_len);
593562306a36Sopenharmony_ci	if (IS_ERR(journal_bdev))
593662306a36Sopenharmony_ci		return ERR_CAST(journal_bdev);
593762306a36Sopenharmony_ci
593862306a36Sopenharmony_ci	journal = jbd2_journal_init_dev(journal_bdev, sb->s_bdev, j_start,
593962306a36Sopenharmony_ci					j_len, sb->s_blocksize);
594062306a36Sopenharmony_ci	if (IS_ERR(journal)) {
594162306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "failed to create device journal");
594262306a36Sopenharmony_ci		errno = PTR_ERR(journal);
594362306a36Sopenharmony_ci		goto out_bdev;
594462306a36Sopenharmony_ci	}
594562306a36Sopenharmony_ci	if (be32_to_cpu(journal->j_superblock->s_nr_users) != 1) {
594662306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "External journal has more than one "
594762306a36Sopenharmony_ci					"user (unsupported) - %d",
594862306a36Sopenharmony_ci			be32_to_cpu(journal->j_superblock->s_nr_users));
594962306a36Sopenharmony_ci		errno = -EINVAL;
595062306a36Sopenharmony_ci		goto out_journal;
595162306a36Sopenharmony_ci	}
595262306a36Sopenharmony_ci	journal->j_private = sb;
595362306a36Sopenharmony_ci	EXT4_SB(sb)->s_journal_bdev = journal_bdev;
595462306a36Sopenharmony_ci	ext4_init_journal_params(sb, journal);
595562306a36Sopenharmony_ci	return journal;
595662306a36Sopenharmony_ci
595762306a36Sopenharmony_ciout_journal:
595862306a36Sopenharmony_ci	jbd2_journal_destroy(journal);
595962306a36Sopenharmony_ciout_bdev:
596062306a36Sopenharmony_ci	blkdev_put(journal_bdev, sb);
596162306a36Sopenharmony_ci	return ERR_PTR(errno);
596262306a36Sopenharmony_ci}
596362306a36Sopenharmony_ci
596462306a36Sopenharmony_cistatic int ext4_load_journal(struct super_block *sb,
596562306a36Sopenharmony_ci			     struct ext4_super_block *es,
596662306a36Sopenharmony_ci			     unsigned long journal_devnum)
596762306a36Sopenharmony_ci{
596862306a36Sopenharmony_ci	journal_t *journal;
596962306a36Sopenharmony_ci	unsigned int journal_inum = le32_to_cpu(es->s_journal_inum);
597062306a36Sopenharmony_ci	dev_t journal_dev;
597162306a36Sopenharmony_ci	int err = 0;
597262306a36Sopenharmony_ci	int really_read_only;
597362306a36Sopenharmony_ci	int journal_dev_ro;
597462306a36Sopenharmony_ci
597562306a36Sopenharmony_ci	if (WARN_ON_ONCE(!ext4_has_feature_journal(sb)))
597662306a36Sopenharmony_ci		return -EFSCORRUPTED;
597762306a36Sopenharmony_ci
597862306a36Sopenharmony_ci	if (journal_devnum &&
597962306a36Sopenharmony_ci	    journal_devnum != le32_to_cpu(es->s_journal_dev)) {
598062306a36Sopenharmony_ci		ext4_msg(sb, KERN_INFO, "external journal device major/minor "
598162306a36Sopenharmony_ci			"numbers have changed");
598262306a36Sopenharmony_ci		journal_dev = new_decode_dev(journal_devnum);
598362306a36Sopenharmony_ci	} else
598462306a36Sopenharmony_ci		journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev));
598562306a36Sopenharmony_ci
598662306a36Sopenharmony_ci	if (journal_inum && journal_dev) {
598762306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR,
598862306a36Sopenharmony_ci			 "filesystem has both journal inode and journal device!");
598962306a36Sopenharmony_ci		return -EINVAL;
599062306a36Sopenharmony_ci	}
599162306a36Sopenharmony_ci
599262306a36Sopenharmony_ci	if (journal_inum) {
599362306a36Sopenharmony_ci		journal = ext4_open_inode_journal(sb, journal_inum);
599462306a36Sopenharmony_ci		if (IS_ERR(journal))
599562306a36Sopenharmony_ci			return PTR_ERR(journal);
599662306a36Sopenharmony_ci	} else {
599762306a36Sopenharmony_ci		journal = ext4_open_dev_journal(sb, journal_dev);
599862306a36Sopenharmony_ci		if (IS_ERR(journal))
599962306a36Sopenharmony_ci			return PTR_ERR(journal);
600062306a36Sopenharmony_ci	}
600162306a36Sopenharmony_ci
600262306a36Sopenharmony_ci	journal_dev_ro = bdev_read_only(journal->j_dev);
600362306a36Sopenharmony_ci	really_read_only = bdev_read_only(sb->s_bdev) | journal_dev_ro;
600462306a36Sopenharmony_ci
600562306a36Sopenharmony_ci	if (journal_dev_ro && !sb_rdonly(sb)) {
600662306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR,
600762306a36Sopenharmony_ci			 "journal device read-only, try mounting with '-o ro'");
600862306a36Sopenharmony_ci		err = -EROFS;
600962306a36Sopenharmony_ci		goto err_out;
601062306a36Sopenharmony_ci	}
601162306a36Sopenharmony_ci
601262306a36Sopenharmony_ci	/*
601362306a36Sopenharmony_ci	 * Are we loading a blank journal or performing recovery after a
601462306a36Sopenharmony_ci	 * crash?  For recovery, we need to check in advance whether we
601562306a36Sopenharmony_ci	 * can get read-write access to the device.
601662306a36Sopenharmony_ci	 */
601762306a36Sopenharmony_ci	if (ext4_has_feature_journal_needs_recovery(sb)) {
601862306a36Sopenharmony_ci		if (sb_rdonly(sb)) {
601962306a36Sopenharmony_ci			ext4_msg(sb, KERN_INFO, "INFO: recovery "
602062306a36Sopenharmony_ci					"required on readonly filesystem");
602162306a36Sopenharmony_ci			if (really_read_only) {
602262306a36Sopenharmony_ci				ext4_msg(sb, KERN_ERR, "write access "
602362306a36Sopenharmony_ci					"unavailable, cannot proceed "
602462306a36Sopenharmony_ci					"(try mounting with noload)");
602562306a36Sopenharmony_ci				err = -EROFS;
602662306a36Sopenharmony_ci				goto err_out;
602762306a36Sopenharmony_ci			}
602862306a36Sopenharmony_ci			ext4_msg(sb, KERN_INFO, "write access will "
602962306a36Sopenharmony_ci			       "be enabled during recovery");
603062306a36Sopenharmony_ci		}
603162306a36Sopenharmony_ci	}
603262306a36Sopenharmony_ci
603362306a36Sopenharmony_ci	if (!(journal->j_flags & JBD2_BARRIER))
603462306a36Sopenharmony_ci		ext4_msg(sb, KERN_INFO, "barriers disabled");
603562306a36Sopenharmony_ci
603662306a36Sopenharmony_ci	if (!ext4_has_feature_journal_needs_recovery(sb))
603762306a36Sopenharmony_ci		err = jbd2_journal_wipe(journal, !really_read_only);
603862306a36Sopenharmony_ci	if (!err) {
603962306a36Sopenharmony_ci		char *save = kmalloc(EXT4_S_ERR_LEN, GFP_KERNEL);
604062306a36Sopenharmony_ci		__le16 orig_state;
604162306a36Sopenharmony_ci		bool changed = false;
604262306a36Sopenharmony_ci
604362306a36Sopenharmony_ci		if (save)
604462306a36Sopenharmony_ci			memcpy(save, ((char *) es) +
604562306a36Sopenharmony_ci			       EXT4_S_ERR_START, EXT4_S_ERR_LEN);
604662306a36Sopenharmony_ci		err = jbd2_journal_load(journal);
604762306a36Sopenharmony_ci		if (save && memcmp(((char *) es) + EXT4_S_ERR_START,
604862306a36Sopenharmony_ci				   save, EXT4_S_ERR_LEN)) {
604962306a36Sopenharmony_ci			memcpy(((char *) es) + EXT4_S_ERR_START,
605062306a36Sopenharmony_ci			       save, EXT4_S_ERR_LEN);
605162306a36Sopenharmony_ci			changed = true;
605262306a36Sopenharmony_ci		}
605362306a36Sopenharmony_ci		kfree(save);
605462306a36Sopenharmony_ci		orig_state = es->s_state;
605562306a36Sopenharmony_ci		es->s_state |= cpu_to_le16(EXT4_SB(sb)->s_mount_state &
605662306a36Sopenharmony_ci					   EXT4_ERROR_FS);
605762306a36Sopenharmony_ci		if (orig_state != es->s_state)
605862306a36Sopenharmony_ci			changed = true;
605962306a36Sopenharmony_ci		/* Write out restored error information to the superblock */
606062306a36Sopenharmony_ci		if (changed && !really_read_only) {
606162306a36Sopenharmony_ci			int err2;
606262306a36Sopenharmony_ci			err2 = ext4_commit_super(sb);
606362306a36Sopenharmony_ci			err = err ? : err2;
606462306a36Sopenharmony_ci		}
606562306a36Sopenharmony_ci	}
606662306a36Sopenharmony_ci
606762306a36Sopenharmony_ci	if (err) {
606862306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "error loading journal");
606962306a36Sopenharmony_ci		goto err_out;
607062306a36Sopenharmony_ci	}
607162306a36Sopenharmony_ci
607262306a36Sopenharmony_ci	EXT4_SB(sb)->s_journal = journal;
607362306a36Sopenharmony_ci	err = ext4_clear_journal_err(sb, es);
607462306a36Sopenharmony_ci	if (err) {
607562306a36Sopenharmony_ci		EXT4_SB(sb)->s_journal = NULL;
607662306a36Sopenharmony_ci		jbd2_journal_destroy(journal);
607762306a36Sopenharmony_ci		return err;
607862306a36Sopenharmony_ci	}
607962306a36Sopenharmony_ci
608062306a36Sopenharmony_ci	if (!really_read_only && journal_devnum &&
608162306a36Sopenharmony_ci	    journal_devnum != le32_to_cpu(es->s_journal_dev)) {
608262306a36Sopenharmony_ci		es->s_journal_dev = cpu_to_le32(journal_devnum);
608362306a36Sopenharmony_ci		ext4_commit_super(sb);
608462306a36Sopenharmony_ci	}
608562306a36Sopenharmony_ci	if (!really_read_only && journal_inum &&
608662306a36Sopenharmony_ci	    journal_inum != le32_to_cpu(es->s_journal_inum)) {
608762306a36Sopenharmony_ci		es->s_journal_inum = cpu_to_le32(journal_inum);
608862306a36Sopenharmony_ci		ext4_commit_super(sb);
608962306a36Sopenharmony_ci	}
609062306a36Sopenharmony_ci
609162306a36Sopenharmony_ci	return 0;
609262306a36Sopenharmony_ci
609362306a36Sopenharmony_cierr_out:
609462306a36Sopenharmony_ci	jbd2_journal_destroy(journal);
609562306a36Sopenharmony_ci	return err;
609662306a36Sopenharmony_ci}
609762306a36Sopenharmony_ci
609862306a36Sopenharmony_ci/* Copy state of EXT4_SB(sb) into buffer for on-disk superblock */
609962306a36Sopenharmony_cistatic void ext4_update_super(struct super_block *sb)
610062306a36Sopenharmony_ci{
610162306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
610262306a36Sopenharmony_ci	struct ext4_super_block *es = sbi->s_es;
610362306a36Sopenharmony_ci	struct buffer_head *sbh = sbi->s_sbh;
610462306a36Sopenharmony_ci
610562306a36Sopenharmony_ci	lock_buffer(sbh);
610662306a36Sopenharmony_ci	/*
610762306a36Sopenharmony_ci	 * If the file system is mounted read-only, don't update the
610862306a36Sopenharmony_ci	 * superblock write time.  This avoids updating the superblock
610962306a36Sopenharmony_ci	 * write time when we are mounting the root file system
611062306a36Sopenharmony_ci	 * read/only but we need to replay the journal; at that point,
611162306a36Sopenharmony_ci	 * for people who are east of GMT and who make their clock
611262306a36Sopenharmony_ci	 * tick in localtime for Windows bug-for-bug compatibility,
611362306a36Sopenharmony_ci	 * the clock is set in the future, and this will cause e2fsck
611462306a36Sopenharmony_ci	 * to complain and force a full file system check.
611562306a36Sopenharmony_ci	 */
611662306a36Sopenharmony_ci	if (!sb_rdonly(sb))
611762306a36Sopenharmony_ci		ext4_update_tstamp(es, s_wtime);
611862306a36Sopenharmony_ci	es->s_kbytes_written =
611962306a36Sopenharmony_ci		cpu_to_le64(sbi->s_kbytes_written +
612062306a36Sopenharmony_ci		    ((part_stat_read(sb->s_bdev, sectors[STAT_WRITE]) -
612162306a36Sopenharmony_ci		      sbi->s_sectors_written_start) >> 1));
612262306a36Sopenharmony_ci	if (percpu_counter_initialized(&sbi->s_freeclusters_counter))
612362306a36Sopenharmony_ci		ext4_free_blocks_count_set(es,
612462306a36Sopenharmony_ci			EXT4_C2B(sbi, percpu_counter_sum_positive(
612562306a36Sopenharmony_ci				&sbi->s_freeclusters_counter)));
612662306a36Sopenharmony_ci	if (percpu_counter_initialized(&sbi->s_freeinodes_counter))
612762306a36Sopenharmony_ci		es->s_free_inodes_count =
612862306a36Sopenharmony_ci			cpu_to_le32(percpu_counter_sum_positive(
612962306a36Sopenharmony_ci				&sbi->s_freeinodes_counter));
613062306a36Sopenharmony_ci	/* Copy error information to the on-disk superblock */
613162306a36Sopenharmony_ci	spin_lock(&sbi->s_error_lock);
613262306a36Sopenharmony_ci	if (sbi->s_add_error_count > 0) {
613362306a36Sopenharmony_ci		es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
613462306a36Sopenharmony_ci		if (!es->s_first_error_time && !es->s_first_error_time_hi) {
613562306a36Sopenharmony_ci			__ext4_update_tstamp(&es->s_first_error_time,
613662306a36Sopenharmony_ci					     &es->s_first_error_time_hi,
613762306a36Sopenharmony_ci					     sbi->s_first_error_time);
613862306a36Sopenharmony_ci			strncpy(es->s_first_error_func, sbi->s_first_error_func,
613962306a36Sopenharmony_ci				sizeof(es->s_first_error_func));
614062306a36Sopenharmony_ci			es->s_first_error_line =
614162306a36Sopenharmony_ci				cpu_to_le32(sbi->s_first_error_line);
614262306a36Sopenharmony_ci			es->s_first_error_ino =
614362306a36Sopenharmony_ci				cpu_to_le32(sbi->s_first_error_ino);
614462306a36Sopenharmony_ci			es->s_first_error_block =
614562306a36Sopenharmony_ci				cpu_to_le64(sbi->s_first_error_block);
614662306a36Sopenharmony_ci			es->s_first_error_errcode =
614762306a36Sopenharmony_ci				ext4_errno_to_code(sbi->s_first_error_code);
614862306a36Sopenharmony_ci		}
614962306a36Sopenharmony_ci		__ext4_update_tstamp(&es->s_last_error_time,
615062306a36Sopenharmony_ci				     &es->s_last_error_time_hi,
615162306a36Sopenharmony_ci				     sbi->s_last_error_time);
615262306a36Sopenharmony_ci		strncpy(es->s_last_error_func, sbi->s_last_error_func,
615362306a36Sopenharmony_ci			sizeof(es->s_last_error_func));
615462306a36Sopenharmony_ci		es->s_last_error_line = cpu_to_le32(sbi->s_last_error_line);
615562306a36Sopenharmony_ci		es->s_last_error_ino = cpu_to_le32(sbi->s_last_error_ino);
615662306a36Sopenharmony_ci		es->s_last_error_block = cpu_to_le64(sbi->s_last_error_block);
615762306a36Sopenharmony_ci		es->s_last_error_errcode =
615862306a36Sopenharmony_ci				ext4_errno_to_code(sbi->s_last_error_code);
615962306a36Sopenharmony_ci		/*
616062306a36Sopenharmony_ci		 * Start the daily error reporting function if it hasn't been
616162306a36Sopenharmony_ci		 * started already
616262306a36Sopenharmony_ci		 */
616362306a36Sopenharmony_ci		if (!es->s_error_count)
616462306a36Sopenharmony_ci			mod_timer(&sbi->s_err_report, jiffies + 24*60*60*HZ);
616562306a36Sopenharmony_ci		le32_add_cpu(&es->s_error_count, sbi->s_add_error_count);
616662306a36Sopenharmony_ci		sbi->s_add_error_count = 0;
616762306a36Sopenharmony_ci	}
616862306a36Sopenharmony_ci	spin_unlock(&sbi->s_error_lock);
616962306a36Sopenharmony_ci
617062306a36Sopenharmony_ci	ext4_superblock_csum_set(sb);
617162306a36Sopenharmony_ci	unlock_buffer(sbh);
617262306a36Sopenharmony_ci}
617362306a36Sopenharmony_ci
617462306a36Sopenharmony_cistatic int ext4_commit_super(struct super_block *sb)
617562306a36Sopenharmony_ci{
617662306a36Sopenharmony_ci	struct buffer_head *sbh = EXT4_SB(sb)->s_sbh;
617762306a36Sopenharmony_ci
617862306a36Sopenharmony_ci	if (!sbh)
617962306a36Sopenharmony_ci		return -EINVAL;
618062306a36Sopenharmony_ci	if (block_device_ejected(sb))
618162306a36Sopenharmony_ci		return -ENODEV;
618262306a36Sopenharmony_ci
618362306a36Sopenharmony_ci	ext4_update_super(sb);
618462306a36Sopenharmony_ci
618562306a36Sopenharmony_ci	lock_buffer(sbh);
618662306a36Sopenharmony_ci	/* Buffer got discarded which means block device got invalidated */
618762306a36Sopenharmony_ci	if (!buffer_mapped(sbh)) {
618862306a36Sopenharmony_ci		unlock_buffer(sbh);
618962306a36Sopenharmony_ci		return -EIO;
619062306a36Sopenharmony_ci	}
619162306a36Sopenharmony_ci
619262306a36Sopenharmony_ci	if (buffer_write_io_error(sbh) || !buffer_uptodate(sbh)) {
619362306a36Sopenharmony_ci		/*
619462306a36Sopenharmony_ci		 * Oh, dear.  A previous attempt to write the
619562306a36Sopenharmony_ci		 * superblock failed.  This could happen because the
619662306a36Sopenharmony_ci		 * USB device was yanked out.  Or it could happen to
619762306a36Sopenharmony_ci		 * be a transient write error and maybe the block will
619862306a36Sopenharmony_ci		 * be remapped.  Nothing we can do but to retry the
619962306a36Sopenharmony_ci		 * write and hope for the best.
620062306a36Sopenharmony_ci		 */
620162306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "previous I/O error to "
620262306a36Sopenharmony_ci		       "superblock detected");
620362306a36Sopenharmony_ci		clear_buffer_write_io_error(sbh);
620462306a36Sopenharmony_ci		set_buffer_uptodate(sbh);
620562306a36Sopenharmony_ci	}
620662306a36Sopenharmony_ci	get_bh(sbh);
620762306a36Sopenharmony_ci	/* Clear potential dirty bit if it was journalled update */
620862306a36Sopenharmony_ci	clear_buffer_dirty(sbh);
620962306a36Sopenharmony_ci	sbh->b_end_io = end_buffer_write_sync;
621062306a36Sopenharmony_ci	submit_bh(REQ_OP_WRITE | REQ_SYNC |
621162306a36Sopenharmony_ci		  (test_opt(sb, BARRIER) ? REQ_FUA : 0), sbh);
621262306a36Sopenharmony_ci	wait_on_buffer(sbh);
621362306a36Sopenharmony_ci	if (buffer_write_io_error(sbh)) {
621462306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "I/O error while writing "
621562306a36Sopenharmony_ci		       "superblock");
621662306a36Sopenharmony_ci		clear_buffer_write_io_error(sbh);
621762306a36Sopenharmony_ci		set_buffer_uptodate(sbh);
621862306a36Sopenharmony_ci		return -EIO;
621962306a36Sopenharmony_ci	}
622062306a36Sopenharmony_ci	return 0;
622162306a36Sopenharmony_ci}
622262306a36Sopenharmony_ci
622362306a36Sopenharmony_ci/*
622462306a36Sopenharmony_ci * Have we just finished recovery?  If so, and if we are mounting (or
622562306a36Sopenharmony_ci * remounting) the filesystem readonly, then we will end up with a
622662306a36Sopenharmony_ci * consistent fs on disk.  Record that fact.
622762306a36Sopenharmony_ci */
622862306a36Sopenharmony_cistatic int ext4_mark_recovery_complete(struct super_block *sb,
622962306a36Sopenharmony_ci				       struct ext4_super_block *es)
623062306a36Sopenharmony_ci{
623162306a36Sopenharmony_ci	int err;
623262306a36Sopenharmony_ci	journal_t *journal = EXT4_SB(sb)->s_journal;
623362306a36Sopenharmony_ci
623462306a36Sopenharmony_ci	if (!ext4_has_feature_journal(sb)) {
623562306a36Sopenharmony_ci		if (journal != NULL) {
623662306a36Sopenharmony_ci			ext4_error(sb, "Journal got removed while the fs was "
623762306a36Sopenharmony_ci				   "mounted!");
623862306a36Sopenharmony_ci			return -EFSCORRUPTED;
623962306a36Sopenharmony_ci		}
624062306a36Sopenharmony_ci		return 0;
624162306a36Sopenharmony_ci	}
624262306a36Sopenharmony_ci	jbd2_journal_lock_updates(journal);
624362306a36Sopenharmony_ci	err = jbd2_journal_flush(journal, 0);
624462306a36Sopenharmony_ci	if (err < 0)
624562306a36Sopenharmony_ci		goto out;
624662306a36Sopenharmony_ci
624762306a36Sopenharmony_ci	if (sb_rdonly(sb) && (ext4_has_feature_journal_needs_recovery(sb) ||
624862306a36Sopenharmony_ci	    ext4_has_feature_orphan_present(sb))) {
624962306a36Sopenharmony_ci		if (!ext4_orphan_file_empty(sb)) {
625062306a36Sopenharmony_ci			ext4_error(sb, "Orphan file not empty on read-only fs.");
625162306a36Sopenharmony_ci			err = -EFSCORRUPTED;
625262306a36Sopenharmony_ci			goto out;
625362306a36Sopenharmony_ci		}
625462306a36Sopenharmony_ci		ext4_clear_feature_journal_needs_recovery(sb);
625562306a36Sopenharmony_ci		ext4_clear_feature_orphan_present(sb);
625662306a36Sopenharmony_ci		ext4_commit_super(sb);
625762306a36Sopenharmony_ci	}
625862306a36Sopenharmony_ciout:
625962306a36Sopenharmony_ci	jbd2_journal_unlock_updates(journal);
626062306a36Sopenharmony_ci	return err;
626162306a36Sopenharmony_ci}
626262306a36Sopenharmony_ci
626362306a36Sopenharmony_ci/*
626462306a36Sopenharmony_ci * If we are mounting (or read-write remounting) a filesystem whose journal
626562306a36Sopenharmony_ci * has recorded an error from a previous lifetime, move that error to the
626662306a36Sopenharmony_ci * main filesystem now.
626762306a36Sopenharmony_ci */
626862306a36Sopenharmony_cistatic int ext4_clear_journal_err(struct super_block *sb,
626962306a36Sopenharmony_ci				   struct ext4_super_block *es)
627062306a36Sopenharmony_ci{
627162306a36Sopenharmony_ci	journal_t *journal;
627262306a36Sopenharmony_ci	int j_errno;
627362306a36Sopenharmony_ci	const char *errstr;
627462306a36Sopenharmony_ci
627562306a36Sopenharmony_ci	if (!ext4_has_feature_journal(sb)) {
627662306a36Sopenharmony_ci		ext4_error(sb, "Journal got removed while the fs was mounted!");
627762306a36Sopenharmony_ci		return -EFSCORRUPTED;
627862306a36Sopenharmony_ci	}
627962306a36Sopenharmony_ci
628062306a36Sopenharmony_ci	journal = EXT4_SB(sb)->s_journal;
628162306a36Sopenharmony_ci
628262306a36Sopenharmony_ci	/*
628362306a36Sopenharmony_ci	 * Now check for any error status which may have been recorded in the
628462306a36Sopenharmony_ci	 * journal by a prior ext4_error() or ext4_abort()
628562306a36Sopenharmony_ci	 */
628662306a36Sopenharmony_ci
628762306a36Sopenharmony_ci	j_errno = jbd2_journal_errno(journal);
628862306a36Sopenharmony_ci	if (j_errno) {
628962306a36Sopenharmony_ci		char nbuf[16];
629062306a36Sopenharmony_ci
629162306a36Sopenharmony_ci		errstr = ext4_decode_error(sb, j_errno, nbuf);
629262306a36Sopenharmony_ci		ext4_warning(sb, "Filesystem error recorded "
629362306a36Sopenharmony_ci			     "from previous mount: %s", errstr);
629462306a36Sopenharmony_ci
629562306a36Sopenharmony_ci		EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
629662306a36Sopenharmony_ci		es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
629762306a36Sopenharmony_ci		j_errno = ext4_commit_super(sb);
629862306a36Sopenharmony_ci		if (j_errno)
629962306a36Sopenharmony_ci			return j_errno;
630062306a36Sopenharmony_ci		ext4_warning(sb, "Marked fs in need of filesystem check.");
630162306a36Sopenharmony_ci
630262306a36Sopenharmony_ci		jbd2_journal_clear_err(journal);
630362306a36Sopenharmony_ci		jbd2_journal_update_sb_errno(journal);
630462306a36Sopenharmony_ci	}
630562306a36Sopenharmony_ci	return 0;
630662306a36Sopenharmony_ci}
630762306a36Sopenharmony_ci
630862306a36Sopenharmony_ci/*
630962306a36Sopenharmony_ci * Force the running and committing transactions to commit,
631062306a36Sopenharmony_ci * and wait on the commit.
631162306a36Sopenharmony_ci */
631262306a36Sopenharmony_ciint ext4_force_commit(struct super_block *sb)
631362306a36Sopenharmony_ci{
631462306a36Sopenharmony_ci	return ext4_journal_force_commit(EXT4_SB(sb)->s_journal);
631562306a36Sopenharmony_ci}
631662306a36Sopenharmony_ci
631762306a36Sopenharmony_cistatic int ext4_sync_fs(struct super_block *sb, int wait)
631862306a36Sopenharmony_ci{
631962306a36Sopenharmony_ci	int ret = 0;
632062306a36Sopenharmony_ci	tid_t target;
632162306a36Sopenharmony_ci	bool needs_barrier = false;
632262306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
632362306a36Sopenharmony_ci
632462306a36Sopenharmony_ci	if (unlikely(ext4_forced_shutdown(sb)))
632562306a36Sopenharmony_ci		return 0;
632662306a36Sopenharmony_ci
632762306a36Sopenharmony_ci	trace_ext4_sync_fs(sb, wait);
632862306a36Sopenharmony_ci	flush_workqueue(sbi->rsv_conversion_wq);
632962306a36Sopenharmony_ci	/*
633062306a36Sopenharmony_ci	 * Writeback quota in non-journalled quota case - journalled quota has
633162306a36Sopenharmony_ci	 * no dirty dquots
633262306a36Sopenharmony_ci	 */
633362306a36Sopenharmony_ci	dquot_writeback_dquots(sb, -1);
633462306a36Sopenharmony_ci	/*
633562306a36Sopenharmony_ci	 * Data writeback is possible w/o journal transaction, so barrier must
633662306a36Sopenharmony_ci	 * being sent at the end of the function. But we can skip it if
633762306a36Sopenharmony_ci	 * transaction_commit will do it for us.
633862306a36Sopenharmony_ci	 */
633962306a36Sopenharmony_ci	if (sbi->s_journal) {
634062306a36Sopenharmony_ci		target = jbd2_get_latest_transaction(sbi->s_journal);
634162306a36Sopenharmony_ci		if (wait && sbi->s_journal->j_flags & JBD2_BARRIER &&
634262306a36Sopenharmony_ci		    !jbd2_trans_will_send_data_barrier(sbi->s_journal, target))
634362306a36Sopenharmony_ci			needs_barrier = true;
634462306a36Sopenharmony_ci
634562306a36Sopenharmony_ci		if (jbd2_journal_start_commit(sbi->s_journal, &target)) {
634662306a36Sopenharmony_ci			if (wait)
634762306a36Sopenharmony_ci				ret = jbd2_log_wait_commit(sbi->s_journal,
634862306a36Sopenharmony_ci							   target);
634962306a36Sopenharmony_ci		}
635062306a36Sopenharmony_ci	} else if (wait && test_opt(sb, BARRIER))
635162306a36Sopenharmony_ci		needs_barrier = true;
635262306a36Sopenharmony_ci	if (needs_barrier) {
635362306a36Sopenharmony_ci		int err;
635462306a36Sopenharmony_ci		err = blkdev_issue_flush(sb->s_bdev);
635562306a36Sopenharmony_ci		if (!ret)
635662306a36Sopenharmony_ci			ret = err;
635762306a36Sopenharmony_ci	}
635862306a36Sopenharmony_ci
635962306a36Sopenharmony_ci	return ret;
636062306a36Sopenharmony_ci}
636162306a36Sopenharmony_ci
636262306a36Sopenharmony_ci/*
636362306a36Sopenharmony_ci * LVM calls this function before a (read-only) snapshot is created.  This
636462306a36Sopenharmony_ci * gives us a chance to flush the journal completely and mark the fs clean.
636562306a36Sopenharmony_ci *
636662306a36Sopenharmony_ci * Note that only this function cannot bring a filesystem to be in a clean
636762306a36Sopenharmony_ci * state independently. It relies on upper layer to stop all data & metadata
636862306a36Sopenharmony_ci * modifications.
636962306a36Sopenharmony_ci */
637062306a36Sopenharmony_cistatic int ext4_freeze(struct super_block *sb)
637162306a36Sopenharmony_ci{
637262306a36Sopenharmony_ci	int error = 0;
637362306a36Sopenharmony_ci	journal_t *journal = EXT4_SB(sb)->s_journal;
637462306a36Sopenharmony_ci
637562306a36Sopenharmony_ci	if (journal) {
637662306a36Sopenharmony_ci		/* Now we set up the journal barrier. */
637762306a36Sopenharmony_ci		jbd2_journal_lock_updates(journal);
637862306a36Sopenharmony_ci
637962306a36Sopenharmony_ci		/*
638062306a36Sopenharmony_ci		 * Don't clear the needs_recovery flag if we failed to
638162306a36Sopenharmony_ci		 * flush the journal.
638262306a36Sopenharmony_ci		 */
638362306a36Sopenharmony_ci		error = jbd2_journal_flush(journal, 0);
638462306a36Sopenharmony_ci		if (error < 0)
638562306a36Sopenharmony_ci			goto out;
638662306a36Sopenharmony_ci
638762306a36Sopenharmony_ci		/* Journal blocked and flushed, clear needs_recovery flag. */
638862306a36Sopenharmony_ci		ext4_clear_feature_journal_needs_recovery(sb);
638962306a36Sopenharmony_ci		if (ext4_orphan_file_empty(sb))
639062306a36Sopenharmony_ci			ext4_clear_feature_orphan_present(sb);
639162306a36Sopenharmony_ci	}
639262306a36Sopenharmony_ci
639362306a36Sopenharmony_ci	error = ext4_commit_super(sb);
639462306a36Sopenharmony_ciout:
639562306a36Sopenharmony_ci	if (journal)
639662306a36Sopenharmony_ci		/* we rely on upper layer to stop further updates */
639762306a36Sopenharmony_ci		jbd2_journal_unlock_updates(journal);
639862306a36Sopenharmony_ci	return error;
639962306a36Sopenharmony_ci}
640062306a36Sopenharmony_ci
640162306a36Sopenharmony_ci/*
640262306a36Sopenharmony_ci * Called by LVM after the snapshot is done.  We need to reset the RECOVER
640362306a36Sopenharmony_ci * flag here, even though the filesystem is not technically dirty yet.
640462306a36Sopenharmony_ci */
640562306a36Sopenharmony_cistatic int ext4_unfreeze(struct super_block *sb)
640662306a36Sopenharmony_ci{
640762306a36Sopenharmony_ci	if (ext4_forced_shutdown(sb))
640862306a36Sopenharmony_ci		return 0;
640962306a36Sopenharmony_ci
641062306a36Sopenharmony_ci	if (EXT4_SB(sb)->s_journal) {
641162306a36Sopenharmony_ci		/* Reset the needs_recovery flag before the fs is unlocked. */
641262306a36Sopenharmony_ci		ext4_set_feature_journal_needs_recovery(sb);
641362306a36Sopenharmony_ci		if (ext4_has_feature_orphan_file(sb))
641462306a36Sopenharmony_ci			ext4_set_feature_orphan_present(sb);
641562306a36Sopenharmony_ci	}
641662306a36Sopenharmony_ci
641762306a36Sopenharmony_ci	ext4_commit_super(sb);
641862306a36Sopenharmony_ci	return 0;
641962306a36Sopenharmony_ci}
642062306a36Sopenharmony_ci
642162306a36Sopenharmony_ci/*
642262306a36Sopenharmony_ci * Structure to save mount options for ext4_remount's benefit
642362306a36Sopenharmony_ci */
642462306a36Sopenharmony_cistruct ext4_mount_options {
642562306a36Sopenharmony_ci	unsigned long s_mount_opt;
642662306a36Sopenharmony_ci	unsigned long s_mount_opt2;
642762306a36Sopenharmony_ci	kuid_t s_resuid;
642862306a36Sopenharmony_ci	kgid_t s_resgid;
642962306a36Sopenharmony_ci	unsigned long s_commit_interval;
643062306a36Sopenharmony_ci	u32 s_min_batch_time, s_max_batch_time;
643162306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
643262306a36Sopenharmony_ci	int s_jquota_fmt;
643362306a36Sopenharmony_ci	char *s_qf_names[EXT4_MAXQUOTAS];
643462306a36Sopenharmony_ci#endif
643562306a36Sopenharmony_ci};
643662306a36Sopenharmony_ci
643762306a36Sopenharmony_cistatic int __ext4_remount(struct fs_context *fc, struct super_block *sb)
643862306a36Sopenharmony_ci{
643962306a36Sopenharmony_ci	struct ext4_fs_context *ctx = fc->fs_private;
644062306a36Sopenharmony_ci	struct ext4_super_block *es;
644162306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
644262306a36Sopenharmony_ci	unsigned long old_sb_flags;
644362306a36Sopenharmony_ci	struct ext4_mount_options old_opts;
644462306a36Sopenharmony_ci	ext4_group_t g;
644562306a36Sopenharmony_ci	int err = 0;
644662306a36Sopenharmony_ci	int alloc_ctx;
644762306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
644862306a36Sopenharmony_ci	int enable_quota = 0;
644962306a36Sopenharmony_ci	int i, j;
645062306a36Sopenharmony_ci	char *to_free[EXT4_MAXQUOTAS];
645162306a36Sopenharmony_ci#endif
645262306a36Sopenharmony_ci
645362306a36Sopenharmony_ci
645462306a36Sopenharmony_ci	/* Store the original options */
645562306a36Sopenharmony_ci	old_sb_flags = sb->s_flags;
645662306a36Sopenharmony_ci	old_opts.s_mount_opt = sbi->s_mount_opt;
645762306a36Sopenharmony_ci	old_opts.s_mount_opt2 = sbi->s_mount_opt2;
645862306a36Sopenharmony_ci	old_opts.s_resuid = sbi->s_resuid;
645962306a36Sopenharmony_ci	old_opts.s_resgid = sbi->s_resgid;
646062306a36Sopenharmony_ci	old_opts.s_commit_interval = sbi->s_commit_interval;
646162306a36Sopenharmony_ci	old_opts.s_min_batch_time = sbi->s_min_batch_time;
646262306a36Sopenharmony_ci	old_opts.s_max_batch_time = sbi->s_max_batch_time;
646362306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
646462306a36Sopenharmony_ci	old_opts.s_jquota_fmt = sbi->s_jquota_fmt;
646562306a36Sopenharmony_ci	for (i = 0; i < EXT4_MAXQUOTAS; i++)
646662306a36Sopenharmony_ci		if (sbi->s_qf_names[i]) {
646762306a36Sopenharmony_ci			char *qf_name = get_qf_name(sb, sbi, i);
646862306a36Sopenharmony_ci
646962306a36Sopenharmony_ci			old_opts.s_qf_names[i] = kstrdup(qf_name, GFP_KERNEL);
647062306a36Sopenharmony_ci			if (!old_opts.s_qf_names[i]) {
647162306a36Sopenharmony_ci				for (j = 0; j < i; j++)
647262306a36Sopenharmony_ci					kfree(old_opts.s_qf_names[j]);
647362306a36Sopenharmony_ci				return -ENOMEM;
647462306a36Sopenharmony_ci			}
647562306a36Sopenharmony_ci		} else
647662306a36Sopenharmony_ci			old_opts.s_qf_names[i] = NULL;
647762306a36Sopenharmony_ci#endif
647862306a36Sopenharmony_ci	if (!(ctx->spec & EXT4_SPEC_JOURNAL_IOPRIO)) {
647962306a36Sopenharmony_ci		if (sbi->s_journal && sbi->s_journal->j_task->io_context)
648062306a36Sopenharmony_ci			ctx->journal_ioprio =
648162306a36Sopenharmony_ci				sbi->s_journal->j_task->io_context->ioprio;
648262306a36Sopenharmony_ci		else
648362306a36Sopenharmony_ci			ctx->journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
648462306a36Sopenharmony_ci
648562306a36Sopenharmony_ci	}
648662306a36Sopenharmony_ci
648762306a36Sopenharmony_ci	/*
648862306a36Sopenharmony_ci	 * Changing the DIOREAD_NOLOCK or DELALLOC mount options may cause
648962306a36Sopenharmony_ci	 * two calls to ext4_should_dioread_nolock() to return inconsistent
649062306a36Sopenharmony_ci	 * values, triggering WARN_ON in ext4_add_complete_io(). we grab
649162306a36Sopenharmony_ci	 * here s_writepages_rwsem to avoid race between writepages ops and
649262306a36Sopenharmony_ci	 * remount.
649362306a36Sopenharmony_ci	 */
649462306a36Sopenharmony_ci	alloc_ctx = ext4_writepages_down_write(sb);
649562306a36Sopenharmony_ci	ext4_apply_options(fc, sb);
649662306a36Sopenharmony_ci	ext4_writepages_up_write(sb, alloc_ctx);
649762306a36Sopenharmony_ci
649862306a36Sopenharmony_ci	if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^
649962306a36Sopenharmony_ci	    test_opt(sb, JOURNAL_CHECKSUM)) {
650062306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "changing journal_checksum "
650162306a36Sopenharmony_ci			 "during remount not supported; ignoring");
650262306a36Sopenharmony_ci		sbi->s_mount_opt ^= EXT4_MOUNT_JOURNAL_CHECKSUM;
650362306a36Sopenharmony_ci	}
650462306a36Sopenharmony_ci
650562306a36Sopenharmony_ci	if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
650662306a36Sopenharmony_ci		if (test_opt2(sb, EXPLICIT_DELALLOC)) {
650762306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "can't mount with "
650862306a36Sopenharmony_ci				 "both data=journal and delalloc");
650962306a36Sopenharmony_ci			err = -EINVAL;
651062306a36Sopenharmony_ci			goto restore_opts;
651162306a36Sopenharmony_ci		}
651262306a36Sopenharmony_ci		if (test_opt(sb, DIOREAD_NOLOCK)) {
651362306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "can't mount with "
651462306a36Sopenharmony_ci				 "both data=journal and dioread_nolock");
651562306a36Sopenharmony_ci			err = -EINVAL;
651662306a36Sopenharmony_ci			goto restore_opts;
651762306a36Sopenharmony_ci		}
651862306a36Sopenharmony_ci	} else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) {
651962306a36Sopenharmony_ci		if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
652062306a36Sopenharmony_ci			ext4_msg(sb, KERN_ERR, "can't mount with "
652162306a36Sopenharmony_ci				"journal_async_commit in data=ordered mode");
652262306a36Sopenharmony_ci			err = -EINVAL;
652362306a36Sopenharmony_ci			goto restore_opts;
652462306a36Sopenharmony_ci		}
652562306a36Sopenharmony_ci	}
652662306a36Sopenharmony_ci
652762306a36Sopenharmony_ci	if ((sbi->s_mount_opt ^ old_opts.s_mount_opt) & EXT4_MOUNT_NO_MBCACHE) {
652862306a36Sopenharmony_ci		ext4_msg(sb, KERN_ERR, "can't enable nombcache during remount");
652962306a36Sopenharmony_ci		err = -EINVAL;
653062306a36Sopenharmony_ci		goto restore_opts;
653162306a36Sopenharmony_ci	}
653262306a36Sopenharmony_ci
653362306a36Sopenharmony_ci	if (test_opt2(sb, ABORT))
653462306a36Sopenharmony_ci		ext4_abort(sb, ESHUTDOWN, "Abort forced by user");
653562306a36Sopenharmony_ci
653662306a36Sopenharmony_ci	sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
653762306a36Sopenharmony_ci		(test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0);
653862306a36Sopenharmony_ci
653962306a36Sopenharmony_ci	es = sbi->s_es;
654062306a36Sopenharmony_ci
654162306a36Sopenharmony_ci	if (sbi->s_journal) {
654262306a36Sopenharmony_ci		ext4_init_journal_params(sb, sbi->s_journal);
654362306a36Sopenharmony_ci		set_task_ioprio(sbi->s_journal->j_task, ctx->journal_ioprio);
654462306a36Sopenharmony_ci	}
654562306a36Sopenharmony_ci
654662306a36Sopenharmony_ci	/* Flush outstanding errors before changing fs state */
654762306a36Sopenharmony_ci	flush_work(&sbi->s_sb_upd_work);
654862306a36Sopenharmony_ci
654962306a36Sopenharmony_ci	if ((bool)(fc->sb_flags & SB_RDONLY) != sb_rdonly(sb)) {
655062306a36Sopenharmony_ci		if (ext4_forced_shutdown(sb)) {
655162306a36Sopenharmony_ci			err = -EROFS;
655262306a36Sopenharmony_ci			goto restore_opts;
655362306a36Sopenharmony_ci		}
655462306a36Sopenharmony_ci
655562306a36Sopenharmony_ci		if (fc->sb_flags & SB_RDONLY) {
655662306a36Sopenharmony_ci			err = sync_filesystem(sb);
655762306a36Sopenharmony_ci			if (err < 0)
655862306a36Sopenharmony_ci				goto restore_opts;
655962306a36Sopenharmony_ci			err = dquot_suspend(sb, -1);
656062306a36Sopenharmony_ci			if (err < 0)
656162306a36Sopenharmony_ci				goto restore_opts;
656262306a36Sopenharmony_ci
656362306a36Sopenharmony_ci			/*
656462306a36Sopenharmony_ci			 * First of all, the unconditional stuff we have to do
656562306a36Sopenharmony_ci			 * to disable replay of the journal when we next remount
656662306a36Sopenharmony_ci			 */
656762306a36Sopenharmony_ci			sb->s_flags |= SB_RDONLY;
656862306a36Sopenharmony_ci
656962306a36Sopenharmony_ci			/*
657062306a36Sopenharmony_ci			 * OK, test if we are remounting a valid rw partition
657162306a36Sopenharmony_ci			 * readonly, and if so set the rdonly flag and then
657262306a36Sopenharmony_ci			 * mark the partition as valid again.
657362306a36Sopenharmony_ci			 */
657462306a36Sopenharmony_ci			if (!(es->s_state & cpu_to_le16(EXT4_VALID_FS)) &&
657562306a36Sopenharmony_ci			    (sbi->s_mount_state & EXT4_VALID_FS))
657662306a36Sopenharmony_ci				es->s_state = cpu_to_le16(sbi->s_mount_state);
657762306a36Sopenharmony_ci
657862306a36Sopenharmony_ci			if (sbi->s_journal) {
657962306a36Sopenharmony_ci				/*
658062306a36Sopenharmony_ci				 * We let remount-ro finish even if marking fs
658162306a36Sopenharmony_ci				 * as clean failed...
658262306a36Sopenharmony_ci				 */
658362306a36Sopenharmony_ci				ext4_mark_recovery_complete(sb, es);
658462306a36Sopenharmony_ci			}
658562306a36Sopenharmony_ci		} else {
658662306a36Sopenharmony_ci			/* Make sure we can mount this feature set readwrite */
658762306a36Sopenharmony_ci			if (ext4_has_feature_readonly(sb) ||
658862306a36Sopenharmony_ci			    !ext4_feature_set_ok(sb, 0)) {
658962306a36Sopenharmony_ci				err = -EROFS;
659062306a36Sopenharmony_ci				goto restore_opts;
659162306a36Sopenharmony_ci			}
659262306a36Sopenharmony_ci			/*
659362306a36Sopenharmony_ci			 * Make sure the group descriptor checksums
659462306a36Sopenharmony_ci			 * are sane.  If they aren't, refuse to remount r/w.
659562306a36Sopenharmony_ci			 */
659662306a36Sopenharmony_ci			for (g = 0; g < sbi->s_groups_count; g++) {
659762306a36Sopenharmony_ci				struct ext4_group_desc *gdp =
659862306a36Sopenharmony_ci					ext4_get_group_desc(sb, g, NULL);
659962306a36Sopenharmony_ci
660062306a36Sopenharmony_ci				if (!ext4_group_desc_csum_verify(sb, g, gdp)) {
660162306a36Sopenharmony_ci					ext4_msg(sb, KERN_ERR,
660262306a36Sopenharmony_ci	       "ext4_remount: Checksum for group %u failed (%u!=%u)",
660362306a36Sopenharmony_ci		g, le16_to_cpu(ext4_group_desc_csum(sb, g, gdp)),
660462306a36Sopenharmony_ci					       le16_to_cpu(gdp->bg_checksum));
660562306a36Sopenharmony_ci					err = -EFSBADCRC;
660662306a36Sopenharmony_ci					goto restore_opts;
660762306a36Sopenharmony_ci				}
660862306a36Sopenharmony_ci			}
660962306a36Sopenharmony_ci
661062306a36Sopenharmony_ci			/*
661162306a36Sopenharmony_ci			 * If we have an unprocessed orphan list hanging
661262306a36Sopenharmony_ci			 * around from a previously readonly bdev mount,
661362306a36Sopenharmony_ci			 * require a full umount/remount for now.
661462306a36Sopenharmony_ci			 */
661562306a36Sopenharmony_ci			if (es->s_last_orphan || !ext4_orphan_file_empty(sb)) {
661662306a36Sopenharmony_ci				ext4_msg(sb, KERN_WARNING, "Couldn't "
661762306a36Sopenharmony_ci				       "remount RDWR because of unprocessed "
661862306a36Sopenharmony_ci				       "orphan inode list.  Please "
661962306a36Sopenharmony_ci				       "umount/remount instead");
662062306a36Sopenharmony_ci				err = -EINVAL;
662162306a36Sopenharmony_ci				goto restore_opts;
662262306a36Sopenharmony_ci			}
662362306a36Sopenharmony_ci
662462306a36Sopenharmony_ci			/*
662562306a36Sopenharmony_ci			 * Mounting a RDONLY partition read-write, so reread
662662306a36Sopenharmony_ci			 * and store the current valid flag.  (It may have
662762306a36Sopenharmony_ci			 * been changed by e2fsck since we originally mounted
662862306a36Sopenharmony_ci			 * the partition.)
662962306a36Sopenharmony_ci			 */
663062306a36Sopenharmony_ci			if (sbi->s_journal) {
663162306a36Sopenharmony_ci				err = ext4_clear_journal_err(sb, es);
663262306a36Sopenharmony_ci				if (err)
663362306a36Sopenharmony_ci					goto restore_opts;
663462306a36Sopenharmony_ci			}
663562306a36Sopenharmony_ci			sbi->s_mount_state = (le16_to_cpu(es->s_state) &
663662306a36Sopenharmony_ci					      ~EXT4_FC_REPLAY);
663762306a36Sopenharmony_ci
663862306a36Sopenharmony_ci			err = ext4_setup_super(sb, es, 0);
663962306a36Sopenharmony_ci			if (err)
664062306a36Sopenharmony_ci				goto restore_opts;
664162306a36Sopenharmony_ci
664262306a36Sopenharmony_ci			sb->s_flags &= ~SB_RDONLY;
664362306a36Sopenharmony_ci			if (ext4_has_feature_mmp(sb)) {
664462306a36Sopenharmony_ci				err = ext4_multi_mount_protect(sb,
664562306a36Sopenharmony_ci						le64_to_cpu(es->s_mmp_block));
664662306a36Sopenharmony_ci				if (err)
664762306a36Sopenharmony_ci					goto restore_opts;
664862306a36Sopenharmony_ci			}
664962306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
665062306a36Sopenharmony_ci			enable_quota = 1;
665162306a36Sopenharmony_ci#endif
665262306a36Sopenharmony_ci		}
665362306a36Sopenharmony_ci	}
665462306a36Sopenharmony_ci
665562306a36Sopenharmony_ci	/*
665662306a36Sopenharmony_ci	 * Handle creation of system zone data early because it can fail.
665762306a36Sopenharmony_ci	 * Releasing of existing data is done when we are sure remount will
665862306a36Sopenharmony_ci	 * succeed.
665962306a36Sopenharmony_ci	 */
666062306a36Sopenharmony_ci	if (test_opt(sb, BLOCK_VALIDITY) && !sbi->s_system_blks) {
666162306a36Sopenharmony_ci		err = ext4_setup_system_zone(sb);
666262306a36Sopenharmony_ci		if (err)
666362306a36Sopenharmony_ci			goto restore_opts;
666462306a36Sopenharmony_ci	}
666562306a36Sopenharmony_ci
666662306a36Sopenharmony_ci	if (sbi->s_journal == NULL && !(old_sb_flags & SB_RDONLY)) {
666762306a36Sopenharmony_ci		err = ext4_commit_super(sb);
666862306a36Sopenharmony_ci		if (err)
666962306a36Sopenharmony_ci			goto restore_opts;
667062306a36Sopenharmony_ci	}
667162306a36Sopenharmony_ci
667262306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
667362306a36Sopenharmony_ci	if (enable_quota) {
667462306a36Sopenharmony_ci		if (sb_any_quota_suspended(sb))
667562306a36Sopenharmony_ci			dquot_resume(sb, -1);
667662306a36Sopenharmony_ci		else if (ext4_has_feature_quota(sb)) {
667762306a36Sopenharmony_ci			err = ext4_enable_quotas(sb);
667862306a36Sopenharmony_ci			if (err)
667962306a36Sopenharmony_ci				goto restore_opts;
668062306a36Sopenharmony_ci		}
668162306a36Sopenharmony_ci	}
668262306a36Sopenharmony_ci	/* Release old quota file names */
668362306a36Sopenharmony_ci	for (i = 0; i < EXT4_MAXQUOTAS; i++)
668462306a36Sopenharmony_ci		kfree(old_opts.s_qf_names[i]);
668562306a36Sopenharmony_ci#endif
668662306a36Sopenharmony_ci	if (!test_opt(sb, BLOCK_VALIDITY) && sbi->s_system_blks)
668762306a36Sopenharmony_ci		ext4_release_system_zone(sb);
668862306a36Sopenharmony_ci
668962306a36Sopenharmony_ci	/*
669062306a36Sopenharmony_ci	 * Reinitialize lazy itable initialization thread based on
669162306a36Sopenharmony_ci	 * current settings
669262306a36Sopenharmony_ci	 */
669362306a36Sopenharmony_ci	if (sb_rdonly(sb) || !test_opt(sb, INIT_INODE_TABLE))
669462306a36Sopenharmony_ci		ext4_unregister_li_request(sb);
669562306a36Sopenharmony_ci	else {
669662306a36Sopenharmony_ci		ext4_group_t first_not_zeroed;
669762306a36Sopenharmony_ci		first_not_zeroed = ext4_has_uninit_itable(sb);
669862306a36Sopenharmony_ci		ext4_register_li_request(sb, first_not_zeroed);
669962306a36Sopenharmony_ci	}
670062306a36Sopenharmony_ci
670162306a36Sopenharmony_ci	if (!ext4_has_feature_mmp(sb) || sb_rdonly(sb))
670262306a36Sopenharmony_ci		ext4_stop_mmpd(sbi);
670362306a36Sopenharmony_ci
670462306a36Sopenharmony_ci	return 0;
670562306a36Sopenharmony_ci
670662306a36Sopenharmony_cirestore_opts:
670762306a36Sopenharmony_ci	/*
670862306a36Sopenharmony_ci	 * If there was a failing r/w to ro transition, we may need to
670962306a36Sopenharmony_ci	 * re-enable quota
671062306a36Sopenharmony_ci	 */
671162306a36Sopenharmony_ci	if (sb_rdonly(sb) && !(old_sb_flags & SB_RDONLY) &&
671262306a36Sopenharmony_ci	    sb_any_quota_suspended(sb))
671362306a36Sopenharmony_ci		dquot_resume(sb, -1);
671462306a36Sopenharmony_ci
671562306a36Sopenharmony_ci	alloc_ctx = ext4_writepages_down_write(sb);
671662306a36Sopenharmony_ci	sb->s_flags = old_sb_flags;
671762306a36Sopenharmony_ci	sbi->s_mount_opt = old_opts.s_mount_opt;
671862306a36Sopenharmony_ci	sbi->s_mount_opt2 = old_opts.s_mount_opt2;
671962306a36Sopenharmony_ci	sbi->s_resuid = old_opts.s_resuid;
672062306a36Sopenharmony_ci	sbi->s_resgid = old_opts.s_resgid;
672162306a36Sopenharmony_ci	sbi->s_commit_interval = old_opts.s_commit_interval;
672262306a36Sopenharmony_ci	sbi->s_min_batch_time = old_opts.s_min_batch_time;
672362306a36Sopenharmony_ci	sbi->s_max_batch_time = old_opts.s_max_batch_time;
672462306a36Sopenharmony_ci	ext4_writepages_up_write(sb, alloc_ctx);
672562306a36Sopenharmony_ci
672662306a36Sopenharmony_ci	if (!test_opt(sb, BLOCK_VALIDITY) && sbi->s_system_blks)
672762306a36Sopenharmony_ci		ext4_release_system_zone(sb);
672862306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
672962306a36Sopenharmony_ci	sbi->s_jquota_fmt = old_opts.s_jquota_fmt;
673062306a36Sopenharmony_ci	for (i = 0; i < EXT4_MAXQUOTAS; i++) {
673162306a36Sopenharmony_ci		to_free[i] = get_qf_name(sb, sbi, i);
673262306a36Sopenharmony_ci		rcu_assign_pointer(sbi->s_qf_names[i], old_opts.s_qf_names[i]);
673362306a36Sopenharmony_ci	}
673462306a36Sopenharmony_ci	synchronize_rcu();
673562306a36Sopenharmony_ci	for (i = 0; i < EXT4_MAXQUOTAS; i++)
673662306a36Sopenharmony_ci		kfree(to_free[i]);
673762306a36Sopenharmony_ci#endif
673862306a36Sopenharmony_ci	if (!ext4_has_feature_mmp(sb) || sb_rdonly(sb))
673962306a36Sopenharmony_ci		ext4_stop_mmpd(sbi);
674062306a36Sopenharmony_ci	return err;
674162306a36Sopenharmony_ci}
674262306a36Sopenharmony_ci
674362306a36Sopenharmony_cistatic int ext4_reconfigure(struct fs_context *fc)
674462306a36Sopenharmony_ci{
674562306a36Sopenharmony_ci	struct super_block *sb = fc->root->d_sb;
674662306a36Sopenharmony_ci	int ret;
674762306a36Sopenharmony_ci
674862306a36Sopenharmony_ci	fc->s_fs_info = EXT4_SB(sb);
674962306a36Sopenharmony_ci
675062306a36Sopenharmony_ci	ret = ext4_check_opt_consistency(fc, sb);
675162306a36Sopenharmony_ci	if (ret < 0)
675262306a36Sopenharmony_ci		return ret;
675362306a36Sopenharmony_ci
675462306a36Sopenharmony_ci	ret = __ext4_remount(fc, sb);
675562306a36Sopenharmony_ci	if (ret < 0)
675662306a36Sopenharmony_ci		return ret;
675762306a36Sopenharmony_ci
675862306a36Sopenharmony_ci	ext4_msg(sb, KERN_INFO, "re-mounted %pU %s. Quota mode: %s.",
675962306a36Sopenharmony_ci		 &sb->s_uuid, sb_rdonly(sb) ? "ro" : "r/w",
676062306a36Sopenharmony_ci		 ext4_quota_mode(sb));
676162306a36Sopenharmony_ci
676262306a36Sopenharmony_ci	return 0;
676362306a36Sopenharmony_ci}
676462306a36Sopenharmony_ci
676562306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
676662306a36Sopenharmony_cistatic int ext4_statfs_project(struct super_block *sb,
676762306a36Sopenharmony_ci			       kprojid_t projid, struct kstatfs *buf)
676862306a36Sopenharmony_ci{
676962306a36Sopenharmony_ci	struct kqid qid;
677062306a36Sopenharmony_ci	struct dquot *dquot;
677162306a36Sopenharmony_ci	u64 limit;
677262306a36Sopenharmony_ci	u64 curblock;
677362306a36Sopenharmony_ci
677462306a36Sopenharmony_ci	qid = make_kqid_projid(projid);
677562306a36Sopenharmony_ci	dquot = dqget(sb, qid);
677662306a36Sopenharmony_ci	if (IS_ERR(dquot))
677762306a36Sopenharmony_ci		return PTR_ERR(dquot);
677862306a36Sopenharmony_ci	spin_lock(&dquot->dq_dqb_lock);
677962306a36Sopenharmony_ci
678062306a36Sopenharmony_ci	limit = min_not_zero(dquot->dq_dqb.dqb_bsoftlimit,
678162306a36Sopenharmony_ci			     dquot->dq_dqb.dqb_bhardlimit);
678262306a36Sopenharmony_ci	limit >>= sb->s_blocksize_bits;
678362306a36Sopenharmony_ci
678462306a36Sopenharmony_ci	if (limit && buf->f_blocks > limit) {
678562306a36Sopenharmony_ci		curblock = (dquot->dq_dqb.dqb_curspace +
678662306a36Sopenharmony_ci			    dquot->dq_dqb.dqb_rsvspace) >> sb->s_blocksize_bits;
678762306a36Sopenharmony_ci		buf->f_blocks = limit;
678862306a36Sopenharmony_ci		buf->f_bfree = buf->f_bavail =
678962306a36Sopenharmony_ci			(buf->f_blocks > curblock) ?
679062306a36Sopenharmony_ci			 (buf->f_blocks - curblock) : 0;
679162306a36Sopenharmony_ci	}
679262306a36Sopenharmony_ci
679362306a36Sopenharmony_ci	limit = min_not_zero(dquot->dq_dqb.dqb_isoftlimit,
679462306a36Sopenharmony_ci			     dquot->dq_dqb.dqb_ihardlimit);
679562306a36Sopenharmony_ci	if (limit && buf->f_files > limit) {
679662306a36Sopenharmony_ci		buf->f_files = limit;
679762306a36Sopenharmony_ci		buf->f_ffree =
679862306a36Sopenharmony_ci			(buf->f_files > dquot->dq_dqb.dqb_curinodes) ?
679962306a36Sopenharmony_ci			 (buf->f_files - dquot->dq_dqb.dqb_curinodes) : 0;
680062306a36Sopenharmony_ci	}
680162306a36Sopenharmony_ci
680262306a36Sopenharmony_ci	spin_unlock(&dquot->dq_dqb_lock);
680362306a36Sopenharmony_ci	dqput(dquot);
680462306a36Sopenharmony_ci	return 0;
680562306a36Sopenharmony_ci}
680662306a36Sopenharmony_ci#endif
680762306a36Sopenharmony_ci
680862306a36Sopenharmony_cistatic int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
680962306a36Sopenharmony_ci{
681062306a36Sopenharmony_ci	struct super_block *sb = dentry->d_sb;
681162306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
681262306a36Sopenharmony_ci	struct ext4_super_block *es = sbi->s_es;
681362306a36Sopenharmony_ci	ext4_fsblk_t overhead = 0, resv_blocks;
681462306a36Sopenharmony_ci	s64 bfree;
681562306a36Sopenharmony_ci	resv_blocks = EXT4_C2B(sbi, atomic64_read(&sbi->s_resv_clusters));
681662306a36Sopenharmony_ci
681762306a36Sopenharmony_ci	if (!test_opt(sb, MINIX_DF))
681862306a36Sopenharmony_ci		overhead = sbi->s_overhead;
681962306a36Sopenharmony_ci
682062306a36Sopenharmony_ci	buf->f_type = EXT4_SUPER_MAGIC;
682162306a36Sopenharmony_ci	buf->f_bsize = sb->s_blocksize;
682262306a36Sopenharmony_ci	buf->f_blocks = ext4_blocks_count(es) - EXT4_C2B(sbi, overhead);
682362306a36Sopenharmony_ci	bfree = percpu_counter_sum_positive(&sbi->s_freeclusters_counter) -
682462306a36Sopenharmony_ci		percpu_counter_sum_positive(&sbi->s_dirtyclusters_counter);
682562306a36Sopenharmony_ci	/* prevent underflow in case that few free space is available */
682662306a36Sopenharmony_ci	buf->f_bfree = EXT4_C2B(sbi, max_t(s64, bfree, 0));
682762306a36Sopenharmony_ci	buf->f_bavail = buf->f_bfree -
682862306a36Sopenharmony_ci			(ext4_r_blocks_count(es) + resv_blocks);
682962306a36Sopenharmony_ci	if (buf->f_bfree < (ext4_r_blocks_count(es) + resv_blocks))
683062306a36Sopenharmony_ci		buf->f_bavail = 0;
683162306a36Sopenharmony_ci	buf->f_files = le32_to_cpu(es->s_inodes_count);
683262306a36Sopenharmony_ci	buf->f_ffree = percpu_counter_sum_positive(&sbi->s_freeinodes_counter);
683362306a36Sopenharmony_ci	buf->f_namelen = EXT4_NAME_LEN;
683462306a36Sopenharmony_ci	buf->f_fsid = uuid_to_fsid(es->s_uuid);
683562306a36Sopenharmony_ci
683662306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
683762306a36Sopenharmony_ci	if (ext4_test_inode_flag(dentry->d_inode, EXT4_INODE_PROJINHERIT) &&
683862306a36Sopenharmony_ci	    sb_has_quota_limits_enabled(sb, PRJQUOTA))
683962306a36Sopenharmony_ci		ext4_statfs_project(sb, EXT4_I(dentry->d_inode)->i_projid, buf);
684062306a36Sopenharmony_ci#endif
684162306a36Sopenharmony_ci	return 0;
684262306a36Sopenharmony_ci}
684362306a36Sopenharmony_ci
684462306a36Sopenharmony_ci
684562306a36Sopenharmony_ci#ifdef CONFIG_QUOTA
684662306a36Sopenharmony_ci
684762306a36Sopenharmony_ci/*
684862306a36Sopenharmony_ci * Helper functions so that transaction is started before we acquire dqio_sem
684962306a36Sopenharmony_ci * to keep correct lock ordering of transaction > dqio_sem
685062306a36Sopenharmony_ci */
685162306a36Sopenharmony_cistatic inline struct inode *dquot_to_inode(struct dquot *dquot)
685262306a36Sopenharmony_ci{
685362306a36Sopenharmony_ci	return sb_dqopt(dquot->dq_sb)->files[dquot->dq_id.type];
685462306a36Sopenharmony_ci}
685562306a36Sopenharmony_ci
685662306a36Sopenharmony_cistatic int ext4_write_dquot(struct dquot *dquot)
685762306a36Sopenharmony_ci{
685862306a36Sopenharmony_ci	int ret, err;
685962306a36Sopenharmony_ci	handle_t *handle;
686062306a36Sopenharmony_ci	struct inode *inode;
686162306a36Sopenharmony_ci
686262306a36Sopenharmony_ci	inode = dquot_to_inode(dquot);
686362306a36Sopenharmony_ci	handle = ext4_journal_start(inode, EXT4_HT_QUOTA,
686462306a36Sopenharmony_ci				    EXT4_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
686562306a36Sopenharmony_ci	if (IS_ERR(handle))
686662306a36Sopenharmony_ci		return PTR_ERR(handle);
686762306a36Sopenharmony_ci	ret = dquot_commit(dquot);
686862306a36Sopenharmony_ci	err = ext4_journal_stop(handle);
686962306a36Sopenharmony_ci	if (!ret)
687062306a36Sopenharmony_ci		ret = err;
687162306a36Sopenharmony_ci	return ret;
687262306a36Sopenharmony_ci}
687362306a36Sopenharmony_ci
687462306a36Sopenharmony_cistatic int ext4_acquire_dquot(struct dquot *dquot)
687562306a36Sopenharmony_ci{
687662306a36Sopenharmony_ci	int ret, err;
687762306a36Sopenharmony_ci	handle_t *handle;
687862306a36Sopenharmony_ci
687962306a36Sopenharmony_ci	handle = ext4_journal_start(dquot_to_inode(dquot), EXT4_HT_QUOTA,
688062306a36Sopenharmony_ci				    EXT4_QUOTA_INIT_BLOCKS(dquot->dq_sb));
688162306a36Sopenharmony_ci	if (IS_ERR(handle))
688262306a36Sopenharmony_ci		return PTR_ERR(handle);
688362306a36Sopenharmony_ci	ret = dquot_acquire(dquot);
688462306a36Sopenharmony_ci	err = ext4_journal_stop(handle);
688562306a36Sopenharmony_ci	if (!ret)
688662306a36Sopenharmony_ci		ret = err;
688762306a36Sopenharmony_ci	return ret;
688862306a36Sopenharmony_ci}
688962306a36Sopenharmony_ci
689062306a36Sopenharmony_cistatic int ext4_release_dquot(struct dquot *dquot)
689162306a36Sopenharmony_ci{
689262306a36Sopenharmony_ci	int ret, err;
689362306a36Sopenharmony_ci	handle_t *handle;
689462306a36Sopenharmony_ci
689562306a36Sopenharmony_ci	handle = ext4_journal_start(dquot_to_inode(dquot), EXT4_HT_QUOTA,
689662306a36Sopenharmony_ci				    EXT4_QUOTA_DEL_BLOCKS(dquot->dq_sb));
689762306a36Sopenharmony_ci	if (IS_ERR(handle)) {
689862306a36Sopenharmony_ci		/* Release dquot anyway to avoid endless cycle in dqput() */
689962306a36Sopenharmony_ci		dquot_release(dquot);
690062306a36Sopenharmony_ci		return PTR_ERR(handle);
690162306a36Sopenharmony_ci	}
690262306a36Sopenharmony_ci	ret = dquot_release(dquot);
690362306a36Sopenharmony_ci	err = ext4_journal_stop(handle);
690462306a36Sopenharmony_ci	if (!ret)
690562306a36Sopenharmony_ci		ret = err;
690662306a36Sopenharmony_ci	return ret;
690762306a36Sopenharmony_ci}
690862306a36Sopenharmony_ci
690962306a36Sopenharmony_cistatic int ext4_mark_dquot_dirty(struct dquot *dquot)
691062306a36Sopenharmony_ci{
691162306a36Sopenharmony_ci	struct super_block *sb = dquot->dq_sb;
691262306a36Sopenharmony_ci
691362306a36Sopenharmony_ci	if (ext4_is_quota_journalled(sb)) {
691462306a36Sopenharmony_ci		dquot_mark_dquot_dirty(dquot);
691562306a36Sopenharmony_ci		return ext4_write_dquot(dquot);
691662306a36Sopenharmony_ci	} else {
691762306a36Sopenharmony_ci		return dquot_mark_dquot_dirty(dquot);
691862306a36Sopenharmony_ci	}
691962306a36Sopenharmony_ci}
692062306a36Sopenharmony_ci
692162306a36Sopenharmony_cistatic int ext4_write_info(struct super_block *sb, int type)
692262306a36Sopenharmony_ci{
692362306a36Sopenharmony_ci	int ret, err;
692462306a36Sopenharmony_ci	handle_t *handle;
692562306a36Sopenharmony_ci
692662306a36Sopenharmony_ci	/* Data block + inode block */
692762306a36Sopenharmony_ci	handle = ext4_journal_start_sb(sb, EXT4_HT_QUOTA, 2);
692862306a36Sopenharmony_ci	if (IS_ERR(handle))
692962306a36Sopenharmony_ci		return PTR_ERR(handle);
693062306a36Sopenharmony_ci	ret = dquot_commit_info(sb, type);
693162306a36Sopenharmony_ci	err = ext4_journal_stop(handle);
693262306a36Sopenharmony_ci	if (!ret)
693362306a36Sopenharmony_ci		ret = err;
693462306a36Sopenharmony_ci	return ret;
693562306a36Sopenharmony_ci}
693662306a36Sopenharmony_ci
693762306a36Sopenharmony_cistatic void lockdep_set_quota_inode(struct inode *inode, int subclass)
693862306a36Sopenharmony_ci{
693962306a36Sopenharmony_ci	struct ext4_inode_info *ei = EXT4_I(inode);
694062306a36Sopenharmony_ci
694162306a36Sopenharmony_ci	/* The first argument of lockdep_set_subclass has to be
694262306a36Sopenharmony_ci	 * *exactly* the same as the argument to init_rwsem() --- in
694362306a36Sopenharmony_ci	 * this case, in init_once() --- or lockdep gets unhappy
694462306a36Sopenharmony_ci	 * because the name of the lock is set using the
694562306a36Sopenharmony_ci	 * stringification of the argument to init_rwsem().
694662306a36Sopenharmony_ci	 */
694762306a36Sopenharmony_ci	(void) ei;	/* shut up clang warning if !CONFIG_LOCKDEP */
694862306a36Sopenharmony_ci	lockdep_set_subclass(&ei->i_data_sem, subclass);
694962306a36Sopenharmony_ci}
695062306a36Sopenharmony_ci
695162306a36Sopenharmony_ci/*
695262306a36Sopenharmony_ci * Standard function to be called on quota_on
695362306a36Sopenharmony_ci */
695462306a36Sopenharmony_cistatic int ext4_quota_on(struct super_block *sb, int type, int format_id,
695562306a36Sopenharmony_ci			 const struct path *path)
695662306a36Sopenharmony_ci{
695762306a36Sopenharmony_ci	int err;
695862306a36Sopenharmony_ci
695962306a36Sopenharmony_ci	if (!test_opt(sb, QUOTA))
696062306a36Sopenharmony_ci		return -EINVAL;
696162306a36Sopenharmony_ci
696262306a36Sopenharmony_ci	/* Quotafile not on the same filesystem? */
696362306a36Sopenharmony_ci	if (path->dentry->d_sb != sb)
696462306a36Sopenharmony_ci		return -EXDEV;
696562306a36Sopenharmony_ci
696662306a36Sopenharmony_ci	/* Quota already enabled for this file? */
696762306a36Sopenharmony_ci	if (IS_NOQUOTA(d_inode(path->dentry)))
696862306a36Sopenharmony_ci		return -EBUSY;
696962306a36Sopenharmony_ci
697062306a36Sopenharmony_ci	/* Journaling quota? */
697162306a36Sopenharmony_ci	if (EXT4_SB(sb)->s_qf_names[type]) {
697262306a36Sopenharmony_ci		/* Quotafile not in fs root? */
697362306a36Sopenharmony_ci		if (path->dentry->d_parent != sb->s_root)
697462306a36Sopenharmony_ci			ext4_msg(sb, KERN_WARNING,
697562306a36Sopenharmony_ci				"Quota file not on filesystem root. "
697662306a36Sopenharmony_ci				"Journaled quota will not work");
697762306a36Sopenharmony_ci		sb_dqopt(sb)->flags |= DQUOT_NOLIST_DIRTY;
697862306a36Sopenharmony_ci	} else {
697962306a36Sopenharmony_ci		/*
698062306a36Sopenharmony_ci		 * Clear the flag just in case mount options changed since
698162306a36Sopenharmony_ci		 * last time.
698262306a36Sopenharmony_ci		 */
698362306a36Sopenharmony_ci		sb_dqopt(sb)->flags &= ~DQUOT_NOLIST_DIRTY;
698462306a36Sopenharmony_ci	}
698562306a36Sopenharmony_ci
698662306a36Sopenharmony_ci	lockdep_set_quota_inode(path->dentry->d_inode, I_DATA_SEM_QUOTA);
698762306a36Sopenharmony_ci	err = dquot_quota_on(sb, type, format_id, path);
698862306a36Sopenharmony_ci	if (!err) {
698962306a36Sopenharmony_ci		struct inode *inode = d_inode(path->dentry);
699062306a36Sopenharmony_ci		handle_t *handle;
699162306a36Sopenharmony_ci
699262306a36Sopenharmony_ci		/*
699362306a36Sopenharmony_ci		 * Set inode flags to prevent userspace from messing with quota
699462306a36Sopenharmony_ci		 * files. If this fails, we return success anyway since quotas
699562306a36Sopenharmony_ci		 * are already enabled and this is not a hard failure.
699662306a36Sopenharmony_ci		 */
699762306a36Sopenharmony_ci		inode_lock(inode);
699862306a36Sopenharmony_ci		handle = ext4_journal_start(inode, EXT4_HT_QUOTA, 1);
699962306a36Sopenharmony_ci		if (IS_ERR(handle))
700062306a36Sopenharmony_ci			goto unlock_inode;
700162306a36Sopenharmony_ci		EXT4_I(inode)->i_flags |= EXT4_NOATIME_FL | EXT4_IMMUTABLE_FL;
700262306a36Sopenharmony_ci		inode_set_flags(inode, S_NOATIME | S_IMMUTABLE,
700362306a36Sopenharmony_ci				S_NOATIME | S_IMMUTABLE);
700462306a36Sopenharmony_ci		err = ext4_mark_inode_dirty(handle, inode);
700562306a36Sopenharmony_ci		ext4_journal_stop(handle);
700662306a36Sopenharmony_ci	unlock_inode:
700762306a36Sopenharmony_ci		inode_unlock(inode);
700862306a36Sopenharmony_ci		if (err)
700962306a36Sopenharmony_ci			dquot_quota_off(sb, type);
701062306a36Sopenharmony_ci	}
701162306a36Sopenharmony_ci	if (err)
701262306a36Sopenharmony_ci		lockdep_set_quota_inode(path->dentry->d_inode,
701362306a36Sopenharmony_ci					     I_DATA_SEM_NORMAL);
701462306a36Sopenharmony_ci	return err;
701562306a36Sopenharmony_ci}
701662306a36Sopenharmony_ci
701762306a36Sopenharmony_cistatic inline bool ext4_check_quota_inum(int type, unsigned long qf_inum)
701862306a36Sopenharmony_ci{
701962306a36Sopenharmony_ci	switch (type) {
702062306a36Sopenharmony_ci	case USRQUOTA:
702162306a36Sopenharmony_ci		return qf_inum == EXT4_USR_QUOTA_INO;
702262306a36Sopenharmony_ci	case GRPQUOTA:
702362306a36Sopenharmony_ci		return qf_inum == EXT4_GRP_QUOTA_INO;
702462306a36Sopenharmony_ci	case PRJQUOTA:
702562306a36Sopenharmony_ci		return qf_inum >= EXT4_GOOD_OLD_FIRST_INO;
702662306a36Sopenharmony_ci	default:
702762306a36Sopenharmony_ci		BUG();
702862306a36Sopenharmony_ci	}
702962306a36Sopenharmony_ci}
703062306a36Sopenharmony_ci
703162306a36Sopenharmony_cistatic int ext4_quota_enable(struct super_block *sb, int type, int format_id,
703262306a36Sopenharmony_ci			     unsigned int flags)
703362306a36Sopenharmony_ci{
703462306a36Sopenharmony_ci	int err;
703562306a36Sopenharmony_ci	struct inode *qf_inode;
703662306a36Sopenharmony_ci	unsigned long qf_inums[EXT4_MAXQUOTAS] = {
703762306a36Sopenharmony_ci		le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum),
703862306a36Sopenharmony_ci		le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum),
703962306a36Sopenharmony_ci		le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum)
704062306a36Sopenharmony_ci	};
704162306a36Sopenharmony_ci
704262306a36Sopenharmony_ci	BUG_ON(!ext4_has_feature_quota(sb));
704362306a36Sopenharmony_ci
704462306a36Sopenharmony_ci	if (!qf_inums[type])
704562306a36Sopenharmony_ci		return -EPERM;
704662306a36Sopenharmony_ci
704762306a36Sopenharmony_ci	if (!ext4_check_quota_inum(type, qf_inums[type])) {
704862306a36Sopenharmony_ci		ext4_error(sb, "Bad quota inum: %lu, type: %d",
704962306a36Sopenharmony_ci				qf_inums[type], type);
705062306a36Sopenharmony_ci		return -EUCLEAN;
705162306a36Sopenharmony_ci	}
705262306a36Sopenharmony_ci
705362306a36Sopenharmony_ci	qf_inode = ext4_iget(sb, qf_inums[type], EXT4_IGET_SPECIAL);
705462306a36Sopenharmony_ci	if (IS_ERR(qf_inode)) {
705562306a36Sopenharmony_ci		ext4_error(sb, "Bad quota inode: %lu, type: %d",
705662306a36Sopenharmony_ci				qf_inums[type], type);
705762306a36Sopenharmony_ci		return PTR_ERR(qf_inode);
705862306a36Sopenharmony_ci	}
705962306a36Sopenharmony_ci
706062306a36Sopenharmony_ci	/* Don't account quota for quota files to avoid recursion */
706162306a36Sopenharmony_ci	qf_inode->i_flags |= S_NOQUOTA;
706262306a36Sopenharmony_ci	lockdep_set_quota_inode(qf_inode, I_DATA_SEM_QUOTA);
706362306a36Sopenharmony_ci	err = dquot_load_quota_inode(qf_inode, type, format_id, flags);
706462306a36Sopenharmony_ci	if (err)
706562306a36Sopenharmony_ci		lockdep_set_quota_inode(qf_inode, I_DATA_SEM_NORMAL);
706662306a36Sopenharmony_ci	iput(qf_inode);
706762306a36Sopenharmony_ci
706862306a36Sopenharmony_ci	return err;
706962306a36Sopenharmony_ci}
707062306a36Sopenharmony_ci
707162306a36Sopenharmony_ci/* Enable usage tracking for all quota types. */
707262306a36Sopenharmony_ciint ext4_enable_quotas(struct super_block *sb)
707362306a36Sopenharmony_ci{
707462306a36Sopenharmony_ci	int type, err = 0;
707562306a36Sopenharmony_ci	unsigned long qf_inums[EXT4_MAXQUOTAS] = {
707662306a36Sopenharmony_ci		le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum),
707762306a36Sopenharmony_ci		le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum),
707862306a36Sopenharmony_ci		le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum)
707962306a36Sopenharmony_ci	};
708062306a36Sopenharmony_ci	bool quota_mopt[EXT4_MAXQUOTAS] = {
708162306a36Sopenharmony_ci		test_opt(sb, USRQUOTA),
708262306a36Sopenharmony_ci		test_opt(sb, GRPQUOTA),
708362306a36Sopenharmony_ci		test_opt(sb, PRJQUOTA),
708462306a36Sopenharmony_ci	};
708562306a36Sopenharmony_ci
708662306a36Sopenharmony_ci	sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE | DQUOT_NOLIST_DIRTY;
708762306a36Sopenharmony_ci	for (type = 0; type < EXT4_MAXQUOTAS; type++) {
708862306a36Sopenharmony_ci		if (qf_inums[type]) {
708962306a36Sopenharmony_ci			err = ext4_quota_enable(sb, type, QFMT_VFS_V1,
709062306a36Sopenharmony_ci				DQUOT_USAGE_ENABLED |
709162306a36Sopenharmony_ci				(quota_mopt[type] ? DQUOT_LIMITS_ENABLED : 0));
709262306a36Sopenharmony_ci			if (err) {
709362306a36Sopenharmony_ci				ext4_warning(sb,
709462306a36Sopenharmony_ci					"Failed to enable quota tracking "
709562306a36Sopenharmony_ci					"(type=%d, err=%d, ino=%lu). "
709662306a36Sopenharmony_ci					"Please run e2fsck to fix.", type,
709762306a36Sopenharmony_ci					err, qf_inums[type]);
709862306a36Sopenharmony_ci
709962306a36Sopenharmony_ci				ext4_quotas_off(sb, type);
710062306a36Sopenharmony_ci				return err;
710162306a36Sopenharmony_ci			}
710262306a36Sopenharmony_ci		}
710362306a36Sopenharmony_ci	}
710462306a36Sopenharmony_ci	return 0;
710562306a36Sopenharmony_ci}
710662306a36Sopenharmony_ci
710762306a36Sopenharmony_cistatic int ext4_quota_off(struct super_block *sb, int type)
710862306a36Sopenharmony_ci{
710962306a36Sopenharmony_ci	struct inode *inode = sb_dqopt(sb)->files[type];
711062306a36Sopenharmony_ci	handle_t *handle;
711162306a36Sopenharmony_ci	int err;
711262306a36Sopenharmony_ci
711362306a36Sopenharmony_ci	/* Force all delayed allocation blocks to be allocated.
711462306a36Sopenharmony_ci	 * Caller already holds s_umount sem */
711562306a36Sopenharmony_ci	if (test_opt(sb, DELALLOC))
711662306a36Sopenharmony_ci		sync_filesystem(sb);
711762306a36Sopenharmony_ci
711862306a36Sopenharmony_ci	if (!inode || !igrab(inode))
711962306a36Sopenharmony_ci		goto out;
712062306a36Sopenharmony_ci
712162306a36Sopenharmony_ci	err = dquot_quota_off(sb, type);
712262306a36Sopenharmony_ci	if (err || ext4_has_feature_quota(sb))
712362306a36Sopenharmony_ci		goto out_put;
712462306a36Sopenharmony_ci	/*
712562306a36Sopenharmony_ci	 * When the filesystem was remounted read-only first, we cannot cleanup
712662306a36Sopenharmony_ci	 * inode flags here. Bad luck but people should be using QUOTA feature
712762306a36Sopenharmony_ci	 * these days anyway.
712862306a36Sopenharmony_ci	 */
712962306a36Sopenharmony_ci	if (sb_rdonly(sb))
713062306a36Sopenharmony_ci		goto out_put;
713162306a36Sopenharmony_ci
713262306a36Sopenharmony_ci	inode_lock(inode);
713362306a36Sopenharmony_ci	/*
713462306a36Sopenharmony_ci	 * Update modification times of quota files when userspace can
713562306a36Sopenharmony_ci	 * start looking at them. If we fail, we return success anyway since
713662306a36Sopenharmony_ci	 * this is not a hard failure and quotas are already disabled.
713762306a36Sopenharmony_ci	 */
713862306a36Sopenharmony_ci	handle = ext4_journal_start(inode, EXT4_HT_QUOTA, 1);
713962306a36Sopenharmony_ci	if (IS_ERR(handle)) {
714062306a36Sopenharmony_ci		err = PTR_ERR(handle);
714162306a36Sopenharmony_ci		goto out_unlock;
714262306a36Sopenharmony_ci	}
714362306a36Sopenharmony_ci	EXT4_I(inode)->i_flags &= ~(EXT4_NOATIME_FL | EXT4_IMMUTABLE_FL);
714462306a36Sopenharmony_ci	inode_set_flags(inode, 0, S_NOATIME | S_IMMUTABLE);
714562306a36Sopenharmony_ci	inode->i_mtime = inode_set_ctime_current(inode);
714662306a36Sopenharmony_ci	err = ext4_mark_inode_dirty(handle, inode);
714762306a36Sopenharmony_ci	ext4_journal_stop(handle);
714862306a36Sopenharmony_ciout_unlock:
714962306a36Sopenharmony_ci	inode_unlock(inode);
715062306a36Sopenharmony_ciout_put:
715162306a36Sopenharmony_ci	lockdep_set_quota_inode(inode, I_DATA_SEM_NORMAL);
715262306a36Sopenharmony_ci	iput(inode);
715362306a36Sopenharmony_ci	return err;
715462306a36Sopenharmony_ciout:
715562306a36Sopenharmony_ci	return dquot_quota_off(sb, type);
715662306a36Sopenharmony_ci}
715762306a36Sopenharmony_ci
715862306a36Sopenharmony_ci/* Read data from quotafile - avoid pagecache and such because we cannot afford
715962306a36Sopenharmony_ci * acquiring the locks... As quota files are never truncated and quota code
716062306a36Sopenharmony_ci * itself serializes the operations (and no one else should touch the files)
716162306a36Sopenharmony_ci * we don't have to be afraid of races */
716262306a36Sopenharmony_cistatic ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
716362306a36Sopenharmony_ci			       size_t len, loff_t off)
716462306a36Sopenharmony_ci{
716562306a36Sopenharmony_ci	struct inode *inode = sb_dqopt(sb)->files[type];
716662306a36Sopenharmony_ci	ext4_lblk_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
716762306a36Sopenharmony_ci	int offset = off & (sb->s_blocksize - 1);
716862306a36Sopenharmony_ci	int tocopy;
716962306a36Sopenharmony_ci	size_t toread;
717062306a36Sopenharmony_ci	struct buffer_head *bh;
717162306a36Sopenharmony_ci	loff_t i_size = i_size_read(inode);
717262306a36Sopenharmony_ci
717362306a36Sopenharmony_ci	if (off > i_size)
717462306a36Sopenharmony_ci		return 0;
717562306a36Sopenharmony_ci	if (off+len > i_size)
717662306a36Sopenharmony_ci		len = i_size-off;
717762306a36Sopenharmony_ci	toread = len;
717862306a36Sopenharmony_ci	while (toread > 0) {
717962306a36Sopenharmony_ci		tocopy = min_t(unsigned long, sb->s_blocksize - offset, toread);
718062306a36Sopenharmony_ci		bh = ext4_bread(NULL, inode, blk, 0);
718162306a36Sopenharmony_ci		if (IS_ERR(bh))
718262306a36Sopenharmony_ci			return PTR_ERR(bh);
718362306a36Sopenharmony_ci		if (!bh)	/* A hole? */
718462306a36Sopenharmony_ci			memset(data, 0, tocopy);
718562306a36Sopenharmony_ci		else
718662306a36Sopenharmony_ci			memcpy(data, bh->b_data+offset, tocopy);
718762306a36Sopenharmony_ci		brelse(bh);
718862306a36Sopenharmony_ci		offset = 0;
718962306a36Sopenharmony_ci		toread -= tocopy;
719062306a36Sopenharmony_ci		data += tocopy;
719162306a36Sopenharmony_ci		blk++;
719262306a36Sopenharmony_ci	}
719362306a36Sopenharmony_ci	return len;
719462306a36Sopenharmony_ci}
719562306a36Sopenharmony_ci
719662306a36Sopenharmony_ci/* Write to quotafile (we know the transaction is already started and has
719762306a36Sopenharmony_ci * enough credits) */
719862306a36Sopenharmony_cistatic ssize_t ext4_quota_write(struct super_block *sb, int type,
719962306a36Sopenharmony_ci				const char *data, size_t len, loff_t off)
720062306a36Sopenharmony_ci{
720162306a36Sopenharmony_ci	struct inode *inode = sb_dqopt(sb)->files[type];
720262306a36Sopenharmony_ci	ext4_lblk_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
720362306a36Sopenharmony_ci	int err = 0, err2 = 0, offset = off & (sb->s_blocksize - 1);
720462306a36Sopenharmony_ci	int retries = 0;
720562306a36Sopenharmony_ci	struct buffer_head *bh;
720662306a36Sopenharmony_ci	handle_t *handle = journal_current_handle();
720762306a36Sopenharmony_ci
720862306a36Sopenharmony_ci	if (!handle) {
720962306a36Sopenharmony_ci		ext4_msg(sb, KERN_WARNING, "Quota write (off=%llu, len=%llu)"
721062306a36Sopenharmony_ci			" cancelled because transaction is not started",
721162306a36Sopenharmony_ci			(unsigned long long)off, (unsigned long long)len);
721262306a36Sopenharmony_ci		return -EIO;
721362306a36Sopenharmony_ci	}
721462306a36Sopenharmony_ci	/*
721562306a36Sopenharmony_ci	 * Since we account only one data block in transaction credits,
721662306a36Sopenharmony_ci	 * then it is impossible to cross a block boundary.
721762306a36Sopenharmony_ci	 */
721862306a36Sopenharmony_ci	if (sb->s_blocksize - offset < len) {
721962306a36Sopenharmony_ci		ext4_msg(sb, KERN_WARNING, "Quota write (off=%llu, len=%llu)"
722062306a36Sopenharmony_ci			" cancelled because not block aligned",
722162306a36Sopenharmony_ci			(unsigned long long)off, (unsigned long long)len);
722262306a36Sopenharmony_ci		return -EIO;
722362306a36Sopenharmony_ci	}
722462306a36Sopenharmony_ci
722562306a36Sopenharmony_ci	do {
722662306a36Sopenharmony_ci		bh = ext4_bread(handle, inode, blk,
722762306a36Sopenharmony_ci				EXT4_GET_BLOCKS_CREATE |
722862306a36Sopenharmony_ci				EXT4_GET_BLOCKS_METADATA_NOFAIL);
722962306a36Sopenharmony_ci	} while (PTR_ERR(bh) == -ENOSPC &&
723062306a36Sopenharmony_ci		 ext4_should_retry_alloc(inode->i_sb, &retries));
723162306a36Sopenharmony_ci	if (IS_ERR(bh))
723262306a36Sopenharmony_ci		return PTR_ERR(bh);
723362306a36Sopenharmony_ci	if (!bh)
723462306a36Sopenharmony_ci		goto out;
723562306a36Sopenharmony_ci	BUFFER_TRACE(bh, "get write access");
723662306a36Sopenharmony_ci	err = ext4_journal_get_write_access(handle, sb, bh, EXT4_JTR_NONE);
723762306a36Sopenharmony_ci	if (err) {
723862306a36Sopenharmony_ci		brelse(bh);
723962306a36Sopenharmony_ci		return err;
724062306a36Sopenharmony_ci	}
724162306a36Sopenharmony_ci	lock_buffer(bh);
724262306a36Sopenharmony_ci	memcpy(bh->b_data+offset, data, len);
724362306a36Sopenharmony_ci	flush_dcache_page(bh->b_page);
724462306a36Sopenharmony_ci	unlock_buffer(bh);
724562306a36Sopenharmony_ci	err = ext4_handle_dirty_metadata(handle, NULL, bh);
724662306a36Sopenharmony_ci	brelse(bh);
724762306a36Sopenharmony_ciout:
724862306a36Sopenharmony_ci	if (inode->i_size < off + len) {
724962306a36Sopenharmony_ci		i_size_write(inode, off + len);
725062306a36Sopenharmony_ci		EXT4_I(inode)->i_disksize = inode->i_size;
725162306a36Sopenharmony_ci		err2 = ext4_mark_inode_dirty(handle, inode);
725262306a36Sopenharmony_ci		if (unlikely(err2 && !err))
725362306a36Sopenharmony_ci			err = err2;
725462306a36Sopenharmony_ci	}
725562306a36Sopenharmony_ci	return err ? err : len;
725662306a36Sopenharmony_ci}
725762306a36Sopenharmony_ci#endif
725862306a36Sopenharmony_ci
725962306a36Sopenharmony_ci#if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT2)
726062306a36Sopenharmony_cistatic inline void register_as_ext2(void)
726162306a36Sopenharmony_ci{
726262306a36Sopenharmony_ci	int err = register_filesystem(&ext2_fs_type);
726362306a36Sopenharmony_ci	if (err)
726462306a36Sopenharmony_ci		printk(KERN_WARNING
726562306a36Sopenharmony_ci		       "EXT4-fs: Unable to register as ext2 (%d)\n", err);
726662306a36Sopenharmony_ci}
726762306a36Sopenharmony_ci
726862306a36Sopenharmony_cistatic inline void unregister_as_ext2(void)
726962306a36Sopenharmony_ci{
727062306a36Sopenharmony_ci	unregister_filesystem(&ext2_fs_type);
727162306a36Sopenharmony_ci}
727262306a36Sopenharmony_ci
727362306a36Sopenharmony_cistatic inline int ext2_feature_set_ok(struct super_block *sb)
727462306a36Sopenharmony_ci{
727562306a36Sopenharmony_ci	if (ext4_has_unknown_ext2_incompat_features(sb))
727662306a36Sopenharmony_ci		return 0;
727762306a36Sopenharmony_ci	if (sb_rdonly(sb))
727862306a36Sopenharmony_ci		return 1;
727962306a36Sopenharmony_ci	if (ext4_has_unknown_ext2_ro_compat_features(sb))
728062306a36Sopenharmony_ci		return 0;
728162306a36Sopenharmony_ci	return 1;
728262306a36Sopenharmony_ci}
728362306a36Sopenharmony_ci#else
728462306a36Sopenharmony_cistatic inline void register_as_ext2(void) { }
728562306a36Sopenharmony_cistatic inline void unregister_as_ext2(void) { }
728662306a36Sopenharmony_cistatic inline int ext2_feature_set_ok(struct super_block *sb) { return 0; }
728762306a36Sopenharmony_ci#endif
728862306a36Sopenharmony_ci
728962306a36Sopenharmony_cistatic inline void register_as_ext3(void)
729062306a36Sopenharmony_ci{
729162306a36Sopenharmony_ci	int err = register_filesystem(&ext3_fs_type);
729262306a36Sopenharmony_ci	if (err)
729362306a36Sopenharmony_ci		printk(KERN_WARNING
729462306a36Sopenharmony_ci		       "EXT4-fs: Unable to register as ext3 (%d)\n", err);
729562306a36Sopenharmony_ci}
729662306a36Sopenharmony_ci
729762306a36Sopenharmony_cistatic inline void unregister_as_ext3(void)
729862306a36Sopenharmony_ci{
729962306a36Sopenharmony_ci	unregister_filesystem(&ext3_fs_type);
730062306a36Sopenharmony_ci}
730162306a36Sopenharmony_ci
730262306a36Sopenharmony_cistatic inline int ext3_feature_set_ok(struct super_block *sb)
730362306a36Sopenharmony_ci{
730462306a36Sopenharmony_ci	if (ext4_has_unknown_ext3_incompat_features(sb))
730562306a36Sopenharmony_ci		return 0;
730662306a36Sopenharmony_ci	if (!ext4_has_feature_journal(sb))
730762306a36Sopenharmony_ci		return 0;
730862306a36Sopenharmony_ci	if (sb_rdonly(sb))
730962306a36Sopenharmony_ci		return 1;
731062306a36Sopenharmony_ci	if (ext4_has_unknown_ext3_ro_compat_features(sb))
731162306a36Sopenharmony_ci		return 0;
731262306a36Sopenharmony_ci	return 1;
731362306a36Sopenharmony_ci}
731462306a36Sopenharmony_ci
731562306a36Sopenharmony_cistatic void ext4_kill_sb(struct super_block *sb)
731662306a36Sopenharmony_ci{
731762306a36Sopenharmony_ci	struct ext4_sb_info *sbi = EXT4_SB(sb);
731862306a36Sopenharmony_ci	struct block_device *journal_bdev = sbi ? sbi->s_journal_bdev : NULL;
731962306a36Sopenharmony_ci
732062306a36Sopenharmony_ci	kill_block_super(sb);
732162306a36Sopenharmony_ci
732262306a36Sopenharmony_ci	if (journal_bdev)
732362306a36Sopenharmony_ci		blkdev_put(journal_bdev, sb);
732462306a36Sopenharmony_ci}
732562306a36Sopenharmony_ci
732662306a36Sopenharmony_cistatic struct file_system_type ext4_fs_type = {
732762306a36Sopenharmony_ci	.owner			= THIS_MODULE,
732862306a36Sopenharmony_ci	.name			= "ext4",
732962306a36Sopenharmony_ci	.init_fs_context	= ext4_init_fs_context,
733062306a36Sopenharmony_ci	.parameters		= ext4_param_specs,
733162306a36Sopenharmony_ci	.kill_sb		= ext4_kill_sb,
733262306a36Sopenharmony_ci	.fs_flags		= FS_REQUIRES_DEV | FS_ALLOW_IDMAP,
733362306a36Sopenharmony_ci};
733462306a36Sopenharmony_ciMODULE_ALIAS_FS("ext4");
733562306a36Sopenharmony_ci
733662306a36Sopenharmony_ci/* Shared across all ext4 file systems */
733762306a36Sopenharmony_ciwait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
733862306a36Sopenharmony_ci
733962306a36Sopenharmony_cistatic int __init ext4_init_fs(void)
734062306a36Sopenharmony_ci{
734162306a36Sopenharmony_ci	int i, err;
734262306a36Sopenharmony_ci
734362306a36Sopenharmony_ci	ratelimit_state_init(&ext4_mount_msg_ratelimit, 30 * HZ, 64);
734462306a36Sopenharmony_ci	ext4_li_info = NULL;
734562306a36Sopenharmony_ci
734662306a36Sopenharmony_ci	/* Build-time check for flags consistency */
734762306a36Sopenharmony_ci	ext4_check_flag_values();
734862306a36Sopenharmony_ci
734962306a36Sopenharmony_ci	for (i = 0; i < EXT4_WQ_HASH_SZ; i++)
735062306a36Sopenharmony_ci		init_waitqueue_head(&ext4__ioend_wq[i]);
735162306a36Sopenharmony_ci
735262306a36Sopenharmony_ci	err = ext4_init_es();
735362306a36Sopenharmony_ci	if (err)
735462306a36Sopenharmony_ci		return err;
735562306a36Sopenharmony_ci
735662306a36Sopenharmony_ci	err = ext4_init_pending();
735762306a36Sopenharmony_ci	if (err)
735862306a36Sopenharmony_ci		goto out7;
735962306a36Sopenharmony_ci
736062306a36Sopenharmony_ci	err = ext4_init_post_read_processing();
736162306a36Sopenharmony_ci	if (err)
736262306a36Sopenharmony_ci		goto out6;
736362306a36Sopenharmony_ci
736462306a36Sopenharmony_ci	err = ext4_init_pageio();
736562306a36Sopenharmony_ci	if (err)
736662306a36Sopenharmony_ci		goto out5;
736762306a36Sopenharmony_ci
736862306a36Sopenharmony_ci	err = ext4_init_system_zone();
736962306a36Sopenharmony_ci	if (err)
737062306a36Sopenharmony_ci		goto out4;
737162306a36Sopenharmony_ci
737262306a36Sopenharmony_ci	err = ext4_init_sysfs();
737362306a36Sopenharmony_ci	if (err)
737462306a36Sopenharmony_ci		goto out3;
737562306a36Sopenharmony_ci
737662306a36Sopenharmony_ci	err = ext4_init_mballoc();
737762306a36Sopenharmony_ci	if (err)
737862306a36Sopenharmony_ci		goto out2;
737962306a36Sopenharmony_ci	err = init_inodecache();
738062306a36Sopenharmony_ci	if (err)
738162306a36Sopenharmony_ci		goto out1;
738262306a36Sopenharmony_ci
738362306a36Sopenharmony_ci	err = ext4_fc_init_dentry_cache();
738462306a36Sopenharmony_ci	if (err)
738562306a36Sopenharmony_ci		goto out05;
738662306a36Sopenharmony_ci
738762306a36Sopenharmony_ci	register_as_ext3();
738862306a36Sopenharmony_ci	register_as_ext2();
738962306a36Sopenharmony_ci	err = register_filesystem(&ext4_fs_type);
739062306a36Sopenharmony_ci	if (err)
739162306a36Sopenharmony_ci		goto out;
739262306a36Sopenharmony_ci
739362306a36Sopenharmony_ci	return 0;
739462306a36Sopenharmony_ciout:
739562306a36Sopenharmony_ci	unregister_as_ext2();
739662306a36Sopenharmony_ci	unregister_as_ext3();
739762306a36Sopenharmony_ci	ext4_fc_destroy_dentry_cache();
739862306a36Sopenharmony_ciout05:
739962306a36Sopenharmony_ci	destroy_inodecache();
740062306a36Sopenharmony_ciout1:
740162306a36Sopenharmony_ci	ext4_exit_mballoc();
740262306a36Sopenharmony_ciout2:
740362306a36Sopenharmony_ci	ext4_exit_sysfs();
740462306a36Sopenharmony_ciout3:
740562306a36Sopenharmony_ci	ext4_exit_system_zone();
740662306a36Sopenharmony_ciout4:
740762306a36Sopenharmony_ci	ext4_exit_pageio();
740862306a36Sopenharmony_ciout5:
740962306a36Sopenharmony_ci	ext4_exit_post_read_processing();
741062306a36Sopenharmony_ciout6:
741162306a36Sopenharmony_ci	ext4_exit_pending();
741262306a36Sopenharmony_ciout7:
741362306a36Sopenharmony_ci	ext4_exit_es();
741462306a36Sopenharmony_ci
741562306a36Sopenharmony_ci	return err;
741662306a36Sopenharmony_ci}
741762306a36Sopenharmony_ci
741862306a36Sopenharmony_cistatic void __exit ext4_exit_fs(void)
741962306a36Sopenharmony_ci{
742062306a36Sopenharmony_ci	ext4_destroy_lazyinit_thread();
742162306a36Sopenharmony_ci	unregister_as_ext2();
742262306a36Sopenharmony_ci	unregister_as_ext3();
742362306a36Sopenharmony_ci	unregister_filesystem(&ext4_fs_type);
742462306a36Sopenharmony_ci	ext4_fc_destroy_dentry_cache();
742562306a36Sopenharmony_ci	destroy_inodecache();
742662306a36Sopenharmony_ci	ext4_exit_mballoc();
742762306a36Sopenharmony_ci	ext4_exit_sysfs();
742862306a36Sopenharmony_ci	ext4_exit_system_zone();
742962306a36Sopenharmony_ci	ext4_exit_pageio();
743062306a36Sopenharmony_ci	ext4_exit_post_read_processing();
743162306a36Sopenharmony_ci	ext4_exit_es();
743262306a36Sopenharmony_ci	ext4_exit_pending();
743362306a36Sopenharmony_ci}
743462306a36Sopenharmony_ci
743562306a36Sopenharmony_ciMODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
743662306a36Sopenharmony_ciMODULE_DESCRIPTION("Fourth Extended Filesystem");
743762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
743862306a36Sopenharmony_ciMODULE_SOFTDEP("pre: crc32c");
743962306a36Sopenharmony_cimodule_init(ext4_init_fs)
744062306a36Sopenharmony_cimodule_exit(ext4_exit_fs)
7441