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, ¶m); 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