18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/ext4/super.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1992, 1993, 1994, 1995 68c2ecf20Sopenharmony_ci * Remy Card (card@masi.ibp.fr) 78c2ecf20Sopenharmony_ci * Laboratoire MASI - Institut Blaise Pascal 88c2ecf20Sopenharmony_ci * Universite Pierre et Marie Curie (Paris VI) 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * from 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * linux/fs/minix/inode.c 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Big-endian to little-endian byte-swapping/bitmaps by 178c2ecf20Sopenharmony_ci * David S. Miller (davem@caip.rutgers.edu), 1995 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <linux/string.h> 228c2ecf20Sopenharmony_ci#include <linux/fs.h> 238c2ecf20Sopenharmony_ci#include <linux/time.h> 248c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 258c2ecf20Sopenharmony_ci#include <linux/slab.h> 268c2ecf20Sopenharmony_ci#include <linux/init.h> 278c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 288c2ecf20Sopenharmony_ci#include <linux/backing-dev.h> 298c2ecf20Sopenharmony_ci#include <linux/parser.h> 308c2ecf20Sopenharmony_ci#include <linux/buffer_head.h> 318c2ecf20Sopenharmony_ci#include <linux/exportfs.h> 328c2ecf20Sopenharmony_ci#include <linux/vfs.h> 338c2ecf20Sopenharmony_ci#include <linux/random.h> 348c2ecf20Sopenharmony_ci#include <linux/mount.h> 358c2ecf20Sopenharmony_ci#include <linux/namei.h> 368c2ecf20Sopenharmony_ci#include <linux/quotaops.h> 378c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 388c2ecf20Sopenharmony_ci#include <linux/ctype.h> 398c2ecf20Sopenharmony_ci#include <linux/log2.h> 408c2ecf20Sopenharmony_ci#include <linux/crc16.h> 418c2ecf20Sopenharmony_ci#include <linux/dax.h> 428c2ecf20Sopenharmony_ci#include <linux/cleancache.h> 438c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 448c2ecf20Sopenharmony_ci#include <linux/iversion.h> 458c2ecf20Sopenharmony_ci#include <linux/unicode.h> 468c2ecf20Sopenharmony_ci#include <linux/part_stat.h> 478c2ecf20Sopenharmony_ci#include <linux/kthread.h> 488c2ecf20Sopenharmony_ci#include <linux/freezer.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include "ext4.h" 518c2ecf20Sopenharmony_ci#include "ext4_extents.h" /* Needed for trace points definition */ 528c2ecf20Sopenharmony_ci#include "ext4_jbd2.h" 538c2ecf20Sopenharmony_ci#include "xattr.h" 548c2ecf20Sopenharmony_ci#include "acl.h" 558c2ecf20Sopenharmony_ci#include "mballoc.h" 568c2ecf20Sopenharmony_ci#include "fsmap.h" 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 598c2ecf20Sopenharmony_ci#include <trace/events/ext4.h> 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic struct ext4_lazy_init *ext4_li_info; 628c2ecf20Sopenharmony_cistatic struct mutex ext4_li_mtx; 638c2ecf20Sopenharmony_cistatic struct ratelimit_state ext4_mount_msg_ratelimit; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int ext4_load_journal(struct super_block *, struct ext4_super_block *, 668c2ecf20Sopenharmony_ci unsigned long journal_devnum); 678c2ecf20Sopenharmony_cistatic int ext4_show_options(struct seq_file *seq, struct dentry *root); 688c2ecf20Sopenharmony_cistatic void ext4_update_super(struct super_block *sb); 698c2ecf20Sopenharmony_cistatic int ext4_commit_super(struct super_block *sb); 708c2ecf20Sopenharmony_cistatic int ext4_mark_recovery_complete(struct super_block *sb, 718c2ecf20Sopenharmony_ci struct ext4_super_block *es); 728c2ecf20Sopenharmony_cistatic int ext4_clear_journal_err(struct super_block *sb, 738c2ecf20Sopenharmony_ci struct ext4_super_block *es); 748c2ecf20Sopenharmony_cistatic int ext4_sync_fs(struct super_block *sb, int wait); 758c2ecf20Sopenharmony_cistatic int ext4_remount(struct super_block *sb, int *flags, char *data); 768c2ecf20Sopenharmony_cistatic int ext4_statfs(struct dentry *dentry, struct kstatfs *buf); 778c2ecf20Sopenharmony_cistatic int ext4_unfreeze(struct super_block *sb); 788c2ecf20Sopenharmony_cistatic int ext4_freeze(struct super_block *sb); 798c2ecf20Sopenharmony_cistatic struct dentry *ext4_mount(struct file_system_type *fs_type, int flags, 808c2ecf20Sopenharmony_ci const char *dev_name, void *data); 818c2ecf20Sopenharmony_cistatic inline int ext2_feature_set_ok(struct super_block *sb); 828c2ecf20Sopenharmony_cistatic inline int ext3_feature_set_ok(struct super_block *sb); 838c2ecf20Sopenharmony_cistatic int ext4_feature_set_ok(struct super_block *sb, int readonly); 848c2ecf20Sopenharmony_cistatic void ext4_destroy_lazyinit_thread(void); 858c2ecf20Sopenharmony_cistatic void ext4_unregister_li_request(struct super_block *sb); 868c2ecf20Sopenharmony_cistatic void ext4_clear_request_list(void); 878c2ecf20Sopenharmony_cistatic struct inode *ext4_get_journal_inode(struct super_block *sb, 888c2ecf20Sopenharmony_ci unsigned int journal_inum); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* 918c2ecf20Sopenharmony_ci * Lock ordering 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * Note the difference between i_mmap_sem (EXT4_I(inode)->i_mmap_sem) and 948c2ecf20Sopenharmony_ci * i_mmap_rwsem (inode->i_mmap_rwsem)! 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * page fault path: 978c2ecf20Sopenharmony_ci * mmap_lock -> sb_start_pagefault -> i_mmap_sem (r) -> transaction start -> 988c2ecf20Sopenharmony_ci * page lock -> i_data_sem (rw) 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * buffered write path: 1018c2ecf20Sopenharmony_ci * sb_start_write -> i_mutex -> mmap_lock 1028c2ecf20Sopenharmony_ci * sb_start_write -> i_mutex -> transaction start -> page lock -> 1038c2ecf20Sopenharmony_ci * i_data_sem (rw) 1048c2ecf20Sopenharmony_ci * 1058c2ecf20Sopenharmony_ci * truncate: 1068c2ecf20Sopenharmony_ci * sb_start_write -> i_mutex -> i_mmap_sem (w) -> i_mmap_rwsem (w) -> page lock 1078c2ecf20Sopenharmony_ci * sb_start_write -> i_mutex -> i_mmap_sem (w) -> transaction start -> 1088c2ecf20Sopenharmony_ci * i_data_sem (rw) 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci * direct IO: 1118c2ecf20Sopenharmony_ci * sb_start_write -> i_mutex -> mmap_lock 1128c2ecf20Sopenharmony_ci * sb_start_write -> i_mutex -> transaction start -> i_data_sem (rw) 1138c2ecf20Sopenharmony_ci * 1148c2ecf20Sopenharmony_ci * writepages: 1158c2ecf20Sopenharmony_ci * transaction start -> page lock(s) -> i_data_sem (rw) 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT2) 1198c2ecf20Sopenharmony_cistatic struct file_system_type ext2_fs_type = { 1208c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1218c2ecf20Sopenharmony_ci .name = "ext2", 1228c2ecf20Sopenharmony_ci .mount = ext4_mount, 1238c2ecf20Sopenharmony_ci .kill_sb = kill_block_super, 1248c2ecf20Sopenharmony_ci .fs_flags = FS_REQUIRES_DEV, 1258c2ecf20Sopenharmony_ci}; 1268c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("ext2"); 1278c2ecf20Sopenharmony_ciMODULE_ALIAS("ext2"); 1288c2ecf20Sopenharmony_ci#define IS_EXT2_SB(sb) ((sb)->s_bdev->bd_holder == &ext2_fs_type) 1298c2ecf20Sopenharmony_ci#else 1308c2ecf20Sopenharmony_ci#define IS_EXT2_SB(sb) (0) 1318c2ecf20Sopenharmony_ci#endif 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic struct file_system_type ext3_fs_type = { 1358c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1368c2ecf20Sopenharmony_ci .name = "ext3", 1378c2ecf20Sopenharmony_ci .mount = ext4_mount, 1388c2ecf20Sopenharmony_ci .kill_sb = kill_block_super, 1398c2ecf20Sopenharmony_ci .fs_flags = FS_REQUIRES_DEV, 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("ext3"); 1428c2ecf20Sopenharmony_ciMODULE_ALIAS("ext3"); 1438c2ecf20Sopenharmony_ci#define IS_EXT3_SB(sb) ((sb)->s_bdev->bd_holder == &ext3_fs_type) 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic inline void __ext4_read_bh(struct buffer_head *bh, int op_flags, 1478c2ecf20Sopenharmony_ci bh_end_io_t *end_io) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci /* 1508c2ecf20Sopenharmony_ci * buffer's verified bit is no longer valid after reading from 1518c2ecf20Sopenharmony_ci * disk again due to write out error, clear it to make sure we 1528c2ecf20Sopenharmony_ci * recheck the buffer contents. 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_ci clear_buffer_verified(bh); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci bh->b_end_io = end_io ? end_io : end_buffer_read_sync; 1578c2ecf20Sopenharmony_ci get_bh(bh); 1588c2ecf20Sopenharmony_ci submit_bh(REQ_OP_READ, op_flags, bh); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_civoid ext4_read_bh_nowait(struct buffer_head *bh, int op_flags, 1628c2ecf20Sopenharmony_ci bh_end_io_t *end_io) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci BUG_ON(!buffer_locked(bh)); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (ext4_buffer_uptodate(bh)) { 1678c2ecf20Sopenharmony_ci unlock_buffer(bh); 1688c2ecf20Sopenharmony_ci return; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci __ext4_read_bh(bh, op_flags, end_io); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ciint ext4_read_bh(struct buffer_head *bh, int op_flags, bh_end_io_t *end_io) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci BUG_ON(!buffer_locked(bh)); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (ext4_buffer_uptodate(bh)) { 1788c2ecf20Sopenharmony_ci unlock_buffer(bh); 1798c2ecf20Sopenharmony_ci return 0; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci __ext4_read_bh(bh, op_flags, end_io); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci wait_on_buffer(bh); 1858c2ecf20Sopenharmony_ci if (buffer_uptodate(bh)) 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci return -EIO; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ciint ext4_read_bh_lock(struct buffer_head *bh, int op_flags, bool wait) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci lock_buffer(bh); 1938c2ecf20Sopenharmony_ci if (!wait) { 1948c2ecf20Sopenharmony_ci ext4_read_bh_nowait(bh, op_flags, NULL); 1958c2ecf20Sopenharmony_ci return 0; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci return ext4_read_bh(bh, op_flags, NULL); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci/* 2018c2ecf20Sopenharmony_ci * This works like __bread_gfp() except it uses ERR_PTR for error 2028c2ecf20Sopenharmony_ci * returns. Currently with sb_bread it's impossible to distinguish 2038c2ecf20Sopenharmony_ci * between ENOMEM and EIO situations (since both result in a NULL 2048c2ecf20Sopenharmony_ci * return. 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_cistatic struct buffer_head *__ext4_sb_bread_gfp(struct super_block *sb, 2078c2ecf20Sopenharmony_ci sector_t block, int op_flags, 2088c2ecf20Sopenharmony_ci gfp_t gfp) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct buffer_head *bh; 2118c2ecf20Sopenharmony_ci int ret; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci bh = sb_getblk_gfp(sb, block, gfp); 2148c2ecf20Sopenharmony_ci if (bh == NULL) 2158c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2168c2ecf20Sopenharmony_ci if (ext4_buffer_uptodate(bh)) 2178c2ecf20Sopenharmony_ci return bh; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci ret = ext4_read_bh_lock(bh, REQ_META | op_flags, true); 2208c2ecf20Sopenharmony_ci if (ret) { 2218c2ecf20Sopenharmony_ci put_bh(bh); 2228c2ecf20Sopenharmony_ci return ERR_PTR(ret); 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci return bh; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistruct buffer_head *ext4_sb_bread(struct super_block *sb, sector_t block, 2288c2ecf20Sopenharmony_ci int op_flags) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci return __ext4_sb_bread_gfp(sb, block, op_flags, __GFP_MOVABLE); 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistruct buffer_head *ext4_sb_bread_unmovable(struct super_block *sb, 2348c2ecf20Sopenharmony_ci sector_t block) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci return __ext4_sb_bread_gfp(sb, block, 0, 0); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_civoid ext4_sb_breadahead_unmovable(struct super_block *sb, sector_t block) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct buffer_head *bh = sb_getblk_gfp(sb, block, 0); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (likely(bh)) { 2448c2ecf20Sopenharmony_ci if (trylock_buffer(bh)) 2458c2ecf20Sopenharmony_ci ext4_read_bh_nowait(bh, REQ_RAHEAD, NULL); 2468c2ecf20Sopenharmony_ci brelse(bh); 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int ext4_verify_csum_type(struct super_block *sb, 2518c2ecf20Sopenharmony_ci struct ext4_super_block *es) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci if (!ext4_has_feature_metadata_csum(sb)) 2548c2ecf20Sopenharmony_ci return 1; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return es->s_checksum_type == EXT4_CRC32C_CHKSUM; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic __le32 ext4_superblock_csum(struct super_block *sb, 2608c2ecf20Sopenharmony_ci struct ext4_super_block *es) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 2638c2ecf20Sopenharmony_ci int offset = offsetof(struct ext4_super_block, s_checksum); 2648c2ecf20Sopenharmony_ci __u32 csum; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci csum = ext4_chksum(sbi, ~0, (char *)es, offset); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return cpu_to_le32(csum); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic int ext4_superblock_csum_verify(struct super_block *sb, 2728c2ecf20Sopenharmony_ci struct ext4_super_block *es) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci if (!ext4_has_metadata_csum(sb)) 2758c2ecf20Sopenharmony_ci return 1; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return es->s_checksum == ext4_superblock_csum(sb, es); 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_civoid ext4_superblock_csum_set(struct super_block *sb) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct ext4_super_block *es = EXT4_SB(sb)->s_es; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (!ext4_has_metadata_csum(sb)) 2858c2ecf20Sopenharmony_ci return; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci es->s_checksum = ext4_superblock_csum(sb, es); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ciext4_fsblk_t ext4_block_bitmap(struct super_block *sb, 2918c2ecf20Sopenharmony_ci struct ext4_group_desc *bg) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci return le32_to_cpu(bg->bg_block_bitmap_lo) | 2948c2ecf20Sopenharmony_ci (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? 2958c2ecf20Sopenharmony_ci (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ciext4_fsblk_t ext4_inode_bitmap(struct super_block *sb, 2998c2ecf20Sopenharmony_ci struct ext4_group_desc *bg) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci return le32_to_cpu(bg->bg_inode_bitmap_lo) | 3028c2ecf20Sopenharmony_ci (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? 3038c2ecf20Sopenharmony_ci (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ciext4_fsblk_t ext4_inode_table(struct super_block *sb, 3078c2ecf20Sopenharmony_ci struct ext4_group_desc *bg) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci return le32_to_cpu(bg->bg_inode_table_lo) | 3108c2ecf20Sopenharmony_ci (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? 3118c2ecf20Sopenharmony_ci (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci__u32 ext4_free_group_clusters(struct super_block *sb, 3158c2ecf20Sopenharmony_ci struct ext4_group_desc *bg) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci return le16_to_cpu(bg->bg_free_blocks_count_lo) | 3188c2ecf20Sopenharmony_ci (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? 3198c2ecf20Sopenharmony_ci (__u32)le16_to_cpu(bg->bg_free_blocks_count_hi) << 16 : 0); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci__u32 ext4_free_inodes_count(struct super_block *sb, 3238c2ecf20Sopenharmony_ci struct ext4_group_desc *bg) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci return le16_to_cpu(bg->bg_free_inodes_count_lo) | 3268c2ecf20Sopenharmony_ci (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? 3278c2ecf20Sopenharmony_ci (__u32)le16_to_cpu(bg->bg_free_inodes_count_hi) << 16 : 0); 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci__u32 ext4_used_dirs_count(struct super_block *sb, 3318c2ecf20Sopenharmony_ci struct ext4_group_desc *bg) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci return le16_to_cpu(bg->bg_used_dirs_count_lo) | 3348c2ecf20Sopenharmony_ci (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? 3358c2ecf20Sopenharmony_ci (__u32)le16_to_cpu(bg->bg_used_dirs_count_hi) << 16 : 0); 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci__u32 ext4_itable_unused_count(struct super_block *sb, 3398c2ecf20Sopenharmony_ci struct ext4_group_desc *bg) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci return le16_to_cpu(bg->bg_itable_unused_lo) | 3428c2ecf20Sopenharmony_ci (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? 3438c2ecf20Sopenharmony_ci (__u32)le16_to_cpu(bg->bg_itable_unused_hi) << 16 : 0); 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_civoid ext4_block_bitmap_set(struct super_block *sb, 3478c2ecf20Sopenharmony_ci struct ext4_group_desc *bg, ext4_fsblk_t blk) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci bg->bg_block_bitmap_lo = cpu_to_le32((u32)blk); 3508c2ecf20Sopenharmony_ci if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) 3518c2ecf20Sopenharmony_ci bg->bg_block_bitmap_hi = cpu_to_le32(blk >> 32); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_civoid ext4_inode_bitmap_set(struct super_block *sb, 3558c2ecf20Sopenharmony_ci struct ext4_group_desc *bg, ext4_fsblk_t blk) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci bg->bg_inode_bitmap_lo = cpu_to_le32((u32)blk); 3588c2ecf20Sopenharmony_ci if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) 3598c2ecf20Sopenharmony_ci bg->bg_inode_bitmap_hi = cpu_to_le32(blk >> 32); 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_civoid ext4_inode_table_set(struct super_block *sb, 3638c2ecf20Sopenharmony_ci struct ext4_group_desc *bg, ext4_fsblk_t blk) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci bg->bg_inode_table_lo = cpu_to_le32((u32)blk); 3668c2ecf20Sopenharmony_ci if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) 3678c2ecf20Sopenharmony_ci bg->bg_inode_table_hi = cpu_to_le32(blk >> 32); 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_civoid ext4_free_group_clusters_set(struct super_block *sb, 3718c2ecf20Sopenharmony_ci struct ext4_group_desc *bg, __u32 count) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci bg->bg_free_blocks_count_lo = cpu_to_le16((__u16)count); 3748c2ecf20Sopenharmony_ci if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) 3758c2ecf20Sopenharmony_ci bg->bg_free_blocks_count_hi = cpu_to_le16(count >> 16); 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_civoid ext4_free_inodes_set(struct super_block *sb, 3798c2ecf20Sopenharmony_ci struct ext4_group_desc *bg, __u32 count) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci bg->bg_free_inodes_count_lo = cpu_to_le16((__u16)count); 3828c2ecf20Sopenharmony_ci if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) 3838c2ecf20Sopenharmony_ci bg->bg_free_inodes_count_hi = cpu_to_le16(count >> 16); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_civoid ext4_used_dirs_set(struct super_block *sb, 3878c2ecf20Sopenharmony_ci struct ext4_group_desc *bg, __u32 count) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci bg->bg_used_dirs_count_lo = cpu_to_le16((__u16)count); 3908c2ecf20Sopenharmony_ci if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) 3918c2ecf20Sopenharmony_ci bg->bg_used_dirs_count_hi = cpu_to_le16(count >> 16); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_civoid ext4_itable_unused_set(struct super_block *sb, 3958c2ecf20Sopenharmony_ci struct ext4_group_desc *bg, __u32 count) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci bg->bg_itable_unused_lo = cpu_to_le16((__u16)count); 3988c2ecf20Sopenharmony_ci if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) 3998c2ecf20Sopenharmony_ci bg->bg_itable_unused_hi = cpu_to_le16(count >> 16); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic void __ext4_update_tstamp(__le32 *lo, __u8 *hi, time64_t now) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci now = clamp_val(now, 0, (1ull << 40) - 1); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci *lo = cpu_to_le32(lower_32_bits(now)); 4078c2ecf20Sopenharmony_ci *hi = upper_32_bits(now); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic time64_t __ext4_get_tstamp(__le32 *lo, __u8 *hi) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci return ((time64_t)(*hi) << 32) + le32_to_cpu(*lo); 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci#define ext4_update_tstamp(es, tstamp) \ 4158c2ecf20Sopenharmony_ci __ext4_update_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi, \ 4168c2ecf20Sopenharmony_ci ktime_get_real_seconds()) 4178c2ecf20Sopenharmony_ci#define ext4_get_tstamp(es, tstamp) \ 4188c2ecf20Sopenharmony_ci __ext4_get_tstamp(&(es)->tstamp, &(es)->tstamp ## _hi) 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci/* 4218c2ecf20Sopenharmony_ci * The del_gendisk() function uninitializes the disk-specific data 4228c2ecf20Sopenharmony_ci * structures, including the bdi structure, without telling anyone 4238c2ecf20Sopenharmony_ci * else. Once this happens, any attempt to call mark_buffer_dirty() 4248c2ecf20Sopenharmony_ci * (for example, by ext4_commit_super), will cause a kernel OOPS. 4258c2ecf20Sopenharmony_ci * This is a kludge to prevent these oops until we can put in a proper 4268c2ecf20Sopenharmony_ci * hook in del_gendisk() to inform the VFS and file system layers. 4278c2ecf20Sopenharmony_ci */ 4288c2ecf20Sopenharmony_cistatic int block_device_ejected(struct super_block *sb) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci struct inode *bd_inode = sb->s_bdev->bd_inode; 4318c2ecf20Sopenharmony_ci struct backing_dev_info *bdi = inode_to_bdi(bd_inode); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci return bdi->dev == NULL; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct super_block *sb = journal->j_private; 4398c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 4408c2ecf20Sopenharmony_ci int error = is_journal_aborted(journal); 4418c2ecf20Sopenharmony_ci struct ext4_journal_cb_entry *jce; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci BUG_ON(txn->t_state == T_FINISHED); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci ext4_process_freed_data(sb, txn->t_tid); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci spin_lock(&sbi->s_md_lock); 4488c2ecf20Sopenharmony_ci while (!list_empty(&txn->t_private_list)) { 4498c2ecf20Sopenharmony_ci jce = list_entry(txn->t_private_list.next, 4508c2ecf20Sopenharmony_ci struct ext4_journal_cb_entry, jce_list); 4518c2ecf20Sopenharmony_ci list_del_init(&jce->jce_list); 4528c2ecf20Sopenharmony_ci spin_unlock(&sbi->s_md_lock); 4538c2ecf20Sopenharmony_ci jce->jce_func(sb, jce, error); 4548c2ecf20Sopenharmony_ci spin_lock(&sbi->s_md_lock); 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci spin_unlock(&sbi->s_md_lock); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci/* 4608c2ecf20Sopenharmony_ci * This writepage callback for write_cache_pages() 4618c2ecf20Sopenharmony_ci * takes care of a few cases after page cleaning. 4628c2ecf20Sopenharmony_ci * 4638c2ecf20Sopenharmony_ci * write_cache_pages() already checks for dirty pages 4648c2ecf20Sopenharmony_ci * and calls clear_page_dirty_for_io(), which we want, 4658c2ecf20Sopenharmony_ci * to write protect the pages. 4668c2ecf20Sopenharmony_ci * 4678c2ecf20Sopenharmony_ci * However, we may have to redirty a page (see below.) 4688c2ecf20Sopenharmony_ci */ 4698c2ecf20Sopenharmony_cistatic int ext4_journalled_writepage_callback(struct page *page, 4708c2ecf20Sopenharmony_ci struct writeback_control *wbc, 4718c2ecf20Sopenharmony_ci void *data) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci transaction_t *transaction = (transaction_t *) data; 4748c2ecf20Sopenharmony_ci struct buffer_head *bh, *head; 4758c2ecf20Sopenharmony_ci struct journal_head *jh; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci bh = head = page_buffers(page); 4788c2ecf20Sopenharmony_ci do { 4798c2ecf20Sopenharmony_ci /* 4808c2ecf20Sopenharmony_ci * We have to redirty a page in these cases: 4818c2ecf20Sopenharmony_ci * 1) If buffer is dirty, it means the page was dirty because it 4828c2ecf20Sopenharmony_ci * contains a buffer that needs checkpointing. So the dirty bit 4838c2ecf20Sopenharmony_ci * needs to be preserved so that checkpointing writes the buffer 4848c2ecf20Sopenharmony_ci * properly. 4858c2ecf20Sopenharmony_ci * 2) If buffer is not part of the committing transaction 4868c2ecf20Sopenharmony_ci * (we may have just accidentally come across this buffer because 4878c2ecf20Sopenharmony_ci * inode range tracking is not exact) or if the currently running 4888c2ecf20Sopenharmony_ci * transaction already contains this buffer as well, dirty bit 4898c2ecf20Sopenharmony_ci * needs to be preserved so that the buffer gets writeprotected 4908c2ecf20Sopenharmony_ci * properly on running transaction's commit. 4918c2ecf20Sopenharmony_ci */ 4928c2ecf20Sopenharmony_ci jh = bh2jh(bh); 4938c2ecf20Sopenharmony_ci if (buffer_dirty(bh) || 4948c2ecf20Sopenharmony_ci (jh && (jh->b_transaction != transaction || 4958c2ecf20Sopenharmony_ci jh->b_next_transaction))) { 4968c2ecf20Sopenharmony_ci redirty_page_for_writepage(wbc, page); 4978c2ecf20Sopenharmony_ci goto out; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci } while ((bh = bh->b_this_page) != head); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ciout: 5028c2ecf20Sopenharmony_ci return AOP_WRITEPAGE_ACTIVATE; 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic int ext4_journalled_submit_inode_data_buffers(struct jbd2_inode *jinode) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci struct address_space *mapping = jinode->i_vfs_inode->i_mapping; 5088c2ecf20Sopenharmony_ci struct writeback_control wbc = { 5098c2ecf20Sopenharmony_ci .sync_mode = WB_SYNC_ALL, 5108c2ecf20Sopenharmony_ci .nr_to_write = LONG_MAX, 5118c2ecf20Sopenharmony_ci .range_start = jinode->i_dirty_start, 5128c2ecf20Sopenharmony_ci .range_end = jinode->i_dirty_end, 5138c2ecf20Sopenharmony_ci }; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci return write_cache_pages(mapping, &wbc, 5168c2ecf20Sopenharmony_ci ext4_journalled_writepage_callback, 5178c2ecf20Sopenharmony_ci jinode->i_transaction); 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic int ext4_journal_submit_inode_data_buffers(struct jbd2_inode *jinode) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci int ret; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if (ext4_should_journal_data(jinode->i_vfs_inode)) 5258c2ecf20Sopenharmony_ci ret = ext4_journalled_submit_inode_data_buffers(jinode); 5268c2ecf20Sopenharmony_ci else 5278c2ecf20Sopenharmony_ci ret = jbd2_journal_submit_inode_data_buffers(jinode); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci return ret; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic int ext4_journal_finish_inode_data_buffers(struct jbd2_inode *jinode) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci int ret = 0; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci if (!ext4_should_journal_data(jinode->i_vfs_inode)) 5378c2ecf20Sopenharmony_ci ret = jbd2_journal_finish_inode_data_buffers(jinode); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci return ret; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic bool system_going_down(void) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci return system_state == SYSTEM_HALT || system_state == SYSTEM_POWER_OFF 5458c2ecf20Sopenharmony_ci || system_state == SYSTEM_RESTART; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistruct ext4_err_translation { 5498c2ecf20Sopenharmony_ci int code; 5508c2ecf20Sopenharmony_ci int errno; 5518c2ecf20Sopenharmony_ci}; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci#define EXT4_ERR_TRANSLATE(err) { .code = EXT4_ERR_##err, .errno = err } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic struct ext4_err_translation err_translation[] = { 5568c2ecf20Sopenharmony_ci EXT4_ERR_TRANSLATE(EIO), 5578c2ecf20Sopenharmony_ci EXT4_ERR_TRANSLATE(ENOMEM), 5588c2ecf20Sopenharmony_ci EXT4_ERR_TRANSLATE(EFSBADCRC), 5598c2ecf20Sopenharmony_ci EXT4_ERR_TRANSLATE(EFSCORRUPTED), 5608c2ecf20Sopenharmony_ci EXT4_ERR_TRANSLATE(ENOSPC), 5618c2ecf20Sopenharmony_ci EXT4_ERR_TRANSLATE(ENOKEY), 5628c2ecf20Sopenharmony_ci EXT4_ERR_TRANSLATE(EROFS), 5638c2ecf20Sopenharmony_ci EXT4_ERR_TRANSLATE(EFBIG), 5648c2ecf20Sopenharmony_ci EXT4_ERR_TRANSLATE(EEXIST), 5658c2ecf20Sopenharmony_ci EXT4_ERR_TRANSLATE(ERANGE), 5668c2ecf20Sopenharmony_ci EXT4_ERR_TRANSLATE(EOVERFLOW), 5678c2ecf20Sopenharmony_ci EXT4_ERR_TRANSLATE(EBUSY), 5688c2ecf20Sopenharmony_ci EXT4_ERR_TRANSLATE(ENOTDIR), 5698c2ecf20Sopenharmony_ci EXT4_ERR_TRANSLATE(ENOTEMPTY), 5708c2ecf20Sopenharmony_ci EXT4_ERR_TRANSLATE(ESHUTDOWN), 5718c2ecf20Sopenharmony_ci EXT4_ERR_TRANSLATE(EFAULT), 5728c2ecf20Sopenharmony_ci}; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic int ext4_errno_to_code(int errno) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci int i; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(err_translation); i++) 5798c2ecf20Sopenharmony_ci if (err_translation[i].errno == errno) 5808c2ecf20Sopenharmony_ci return err_translation[i].code; 5818c2ecf20Sopenharmony_ci return EXT4_ERR_UNKNOWN; 5828c2ecf20Sopenharmony_ci} 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_cistatic void save_error_info(struct super_block *sb, int error, 5858c2ecf20Sopenharmony_ci __u32 ino, __u64 block, 5868c2ecf20Sopenharmony_ci const char *func, unsigned int line) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci /* We default to EFSCORRUPTED error... */ 5918c2ecf20Sopenharmony_ci if (error == 0) 5928c2ecf20Sopenharmony_ci error = EFSCORRUPTED; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci spin_lock(&sbi->s_error_lock); 5958c2ecf20Sopenharmony_ci sbi->s_add_error_count++; 5968c2ecf20Sopenharmony_ci sbi->s_last_error_code = error; 5978c2ecf20Sopenharmony_ci sbi->s_last_error_line = line; 5988c2ecf20Sopenharmony_ci sbi->s_last_error_ino = ino; 5998c2ecf20Sopenharmony_ci sbi->s_last_error_block = block; 6008c2ecf20Sopenharmony_ci sbi->s_last_error_func = func; 6018c2ecf20Sopenharmony_ci sbi->s_last_error_time = ktime_get_real_seconds(); 6028c2ecf20Sopenharmony_ci if (!sbi->s_first_error_time) { 6038c2ecf20Sopenharmony_ci sbi->s_first_error_code = error; 6048c2ecf20Sopenharmony_ci sbi->s_first_error_line = line; 6058c2ecf20Sopenharmony_ci sbi->s_first_error_ino = ino; 6068c2ecf20Sopenharmony_ci sbi->s_first_error_block = block; 6078c2ecf20Sopenharmony_ci sbi->s_first_error_func = func; 6088c2ecf20Sopenharmony_ci sbi->s_first_error_time = sbi->s_last_error_time; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci spin_unlock(&sbi->s_error_lock); 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci/* Deal with the reporting of failure conditions on a filesystem such as 6148c2ecf20Sopenharmony_ci * inconsistencies detected or read IO failures. 6158c2ecf20Sopenharmony_ci * 6168c2ecf20Sopenharmony_ci * On ext2, we can store the error state of the filesystem in the 6178c2ecf20Sopenharmony_ci * superblock. That is not possible on ext4, because we may have other 6188c2ecf20Sopenharmony_ci * write ordering constraints on the superblock which prevent us from 6198c2ecf20Sopenharmony_ci * writing it out straight away; and given that the journal is about to 6208c2ecf20Sopenharmony_ci * be aborted, we can't rely on the current, or future, transactions to 6218c2ecf20Sopenharmony_ci * write out the superblock safely. 6228c2ecf20Sopenharmony_ci * 6238c2ecf20Sopenharmony_ci * We'll just use the jbd2_journal_abort() error code to record an error in 6248c2ecf20Sopenharmony_ci * the journal instead. On recovery, the journal will complain about 6258c2ecf20Sopenharmony_ci * that error until we've noted it down and cleared it. 6268c2ecf20Sopenharmony_ci * 6278c2ecf20Sopenharmony_ci * If force_ro is set, we unconditionally force the filesystem into an 6288c2ecf20Sopenharmony_ci * ABORT|READONLY state, unless the error response on the fs has been set to 6298c2ecf20Sopenharmony_ci * panic in which case we take the easy way out and panic immediately. This is 6308c2ecf20Sopenharmony_ci * used to deal with unrecoverable failures such as journal IO errors or ENOMEM 6318c2ecf20Sopenharmony_ci * at a critical moment in log management. 6328c2ecf20Sopenharmony_ci */ 6338c2ecf20Sopenharmony_cistatic void ext4_handle_error(struct super_block *sb, bool force_ro, int error, 6348c2ecf20Sopenharmony_ci __u32 ino, __u64 block, 6358c2ecf20Sopenharmony_ci const char *func, unsigned int line) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci journal_t *journal = EXT4_SB(sb)->s_journal; 6388c2ecf20Sopenharmony_ci bool continue_fs = !force_ro && test_opt(sb, ERRORS_CONT); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; 6418c2ecf20Sopenharmony_ci if (test_opt(sb, WARN_ON_ERROR)) 6428c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (!continue_fs && !sb_rdonly(sb)) { 6458c2ecf20Sopenharmony_ci ext4_set_mount_flag(sb, EXT4_MF_FS_ABORTED); 6468c2ecf20Sopenharmony_ci if (journal) 6478c2ecf20Sopenharmony_ci jbd2_journal_abort(journal, -EIO); 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (!bdev_read_only(sb->s_bdev)) { 6518c2ecf20Sopenharmony_ci save_error_info(sb, error, ino, block, func, line); 6528c2ecf20Sopenharmony_ci /* 6538c2ecf20Sopenharmony_ci * In case the fs should keep running, we need to writeout 6548c2ecf20Sopenharmony_ci * superblock through the journal. Due to lock ordering 6558c2ecf20Sopenharmony_ci * constraints, it may not be safe to do it right here so we 6568c2ecf20Sopenharmony_ci * defer superblock flushing to a workqueue. 6578c2ecf20Sopenharmony_ci */ 6588c2ecf20Sopenharmony_ci if (continue_fs && journal) 6598c2ecf20Sopenharmony_ci schedule_work(&EXT4_SB(sb)->s_error_work); 6608c2ecf20Sopenharmony_ci else 6618c2ecf20Sopenharmony_ci ext4_commit_super(sb); 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* 6658c2ecf20Sopenharmony_ci * We force ERRORS_RO behavior when system is rebooting. Otherwise we 6668c2ecf20Sopenharmony_ci * could panic during 'reboot -f' as the underlying device got already 6678c2ecf20Sopenharmony_ci * disabled. 6688c2ecf20Sopenharmony_ci */ 6698c2ecf20Sopenharmony_ci if (test_opt(sb, ERRORS_PANIC) && !system_going_down()) { 6708c2ecf20Sopenharmony_ci panic("EXT4-fs (device %s): panic forced after error\n", 6718c2ecf20Sopenharmony_ci sb->s_id); 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (sb_rdonly(sb) || continue_fs) 6758c2ecf20Sopenharmony_ci return; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only"); 6788c2ecf20Sopenharmony_ci /* 6798c2ecf20Sopenharmony_ci * Make sure updated value of ->s_mount_flags will be visible before 6808c2ecf20Sopenharmony_ci * ->s_flags update 6818c2ecf20Sopenharmony_ci */ 6828c2ecf20Sopenharmony_ci smp_wmb(); 6838c2ecf20Sopenharmony_ci sb->s_flags |= SB_RDONLY; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cistatic void flush_stashed_error_work(struct work_struct *work) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = container_of(work, struct ext4_sb_info, 6898c2ecf20Sopenharmony_ci s_error_work); 6908c2ecf20Sopenharmony_ci journal_t *journal = sbi->s_journal; 6918c2ecf20Sopenharmony_ci handle_t *handle; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci /* 6948c2ecf20Sopenharmony_ci * If the journal is still running, we have to write out superblock 6958c2ecf20Sopenharmony_ci * through the journal to avoid collisions of other journalled sb 6968c2ecf20Sopenharmony_ci * updates. 6978c2ecf20Sopenharmony_ci * 6988c2ecf20Sopenharmony_ci * We use directly jbd2 functions here to avoid recursing back into 6998c2ecf20Sopenharmony_ci * ext4 error handling code during handling of previous errors. 7008c2ecf20Sopenharmony_ci */ 7018c2ecf20Sopenharmony_ci if (!sb_rdonly(sbi->s_sb) && journal) { 7028c2ecf20Sopenharmony_ci struct buffer_head *sbh = sbi->s_sbh; 7038c2ecf20Sopenharmony_ci handle = jbd2_journal_start(journal, 1); 7048c2ecf20Sopenharmony_ci if (IS_ERR(handle)) 7058c2ecf20Sopenharmony_ci goto write_directly; 7068c2ecf20Sopenharmony_ci if (jbd2_journal_get_write_access(handle, sbh)) { 7078c2ecf20Sopenharmony_ci jbd2_journal_stop(handle); 7088c2ecf20Sopenharmony_ci goto write_directly; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci ext4_update_super(sbi->s_sb); 7118c2ecf20Sopenharmony_ci if (buffer_write_io_error(sbh) || !buffer_uptodate(sbh)) { 7128c2ecf20Sopenharmony_ci ext4_msg(sbi->s_sb, KERN_ERR, "previous I/O error to " 7138c2ecf20Sopenharmony_ci "superblock detected"); 7148c2ecf20Sopenharmony_ci clear_buffer_write_io_error(sbh); 7158c2ecf20Sopenharmony_ci set_buffer_uptodate(sbh); 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (jbd2_journal_dirty_metadata(handle, sbh)) { 7198c2ecf20Sopenharmony_ci jbd2_journal_stop(handle); 7208c2ecf20Sopenharmony_ci goto write_directly; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci jbd2_journal_stop(handle); 7238c2ecf20Sopenharmony_ci return; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ciwrite_directly: 7268c2ecf20Sopenharmony_ci /* 7278c2ecf20Sopenharmony_ci * Write through journal failed. Write sb directly to get error info 7288c2ecf20Sopenharmony_ci * out and hope for the best. 7298c2ecf20Sopenharmony_ci */ 7308c2ecf20Sopenharmony_ci ext4_commit_super(sbi->s_sb); 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci#define ext4_error_ratelimit(sb) \ 7348c2ecf20Sopenharmony_ci ___ratelimit(&(EXT4_SB(sb)->s_err_ratelimit_state), \ 7358c2ecf20Sopenharmony_ci "EXT4-fs error") 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_civoid __ext4_error(struct super_block *sb, const char *function, 7388c2ecf20Sopenharmony_ci unsigned int line, bool force_ro, int error, __u64 block, 7398c2ecf20Sopenharmony_ci const char *fmt, ...) 7408c2ecf20Sopenharmony_ci{ 7418c2ecf20Sopenharmony_ci struct va_format vaf; 7428c2ecf20Sopenharmony_ci va_list args; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (unlikely(ext4_forced_shutdown(EXT4_SB(sb)))) 7458c2ecf20Sopenharmony_ci return; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci trace_ext4_error(sb, function, line); 7488c2ecf20Sopenharmony_ci if (ext4_error_ratelimit(sb)) { 7498c2ecf20Sopenharmony_ci va_start(args, fmt); 7508c2ecf20Sopenharmony_ci vaf.fmt = fmt; 7518c2ecf20Sopenharmony_ci vaf.va = &args; 7528c2ecf20Sopenharmony_ci printk(KERN_CRIT 7538c2ecf20Sopenharmony_ci "EXT4-fs error (device %s): %s:%d: comm %s: %pV\n", 7548c2ecf20Sopenharmony_ci sb->s_id, function, line, current->comm, &vaf); 7558c2ecf20Sopenharmony_ci va_end(args); 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci ext4_handle_error(sb, force_ro, error, 0, block, function, line); 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_civoid __ext4_error_inode(struct inode *inode, const char *function, 7618c2ecf20Sopenharmony_ci unsigned int line, ext4_fsblk_t block, int error, 7628c2ecf20Sopenharmony_ci const char *fmt, ...) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci va_list args; 7658c2ecf20Sopenharmony_ci struct va_format vaf; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) 7688c2ecf20Sopenharmony_ci return; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci trace_ext4_error(inode->i_sb, function, line); 7718c2ecf20Sopenharmony_ci if (ext4_error_ratelimit(inode->i_sb)) { 7728c2ecf20Sopenharmony_ci va_start(args, fmt); 7738c2ecf20Sopenharmony_ci vaf.fmt = fmt; 7748c2ecf20Sopenharmony_ci vaf.va = &args; 7758c2ecf20Sopenharmony_ci if (block) 7768c2ecf20Sopenharmony_ci printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: " 7778c2ecf20Sopenharmony_ci "inode #%lu: block %llu: comm %s: %pV\n", 7788c2ecf20Sopenharmony_ci inode->i_sb->s_id, function, line, inode->i_ino, 7798c2ecf20Sopenharmony_ci block, current->comm, &vaf); 7808c2ecf20Sopenharmony_ci else 7818c2ecf20Sopenharmony_ci printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: " 7828c2ecf20Sopenharmony_ci "inode #%lu: comm %s: %pV\n", 7838c2ecf20Sopenharmony_ci inode->i_sb->s_id, function, line, inode->i_ino, 7848c2ecf20Sopenharmony_ci current->comm, &vaf); 7858c2ecf20Sopenharmony_ci va_end(args); 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci ext4_handle_error(inode->i_sb, false, error, inode->i_ino, block, 7888c2ecf20Sopenharmony_ci function, line); 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_civoid __ext4_error_file(struct file *file, const char *function, 7928c2ecf20Sopenharmony_ci unsigned int line, ext4_fsblk_t block, 7938c2ecf20Sopenharmony_ci const char *fmt, ...) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci va_list args; 7968c2ecf20Sopenharmony_ci struct va_format vaf; 7978c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 7988c2ecf20Sopenharmony_ci char pathname[80], *path; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) 8018c2ecf20Sopenharmony_ci return; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci trace_ext4_error(inode->i_sb, function, line); 8048c2ecf20Sopenharmony_ci if (ext4_error_ratelimit(inode->i_sb)) { 8058c2ecf20Sopenharmony_ci path = file_path(file, pathname, sizeof(pathname)); 8068c2ecf20Sopenharmony_ci if (IS_ERR(path)) 8078c2ecf20Sopenharmony_ci path = "(unknown)"; 8088c2ecf20Sopenharmony_ci va_start(args, fmt); 8098c2ecf20Sopenharmony_ci vaf.fmt = fmt; 8108c2ecf20Sopenharmony_ci vaf.va = &args; 8118c2ecf20Sopenharmony_ci if (block) 8128c2ecf20Sopenharmony_ci printk(KERN_CRIT 8138c2ecf20Sopenharmony_ci "EXT4-fs error (device %s): %s:%d: inode #%lu: " 8148c2ecf20Sopenharmony_ci "block %llu: comm %s: path %s: %pV\n", 8158c2ecf20Sopenharmony_ci inode->i_sb->s_id, function, line, inode->i_ino, 8168c2ecf20Sopenharmony_ci block, current->comm, path, &vaf); 8178c2ecf20Sopenharmony_ci else 8188c2ecf20Sopenharmony_ci printk(KERN_CRIT 8198c2ecf20Sopenharmony_ci "EXT4-fs error (device %s): %s:%d: inode #%lu: " 8208c2ecf20Sopenharmony_ci "comm %s: path %s: %pV\n", 8218c2ecf20Sopenharmony_ci inode->i_sb->s_id, function, line, inode->i_ino, 8228c2ecf20Sopenharmony_ci current->comm, path, &vaf); 8238c2ecf20Sopenharmony_ci va_end(args); 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci ext4_handle_error(inode->i_sb, false, EFSCORRUPTED, inode->i_ino, block, 8268c2ecf20Sopenharmony_ci function, line); 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ciconst char *ext4_decode_error(struct super_block *sb, int errno, 8308c2ecf20Sopenharmony_ci char nbuf[16]) 8318c2ecf20Sopenharmony_ci{ 8328c2ecf20Sopenharmony_ci char *errstr = NULL; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci switch (errno) { 8358c2ecf20Sopenharmony_ci case -EFSCORRUPTED: 8368c2ecf20Sopenharmony_ci errstr = "Corrupt filesystem"; 8378c2ecf20Sopenharmony_ci break; 8388c2ecf20Sopenharmony_ci case -EFSBADCRC: 8398c2ecf20Sopenharmony_ci errstr = "Filesystem failed CRC"; 8408c2ecf20Sopenharmony_ci break; 8418c2ecf20Sopenharmony_ci case -EIO: 8428c2ecf20Sopenharmony_ci errstr = "IO failure"; 8438c2ecf20Sopenharmony_ci break; 8448c2ecf20Sopenharmony_ci case -ENOMEM: 8458c2ecf20Sopenharmony_ci errstr = "Out of memory"; 8468c2ecf20Sopenharmony_ci break; 8478c2ecf20Sopenharmony_ci case -EROFS: 8488c2ecf20Sopenharmony_ci if (!sb || (EXT4_SB(sb)->s_journal && 8498c2ecf20Sopenharmony_ci EXT4_SB(sb)->s_journal->j_flags & JBD2_ABORT)) 8508c2ecf20Sopenharmony_ci errstr = "Journal has aborted"; 8518c2ecf20Sopenharmony_ci else 8528c2ecf20Sopenharmony_ci errstr = "Readonly filesystem"; 8538c2ecf20Sopenharmony_ci break; 8548c2ecf20Sopenharmony_ci default: 8558c2ecf20Sopenharmony_ci /* If the caller passed in an extra buffer for unknown 8568c2ecf20Sopenharmony_ci * errors, textualise them now. Else we just return 8578c2ecf20Sopenharmony_ci * NULL. */ 8588c2ecf20Sopenharmony_ci if (nbuf) { 8598c2ecf20Sopenharmony_ci /* Check for truncated error codes... */ 8608c2ecf20Sopenharmony_ci if (snprintf(nbuf, 16, "error %d", -errno) >= 0) 8618c2ecf20Sopenharmony_ci errstr = nbuf; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci break; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci return errstr; 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci/* __ext4_std_error decodes expected errors from journaling functions 8708c2ecf20Sopenharmony_ci * automatically and invokes the appropriate error response. */ 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_civoid __ext4_std_error(struct super_block *sb, const char *function, 8738c2ecf20Sopenharmony_ci unsigned int line, int errno) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci char nbuf[16]; 8768c2ecf20Sopenharmony_ci const char *errstr; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (unlikely(ext4_forced_shutdown(EXT4_SB(sb)))) 8798c2ecf20Sopenharmony_ci return; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci /* Special case: if the error is EROFS, and we're not already 8828c2ecf20Sopenharmony_ci * inside a transaction, then there's really no point in logging 8838c2ecf20Sopenharmony_ci * an error. */ 8848c2ecf20Sopenharmony_ci if (errno == -EROFS && journal_current_handle() == NULL && sb_rdonly(sb)) 8858c2ecf20Sopenharmony_ci return; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci if (ext4_error_ratelimit(sb)) { 8888c2ecf20Sopenharmony_ci errstr = ext4_decode_error(sb, errno, nbuf); 8898c2ecf20Sopenharmony_ci printk(KERN_CRIT "EXT4-fs error (device %s) in %s:%d: %s\n", 8908c2ecf20Sopenharmony_ci sb->s_id, function, line, errstr); 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci ext4_handle_error(sb, false, -errno, 0, 0, function, line); 8948c2ecf20Sopenharmony_ci} 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_civoid __ext4_msg(struct super_block *sb, 8978c2ecf20Sopenharmony_ci const char *prefix, const char *fmt, ...) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci struct va_format vaf; 9008c2ecf20Sopenharmony_ci va_list args; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci atomic_inc(&EXT4_SB(sb)->s_msg_count); 9038c2ecf20Sopenharmony_ci if (!___ratelimit(&(EXT4_SB(sb)->s_msg_ratelimit_state), "EXT4-fs")) 9048c2ecf20Sopenharmony_ci return; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci va_start(args, fmt); 9078c2ecf20Sopenharmony_ci vaf.fmt = fmt; 9088c2ecf20Sopenharmony_ci vaf.va = &args; 9098c2ecf20Sopenharmony_ci printk("%sEXT4-fs (%s): %pV\n", prefix, sb->s_id, &vaf); 9108c2ecf20Sopenharmony_ci va_end(args); 9118c2ecf20Sopenharmony_ci} 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_cistatic int ext4_warning_ratelimit(struct super_block *sb) 9148c2ecf20Sopenharmony_ci{ 9158c2ecf20Sopenharmony_ci atomic_inc(&EXT4_SB(sb)->s_warning_count); 9168c2ecf20Sopenharmony_ci return ___ratelimit(&(EXT4_SB(sb)->s_warning_ratelimit_state), 9178c2ecf20Sopenharmony_ci "EXT4-fs warning"); 9188c2ecf20Sopenharmony_ci} 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_civoid __ext4_warning(struct super_block *sb, const char *function, 9218c2ecf20Sopenharmony_ci unsigned int line, const char *fmt, ...) 9228c2ecf20Sopenharmony_ci{ 9238c2ecf20Sopenharmony_ci struct va_format vaf; 9248c2ecf20Sopenharmony_ci va_list args; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci if (!ext4_warning_ratelimit(sb)) 9278c2ecf20Sopenharmony_ci return; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci va_start(args, fmt); 9308c2ecf20Sopenharmony_ci vaf.fmt = fmt; 9318c2ecf20Sopenharmony_ci vaf.va = &args; 9328c2ecf20Sopenharmony_ci printk(KERN_WARNING "EXT4-fs warning (device %s): %s:%d: %pV\n", 9338c2ecf20Sopenharmony_ci sb->s_id, function, line, &vaf); 9348c2ecf20Sopenharmony_ci va_end(args); 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_civoid __ext4_warning_inode(const struct inode *inode, const char *function, 9388c2ecf20Sopenharmony_ci unsigned int line, const char *fmt, ...) 9398c2ecf20Sopenharmony_ci{ 9408c2ecf20Sopenharmony_ci struct va_format vaf; 9418c2ecf20Sopenharmony_ci va_list args; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci if (!ext4_warning_ratelimit(inode->i_sb)) 9448c2ecf20Sopenharmony_ci return; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci va_start(args, fmt); 9478c2ecf20Sopenharmony_ci vaf.fmt = fmt; 9488c2ecf20Sopenharmony_ci vaf.va = &args; 9498c2ecf20Sopenharmony_ci printk(KERN_WARNING "EXT4-fs warning (device %s): %s:%d: " 9508c2ecf20Sopenharmony_ci "inode #%lu: comm %s: %pV\n", inode->i_sb->s_id, 9518c2ecf20Sopenharmony_ci function, line, inode->i_ino, current->comm, &vaf); 9528c2ecf20Sopenharmony_ci va_end(args); 9538c2ecf20Sopenharmony_ci} 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_civoid __ext4_grp_locked_error(const char *function, unsigned int line, 9568c2ecf20Sopenharmony_ci struct super_block *sb, ext4_group_t grp, 9578c2ecf20Sopenharmony_ci unsigned long ino, ext4_fsblk_t block, 9588c2ecf20Sopenharmony_ci const char *fmt, ...) 9598c2ecf20Sopenharmony_ci__releases(bitlock) 9608c2ecf20Sopenharmony_ci__acquires(bitlock) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci struct va_format vaf; 9638c2ecf20Sopenharmony_ci va_list args; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (unlikely(ext4_forced_shutdown(EXT4_SB(sb)))) 9668c2ecf20Sopenharmony_ci return; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci trace_ext4_error(sb, function, line); 9698c2ecf20Sopenharmony_ci if (ext4_error_ratelimit(sb)) { 9708c2ecf20Sopenharmony_ci va_start(args, fmt); 9718c2ecf20Sopenharmony_ci vaf.fmt = fmt; 9728c2ecf20Sopenharmony_ci vaf.va = &args; 9738c2ecf20Sopenharmony_ci printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: group %u, ", 9748c2ecf20Sopenharmony_ci sb->s_id, function, line, grp); 9758c2ecf20Sopenharmony_ci if (ino) 9768c2ecf20Sopenharmony_ci printk(KERN_CONT "inode %lu: ", ino); 9778c2ecf20Sopenharmony_ci if (block) 9788c2ecf20Sopenharmony_ci printk(KERN_CONT "block %llu:", 9798c2ecf20Sopenharmony_ci (unsigned long long) block); 9808c2ecf20Sopenharmony_ci printk(KERN_CONT "%pV\n", &vaf); 9818c2ecf20Sopenharmony_ci va_end(args); 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (test_opt(sb, ERRORS_CONT)) { 9858c2ecf20Sopenharmony_ci if (test_opt(sb, WARN_ON_ERROR)) 9868c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 9878c2ecf20Sopenharmony_ci EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; 9888c2ecf20Sopenharmony_ci if (!bdev_read_only(sb->s_bdev)) { 9898c2ecf20Sopenharmony_ci save_error_info(sb, EFSCORRUPTED, ino, block, function, 9908c2ecf20Sopenharmony_ci line); 9918c2ecf20Sopenharmony_ci schedule_work(&EXT4_SB(sb)->s_error_work); 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci return; 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci ext4_unlock_group(sb, grp); 9968c2ecf20Sopenharmony_ci ext4_handle_error(sb, false, EFSCORRUPTED, ino, block, function, line); 9978c2ecf20Sopenharmony_ci /* 9988c2ecf20Sopenharmony_ci * We only get here in the ERRORS_RO case; relocking the group 9998c2ecf20Sopenharmony_ci * may be dangerous, but nothing bad will happen since the 10008c2ecf20Sopenharmony_ci * filesystem will have already been marked read/only and the 10018c2ecf20Sopenharmony_ci * journal has been aborted. We return 1 as a hint to callers 10028c2ecf20Sopenharmony_ci * who might what to use the return value from 10038c2ecf20Sopenharmony_ci * ext4_grp_locked_error() to distinguish between the 10048c2ecf20Sopenharmony_ci * ERRORS_CONT and ERRORS_RO case, and perhaps return more 10058c2ecf20Sopenharmony_ci * aggressively from the ext4 function in question, with a 10068c2ecf20Sopenharmony_ci * more appropriate error code. 10078c2ecf20Sopenharmony_ci */ 10088c2ecf20Sopenharmony_ci ext4_lock_group(sb, grp); 10098c2ecf20Sopenharmony_ci return; 10108c2ecf20Sopenharmony_ci} 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_civoid ext4_mark_group_bitmap_corrupted(struct super_block *sb, 10138c2ecf20Sopenharmony_ci ext4_group_t group, 10148c2ecf20Sopenharmony_ci unsigned int flags) 10158c2ecf20Sopenharmony_ci{ 10168c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 10178c2ecf20Sopenharmony_ci struct ext4_group_info *grp = ext4_get_group_info(sb, group); 10188c2ecf20Sopenharmony_ci struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL); 10198c2ecf20Sopenharmony_ci int ret; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci if (!grp || !gdp) 10228c2ecf20Sopenharmony_ci return; 10238c2ecf20Sopenharmony_ci if (flags & EXT4_GROUP_INFO_BBITMAP_CORRUPT) { 10248c2ecf20Sopenharmony_ci ret = ext4_test_and_set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, 10258c2ecf20Sopenharmony_ci &grp->bb_state); 10268c2ecf20Sopenharmony_ci if (!ret) 10278c2ecf20Sopenharmony_ci percpu_counter_sub(&sbi->s_freeclusters_counter, 10288c2ecf20Sopenharmony_ci grp->bb_free); 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (flags & EXT4_GROUP_INFO_IBITMAP_CORRUPT) { 10328c2ecf20Sopenharmony_ci ret = ext4_test_and_set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, 10338c2ecf20Sopenharmony_ci &grp->bb_state); 10348c2ecf20Sopenharmony_ci if (!ret && gdp) { 10358c2ecf20Sopenharmony_ci int count; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci count = ext4_free_inodes_count(sb, gdp); 10388c2ecf20Sopenharmony_ci percpu_counter_sub(&sbi->s_freeinodes_counter, 10398c2ecf20Sopenharmony_ci count); 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci} 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_civoid ext4_update_dynamic_rev(struct super_block *sb) 10458c2ecf20Sopenharmony_ci{ 10468c2ecf20Sopenharmony_ci struct ext4_super_block *es = EXT4_SB(sb)->s_es; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci if (le32_to_cpu(es->s_rev_level) > EXT4_GOOD_OLD_REV) 10498c2ecf20Sopenharmony_ci return; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci ext4_warning(sb, 10528c2ecf20Sopenharmony_ci "updating to rev %d because of new feature flag, " 10538c2ecf20Sopenharmony_ci "running e2fsck is recommended", 10548c2ecf20Sopenharmony_ci EXT4_DYNAMIC_REV); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci es->s_first_ino = cpu_to_le32(EXT4_GOOD_OLD_FIRST_INO); 10578c2ecf20Sopenharmony_ci es->s_inode_size = cpu_to_le16(EXT4_GOOD_OLD_INODE_SIZE); 10588c2ecf20Sopenharmony_ci es->s_rev_level = cpu_to_le32(EXT4_DYNAMIC_REV); 10598c2ecf20Sopenharmony_ci /* leave es->s_feature_*compat flags alone */ 10608c2ecf20Sopenharmony_ci /* es->s_uuid will be set by e2fsck if empty */ 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci /* 10638c2ecf20Sopenharmony_ci * The rest of the superblock fields should be zero, and if not it 10648c2ecf20Sopenharmony_ci * means they are likely already in use, so leave them alone. We 10658c2ecf20Sopenharmony_ci * can leave it up to e2fsck to clean up any inconsistencies there. 10668c2ecf20Sopenharmony_ci */ 10678c2ecf20Sopenharmony_ci} 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci/* 10708c2ecf20Sopenharmony_ci * Open the external journal device 10718c2ecf20Sopenharmony_ci */ 10728c2ecf20Sopenharmony_cistatic struct block_device *ext4_blkdev_get(dev_t dev, struct super_block *sb) 10738c2ecf20Sopenharmony_ci{ 10748c2ecf20Sopenharmony_ci struct block_device *bdev; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb); 10778c2ecf20Sopenharmony_ci if (IS_ERR(bdev)) 10788c2ecf20Sopenharmony_ci goto fail; 10798c2ecf20Sopenharmony_ci return bdev; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_cifail: 10828c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 10838c2ecf20Sopenharmony_ci "failed to open journal device unknown-block(%u,%u) %ld", 10848c2ecf20Sopenharmony_ci MAJOR(dev), MINOR(dev), PTR_ERR(bdev)); 10858c2ecf20Sopenharmony_ci return NULL; 10868c2ecf20Sopenharmony_ci} 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci/* 10898c2ecf20Sopenharmony_ci * Release the journal device 10908c2ecf20Sopenharmony_ci */ 10918c2ecf20Sopenharmony_cistatic void ext4_blkdev_put(struct block_device *bdev) 10928c2ecf20Sopenharmony_ci{ 10938c2ecf20Sopenharmony_ci blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); 10948c2ecf20Sopenharmony_ci} 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_cistatic void ext4_blkdev_remove(struct ext4_sb_info *sbi) 10978c2ecf20Sopenharmony_ci{ 10988c2ecf20Sopenharmony_ci struct block_device *bdev; 10998c2ecf20Sopenharmony_ci bdev = sbi->s_journal_bdev; 11008c2ecf20Sopenharmony_ci if (bdev) { 11018c2ecf20Sopenharmony_ci /* 11028c2ecf20Sopenharmony_ci * Invalidate the journal device's buffers. We don't want them 11038c2ecf20Sopenharmony_ci * floating about in memory - the physical journal device may 11048c2ecf20Sopenharmony_ci * hotswapped, and it breaks the `ro-after' testing code. 11058c2ecf20Sopenharmony_ci */ 11068c2ecf20Sopenharmony_ci invalidate_bdev(bdev); 11078c2ecf20Sopenharmony_ci ext4_blkdev_put(bdev); 11088c2ecf20Sopenharmony_ci sbi->s_journal_bdev = NULL; 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci} 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_cistatic inline struct inode *orphan_list_entry(struct list_head *l) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci return &list_entry(l, struct ext4_inode_info, i_orphan)->vfs_inode; 11158c2ecf20Sopenharmony_ci} 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_cistatic void dump_orphan_list(struct super_block *sb, struct ext4_sb_info *sbi) 11188c2ecf20Sopenharmony_ci{ 11198c2ecf20Sopenharmony_ci struct list_head *l; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "sb orphan head is %d", 11228c2ecf20Sopenharmony_ci le32_to_cpu(sbi->s_es->s_last_orphan)); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci printk(KERN_ERR "sb_info orphan list:\n"); 11258c2ecf20Sopenharmony_ci list_for_each(l, &sbi->s_orphan) { 11268c2ecf20Sopenharmony_ci struct inode *inode = orphan_list_entry(l); 11278c2ecf20Sopenharmony_ci printk(KERN_ERR " " 11288c2ecf20Sopenharmony_ci "inode %s:%lu at %p: mode %o, nlink %d, next %d\n", 11298c2ecf20Sopenharmony_ci inode->i_sb->s_id, inode->i_ino, inode, 11308c2ecf20Sopenharmony_ci inode->i_mode, inode->i_nlink, 11318c2ecf20Sopenharmony_ci NEXT_ORPHAN(inode)); 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci} 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 11368c2ecf20Sopenharmony_cistatic int ext4_quota_off(struct super_block *sb, int type); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_cistatic inline void ext4_quota_off_umount(struct super_block *sb) 11398c2ecf20Sopenharmony_ci{ 11408c2ecf20Sopenharmony_ci int type; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci /* Use our quota_off function to clear inode flags etc. */ 11438c2ecf20Sopenharmony_ci for (type = 0; type < EXT4_MAXQUOTAS; type++) 11448c2ecf20Sopenharmony_ci ext4_quota_off(sb, type); 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci/* 11488c2ecf20Sopenharmony_ci * This is a helper function which is used in the mount/remount 11498c2ecf20Sopenharmony_ci * codepaths (which holds s_umount) to fetch the quota file name. 11508c2ecf20Sopenharmony_ci */ 11518c2ecf20Sopenharmony_cistatic inline char *get_qf_name(struct super_block *sb, 11528c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi, 11538c2ecf20Sopenharmony_ci int type) 11548c2ecf20Sopenharmony_ci{ 11558c2ecf20Sopenharmony_ci return rcu_dereference_protected(sbi->s_qf_names[type], 11568c2ecf20Sopenharmony_ci lockdep_is_held(&sb->s_umount)); 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci#else 11598c2ecf20Sopenharmony_cistatic inline void ext4_quota_off_umount(struct super_block *sb) 11608c2ecf20Sopenharmony_ci{ 11618c2ecf20Sopenharmony_ci} 11628c2ecf20Sopenharmony_ci#endif 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_cistatic void ext4_put_super(struct super_block *sb) 11658c2ecf20Sopenharmony_ci{ 11668c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 11678c2ecf20Sopenharmony_ci struct ext4_super_block *es = sbi->s_es; 11688c2ecf20Sopenharmony_ci struct buffer_head **group_desc; 11698c2ecf20Sopenharmony_ci struct flex_groups **flex_groups; 11708c2ecf20Sopenharmony_ci int aborted = 0; 11718c2ecf20Sopenharmony_ci int i, err; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci /* 11748c2ecf20Sopenharmony_ci * Unregister sysfs before destroying jbd2 journal. 11758c2ecf20Sopenharmony_ci * Since we could still access attr_journal_task attribute via sysfs 11768c2ecf20Sopenharmony_ci * path which could have sbi->s_journal->j_task as NULL 11778c2ecf20Sopenharmony_ci * Unregister sysfs before flush sbi->s_error_work. 11788c2ecf20Sopenharmony_ci * Since user may read /proc/fs/ext4/xx/mb_groups during umount, If 11798c2ecf20Sopenharmony_ci * read metadata verify failed then will queue error work. 11808c2ecf20Sopenharmony_ci * flush_stashed_error_work will call start_this_handle may trigger 11818c2ecf20Sopenharmony_ci * BUG_ON. 11828c2ecf20Sopenharmony_ci */ 11838c2ecf20Sopenharmony_ci ext4_unregister_sysfs(sb); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci ext4_unregister_li_request(sb); 11868c2ecf20Sopenharmony_ci ext4_quota_off_umount(sb); 11878c2ecf20Sopenharmony_ci flush_work(&sbi->s_error_work); 11888c2ecf20Sopenharmony_ci destroy_workqueue(sbi->rsv_conversion_wq); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci if (sbi->s_journal) { 11918c2ecf20Sopenharmony_ci aborted = is_journal_aborted(sbi->s_journal); 11928c2ecf20Sopenharmony_ci err = jbd2_journal_destroy(sbi->s_journal); 11938c2ecf20Sopenharmony_ci sbi->s_journal = NULL; 11948c2ecf20Sopenharmony_ci if ((err < 0) && !aborted) { 11958c2ecf20Sopenharmony_ci ext4_abort(sb, -err, "Couldn't clean up the journal"); 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci } 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci ext4_es_unregister_shrinker(sbi); 12008c2ecf20Sopenharmony_ci del_timer_sync(&sbi->s_err_report); 12018c2ecf20Sopenharmony_ci ext4_release_system_zone(sb); 12028c2ecf20Sopenharmony_ci ext4_mb_release(sb); 12038c2ecf20Sopenharmony_ci ext4_ext_release(sb); 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci if (!sb_rdonly(sb) && !aborted) { 12068c2ecf20Sopenharmony_ci ext4_clear_feature_journal_needs_recovery(sb); 12078c2ecf20Sopenharmony_ci es->s_state = cpu_to_le16(sbi->s_mount_state); 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) 12108c2ecf20Sopenharmony_ci ext4_commit_super(sb); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci rcu_read_lock(); 12138c2ecf20Sopenharmony_ci group_desc = rcu_dereference(sbi->s_group_desc); 12148c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_gdb_count; i++) 12158c2ecf20Sopenharmony_ci brelse(group_desc[i]); 12168c2ecf20Sopenharmony_ci kvfree(group_desc); 12178c2ecf20Sopenharmony_ci flex_groups = rcu_dereference(sbi->s_flex_groups); 12188c2ecf20Sopenharmony_ci if (flex_groups) { 12198c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_flex_groups_allocated; i++) 12208c2ecf20Sopenharmony_ci kvfree(flex_groups[i]); 12218c2ecf20Sopenharmony_ci kvfree(flex_groups); 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci rcu_read_unlock(); 12248c2ecf20Sopenharmony_ci percpu_counter_destroy(&sbi->s_freeclusters_counter); 12258c2ecf20Sopenharmony_ci percpu_counter_destroy(&sbi->s_freeinodes_counter); 12268c2ecf20Sopenharmony_ci percpu_counter_destroy(&sbi->s_dirs_counter); 12278c2ecf20Sopenharmony_ci percpu_counter_destroy(&sbi->s_dirtyclusters_counter); 12288c2ecf20Sopenharmony_ci percpu_counter_destroy(&sbi->s_sra_exceeded_retry_limit); 12298c2ecf20Sopenharmony_ci percpu_free_rwsem(&sbi->s_writepages_rwsem); 12308c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 12318c2ecf20Sopenharmony_ci for (i = 0; i < EXT4_MAXQUOTAS; i++) 12328c2ecf20Sopenharmony_ci kfree(get_qf_name(sb, sbi, i)); 12338c2ecf20Sopenharmony_ci#endif 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci /* Debugging code just in case the in-memory inode orphan list 12368c2ecf20Sopenharmony_ci * isn't empty. The on-disk one can be non-empty if we've 12378c2ecf20Sopenharmony_ci * detected an error and taken the fs readonly, but the 12388c2ecf20Sopenharmony_ci * in-memory list had better be clean by this point. */ 12398c2ecf20Sopenharmony_ci if (!list_empty(&sbi->s_orphan)) 12408c2ecf20Sopenharmony_ci dump_orphan_list(sb, sbi); 12418c2ecf20Sopenharmony_ci J_ASSERT(list_empty(&sbi->s_orphan)); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci sync_blockdev(sb->s_bdev); 12448c2ecf20Sopenharmony_ci invalidate_bdev(sb->s_bdev); 12458c2ecf20Sopenharmony_ci if (sbi->s_journal_bdev && sbi->s_journal_bdev != sb->s_bdev) { 12468c2ecf20Sopenharmony_ci sync_blockdev(sbi->s_journal_bdev); 12478c2ecf20Sopenharmony_ci ext4_blkdev_remove(sbi); 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci ext4_xattr_destroy_cache(sbi->s_ea_inode_cache); 12518c2ecf20Sopenharmony_ci sbi->s_ea_inode_cache = NULL; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci ext4_xattr_destroy_cache(sbi->s_ea_block_cache); 12548c2ecf20Sopenharmony_ci sbi->s_ea_block_cache = NULL; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci ext4_stop_mmpd(sbi); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci brelse(sbi->s_sbh); 12598c2ecf20Sopenharmony_ci sb->s_fs_info = NULL; 12608c2ecf20Sopenharmony_ci /* 12618c2ecf20Sopenharmony_ci * Now that we are completely done shutting down the 12628c2ecf20Sopenharmony_ci * superblock, we need to actually destroy the kobject. 12638c2ecf20Sopenharmony_ci */ 12648c2ecf20Sopenharmony_ci kobject_put(&sbi->s_kobj); 12658c2ecf20Sopenharmony_ci wait_for_completion(&sbi->s_kobj_unregister); 12668c2ecf20Sopenharmony_ci if (sbi->s_chksum_driver) 12678c2ecf20Sopenharmony_ci crypto_free_shash(sbi->s_chksum_driver); 12688c2ecf20Sopenharmony_ci kfree(sbi->s_blockgroup_lock); 12698c2ecf20Sopenharmony_ci fs_put_dax(sbi->s_daxdev); 12708c2ecf20Sopenharmony_ci fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy); 12718c2ecf20Sopenharmony_ci#ifdef CONFIG_UNICODE 12728c2ecf20Sopenharmony_ci utf8_unload(sb->s_encoding); 12738c2ecf20Sopenharmony_ci#endif 12748c2ecf20Sopenharmony_ci kfree(sbi); 12758c2ecf20Sopenharmony_ci} 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_cistatic struct kmem_cache *ext4_inode_cachep; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci/* 12808c2ecf20Sopenharmony_ci * Called inside transaction, so use GFP_NOFS 12818c2ecf20Sopenharmony_ci */ 12828c2ecf20Sopenharmony_cistatic struct inode *ext4_alloc_inode(struct super_block *sb) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci struct ext4_inode_info *ei; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci ei = kmem_cache_alloc(ext4_inode_cachep, GFP_NOFS); 12878c2ecf20Sopenharmony_ci if (!ei) 12888c2ecf20Sopenharmony_ci return NULL; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci inode_set_iversion(&ei->vfs_inode, 1); 12918c2ecf20Sopenharmony_ci ei->i_flags = 0; 12928c2ecf20Sopenharmony_ci spin_lock_init(&ei->i_raw_lock); 12938c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ei->i_prealloc_list); 12948c2ecf20Sopenharmony_ci atomic_set(&ei->i_prealloc_active, 0); 12958c2ecf20Sopenharmony_ci spin_lock_init(&ei->i_prealloc_lock); 12968c2ecf20Sopenharmony_ci ext4_es_init_tree(&ei->i_es_tree); 12978c2ecf20Sopenharmony_ci rwlock_init(&ei->i_es_lock); 12988c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ei->i_es_list); 12998c2ecf20Sopenharmony_ci ei->i_es_all_nr = 0; 13008c2ecf20Sopenharmony_ci ei->i_es_shk_nr = 0; 13018c2ecf20Sopenharmony_ci ei->i_es_shrink_lblk = 0; 13028c2ecf20Sopenharmony_ci ei->i_reserved_data_blocks = 0; 13038c2ecf20Sopenharmony_ci spin_lock_init(&(ei->i_block_reservation_lock)); 13048c2ecf20Sopenharmony_ci ext4_init_pending_tree(&ei->i_pending_tree); 13058c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 13068c2ecf20Sopenharmony_ci ei->i_reserved_quota = 0; 13078c2ecf20Sopenharmony_ci memset(&ei->i_dquot, 0, sizeof(ei->i_dquot)); 13088c2ecf20Sopenharmony_ci#endif 13098c2ecf20Sopenharmony_ci ei->jinode = NULL; 13108c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ei->i_rsv_conversion_list); 13118c2ecf20Sopenharmony_ci spin_lock_init(&ei->i_completed_io_lock); 13128c2ecf20Sopenharmony_ci ei->i_sync_tid = 0; 13138c2ecf20Sopenharmony_ci ei->i_datasync_tid = 0; 13148c2ecf20Sopenharmony_ci atomic_set(&ei->i_unwritten, 0); 13158c2ecf20Sopenharmony_ci INIT_WORK(&ei->i_rsv_conversion_work, ext4_end_io_rsv_work); 13168c2ecf20Sopenharmony_ci ext4_fc_init_inode(&ei->vfs_inode); 13178c2ecf20Sopenharmony_ci mutex_init(&ei->i_fc_lock); 13188c2ecf20Sopenharmony_ci return &ei->vfs_inode; 13198c2ecf20Sopenharmony_ci} 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_cistatic int ext4_drop_inode(struct inode *inode) 13228c2ecf20Sopenharmony_ci{ 13238c2ecf20Sopenharmony_ci int drop = generic_drop_inode(inode); 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci if (!drop) 13268c2ecf20Sopenharmony_ci drop = fscrypt_drop_inode(inode); 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci trace_ext4_drop_inode(inode, drop); 13298c2ecf20Sopenharmony_ci return drop; 13308c2ecf20Sopenharmony_ci} 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_cistatic void ext4_free_in_core_inode(struct inode *inode) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci fscrypt_free_inode(inode); 13358c2ecf20Sopenharmony_ci if (!list_empty(&(EXT4_I(inode)->i_fc_list))) { 13368c2ecf20Sopenharmony_ci pr_warn("%s: inode %ld still in fc list", 13378c2ecf20Sopenharmony_ci __func__, inode->i_ino); 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci kmem_cache_free(ext4_inode_cachep, EXT4_I(inode)); 13408c2ecf20Sopenharmony_ci} 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_cistatic void ext4_destroy_inode(struct inode *inode) 13438c2ecf20Sopenharmony_ci{ 13448c2ecf20Sopenharmony_ci if (!list_empty(&(EXT4_I(inode)->i_orphan))) { 13458c2ecf20Sopenharmony_ci ext4_msg(inode->i_sb, KERN_ERR, 13468c2ecf20Sopenharmony_ci "Inode %lu (%p): orphan list check failed!", 13478c2ecf20Sopenharmony_ci inode->i_ino, EXT4_I(inode)); 13488c2ecf20Sopenharmony_ci print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 4, 13498c2ecf20Sopenharmony_ci EXT4_I(inode), sizeof(struct ext4_inode_info), 13508c2ecf20Sopenharmony_ci true); 13518c2ecf20Sopenharmony_ci dump_stack(); 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci if (EXT4_I(inode)->i_reserved_data_blocks) 13558c2ecf20Sopenharmony_ci ext4_msg(inode->i_sb, KERN_ERR, 13568c2ecf20Sopenharmony_ci "Inode %lu (%p): i_reserved_data_blocks (%u) not cleared!", 13578c2ecf20Sopenharmony_ci inode->i_ino, EXT4_I(inode), 13588c2ecf20Sopenharmony_ci EXT4_I(inode)->i_reserved_data_blocks); 13598c2ecf20Sopenharmony_ci} 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_cistatic void init_once(void *foo) 13628c2ecf20Sopenharmony_ci{ 13638c2ecf20Sopenharmony_ci struct ext4_inode_info *ei = (struct ext4_inode_info *) foo; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ei->i_orphan); 13668c2ecf20Sopenharmony_ci init_rwsem(&ei->xattr_sem); 13678c2ecf20Sopenharmony_ci init_rwsem(&ei->i_data_sem); 13688c2ecf20Sopenharmony_ci init_rwsem(&ei->i_mmap_sem); 13698c2ecf20Sopenharmony_ci inode_init_once(&ei->vfs_inode); 13708c2ecf20Sopenharmony_ci ext4_fc_init_inode(&ei->vfs_inode); 13718c2ecf20Sopenharmony_ci} 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_cistatic int __init init_inodecache(void) 13748c2ecf20Sopenharmony_ci{ 13758c2ecf20Sopenharmony_ci ext4_inode_cachep = kmem_cache_create_usercopy("ext4_inode_cache", 13768c2ecf20Sopenharmony_ci sizeof(struct ext4_inode_info), 0, 13778c2ecf20Sopenharmony_ci (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD| 13788c2ecf20Sopenharmony_ci SLAB_ACCOUNT), 13798c2ecf20Sopenharmony_ci offsetof(struct ext4_inode_info, i_data), 13808c2ecf20Sopenharmony_ci sizeof_field(struct ext4_inode_info, i_data), 13818c2ecf20Sopenharmony_ci init_once); 13828c2ecf20Sopenharmony_ci if (ext4_inode_cachep == NULL) 13838c2ecf20Sopenharmony_ci return -ENOMEM; 13848c2ecf20Sopenharmony_ci return 0; 13858c2ecf20Sopenharmony_ci} 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_cistatic void destroy_inodecache(void) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci /* 13908c2ecf20Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 13918c2ecf20Sopenharmony_ci * destroy cache. 13928c2ecf20Sopenharmony_ci */ 13938c2ecf20Sopenharmony_ci rcu_barrier(); 13948c2ecf20Sopenharmony_ci kmem_cache_destroy(ext4_inode_cachep); 13958c2ecf20Sopenharmony_ci} 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_civoid ext4_clear_inode(struct inode *inode) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci ext4_fc_del(inode); 14008c2ecf20Sopenharmony_ci invalidate_inode_buffers(inode); 14018c2ecf20Sopenharmony_ci clear_inode(inode); 14028c2ecf20Sopenharmony_ci ext4_discard_preallocations(inode, 0); 14038c2ecf20Sopenharmony_ci ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS); 14048c2ecf20Sopenharmony_ci dquot_drop(inode); 14058c2ecf20Sopenharmony_ci if (EXT4_I(inode)->jinode) { 14068c2ecf20Sopenharmony_ci jbd2_journal_release_jbd_inode(EXT4_JOURNAL(inode), 14078c2ecf20Sopenharmony_ci EXT4_I(inode)->jinode); 14088c2ecf20Sopenharmony_ci jbd2_free_inode(EXT4_I(inode)->jinode); 14098c2ecf20Sopenharmony_ci EXT4_I(inode)->jinode = NULL; 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci fscrypt_put_encryption_info(inode); 14128c2ecf20Sopenharmony_ci fsverity_cleanup_inode(inode); 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_cistatic struct inode *ext4_nfs_get_inode(struct super_block *sb, 14168c2ecf20Sopenharmony_ci u64 ino, u32 generation) 14178c2ecf20Sopenharmony_ci{ 14188c2ecf20Sopenharmony_ci struct inode *inode; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci /* 14218c2ecf20Sopenharmony_ci * Currently we don't know the generation for parent directory, so 14228c2ecf20Sopenharmony_ci * a generation of 0 means "accept any" 14238c2ecf20Sopenharmony_ci */ 14248c2ecf20Sopenharmony_ci inode = ext4_iget(sb, ino, EXT4_IGET_HANDLE); 14258c2ecf20Sopenharmony_ci if (IS_ERR(inode)) 14268c2ecf20Sopenharmony_ci return ERR_CAST(inode); 14278c2ecf20Sopenharmony_ci if (generation && inode->i_generation != generation) { 14288c2ecf20Sopenharmony_ci iput(inode); 14298c2ecf20Sopenharmony_ci return ERR_PTR(-ESTALE); 14308c2ecf20Sopenharmony_ci } 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci return inode; 14338c2ecf20Sopenharmony_ci} 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_cistatic struct dentry *ext4_fh_to_dentry(struct super_block *sb, struct fid *fid, 14368c2ecf20Sopenharmony_ci int fh_len, int fh_type) 14378c2ecf20Sopenharmony_ci{ 14388c2ecf20Sopenharmony_ci return generic_fh_to_dentry(sb, fid, fh_len, fh_type, 14398c2ecf20Sopenharmony_ci ext4_nfs_get_inode); 14408c2ecf20Sopenharmony_ci} 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_cistatic struct dentry *ext4_fh_to_parent(struct super_block *sb, struct fid *fid, 14438c2ecf20Sopenharmony_ci int fh_len, int fh_type) 14448c2ecf20Sopenharmony_ci{ 14458c2ecf20Sopenharmony_ci return generic_fh_to_parent(sb, fid, fh_len, fh_type, 14468c2ecf20Sopenharmony_ci ext4_nfs_get_inode); 14478c2ecf20Sopenharmony_ci} 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_cistatic int ext4_nfs_commit_metadata(struct inode *inode) 14508c2ecf20Sopenharmony_ci{ 14518c2ecf20Sopenharmony_ci struct writeback_control wbc = { 14528c2ecf20Sopenharmony_ci .sync_mode = WB_SYNC_ALL 14538c2ecf20Sopenharmony_ci }; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci trace_ext4_nfs_commit_metadata(inode); 14568c2ecf20Sopenharmony_ci return ext4_write_inode(inode, &wbc); 14578c2ecf20Sopenharmony_ci} 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION 14608c2ecf20Sopenharmony_cistatic int ext4_get_context(struct inode *inode, void *ctx, size_t len) 14618c2ecf20Sopenharmony_ci{ 14628c2ecf20Sopenharmony_ci return ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION, 14638c2ecf20Sopenharmony_ci EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx, len); 14648c2ecf20Sopenharmony_ci} 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_cistatic int ext4_set_context(struct inode *inode, const void *ctx, size_t len, 14678c2ecf20Sopenharmony_ci void *fs_data) 14688c2ecf20Sopenharmony_ci{ 14698c2ecf20Sopenharmony_ci handle_t *handle = fs_data; 14708c2ecf20Sopenharmony_ci int res, res2, credits, retries = 0; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci /* 14738c2ecf20Sopenharmony_ci * Encrypting the root directory is not allowed because e2fsck expects 14748c2ecf20Sopenharmony_ci * lost+found to exist and be unencrypted, and encrypting the root 14758c2ecf20Sopenharmony_ci * directory would imply encrypting the lost+found directory as well as 14768c2ecf20Sopenharmony_ci * the filename "lost+found" itself. 14778c2ecf20Sopenharmony_ci */ 14788c2ecf20Sopenharmony_ci if (inode->i_ino == EXT4_ROOT_INO) 14798c2ecf20Sopenharmony_ci return -EPERM; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(IS_DAX(inode) && i_size_read(inode))) 14828c2ecf20Sopenharmony_ci return -EINVAL; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci if (ext4_test_inode_flag(inode, EXT4_INODE_DAX)) 14858c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci res = ext4_convert_inline_data(inode); 14888c2ecf20Sopenharmony_ci if (res) 14898c2ecf20Sopenharmony_ci return res; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci /* 14928c2ecf20Sopenharmony_ci * If a journal handle was specified, then the encryption context is 14938c2ecf20Sopenharmony_ci * being set on a new inode via inheritance and is part of a larger 14948c2ecf20Sopenharmony_ci * transaction to create the inode. Otherwise the encryption context is 14958c2ecf20Sopenharmony_ci * being set on an existing inode in its own transaction. Only in the 14968c2ecf20Sopenharmony_ci * latter case should the "retry on ENOSPC" logic be used. 14978c2ecf20Sopenharmony_ci */ 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci if (handle) { 15008c2ecf20Sopenharmony_ci res = ext4_xattr_set_handle(handle, inode, 15018c2ecf20Sopenharmony_ci EXT4_XATTR_INDEX_ENCRYPTION, 15028c2ecf20Sopenharmony_ci EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, 15038c2ecf20Sopenharmony_ci ctx, len, 0); 15048c2ecf20Sopenharmony_ci if (!res) { 15058c2ecf20Sopenharmony_ci ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT); 15068c2ecf20Sopenharmony_ci ext4_clear_inode_state(inode, 15078c2ecf20Sopenharmony_ci EXT4_STATE_MAY_INLINE_DATA); 15088c2ecf20Sopenharmony_ci /* 15098c2ecf20Sopenharmony_ci * Update inode->i_flags - S_ENCRYPTED will be enabled, 15108c2ecf20Sopenharmony_ci * S_DAX may be disabled 15118c2ecf20Sopenharmony_ci */ 15128c2ecf20Sopenharmony_ci ext4_set_inode_flags(inode, false); 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci return res; 15158c2ecf20Sopenharmony_ci } 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci res = dquot_initialize(inode); 15188c2ecf20Sopenharmony_ci if (res) 15198c2ecf20Sopenharmony_ci return res; 15208c2ecf20Sopenharmony_ciretry: 15218c2ecf20Sopenharmony_ci res = ext4_xattr_set_credits(inode, len, false /* is_create */, 15228c2ecf20Sopenharmony_ci &credits); 15238c2ecf20Sopenharmony_ci if (res) 15248c2ecf20Sopenharmony_ci return res; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci handle = ext4_journal_start(inode, EXT4_HT_MISC, credits); 15278c2ecf20Sopenharmony_ci if (IS_ERR(handle)) 15288c2ecf20Sopenharmony_ci return PTR_ERR(handle); 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci res = ext4_xattr_set_handle(handle, inode, EXT4_XATTR_INDEX_ENCRYPTION, 15318c2ecf20Sopenharmony_ci EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, 15328c2ecf20Sopenharmony_ci ctx, len, 0); 15338c2ecf20Sopenharmony_ci if (!res) { 15348c2ecf20Sopenharmony_ci ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT); 15358c2ecf20Sopenharmony_ci /* 15368c2ecf20Sopenharmony_ci * Update inode->i_flags - S_ENCRYPTED will be enabled, 15378c2ecf20Sopenharmony_ci * S_DAX may be disabled 15388c2ecf20Sopenharmony_ci */ 15398c2ecf20Sopenharmony_ci ext4_set_inode_flags(inode, false); 15408c2ecf20Sopenharmony_ci res = ext4_mark_inode_dirty(handle, inode); 15418c2ecf20Sopenharmony_ci if (res) 15428c2ecf20Sopenharmony_ci EXT4_ERROR_INODE(inode, "Failed to mark inode dirty"); 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci res2 = ext4_journal_stop(handle); 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci if (res == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) 15478c2ecf20Sopenharmony_ci goto retry; 15488c2ecf20Sopenharmony_ci if (!res) 15498c2ecf20Sopenharmony_ci res = res2; 15508c2ecf20Sopenharmony_ci return res; 15518c2ecf20Sopenharmony_ci} 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_cistatic const union fscrypt_policy *ext4_get_dummy_policy(struct super_block *sb) 15548c2ecf20Sopenharmony_ci{ 15558c2ecf20Sopenharmony_ci return EXT4_SB(sb)->s_dummy_enc_policy.policy; 15568c2ecf20Sopenharmony_ci} 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_cistatic bool ext4_has_stable_inodes(struct super_block *sb) 15598c2ecf20Sopenharmony_ci{ 15608c2ecf20Sopenharmony_ci return ext4_has_feature_stable_inodes(sb); 15618c2ecf20Sopenharmony_ci} 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_cistatic void ext4_get_ino_and_lblk_bits(struct super_block *sb, 15648c2ecf20Sopenharmony_ci int *ino_bits_ret, int *lblk_bits_ret) 15658c2ecf20Sopenharmony_ci{ 15668c2ecf20Sopenharmony_ci *ino_bits_ret = 8 * sizeof(EXT4_SB(sb)->s_es->s_inodes_count); 15678c2ecf20Sopenharmony_ci *lblk_bits_ret = 8 * sizeof(ext4_lblk_t); 15688c2ecf20Sopenharmony_ci} 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_cistatic const struct fscrypt_operations ext4_cryptops = { 15718c2ecf20Sopenharmony_ci .key_prefix = "ext4:", 15728c2ecf20Sopenharmony_ci .get_context = ext4_get_context, 15738c2ecf20Sopenharmony_ci .set_context = ext4_set_context, 15748c2ecf20Sopenharmony_ci .get_dummy_policy = ext4_get_dummy_policy, 15758c2ecf20Sopenharmony_ci .empty_dir = ext4_empty_dir, 15768c2ecf20Sopenharmony_ci .max_namelen = EXT4_NAME_LEN, 15778c2ecf20Sopenharmony_ci .has_stable_inodes = ext4_has_stable_inodes, 15788c2ecf20Sopenharmony_ci .get_ino_and_lblk_bits = ext4_get_ino_and_lblk_bits, 15798c2ecf20Sopenharmony_ci}; 15808c2ecf20Sopenharmony_ci#endif 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 15838c2ecf20Sopenharmony_cistatic const char * const quotatypes[] = INITQFNAMES; 15848c2ecf20Sopenharmony_ci#define QTYPE2NAME(t) (quotatypes[t]) 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_cistatic int ext4_write_dquot(struct dquot *dquot); 15878c2ecf20Sopenharmony_cistatic int ext4_acquire_dquot(struct dquot *dquot); 15888c2ecf20Sopenharmony_cistatic int ext4_release_dquot(struct dquot *dquot); 15898c2ecf20Sopenharmony_cistatic int ext4_mark_dquot_dirty(struct dquot *dquot); 15908c2ecf20Sopenharmony_cistatic int ext4_write_info(struct super_block *sb, int type); 15918c2ecf20Sopenharmony_cistatic int ext4_quota_on(struct super_block *sb, int type, int format_id, 15928c2ecf20Sopenharmony_ci const struct path *path); 15938c2ecf20Sopenharmony_cistatic int ext4_quota_on_mount(struct super_block *sb, int type); 15948c2ecf20Sopenharmony_cistatic ssize_t ext4_quota_read(struct super_block *sb, int type, char *data, 15958c2ecf20Sopenharmony_ci size_t len, loff_t off); 15968c2ecf20Sopenharmony_cistatic ssize_t ext4_quota_write(struct super_block *sb, int type, 15978c2ecf20Sopenharmony_ci const char *data, size_t len, loff_t off); 15988c2ecf20Sopenharmony_cistatic int ext4_quota_enable(struct super_block *sb, int type, int format_id, 15998c2ecf20Sopenharmony_ci unsigned int flags); 16008c2ecf20Sopenharmony_cistatic int ext4_enable_quotas(struct super_block *sb); 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_cistatic struct dquot **ext4_get_dquots(struct inode *inode) 16038c2ecf20Sopenharmony_ci{ 16048c2ecf20Sopenharmony_ci return EXT4_I(inode)->i_dquot; 16058c2ecf20Sopenharmony_ci} 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_cistatic const struct dquot_operations ext4_quota_operations = { 16088c2ecf20Sopenharmony_ci .get_reserved_space = ext4_get_reserved_space, 16098c2ecf20Sopenharmony_ci .write_dquot = ext4_write_dquot, 16108c2ecf20Sopenharmony_ci .acquire_dquot = ext4_acquire_dquot, 16118c2ecf20Sopenharmony_ci .release_dquot = ext4_release_dquot, 16128c2ecf20Sopenharmony_ci .mark_dirty = ext4_mark_dquot_dirty, 16138c2ecf20Sopenharmony_ci .write_info = ext4_write_info, 16148c2ecf20Sopenharmony_ci .alloc_dquot = dquot_alloc, 16158c2ecf20Sopenharmony_ci .destroy_dquot = dquot_destroy, 16168c2ecf20Sopenharmony_ci .get_projid = ext4_get_projid, 16178c2ecf20Sopenharmony_ci .get_inode_usage = ext4_get_inode_usage, 16188c2ecf20Sopenharmony_ci .get_next_id = dquot_get_next_id, 16198c2ecf20Sopenharmony_ci}; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_cistatic const struct quotactl_ops ext4_qctl_operations = { 16228c2ecf20Sopenharmony_ci .quota_on = ext4_quota_on, 16238c2ecf20Sopenharmony_ci .quota_off = ext4_quota_off, 16248c2ecf20Sopenharmony_ci .quota_sync = dquot_quota_sync, 16258c2ecf20Sopenharmony_ci .get_state = dquot_get_state, 16268c2ecf20Sopenharmony_ci .set_info = dquot_set_dqinfo, 16278c2ecf20Sopenharmony_ci .get_dqblk = dquot_get_dqblk, 16288c2ecf20Sopenharmony_ci .set_dqblk = dquot_set_dqblk, 16298c2ecf20Sopenharmony_ci .get_nextdqblk = dquot_get_next_dqblk, 16308c2ecf20Sopenharmony_ci}; 16318c2ecf20Sopenharmony_ci#endif 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_cistatic const struct super_operations ext4_sops = { 16348c2ecf20Sopenharmony_ci .alloc_inode = ext4_alloc_inode, 16358c2ecf20Sopenharmony_ci .free_inode = ext4_free_in_core_inode, 16368c2ecf20Sopenharmony_ci .destroy_inode = ext4_destroy_inode, 16378c2ecf20Sopenharmony_ci .write_inode = ext4_write_inode, 16388c2ecf20Sopenharmony_ci .dirty_inode = ext4_dirty_inode, 16398c2ecf20Sopenharmony_ci .drop_inode = ext4_drop_inode, 16408c2ecf20Sopenharmony_ci .evict_inode = ext4_evict_inode, 16418c2ecf20Sopenharmony_ci .put_super = ext4_put_super, 16428c2ecf20Sopenharmony_ci .sync_fs = ext4_sync_fs, 16438c2ecf20Sopenharmony_ci .freeze_fs = ext4_freeze, 16448c2ecf20Sopenharmony_ci .unfreeze_fs = ext4_unfreeze, 16458c2ecf20Sopenharmony_ci .statfs = ext4_statfs, 16468c2ecf20Sopenharmony_ci .remount_fs = ext4_remount, 16478c2ecf20Sopenharmony_ci .show_options = ext4_show_options, 16488c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 16498c2ecf20Sopenharmony_ci .quota_read = ext4_quota_read, 16508c2ecf20Sopenharmony_ci .quota_write = ext4_quota_write, 16518c2ecf20Sopenharmony_ci .get_dquots = ext4_get_dquots, 16528c2ecf20Sopenharmony_ci#endif 16538c2ecf20Sopenharmony_ci}; 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_cistatic const struct export_operations ext4_export_ops = { 16568c2ecf20Sopenharmony_ci .fh_to_dentry = ext4_fh_to_dentry, 16578c2ecf20Sopenharmony_ci .fh_to_parent = ext4_fh_to_parent, 16588c2ecf20Sopenharmony_ci .get_parent = ext4_get_parent, 16598c2ecf20Sopenharmony_ci .commit_metadata = ext4_nfs_commit_metadata, 16608c2ecf20Sopenharmony_ci}; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_cienum { 16638c2ecf20Sopenharmony_ci Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, 16648c2ecf20Sopenharmony_ci Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, 16658c2ecf20Sopenharmony_ci Opt_nouid32, Opt_debug, Opt_removed, 16668c2ecf20Sopenharmony_ci Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, 16678c2ecf20Sopenharmony_ci Opt_auto_da_alloc, Opt_noauto_da_alloc, Opt_noload, 16688c2ecf20Sopenharmony_ci Opt_commit, Opt_min_batch_time, Opt_max_batch_time, Opt_journal_dev, 16698c2ecf20Sopenharmony_ci Opt_journal_path, Opt_journal_checksum, Opt_journal_async_commit, 16708c2ecf20Sopenharmony_ci Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, 16718c2ecf20Sopenharmony_ci Opt_data_err_abort, Opt_data_err_ignore, Opt_test_dummy_encryption, 16728c2ecf20Sopenharmony_ci Opt_inlinecrypt, 16738c2ecf20Sopenharmony_ci Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, 16748c2ecf20Sopenharmony_ci Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota, 16758c2ecf20Sopenharmony_ci Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err, 16768c2ecf20Sopenharmony_ci Opt_usrquota, Opt_grpquota, Opt_prjquota, Opt_i_version, 16778c2ecf20Sopenharmony_ci Opt_dax, Opt_dax_always, Opt_dax_inode, Opt_dax_never, 16788c2ecf20Sopenharmony_ci Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_warn_on_error, 16798c2ecf20Sopenharmony_ci Opt_nowarn_on_error, Opt_mblk_io_submit, 16808c2ecf20Sopenharmony_ci Opt_lazytime, Opt_nolazytime, Opt_debug_want_extra_isize, 16818c2ecf20Sopenharmony_ci Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity, 16828c2ecf20Sopenharmony_ci Opt_inode_readahead_blks, Opt_journal_ioprio, 16838c2ecf20Sopenharmony_ci Opt_dioread_nolock, Opt_dioread_lock, 16848c2ecf20Sopenharmony_ci Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable, 16858c2ecf20Sopenharmony_ci Opt_max_dir_size_kb, Opt_nojournal_checksum, Opt_nombcache, 16868c2ecf20Sopenharmony_ci Opt_prefetch_block_bitmaps, 16878c2ecf20Sopenharmony_ci#ifdef CONFIG_EXT4_DEBUG 16888c2ecf20Sopenharmony_ci Opt_fc_debug_max_replay, Opt_fc_debug_force 16898c2ecf20Sopenharmony_ci#endif 16908c2ecf20Sopenharmony_ci}; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_cistatic const match_table_t tokens = { 16938c2ecf20Sopenharmony_ci {Opt_bsd_df, "bsddf"}, 16948c2ecf20Sopenharmony_ci {Opt_minix_df, "minixdf"}, 16958c2ecf20Sopenharmony_ci {Opt_grpid, "grpid"}, 16968c2ecf20Sopenharmony_ci {Opt_grpid, "bsdgroups"}, 16978c2ecf20Sopenharmony_ci {Opt_nogrpid, "nogrpid"}, 16988c2ecf20Sopenharmony_ci {Opt_nogrpid, "sysvgroups"}, 16998c2ecf20Sopenharmony_ci {Opt_resgid, "resgid=%u"}, 17008c2ecf20Sopenharmony_ci {Opt_resuid, "resuid=%u"}, 17018c2ecf20Sopenharmony_ci {Opt_sb, "sb=%u"}, 17028c2ecf20Sopenharmony_ci {Opt_err_cont, "errors=continue"}, 17038c2ecf20Sopenharmony_ci {Opt_err_panic, "errors=panic"}, 17048c2ecf20Sopenharmony_ci {Opt_err_ro, "errors=remount-ro"}, 17058c2ecf20Sopenharmony_ci {Opt_nouid32, "nouid32"}, 17068c2ecf20Sopenharmony_ci {Opt_debug, "debug"}, 17078c2ecf20Sopenharmony_ci {Opt_removed, "oldalloc"}, 17088c2ecf20Sopenharmony_ci {Opt_removed, "orlov"}, 17098c2ecf20Sopenharmony_ci {Opt_user_xattr, "user_xattr"}, 17108c2ecf20Sopenharmony_ci {Opt_nouser_xattr, "nouser_xattr"}, 17118c2ecf20Sopenharmony_ci {Opt_acl, "acl"}, 17128c2ecf20Sopenharmony_ci {Opt_noacl, "noacl"}, 17138c2ecf20Sopenharmony_ci {Opt_noload, "norecovery"}, 17148c2ecf20Sopenharmony_ci {Opt_noload, "noload"}, 17158c2ecf20Sopenharmony_ci {Opt_removed, "nobh"}, 17168c2ecf20Sopenharmony_ci {Opt_removed, "bh"}, 17178c2ecf20Sopenharmony_ci {Opt_commit, "commit=%u"}, 17188c2ecf20Sopenharmony_ci {Opt_min_batch_time, "min_batch_time=%u"}, 17198c2ecf20Sopenharmony_ci {Opt_max_batch_time, "max_batch_time=%u"}, 17208c2ecf20Sopenharmony_ci {Opt_journal_dev, "journal_dev=%u"}, 17218c2ecf20Sopenharmony_ci {Opt_journal_path, "journal_path=%s"}, 17228c2ecf20Sopenharmony_ci {Opt_journal_checksum, "journal_checksum"}, 17238c2ecf20Sopenharmony_ci {Opt_nojournal_checksum, "nojournal_checksum"}, 17248c2ecf20Sopenharmony_ci {Opt_journal_async_commit, "journal_async_commit"}, 17258c2ecf20Sopenharmony_ci {Opt_abort, "abort"}, 17268c2ecf20Sopenharmony_ci {Opt_data_journal, "data=journal"}, 17278c2ecf20Sopenharmony_ci {Opt_data_ordered, "data=ordered"}, 17288c2ecf20Sopenharmony_ci {Opt_data_writeback, "data=writeback"}, 17298c2ecf20Sopenharmony_ci {Opt_data_err_abort, "data_err=abort"}, 17308c2ecf20Sopenharmony_ci {Opt_data_err_ignore, "data_err=ignore"}, 17318c2ecf20Sopenharmony_ci {Opt_offusrjquota, "usrjquota="}, 17328c2ecf20Sopenharmony_ci {Opt_usrjquota, "usrjquota=%s"}, 17338c2ecf20Sopenharmony_ci {Opt_offgrpjquota, "grpjquota="}, 17348c2ecf20Sopenharmony_ci {Opt_grpjquota, "grpjquota=%s"}, 17358c2ecf20Sopenharmony_ci {Opt_jqfmt_vfsold, "jqfmt=vfsold"}, 17368c2ecf20Sopenharmony_ci {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"}, 17378c2ecf20Sopenharmony_ci {Opt_jqfmt_vfsv1, "jqfmt=vfsv1"}, 17388c2ecf20Sopenharmony_ci {Opt_grpquota, "grpquota"}, 17398c2ecf20Sopenharmony_ci {Opt_noquota, "noquota"}, 17408c2ecf20Sopenharmony_ci {Opt_quota, "quota"}, 17418c2ecf20Sopenharmony_ci {Opt_usrquota, "usrquota"}, 17428c2ecf20Sopenharmony_ci {Opt_prjquota, "prjquota"}, 17438c2ecf20Sopenharmony_ci {Opt_barrier, "barrier=%u"}, 17448c2ecf20Sopenharmony_ci {Opt_barrier, "barrier"}, 17458c2ecf20Sopenharmony_ci {Opt_nobarrier, "nobarrier"}, 17468c2ecf20Sopenharmony_ci {Opt_i_version, "i_version"}, 17478c2ecf20Sopenharmony_ci {Opt_dax, "dax"}, 17488c2ecf20Sopenharmony_ci {Opt_dax_always, "dax=always"}, 17498c2ecf20Sopenharmony_ci {Opt_dax_inode, "dax=inode"}, 17508c2ecf20Sopenharmony_ci {Opt_dax_never, "dax=never"}, 17518c2ecf20Sopenharmony_ci {Opt_stripe, "stripe=%u"}, 17528c2ecf20Sopenharmony_ci {Opt_delalloc, "delalloc"}, 17538c2ecf20Sopenharmony_ci {Opt_warn_on_error, "warn_on_error"}, 17548c2ecf20Sopenharmony_ci {Opt_nowarn_on_error, "nowarn_on_error"}, 17558c2ecf20Sopenharmony_ci {Opt_lazytime, "lazytime"}, 17568c2ecf20Sopenharmony_ci {Opt_nolazytime, "nolazytime"}, 17578c2ecf20Sopenharmony_ci {Opt_debug_want_extra_isize, "debug_want_extra_isize=%u"}, 17588c2ecf20Sopenharmony_ci {Opt_nodelalloc, "nodelalloc"}, 17598c2ecf20Sopenharmony_ci {Opt_removed, "mblk_io_submit"}, 17608c2ecf20Sopenharmony_ci {Opt_removed, "nomblk_io_submit"}, 17618c2ecf20Sopenharmony_ci {Opt_block_validity, "block_validity"}, 17628c2ecf20Sopenharmony_ci {Opt_noblock_validity, "noblock_validity"}, 17638c2ecf20Sopenharmony_ci {Opt_inode_readahead_blks, "inode_readahead_blks=%u"}, 17648c2ecf20Sopenharmony_ci {Opt_journal_ioprio, "journal_ioprio=%u"}, 17658c2ecf20Sopenharmony_ci {Opt_auto_da_alloc, "auto_da_alloc=%u"}, 17668c2ecf20Sopenharmony_ci {Opt_auto_da_alloc, "auto_da_alloc"}, 17678c2ecf20Sopenharmony_ci {Opt_noauto_da_alloc, "noauto_da_alloc"}, 17688c2ecf20Sopenharmony_ci {Opt_dioread_nolock, "dioread_nolock"}, 17698c2ecf20Sopenharmony_ci {Opt_dioread_lock, "nodioread_nolock"}, 17708c2ecf20Sopenharmony_ci {Opt_dioread_lock, "dioread_lock"}, 17718c2ecf20Sopenharmony_ci {Opt_discard, "discard"}, 17728c2ecf20Sopenharmony_ci {Opt_nodiscard, "nodiscard"}, 17738c2ecf20Sopenharmony_ci {Opt_init_itable, "init_itable=%u"}, 17748c2ecf20Sopenharmony_ci {Opt_init_itable, "init_itable"}, 17758c2ecf20Sopenharmony_ci {Opt_noinit_itable, "noinit_itable"}, 17768c2ecf20Sopenharmony_ci#ifdef CONFIG_EXT4_DEBUG 17778c2ecf20Sopenharmony_ci {Opt_fc_debug_force, "fc_debug_force"}, 17788c2ecf20Sopenharmony_ci {Opt_fc_debug_max_replay, "fc_debug_max_replay=%u"}, 17798c2ecf20Sopenharmony_ci#endif 17808c2ecf20Sopenharmony_ci {Opt_max_dir_size_kb, "max_dir_size_kb=%u"}, 17818c2ecf20Sopenharmony_ci {Opt_test_dummy_encryption, "test_dummy_encryption=%s"}, 17828c2ecf20Sopenharmony_ci {Opt_test_dummy_encryption, "test_dummy_encryption"}, 17838c2ecf20Sopenharmony_ci {Opt_inlinecrypt, "inlinecrypt"}, 17848c2ecf20Sopenharmony_ci {Opt_nombcache, "nombcache"}, 17858c2ecf20Sopenharmony_ci {Opt_nombcache, "no_mbcache"}, /* for backward compatibility */ 17868c2ecf20Sopenharmony_ci {Opt_prefetch_block_bitmaps, "prefetch_block_bitmaps"}, 17878c2ecf20Sopenharmony_ci {Opt_removed, "check=none"}, /* mount option from ext2/3 */ 17888c2ecf20Sopenharmony_ci {Opt_removed, "nocheck"}, /* mount option from ext2/3 */ 17898c2ecf20Sopenharmony_ci {Opt_removed, "reservation"}, /* mount option from ext2/3 */ 17908c2ecf20Sopenharmony_ci {Opt_removed, "noreservation"}, /* mount option from ext2/3 */ 17918c2ecf20Sopenharmony_ci {Opt_removed, "journal=%u"}, /* mount option from ext2/3 */ 17928c2ecf20Sopenharmony_ci {Opt_err, NULL}, 17938c2ecf20Sopenharmony_ci}; 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_cistatic ext4_fsblk_t get_sb_block(void **data) 17968c2ecf20Sopenharmony_ci{ 17978c2ecf20Sopenharmony_ci ext4_fsblk_t sb_block; 17988c2ecf20Sopenharmony_ci char *options = (char *) *data; 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci if (!options || strncmp(options, "sb=", 3) != 0) 18018c2ecf20Sopenharmony_ci return 1; /* Default location */ 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci options += 3; 18048c2ecf20Sopenharmony_ci /* TODO: use simple_strtoll with >32bit ext4 */ 18058c2ecf20Sopenharmony_ci sb_block = simple_strtoul(options, &options, 0); 18068c2ecf20Sopenharmony_ci if (*options && *options != ',') { 18078c2ecf20Sopenharmony_ci printk(KERN_ERR "EXT4-fs: Invalid sb specification: %s\n", 18088c2ecf20Sopenharmony_ci (char *) *data); 18098c2ecf20Sopenharmony_ci return 1; 18108c2ecf20Sopenharmony_ci } 18118c2ecf20Sopenharmony_ci if (*options == ',') 18128c2ecf20Sopenharmony_ci options++; 18138c2ecf20Sopenharmony_ci *data = (void *) options; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci return sb_block; 18168c2ecf20Sopenharmony_ci} 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci#define DEFAULT_JOURNAL_IOPRIO (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 3)) 18198c2ecf20Sopenharmony_cistatic const char deprecated_msg[] = 18208c2ecf20Sopenharmony_ci "Mount option \"%s\" will be removed by %s\n" 18218c2ecf20Sopenharmony_ci "Contact linux-ext4@vger.kernel.org if you think we should keep it.\n"; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 18248c2ecf20Sopenharmony_cistatic int set_qf_name(struct super_block *sb, int qtype, substring_t *args) 18258c2ecf20Sopenharmony_ci{ 18268c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 18278c2ecf20Sopenharmony_ci char *qname, *old_qname = get_qf_name(sb, sbi, qtype); 18288c2ecf20Sopenharmony_ci int ret = -1; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci if (sb_any_quota_loaded(sb) && !old_qname) { 18318c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 18328c2ecf20Sopenharmony_ci "Cannot change journaled " 18338c2ecf20Sopenharmony_ci "quota options when quota turned on"); 18348c2ecf20Sopenharmony_ci return -1; 18358c2ecf20Sopenharmony_ci } 18368c2ecf20Sopenharmony_ci if (ext4_has_feature_quota(sb)) { 18378c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "Journaled quota options " 18388c2ecf20Sopenharmony_ci "ignored when QUOTA feature is enabled"); 18398c2ecf20Sopenharmony_ci return 1; 18408c2ecf20Sopenharmony_ci } 18418c2ecf20Sopenharmony_ci qname = match_strdup(args); 18428c2ecf20Sopenharmony_ci if (!qname) { 18438c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 18448c2ecf20Sopenharmony_ci "Not enough memory for storing quotafile name"); 18458c2ecf20Sopenharmony_ci return -1; 18468c2ecf20Sopenharmony_ci } 18478c2ecf20Sopenharmony_ci if (old_qname) { 18488c2ecf20Sopenharmony_ci if (strcmp(old_qname, qname) == 0) 18498c2ecf20Sopenharmony_ci ret = 1; 18508c2ecf20Sopenharmony_ci else 18518c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 18528c2ecf20Sopenharmony_ci "%s quota file already specified", 18538c2ecf20Sopenharmony_ci QTYPE2NAME(qtype)); 18548c2ecf20Sopenharmony_ci goto errout; 18558c2ecf20Sopenharmony_ci } 18568c2ecf20Sopenharmony_ci if (strchr(qname, '/')) { 18578c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 18588c2ecf20Sopenharmony_ci "quotafile must be on filesystem root"); 18598c2ecf20Sopenharmony_ci goto errout; 18608c2ecf20Sopenharmony_ci } 18618c2ecf20Sopenharmony_ci rcu_assign_pointer(sbi->s_qf_names[qtype], qname); 18628c2ecf20Sopenharmony_ci set_opt(sb, QUOTA); 18638c2ecf20Sopenharmony_ci return 1; 18648c2ecf20Sopenharmony_cierrout: 18658c2ecf20Sopenharmony_ci kfree(qname); 18668c2ecf20Sopenharmony_ci return ret; 18678c2ecf20Sopenharmony_ci} 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_cistatic int clear_qf_name(struct super_block *sb, int qtype) 18708c2ecf20Sopenharmony_ci{ 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 18738c2ecf20Sopenharmony_ci char *old_qname = get_qf_name(sb, sbi, qtype); 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci if (sb_any_quota_loaded(sb) && old_qname) { 18768c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Cannot change journaled quota options" 18778c2ecf20Sopenharmony_ci " when quota turned on"); 18788c2ecf20Sopenharmony_ci return -1; 18798c2ecf20Sopenharmony_ci } 18808c2ecf20Sopenharmony_ci rcu_assign_pointer(sbi->s_qf_names[qtype], NULL); 18818c2ecf20Sopenharmony_ci synchronize_rcu(); 18828c2ecf20Sopenharmony_ci kfree(old_qname); 18838c2ecf20Sopenharmony_ci return 1; 18848c2ecf20Sopenharmony_ci} 18858c2ecf20Sopenharmony_ci#endif 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci#define MOPT_SET 0x0001 18888c2ecf20Sopenharmony_ci#define MOPT_CLEAR 0x0002 18898c2ecf20Sopenharmony_ci#define MOPT_NOSUPPORT 0x0004 18908c2ecf20Sopenharmony_ci#define MOPT_EXPLICIT 0x0008 18918c2ecf20Sopenharmony_ci#define MOPT_CLEAR_ERR 0x0010 18928c2ecf20Sopenharmony_ci#define MOPT_GTE0 0x0020 18938c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 18948c2ecf20Sopenharmony_ci#define MOPT_Q 0 18958c2ecf20Sopenharmony_ci#define MOPT_QFMT 0x0040 18968c2ecf20Sopenharmony_ci#else 18978c2ecf20Sopenharmony_ci#define MOPT_Q MOPT_NOSUPPORT 18988c2ecf20Sopenharmony_ci#define MOPT_QFMT MOPT_NOSUPPORT 18998c2ecf20Sopenharmony_ci#endif 19008c2ecf20Sopenharmony_ci#define MOPT_DATAJ 0x0080 19018c2ecf20Sopenharmony_ci#define MOPT_NO_EXT2 0x0100 19028c2ecf20Sopenharmony_ci#define MOPT_NO_EXT3 0x0200 19038c2ecf20Sopenharmony_ci#define MOPT_EXT4_ONLY (MOPT_NO_EXT2 | MOPT_NO_EXT3) 19048c2ecf20Sopenharmony_ci#define MOPT_STRING 0x0400 19058c2ecf20Sopenharmony_ci#define MOPT_SKIP 0x0800 19068c2ecf20Sopenharmony_ci#define MOPT_2 0x1000 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_cistatic const struct mount_opts { 19098c2ecf20Sopenharmony_ci int token; 19108c2ecf20Sopenharmony_ci int mount_opt; 19118c2ecf20Sopenharmony_ci int flags; 19128c2ecf20Sopenharmony_ci} ext4_mount_opts[] = { 19138c2ecf20Sopenharmony_ci {Opt_minix_df, EXT4_MOUNT_MINIX_DF, MOPT_SET}, 19148c2ecf20Sopenharmony_ci {Opt_bsd_df, EXT4_MOUNT_MINIX_DF, MOPT_CLEAR}, 19158c2ecf20Sopenharmony_ci {Opt_grpid, EXT4_MOUNT_GRPID, MOPT_SET}, 19168c2ecf20Sopenharmony_ci {Opt_nogrpid, EXT4_MOUNT_GRPID, MOPT_CLEAR}, 19178c2ecf20Sopenharmony_ci {Opt_block_validity, EXT4_MOUNT_BLOCK_VALIDITY, MOPT_SET}, 19188c2ecf20Sopenharmony_ci {Opt_noblock_validity, EXT4_MOUNT_BLOCK_VALIDITY, MOPT_CLEAR}, 19198c2ecf20Sopenharmony_ci {Opt_dioread_nolock, EXT4_MOUNT_DIOREAD_NOLOCK, 19208c2ecf20Sopenharmony_ci MOPT_EXT4_ONLY | MOPT_SET}, 19218c2ecf20Sopenharmony_ci {Opt_dioread_lock, EXT4_MOUNT_DIOREAD_NOLOCK, 19228c2ecf20Sopenharmony_ci MOPT_EXT4_ONLY | MOPT_CLEAR}, 19238c2ecf20Sopenharmony_ci {Opt_discard, EXT4_MOUNT_DISCARD, MOPT_SET}, 19248c2ecf20Sopenharmony_ci {Opt_nodiscard, EXT4_MOUNT_DISCARD, MOPT_CLEAR}, 19258c2ecf20Sopenharmony_ci {Opt_delalloc, EXT4_MOUNT_DELALLOC, 19268c2ecf20Sopenharmony_ci MOPT_EXT4_ONLY | MOPT_SET | MOPT_EXPLICIT}, 19278c2ecf20Sopenharmony_ci {Opt_nodelalloc, EXT4_MOUNT_DELALLOC, 19288c2ecf20Sopenharmony_ci MOPT_EXT4_ONLY | MOPT_CLEAR}, 19298c2ecf20Sopenharmony_ci {Opt_warn_on_error, EXT4_MOUNT_WARN_ON_ERROR, MOPT_SET}, 19308c2ecf20Sopenharmony_ci {Opt_nowarn_on_error, EXT4_MOUNT_WARN_ON_ERROR, MOPT_CLEAR}, 19318c2ecf20Sopenharmony_ci {Opt_commit, 0, MOPT_NO_EXT2}, 19328c2ecf20Sopenharmony_ci {Opt_nojournal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM, 19338c2ecf20Sopenharmony_ci MOPT_EXT4_ONLY | MOPT_CLEAR}, 19348c2ecf20Sopenharmony_ci {Opt_journal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM, 19358c2ecf20Sopenharmony_ci MOPT_EXT4_ONLY | MOPT_SET | MOPT_EXPLICIT}, 19368c2ecf20Sopenharmony_ci {Opt_journal_async_commit, (EXT4_MOUNT_JOURNAL_ASYNC_COMMIT | 19378c2ecf20Sopenharmony_ci EXT4_MOUNT_JOURNAL_CHECKSUM), 19388c2ecf20Sopenharmony_ci MOPT_EXT4_ONLY | MOPT_SET | MOPT_EXPLICIT}, 19398c2ecf20Sopenharmony_ci {Opt_noload, EXT4_MOUNT_NOLOAD, MOPT_NO_EXT2 | MOPT_SET}, 19408c2ecf20Sopenharmony_ci {Opt_err_panic, EXT4_MOUNT_ERRORS_PANIC, MOPT_SET | MOPT_CLEAR_ERR}, 19418c2ecf20Sopenharmony_ci {Opt_err_ro, EXT4_MOUNT_ERRORS_RO, MOPT_SET | MOPT_CLEAR_ERR}, 19428c2ecf20Sopenharmony_ci {Opt_err_cont, EXT4_MOUNT_ERRORS_CONT, MOPT_SET | MOPT_CLEAR_ERR}, 19438c2ecf20Sopenharmony_ci {Opt_data_err_abort, EXT4_MOUNT_DATA_ERR_ABORT, 19448c2ecf20Sopenharmony_ci MOPT_NO_EXT2}, 19458c2ecf20Sopenharmony_ci {Opt_data_err_ignore, EXT4_MOUNT_DATA_ERR_ABORT, 19468c2ecf20Sopenharmony_ci MOPT_NO_EXT2}, 19478c2ecf20Sopenharmony_ci {Opt_barrier, EXT4_MOUNT_BARRIER, MOPT_SET}, 19488c2ecf20Sopenharmony_ci {Opt_nobarrier, EXT4_MOUNT_BARRIER, MOPT_CLEAR}, 19498c2ecf20Sopenharmony_ci {Opt_noauto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_SET}, 19508c2ecf20Sopenharmony_ci {Opt_auto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_CLEAR}, 19518c2ecf20Sopenharmony_ci {Opt_noinit_itable, EXT4_MOUNT_INIT_INODE_TABLE, MOPT_CLEAR}, 19528c2ecf20Sopenharmony_ci {Opt_commit, 0, MOPT_GTE0}, 19538c2ecf20Sopenharmony_ci {Opt_max_batch_time, 0, MOPT_GTE0}, 19548c2ecf20Sopenharmony_ci {Opt_min_batch_time, 0, MOPT_GTE0}, 19558c2ecf20Sopenharmony_ci {Opt_inode_readahead_blks, 0, MOPT_GTE0}, 19568c2ecf20Sopenharmony_ci {Opt_init_itable, 0, MOPT_GTE0}, 19578c2ecf20Sopenharmony_ci {Opt_dax, EXT4_MOUNT_DAX_ALWAYS, MOPT_SET | MOPT_SKIP}, 19588c2ecf20Sopenharmony_ci {Opt_dax_always, EXT4_MOUNT_DAX_ALWAYS, 19598c2ecf20Sopenharmony_ci MOPT_EXT4_ONLY | MOPT_SET | MOPT_SKIP}, 19608c2ecf20Sopenharmony_ci {Opt_dax_inode, EXT4_MOUNT2_DAX_INODE, 19618c2ecf20Sopenharmony_ci MOPT_EXT4_ONLY | MOPT_SET | MOPT_SKIP}, 19628c2ecf20Sopenharmony_ci {Opt_dax_never, EXT4_MOUNT2_DAX_NEVER, 19638c2ecf20Sopenharmony_ci MOPT_EXT4_ONLY | MOPT_SET | MOPT_SKIP}, 19648c2ecf20Sopenharmony_ci {Opt_stripe, 0, MOPT_GTE0}, 19658c2ecf20Sopenharmony_ci {Opt_resuid, 0, MOPT_GTE0}, 19668c2ecf20Sopenharmony_ci {Opt_resgid, 0, MOPT_GTE0}, 19678c2ecf20Sopenharmony_ci {Opt_journal_dev, 0, MOPT_NO_EXT2 | MOPT_GTE0}, 19688c2ecf20Sopenharmony_ci {Opt_journal_path, 0, MOPT_NO_EXT2 | MOPT_STRING}, 19698c2ecf20Sopenharmony_ci {Opt_journal_ioprio, 0, MOPT_NO_EXT2 | MOPT_GTE0}, 19708c2ecf20Sopenharmony_ci {Opt_data_journal, EXT4_MOUNT_JOURNAL_DATA, MOPT_NO_EXT2 | MOPT_DATAJ}, 19718c2ecf20Sopenharmony_ci {Opt_data_ordered, EXT4_MOUNT_ORDERED_DATA, MOPT_NO_EXT2 | MOPT_DATAJ}, 19728c2ecf20Sopenharmony_ci {Opt_data_writeback, EXT4_MOUNT_WRITEBACK_DATA, 19738c2ecf20Sopenharmony_ci MOPT_NO_EXT2 | MOPT_DATAJ}, 19748c2ecf20Sopenharmony_ci {Opt_user_xattr, EXT4_MOUNT_XATTR_USER, MOPT_SET}, 19758c2ecf20Sopenharmony_ci {Opt_nouser_xattr, EXT4_MOUNT_XATTR_USER, MOPT_CLEAR}, 19768c2ecf20Sopenharmony_ci#ifdef CONFIG_EXT4_FS_POSIX_ACL 19778c2ecf20Sopenharmony_ci {Opt_acl, EXT4_MOUNT_POSIX_ACL, MOPT_SET}, 19788c2ecf20Sopenharmony_ci {Opt_noacl, EXT4_MOUNT_POSIX_ACL, MOPT_CLEAR}, 19798c2ecf20Sopenharmony_ci#else 19808c2ecf20Sopenharmony_ci {Opt_acl, 0, MOPT_NOSUPPORT}, 19818c2ecf20Sopenharmony_ci {Opt_noacl, 0, MOPT_NOSUPPORT}, 19828c2ecf20Sopenharmony_ci#endif 19838c2ecf20Sopenharmony_ci {Opt_nouid32, EXT4_MOUNT_NO_UID32, MOPT_SET}, 19848c2ecf20Sopenharmony_ci {Opt_debug, EXT4_MOUNT_DEBUG, MOPT_SET}, 19858c2ecf20Sopenharmony_ci {Opt_debug_want_extra_isize, 0, MOPT_GTE0}, 19868c2ecf20Sopenharmony_ci {Opt_quota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA, MOPT_SET | MOPT_Q}, 19878c2ecf20Sopenharmony_ci {Opt_usrquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA, 19888c2ecf20Sopenharmony_ci MOPT_SET | MOPT_Q}, 19898c2ecf20Sopenharmony_ci {Opt_grpquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_GRPQUOTA, 19908c2ecf20Sopenharmony_ci MOPT_SET | MOPT_Q}, 19918c2ecf20Sopenharmony_ci {Opt_prjquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_PRJQUOTA, 19928c2ecf20Sopenharmony_ci MOPT_SET | MOPT_Q}, 19938c2ecf20Sopenharmony_ci {Opt_noquota, (EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA | 19948c2ecf20Sopenharmony_ci EXT4_MOUNT_GRPQUOTA | EXT4_MOUNT_PRJQUOTA), 19958c2ecf20Sopenharmony_ci MOPT_CLEAR | MOPT_Q}, 19968c2ecf20Sopenharmony_ci {Opt_usrjquota, 0, MOPT_Q | MOPT_STRING}, 19978c2ecf20Sopenharmony_ci {Opt_grpjquota, 0, MOPT_Q | MOPT_STRING}, 19988c2ecf20Sopenharmony_ci {Opt_offusrjquota, 0, MOPT_Q}, 19998c2ecf20Sopenharmony_ci {Opt_offgrpjquota, 0, MOPT_Q}, 20008c2ecf20Sopenharmony_ci {Opt_jqfmt_vfsold, QFMT_VFS_OLD, MOPT_QFMT}, 20018c2ecf20Sopenharmony_ci {Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT}, 20028c2ecf20Sopenharmony_ci {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT}, 20038c2ecf20Sopenharmony_ci {Opt_max_dir_size_kb, 0, MOPT_GTE0}, 20048c2ecf20Sopenharmony_ci {Opt_test_dummy_encryption, 0, MOPT_STRING}, 20058c2ecf20Sopenharmony_ci {Opt_nombcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET}, 20068c2ecf20Sopenharmony_ci {Opt_prefetch_block_bitmaps, EXT4_MOUNT_PREFETCH_BLOCK_BITMAPS, 20078c2ecf20Sopenharmony_ci MOPT_SET}, 20088c2ecf20Sopenharmony_ci#ifdef CONFIG_EXT4_DEBUG 20098c2ecf20Sopenharmony_ci {Opt_fc_debug_force, EXT4_MOUNT2_JOURNAL_FAST_COMMIT, 20108c2ecf20Sopenharmony_ci MOPT_SET | MOPT_2 | MOPT_EXT4_ONLY}, 20118c2ecf20Sopenharmony_ci {Opt_fc_debug_max_replay, 0, MOPT_GTE0}, 20128c2ecf20Sopenharmony_ci#endif 20138c2ecf20Sopenharmony_ci {Opt_err, 0, 0} 20148c2ecf20Sopenharmony_ci}; 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci#ifdef CONFIG_UNICODE 20178c2ecf20Sopenharmony_cistatic const struct ext4_sb_encodings { 20188c2ecf20Sopenharmony_ci __u16 magic; 20198c2ecf20Sopenharmony_ci char *name; 20208c2ecf20Sopenharmony_ci char *version; 20218c2ecf20Sopenharmony_ci} ext4_sb_encoding_map[] = { 20228c2ecf20Sopenharmony_ci {EXT4_ENC_UTF8_12_1, "utf8", "12.1.0"}, 20238c2ecf20Sopenharmony_ci}; 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_cistatic int ext4_sb_read_encoding(const struct ext4_super_block *es, 20268c2ecf20Sopenharmony_ci const struct ext4_sb_encodings **encoding, 20278c2ecf20Sopenharmony_ci __u16 *flags) 20288c2ecf20Sopenharmony_ci{ 20298c2ecf20Sopenharmony_ci __u16 magic = le16_to_cpu(es->s_encoding); 20308c2ecf20Sopenharmony_ci int i; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ext4_sb_encoding_map); i++) 20338c2ecf20Sopenharmony_ci if (magic == ext4_sb_encoding_map[i].magic) 20348c2ecf20Sopenharmony_ci break; 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci if (i >= ARRAY_SIZE(ext4_sb_encoding_map)) 20378c2ecf20Sopenharmony_ci return -EINVAL; 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci *encoding = &ext4_sb_encoding_map[i]; 20408c2ecf20Sopenharmony_ci *flags = le16_to_cpu(es->s_encoding_flags); 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci return 0; 20438c2ecf20Sopenharmony_ci} 20448c2ecf20Sopenharmony_ci#endif 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_cistatic int ext4_set_test_dummy_encryption(struct super_block *sb, 20478c2ecf20Sopenharmony_ci const char *opt, 20488c2ecf20Sopenharmony_ci const substring_t *arg, 20498c2ecf20Sopenharmony_ci bool is_remount) 20508c2ecf20Sopenharmony_ci{ 20518c2ecf20Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION 20528c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 20538c2ecf20Sopenharmony_ci int err; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci if (!ext4_has_feature_encrypt(sb)) { 20568c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 20578c2ecf20Sopenharmony_ci "test_dummy_encryption requires encrypt feature"); 20588c2ecf20Sopenharmony_ci return -1; 20598c2ecf20Sopenharmony_ci } 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci /* 20628c2ecf20Sopenharmony_ci * This mount option is just for testing, and it's not worthwhile to 20638c2ecf20Sopenharmony_ci * implement the extra complexity (e.g. RCU protection) that would be 20648c2ecf20Sopenharmony_ci * needed to allow it to be set or changed during remount. We do allow 20658c2ecf20Sopenharmony_ci * it to be specified during remount, but only if there is no change. 20668c2ecf20Sopenharmony_ci */ 20678c2ecf20Sopenharmony_ci if (is_remount && !sbi->s_dummy_enc_policy.policy) { 20688c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 20698c2ecf20Sopenharmony_ci "Can't set test_dummy_encryption on remount"); 20708c2ecf20Sopenharmony_ci return -1; 20718c2ecf20Sopenharmony_ci } 20728c2ecf20Sopenharmony_ci err = fscrypt_set_test_dummy_encryption(sb, arg->from, 20738c2ecf20Sopenharmony_ci &sbi->s_dummy_enc_policy); 20748c2ecf20Sopenharmony_ci if (err) { 20758c2ecf20Sopenharmony_ci if (err == -EEXIST) 20768c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 20778c2ecf20Sopenharmony_ci "Can't change test_dummy_encryption on remount"); 20788c2ecf20Sopenharmony_ci else if (err == -EINVAL) 20798c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 20808c2ecf20Sopenharmony_ci "Value of option \"%s\" is unrecognized", opt); 20818c2ecf20Sopenharmony_ci else 20828c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 20838c2ecf20Sopenharmony_ci "Error processing option \"%s\" [%d]", 20848c2ecf20Sopenharmony_ci opt, err); 20858c2ecf20Sopenharmony_ci return -1; 20868c2ecf20Sopenharmony_ci } 20878c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, "Test dummy encryption mode enabled"); 20888c2ecf20Sopenharmony_ci return 1; 20898c2ecf20Sopenharmony_ci#else 20908c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 20918c2ecf20Sopenharmony_ci "test_dummy_encryption option not supported"); 20928c2ecf20Sopenharmony_ci return -1; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci#endif 20958c2ecf20Sopenharmony_ci} 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_cistatic int handle_mount_opt(struct super_block *sb, char *opt, int token, 20988c2ecf20Sopenharmony_ci substring_t *args, unsigned long *journal_devnum, 20998c2ecf20Sopenharmony_ci unsigned int *journal_ioprio, int is_remount) 21008c2ecf20Sopenharmony_ci{ 21018c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 21028c2ecf20Sopenharmony_ci const struct mount_opts *m; 21038c2ecf20Sopenharmony_ci kuid_t uid; 21048c2ecf20Sopenharmony_ci kgid_t gid; 21058c2ecf20Sopenharmony_ci int arg = 0; 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 21088c2ecf20Sopenharmony_ci if (token == Opt_usrjquota) 21098c2ecf20Sopenharmony_ci return set_qf_name(sb, USRQUOTA, &args[0]); 21108c2ecf20Sopenharmony_ci else if (token == Opt_grpjquota) 21118c2ecf20Sopenharmony_ci return set_qf_name(sb, GRPQUOTA, &args[0]); 21128c2ecf20Sopenharmony_ci else if (token == Opt_offusrjquota) 21138c2ecf20Sopenharmony_ci return clear_qf_name(sb, USRQUOTA); 21148c2ecf20Sopenharmony_ci else if (token == Opt_offgrpjquota) 21158c2ecf20Sopenharmony_ci return clear_qf_name(sb, GRPQUOTA); 21168c2ecf20Sopenharmony_ci#endif 21178c2ecf20Sopenharmony_ci switch (token) { 21188c2ecf20Sopenharmony_ci case Opt_noacl: 21198c2ecf20Sopenharmony_ci case Opt_nouser_xattr: 21208c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, deprecated_msg, opt, "3.5"); 21218c2ecf20Sopenharmony_ci break; 21228c2ecf20Sopenharmony_ci case Opt_sb: 21238c2ecf20Sopenharmony_ci return 1; /* handled by get_sb_block() */ 21248c2ecf20Sopenharmony_ci case Opt_removed: 21258c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, "Ignoring removed %s option", opt); 21268c2ecf20Sopenharmony_ci return 1; 21278c2ecf20Sopenharmony_ci case Opt_abort: 21288c2ecf20Sopenharmony_ci ext4_set_mount_flag(sb, EXT4_MF_FS_ABORTED); 21298c2ecf20Sopenharmony_ci return 1; 21308c2ecf20Sopenharmony_ci case Opt_i_version: 21318c2ecf20Sopenharmony_ci sb->s_flags |= SB_I_VERSION; 21328c2ecf20Sopenharmony_ci return 1; 21338c2ecf20Sopenharmony_ci case Opt_lazytime: 21348c2ecf20Sopenharmony_ci sb->s_flags |= SB_LAZYTIME; 21358c2ecf20Sopenharmony_ci return 1; 21368c2ecf20Sopenharmony_ci case Opt_nolazytime: 21378c2ecf20Sopenharmony_ci sb->s_flags &= ~SB_LAZYTIME; 21388c2ecf20Sopenharmony_ci return 1; 21398c2ecf20Sopenharmony_ci case Opt_inlinecrypt: 21408c2ecf20Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION_INLINE_CRYPT 21418c2ecf20Sopenharmony_ci sb->s_flags |= SB_INLINECRYPT; 21428c2ecf20Sopenharmony_ci#else 21438c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "inline encryption not supported"); 21448c2ecf20Sopenharmony_ci#endif 21458c2ecf20Sopenharmony_ci return 1; 21468c2ecf20Sopenharmony_ci } 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci for (m = ext4_mount_opts; m->token != Opt_err; m++) 21498c2ecf20Sopenharmony_ci if (token == m->token) 21508c2ecf20Sopenharmony_ci break; 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci if (m->token == Opt_err) { 21538c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" " 21548c2ecf20Sopenharmony_ci "or missing value", opt); 21558c2ecf20Sopenharmony_ci return -1; 21568c2ecf20Sopenharmony_ci } 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci if ((m->flags & MOPT_NO_EXT2) && IS_EXT2_SB(sb)) { 21598c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 21608c2ecf20Sopenharmony_ci "Mount option \"%s\" incompatible with ext2", opt); 21618c2ecf20Sopenharmony_ci return -1; 21628c2ecf20Sopenharmony_ci } 21638c2ecf20Sopenharmony_ci if ((m->flags & MOPT_NO_EXT3) && IS_EXT3_SB(sb)) { 21648c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 21658c2ecf20Sopenharmony_ci "Mount option \"%s\" incompatible with ext3", opt); 21668c2ecf20Sopenharmony_ci return -1; 21678c2ecf20Sopenharmony_ci } 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci if (args->from && !(m->flags & MOPT_STRING) && match_int(args, &arg)) 21708c2ecf20Sopenharmony_ci return -1; 21718c2ecf20Sopenharmony_ci if (args->from && (m->flags & MOPT_GTE0) && (arg < 0)) 21728c2ecf20Sopenharmony_ci return -1; 21738c2ecf20Sopenharmony_ci if (m->flags & MOPT_EXPLICIT) { 21748c2ecf20Sopenharmony_ci if (m->mount_opt & EXT4_MOUNT_DELALLOC) { 21758c2ecf20Sopenharmony_ci set_opt2(sb, EXPLICIT_DELALLOC); 21768c2ecf20Sopenharmony_ci } else if (m->mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) { 21778c2ecf20Sopenharmony_ci set_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM); 21788c2ecf20Sopenharmony_ci } else 21798c2ecf20Sopenharmony_ci return -1; 21808c2ecf20Sopenharmony_ci } 21818c2ecf20Sopenharmony_ci if (m->flags & MOPT_CLEAR_ERR) 21828c2ecf20Sopenharmony_ci clear_opt(sb, ERRORS_MASK); 21838c2ecf20Sopenharmony_ci if (token == Opt_noquota && sb_any_quota_loaded(sb)) { 21848c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Cannot change quota " 21858c2ecf20Sopenharmony_ci "options when quota turned on"); 21868c2ecf20Sopenharmony_ci return -1; 21878c2ecf20Sopenharmony_ci } 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci if (m->flags & MOPT_NOSUPPORT) { 21908c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "%s option not supported", opt); 21918c2ecf20Sopenharmony_ci } else if (token == Opt_commit) { 21928c2ecf20Sopenharmony_ci if (arg == 0) 21938c2ecf20Sopenharmony_ci arg = JBD2_DEFAULT_MAX_COMMIT_AGE; 21948c2ecf20Sopenharmony_ci else if (arg > INT_MAX / HZ) { 21958c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 21968c2ecf20Sopenharmony_ci "Invalid commit interval %d, " 21978c2ecf20Sopenharmony_ci "must be smaller than %d", 21988c2ecf20Sopenharmony_ci arg, INT_MAX / HZ); 21998c2ecf20Sopenharmony_ci return -1; 22008c2ecf20Sopenharmony_ci } 22018c2ecf20Sopenharmony_ci sbi->s_commit_interval = HZ * arg; 22028c2ecf20Sopenharmony_ci } else if (token == Opt_debug_want_extra_isize) { 22038c2ecf20Sopenharmony_ci if ((arg & 1) || 22048c2ecf20Sopenharmony_ci (arg < 4) || 22058c2ecf20Sopenharmony_ci (arg > (sbi->s_inode_size - EXT4_GOOD_OLD_INODE_SIZE))) { 22068c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 22078c2ecf20Sopenharmony_ci "Invalid want_extra_isize %d", arg); 22088c2ecf20Sopenharmony_ci return -1; 22098c2ecf20Sopenharmony_ci } 22108c2ecf20Sopenharmony_ci sbi->s_want_extra_isize = arg; 22118c2ecf20Sopenharmony_ci } else if (token == Opt_max_batch_time) { 22128c2ecf20Sopenharmony_ci sbi->s_max_batch_time = arg; 22138c2ecf20Sopenharmony_ci } else if (token == Opt_min_batch_time) { 22148c2ecf20Sopenharmony_ci sbi->s_min_batch_time = arg; 22158c2ecf20Sopenharmony_ci } else if (token == Opt_inode_readahead_blks) { 22168c2ecf20Sopenharmony_ci if (arg && (arg > (1 << 30) || !is_power_of_2(arg))) { 22178c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 22188c2ecf20Sopenharmony_ci "EXT4-fs: inode_readahead_blks must be " 22198c2ecf20Sopenharmony_ci "0 or a power of 2 smaller than 2^31"); 22208c2ecf20Sopenharmony_ci return -1; 22218c2ecf20Sopenharmony_ci } 22228c2ecf20Sopenharmony_ci sbi->s_inode_readahead_blks = arg; 22238c2ecf20Sopenharmony_ci } else if (token == Opt_init_itable) { 22248c2ecf20Sopenharmony_ci set_opt(sb, INIT_INODE_TABLE); 22258c2ecf20Sopenharmony_ci if (!args->from) 22268c2ecf20Sopenharmony_ci arg = EXT4_DEF_LI_WAIT_MULT; 22278c2ecf20Sopenharmony_ci sbi->s_li_wait_mult = arg; 22288c2ecf20Sopenharmony_ci } else if (token == Opt_max_dir_size_kb) { 22298c2ecf20Sopenharmony_ci sbi->s_max_dir_size_kb = arg; 22308c2ecf20Sopenharmony_ci#ifdef CONFIG_EXT4_DEBUG 22318c2ecf20Sopenharmony_ci } else if (token == Opt_fc_debug_max_replay) { 22328c2ecf20Sopenharmony_ci sbi->s_fc_debug_max_replay = arg; 22338c2ecf20Sopenharmony_ci#endif 22348c2ecf20Sopenharmony_ci } else if (token == Opt_stripe) { 22358c2ecf20Sopenharmony_ci sbi->s_stripe = arg; 22368c2ecf20Sopenharmony_ci } else if (token == Opt_resuid) { 22378c2ecf20Sopenharmony_ci uid = make_kuid(current_user_ns(), arg); 22388c2ecf20Sopenharmony_ci if (!uid_valid(uid)) { 22398c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Invalid uid value %d", arg); 22408c2ecf20Sopenharmony_ci return -1; 22418c2ecf20Sopenharmony_ci } 22428c2ecf20Sopenharmony_ci sbi->s_resuid = uid; 22438c2ecf20Sopenharmony_ci } else if (token == Opt_resgid) { 22448c2ecf20Sopenharmony_ci gid = make_kgid(current_user_ns(), arg); 22458c2ecf20Sopenharmony_ci if (!gid_valid(gid)) { 22468c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Invalid gid value %d", arg); 22478c2ecf20Sopenharmony_ci return -1; 22488c2ecf20Sopenharmony_ci } 22498c2ecf20Sopenharmony_ci sbi->s_resgid = gid; 22508c2ecf20Sopenharmony_ci } else if (token == Opt_journal_dev) { 22518c2ecf20Sopenharmony_ci if (is_remount) { 22528c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 22538c2ecf20Sopenharmony_ci "Cannot specify journal on remount"); 22548c2ecf20Sopenharmony_ci return -1; 22558c2ecf20Sopenharmony_ci } 22568c2ecf20Sopenharmony_ci *journal_devnum = arg; 22578c2ecf20Sopenharmony_ci } else if (token == Opt_journal_path) { 22588c2ecf20Sopenharmony_ci char *journal_path; 22598c2ecf20Sopenharmony_ci struct inode *journal_inode; 22608c2ecf20Sopenharmony_ci struct path path; 22618c2ecf20Sopenharmony_ci int error; 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci if (is_remount) { 22648c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 22658c2ecf20Sopenharmony_ci "Cannot specify journal on remount"); 22668c2ecf20Sopenharmony_ci return -1; 22678c2ecf20Sopenharmony_ci } 22688c2ecf20Sopenharmony_ci journal_path = match_strdup(&args[0]); 22698c2ecf20Sopenharmony_ci if (!journal_path) { 22708c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "error: could not dup " 22718c2ecf20Sopenharmony_ci "journal device string"); 22728c2ecf20Sopenharmony_ci return -1; 22738c2ecf20Sopenharmony_ci } 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci error = kern_path(journal_path, LOOKUP_FOLLOW, &path); 22768c2ecf20Sopenharmony_ci if (error) { 22778c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "error: could not find " 22788c2ecf20Sopenharmony_ci "journal device path: error %d", error); 22798c2ecf20Sopenharmony_ci kfree(journal_path); 22808c2ecf20Sopenharmony_ci return -1; 22818c2ecf20Sopenharmony_ci } 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci journal_inode = d_inode(path.dentry); 22848c2ecf20Sopenharmony_ci if (!S_ISBLK(journal_inode->i_mode)) { 22858c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "error: journal path %s " 22868c2ecf20Sopenharmony_ci "is not a block device", journal_path); 22878c2ecf20Sopenharmony_ci path_put(&path); 22888c2ecf20Sopenharmony_ci kfree(journal_path); 22898c2ecf20Sopenharmony_ci return -1; 22908c2ecf20Sopenharmony_ci } 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci *journal_devnum = new_encode_dev(journal_inode->i_rdev); 22938c2ecf20Sopenharmony_ci path_put(&path); 22948c2ecf20Sopenharmony_ci kfree(journal_path); 22958c2ecf20Sopenharmony_ci } else if (token == Opt_journal_ioprio) { 22968c2ecf20Sopenharmony_ci if (arg > 7) { 22978c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Invalid journal IO priority" 22988c2ecf20Sopenharmony_ci " (must be 0-7)"); 22998c2ecf20Sopenharmony_ci return -1; 23008c2ecf20Sopenharmony_ci } 23018c2ecf20Sopenharmony_ci *journal_ioprio = 23028c2ecf20Sopenharmony_ci IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, arg); 23038c2ecf20Sopenharmony_ci } else if (token == Opt_test_dummy_encryption) { 23048c2ecf20Sopenharmony_ci return ext4_set_test_dummy_encryption(sb, opt, &args[0], 23058c2ecf20Sopenharmony_ci is_remount); 23068c2ecf20Sopenharmony_ci } else if (m->flags & MOPT_DATAJ) { 23078c2ecf20Sopenharmony_ci if (is_remount) { 23088c2ecf20Sopenharmony_ci if (!sbi->s_journal) 23098c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, "Remounting file system with no journal so ignoring journalled data option"); 23108c2ecf20Sopenharmony_ci else if (test_opt(sb, DATA_FLAGS) != m->mount_opt) { 23118c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 23128c2ecf20Sopenharmony_ci "Cannot change data mode on remount"); 23138c2ecf20Sopenharmony_ci return -1; 23148c2ecf20Sopenharmony_ci } 23158c2ecf20Sopenharmony_ci } else { 23168c2ecf20Sopenharmony_ci clear_opt(sb, DATA_FLAGS); 23178c2ecf20Sopenharmony_ci sbi->s_mount_opt |= m->mount_opt; 23188c2ecf20Sopenharmony_ci } 23198c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 23208c2ecf20Sopenharmony_ci } else if (m->flags & MOPT_QFMT) { 23218c2ecf20Sopenharmony_ci if (sb_any_quota_loaded(sb) && 23228c2ecf20Sopenharmony_ci sbi->s_jquota_fmt != m->mount_opt) { 23238c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Cannot change journaled " 23248c2ecf20Sopenharmony_ci "quota options when quota turned on"); 23258c2ecf20Sopenharmony_ci return -1; 23268c2ecf20Sopenharmony_ci } 23278c2ecf20Sopenharmony_ci if (ext4_has_feature_quota(sb)) { 23288c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, 23298c2ecf20Sopenharmony_ci "Quota format mount options ignored " 23308c2ecf20Sopenharmony_ci "when QUOTA feature is enabled"); 23318c2ecf20Sopenharmony_ci return 1; 23328c2ecf20Sopenharmony_ci } 23338c2ecf20Sopenharmony_ci sbi->s_jquota_fmt = m->mount_opt; 23348c2ecf20Sopenharmony_ci#endif 23358c2ecf20Sopenharmony_ci } else if (token == Opt_dax || token == Opt_dax_always || 23368c2ecf20Sopenharmony_ci token == Opt_dax_inode || token == Opt_dax_never) { 23378c2ecf20Sopenharmony_ci#ifdef CONFIG_FS_DAX 23388c2ecf20Sopenharmony_ci switch (token) { 23398c2ecf20Sopenharmony_ci case Opt_dax: 23408c2ecf20Sopenharmony_ci case Opt_dax_always: 23418c2ecf20Sopenharmony_ci if (is_remount && 23428c2ecf20Sopenharmony_ci (!(sbi->s_mount_opt & EXT4_MOUNT_DAX_ALWAYS) || 23438c2ecf20Sopenharmony_ci (sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_NEVER))) { 23448c2ecf20Sopenharmony_ci fail_dax_change_remount: 23458c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "can't change " 23468c2ecf20Sopenharmony_ci "dax mount option while remounting"); 23478c2ecf20Sopenharmony_ci return -1; 23488c2ecf20Sopenharmony_ci } 23498c2ecf20Sopenharmony_ci if (is_remount && 23508c2ecf20Sopenharmony_ci (test_opt(sb, DATA_FLAGS) == 23518c2ecf20Sopenharmony_ci EXT4_MOUNT_JOURNAL_DATA)) { 23528c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "can't mount with " 23538c2ecf20Sopenharmony_ci "both data=journal and dax"); 23548c2ecf20Sopenharmony_ci return -1; 23558c2ecf20Sopenharmony_ci } 23568c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 23578c2ecf20Sopenharmony_ci "DAX enabled. Warning: EXPERIMENTAL, use at your own risk"); 23588c2ecf20Sopenharmony_ci sbi->s_mount_opt |= EXT4_MOUNT_DAX_ALWAYS; 23598c2ecf20Sopenharmony_ci sbi->s_mount_opt2 &= ~EXT4_MOUNT2_DAX_NEVER; 23608c2ecf20Sopenharmony_ci break; 23618c2ecf20Sopenharmony_ci case Opt_dax_never: 23628c2ecf20Sopenharmony_ci if (is_remount && 23638c2ecf20Sopenharmony_ci (!(sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_NEVER) || 23648c2ecf20Sopenharmony_ci (sbi->s_mount_opt & EXT4_MOUNT_DAX_ALWAYS))) 23658c2ecf20Sopenharmony_ci goto fail_dax_change_remount; 23668c2ecf20Sopenharmony_ci sbi->s_mount_opt2 |= EXT4_MOUNT2_DAX_NEVER; 23678c2ecf20Sopenharmony_ci sbi->s_mount_opt &= ~EXT4_MOUNT_DAX_ALWAYS; 23688c2ecf20Sopenharmony_ci break; 23698c2ecf20Sopenharmony_ci case Opt_dax_inode: 23708c2ecf20Sopenharmony_ci if (is_remount && 23718c2ecf20Sopenharmony_ci ((sbi->s_mount_opt & EXT4_MOUNT_DAX_ALWAYS) || 23728c2ecf20Sopenharmony_ci (sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_NEVER) || 23738c2ecf20Sopenharmony_ci !(sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_INODE))) 23748c2ecf20Sopenharmony_ci goto fail_dax_change_remount; 23758c2ecf20Sopenharmony_ci sbi->s_mount_opt &= ~EXT4_MOUNT_DAX_ALWAYS; 23768c2ecf20Sopenharmony_ci sbi->s_mount_opt2 &= ~EXT4_MOUNT2_DAX_NEVER; 23778c2ecf20Sopenharmony_ci /* Strictly for printing options */ 23788c2ecf20Sopenharmony_ci sbi->s_mount_opt2 |= EXT4_MOUNT2_DAX_INODE; 23798c2ecf20Sopenharmony_ci break; 23808c2ecf20Sopenharmony_ci } 23818c2ecf20Sopenharmony_ci#else 23828c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "dax option not supported"); 23838c2ecf20Sopenharmony_ci sbi->s_mount_opt2 |= EXT4_MOUNT2_DAX_NEVER; 23848c2ecf20Sopenharmony_ci sbi->s_mount_opt &= ~EXT4_MOUNT_DAX_ALWAYS; 23858c2ecf20Sopenharmony_ci return -1; 23868c2ecf20Sopenharmony_ci#endif 23878c2ecf20Sopenharmony_ci } else if (token == Opt_data_err_abort) { 23888c2ecf20Sopenharmony_ci sbi->s_mount_opt |= m->mount_opt; 23898c2ecf20Sopenharmony_ci } else if (token == Opt_data_err_ignore) { 23908c2ecf20Sopenharmony_ci sbi->s_mount_opt &= ~m->mount_opt; 23918c2ecf20Sopenharmony_ci } else { 23928c2ecf20Sopenharmony_ci if (!args->from) 23938c2ecf20Sopenharmony_ci arg = 1; 23948c2ecf20Sopenharmony_ci if (m->flags & MOPT_CLEAR) 23958c2ecf20Sopenharmony_ci arg = !arg; 23968c2ecf20Sopenharmony_ci else if (unlikely(!(m->flags & MOPT_SET))) { 23978c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 23988c2ecf20Sopenharmony_ci "buggy handling of option %s", opt); 23998c2ecf20Sopenharmony_ci WARN_ON(1); 24008c2ecf20Sopenharmony_ci return -1; 24018c2ecf20Sopenharmony_ci } 24028c2ecf20Sopenharmony_ci if (m->flags & MOPT_2) { 24038c2ecf20Sopenharmony_ci if (arg != 0) 24048c2ecf20Sopenharmony_ci sbi->s_mount_opt2 |= m->mount_opt; 24058c2ecf20Sopenharmony_ci else 24068c2ecf20Sopenharmony_ci sbi->s_mount_opt2 &= ~m->mount_opt; 24078c2ecf20Sopenharmony_ci } else { 24088c2ecf20Sopenharmony_ci if (arg != 0) 24098c2ecf20Sopenharmony_ci sbi->s_mount_opt |= m->mount_opt; 24108c2ecf20Sopenharmony_ci else 24118c2ecf20Sopenharmony_ci sbi->s_mount_opt &= ~m->mount_opt; 24128c2ecf20Sopenharmony_ci } 24138c2ecf20Sopenharmony_ci } 24148c2ecf20Sopenharmony_ci return 1; 24158c2ecf20Sopenharmony_ci} 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_cistatic int parse_options(char *options, struct super_block *sb, 24188c2ecf20Sopenharmony_ci unsigned long *journal_devnum, 24198c2ecf20Sopenharmony_ci unsigned int *journal_ioprio, 24208c2ecf20Sopenharmony_ci int is_remount) 24218c2ecf20Sopenharmony_ci{ 24228c2ecf20Sopenharmony_ci struct ext4_sb_info __maybe_unused *sbi = EXT4_SB(sb); 24238c2ecf20Sopenharmony_ci char *p, __maybe_unused *usr_qf_name, __maybe_unused *grp_qf_name; 24248c2ecf20Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 24258c2ecf20Sopenharmony_ci int token; 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci if (!options) 24288c2ecf20Sopenharmony_ci return 1; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci while ((p = strsep(&options, ",")) != NULL) { 24318c2ecf20Sopenharmony_ci if (!*p) 24328c2ecf20Sopenharmony_ci continue; 24338c2ecf20Sopenharmony_ci /* 24348c2ecf20Sopenharmony_ci * Initialize args struct so we know whether arg was 24358c2ecf20Sopenharmony_ci * found; some options take optional arguments. 24368c2ecf20Sopenharmony_ci */ 24378c2ecf20Sopenharmony_ci args[0].to = args[0].from = NULL; 24388c2ecf20Sopenharmony_ci token = match_token(p, tokens, args); 24398c2ecf20Sopenharmony_ci if (handle_mount_opt(sb, p, token, args, journal_devnum, 24408c2ecf20Sopenharmony_ci journal_ioprio, is_remount) < 0) 24418c2ecf20Sopenharmony_ci return 0; 24428c2ecf20Sopenharmony_ci } 24438c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 24448c2ecf20Sopenharmony_ci /* 24458c2ecf20Sopenharmony_ci * We do the test below only for project quotas. 'usrquota' and 24468c2ecf20Sopenharmony_ci * 'grpquota' mount options are allowed even without quota feature 24478c2ecf20Sopenharmony_ci * to support legacy quotas in quota files. 24488c2ecf20Sopenharmony_ci */ 24498c2ecf20Sopenharmony_ci if (test_opt(sb, PRJQUOTA) && !ext4_has_feature_project(sb)) { 24508c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Project quota feature not enabled. " 24518c2ecf20Sopenharmony_ci "Cannot enable project quota enforcement."); 24528c2ecf20Sopenharmony_ci return 0; 24538c2ecf20Sopenharmony_ci } 24548c2ecf20Sopenharmony_ci usr_qf_name = get_qf_name(sb, sbi, USRQUOTA); 24558c2ecf20Sopenharmony_ci grp_qf_name = get_qf_name(sb, sbi, GRPQUOTA); 24568c2ecf20Sopenharmony_ci if (usr_qf_name || grp_qf_name) { 24578c2ecf20Sopenharmony_ci if (test_opt(sb, USRQUOTA) && usr_qf_name) 24588c2ecf20Sopenharmony_ci clear_opt(sb, USRQUOTA); 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci if (test_opt(sb, GRPQUOTA) && grp_qf_name) 24618c2ecf20Sopenharmony_ci clear_opt(sb, GRPQUOTA); 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci if (test_opt(sb, GRPQUOTA) || test_opt(sb, USRQUOTA)) { 24648c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "old and new quota " 24658c2ecf20Sopenharmony_ci "format mixing"); 24668c2ecf20Sopenharmony_ci return 0; 24678c2ecf20Sopenharmony_ci } 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci if (!sbi->s_jquota_fmt) { 24708c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "journaled quota format " 24718c2ecf20Sopenharmony_ci "not specified"); 24728c2ecf20Sopenharmony_ci return 0; 24738c2ecf20Sopenharmony_ci } 24748c2ecf20Sopenharmony_ci } 24758c2ecf20Sopenharmony_ci#endif 24768c2ecf20Sopenharmony_ci if (test_opt(sb, DIOREAD_NOLOCK)) { 24778c2ecf20Sopenharmony_ci int blocksize = 24788c2ecf20Sopenharmony_ci BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size); 24798c2ecf20Sopenharmony_ci if (blocksize < PAGE_SIZE) 24808c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, "Warning: mounting with an " 24818c2ecf20Sopenharmony_ci "experimental mount option 'dioread_nolock' " 24828c2ecf20Sopenharmony_ci "for blocksize < PAGE_SIZE"); 24838c2ecf20Sopenharmony_ci } 24848c2ecf20Sopenharmony_ci return 1; 24858c2ecf20Sopenharmony_ci} 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_cistatic inline void ext4_show_quota_options(struct seq_file *seq, 24888c2ecf20Sopenharmony_ci struct super_block *sb) 24898c2ecf20Sopenharmony_ci{ 24908c2ecf20Sopenharmony_ci#if defined(CONFIG_QUOTA) 24918c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 24928c2ecf20Sopenharmony_ci char *usr_qf_name, *grp_qf_name; 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci if (sbi->s_jquota_fmt) { 24958c2ecf20Sopenharmony_ci char *fmtname = ""; 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci switch (sbi->s_jquota_fmt) { 24988c2ecf20Sopenharmony_ci case QFMT_VFS_OLD: 24998c2ecf20Sopenharmony_ci fmtname = "vfsold"; 25008c2ecf20Sopenharmony_ci break; 25018c2ecf20Sopenharmony_ci case QFMT_VFS_V0: 25028c2ecf20Sopenharmony_ci fmtname = "vfsv0"; 25038c2ecf20Sopenharmony_ci break; 25048c2ecf20Sopenharmony_ci case QFMT_VFS_V1: 25058c2ecf20Sopenharmony_ci fmtname = "vfsv1"; 25068c2ecf20Sopenharmony_ci break; 25078c2ecf20Sopenharmony_ci } 25088c2ecf20Sopenharmony_ci seq_printf(seq, ",jqfmt=%s", fmtname); 25098c2ecf20Sopenharmony_ci } 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_ci rcu_read_lock(); 25128c2ecf20Sopenharmony_ci usr_qf_name = rcu_dereference(sbi->s_qf_names[USRQUOTA]); 25138c2ecf20Sopenharmony_ci grp_qf_name = rcu_dereference(sbi->s_qf_names[GRPQUOTA]); 25148c2ecf20Sopenharmony_ci if (usr_qf_name) 25158c2ecf20Sopenharmony_ci seq_show_option(seq, "usrjquota", usr_qf_name); 25168c2ecf20Sopenharmony_ci if (grp_qf_name) 25178c2ecf20Sopenharmony_ci seq_show_option(seq, "grpjquota", grp_qf_name); 25188c2ecf20Sopenharmony_ci rcu_read_unlock(); 25198c2ecf20Sopenharmony_ci#endif 25208c2ecf20Sopenharmony_ci} 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_cistatic const char *token2str(int token) 25238c2ecf20Sopenharmony_ci{ 25248c2ecf20Sopenharmony_ci const struct match_token *t; 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_ci for (t = tokens; t->token != Opt_err; t++) 25278c2ecf20Sopenharmony_ci if (t->token == token && !strchr(t->pattern, '=')) 25288c2ecf20Sopenharmony_ci break; 25298c2ecf20Sopenharmony_ci return t->pattern; 25308c2ecf20Sopenharmony_ci} 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci/* 25338c2ecf20Sopenharmony_ci * Show an option if 25348c2ecf20Sopenharmony_ci * - it's set to a non-default value OR 25358c2ecf20Sopenharmony_ci * - if the per-sb default is different from the global default 25368c2ecf20Sopenharmony_ci */ 25378c2ecf20Sopenharmony_cistatic int _ext4_show_options(struct seq_file *seq, struct super_block *sb, 25388c2ecf20Sopenharmony_ci int nodefs) 25398c2ecf20Sopenharmony_ci{ 25408c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 25418c2ecf20Sopenharmony_ci struct ext4_super_block *es = sbi->s_es; 25428c2ecf20Sopenharmony_ci int def_errors, def_mount_opt = sbi->s_def_mount_opt; 25438c2ecf20Sopenharmony_ci const struct mount_opts *m; 25448c2ecf20Sopenharmony_ci char sep = nodefs ? '\n' : ','; 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci#define SEQ_OPTS_PUTS(str) seq_printf(seq, "%c" str, sep) 25478c2ecf20Sopenharmony_ci#define SEQ_OPTS_PRINT(str, arg) seq_printf(seq, "%c" str, sep, arg) 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci if (sbi->s_sb_block != 1) 25508c2ecf20Sopenharmony_ci SEQ_OPTS_PRINT("sb=%llu", sbi->s_sb_block); 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci for (m = ext4_mount_opts; m->token != Opt_err; m++) { 25538c2ecf20Sopenharmony_ci int want_set = m->flags & MOPT_SET; 25548c2ecf20Sopenharmony_ci if (((m->flags & (MOPT_SET|MOPT_CLEAR)) == 0) || 25558c2ecf20Sopenharmony_ci (m->flags & MOPT_CLEAR_ERR) || m->flags & MOPT_SKIP) 25568c2ecf20Sopenharmony_ci continue; 25578c2ecf20Sopenharmony_ci if (!nodefs && !(m->mount_opt & (sbi->s_mount_opt ^ def_mount_opt))) 25588c2ecf20Sopenharmony_ci continue; /* skip if same as the default */ 25598c2ecf20Sopenharmony_ci if ((want_set && 25608c2ecf20Sopenharmony_ci (sbi->s_mount_opt & m->mount_opt) != m->mount_opt) || 25618c2ecf20Sopenharmony_ci (!want_set && (sbi->s_mount_opt & m->mount_opt))) 25628c2ecf20Sopenharmony_ci continue; /* select Opt_noFoo vs Opt_Foo */ 25638c2ecf20Sopenharmony_ci SEQ_OPTS_PRINT("%s", token2str(m->token)); 25648c2ecf20Sopenharmony_ci } 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ci if (nodefs || !uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT4_DEF_RESUID)) || 25678c2ecf20Sopenharmony_ci le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID) 25688c2ecf20Sopenharmony_ci SEQ_OPTS_PRINT("resuid=%u", 25698c2ecf20Sopenharmony_ci from_kuid_munged(&init_user_ns, sbi->s_resuid)); 25708c2ecf20Sopenharmony_ci if (nodefs || !gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT4_DEF_RESGID)) || 25718c2ecf20Sopenharmony_ci le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID) 25728c2ecf20Sopenharmony_ci SEQ_OPTS_PRINT("resgid=%u", 25738c2ecf20Sopenharmony_ci from_kgid_munged(&init_user_ns, sbi->s_resgid)); 25748c2ecf20Sopenharmony_ci def_errors = nodefs ? -1 : le16_to_cpu(es->s_errors); 25758c2ecf20Sopenharmony_ci if (test_opt(sb, ERRORS_RO) && def_errors != EXT4_ERRORS_RO) 25768c2ecf20Sopenharmony_ci SEQ_OPTS_PUTS("errors=remount-ro"); 25778c2ecf20Sopenharmony_ci if (test_opt(sb, ERRORS_CONT) && def_errors != EXT4_ERRORS_CONTINUE) 25788c2ecf20Sopenharmony_ci SEQ_OPTS_PUTS("errors=continue"); 25798c2ecf20Sopenharmony_ci if (test_opt(sb, ERRORS_PANIC) && def_errors != EXT4_ERRORS_PANIC) 25808c2ecf20Sopenharmony_ci SEQ_OPTS_PUTS("errors=panic"); 25818c2ecf20Sopenharmony_ci if (nodefs || sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) 25828c2ecf20Sopenharmony_ci SEQ_OPTS_PRINT("commit=%lu", sbi->s_commit_interval / HZ); 25838c2ecf20Sopenharmony_ci if (nodefs || sbi->s_min_batch_time != EXT4_DEF_MIN_BATCH_TIME) 25848c2ecf20Sopenharmony_ci SEQ_OPTS_PRINT("min_batch_time=%u", sbi->s_min_batch_time); 25858c2ecf20Sopenharmony_ci if (nodefs || sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME) 25868c2ecf20Sopenharmony_ci SEQ_OPTS_PRINT("max_batch_time=%u", sbi->s_max_batch_time); 25878c2ecf20Sopenharmony_ci if (sb->s_flags & SB_I_VERSION) 25888c2ecf20Sopenharmony_ci SEQ_OPTS_PUTS("i_version"); 25898c2ecf20Sopenharmony_ci if (nodefs || sbi->s_stripe) 25908c2ecf20Sopenharmony_ci SEQ_OPTS_PRINT("stripe=%lu", sbi->s_stripe); 25918c2ecf20Sopenharmony_ci if (nodefs || EXT4_MOUNT_DATA_FLAGS & 25928c2ecf20Sopenharmony_ci (sbi->s_mount_opt ^ def_mount_opt)) { 25938c2ecf20Sopenharmony_ci if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) 25948c2ecf20Sopenharmony_ci SEQ_OPTS_PUTS("data=journal"); 25958c2ecf20Sopenharmony_ci else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) 25968c2ecf20Sopenharmony_ci SEQ_OPTS_PUTS("data=ordered"); 25978c2ecf20Sopenharmony_ci else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) 25988c2ecf20Sopenharmony_ci SEQ_OPTS_PUTS("data=writeback"); 25998c2ecf20Sopenharmony_ci } 26008c2ecf20Sopenharmony_ci if (nodefs || 26018c2ecf20Sopenharmony_ci sbi->s_inode_readahead_blks != EXT4_DEF_INODE_READAHEAD_BLKS) 26028c2ecf20Sopenharmony_ci SEQ_OPTS_PRINT("inode_readahead_blks=%u", 26038c2ecf20Sopenharmony_ci sbi->s_inode_readahead_blks); 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci if (test_opt(sb, INIT_INODE_TABLE) && (nodefs || 26068c2ecf20Sopenharmony_ci (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT))) 26078c2ecf20Sopenharmony_ci SEQ_OPTS_PRINT("init_itable=%u", sbi->s_li_wait_mult); 26088c2ecf20Sopenharmony_ci if (nodefs || sbi->s_max_dir_size_kb) 26098c2ecf20Sopenharmony_ci SEQ_OPTS_PRINT("max_dir_size_kb=%u", sbi->s_max_dir_size_kb); 26108c2ecf20Sopenharmony_ci if (test_opt(sb, DATA_ERR_ABORT)) 26118c2ecf20Sopenharmony_ci SEQ_OPTS_PUTS("data_err=abort"); 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci fscrypt_show_test_dummy_encryption(seq, sep, sb); 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci if (sb->s_flags & SB_INLINECRYPT) 26168c2ecf20Sopenharmony_ci SEQ_OPTS_PUTS("inlinecrypt"); 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ci if (test_opt(sb, DAX_ALWAYS)) { 26198c2ecf20Sopenharmony_ci if (IS_EXT2_SB(sb)) 26208c2ecf20Sopenharmony_ci SEQ_OPTS_PUTS("dax"); 26218c2ecf20Sopenharmony_ci else 26228c2ecf20Sopenharmony_ci SEQ_OPTS_PUTS("dax=always"); 26238c2ecf20Sopenharmony_ci } else if (test_opt2(sb, DAX_NEVER)) { 26248c2ecf20Sopenharmony_ci SEQ_OPTS_PUTS("dax=never"); 26258c2ecf20Sopenharmony_ci } else if (test_opt2(sb, DAX_INODE)) { 26268c2ecf20Sopenharmony_ci SEQ_OPTS_PUTS("dax=inode"); 26278c2ecf20Sopenharmony_ci } 26288c2ecf20Sopenharmony_ci ext4_show_quota_options(seq, sb); 26298c2ecf20Sopenharmony_ci return 0; 26308c2ecf20Sopenharmony_ci} 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_cistatic int ext4_show_options(struct seq_file *seq, struct dentry *root) 26338c2ecf20Sopenharmony_ci{ 26348c2ecf20Sopenharmony_ci return _ext4_show_options(seq, root->d_sb, 0); 26358c2ecf20Sopenharmony_ci} 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ciint ext4_seq_options_show(struct seq_file *seq, void *offset) 26388c2ecf20Sopenharmony_ci{ 26398c2ecf20Sopenharmony_ci struct super_block *sb = seq->private; 26408c2ecf20Sopenharmony_ci int rc; 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci seq_puts(seq, sb_rdonly(sb) ? "ro" : "rw"); 26438c2ecf20Sopenharmony_ci rc = _ext4_show_options(seq, sb, 1); 26448c2ecf20Sopenharmony_ci seq_puts(seq, "\n"); 26458c2ecf20Sopenharmony_ci return rc; 26468c2ecf20Sopenharmony_ci} 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_cistatic int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, 26498c2ecf20Sopenharmony_ci int read_only) 26508c2ecf20Sopenharmony_ci{ 26518c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 26528c2ecf20Sopenharmony_ci int err = 0; 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci if (le32_to_cpu(es->s_rev_level) > EXT4_MAX_SUPP_REV) { 26558c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "revision level too high, " 26568c2ecf20Sopenharmony_ci "forcing read-only mode"); 26578c2ecf20Sopenharmony_ci err = -EROFS; 26588c2ecf20Sopenharmony_ci goto done; 26598c2ecf20Sopenharmony_ci } 26608c2ecf20Sopenharmony_ci if (read_only) 26618c2ecf20Sopenharmony_ci goto done; 26628c2ecf20Sopenharmony_ci if (!(sbi->s_mount_state & EXT4_VALID_FS)) 26638c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, "warning: mounting unchecked fs, " 26648c2ecf20Sopenharmony_ci "running e2fsck is recommended"); 26658c2ecf20Sopenharmony_ci else if (sbi->s_mount_state & EXT4_ERROR_FS) 26668c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 26678c2ecf20Sopenharmony_ci "warning: mounting fs with errors, " 26688c2ecf20Sopenharmony_ci "running e2fsck is recommended"); 26698c2ecf20Sopenharmony_ci else if ((__s16) le16_to_cpu(es->s_max_mnt_count) > 0 && 26708c2ecf20Sopenharmony_ci le16_to_cpu(es->s_mnt_count) >= 26718c2ecf20Sopenharmony_ci (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) 26728c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 26738c2ecf20Sopenharmony_ci "warning: maximal mount count reached, " 26748c2ecf20Sopenharmony_ci "running e2fsck is recommended"); 26758c2ecf20Sopenharmony_ci else if (le32_to_cpu(es->s_checkinterval) && 26768c2ecf20Sopenharmony_ci (ext4_get_tstamp(es, s_lastcheck) + 26778c2ecf20Sopenharmony_ci le32_to_cpu(es->s_checkinterval) <= ktime_get_real_seconds())) 26788c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 26798c2ecf20Sopenharmony_ci "warning: checktime reached, " 26808c2ecf20Sopenharmony_ci "running e2fsck is recommended"); 26818c2ecf20Sopenharmony_ci if (!sbi->s_journal) 26828c2ecf20Sopenharmony_ci es->s_state &= cpu_to_le16(~EXT4_VALID_FS); 26838c2ecf20Sopenharmony_ci if (!(__s16) le16_to_cpu(es->s_max_mnt_count)) 26848c2ecf20Sopenharmony_ci es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT); 26858c2ecf20Sopenharmony_ci le16_add_cpu(&es->s_mnt_count, 1); 26868c2ecf20Sopenharmony_ci ext4_update_tstamp(es, s_mtime); 26878c2ecf20Sopenharmony_ci if (sbi->s_journal) 26888c2ecf20Sopenharmony_ci ext4_set_feature_journal_needs_recovery(sb); 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci err = ext4_commit_super(sb); 26918c2ecf20Sopenharmony_cidone: 26928c2ecf20Sopenharmony_ci if (test_opt(sb, DEBUG)) 26938c2ecf20Sopenharmony_ci printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%u, " 26948c2ecf20Sopenharmony_ci "bpg=%lu, ipg=%lu, mo=%04x, mo2=%04x]\n", 26958c2ecf20Sopenharmony_ci sb->s_blocksize, 26968c2ecf20Sopenharmony_ci sbi->s_groups_count, 26978c2ecf20Sopenharmony_ci EXT4_BLOCKS_PER_GROUP(sb), 26988c2ecf20Sopenharmony_ci EXT4_INODES_PER_GROUP(sb), 26998c2ecf20Sopenharmony_ci sbi->s_mount_opt, sbi->s_mount_opt2); 27008c2ecf20Sopenharmony_ci 27018c2ecf20Sopenharmony_ci cleancache_init_fs(sb); 27028c2ecf20Sopenharmony_ci return err; 27038c2ecf20Sopenharmony_ci} 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ciint ext4_alloc_flex_bg_array(struct super_block *sb, ext4_group_t ngroup) 27068c2ecf20Sopenharmony_ci{ 27078c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 27088c2ecf20Sopenharmony_ci struct flex_groups **old_groups, **new_groups; 27098c2ecf20Sopenharmony_ci int size, i, j; 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci if (!sbi->s_log_groups_per_flex) 27128c2ecf20Sopenharmony_ci return 0; 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci size = ext4_flex_group(sbi, ngroup - 1) + 1; 27158c2ecf20Sopenharmony_ci if (size <= sbi->s_flex_groups_allocated) 27168c2ecf20Sopenharmony_ci return 0; 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci new_groups = kvzalloc(roundup_pow_of_two(size * 27198c2ecf20Sopenharmony_ci sizeof(*sbi->s_flex_groups)), GFP_KERNEL); 27208c2ecf20Sopenharmony_ci if (!new_groups) { 27218c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 27228c2ecf20Sopenharmony_ci "not enough memory for %d flex group pointers", size); 27238c2ecf20Sopenharmony_ci return -ENOMEM; 27248c2ecf20Sopenharmony_ci } 27258c2ecf20Sopenharmony_ci for (i = sbi->s_flex_groups_allocated; i < size; i++) { 27268c2ecf20Sopenharmony_ci new_groups[i] = kvzalloc(roundup_pow_of_two( 27278c2ecf20Sopenharmony_ci sizeof(struct flex_groups)), 27288c2ecf20Sopenharmony_ci GFP_KERNEL); 27298c2ecf20Sopenharmony_ci if (!new_groups[i]) { 27308c2ecf20Sopenharmony_ci for (j = sbi->s_flex_groups_allocated; j < i; j++) 27318c2ecf20Sopenharmony_ci kvfree(new_groups[j]); 27328c2ecf20Sopenharmony_ci kvfree(new_groups); 27338c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 27348c2ecf20Sopenharmony_ci "not enough memory for %d flex groups", size); 27358c2ecf20Sopenharmony_ci return -ENOMEM; 27368c2ecf20Sopenharmony_ci } 27378c2ecf20Sopenharmony_ci } 27388c2ecf20Sopenharmony_ci rcu_read_lock(); 27398c2ecf20Sopenharmony_ci old_groups = rcu_dereference(sbi->s_flex_groups); 27408c2ecf20Sopenharmony_ci if (old_groups) 27418c2ecf20Sopenharmony_ci memcpy(new_groups, old_groups, 27428c2ecf20Sopenharmony_ci (sbi->s_flex_groups_allocated * 27438c2ecf20Sopenharmony_ci sizeof(struct flex_groups *))); 27448c2ecf20Sopenharmony_ci rcu_read_unlock(); 27458c2ecf20Sopenharmony_ci rcu_assign_pointer(sbi->s_flex_groups, new_groups); 27468c2ecf20Sopenharmony_ci sbi->s_flex_groups_allocated = size; 27478c2ecf20Sopenharmony_ci if (old_groups) 27488c2ecf20Sopenharmony_ci ext4_kvfree_array_rcu(old_groups); 27498c2ecf20Sopenharmony_ci return 0; 27508c2ecf20Sopenharmony_ci} 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_cistatic int ext4_fill_flex_info(struct super_block *sb) 27538c2ecf20Sopenharmony_ci{ 27548c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 27558c2ecf20Sopenharmony_ci struct ext4_group_desc *gdp = NULL; 27568c2ecf20Sopenharmony_ci struct flex_groups *fg; 27578c2ecf20Sopenharmony_ci ext4_group_t flex_group; 27588c2ecf20Sopenharmony_ci int i, err; 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex; 27618c2ecf20Sopenharmony_ci if (sbi->s_log_groups_per_flex < 1 || sbi->s_log_groups_per_flex > 31) { 27628c2ecf20Sopenharmony_ci sbi->s_log_groups_per_flex = 0; 27638c2ecf20Sopenharmony_ci return 1; 27648c2ecf20Sopenharmony_ci } 27658c2ecf20Sopenharmony_ci 27668c2ecf20Sopenharmony_ci err = ext4_alloc_flex_bg_array(sb, sbi->s_groups_count); 27678c2ecf20Sopenharmony_ci if (err) 27688c2ecf20Sopenharmony_ci goto failed; 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_groups_count; i++) { 27718c2ecf20Sopenharmony_ci gdp = ext4_get_group_desc(sb, i, NULL); 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_ci flex_group = ext4_flex_group(sbi, i); 27748c2ecf20Sopenharmony_ci fg = sbi_array_rcu_deref(sbi, s_flex_groups, flex_group); 27758c2ecf20Sopenharmony_ci atomic_add(ext4_free_inodes_count(sb, gdp), &fg->free_inodes); 27768c2ecf20Sopenharmony_ci atomic64_add(ext4_free_group_clusters(sb, gdp), 27778c2ecf20Sopenharmony_ci &fg->free_clusters); 27788c2ecf20Sopenharmony_ci atomic_add(ext4_used_dirs_count(sb, gdp), &fg->used_dirs); 27798c2ecf20Sopenharmony_ci } 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci return 1; 27828c2ecf20Sopenharmony_cifailed: 27838c2ecf20Sopenharmony_ci return 0; 27848c2ecf20Sopenharmony_ci} 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_cistatic __le16 ext4_group_desc_csum(struct super_block *sb, __u32 block_group, 27878c2ecf20Sopenharmony_ci struct ext4_group_desc *gdp) 27888c2ecf20Sopenharmony_ci{ 27898c2ecf20Sopenharmony_ci int offset = offsetof(struct ext4_group_desc, bg_checksum); 27908c2ecf20Sopenharmony_ci __u16 crc = 0; 27918c2ecf20Sopenharmony_ci __le32 le_group = cpu_to_le32(block_group); 27928c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_ci if (ext4_has_metadata_csum(sbi->s_sb)) { 27958c2ecf20Sopenharmony_ci /* Use new metadata_csum algorithm */ 27968c2ecf20Sopenharmony_ci __u32 csum32; 27978c2ecf20Sopenharmony_ci __u16 dummy_csum = 0; 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci csum32 = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&le_group, 28008c2ecf20Sopenharmony_ci sizeof(le_group)); 28018c2ecf20Sopenharmony_ci csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp, offset); 28028c2ecf20Sopenharmony_ci csum32 = ext4_chksum(sbi, csum32, (__u8 *)&dummy_csum, 28038c2ecf20Sopenharmony_ci sizeof(dummy_csum)); 28048c2ecf20Sopenharmony_ci offset += sizeof(dummy_csum); 28058c2ecf20Sopenharmony_ci if (offset < sbi->s_desc_size) 28068c2ecf20Sopenharmony_ci csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp + offset, 28078c2ecf20Sopenharmony_ci sbi->s_desc_size - offset); 28088c2ecf20Sopenharmony_ci 28098c2ecf20Sopenharmony_ci crc = csum32 & 0xFFFF; 28108c2ecf20Sopenharmony_ci goto out; 28118c2ecf20Sopenharmony_ci } 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci /* old crc16 code */ 28148c2ecf20Sopenharmony_ci if (!ext4_has_feature_gdt_csum(sb)) 28158c2ecf20Sopenharmony_ci return 0; 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid)); 28188c2ecf20Sopenharmony_ci crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group)); 28198c2ecf20Sopenharmony_ci crc = crc16(crc, (__u8 *)gdp, offset); 28208c2ecf20Sopenharmony_ci offset += sizeof(gdp->bg_checksum); /* skip checksum */ 28218c2ecf20Sopenharmony_ci /* for checksum of struct ext4_group_desc do the rest...*/ 28228c2ecf20Sopenharmony_ci if (ext4_has_feature_64bit(sb) && offset < sbi->s_desc_size) 28238c2ecf20Sopenharmony_ci crc = crc16(crc, (__u8 *)gdp + offset, 28248c2ecf20Sopenharmony_ci sbi->s_desc_size - offset); 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ciout: 28278c2ecf20Sopenharmony_ci return cpu_to_le16(crc); 28288c2ecf20Sopenharmony_ci} 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_ciint ext4_group_desc_csum_verify(struct super_block *sb, __u32 block_group, 28318c2ecf20Sopenharmony_ci struct ext4_group_desc *gdp) 28328c2ecf20Sopenharmony_ci{ 28338c2ecf20Sopenharmony_ci if (ext4_has_group_desc_csum(sb) && 28348c2ecf20Sopenharmony_ci (gdp->bg_checksum != ext4_group_desc_csum(sb, block_group, gdp))) 28358c2ecf20Sopenharmony_ci return 0; 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ci return 1; 28388c2ecf20Sopenharmony_ci} 28398c2ecf20Sopenharmony_ci 28408c2ecf20Sopenharmony_civoid ext4_group_desc_csum_set(struct super_block *sb, __u32 block_group, 28418c2ecf20Sopenharmony_ci struct ext4_group_desc *gdp) 28428c2ecf20Sopenharmony_ci{ 28438c2ecf20Sopenharmony_ci if (!ext4_has_group_desc_csum(sb)) 28448c2ecf20Sopenharmony_ci return; 28458c2ecf20Sopenharmony_ci gdp->bg_checksum = ext4_group_desc_csum(sb, block_group, gdp); 28468c2ecf20Sopenharmony_ci} 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci/* Called at mount-time, super-block is locked */ 28498c2ecf20Sopenharmony_cistatic int ext4_check_descriptors(struct super_block *sb, 28508c2ecf20Sopenharmony_ci ext4_fsblk_t sb_block, 28518c2ecf20Sopenharmony_ci ext4_group_t *first_not_zeroed) 28528c2ecf20Sopenharmony_ci{ 28538c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 28548c2ecf20Sopenharmony_ci ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); 28558c2ecf20Sopenharmony_ci ext4_fsblk_t last_block; 28568c2ecf20Sopenharmony_ci ext4_fsblk_t last_bg_block = sb_block + ext4_bg_num_gdb(sb, 0); 28578c2ecf20Sopenharmony_ci ext4_fsblk_t block_bitmap; 28588c2ecf20Sopenharmony_ci ext4_fsblk_t inode_bitmap; 28598c2ecf20Sopenharmony_ci ext4_fsblk_t inode_table; 28608c2ecf20Sopenharmony_ci int flexbg_flag = 0; 28618c2ecf20Sopenharmony_ci ext4_group_t i, grp = sbi->s_groups_count; 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ci if (ext4_has_feature_flex_bg(sb)) 28648c2ecf20Sopenharmony_ci flexbg_flag = 1; 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci ext4_debug("Checking group descriptors"); 28678c2ecf20Sopenharmony_ci 28688c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_groups_count; i++) { 28698c2ecf20Sopenharmony_ci struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL); 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_ci if (i == sbi->s_groups_count - 1 || flexbg_flag) 28728c2ecf20Sopenharmony_ci last_block = ext4_blocks_count(sbi->s_es) - 1; 28738c2ecf20Sopenharmony_ci else 28748c2ecf20Sopenharmony_ci last_block = first_block + 28758c2ecf20Sopenharmony_ci (EXT4_BLOCKS_PER_GROUP(sb) - 1); 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_ci if ((grp == sbi->s_groups_count) && 28788c2ecf20Sopenharmony_ci !(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))) 28798c2ecf20Sopenharmony_ci grp = i; 28808c2ecf20Sopenharmony_ci 28818c2ecf20Sopenharmony_ci block_bitmap = ext4_block_bitmap(sb, gdp); 28828c2ecf20Sopenharmony_ci if (block_bitmap == sb_block) { 28838c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " 28848c2ecf20Sopenharmony_ci "Block bitmap for group %u overlaps " 28858c2ecf20Sopenharmony_ci "superblock", i); 28868c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) 28878c2ecf20Sopenharmony_ci return 0; 28888c2ecf20Sopenharmony_ci } 28898c2ecf20Sopenharmony_ci if (block_bitmap >= sb_block + 1 && 28908c2ecf20Sopenharmony_ci block_bitmap <= last_bg_block) { 28918c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " 28928c2ecf20Sopenharmony_ci "Block bitmap for group %u overlaps " 28938c2ecf20Sopenharmony_ci "block group descriptors", i); 28948c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) 28958c2ecf20Sopenharmony_ci return 0; 28968c2ecf20Sopenharmony_ci } 28978c2ecf20Sopenharmony_ci if (block_bitmap < first_block || block_bitmap > last_block) { 28988c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " 28998c2ecf20Sopenharmony_ci "Block bitmap for group %u not in group " 29008c2ecf20Sopenharmony_ci "(block %llu)!", i, block_bitmap); 29018c2ecf20Sopenharmony_ci return 0; 29028c2ecf20Sopenharmony_ci } 29038c2ecf20Sopenharmony_ci inode_bitmap = ext4_inode_bitmap(sb, gdp); 29048c2ecf20Sopenharmony_ci if (inode_bitmap == sb_block) { 29058c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " 29068c2ecf20Sopenharmony_ci "Inode bitmap for group %u overlaps " 29078c2ecf20Sopenharmony_ci "superblock", i); 29088c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) 29098c2ecf20Sopenharmony_ci return 0; 29108c2ecf20Sopenharmony_ci } 29118c2ecf20Sopenharmony_ci if (inode_bitmap >= sb_block + 1 && 29128c2ecf20Sopenharmony_ci inode_bitmap <= last_bg_block) { 29138c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " 29148c2ecf20Sopenharmony_ci "Inode bitmap for group %u overlaps " 29158c2ecf20Sopenharmony_ci "block group descriptors", i); 29168c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) 29178c2ecf20Sopenharmony_ci return 0; 29188c2ecf20Sopenharmony_ci } 29198c2ecf20Sopenharmony_ci if (inode_bitmap < first_block || inode_bitmap > last_block) { 29208c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " 29218c2ecf20Sopenharmony_ci "Inode bitmap for group %u not in group " 29228c2ecf20Sopenharmony_ci "(block %llu)!", i, inode_bitmap); 29238c2ecf20Sopenharmony_ci return 0; 29248c2ecf20Sopenharmony_ci } 29258c2ecf20Sopenharmony_ci inode_table = ext4_inode_table(sb, gdp); 29268c2ecf20Sopenharmony_ci if (inode_table == sb_block) { 29278c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " 29288c2ecf20Sopenharmony_ci "Inode table for group %u overlaps " 29298c2ecf20Sopenharmony_ci "superblock", i); 29308c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) 29318c2ecf20Sopenharmony_ci return 0; 29328c2ecf20Sopenharmony_ci } 29338c2ecf20Sopenharmony_ci if (inode_table >= sb_block + 1 && 29348c2ecf20Sopenharmony_ci inode_table <= last_bg_block) { 29358c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " 29368c2ecf20Sopenharmony_ci "Inode table for group %u overlaps " 29378c2ecf20Sopenharmony_ci "block group descriptors", i); 29388c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) 29398c2ecf20Sopenharmony_ci return 0; 29408c2ecf20Sopenharmony_ci } 29418c2ecf20Sopenharmony_ci if (inode_table < first_block || 29428c2ecf20Sopenharmony_ci inode_table + sbi->s_itb_per_group - 1 > last_block) { 29438c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " 29448c2ecf20Sopenharmony_ci "Inode table for group %u not in group " 29458c2ecf20Sopenharmony_ci "(block %llu)!", i, inode_table); 29468c2ecf20Sopenharmony_ci return 0; 29478c2ecf20Sopenharmony_ci } 29488c2ecf20Sopenharmony_ci ext4_lock_group(sb, i); 29498c2ecf20Sopenharmony_ci if (!ext4_group_desc_csum_verify(sb, i, gdp)) { 29508c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " 29518c2ecf20Sopenharmony_ci "Checksum for group %u failed (%u!=%u)", 29528c2ecf20Sopenharmony_ci i, le16_to_cpu(ext4_group_desc_csum(sb, i, 29538c2ecf20Sopenharmony_ci gdp)), le16_to_cpu(gdp->bg_checksum)); 29548c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) { 29558c2ecf20Sopenharmony_ci ext4_unlock_group(sb, i); 29568c2ecf20Sopenharmony_ci return 0; 29578c2ecf20Sopenharmony_ci } 29588c2ecf20Sopenharmony_ci } 29598c2ecf20Sopenharmony_ci ext4_unlock_group(sb, i); 29608c2ecf20Sopenharmony_ci if (!flexbg_flag) 29618c2ecf20Sopenharmony_ci first_block += EXT4_BLOCKS_PER_GROUP(sb); 29628c2ecf20Sopenharmony_ci } 29638c2ecf20Sopenharmony_ci if (NULL != first_not_zeroed) 29648c2ecf20Sopenharmony_ci *first_not_zeroed = grp; 29658c2ecf20Sopenharmony_ci return 1; 29668c2ecf20Sopenharmony_ci} 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ci/* ext4_orphan_cleanup() walks a singly-linked list of inodes (starting at 29698c2ecf20Sopenharmony_ci * the superblock) which were deleted from all directories, but held open by 29708c2ecf20Sopenharmony_ci * a process at the time of a crash. We walk the list and try to delete these 29718c2ecf20Sopenharmony_ci * inodes at recovery time (only with a read-write filesystem). 29728c2ecf20Sopenharmony_ci * 29738c2ecf20Sopenharmony_ci * In order to keep the orphan inode chain consistent during traversal (in 29748c2ecf20Sopenharmony_ci * case of crash during recovery), we link each inode into the superblock 29758c2ecf20Sopenharmony_ci * orphan list_head and handle it the same way as an inode deletion during 29768c2ecf20Sopenharmony_ci * normal operation (which journals the operations for us). 29778c2ecf20Sopenharmony_ci * 29788c2ecf20Sopenharmony_ci * We only do an iget() and an iput() on each inode, which is very safe if we 29798c2ecf20Sopenharmony_ci * accidentally point at an in-use or already deleted inode. The worst that 29808c2ecf20Sopenharmony_ci * can happen in this case is that we get a "bit already cleared" message from 29818c2ecf20Sopenharmony_ci * ext4_free_inode(). The only reason we would point at a wrong inode is if 29828c2ecf20Sopenharmony_ci * e2fsck was run on this filesystem, and it must have already done the orphan 29838c2ecf20Sopenharmony_ci * inode cleanup for us, so we can safely abort without any further action. 29848c2ecf20Sopenharmony_ci */ 29858c2ecf20Sopenharmony_cistatic void ext4_orphan_cleanup(struct super_block *sb, 29868c2ecf20Sopenharmony_ci struct ext4_super_block *es) 29878c2ecf20Sopenharmony_ci{ 29888c2ecf20Sopenharmony_ci unsigned int s_flags = sb->s_flags; 29898c2ecf20Sopenharmony_ci int ret, nr_orphans = 0, nr_truncates = 0; 29908c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 29918c2ecf20Sopenharmony_ci int quota_update = 0; 29928c2ecf20Sopenharmony_ci int i; 29938c2ecf20Sopenharmony_ci#endif 29948c2ecf20Sopenharmony_ci if (!es->s_last_orphan) { 29958c2ecf20Sopenharmony_ci jbd_debug(4, "no orphan inodes to clean up\n"); 29968c2ecf20Sopenharmony_ci return; 29978c2ecf20Sopenharmony_ci } 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ci if (bdev_read_only(sb->s_bdev)) { 30008c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "write access " 30018c2ecf20Sopenharmony_ci "unavailable, skipping orphan cleanup"); 30028c2ecf20Sopenharmony_ci return; 30038c2ecf20Sopenharmony_ci } 30048c2ecf20Sopenharmony_ci 30058c2ecf20Sopenharmony_ci /* Check if feature set would not allow a r/w mount */ 30068c2ecf20Sopenharmony_ci if (!ext4_feature_set_ok(sb, 0)) { 30078c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "Skipping orphan cleanup due to " 30088c2ecf20Sopenharmony_ci "unknown ROCOMPAT features"); 30098c2ecf20Sopenharmony_ci return; 30108c2ecf20Sopenharmony_ci } 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) { 30138c2ecf20Sopenharmony_ci /* don't clear list on RO mount w/ errors */ 30148c2ecf20Sopenharmony_ci if (es->s_last_orphan && !(s_flags & SB_RDONLY)) { 30158c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "Errors on filesystem, " 30168c2ecf20Sopenharmony_ci "clearing orphan list.\n"); 30178c2ecf20Sopenharmony_ci es->s_last_orphan = 0; 30188c2ecf20Sopenharmony_ci } 30198c2ecf20Sopenharmony_ci jbd_debug(1, "Skipping orphan recovery on fs with errors.\n"); 30208c2ecf20Sopenharmony_ci return; 30218c2ecf20Sopenharmony_ci } 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_ci if (s_flags & SB_RDONLY) { 30248c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "orphan cleanup on readonly fs"); 30258c2ecf20Sopenharmony_ci sb->s_flags &= ~SB_RDONLY; 30268c2ecf20Sopenharmony_ci } 30278c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 30288c2ecf20Sopenharmony_ci /* 30298c2ecf20Sopenharmony_ci * Turn on quotas which were not enabled for read-only mounts if 30308c2ecf20Sopenharmony_ci * filesystem has quota feature, so that they are updated correctly. 30318c2ecf20Sopenharmony_ci */ 30328c2ecf20Sopenharmony_ci if (ext4_has_feature_quota(sb) && (s_flags & SB_RDONLY)) { 30338c2ecf20Sopenharmony_ci int ret = ext4_enable_quotas(sb); 30348c2ecf20Sopenharmony_ci 30358c2ecf20Sopenharmony_ci if (!ret) 30368c2ecf20Sopenharmony_ci quota_update = 1; 30378c2ecf20Sopenharmony_ci else 30388c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 30398c2ecf20Sopenharmony_ci "Cannot turn on quotas: error %d", ret); 30408c2ecf20Sopenharmony_ci } 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci /* Turn on journaled quotas used for old sytle */ 30438c2ecf20Sopenharmony_ci for (i = 0; i < EXT4_MAXQUOTAS; i++) { 30448c2ecf20Sopenharmony_ci if (EXT4_SB(sb)->s_qf_names[i]) { 30458c2ecf20Sopenharmony_ci int ret = ext4_quota_on_mount(sb, i); 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_ci if (!ret) 30488c2ecf20Sopenharmony_ci quota_update = 1; 30498c2ecf20Sopenharmony_ci else 30508c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 30518c2ecf20Sopenharmony_ci "Cannot turn on journaled " 30528c2ecf20Sopenharmony_ci "quota: type %d: error %d", i, ret); 30538c2ecf20Sopenharmony_ci } 30548c2ecf20Sopenharmony_ci } 30558c2ecf20Sopenharmony_ci#endif 30568c2ecf20Sopenharmony_ci 30578c2ecf20Sopenharmony_ci while (es->s_last_orphan) { 30588c2ecf20Sopenharmony_ci struct inode *inode; 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_ci /* 30618c2ecf20Sopenharmony_ci * We may have encountered an error during cleanup; if 30628c2ecf20Sopenharmony_ci * so, skip the rest. 30638c2ecf20Sopenharmony_ci */ 30648c2ecf20Sopenharmony_ci if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) { 30658c2ecf20Sopenharmony_ci jbd_debug(1, "Skipping orphan recovery on fs with errors.\n"); 30668c2ecf20Sopenharmony_ci es->s_last_orphan = 0; 30678c2ecf20Sopenharmony_ci break; 30688c2ecf20Sopenharmony_ci } 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci inode = ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan)); 30718c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 30728c2ecf20Sopenharmony_ci es->s_last_orphan = 0; 30738c2ecf20Sopenharmony_ci break; 30748c2ecf20Sopenharmony_ci } 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_ci list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan); 30778c2ecf20Sopenharmony_ci dquot_initialize(inode); 30788c2ecf20Sopenharmony_ci if (inode->i_nlink) { 30798c2ecf20Sopenharmony_ci if (test_opt(sb, DEBUG)) 30808c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_DEBUG, 30818c2ecf20Sopenharmony_ci "%s: truncating inode %lu to %lld bytes", 30828c2ecf20Sopenharmony_ci __func__, inode->i_ino, inode->i_size); 30838c2ecf20Sopenharmony_ci jbd_debug(2, "truncating inode %lu to %lld bytes\n", 30848c2ecf20Sopenharmony_ci inode->i_ino, inode->i_size); 30858c2ecf20Sopenharmony_ci inode_lock(inode); 30868c2ecf20Sopenharmony_ci truncate_inode_pages(inode->i_mapping, inode->i_size); 30878c2ecf20Sopenharmony_ci ret = ext4_truncate(inode); 30888c2ecf20Sopenharmony_ci if (ret) { 30898c2ecf20Sopenharmony_ci /* 30908c2ecf20Sopenharmony_ci * We need to clean up the in-core orphan list 30918c2ecf20Sopenharmony_ci * manually if ext4_truncate() failed to get a 30928c2ecf20Sopenharmony_ci * transaction handle. 30938c2ecf20Sopenharmony_ci */ 30948c2ecf20Sopenharmony_ci ext4_orphan_del(NULL, inode); 30958c2ecf20Sopenharmony_ci ext4_std_error(inode->i_sb, ret); 30968c2ecf20Sopenharmony_ci } 30978c2ecf20Sopenharmony_ci inode_unlock(inode); 30988c2ecf20Sopenharmony_ci nr_truncates++; 30998c2ecf20Sopenharmony_ci } else { 31008c2ecf20Sopenharmony_ci if (test_opt(sb, DEBUG)) 31018c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_DEBUG, 31028c2ecf20Sopenharmony_ci "%s: deleting unreferenced inode %lu", 31038c2ecf20Sopenharmony_ci __func__, inode->i_ino); 31048c2ecf20Sopenharmony_ci jbd_debug(2, "deleting unreferenced inode %lu\n", 31058c2ecf20Sopenharmony_ci inode->i_ino); 31068c2ecf20Sopenharmony_ci nr_orphans++; 31078c2ecf20Sopenharmony_ci } 31088c2ecf20Sopenharmony_ci iput(inode); /* The delete magic happens here! */ 31098c2ecf20Sopenharmony_ci } 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_ci#define PLURAL(x) (x), ((x) == 1) ? "" : "s" 31128c2ecf20Sopenharmony_ci 31138c2ecf20Sopenharmony_ci if (nr_orphans) 31148c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "%d orphan inode%s deleted", 31158c2ecf20Sopenharmony_ci PLURAL(nr_orphans)); 31168c2ecf20Sopenharmony_ci if (nr_truncates) 31178c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "%d truncate%s cleaned up", 31188c2ecf20Sopenharmony_ci PLURAL(nr_truncates)); 31198c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 31208c2ecf20Sopenharmony_ci /* Turn off quotas if they were enabled for orphan cleanup */ 31218c2ecf20Sopenharmony_ci if (quota_update) { 31228c2ecf20Sopenharmony_ci for (i = 0; i < EXT4_MAXQUOTAS; i++) { 31238c2ecf20Sopenharmony_ci if (sb_dqopt(sb)->files[i]) 31248c2ecf20Sopenharmony_ci dquot_quota_off(sb, i); 31258c2ecf20Sopenharmony_ci } 31268c2ecf20Sopenharmony_ci } 31278c2ecf20Sopenharmony_ci#endif 31288c2ecf20Sopenharmony_ci sb->s_flags = s_flags; /* Restore SB_RDONLY status */ 31298c2ecf20Sopenharmony_ci} 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_ci/* 31328c2ecf20Sopenharmony_ci * Maximal extent format file size. 31338c2ecf20Sopenharmony_ci * Resulting logical blkno at s_maxbytes must fit in our on-disk 31348c2ecf20Sopenharmony_ci * extent format containers, within a sector_t, and within i_blocks 31358c2ecf20Sopenharmony_ci * in the vfs. ext4 inode has 48 bits of i_block in fsblock units, 31368c2ecf20Sopenharmony_ci * so that won't be a limiting factor. 31378c2ecf20Sopenharmony_ci * 31388c2ecf20Sopenharmony_ci * However there is other limiting factor. We do store extents in the form 31398c2ecf20Sopenharmony_ci * of starting block and length, hence the resulting length of the extent 31408c2ecf20Sopenharmony_ci * covering maximum file size must fit into on-disk format containers as 31418c2ecf20Sopenharmony_ci * well. Given that length is always by 1 unit bigger than max unit (because 31428c2ecf20Sopenharmony_ci * we count 0 as well) we have to lower the s_maxbytes by one fs block. 31438c2ecf20Sopenharmony_ci * 31448c2ecf20Sopenharmony_ci * Note, this does *not* consider any metadata overhead for vfs i_blocks. 31458c2ecf20Sopenharmony_ci */ 31468c2ecf20Sopenharmony_cistatic loff_t ext4_max_size(int blkbits, int has_huge_files) 31478c2ecf20Sopenharmony_ci{ 31488c2ecf20Sopenharmony_ci loff_t res; 31498c2ecf20Sopenharmony_ci loff_t upper_limit = MAX_LFS_FILESIZE; 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(blkcnt_t) < sizeof(u64)); 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci if (!has_huge_files) { 31548c2ecf20Sopenharmony_ci upper_limit = (1LL << 32) - 1; 31558c2ecf20Sopenharmony_ci 31568c2ecf20Sopenharmony_ci /* total blocks in file system block size */ 31578c2ecf20Sopenharmony_ci upper_limit >>= (blkbits - 9); 31588c2ecf20Sopenharmony_ci upper_limit <<= blkbits; 31598c2ecf20Sopenharmony_ci } 31608c2ecf20Sopenharmony_ci 31618c2ecf20Sopenharmony_ci /* 31628c2ecf20Sopenharmony_ci * 32-bit extent-start container, ee_block. We lower the maxbytes 31638c2ecf20Sopenharmony_ci * by one fs block, so ee_len can cover the extent of maximum file 31648c2ecf20Sopenharmony_ci * size 31658c2ecf20Sopenharmony_ci */ 31668c2ecf20Sopenharmony_ci res = (1LL << 32) - 1; 31678c2ecf20Sopenharmony_ci res <<= blkbits; 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_ci /* Sanity check against vm- & vfs- imposed limits */ 31708c2ecf20Sopenharmony_ci if (res > upper_limit) 31718c2ecf20Sopenharmony_ci res = upper_limit; 31728c2ecf20Sopenharmony_ci 31738c2ecf20Sopenharmony_ci return res; 31748c2ecf20Sopenharmony_ci} 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci/* 31778c2ecf20Sopenharmony_ci * Maximal bitmap file size. There is a direct, and {,double-,triple-}indirect 31788c2ecf20Sopenharmony_ci * block limit, and also a limit of (2^48 - 1) 512-byte sectors in i_blocks. 31798c2ecf20Sopenharmony_ci * We need to be 1 filesystem block less than the 2^48 sector limit. 31808c2ecf20Sopenharmony_ci */ 31818c2ecf20Sopenharmony_cistatic loff_t ext4_max_bitmap_size(int bits, int has_huge_files) 31828c2ecf20Sopenharmony_ci{ 31838c2ecf20Sopenharmony_ci unsigned long long upper_limit, res = EXT4_NDIR_BLOCKS; 31848c2ecf20Sopenharmony_ci int meta_blocks; 31858c2ecf20Sopenharmony_ci 31868c2ecf20Sopenharmony_ci /* 31878c2ecf20Sopenharmony_ci * This is calculated to be the largest file size for a dense, block 31888c2ecf20Sopenharmony_ci * mapped file such that the file's total number of 512-byte sectors, 31898c2ecf20Sopenharmony_ci * including data and all indirect blocks, does not exceed (2^48 - 1). 31908c2ecf20Sopenharmony_ci * 31918c2ecf20Sopenharmony_ci * __u32 i_blocks_lo and _u16 i_blocks_high represent the total 31928c2ecf20Sopenharmony_ci * number of 512-byte sectors of the file. 31938c2ecf20Sopenharmony_ci */ 31948c2ecf20Sopenharmony_ci if (!has_huge_files) { 31958c2ecf20Sopenharmony_ci /* 31968c2ecf20Sopenharmony_ci * !has_huge_files or implies that the inode i_block field 31978c2ecf20Sopenharmony_ci * represents total file blocks in 2^32 512-byte sectors == 31988c2ecf20Sopenharmony_ci * size of vfs inode i_blocks * 8 31998c2ecf20Sopenharmony_ci */ 32008c2ecf20Sopenharmony_ci upper_limit = (1LL << 32) - 1; 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_ci /* total blocks in file system block size */ 32038c2ecf20Sopenharmony_ci upper_limit >>= (bits - 9); 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_ci } else { 32068c2ecf20Sopenharmony_ci /* 32078c2ecf20Sopenharmony_ci * We use 48 bit ext4_inode i_blocks 32088c2ecf20Sopenharmony_ci * With EXT4_HUGE_FILE_FL set the i_blocks 32098c2ecf20Sopenharmony_ci * represent total number of blocks in 32108c2ecf20Sopenharmony_ci * file system block size 32118c2ecf20Sopenharmony_ci */ 32128c2ecf20Sopenharmony_ci upper_limit = (1LL << 48) - 1; 32138c2ecf20Sopenharmony_ci 32148c2ecf20Sopenharmony_ci } 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_ci /* indirect blocks */ 32178c2ecf20Sopenharmony_ci meta_blocks = 1; 32188c2ecf20Sopenharmony_ci /* double indirect blocks */ 32198c2ecf20Sopenharmony_ci meta_blocks += 1 + (1LL << (bits-2)); 32208c2ecf20Sopenharmony_ci /* tripple indirect blocks */ 32218c2ecf20Sopenharmony_ci meta_blocks += 1 + (1LL << (bits-2)) + (1LL << (2*(bits-2))); 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_ci upper_limit -= meta_blocks; 32248c2ecf20Sopenharmony_ci upper_limit <<= bits; 32258c2ecf20Sopenharmony_ci 32268c2ecf20Sopenharmony_ci res += 1LL << (bits-2); 32278c2ecf20Sopenharmony_ci res += 1LL << (2*(bits-2)); 32288c2ecf20Sopenharmony_ci res += 1LL << (3*(bits-2)); 32298c2ecf20Sopenharmony_ci res <<= bits; 32308c2ecf20Sopenharmony_ci if (res > upper_limit) 32318c2ecf20Sopenharmony_ci res = upper_limit; 32328c2ecf20Sopenharmony_ci 32338c2ecf20Sopenharmony_ci if (res > MAX_LFS_FILESIZE) 32348c2ecf20Sopenharmony_ci res = MAX_LFS_FILESIZE; 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci return (loff_t)res; 32378c2ecf20Sopenharmony_ci} 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_cistatic ext4_fsblk_t descriptor_loc(struct super_block *sb, 32408c2ecf20Sopenharmony_ci ext4_fsblk_t logical_sb_block, int nr) 32418c2ecf20Sopenharmony_ci{ 32428c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 32438c2ecf20Sopenharmony_ci ext4_group_t bg, first_meta_bg; 32448c2ecf20Sopenharmony_ci int has_super = 0; 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_ci first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg); 32478c2ecf20Sopenharmony_ci 32488c2ecf20Sopenharmony_ci if (!ext4_has_feature_meta_bg(sb) || nr < first_meta_bg) 32498c2ecf20Sopenharmony_ci return logical_sb_block + nr + 1; 32508c2ecf20Sopenharmony_ci bg = sbi->s_desc_per_block * nr; 32518c2ecf20Sopenharmony_ci if (ext4_bg_has_super(sb, bg)) 32528c2ecf20Sopenharmony_ci has_super = 1; 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci /* 32558c2ecf20Sopenharmony_ci * If we have a meta_bg fs with 1k blocks, group 0's GDT is at 32568c2ecf20Sopenharmony_ci * block 2, not 1. If s_first_data_block == 0 (bigalloc is enabled 32578c2ecf20Sopenharmony_ci * on modern mke2fs or blksize > 1k on older mke2fs) then we must 32588c2ecf20Sopenharmony_ci * compensate. 32598c2ecf20Sopenharmony_ci */ 32608c2ecf20Sopenharmony_ci if (sb->s_blocksize == 1024 && nr == 0 && 32618c2ecf20Sopenharmony_ci le32_to_cpu(sbi->s_es->s_first_data_block) == 0) 32628c2ecf20Sopenharmony_ci has_super++; 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci return (has_super + ext4_group_first_block_no(sb, bg)); 32658c2ecf20Sopenharmony_ci} 32668c2ecf20Sopenharmony_ci 32678c2ecf20Sopenharmony_ci/** 32688c2ecf20Sopenharmony_ci * ext4_get_stripe_size: Get the stripe size. 32698c2ecf20Sopenharmony_ci * @sbi: In memory super block info 32708c2ecf20Sopenharmony_ci * 32718c2ecf20Sopenharmony_ci * If we have specified it via mount option, then 32728c2ecf20Sopenharmony_ci * use the mount option value. If the value specified at mount time is 32738c2ecf20Sopenharmony_ci * greater than the blocks per group use the super block value. 32748c2ecf20Sopenharmony_ci * If the super block value is greater than blocks per group return 0. 32758c2ecf20Sopenharmony_ci * Allocator needs it be less than blocks per group. 32768c2ecf20Sopenharmony_ci * 32778c2ecf20Sopenharmony_ci */ 32788c2ecf20Sopenharmony_cistatic unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi) 32798c2ecf20Sopenharmony_ci{ 32808c2ecf20Sopenharmony_ci unsigned long stride = le16_to_cpu(sbi->s_es->s_raid_stride); 32818c2ecf20Sopenharmony_ci unsigned long stripe_width = 32828c2ecf20Sopenharmony_ci le32_to_cpu(sbi->s_es->s_raid_stripe_width); 32838c2ecf20Sopenharmony_ci int ret; 32848c2ecf20Sopenharmony_ci 32858c2ecf20Sopenharmony_ci if (sbi->s_stripe && sbi->s_stripe <= sbi->s_blocks_per_group) 32868c2ecf20Sopenharmony_ci ret = sbi->s_stripe; 32878c2ecf20Sopenharmony_ci else if (stripe_width && stripe_width <= sbi->s_blocks_per_group) 32888c2ecf20Sopenharmony_ci ret = stripe_width; 32898c2ecf20Sopenharmony_ci else if (stride && stride <= sbi->s_blocks_per_group) 32908c2ecf20Sopenharmony_ci ret = stride; 32918c2ecf20Sopenharmony_ci else 32928c2ecf20Sopenharmony_ci ret = 0; 32938c2ecf20Sopenharmony_ci 32948c2ecf20Sopenharmony_ci /* 32958c2ecf20Sopenharmony_ci * If the stripe width is 1, this makes no sense and 32968c2ecf20Sopenharmony_ci * we set it to 0 to turn off stripe handling code. 32978c2ecf20Sopenharmony_ci */ 32988c2ecf20Sopenharmony_ci if (ret <= 1) 32998c2ecf20Sopenharmony_ci ret = 0; 33008c2ecf20Sopenharmony_ci 33018c2ecf20Sopenharmony_ci return ret; 33028c2ecf20Sopenharmony_ci} 33038c2ecf20Sopenharmony_ci 33048c2ecf20Sopenharmony_ci/* 33058c2ecf20Sopenharmony_ci * Check whether this filesystem can be mounted based on 33068c2ecf20Sopenharmony_ci * the features present and the RDONLY/RDWR mount requested. 33078c2ecf20Sopenharmony_ci * Returns 1 if this filesystem can be mounted as requested, 33088c2ecf20Sopenharmony_ci * 0 if it cannot be. 33098c2ecf20Sopenharmony_ci */ 33108c2ecf20Sopenharmony_cistatic int ext4_feature_set_ok(struct super_block *sb, int readonly) 33118c2ecf20Sopenharmony_ci{ 33128c2ecf20Sopenharmony_ci if (ext4_has_unknown_ext4_incompat_features(sb)) { 33138c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 33148c2ecf20Sopenharmony_ci "Couldn't mount because of " 33158c2ecf20Sopenharmony_ci "unsupported optional features (%x)", 33168c2ecf20Sopenharmony_ci (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_incompat) & 33178c2ecf20Sopenharmony_ci ~EXT4_FEATURE_INCOMPAT_SUPP)); 33188c2ecf20Sopenharmony_ci return 0; 33198c2ecf20Sopenharmony_ci } 33208c2ecf20Sopenharmony_ci 33218c2ecf20Sopenharmony_ci#ifndef CONFIG_UNICODE 33228c2ecf20Sopenharmony_ci if (ext4_has_feature_casefold(sb)) { 33238c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 33248c2ecf20Sopenharmony_ci "Filesystem with casefold feature cannot be " 33258c2ecf20Sopenharmony_ci "mounted without CONFIG_UNICODE"); 33268c2ecf20Sopenharmony_ci return 0; 33278c2ecf20Sopenharmony_ci } 33288c2ecf20Sopenharmony_ci#endif 33298c2ecf20Sopenharmony_ci 33308c2ecf20Sopenharmony_ci if (readonly) 33318c2ecf20Sopenharmony_ci return 1; 33328c2ecf20Sopenharmony_ci 33338c2ecf20Sopenharmony_ci if (ext4_has_feature_readonly(sb)) { 33348c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "filesystem is read-only"); 33358c2ecf20Sopenharmony_ci sb->s_flags |= SB_RDONLY; 33368c2ecf20Sopenharmony_ci return 1; 33378c2ecf20Sopenharmony_ci } 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci /* Check that feature set is OK for a read-write mount */ 33408c2ecf20Sopenharmony_ci if (ext4_has_unknown_ext4_ro_compat_features(sb)) { 33418c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "couldn't mount RDWR because of " 33428c2ecf20Sopenharmony_ci "unsupported optional features (%x)", 33438c2ecf20Sopenharmony_ci (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_ro_compat) & 33448c2ecf20Sopenharmony_ci ~EXT4_FEATURE_RO_COMPAT_SUPP)); 33458c2ecf20Sopenharmony_ci return 0; 33468c2ecf20Sopenharmony_ci } 33478c2ecf20Sopenharmony_ci if (ext4_has_feature_bigalloc(sb) && !ext4_has_feature_extents(sb)) { 33488c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 33498c2ecf20Sopenharmony_ci "Can't support bigalloc feature without " 33508c2ecf20Sopenharmony_ci "extents feature\n"); 33518c2ecf20Sopenharmony_ci return 0; 33528c2ecf20Sopenharmony_ci } 33538c2ecf20Sopenharmony_ci 33548c2ecf20Sopenharmony_ci#if !IS_ENABLED(CONFIG_QUOTA) || !IS_ENABLED(CONFIG_QFMT_V2) 33558c2ecf20Sopenharmony_ci if (!readonly && (ext4_has_feature_quota(sb) || 33568c2ecf20Sopenharmony_ci ext4_has_feature_project(sb))) { 33578c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 33588c2ecf20Sopenharmony_ci "The kernel was not built with CONFIG_QUOTA and CONFIG_QFMT_V2"); 33598c2ecf20Sopenharmony_ci return 0; 33608c2ecf20Sopenharmony_ci } 33618c2ecf20Sopenharmony_ci#endif /* CONFIG_QUOTA */ 33628c2ecf20Sopenharmony_ci return 1; 33638c2ecf20Sopenharmony_ci} 33648c2ecf20Sopenharmony_ci 33658c2ecf20Sopenharmony_ci/* 33668c2ecf20Sopenharmony_ci * This function is called once a day if we have errors logged 33678c2ecf20Sopenharmony_ci * on the file system 33688c2ecf20Sopenharmony_ci */ 33698c2ecf20Sopenharmony_cistatic void print_daily_error_info(struct timer_list *t) 33708c2ecf20Sopenharmony_ci{ 33718c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = from_timer(sbi, t, s_err_report); 33728c2ecf20Sopenharmony_ci struct super_block *sb = sbi->s_sb; 33738c2ecf20Sopenharmony_ci struct ext4_super_block *es = sbi->s_es; 33748c2ecf20Sopenharmony_ci 33758c2ecf20Sopenharmony_ci if (es->s_error_count) 33768c2ecf20Sopenharmony_ci /* fsck newer than v1.41.13 is needed to clean this condition. */ 33778c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_NOTICE, "error count since last fsck: %u", 33788c2ecf20Sopenharmony_ci le32_to_cpu(es->s_error_count)); 33798c2ecf20Sopenharmony_ci if (es->s_first_error_time) { 33808c2ecf20Sopenharmony_ci printk(KERN_NOTICE "EXT4-fs (%s): initial error at time %llu: %.*s:%d", 33818c2ecf20Sopenharmony_ci sb->s_id, 33828c2ecf20Sopenharmony_ci ext4_get_tstamp(es, s_first_error_time), 33838c2ecf20Sopenharmony_ci (int) sizeof(es->s_first_error_func), 33848c2ecf20Sopenharmony_ci es->s_first_error_func, 33858c2ecf20Sopenharmony_ci le32_to_cpu(es->s_first_error_line)); 33868c2ecf20Sopenharmony_ci if (es->s_first_error_ino) 33878c2ecf20Sopenharmony_ci printk(KERN_CONT ": inode %u", 33888c2ecf20Sopenharmony_ci le32_to_cpu(es->s_first_error_ino)); 33898c2ecf20Sopenharmony_ci if (es->s_first_error_block) 33908c2ecf20Sopenharmony_ci printk(KERN_CONT ": block %llu", (unsigned long long) 33918c2ecf20Sopenharmony_ci le64_to_cpu(es->s_first_error_block)); 33928c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 33938c2ecf20Sopenharmony_ci } 33948c2ecf20Sopenharmony_ci if (es->s_last_error_time) { 33958c2ecf20Sopenharmony_ci printk(KERN_NOTICE "EXT4-fs (%s): last error at time %llu: %.*s:%d", 33968c2ecf20Sopenharmony_ci sb->s_id, 33978c2ecf20Sopenharmony_ci ext4_get_tstamp(es, s_last_error_time), 33988c2ecf20Sopenharmony_ci (int) sizeof(es->s_last_error_func), 33998c2ecf20Sopenharmony_ci es->s_last_error_func, 34008c2ecf20Sopenharmony_ci le32_to_cpu(es->s_last_error_line)); 34018c2ecf20Sopenharmony_ci if (es->s_last_error_ino) 34028c2ecf20Sopenharmony_ci printk(KERN_CONT ": inode %u", 34038c2ecf20Sopenharmony_ci le32_to_cpu(es->s_last_error_ino)); 34048c2ecf20Sopenharmony_ci if (es->s_last_error_block) 34058c2ecf20Sopenharmony_ci printk(KERN_CONT ": block %llu", (unsigned long long) 34068c2ecf20Sopenharmony_ci le64_to_cpu(es->s_last_error_block)); 34078c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 34088c2ecf20Sopenharmony_ci } 34098c2ecf20Sopenharmony_ci mod_timer(&sbi->s_err_report, jiffies + 24*60*60*HZ); /* Once a day */ 34108c2ecf20Sopenharmony_ci} 34118c2ecf20Sopenharmony_ci 34128c2ecf20Sopenharmony_ci/* Find next suitable group and run ext4_init_inode_table */ 34138c2ecf20Sopenharmony_cistatic int ext4_run_li_request(struct ext4_li_request *elr) 34148c2ecf20Sopenharmony_ci{ 34158c2ecf20Sopenharmony_ci struct ext4_group_desc *gdp = NULL; 34168c2ecf20Sopenharmony_ci struct super_block *sb = elr->lr_super; 34178c2ecf20Sopenharmony_ci ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count; 34188c2ecf20Sopenharmony_ci ext4_group_t group = elr->lr_next_group; 34198c2ecf20Sopenharmony_ci unsigned int prefetch_ios = 0; 34208c2ecf20Sopenharmony_ci int ret = 0; 34218c2ecf20Sopenharmony_ci u64 start_time; 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci if (elr->lr_mode == EXT4_LI_MODE_PREFETCH_BBITMAP) { 34248c2ecf20Sopenharmony_ci elr->lr_next_group = ext4_mb_prefetch(sb, group, 34258c2ecf20Sopenharmony_ci EXT4_SB(sb)->s_mb_prefetch, &prefetch_ios); 34268c2ecf20Sopenharmony_ci if (prefetch_ios) 34278c2ecf20Sopenharmony_ci ext4_mb_prefetch_fini(sb, elr->lr_next_group, 34288c2ecf20Sopenharmony_ci prefetch_ios); 34298c2ecf20Sopenharmony_ci trace_ext4_prefetch_bitmaps(sb, group, elr->lr_next_group, 34308c2ecf20Sopenharmony_ci prefetch_ios); 34318c2ecf20Sopenharmony_ci if (group >= elr->lr_next_group) { 34328c2ecf20Sopenharmony_ci ret = 1; 34338c2ecf20Sopenharmony_ci if (elr->lr_first_not_zeroed != ngroups && 34348c2ecf20Sopenharmony_ci !sb_rdonly(sb) && test_opt(sb, INIT_INODE_TABLE)) { 34358c2ecf20Sopenharmony_ci elr->lr_next_group = elr->lr_first_not_zeroed; 34368c2ecf20Sopenharmony_ci elr->lr_mode = EXT4_LI_MODE_ITABLE; 34378c2ecf20Sopenharmony_ci ret = 0; 34388c2ecf20Sopenharmony_ci } 34398c2ecf20Sopenharmony_ci } 34408c2ecf20Sopenharmony_ci return ret; 34418c2ecf20Sopenharmony_ci } 34428c2ecf20Sopenharmony_ci 34438c2ecf20Sopenharmony_ci for (; group < ngroups; group++) { 34448c2ecf20Sopenharmony_ci gdp = ext4_get_group_desc(sb, group, NULL); 34458c2ecf20Sopenharmony_ci if (!gdp) { 34468c2ecf20Sopenharmony_ci ret = 1; 34478c2ecf20Sopenharmony_ci break; 34488c2ecf20Sopenharmony_ci } 34498c2ecf20Sopenharmony_ci 34508c2ecf20Sopenharmony_ci if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))) 34518c2ecf20Sopenharmony_ci break; 34528c2ecf20Sopenharmony_ci } 34538c2ecf20Sopenharmony_ci 34548c2ecf20Sopenharmony_ci if (group >= ngroups) 34558c2ecf20Sopenharmony_ci ret = 1; 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_ci if (!ret) { 34588c2ecf20Sopenharmony_ci start_time = ktime_get_real_ns(); 34598c2ecf20Sopenharmony_ci ret = ext4_init_inode_table(sb, group, 34608c2ecf20Sopenharmony_ci elr->lr_timeout ? 0 : 1); 34618c2ecf20Sopenharmony_ci trace_ext4_lazy_itable_init(sb, group); 34628c2ecf20Sopenharmony_ci if (elr->lr_timeout == 0) { 34638c2ecf20Sopenharmony_ci elr->lr_timeout = nsecs_to_jiffies((ktime_get_real_ns() - start_time) * 34648c2ecf20Sopenharmony_ci EXT4_SB(elr->lr_super)->s_li_wait_mult); 34658c2ecf20Sopenharmony_ci } 34668c2ecf20Sopenharmony_ci elr->lr_next_sched = jiffies + elr->lr_timeout; 34678c2ecf20Sopenharmony_ci elr->lr_next_group = group + 1; 34688c2ecf20Sopenharmony_ci } 34698c2ecf20Sopenharmony_ci return ret; 34708c2ecf20Sopenharmony_ci} 34718c2ecf20Sopenharmony_ci 34728c2ecf20Sopenharmony_ci/* 34738c2ecf20Sopenharmony_ci * Remove lr_request from the list_request and free the 34748c2ecf20Sopenharmony_ci * request structure. Should be called with li_list_mtx held 34758c2ecf20Sopenharmony_ci */ 34768c2ecf20Sopenharmony_cistatic void ext4_remove_li_request(struct ext4_li_request *elr) 34778c2ecf20Sopenharmony_ci{ 34788c2ecf20Sopenharmony_ci if (!elr) 34798c2ecf20Sopenharmony_ci return; 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_ci list_del(&elr->lr_request); 34828c2ecf20Sopenharmony_ci EXT4_SB(elr->lr_super)->s_li_request = NULL; 34838c2ecf20Sopenharmony_ci kfree(elr); 34848c2ecf20Sopenharmony_ci} 34858c2ecf20Sopenharmony_ci 34868c2ecf20Sopenharmony_cistatic void ext4_unregister_li_request(struct super_block *sb) 34878c2ecf20Sopenharmony_ci{ 34888c2ecf20Sopenharmony_ci mutex_lock(&ext4_li_mtx); 34898c2ecf20Sopenharmony_ci if (!ext4_li_info) { 34908c2ecf20Sopenharmony_ci mutex_unlock(&ext4_li_mtx); 34918c2ecf20Sopenharmony_ci return; 34928c2ecf20Sopenharmony_ci } 34938c2ecf20Sopenharmony_ci 34948c2ecf20Sopenharmony_ci mutex_lock(&ext4_li_info->li_list_mtx); 34958c2ecf20Sopenharmony_ci ext4_remove_li_request(EXT4_SB(sb)->s_li_request); 34968c2ecf20Sopenharmony_ci mutex_unlock(&ext4_li_info->li_list_mtx); 34978c2ecf20Sopenharmony_ci mutex_unlock(&ext4_li_mtx); 34988c2ecf20Sopenharmony_ci} 34998c2ecf20Sopenharmony_ci 35008c2ecf20Sopenharmony_cistatic struct task_struct *ext4_lazyinit_task; 35018c2ecf20Sopenharmony_ci 35028c2ecf20Sopenharmony_ci/* 35038c2ecf20Sopenharmony_ci * This is the function where ext4lazyinit thread lives. It walks 35048c2ecf20Sopenharmony_ci * through the request list searching for next scheduled filesystem. 35058c2ecf20Sopenharmony_ci * When such a fs is found, run the lazy initialization request 35068c2ecf20Sopenharmony_ci * (ext4_rn_li_request) and keep track of the time spend in this 35078c2ecf20Sopenharmony_ci * function. Based on that time we compute next schedule time of 35088c2ecf20Sopenharmony_ci * the request. When walking through the list is complete, compute 35098c2ecf20Sopenharmony_ci * next waking time and put itself into sleep. 35108c2ecf20Sopenharmony_ci */ 35118c2ecf20Sopenharmony_cistatic int ext4_lazyinit_thread(void *arg) 35128c2ecf20Sopenharmony_ci{ 35138c2ecf20Sopenharmony_ci struct ext4_lazy_init *eli = (struct ext4_lazy_init *)arg; 35148c2ecf20Sopenharmony_ci struct list_head *pos, *n; 35158c2ecf20Sopenharmony_ci struct ext4_li_request *elr; 35168c2ecf20Sopenharmony_ci unsigned long next_wakeup, cur; 35178c2ecf20Sopenharmony_ci 35188c2ecf20Sopenharmony_ci BUG_ON(NULL == eli); 35198c2ecf20Sopenharmony_ci set_freezable(); 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_cicont_thread: 35228c2ecf20Sopenharmony_ci while (true) { 35238c2ecf20Sopenharmony_ci next_wakeup = MAX_JIFFY_OFFSET; 35248c2ecf20Sopenharmony_ci 35258c2ecf20Sopenharmony_ci mutex_lock(&eli->li_list_mtx); 35268c2ecf20Sopenharmony_ci if (list_empty(&eli->li_request_list)) { 35278c2ecf20Sopenharmony_ci mutex_unlock(&eli->li_list_mtx); 35288c2ecf20Sopenharmony_ci goto exit_thread; 35298c2ecf20Sopenharmony_ci } 35308c2ecf20Sopenharmony_ci list_for_each_safe(pos, n, &eli->li_request_list) { 35318c2ecf20Sopenharmony_ci int err = 0; 35328c2ecf20Sopenharmony_ci int progress = 0; 35338c2ecf20Sopenharmony_ci elr = list_entry(pos, struct ext4_li_request, 35348c2ecf20Sopenharmony_ci lr_request); 35358c2ecf20Sopenharmony_ci 35368c2ecf20Sopenharmony_ci if (time_before(jiffies, elr->lr_next_sched)) { 35378c2ecf20Sopenharmony_ci if (time_before(elr->lr_next_sched, next_wakeup)) 35388c2ecf20Sopenharmony_ci next_wakeup = elr->lr_next_sched; 35398c2ecf20Sopenharmony_ci continue; 35408c2ecf20Sopenharmony_ci } 35418c2ecf20Sopenharmony_ci if (down_read_trylock(&elr->lr_super->s_umount)) { 35428c2ecf20Sopenharmony_ci if (sb_start_write_trylock(elr->lr_super)) { 35438c2ecf20Sopenharmony_ci progress = 1; 35448c2ecf20Sopenharmony_ci /* 35458c2ecf20Sopenharmony_ci * We hold sb->s_umount, sb can not 35468c2ecf20Sopenharmony_ci * be removed from the list, it is 35478c2ecf20Sopenharmony_ci * now safe to drop li_list_mtx 35488c2ecf20Sopenharmony_ci */ 35498c2ecf20Sopenharmony_ci mutex_unlock(&eli->li_list_mtx); 35508c2ecf20Sopenharmony_ci err = ext4_run_li_request(elr); 35518c2ecf20Sopenharmony_ci sb_end_write(elr->lr_super); 35528c2ecf20Sopenharmony_ci mutex_lock(&eli->li_list_mtx); 35538c2ecf20Sopenharmony_ci n = pos->next; 35548c2ecf20Sopenharmony_ci } 35558c2ecf20Sopenharmony_ci up_read((&elr->lr_super->s_umount)); 35568c2ecf20Sopenharmony_ci } 35578c2ecf20Sopenharmony_ci /* error, remove the lazy_init job */ 35588c2ecf20Sopenharmony_ci if (err) { 35598c2ecf20Sopenharmony_ci ext4_remove_li_request(elr); 35608c2ecf20Sopenharmony_ci continue; 35618c2ecf20Sopenharmony_ci } 35628c2ecf20Sopenharmony_ci if (!progress) { 35638c2ecf20Sopenharmony_ci elr->lr_next_sched = jiffies + 35648c2ecf20Sopenharmony_ci (prandom_u32() 35658c2ecf20Sopenharmony_ci % (EXT4_DEF_LI_MAX_START_DELAY * HZ)); 35668c2ecf20Sopenharmony_ci } 35678c2ecf20Sopenharmony_ci if (time_before(elr->lr_next_sched, next_wakeup)) 35688c2ecf20Sopenharmony_ci next_wakeup = elr->lr_next_sched; 35698c2ecf20Sopenharmony_ci } 35708c2ecf20Sopenharmony_ci mutex_unlock(&eli->li_list_mtx); 35718c2ecf20Sopenharmony_ci 35728c2ecf20Sopenharmony_ci try_to_freeze(); 35738c2ecf20Sopenharmony_ci 35748c2ecf20Sopenharmony_ci cur = jiffies; 35758c2ecf20Sopenharmony_ci if ((time_after_eq(cur, next_wakeup)) || 35768c2ecf20Sopenharmony_ci (MAX_JIFFY_OFFSET == next_wakeup)) { 35778c2ecf20Sopenharmony_ci cond_resched(); 35788c2ecf20Sopenharmony_ci continue; 35798c2ecf20Sopenharmony_ci } 35808c2ecf20Sopenharmony_ci 35818c2ecf20Sopenharmony_ci schedule_timeout_interruptible(next_wakeup - cur); 35828c2ecf20Sopenharmony_ci 35838c2ecf20Sopenharmony_ci if (kthread_should_stop()) { 35848c2ecf20Sopenharmony_ci ext4_clear_request_list(); 35858c2ecf20Sopenharmony_ci goto exit_thread; 35868c2ecf20Sopenharmony_ci } 35878c2ecf20Sopenharmony_ci } 35888c2ecf20Sopenharmony_ci 35898c2ecf20Sopenharmony_ciexit_thread: 35908c2ecf20Sopenharmony_ci /* 35918c2ecf20Sopenharmony_ci * It looks like the request list is empty, but we need 35928c2ecf20Sopenharmony_ci * to check it under the li_list_mtx lock, to prevent any 35938c2ecf20Sopenharmony_ci * additions into it, and of course we should lock ext4_li_mtx 35948c2ecf20Sopenharmony_ci * to atomically free the list and ext4_li_info, because at 35958c2ecf20Sopenharmony_ci * this point another ext4 filesystem could be registering 35968c2ecf20Sopenharmony_ci * new one. 35978c2ecf20Sopenharmony_ci */ 35988c2ecf20Sopenharmony_ci mutex_lock(&ext4_li_mtx); 35998c2ecf20Sopenharmony_ci mutex_lock(&eli->li_list_mtx); 36008c2ecf20Sopenharmony_ci if (!list_empty(&eli->li_request_list)) { 36018c2ecf20Sopenharmony_ci mutex_unlock(&eli->li_list_mtx); 36028c2ecf20Sopenharmony_ci mutex_unlock(&ext4_li_mtx); 36038c2ecf20Sopenharmony_ci goto cont_thread; 36048c2ecf20Sopenharmony_ci } 36058c2ecf20Sopenharmony_ci mutex_unlock(&eli->li_list_mtx); 36068c2ecf20Sopenharmony_ci kfree(ext4_li_info); 36078c2ecf20Sopenharmony_ci ext4_li_info = NULL; 36088c2ecf20Sopenharmony_ci mutex_unlock(&ext4_li_mtx); 36098c2ecf20Sopenharmony_ci 36108c2ecf20Sopenharmony_ci return 0; 36118c2ecf20Sopenharmony_ci} 36128c2ecf20Sopenharmony_ci 36138c2ecf20Sopenharmony_cistatic void ext4_clear_request_list(void) 36148c2ecf20Sopenharmony_ci{ 36158c2ecf20Sopenharmony_ci struct list_head *pos, *n; 36168c2ecf20Sopenharmony_ci struct ext4_li_request *elr; 36178c2ecf20Sopenharmony_ci 36188c2ecf20Sopenharmony_ci mutex_lock(&ext4_li_info->li_list_mtx); 36198c2ecf20Sopenharmony_ci list_for_each_safe(pos, n, &ext4_li_info->li_request_list) { 36208c2ecf20Sopenharmony_ci elr = list_entry(pos, struct ext4_li_request, 36218c2ecf20Sopenharmony_ci lr_request); 36228c2ecf20Sopenharmony_ci ext4_remove_li_request(elr); 36238c2ecf20Sopenharmony_ci } 36248c2ecf20Sopenharmony_ci mutex_unlock(&ext4_li_info->li_list_mtx); 36258c2ecf20Sopenharmony_ci} 36268c2ecf20Sopenharmony_ci 36278c2ecf20Sopenharmony_cistatic int ext4_run_lazyinit_thread(void) 36288c2ecf20Sopenharmony_ci{ 36298c2ecf20Sopenharmony_ci ext4_lazyinit_task = kthread_run(ext4_lazyinit_thread, 36308c2ecf20Sopenharmony_ci ext4_li_info, "ext4lazyinit"); 36318c2ecf20Sopenharmony_ci if (IS_ERR(ext4_lazyinit_task)) { 36328c2ecf20Sopenharmony_ci int err = PTR_ERR(ext4_lazyinit_task); 36338c2ecf20Sopenharmony_ci ext4_clear_request_list(); 36348c2ecf20Sopenharmony_ci kfree(ext4_li_info); 36358c2ecf20Sopenharmony_ci ext4_li_info = NULL; 36368c2ecf20Sopenharmony_ci printk(KERN_CRIT "EXT4-fs: error %d creating inode table " 36378c2ecf20Sopenharmony_ci "initialization thread\n", 36388c2ecf20Sopenharmony_ci err); 36398c2ecf20Sopenharmony_ci return err; 36408c2ecf20Sopenharmony_ci } 36418c2ecf20Sopenharmony_ci ext4_li_info->li_state |= EXT4_LAZYINIT_RUNNING; 36428c2ecf20Sopenharmony_ci return 0; 36438c2ecf20Sopenharmony_ci} 36448c2ecf20Sopenharmony_ci 36458c2ecf20Sopenharmony_ci/* 36468c2ecf20Sopenharmony_ci * Check whether it make sense to run itable init. thread or not. 36478c2ecf20Sopenharmony_ci * If there is at least one uninitialized inode table, return 36488c2ecf20Sopenharmony_ci * corresponding group number, else the loop goes through all 36498c2ecf20Sopenharmony_ci * groups and return total number of groups. 36508c2ecf20Sopenharmony_ci */ 36518c2ecf20Sopenharmony_cistatic ext4_group_t ext4_has_uninit_itable(struct super_block *sb) 36528c2ecf20Sopenharmony_ci{ 36538c2ecf20Sopenharmony_ci ext4_group_t group, ngroups = EXT4_SB(sb)->s_groups_count; 36548c2ecf20Sopenharmony_ci struct ext4_group_desc *gdp = NULL; 36558c2ecf20Sopenharmony_ci 36568c2ecf20Sopenharmony_ci if (!ext4_has_group_desc_csum(sb)) 36578c2ecf20Sopenharmony_ci return ngroups; 36588c2ecf20Sopenharmony_ci 36598c2ecf20Sopenharmony_ci for (group = 0; group < ngroups; group++) { 36608c2ecf20Sopenharmony_ci gdp = ext4_get_group_desc(sb, group, NULL); 36618c2ecf20Sopenharmony_ci if (!gdp) 36628c2ecf20Sopenharmony_ci continue; 36638c2ecf20Sopenharmony_ci 36648c2ecf20Sopenharmony_ci if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))) 36658c2ecf20Sopenharmony_ci break; 36668c2ecf20Sopenharmony_ci } 36678c2ecf20Sopenharmony_ci 36688c2ecf20Sopenharmony_ci return group; 36698c2ecf20Sopenharmony_ci} 36708c2ecf20Sopenharmony_ci 36718c2ecf20Sopenharmony_cistatic int ext4_li_info_new(void) 36728c2ecf20Sopenharmony_ci{ 36738c2ecf20Sopenharmony_ci struct ext4_lazy_init *eli = NULL; 36748c2ecf20Sopenharmony_ci 36758c2ecf20Sopenharmony_ci eli = kzalloc(sizeof(*eli), GFP_KERNEL); 36768c2ecf20Sopenharmony_ci if (!eli) 36778c2ecf20Sopenharmony_ci return -ENOMEM; 36788c2ecf20Sopenharmony_ci 36798c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&eli->li_request_list); 36808c2ecf20Sopenharmony_ci mutex_init(&eli->li_list_mtx); 36818c2ecf20Sopenharmony_ci 36828c2ecf20Sopenharmony_ci eli->li_state |= EXT4_LAZYINIT_QUIT; 36838c2ecf20Sopenharmony_ci 36848c2ecf20Sopenharmony_ci ext4_li_info = eli; 36858c2ecf20Sopenharmony_ci 36868c2ecf20Sopenharmony_ci return 0; 36878c2ecf20Sopenharmony_ci} 36888c2ecf20Sopenharmony_ci 36898c2ecf20Sopenharmony_cistatic struct ext4_li_request *ext4_li_request_new(struct super_block *sb, 36908c2ecf20Sopenharmony_ci ext4_group_t start) 36918c2ecf20Sopenharmony_ci{ 36928c2ecf20Sopenharmony_ci struct ext4_li_request *elr; 36938c2ecf20Sopenharmony_ci 36948c2ecf20Sopenharmony_ci elr = kzalloc(sizeof(*elr), GFP_KERNEL); 36958c2ecf20Sopenharmony_ci if (!elr) 36968c2ecf20Sopenharmony_ci return NULL; 36978c2ecf20Sopenharmony_ci 36988c2ecf20Sopenharmony_ci elr->lr_super = sb; 36998c2ecf20Sopenharmony_ci elr->lr_first_not_zeroed = start; 37008c2ecf20Sopenharmony_ci if (test_opt(sb, PREFETCH_BLOCK_BITMAPS)) 37018c2ecf20Sopenharmony_ci elr->lr_mode = EXT4_LI_MODE_PREFETCH_BBITMAP; 37028c2ecf20Sopenharmony_ci else { 37038c2ecf20Sopenharmony_ci elr->lr_mode = EXT4_LI_MODE_ITABLE; 37048c2ecf20Sopenharmony_ci elr->lr_next_group = start; 37058c2ecf20Sopenharmony_ci } 37068c2ecf20Sopenharmony_ci 37078c2ecf20Sopenharmony_ci /* 37088c2ecf20Sopenharmony_ci * Randomize first schedule time of the request to 37098c2ecf20Sopenharmony_ci * spread the inode table initialization requests 37108c2ecf20Sopenharmony_ci * better. 37118c2ecf20Sopenharmony_ci */ 37128c2ecf20Sopenharmony_ci elr->lr_next_sched = jiffies + (prandom_u32() % 37138c2ecf20Sopenharmony_ci (EXT4_DEF_LI_MAX_START_DELAY * HZ)); 37148c2ecf20Sopenharmony_ci return elr; 37158c2ecf20Sopenharmony_ci} 37168c2ecf20Sopenharmony_ci 37178c2ecf20Sopenharmony_ciint ext4_register_li_request(struct super_block *sb, 37188c2ecf20Sopenharmony_ci ext4_group_t first_not_zeroed) 37198c2ecf20Sopenharmony_ci{ 37208c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 37218c2ecf20Sopenharmony_ci struct ext4_li_request *elr = NULL; 37228c2ecf20Sopenharmony_ci ext4_group_t ngroups = sbi->s_groups_count; 37238c2ecf20Sopenharmony_ci int ret = 0; 37248c2ecf20Sopenharmony_ci 37258c2ecf20Sopenharmony_ci mutex_lock(&ext4_li_mtx); 37268c2ecf20Sopenharmony_ci if (sbi->s_li_request != NULL) { 37278c2ecf20Sopenharmony_ci /* 37288c2ecf20Sopenharmony_ci * Reset timeout so it can be computed again, because 37298c2ecf20Sopenharmony_ci * s_li_wait_mult might have changed. 37308c2ecf20Sopenharmony_ci */ 37318c2ecf20Sopenharmony_ci sbi->s_li_request->lr_timeout = 0; 37328c2ecf20Sopenharmony_ci goto out; 37338c2ecf20Sopenharmony_ci } 37348c2ecf20Sopenharmony_ci 37358c2ecf20Sopenharmony_ci if (!test_opt(sb, PREFETCH_BLOCK_BITMAPS) && 37368c2ecf20Sopenharmony_ci (first_not_zeroed == ngroups || sb_rdonly(sb) || 37378c2ecf20Sopenharmony_ci !test_opt(sb, INIT_INODE_TABLE))) 37388c2ecf20Sopenharmony_ci goto out; 37398c2ecf20Sopenharmony_ci 37408c2ecf20Sopenharmony_ci elr = ext4_li_request_new(sb, first_not_zeroed); 37418c2ecf20Sopenharmony_ci if (!elr) { 37428c2ecf20Sopenharmony_ci ret = -ENOMEM; 37438c2ecf20Sopenharmony_ci goto out; 37448c2ecf20Sopenharmony_ci } 37458c2ecf20Sopenharmony_ci 37468c2ecf20Sopenharmony_ci if (NULL == ext4_li_info) { 37478c2ecf20Sopenharmony_ci ret = ext4_li_info_new(); 37488c2ecf20Sopenharmony_ci if (ret) 37498c2ecf20Sopenharmony_ci goto out; 37508c2ecf20Sopenharmony_ci } 37518c2ecf20Sopenharmony_ci 37528c2ecf20Sopenharmony_ci mutex_lock(&ext4_li_info->li_list_mtx); 37538c2ecf20Sopenharmony_ci list_add(&elr->lr_request, &ext4_li_info->li_request_list); 37548c2ecf20Sopenharmony_ci mutex_unlock(&ext4_li_info->li_list_mtx); 37558c2ecf20Sopenharmony_ci 37568c2ecf20Sopenharmony_ci sbi->s_li_request = elr; 37578c2ecf20Sopenharmony_ci /* 37588c2ecf20Sopenharmony_ci * set elr to NULL here since it has been inserted to 37598c2ecf20Sopenharmony_ci * the request_list and the removal and free of it is 37608c2ecf20Sopenharmony_ci * handled by ext4_clear_request_list from now on. 37618c2ecf20Sopenharmony_ci */ 37628c2ecf20Sopenharmony_ci elr = NULL; 37638c2ecf20Sopenharmony_ci 37648c2ecf20Sopenharmony_ci if (!(ext4_li_info->li_state & EXT4_LAZYINIT_RUNNING)) { 37658c2ecf20Sopenharmony_ci ret = ext4_run_lazyinit_thread(); 37668c2ecf20Sopenharmony_ci if (ret) 37678c2ecf20Sopenharmony_ci goto out; 37688c2ecf20Sopenharmony_ci } 37698c2ecf20Sopenharmony_ciout: 37708c2ecf20Sopenharmony_ci mutex_unlock(&ext4_li_mtx); 37718c2ecf20Sopenharmony_ci if (ret) 37728c2ecf20Sopenharmony_ci kfree(elr); 37738c2ecf20Sopenharmony_ci return ret; 37748c2ecf20Sopenharmony_ci} 37758c2ecf20Sopenharmony_ci 37768c2ecf20Sopenharmony_ci/* 37778c2ecf20Sopenharmony_ci * We do not need to lock anything since this is called on 37788c2ecf20Sopenharmony_ci * module unload. 37798c2ecf20Sopenharmony_ci */ 37808c2ecf20Sopenharmony_cistatic void ext4_destroy_lazyinit_thread(void) 37818c2ecf20Sopenharmony_ci{ 37828c2ecf20Sopenharmony_ci /* 37838c2ecf20Sopenharmony_ci * If thread exited earlier 37848c2ecf20Sopenharmony_ci * there's nothing to be done. 37858c2ecf20Sopenharmony_ci */ 37868c2ecf20Sopenharmony_ci if (!ext4_li_info || !ext4_lazyinit_task) 37878c2ecf20Sopenharmony_ci return; 37888c2ecf20Sopenharmony_ci 37898c2ecf20Sopenharmony_ci kthread_stop(ext4_lazyinit_task); 37908c2ecf20Sopenharmony_ci} 37918c2ecf20Sopenharmony_ci 37928c2ecf20Sopenharmony_cistatic int set_journal_csum_feature_set(struct super_block *sb) 37938c2ecf20Sopenharmony_ci{ 37948c2ecf20Sopenharmony_ci int ret = 1; 37958c2ecf20Sopenharmony_ci int compat, incompat; 37968c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 37978c2ecf20Sopenharmony_ci 37988c2ecf20Sopenharmony_ci if (ext4_has_metadata_csum(sb)) { 37998c2ecf20Sopenharmony_ci /* journal checksum v3 */ 38008c2ecf20Sopenharmony_ci compat = 0; 38018c2ecf20Sopenharmony_ci incompat = JBD2_FEATURE_INCOMPAT_CSUM_V3; 38028c2ecf20Sopenharmony_ci } else { 38038c2ecf20Sopenharmony_ci /* journal checksum v1 */ 38048c2ecf20Sopenharmony_ci compat = JBD2_FEATURE_COMPAT_CHECKSUM; 38058c2ecf20Sopenharmony_ci incompat = 0; 38068c2ecf20Sopenharmony_ci } 38078c2ecf20Sopenharmony_ci 38088c2ecf20Sopenharmony_ci jbd2_journal_clear_features(sbi->s_journal, 38098c2ecf20Sopenharmony_ci JBD2_FEATURE_COMPAT_CHECKSUM, 0, 38108c2ecf20Sopenharmony_ci JBD2_FEATURE_INCOMPAT_CSUM_V3 | 38118c2ecf20Sopenharmony_ci JBD2_FEATURE_INCOMPAT_CSUM_V2); 38128c2ecf20Sopenharmony_ci if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) { 38138c2ecf20Sopenharmony_ci ret = jbd2_journal_set_features(sbi->s_journal, 38148c2ecf20Sopenharmony_ci compat, 0, 38158c2ecf20Sopenharmony_ci JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT | 38168c2ecf20Sopenharmony_ci incompat); 38178c2ecf20Sopenharmony_ci } else if (test_opt(sb, JOURNAL_CHECKSUM)) { 38188c2ecf20Sopenharmony_ci ret = jbd2_journal_set_features(sbi->s_journal, 38198c2ecf20Sopenharmony_ci compat, 0, 38208c2ecf20Sopenharmony_ci incompat); 38218c2ecf20Sopenharmony_ci jbd2_journal_clear_features(sbi->s_journal, 0, 0, 38228c2ecf20Sopenharmony_ci JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); 38238c2ecf20Sopenharmony_ci } else { 38248c2ecf20Sopenharmony_ci jbd2_journal_clear_features(sbi->s_journal, 0, 0, 38258c2ecf20Sopenharmony_ci JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); 38268c2ecf20Sopenharmony_ci } 38278c2ecf20Sopenharmony_ci 38288c2ecf20Sopenharmony_ci return ret; 38298c2ecf20Sopenharmony_ci} 38308c2ecf20Sopenharmony_ci 38318c2ecf20Sopenharmony_ci/* 38328c2ecf20Sopenharmony_ci * Note: calculating the overhead so we can be compatible with 38338c2ecf20Sopenharmony_ci * historical BSD practice is quite difficult in the face of 38348c2ecf20Sopenharmony_ci * clusters/bigalloc. This is because multiple metadata blocks from 38358c2ecf20Sopenharmony_ci * different block group can end up in the same allocation cluster. 38368c2ecf20Sopenharmony_ci * Calculating the exact overhead in the face of clustered allocation 38378c2ecf20Sopenharmony_ci * requires either O(all block bitmaps) in memory or O(number of block 38388c2ecf20Sopenharmony_ci * groups**2) in time. We will still calculate the superblock for 38398c2ecf20Sopenharmony_ci * older file systems --- and if we come across with a bigalloc file 38408c2ecf20Sopenharmony_ci * system with zero in s_overhead_clusters the estimate will be close to 38418c2ecf20Sopenharmony_ci * correct especially for very large cluster sizes --- but for newer 38428c2ecf20Sopenharmony_ci * file systems, it's better to calculate this figure once at mkfs 38438c2ecf20Sopenharmony_ci * time, and store it in the superblock. If the superblock value is 38448c2ecf20Sopenharmony_ci * present (even for non-bigalloc file systems), we will use it. 38458c2ecf20Sopenharmony_ci */ 38468c2ecf20Sopenharmony_cistatic int count_overhead(struct super_block *sb, ext4_group_t grp, 38478c2ecf20Sopenharmony_ci char *buf) 38488c2ecf20Sopenharmony_ci{ 38498c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 38508c2ecf20Sopenharmony_ci struct ext4_group_desc *gdp; 38518c2ecf20Sopenharmony_ci ext4_fsblk_t first_block, last_block, b; 38528c2ecf20Sopenharmony_ci ext4_group_t i, ngroups = ext4_get_groups_count(sb); 38538c2ecf20Sopenharmony_ci int s, j, count = 0; 38548c2ecf20Sopenharmony_ci int has_super = ext4_bg_has_super(sb, grp); 38558c2ecf20Sopenharmony_ci 38568c2ecf20Sopenharmony_ci if (!ext4_has_feature_bigalloc(sb)) 38578c2ecf20Sopenharmony_ci return (has_super + ext4_bg_num_gdb(sb, grp) + 38588c2ecf20Sopenharmony_ci (has_super ? le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) : 0) + 38598c2ecf20Sopenharmony_ci sbi->s_itb_per_group + 2); 38608c2ecf20Sopenharmony_ci 38618c2ecf20Sopenharmony_ci first_block = le32_to_cpu(sbi->s_es->s_first_data_block) + 38628c2ecf20Sopenharmony_ci (grp * EXT4_BLOCKS_PER_GROUP(sb)); 38638c2ecf20Sopenharmony_ci last_block = first_block + EXT4_BLOCKS_PER_GROUP(sb) - 1; 38648c2ecf20Sopenharmony_ci for (i = 0; i < ngroups; i++) { 38658c2ecf20Sopenharmony_ci gdp = ext4_get_group_desc(sb, i, NULL); 38668c2ecf20Sopenharmony_ci b = ext4_block_bitmap(sb, gdp); 38678c2ecf20Sopenharmony_ci if (b >= first_block && b <= last_block) { 38688c2ecf20Sopenharmony_ci ext4_set_bit(EXT4_B2C(sbi, b - first_block), buf); 38698c2ecf20Sopenharmony_ci count++; 38708c2ecf20Sopenharmony_ci } 38718c2ecf20Sopenharmony_ci b = ext4_inode_bitmap(sb, gdp); 38728c2ecf20Sopenharmony_ci if (b >= first_block && b <= last_block) { 38738c2ecf20Sopenharmony_ci ext4_set_bit(EXT4_B2C(sbi, b - first_block), buf); 38748c2ecf20Sopenharmony_ci count++; 38758c2ecf20Sopenharmony_ci } 38768c2ecf20Sopenharmony_ci b = ext4_inode_table(sb, gdp); 38778c2ecf20Sopenharmony_ci if (b >= first_block && b + sbi->s_itb_per_group <= last_block) 38788c2ecf20Sopenharmony_ci for (j = 0; j < sbi->s_itb_per_group; j++, b++) { 38798c2ecf20Sopenharmony_ci int c = EXT4_B2C(sbi, b - first_block); 38808c2ecf20Sopenharmony_ci ext4_set_bit(c, buf); 38818c2ecf20Sopenharmony_ci count++; 38828c2ecf20Sopenharmony_ci } 38838c2ecf20Sopenharmony_ci if (i != grp) 38848c2ecf20Sopenharmony_ci continue; 38858c2ecf20Sopenharmony_ci s = 0; 38868c2ecf20Sopenharmony_ci if (ext4_bg_has_super(sb, grp)) { 38878c2ecf20Sopenharmony_ci ext4_set_bit(s++, buf); 38888c2ecf20Sopenharmony_ci count++; 38898c2ecf20Sopenharmony_ci } 38908c2ecf20Sopenharmony_ci j = ext4_bg_num_gdb(sb, grp); 38918c2ecf20Sopenharmony_ci if (s + j > EXT4_BLOCKS_PER_GROUP(sb)) { 38928c2ecf20Sopenharmony_ci ext4_error(sb, "Invalid number of block group " 38938c2ecf20Sopenharmony_ci "descriptor blocks: %d", j); 38948c2ecf20Sopenharmony_ci j = EXT4_BLOCKS_PER_GROUP(sb) - s; 38958c2ecf20Sopenharmony_ci } 38968c2ecf20Sopenharmony_ci count += j; 38978c2ecf20Sopenharmony_ci for (; j > 0; j--) 38988c2ecf20Sopenharmony_ci ext4_set_bit(EXT4_B2C(sbi, s++), buf); 38998c2ecf20Sopenharmony_ci } 39008c2ecf20Sopenharmony_ci if (!count) 39018c2ecf20Sopenharmony_ci return 0; 39028c2ecf20Sopenharmony_ci return EXT4_CLUSTERS_PER_GROUP(sb) - 39038c2ecf20Sopenharmony_ci ext4_count_free(buf, EXT4_CLUSTERS_PER_GROUP(sb) / 8); 39048c2ecf20Sopenharmony_ci} 39058c2ecf20Sopenharmony_ci 39068c2ecf20Sopenharmony_ci/* 39078c2ecf20Sopenharmony_ci * Compute the overhead and stash it in sbi->s_overhead 39088c2ecf20Sopenharmony_ci */ 39098c2ecf20Sopenharmony_ciint ext4_calculate_overhead(struct super_block *sb) 39108c2ecf20Sopenharmony_ci{ 39118c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 39128c2ecf20Sopenharmony_ci struct ext4_super_block *es = sbi->s_es; 39138c2ecf20Sopenharmony_ci struct inode *j_inode; 39148c2ecf20Sopenharmony_ci unsigned int j_blocks, j_inum = le32_to_cpu(es->s_journal_inum); 39158c2ecf20Sopenharmony_ci ext4_group_t i, ngroups = ext4_get_groups_count(sb); 39168c2ecf20Sopenharmony_ci ext4_fsblk_t overhead = 0; 39178c2ecf20Sopenharmony_ci char *buf = (char *) get_zeroed_page(GFP_NOFS); 39188c2ecf20Sopenharmony_ci 39198c2ecf20Sopenharmony_ci if (!buf) 39208c2ecf20Sopenharmony_ci return -ENOMEM; 39218c2ecf20Sopenharmony_ci 39228c2ecf20Sopenharmony_ci /* 39238c2ecf20Sopenharmony_ci * Compute the overhead (FS structures). This is constant 39248c2ecf20Sopenharmony_ci * for a given filesystem unless the number of block groups 39258c2ecf20Sopenharmony_ci * changes so we cache the previous value until it does. 39268c2ecf20Sopenharmony_ci */ 39278c2ecf20Sopenharmony_ci 39288c2ecf20Sopenharmony_ci /* 39298c2ecf20Sopenharmony_ci * All of the blocks before first_data_block are overhead 39308c2ecf20Sopenharmony_ci */ 39318c2ecf20Sopenharmony_ci overhead = EXT4_B2C(sbi, le32_to_cpu(es->s_first_data_block)); 39328c2ecf20Sopenharmony_ci 39338c2ecf20Sopenharmony_ci /* 39348c2ecf20Sopenharmony_ci * Add the overhead found in each block group 39358c2ecf20Sopenharmony_ci */ 39368c2ecf20Sopenharmony_ci for (i = 0; i < ngroups; i++) { 39378c2ecf20Sopenharmony_ci int blks; 39388c2ecf20Sopenharmony_ci 39398c2ecf20Sopenharmony_ci blks = count_overhead(sb, i, buf); 39408c2ecf20Sopenharmony_ci overhead += blks; 39418c2ecf20Sopenharmony_ci if (blks) 39428c2ecf20Sopenharmony_ci memset(buf, 0, PAGE_SIZE); 39438c2ecf20Sopenharmony_ci cond_resched(); 39448c2ecf20Sopenharmony_ci } 39458c2ecf20Sopenharmony_ci 39468c2ecf20Sopenharmony_ci /* 39478c2ecf20Sopenharmony_ci * Add the internal journal blocks whether the journal has been 39488c2ecf20Sopenharmony_ci * loaded or not 39498c2ecf20Sopenharmony_ci */ 39508c2ecf20Sopenharmony_ci if (sbi->s_journal && !sbi->s_journal_bdev) 39518c2ecf20Sopenharmony_ci overhead += EXT4_NUM_B2C(sbi, sbi->s_journal->j_total_len); 39528c2ecf20Sopenharmony_ci else if (ext4_has_feature_journal(sb) && !sbi->s_journal && j_inum) { 39538c2ecf20Sopenharmony_ci /* j_inum for internal journal is non-zero */ 39548c2ecf20Sopenharmony_ci j_inode = ext4_get_journal_inode(sb, j_inum); 39558c2ecf20Sopenharmony_ci if (j_inode) { 39568c2ecf20Sopenharmony_ci j_blocks = j_inode->i_size >> sb->s_blocksize_bits; 39578c2ecf20Sopenharmony_ci overhead += EXT4_NUM_B2C(sbi, j_blocks); 39588c2ecf20Sopenharmony_ci iput(j_inode); 39598c2ecf20Sopenharmony_ci } else { 39608c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "can't get journal size"); 39618c2ecf20Sopenharmony_ci } 39628c2ecf20Sopenharmony_ci } 39638c2ecf20Sopenharmony_ci sbi->s_overhead = overhead; 39648c2ecf20Sopenharmony_ci smp_wmb(); 39658c2ecf20Sopenharmony_ci free_page((unsigned long) buf); 39668c2ecf20Sopenharmony_ci return 0; 39678c2ecf20Sopenharmony_ci} 39688c2ecf20Sopenharmony_ci 39698c2ecf20Sopenharmony_cistatic void ext4_set_resv_clusters(struct super_block *sb) 39708c2ecf20Sopenharmony_ci{ 39718c2ecf20Sopenharmony_ci ext4_fsblk_t resv_clusters; 39728c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 39738c2ecf20Sopenharmony_ci 39748c2ecf20Sopenharmony_ci /* 39758c2ecf20Sopenharmony_ci * There's no need to reserve anything when we aren't using extents. 39768c2ecf20Sopenharmony_ci * The space estimates are exact, there are no unwritten extents, 39778c2ecf20Sopenharmony_ci * hole punching doesn't need new metadata... This is needed especially 39788c2ecf20Sopenharmony_ci * to keep ext2/3 backward compatibility. 39798c2ecf20Sopenharmony_ci */ 39808c2ecf20Sopenharmony_ci if (!ext4_has_feature_extents(sb)) 39818c2ecf20Sopenharmony_ci return; 39828c2ecf20Sopenharmony_ci /* 39838c2ecf20Sopenharmony_ci * By default we reserve 2% or 4096 clusters, whichever is smaller. 39848c2ecf20Sopenharmony_ci * This should cover the situations where we can not afford to run 39858c2ecf20Sopenharmony_ci * out of space like for example punch hole, or converting 39868c2ecf20Sopenharmony_ci * unwritten extents in delalloc path. In most cases such 39878c2ecf20Sopenharmony_ci * allocation would require 1, or 2 blocks, higher numbers are 39888c2ecf20Sopenharmony_ci * very rare. 39898c2ecf20Sopenharmony_ci */ 39908c2ecf20Sopenharmony_ci resv_clusters = (ext4_blocks_count(sbi->s_es) >> 39918c2ecf20Sopenharmony_ci sbi->s_cluster_bits); 39928c2ecf20Sopenharmony_ci 39938c2ecf20Sopenharmony_ci do_div(resv_clusters, 50); 39948c2ecf20Sopenharmony_ci resv_clusters = min_t(ext4_fsblk_t, resv_clusters, 4096); 39958c2ecf20Sopenharmony_ci 39968c2ecf20Sopenharmony_ci atomic64_set(&sbi->s_resv_clusters, resv_clusters); 39978c2ecf20Sopenharmony_ci} 39988c2ecf20Sopenharmony_ci 39998c2ecf20Sopenharmony_cistatic int ext4_fill_super(struct super_block *sb, void *data, int silent) 40008c2ecf20Sopenharmony_ci{ 40018c2ecf20Sopenharmony_ci struct dax_device *dax_dev = fs_dax_get_by_bdev(sb->s_bdev); 40028c2ecf20Sopenharmony_ci char *orig_data = kstrdup(data, GFP_KERNEL); 40038c2ecf20Sopenharmony_ci struct buffer_head *bh, **group_desc; 40048c2ecf20Sopenharmony_ci struct ext4_super_block *es = NULL; 40058c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); 40068c2ecf20Sopenharmony_ci struct flex_groups **flex_groups; 40078c2ecf20Sopenharmony_ci ext4_fsblk_t block; 40088c2ecf20Sopenharmony_ci ext4_fsblk_t sb_block = get_sb_block(&data); 40098c2ecf20Sopenharmony_ci ext4_fsblk_t logical_sb_block; 40108c2ecf20Sopenharmony_ci unsigned long offset = 0; 40118c2ecf20Sopenharmony_ci unsigned long journal_devnum = 0; 40128c2ecf20Sopenharmony_ci unsigned long def_mount_opts; 40138c2ecf20Sopenharmony_ci struct inode *root; 40148c2ecf20Sopenharmony_ci const char *descr; 40158c2ecf20Sopenharmony_ci int ret = -ENOMEM; 40168c2ecf20Sopenharmony_ci int blocksize, clustersize; 40178c2ecf20Sopenharmony_ci unsigned int db_count; 40188c2ecf20Sopenharmony_ci unsigned int i; 40198c2ecf20Sopenharmony_ci int needs_recovery, has_huge_files; 40208c2ecf20Sopenharmony_ci __u64 blocks_count; 40218c2ecf20Sopenharmony_ci int err = 0; 40228c2ecf20Sopenharmony_ci unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO; 40238c2ecf20Sopenharmony_ci ext4_group_t first_not_zeroed; 40248c2ecf20Sopenharmony_ci 40258c2ecf20Sopenharmony_ci if ((data && !orig_data) || !sbi) 40268c2ecf20Sopenharmony_ci goto out_free_base; 40278c2ecf20Sopenharmony_ci 40288c2ecf20Sopenharmony_ci sbi->s_daxdev = dax_dev; 40298c2ecf20Sopenharmony_ci sbi->s_blockgroup_lock = 40308c2ecf20Sopenharmony_ci kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL); 40318c2ecf20Sopenharmony_ci if (!sbi->s_blockgroup_lock) 40328c2ecf20Sopenharmony_ci goto out_free_base; 40338c2ecf20Sopenharmony_ci 40348c2ecf20Sopenharmony_ci sb->s_fs_info = sbi; 40358c2ecf20Sopenharmony_ci sbi->s_sb = sb; 40368c2ecf20Sopenharmony_ci sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS; 40378c2ecf20Sopenharmony_ci sbi->s_sb_block = sb_block; 40388c2ecf20Sopenharmony_ci if (sb->s_bdev->bd_part) 40398c2ecf20Sopenharmony_ci sbi->s_sectors_written_start = 40408c2ecf20Sopenharmony_ci part_stat_read(sb->s_bdev->bd_part, sectors[STAT_WRITE]); 40418c2ecf20Sopenharmony_ci 40428c2ecf20Sopenharmony_ci /* Cleanup superblock name */ 40438c2ecf20Sopenharmony_ci strreplace(sb->s_id, '/', '!'); 40448c2ecf20Sopenharmony_ci 40458c2ecf20Sopenharmony_ci /* -EINVAL is default */ 40468c2ecf20Sopenharmony_ci ret = -EINVAL; 40478c2ecf20Sopenharmony_ci blocksize = sb_min_blocksize(sb, EXT4_MIN_BLOCK_SIZE); 40488c2ecf20Sopenharmony_ci if (!blocksize) { 40498c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "unable to set blocksize"); 40508c2ecf20Sopenharmony_ci goto out_fail; 40518c2ecf20Sopenharmony_ci } 40528c2ecf20Sopenharmony_ci 40538c2ecf20Sopenharmony_ci /* 40548c2ecf20Sopenharmony_ci * The ext4 superblock will not be buffer aligned for other than 1kB 40558c2ecf20Sopenharmony_ci * block sizes. We need to calculate the offset from buffer start. 40568c2ecf20Sopenharmony_ci */ 40578c2ecf20Sopenharmony_ci if (blocksize != EXT4_MIN_BLOCK_SIZE) { 40588c2ecf20Sopenharmony_ci logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE; 40598c2ecf20Sopenharmony_ci offset = do_div(logical_sb_block, blocksize); 40608c2ecf20Sopenharmony_ci } else { 40618c2ecf20Sopenharmony_ci logical_sb_block = sb_block; 40628c2ecf20Sopenharmony_ci } 40638c2ecf20Sopenharmony_ci 40648c2ecf20Sopenharmony_ci bh = ext4_sb_bread_unmovable(sb, logical_sb_block); 40658c2ecf20Sopenharmony_ci if (IS_ERR(bh)) { 40668c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "unable to read superblock"); 40678c2ecf20Sopenharmony_ci ret = PTR_ERR(bh); 40688c2ecf20Sopenharmony_ci bh = NULL; 40698c2ecf20Sopenharmony_ci goto out_fail; 40708c2ecf20Sopenharmony_ci } 40718c2ecf20Sopenharmony_ci /* 40728c2ecf20Sopenharmony_ci * Note: s_es must be initialized as soon as possible because 40738c2ecf20Sopenharmony_ci * some ext4 macro-instructions depend on its value 40748c2ecf20Sopenharmony_ci */ 40758c2ecf20Sopenharmony_ci es = (struct ext4_super_block *) (bh->b_data + offset); 40768c2ecf20Sopenharmony_ci sbi->s_es = es; 40778c2ecf20Sopenharmony_ci sb->s_magic = le16_to_cpu(es->s_magic); 40788c2ecf20Sopenharmony_ci if (sb->s_magic != EXT4_SUPER_MAGIC) 40798c2ecf20Sopenharmony_ci goto cantfind_ext4; 40808c2ecf20Sopenharmony_ci sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written); 40818c2ecf20Sopenharmony_ci 40828c2ecf20Sopenharmony_ci /* Warn if metadata_csum and gdt_csum are both set. */ 40838c2ecf20Sopenharmony_ci if (ext4_has_feature_metadata_csum(sb) && 40848c2ecf20Sopenharmony_ci ext4_has_feature_gdt_csum(sb)) 40858c2ecf20Sopenharmony_ci ext4_warning(sb, "metadata_csum and uninit_bg are " 40868c2ecf20Sopenharmony_ci "redundant flags; please run fsck."); 40878c2ecf20Sopenharmony_ci 40888c2ecf20Sopenharmony_ci /* Check for a known checksum algorithm */ 40898c2ecf20Sopenharmony_ci if (!ext4_verify_csum_type(sb, es)) { 40908c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "VFS: Found ext4 filesystem with " 40918c2ecf20Sopenharmony_ci "unknown checksum algorithm."); 40928c2ecf20Sopenharmony_ci silent = 1; 40938c2ecf20Sopenharmony_ci goto cantfind_ext4; 40948c2ecf20Sopenharmony_ci } 40958c2ecf20Sopenharmony_ci 40968c2ecf20Sopenharmony_ci /* Load the checksum driver */ 40978c2ecf20Sopenharmony_ci sbi->s_chksum_driver = crypto_alloc_shash("crc32c", 0, 0); 40988c2ecf20Sopenharmony_ci if (IS_ERR(sbi->s_chksum_driver)) { 40998c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Cannot load crc32c driver."); 41008c2ecf20Sopenharmony_ci ret = PTR_ERR(sbi->s_chksum_driver); 41018c2ecf20Sopenharmony_ci sbi->s_chksum_driver = NULL; 41028c2ecf20Sopenharmony_ci goto failed_mount; 41038c2ecf20Sopenharmony_ci } 41048c2ecf20Sopenharmony_ci 41058c2ecf20Sopenharmony_ci /* Check superblock checksum */ 41068c2ecf20Sopenharmony_ci if (!ext4_superblock_csum_verify(sb, es)) { 41078c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "VFS: Found ext4 filesystem with " 41088c2ecf20Sopenharmony_ci "invalid superblock checksum. Run e2fsck?"); 41098c2ecf20Sopenharmony_ci silent = 1; 41108c2ecf20Sopenharmony_ci ret = -EFSBADCRC; 41118c2ecf20Sopenharmony_ci goto cantfind_ext4; 41128c2ecf20Sopenharmony_ci } 41138c2ecf20Sopenharmony_ci 41148c2ecf20Sopenharmony_ci /* Precompute checksum seed for all metadata */ 41158c2ecf20Sopenharmony_ci if (ext4_has_feature_csum_seed(sb)) 41168c2ecf20Sopenharmony_ci sbi->s_csum_seed = le32_to_cpu(es->s_checksum_seed); 41178c2ecf20Sopenharmony_ci else if (ext4_has_metadata_csum(sb) || ext4_has_feature_ea_inode(sb)) 41188c2ecf20Sopenharmony_ci sbi->s_csum_seed = ext4_chksum(sbi, ~0, es->s_uuid, 41198c2ecf20Sopenharmony_ci sizeof(es->s_uuid)); 41208c2ecf20Sopenharmony_ci 41218c2ecf20Sopenharmony_ci /* Set defaults before we parse the mount options */ 41228c2ecf20Sopenharmony_ci def_mount_opts = le32_to_cpu(es->s_default_mount_opts); 41238c2ecf20Sopenharmony_ci set_opt(sb, INIT_INODE_TABLE); 41248c2ecf20Sopenharmony_ci if (def_mount_opts & EXT4_DEFM_DEBUG) 41258c2ecf20Sopenharmony_ci set_opt(sb, DEBUG); 41268c2ecf20Sopenharmony_ci if (def_mount_opts & EXT4_DEFM_BSDGROUPS) 41278c2ecf20Sopenharmony_ci set_opt(sb, GRPID); 41288c2ecf20Sopenharmony_ci if (def_mount_opts & EXT4_DEFM_UID16) 41298c2ecf20Sopenharmony_ci set_opt(sb, NO_UID32); 41308c2ecf20Sopenharmony_ci /* xattr user namespace & acls are now defaulted on */ 41318c2ecf20Sopenharmony_ci set_opt(sb, XATTR_USER); 41328c2ecf20Sopenharmony_ci#ifdef CONFIG_EXT4_FS_POSIX_ACL 41338c2ecf20Sopenharmony_ci set_opt(sb, POSIX_ACL); 41348c2ecf20Sopenharmony_ci#endif 41358c2ecf20Sopenharmony_ci if (ext4_has_feature_fast_commit(sb)) 41368c2ecf20Sopenharmony_ci set_opt2(sb, JOURNAL_FAST_COMMIT); 41378c2ecf20Sopenharmony_ci /* don't forget to enable journal_csum when metadata_csum is enabled. */ 41388c2ecf20Sopenharmony_ci if (ext4_has_metadata_csum(sb)) 41398c2ecf20Sopenharmony_ci set_opt(sb, JOURNAL_CHECKSUM); 41408c2ecf20Sopenharmony_ci 41418c2ecf20Sopenharmony_ci if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_DATA) 41428c2ecf20Sopenharmony_ci set_opt(sb, JOURNAL_DATA); 41438c2ecf20Sopenharmony_ci else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_ORDERED) 41448c2ecf20Sopenharmony_ci set_opt(sb, ORDERED_DATA); 41458c2ecf20Sopenharmony_ci else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_WBACK) 41468c2ecf20Sopenharmony_ci set_opt(sb, WRITEBACK_DATA); 41478c2ecf20Sopenharmony_ci 41488c2ecf20Sopenharmony_ci if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_PANIC) 41498c2ecf20Sopenharmony_ci set_opt(sb, ERRORS_PANIC); 41508c2ecf20Sopenharmony_ci else if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_CONTINUE) 41518c2ecf20Sopenharmony_ci set_opt(sb, ERRORS_CONT); 41528c2ecf20Sopenharmony_ci else 41538c2ecf20Sopenharmony_ci set_opt(sb, ERRORS_RO); 41548c2ecf20Sopenharmony_ci /* block_validity enabled by default; disable with noblock_validity */ 41558c2ecf20Sopenharmony_ci set_opt(sb, BLOCK_VALIDITY); 41568c2ecf20Sopenharmony_ci if (def_mount_opts & EXT4_DEFM_DISCARD) 41578c2ecf20Sopenharmony_ci set_opt(sb, DISCARD); 41588c2ecf20Sopenharmony_ci 41598c2ecf20Sopenharmony_ci sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid)); 41608c2ecf20Sopenharmony_ci sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid)); 41618c2ecf20Sopenharmony_ci sbi->s_commit_interval = JBD2_DEFAULT_MAX_COMMIT_AGE * HZ; 41628c2ecf20Sopenharmony_ci sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME; 41638c2ecf20Sopenharmony_ci sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME; 41648c2ecf20Sopenharmony_ci 41658c2ecf20Sopenharmony_ci if ((def_mount_opts & EXT4_DEFM_NOBARRIER) == 0) 41668c2ecf20Sopenharmony_ci set_opt(sb, BARRIER); 41678c2ecf20Sopenharmony_ci 41688c2ecf20Sopenharmony_ci /* 41698c2ecf20Sopenharmony_ci * enable delayed allocation by default 41708c2ecf20Sopenharmony_ci * Use -o nodelalloc to turn it off 41718c2ecf20Sopenharmony_ci */ 41728c2ecf20Sopenharmony_ci if (!IS_EXT3_SB(sb) && !IS_EXT2_SB(sb) && 41738c2ecf20Sopenharmony_ci ((def_mount_opts & EXT4_DEFM_NODELALLOC) == 0)) 41748c2ecf20Sopenharmony_ci set_opt(sb, DELALLOC); 41758c2ecf20Sopenharmony_ci 41768c2ecf20Sopenharmony_ci /* 41778c2ecf20Sopenharmony_ci * set default s_li_wait_mult for lazyinit, for the case there is 41788c2ecf20Sopenharmony_ci * no mount option specified. 41798c2ecf20Sopenharmony_ci */ 41808c2ecf20Sopenharmony_ci sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT; 41818c2ecf20Sopenharmony_ci 41828c2ecf20Sopenharmony_ci if (le32_to_cpu(es->s_log_block_size) > 41838c2ecf20Sopenharmony_ci (EXT4_MAX_BLOCK_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) { 41848c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 41858c2ecf20Sopenharmony_ci "Invalid log block size: %u", 41868c2ecf20Sopenharmony_ci le32_to_cpu(es->s_log_block_size)); 41878c2ecf20Sopenharmony_ci goto failed_mount; 41888c2ecf20Sopenharmony_ci } 41898c2ecf20Sopenharmony_ci if (le32_to_cpu(es->s_log_cluster_size) > 41908c2ecf20Sopenharmony_ci (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) { 41918c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 41928c2ecf20Sopenharmony_ci "Invalid log cluster size: %u", 41938c2ecf20Sopenharmony_ci le32_to_cpu(es->s_log_cluster_size)); 41948c2ecf20Sopenharmony_ci goto failed_mount; 41958c2ecf20Sopenharmony_ci } 41968c2ecf20Sopenharmony_ci 41978c2ecf20Sopenharmony_ci blocksize = EXT4_MIN_BLOCK_SIZE << le32_to_cpu(es->s_log_block_size); 41988c2ecf20Sopenharmony_ci 41998c2ecf20Sopenharmony_ci if (blocksize == PAGE_SIZE) 42008c2ecf20Sopenharmony_ci set_opt(sb, DIOREAD_NOLOCK); 42018c2ecf20Sopenharmony_ci 42028c2ecf20Sopenharmony_ci if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) { 42038c2ecf20Sopenharmony_ci sbi->s_inode_size = EXT4_GOOD_OLD_INODE_SIZE; 42048c2ecf20Sopenharmony_ci sbi->s_first_ino = EXT4_GOOD_OLD_FIRST_INO; 42058c2ecf20Sopenharmony_ci } else { 42068c2ecf20Sopenharmony_ci sbi->s_inode_size = le16_to_cpu(es->s_inode_size); 42078c2ecf20Sopenharmony_ci sbi->s_first_ino = le32_to_cpu(es->s_first_ino); 42088c2ecf20Sopenharmony_ci if (sbi->s_first_ino < EXT4_GOOD_OLD_FIRST_INO) { 42098c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "invalid first ino: %u", 42108c2ecf20Sopenharmony_ci sbi->s_first_ino); 42118c2ecf20Sopenharmony_ci goto failed_mount; 42128c2ecf20Sopenharmony_ci } 42138c2ecf20Sopenharmony_ci if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) || 42148c2ecf20Sopenharmony_ci (!is_power_of_2(sbi->s_inode_size)) || 42158c2ecf20Sopenharmony_ci (sbi->s_inode_size > blocksize)) { 42168c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 42178c2ecf20Sopenharmony_ci "unsupported inode size: %d", 42188c2ecf20Sopenharmony_ci sbi->s_inode_size); 42198c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "blocksize: %d", blocksize); 42208c2ecf20Sopenharmony_ci goto failed_mount; 42218c2ecf20Sopenharmony_ci } 42228c2ecf20Sopenharmony_ci /* 42238c2ecf20Sopenharmony_ci * i_atime_extra is the last extra field available for 42248c2ecf20Sopenharmony_ci * [acm]times in struct ext4_inode. Checking for that 42258c2ecf20Sopenharmony_ci * field should suffice to ensure we have extra space 42268c2ecf20Sopenharmony_ci * for all three. 42278c2ecf20Sopenharmony_ci */ 42288c2ecf20Sopenharmony_ci if (sbi->s_inode_size >= offsetof(struct ext4_inode, i_atime_extra) + 42298c2ecf20Sopenharmony_ci sizeof(((struct ext4_inode *)0)->i_atime_extra)) { 42308c2ecf20Sopenharmony_ci sb->s_time_gran = 1; 42318c2ecf20Sopenharmony_ci sb->s_time_max = EXT4_EXTRA_TIMESTAMP_MAX; 42328c2ecf20Sopenharmony_ci } else { 42338c2ecf20Sopenharmony_ci sb->s_time_gran = NSEC_PER_SEC; 42348c2ecf20Sopenharmony_ci sb->s_time_max = EXT4_NON_EXTRA_TIMESTAMP_MAX; 42358c2ecf20Sopenharmony_ci } 42368c2ecf20Sopenharmony_ci sb->s_time_min = EXT4_TIMESTAMP_MIN; 42378c2ecf20Sopenharmony_ci } 42388c2ecf20Sopenharmony_ci if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) { 42398c2ecf20Sopenharmony_ci sbi->s_want_extra_isize = sizeof(struct ext4_inode) - 42408c2ecf20Sopenharmony_ci EXT4_GOOD_OLD_INODE_SIZE; 42418c2ecf20Sopenharmony_ci if (ext4_has_feature_extra_isize(sb)) { 42428c2ecf20Sopenharmony_ci unsigned v, max = (sbi->s_inode_size - 42438c2ecf20Sopenharmony_ci EXT4_GOOD_OLD_INODE_SIZE); 42448c2ecf20Sopenharmony_ci 42458c2ecf20Sopenharmony_ci v = le16_to_cpu(es->s_want_extra_isize); 42468c2ecf20Sopenharmony_ci if (v > max) { 42478c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 42488c2ecf20Sopenharmony_ci "bad s_want_extra_isize: %d", v); 42498c2ecf20Sopenharmony_ci goto failed_mount; 42508c2ecf20Sopenharmony_ci } 42518c2ecf20Sopenharmony_ci if (sbi->s_want_extra_isize < v) 42528c2ecf20Sopenharmony_ci sbi->s_want_extra_isize = v; 42538c2ecf20Sopenharmony_ci 42548c2ecf20Sopenharmony_ci v = le16_to_cpu(es->s_min_extra_isize); 42558c2ecf20Sopenharmony_ci if (v > max) { 42568c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 42578c2ecf20Sopenharmony_ci "bad s_min_extra_isize: %d", v); 42588c2ecf20Sopenharmony_ci goto failed_mount; 42598c2ecf20Sopenharmony_ci } 42608c2ecf20Sopenharmony_ci if (sbi->s_want_extra_isize < v) 42618c2ecf20Sopenharmony_ci sbi->s_want_extra_isize = v; 42628c2ecf20Sopenharmony_ci } 42638c2ecf20Sopenharmony_ci } 42648c2ecf20Sopenharmony_ci 42658c2ecf20Sopenharmony_ci if (sbi->s_es->s_mount_opts[0]) { 42668c2ecf20Sopenharmony_ci char *s_mount_opts = kstrndup(sbi->s_es->s_mount_opts, 42678c2ecf20Sopenharmony_ci sizeof(sbi->s_es->s_mount_opts), 42688c2ecf20Sopenharmony_ci GFP_KERNEL); 42698c2ecf20Sopenharmony_ci if (!s_mount_opts) 42708c2ecf20Sopenharmony_ci goto failed_mount; 42718c2ecf20Sopenharmony_ci if (!parse_options(s_mount_opts, sb, &journal_devnum, 42728c2ecf20Sopenharmony_ci &journal_ioprio, 0)) { 42738c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 42748c2ecf20Sopenharmony_ci "failed to parse options in superblock: %s", 42758c2ecf20Sopenharmony_ci s_mount_opts); 42768c2ecf20Sopenharmony_ci } 42778c2ecf20Sopenharmony_ci kfree(s_mount_opts); 42788c2ecf20Sopenharmony_ci } 42798c2ecf20Sopenharmony_ci sbi->s_def_mount_opt = sbi->s_mount_opt; 42808c2ecf20Sopenharmony_ci if (!parse_options((char *) data, sb, &journal_devnum, 42818c2ecf20Sopenharmony_ci &journal_ioprio, 0)) 42828c2ecf20Sopenharmony_ci goto failed_mount; 42838c2ecf20Sopenharmony_ci 42848c2ecf20Sopenharmony_ci#ifdef CONFIG_UNICODE 42858c2ecf20Sopenharmony_ci if (ext4_has_feature_casefold(sb) && !sb->s_encoding) { 42868c2ecf20Sopenharmony_ci const struct ext4_sb_encodings *encoding_info; 42878c2ecf20Sopenharmony_ci struct unicode_map *encoding; 42888c2ecf20Sopenharmony_ci __u16 encoding_flags; 42898c2ecf20Sopenharmony_ci 42908c2ecf20Sopenharmony_ci if (ext4_has_feature_encrypt(sb)) { 42918c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 42928c2ecf20Sopenharmony_ci "Can't mount with encoding and encryption"); 42938c2ecf20Sopenharmony_ci goto failed_mount; 42948c2ecf20Sopenharmony_ci } 42958c2ecf20Sopenharmony_ci 42968c2ecf20Sopenharmony_ci if (ext4_sb_read_encoding(es, &encoding_info, 42978c2ecf20Sopenharmony_ci &encoding_flags)) { 42988c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 42998c2ecf20Sopenharmony_ci "Encoding requested by superblock is unknown"); 43008c2ecf20Sopenharmony_ci goto failed_mount; 43018c2ecf20Sopenharmony_ci } 43028c2ecf20Sopenharmony_ci 43038c2ecf20Sopenharmony_ci encoding = utf8_load(encoding_info->version); 43048c2ecf20Sopenharmony_ci if (IS_ERR(encoding)) { 43058c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 43068c2ecf20Sopenharmony_ci "can't mount with superblock charset: %s-%s " 43078c2ecf20Sopenharmony_ci "not supported by the kernel. flags: 0x%x.", 43088c2ecf20Sopenharmony_ci encoding_info->name, encoding_info->version, 43098c2ecf20Sopenharmony_ci encoding_flags); 43108c2ecf20Sopenharmony_ci goto failed_mount; 43118c2ecf20Sopenharmony_ci } 43128c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO,"Using encoding defined by superblock: " 43138c2ecf20Sopenharmony_ci "%s-%s with flags 0x%hx", encoding_info->name, 43148c2ecf20Sopenharmony_ci encoding_info->version?:"\b", encoding_flags); 43158c2ecf20Sopenharmony_ci 43168c2ecf20Sopenharmony_ci sb->s_encoding = encoding; 43178c2ecf20Sopenharmony_ci sb->s_encoding_flags = encoding_flags; 43188c2ecf20Sopenharmony_ci } 43198c2ecf20Sopenharmony_ci#endif 43208c2ecf20Sopenharmony_ci 43218c2ecf20Sopenharmony_ci if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) { 43228c2ecf20Sopenharmony_ci printk_once(KERN_WARNING "EXT4-fs: Warning: mounting with data=journal disables delayed allocation, dioread_nolock, O_DIRECT and fast_commit support!\n"); 43238c2ecf20Sopenharmony_ci /* can't mount with both data=journal and dioread_nolock. */ 43248c2ecf20Sopenharmony_ci clear_opt(sb, DIOREAD_NOLOCK); 43258c2ecf20Sopenharmony_ci clear_opt2(sb, JOURNAL_FAST_COMMIT); 43268c2ecf20Sopenharmony_ci if (test_opt2(sb, EXPLICIT_DELALLOC)) { 43278c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "can't mount with " 43288c2ecf20Sopenharmony_ci "both data=journal and delalloc"); 43298c2ecf20Sopenharmony_ci goto failed_mount; 43308c2ecf20Sopenharmony_ci } 43318c2ecf20Sopenharmony_ci if (test_opt(sb, DAX_ALWAYS)) { 43328c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "can't mount with " 43338c2ecf20Sopenharmony_ci "both data=journal and dax"); 43348c2ecf20Sopenharmony_ci goto failed_mount; 43358c2ecf20Sopenharmony_ci } 43368c2ecf20Sopenharmony_ci if (ext4_has_feature_encrypt(sb)) { 43378c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 43388c2ecf20Sopenharmony_ci "encrypted files will use data=ordered " 43398c2ecf20Sopenharmony_ci "instead of data journaling mode"); 43408c2ecf20Sopenharmony_ci } 43418c2ecf20Sopenharmony_ci if (test_opt(sb, DELALLOC)) 43428c2ecf20Sopenharmony_ci clear_opt(sb, DELALLOC); 43438c2ecf20Sopenharmony_ci } else { 43448c2ecf20Sopenharmony_ci sb->s_iflags |= SB_I_CGROUPWB; 43458c2ecf20Sopenharmony_ci } 43468c2ecf20Sopenharmony_ci 43478c2ecf20Sopenharmony_ci sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | 43488c2ecf20Sopenharmony_ci (test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0); 43498c2ecf20Sopenharmony_ci 43508c2ecf20Sopenharmony_ci if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV && 43518c2ecf20Sopenharmony_ci (ext4_has_compat_features(sb) || 43528c2ecf20Sopenharmony_ci ext4_has_ro_compat_features(sb) || 43538c2ecf20Sopenharmony_ci ext4_has_incompat_features(sb))) 43548c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 43558c2ecf20Sopenharmony_ci "feature flags set on rev 0 fs, " 43568c2ecf20Sopenharmony_ci "running e2fsck is recommended"); 43578c2ecf20Sopenharmony_ci 43588c2ecf20Sopenharmony_ci if (es->s_creator_os == cpu_to_le32(EXT4_OS_HURD)) { 43598c2ecf20Sopenharmony_ci set_opt2(sb, HURD_COMPAT); 43608c2ecf20Sopenharmony_ci if (ext4_has_feature_64bit(sb)) { 43618c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 43628c2ecf20Sopenharmony_ci "The Hurd can't support 64-bit file systems"); 43638c2ecf20Sopenharmony_ci goto failed_mount; 43648c2ecf20Sopenharmony_ci } 43658c2ecf20Sopenharmony_ci 43668c2ecf20Sopenharmony_ci /* 43678c2ecf20Sopenharmony_ci * ea_inode feature uses l_i_version field which is not 43688c2ecf20Sopenharmony_ci * available in HURD_COMPAT mode. 43698c2ecf20Sopenharmony_ci */ 43708c2ecf20Sopenharmony_ci if (ext4_has_feature_ea_inode(sb)) { 43718c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 43728c2ecf20Sopenharmony_ci "ea_inode feature is not supported for Hurd"); 43738c2ecf20Sopenharmony_ci goto failed_mount; 43748c2ecf20Sopenharmony_ci } 43758c2ecf20Sopenharmony_ci } 43768c2ecf20Sopenharmony_ci 43778c2ecf20Sopenharmony_ci if (IS_EXT2_SB(sb)) { 43788c2ecf20Sopenharmony_ci if (ext2_feature_set_ok(sb)) 43798c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "mounting ext2 file system " 43808c2ecf20Sopenharmony_ci "using the ext4 subsystem"); 43818c2ecf20Sopenharmony_ci else { 43828c2ecf20Sopenharmony_ci /* 43838c2ecf20Sopenharmony_ci * If we're probing be silent, if this looks like 43848c2ecf20Sopenharmony_ci * it's actually an ext[34] filesystem. 43858c2ecf20Sopenharmony_ci */ 43868c2ecf20Sopenharmony_ci if (silent && ext4_feature_set_ok(sb, sb_rdonly(sb))) 43878c2ecf20Sopenharmony_ci goto failed_mount; 43888c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "couldn't mount as ext2 due " 43898c2ecf20Sopenharmony_ci "to feature incompatibilities"); 43908c2ecf20Sopenharmony_ci goto failed_mount; 43918c2ecf20Sopenharmony_ci } 43928c2ecf20Sopenharmony_ci } 43938c2ecf20Sopenharmony_ci 43948c2ecf20Sopenharmony_ci if (IS_EXT3_SB(sb)) { 43958c2ecf20Sopenharmony_ci if (ext3_feature_set_ok(sb)) 43968c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "mounting ext3 file system " 43978c2ecf20Sopenharmony_ci "using the ext4 subsystem"); 43988c2ecf20Sopenharmony_ci else { 43998c2ecf20Sopenharmony_ci /* 44008c2ecf20Sopenharmony_ci * If we're probing be silent, if this looks like 44018c2ecf20Sopenharmony_ci * it's actually an ext4 filesystem. 44028c2ecf20Sopenharmony_ci */ 44038c2ecf20Sopenharmony_ci if (silent && ext4_feature_set_ok(sb, sb_rdonly(sb))) 44048c2ecf20Sopenharmony_ci goto failed_mount; 44058c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "couldn't mount as ext3 due " 44068c2ecf20Sopenharmony_ci "to feature incompatibilities"); 44078c2ecf20Sopenharmony_ci goto failed_mount; 44088c2ecf20Sopenharmony_ci } 44098c2ecf20Sopenharmony_ci } 44108c2ecf20Sopenharmony_ci 44118c2ecf20Sopenharmony_ci /* 44128c2ecf20Sopenharmony_ci * Check feature flags regardless of the revision level, since we 44138c2ecf20Sopenharmony_ci * previously didn't change the revision level when setting the flags, 44148c2ecf20Sopenharmony_ci * so there is a chance incompat flags are set on a rev 0 filesystem. 44158c2ecf20Sopenharmony_ci */ 44168c2ecf20Sopenharmony_ci if (!ext4_feature_set_ok(sb, (sb_rdonly(sb)))) 44178c2ecf20Sopenharmony_ci goto failed_mount; 44188c2ecf20Sopenharmony_ci 44198c2ecf20Sopenharmony_ci if (le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) > (blocksize / 4)) { 44208c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 44218c2ecf20Sopenharmony_ci "Number of reserved GDT blocks insanely large: %d", 44228c2ecf20Sopenharmony_ci le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks)); 44238c2ecf20Sopenharmony_ci goto failed_mount; 44248c2ecf20Sopenharmony_ci } 44258c2ecf20Sopenharmony_ci 44268c2ecf20Sopenharmony_ci if (bdev_dax_supported(sb->s_bdev, blocksize)) 44278c2ecf20Sopenharmony_ci set_bit(EXT4_FLAGS_BDEV_IS_DAX, &sbi->s_ext4_flags); 44288c2ecf20Sopenharmony_ci 44298c2ecf20Sopenharmony_ci if (sbi->s_mount_opt & EXT4_MOUNT_DAX_ALWAYS) { 44308c2ecf20Sopenharmony_ci if (ext4_has_feature_inline_data(sb)) { 44318c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Cannot use DAX on a filesystem" 44328c2ecf20Sopenharmony_ci " that may contain inline data"); 44338c2ecf20Sopenharmony_ci goto failed_mount; 44348c2ecf20Sopenharmony_ci } 44358c2ecf20Sopenharmony_ci if (!test_bit(EXT4_FLAGS_BDEV_IS_DAX, &sbi->s_ext4_flags)) { 44368c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 44378c2ecf20Sopenharmony_ci "DAX unsupported by block device."); 44388c2ecf20Sopenharmony_ci goto failed_mount; 44398c2ecf20Sopenharmony_ci } 44408c2ecf20Sopenharmony_ci } 44418c2ecf20Sopenharmony_ci 44428c2ecf20Sopenharmony_ci if (ext4_has_feature_encrypt(sb) && es->s_encryption_level) { 44438c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Unsupported encryption level %d", 44448c2ecf20Sopenharmony_ci es->s_encryption_level); 44458c2ecf20Sopenharmony_ci goto failed_mount; 44468c2ecf20Sopenharmony_ci } 44478c2ecf20Sopenharmony_ci 44488c2ecf20Sopenharmony_ci if (sb->s_blocksize != blocksize) { 44498c2ecf20Sopenharmony_ci /* 44508c2ecf20Sopenharmony_ci * bh must be released before kill_bdev(), otherwise 44518c2ecf20Sopenharmony_ci * it won't be freed and its page also. kill_bdev() 44528c2ecf20Sopenharmony_ci * is called by sb_set_blocksize(). 44538c2ecf20Sopenharmony_ci */ 44548c2ecf20Sopenharmony_ci brelse(bh); 44558c2ecf20Sopenharmony_ci /* Validate the filesystem blocksize */ 44568c2ecf20Sopenharmony_ci if (!sb_set_blocksize(sb, blocksize)) { 44578c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "bad block size %d", 44588c2ecf20Sopenharmony_ci blocksize); 44598c2ecf20Sopenharmony_ci bh = NULL; 44608c2ecf20Sopenharmony_ci goto failed_mount; 44618c2ecf20Sopenharmony_ci } 44628c2ecf20Sopenharmony_ci 44638c2ecf20Sopenharmony_ci logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE; 44648c2ecf20Sopenharmony_ci offset = do_div(logical_sb_block, blocksize); 44658c2ecf20Sopenharmony_ci bh = ext4_sb_bread_unmovable(sb, logical_sb_block); 44668c2ecf20Sopenharmony_ci if (IS_ERR(bh)) { 44678c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 44688c2ecf20Sopenharmony_ci "Can't read superblock on 2nd try"); 44698c2ecf20Sopenharmony_ci ret = PTR_ERR(bh); 44708c2ecf20Sopenharmony_ci bh = NULL; 44718c2ecf20Sopenharmony_ci goto failed_mount; 44728c2ecf20Sopenharmony_ci } 44738c2ecf20Sopenharmony_ci es = (struct ext4_super_block *)(bh->b_data + offset); 44748c2ecf20Sopenharmony_ci sbi->s_es = es; 44758c2ecf20Sopenharmony_ci if (es->s_magic != cpu_to_le16(EXT4_SUPER_MAGIC)) { 44768c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 44778c2ecf20Sopenharmony_ci "Magic mismatch, very weird!"); 44788c2ecf20Sopenharmony_ci goto failed_mount; 44798c2ecf20Sopenharmony_ci } 44808c2ecf20Sopenharmony_ci } 44818c2ecf20Sopenharmony_ci 44828c2ecf20Sopenharmony_ci has_huge_files = ext4_has_feature_huge_file(sb); 44838c2ecf20Sopenharmony_ci sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits, 44848c2ecf20Sopenharmony_ci has_huge_files); 44858c2ecf20Sopenharmony_ci sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits, has_huge_files); 44868c2ecf20Sopenharmony_ci 44878c2ecf20Sopenharmony_ci sbi->s_desc_size = le16_to_cpu(es->s_desc_size); 44888c2ecf20Sopenharmony_ci if (ext4_has_feature_64bit(sb)) { 44898c2ecf20Sopenharmony_ci if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE_64BIT || 44908c2ecf20Sopenharmony_ci sbi->s_desc_size > EXT4_MAX_DESC_SIZE || 44918c2ecf20Sopenharmony_ci !is_power_of_2(sbi->s_desc_size)) { 44928c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 44938c2ecf20Sopenharmony_ci "unsupported descriptor size %lu", 44948c2ecf20Sopenharmony_ci sbi->s_desc_size); 44958c2ecf20Sopenharmony_ci goto failed_mount; 44968c2ecf20Sopenharmony_ci } 44978c2ecf20Sopenharmony_ci } else 44988c2ecf20Sopenharmony_ci sbi->s_desc_size = EXT4_MIN_DESC_SIZE; 44998c2ecf20Sopenharmony_ci 45008c2ecf20Sopenharmony_ci sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group); 45018c2ecf20Sopenharmony_ci sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group); 45028c2ecf20Sopenharmony_ci 45038c2ecf20Sopenharmony_ci sbi->s_inodes_per_block = blocksize / EXT4_INODE_SIZE(sb); 45048c2ecf20Sopenharmony_ci if (sbi->s_inodes_per_block == 0) 45058c2ecf20Sopenharmony_ci goto cantfind_ext4; 45068c2ecf20Sopenharmony_ci if (sbi->s_inodes_per_group < sbi->s_inodes_per_block || 45078c2ecf20Sopenharmony_ci sbi->s_inodes_per_group > blocksize * 8) { 45088c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "invalid inodes per group: %lu\n", 45098c2ecf20Sopenharmony_ci sbi->s_inodes_per_group); 45108c2ecf20Sopenharmony_ci goto failed_mount; 45118c2ecf20Sopenharmony_ci } 45128c2ecf20Sopenharmony_ci sbi->s_itb_per_group = sbi->s_inodes_per_group / 45138c2ecf20Sopenharmony_ci sbi->s_inodes_per_block; 45148c2ecf20Sopenharmony_ci sbi->s_desc_per_block = blocksize / EXT4_DESC_SIZE(sb); 45158c2ecf20Sopenharmony_ci sbi->s_sbh = bh; 45168c2ecf20Sopenharmony_ci sbi->s_mount_state = le16_to_cpu(es->s_state) & ~EXT4_FC_REPLAY; 45178c2ecf20Sopenharmony_ci sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb)); 45188c2ecf20Sopenharmony_ci sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb)); 45198c2ecf20Sopenharmony_ci 45208c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 45218c2ecf20Sopenharmony_ci sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); 45228c2ecf20Sopenharmony_ci sbi->s_def_hash_version = es->s_def_hash_version; 45238c2ecf20Sopenharmony_ci if (ext4_has_feature_dir_index(sb)) { 45248c2ecf20Sopenharmony_ci i = le32_to_cpu(es->s_flags); 45258c2ecf20Sopenharmony_ci if (i & EXT2_FLAGS_UNSIGNED_HASH) 45268c2ecf20Sopenharmony_ci sbi->s_hash_unsigned = 3; 45278c2ecf20Sopenharmony_ci else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) { 45288c2ecf20Sopenharmony_ci#ifdef __CHAR_UNSIGNED__ 45298c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) 45308c2ecf20Sopenharmony_ci es->s_flags |= 45318c2ecf20Sopenharmony_ci cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH); 45328c2ecf20Sopenharmony_ci sbi->s_hash_unsigned = 3; 45338c2ecf20Sopenharmony_ci#else 45348c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) 45358c2ecf20Sopenharmony_ci es->s_flags |= 45368c2ecf20Sopenharmony_ci cpu_to_le32(EXT2_FLAGS_SIGNED_HASH); 45378c2ecf20Sopenharmony_ci#endif 45388c2ecf20Sopenharmony_ci } 45398c2ecf20Sopenharmony_ci } 45408c2ecf20Sopenharmony_ci 45418c2ecf20Sopenharmony_ci /* Handle clustersize */ 45428c2ecf20Sopenharmony_ci clustersize = BLOCK_SIZE << le32_to_cpu(es->s_log_cluster_size); 45438c2ecf20Sopenharmony_ci if (ext4_has_feature_bigalloc(sb)) { 45448c2ecf20Sopenharmony_ci if (clustersize < blocksize) { 45458c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 45468c2ecf20Sopenharmony_ci "cluster size (%d) smaller than " 45478c2ecf20Sopenharmony_ci "block size (%d)", clustersize, blocksize); 45488c2ecf20Sopenharmony_ci goto failed_mount; 45498c2ecf20Sopenharmony_ci } 45508c2ecf20Sopenharmony_ci sbi->s_cluster_bits = le32_to_cpu(es->s_log_cluster_size) - 45518c2ecf20Sopenharmony_ci le32_to_cpu(es->s_log_block_size); 45528c2ecf20Sopenharmony_ci sbi->s_clusters_per_group = 45538c2ecf20Sopenharmony_ci le32_to_cpu(es->s_clusters_per_group); 45548c2ecf20Sopenharmony_ci if (sbi->s_clusters_per_group > blocksize * 8) { 45558c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 45568c2ecf20Sopenharmony_ci "#clusters per group too big: %lu", 45578c2ecf20Sopenharmony_ci sbi->s_clusters_per_group); 45588c2ecf20Sopenharmony_ci goto failed_mount; 45598c2ecf20Sopenharmony_ci } 45608c2ecf20Sopenharmony_ci if (sbi->s_blocks_per_group != 45618c2ecf20Sopenharmony_ci (sbi->s_clusters_per_group * (clustersize / blocksize))) { 45628c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "blocks per group (%lu) and " 45638c2ecf20Sopenharmony_ci "clusters per group (%lu) inconsistent", 45648c2ecf20Sopenharmony_ci sbi->s_blocks_per_group, 45658c2ecf20Sopenharmony_ci sbi->s_clusters_per_group); 45668c2ecf20Sopenharmony_ci goto failed_mount; 45678c2ecf20Sopenharmony_ci } 45688c2ecf20Sopenharmony_ci } else { 45698c2ecf20Sopenharmony_ci if (clustersize != blocksize) { 45708c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 45718c2ecf20Sopenharmony_ci "fragment/cluster size (%d) != " 45728c2ecf20Sopenharmony_ci "block size (%d)", clustersize, blocksize); 45738c2ecf20Sopenharmony_ci goto failed_mount; 45748c2ecf20Sopenharmony_ci } 45758c2ecf20Sopenharmony_ci if (sbi->s_blocks_per_group > blocksize * 8) { 45768c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 45778c2ecf20Sopenharmony_ci "#blocks per group too big: %lu", 45788c2ecf20Sopenharmony_ci sbi->s_blocks_per_group); 45798c2ecf20Sopenharmony_ci goto failed_mount; 45808c2ecf20Sopenharmony_ci } 45818c2ecf20Sopenharmony_ci sbi->s_clusters_per_group = sbi->s_blocks_per_group; 45828c2ecf20Sopenharmony_ci sbi->s_cluster_bits = 0; 45838c2ecf20Sopenharmony_ci } 45848c2ecf20Sopenharmony_ci sbi->s_cluster_ratio = clustersize / blocksize; 45858c2ecf20Sopenharmony_ci 45868c2ecf20Sopenharmony_ci /* Do we have standard group size of clustersize * 8 blocks ? */ 45878c2ecf20Sopenharmony_ci if (sbi->s_blocks_per_group == clustersize << 3) 45888c2ecf20Sopenharmony_ci set_opt2(sb, STD_GROUP_SIZE); 45898c2ecf20Sopenharmony_ci 45908c2ecf20Sopenharmony_ci /* 45918c2ecf20Sopenharmony_ci * Test whether we have more sectors than will fit in sector_t, 45928c2ecf20Sopenharmony_ci * and whether the max offset is addressable by the page cache. 45938c2ecf20Sopenharmony_ci */ 45948c2ecf20Sopenharmony_ci err = generic_check_addressable(sb->s_blocksize_bits, 45958c2ecf20Sopenharmony_ci ext4_blocks_count(es)); 45968c2ecf20Sopenharmony_ci if (err) { 45978c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "filesystem" 45988c2ecf20Sopenharmony_ci " too large to mount safely on this system"); 45998c2ecf20Sopenharmony_ci goto failed_mount; 46008c2ecf20Sopenharmony_ci } 46018c2ecf20Sopenharmony_ci 46028c2ecf20Sopenharmony_ci if (EXT4_BLOCKS_PER_GROUP(sb) == 0) 46038c2ecf20Sopenharmony_ci goto cantfind_ext4; 46048c2ecf20Sopenharmony_ci 46058c2ecf20Sopenharmony_ci /* check blocks count against device size */ 46068c2ecf20Sopenharmony_ci blocks_count = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits; 46078c2ecf20Sopenharmony_ci if (blocks_count && ext4_blocks_count(es) > blocks_count) { 46088c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, "bad geometry: block count %llu " 46098c2ecf20Sopenharmony_ci "exceeds size of device (%llu blocks)", 46108c2ecf20Sopenharmony_ci ext4_blocks_count(es), blocks_count); 46118c2ecf20Sopenharmony_ci goto failed_mount; 46128c2ecf20Sopenharmony_ci } 46138c2ecf20Sopenharmony_ci 46148c2ecf20Sopenharmony_ci /* 46158c2ecf20Sopenharmony_ci * It makes no sense for the first data block to be beyond the end 46168c2ecf20Sopenharmony_ci * of the filesystem. 46178c2ecf20Sopenharmony_ci */ 46188c2ecf20Sopenharmony_ci if (le32_to_cpu(es->s_first_data_block) >= ext4_blocks_count(es)) { 46198c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, "bad geometry: first data " 46208c2ecf20Sopenharmony_ci "block %u is beyond end of filesystem (%llu)", 46218c2ecf20Sopenharmony_ci le32_to_cpu(es->s_first_data_block), 46228c2ecf20Sopenharmony_ci ext4_blocks_count(es)); 46238c2ecf20Sopenharmony_ci goto failed_mount; 46248c2ecf20Sopenharmony_ci } 46258c2ecf20Sopenharmony_ci if ((es->s_first_data_block == 0) && (es->s_log_block_size == 0) && 46268c2ecf20Sopenharmony_ci (sbi->s_cluster_ratio == 1)) { 46278c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, "bad geometry: first data " 46288c2ecf20Sopenharmony_ci "block is 0 with a 1k block and cluster size"); 46298c2ecf20Sopenharmony_ci goto failed_mount; 46308c2ecf20Sopenharmony_ci } 46318c2ecf20Sopenharmony_ci 46328c2ecf20Sopenharmony_ci blocks_count = (ext4_blocks_count(es) - 46338c2ecf20Sopenharmony_ci le32_to_cpu(es->s_first_data_block) + 46348c2ecf20Sopenharmony_ci EXT4_BLOCKS_PER_GROUP(sb) - 1); 46358c2ecf20Sopenharmony_ci do_div(blocks_count, EXT4_BLOCKS_PER_GROUP(sb)); 46368c2ecf20Sopenharmony_ci if (blocks_count > ((uint64_t)1<<32) - EXT4_DESC_PER_BLOCK(sb)) { 46378c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, "groups count too large: %llu " 46388c2ecf20Sopenharmony_ci "(block count %llu, first data block %u, " 46398c2ecf20Sopenharmony_ci "blocks per group %lu)", blocks_count, 46408c2ecf20Sopenharmony_ci ext4_blocks_count(es), 46418c2ecf20Sopenharmony_ci le32_to_cpu(es->s_first_data_block), 46428c2ecf20Sopenharmony_ci EXT4_BLOCKS_PER_GROUP(sb)); 46438c2ecf20Sopenharmony_ci goto failed_mount; 46448c2ecf20Sopenharmony_ci } 46458c2ecf20Sopenharmony_ci sbi->s_groups_count = blocks_count; 46468c2ecf20Sopenharmony_ci sbi->s_blockfile_groups = min_t(ext4_group_t, sbi->s_groups_count, 46478c2ecf20Sopenharmony_ci (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb))); 46488c2ecf20Sopenharmony_ci if (((u64)sbi->s_groups_count * sbi->s_inodes_per_group) != 46498c2ecf20Sopenharmony_ci le32_to_cpu(es->s_inodes_count)) { 46508c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "inodes count not valid: %u vs %llu", 46518c2ecf20Sopenharmony_ci le32_to_cpu(es->s_inodes_count), 46528c2ecf20Sopenharmony_ci ((u64)sbi->s_groups_count * sbi->s_inodes_per_group)); 46538c2ecf20Sopenharmony_ci ret = -EINVAL; 46548c2ecf20Sopenharmony_ci goto failed_mount; 46558c2ecf20Sopenharmony_ci } 46568c2ecf20Sopenharmony_ci db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / 46578c2ecf20Sopenharmony_ci EXT4_DESC_PER_BLOCK(sb); 46588c2ecf20Sopenharmony_ci if (ext4_has_feature_meta_bg(sb)) { 46598c2ecf20Sopenharmony_ci if (le32_to_cpu(es->s_first_meta_bg) > db_count) { 46608c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 46618c2ecf20Sopenharmony_ci "first meta block group too large: %u " 46628c2ecf20Sopenharmony_ci "(group descriptor block count %u)", 46638c2ecf20Sopenharmony_ci le32_to_cpu(es->s_first_meta_bg), db_count); 46648c2ecf20Sopenharmony_ci goto failed_mount; 46658c2ecf20Sopenharmony_ci } 46668c2ecf20Sopenharmony_ci } 46678c2ecf20Sopenharmony_ci rcu_assign_pointer(sbi->s_group_desc, 46688c2ecf20Sopenharmony_ci kvmalloc_array(db_count, 46698c2ecf20Sopenharmony_ci sizeof(struct buffer_head *), 46708c2ecf20Sopenharmony_ci GFP_KERNEL)); 46718c2ecf20Sopenharmony_ci if (sbi->s_group_desc == NULL) { 46728c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "not enough memory"); 46738c2ecf20Sopenharmony_ci ret = -ENOMEM; 46748c2ecf20Sopenharmony_ci goto failed_mount; 46758c2ecf20Sopenharmony_ci } 46768c2ecf20Sopenharmony_ci 46778c2ecf20Sopenharmony_ci bgl_lock_init(sbi->s_blockgroup_lock); 46788c2ecf20Sopenharmony_ci 46798c2ecf20Sopenharmony_ci /* Pre-read the descriptors into the buffer cache */ 46808c2ecf20Sopenharmony_ci for (i = 0; i < db_count; i++) { 46818c2ecf20Sopenharmony_ci block = descriptor_loc(sb, logical_sb_block, i); 46828c2ecf20Sopenharmony_ci ext4_sb_breadahead_unmovable(sb, block); 46838c2ecf20Sopenharmony_ci } 46848c2ecf20Sopenharmony_ci 46858c2ecf20Sopenharmony_ci for (i = 0; i < db_count; i++) { 46868c2ecf20Sopenharmony_ci struct buffer_head *bh; 46878c2ecf20Sopenharmony_ci 46888c2ecf20Sopenharmony_ci block = descriptor_loc(sb, logical_sb_block, i); 46898c2ecf20Sopenharmony_ci bh = ext4_sb_bread_unmovable(sb, block); 46908c2ecf20Sopenharmony_ci if (IS_ERR(bh)) { 46918c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 46928c2ecf20Sopenharmony_ci "can't read group descriptor %d", i); 46938c2ecf20Sopenharmony_ci db_count = i; 46948c2ecf20Sopenharmony_ci ret = PTR_ERR(bh); 46958c2ecf20Sopenharmony_ci bh = NULL; 46968c2ecf20Sopenharmony_ci goto failed_mount2; 46978c2ecf20Sopenharmony_ci } 46988c2ecf20Sopenharmony_ci rcu_read_lock(); 46998c2ecf20Sopenharmony_ci rcu_dereference(sbi->s_group_desc)[i] = bh; 47008c2ecf20Sopenharmony_ci rcu_read_unlock(); 47018c2ecf20Sopenharmony_ci } 47028c2ecf20Sopenharmony_ci sbi->s_gdb_count = db_count; 47038c2ecf20Sopenharmony_ci if (!ext4_check_descriptors(sb, logical_sb_block, &first_not_zeroed)) { 47048c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "group descriptors corrupted!"); 47058c2ecf20Sopenharmony_ci ret = -EFSCORRUPTED; 47068c2ecf20Sopenharmony_ci goto failed_mount2; 47078c2ecf20Sopenharmony_ci } 47088c2ecf20Sopenharmony_ci 47098c2ecf20Sopenharmony_ci timer_setup(&sbi->s_err_report, print_daily_error_info, 0); 47108c2ecf20Sopenharmony_ci spin_lock_init(&sbi->s_error_lock); 47118c2ecf20Sopenharmony_ci INIT_WORK(&sbi->s_error_work, flush_stashed_error_work); 47128c2ecf20Sopenharmony_ci 47138c2ecf20Sopenharmony_ci /* Register extent status tree shrinker */ 47148c2ecf20Sopenharmony_ci if (ext4_es_register_shrinker(sbi)) 47158c2ecf20Sopenharmony_ci goto failed_mount3; 47168c2ecf20Sopenharmony_ci 47178c2ecf20Sopenharmony_ci sbi->s_stripe = ext4_get_stripe_size(sbi); 47188c2ecf20Sopenharmony_ci sbi->s_extent_max_zeroout_kb = 32; 47198c2ecf20Sopenharmony_ci 47208c2ecf20Sopenharmony_ci /* 47218c2ecf20Sopenharmony_ci * set up enough so that it can read an inode 47228c2ecf20Sopenharmony_ci */ 47238c2ecf20Sopenharmony_ci sb->s_op = &ext4_sops; 47248c2ecf20Sopenharmony_ci sb->s_export_op = &ext4_export_ops; 47258c2ecf20Sopenharmony_ci sb->s_xattr = ext4_xattr_handlers; 47268c2ecf20Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION 47278c2ecf20Sopenharmony_ci sb->s_cop = &ext4_cryptops; 47288c2ecf20Sopenharmony_ci#endif 47298c2ecf20Sopenharmony_ci#ifdef CONFIG_FS_VERITY 47308c2ecf20Sopenharmony_ci sb->s_vop = &ext4_verityops; 47318c2ecf20Sopenharmony_ci#endif 47328c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 47338c2ecf20Sopenharmony_ci sb->dq_op = &ext4_quota_operations; 47348c2ecf20Sopenharmony_ci if (ext4_has_feature_quota(sb)) 47358c2ecf20Sopenharmony_ci sb->s_qcop = &dquot_quotactl_sysfile_ops; 47368c2ecf20Sopenharmony_ci else 47378c2ecf20Sopenharmony_ci sb->s_qcop = &ext4_qctl_operations; 47388c2ecf20Sopenharmony_ci sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ; 47398c2ecf20Sopenharmony_ci#endif 47408c2ecf20Sopenharmony_ci memcpy(&sb->s_uuid, es->s_uuid, sizeof(es->s_uuid)); 47418c2ecf20Sopenharmony_ci 47428c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ 47438c2ecf20Sopenharmony_ci mutex_init(&sbi->s_orphan_lock); 47448c2ecf20Sopenharmony_ci 47458c2ecf20Sopenharmony_ci /* Initialize fast commit stuff */ 47468c2ecf20Sopenharmony_ci atomic_set(&sbi->s_fc_subtid, 0); 47478c2ecf20Sopenharmony_ci atomic_set(&sbi->s_fc_ineligible_updates, 0); 47488c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sbi->s_fc_q[FC_Q_MAIN]); 47498c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sbi->s_fc_q[FC_Q_STAGING]); 47508c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sbi->s_fc_dentry_q[FC_Q_MAIN]); 47518c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sbi->s_fc_dentry_q[FC_Q_STAGING]); 47528c2ecf20Sopenharmony_ci sbi->s_fc_bytes = 0; 47538c2ecf20Sopenharmony_ci ext4_clear_mount_flag(sb, EXT4_MF_FC_INELIGIBLE); 47548c2ecf20Sopenharmony_ci ext4_clear_mount_flag(sb, EXT4_MF_FC_COMMITTING); 47558c2ecf20Sopenharmony_ci spin_lock_init(&sbi->s_fc_lock); 47568c2ecf20Sopenharmony_ci memset(&sbi->s_fc_stats, 0, sizeof(sbi->s_fc_stats)); 47578c2ecf20Sopenharmony_ci sbi->s_fc_replay_state.fc_regions = NULL; 47588c2ecf20Sopenharmony_ci sbi->s_fc_replay_state.fc_regions_size = 0; 47598c2ecf20Sopenharmony_ci sbi->s_fc_replay_state.fc_regions_used = 0; 47608c2ecf20Sopenharmony_ci sbi->s_fc_replay_state.fc_regions_valid = 0; 47618c2ecf20Sopenharmony_ci sbi->s_fc_replay_state.fc_modified_inodes = NULL; 47628c2ecf20Sopenharmony_ci sbi->s_fc_replay_state.fc_modified_inodes_size = 0; 47638c2ecf20Sopenharmony_ci sbi->s_fc_replay_state.fc_modified_inodes_used = 0; 47648c2ecf20Sopenharmony_ci 47658c2ecf20Sopenharmony_ci sb->s_root = NULL; 47668c2ecf20Sopenharmony_ci 47678c2ecf20Sopenharmony_ci needs_recovery = (es->s_last_orphan != 0 || 47688c2ecf20Sopenharmony_ci ext4_has_feature_journal_needs_recovery(sb)); 47698c2ecf20Sopenharmony_ci 47708c2ecf20Sopenharmony_ci if (ext4_has_feature_mmp(sb) && !sb_rdonly(sb)) { 47718c2ecf20Sopenharmony_ci err = ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block)); 47728c2ecf20Sopenharmony_ci if (err) 47738c2ecf20Sopenharmony_ci goto failed_mount3a; 47748c2ecf20Sopenharmony_ci } 47758c2ecf20Sopenharmony_ci 47768c2ecf20Sopenharmony_ci /* 47778c2ecf20Sopenharmony_ci * The first inode we look at is the journal inode. Don't try 47788c2ecf20Sopenharmony_ci * root first: it may be modified in the journal! 47798c2ecf20Sopenharmony_ci */ 47808c2ecf20Sopenharmony_ci if (!test_opt(sb, NOLOAD) && ext4_has_feature_journal(sb)) { 47818c2ecf20Sopenharmony_ci err = ext4_load_journal(sb, es, journal_devnum); 47828c2ecf20Sopenharmony_ci if (err) 47838c2ecf20Sopenharmony_ci goto failed_mount3a; 47848c2ecf20Sopenharmony_ci } else if (test_opt(sb, NOLOAD) && !sb_rdonly(sb) && 47858c2ecf20Sopenharmony_ci ext4_has_feature_journal_needs_recovery(sb)) { 47868c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "required journal recovery " 47878c2ecf20Sopenharmony_ci "suppressed and not mounted read-only"); 47888c2ecf20Sopenharmony_ci goto failed_mount3a; 47898c2ecf20Sopenharmony_ci } else { 47908c2ecf20Sopenharmony_ci /* Nojournal mode, all journal mount options are illegal */ 47918c2ecf20Sopenharmony_ci if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) { 47928c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "can't mount with " 47938c2ecf20Sopenharmony_ci "journal_async_commit, fs mounted w/o journal"); 47948c2ecf20Sopenharmony_ci goto failed_mount3a; 47958c2ecf20Sopenharmony_ci } 47968c2ecf20Sopenharmony_ci 47978c2ecf20Sopenharmony_ci if (test_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM)) { 47988c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "can't mount with " 47998c2ecf20Sopenharmony_ci "journal_checksum, fs mounted w/o journal"); 48008c2ecf20Sopenharmony_ci goto failed_mount3a; 48018c2ecf20Sopenharmony_ci } 48028c2ecf20Sopenharmony_ci if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) { 48038c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "can't mount with " 48048c2ecf20Sopenharmony_ci "commit=%lu, fs mounted w/o journal", 48058c2ecf20Sopenharmony_ci sbi->s_commit_interval / HZ); 48068c2ecf20Sopenharmony_ci goto failed_mount3a; 48078c2ecf20Sopenharmony_ci } 48088c2ecf20Sopenharmony_ci if (EXT4_MOUNT_DATA_FLAGS & 48098c2ecf20Sopenharmony_ci (sbi->s_mount_opt ^ sbi->s_def_mount_opt)) { 48108c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "can't mount with " 48118c2ecf20Sopenharmony_ci "data=, fs mounted w/o journal"); 48128c2ecf20Sopenharmony_ci goto failed_mount3a; 48138c2ecf20Sopenharmony_ci } 48148c2ecf20Sopenharmony_ci sbi->s_def_mount_opt &= ~EXT4_MOUNT_JOURNAL_CHECKSUM; 48158c2ecf20Sopenharmony_ci clear_opt(sb, JOURNAL_CHECKSUM); 48168c2ecf20Sopenharmony_ci clear_opt(sb, DATA_FLAGS); 48178c2ecf20Sopenharmony_ci clear_opt2(sb, JOURNAL_FAST_COMMIT); 48188c2ecf20Sopenharmony_ci sbi->s_journal = NULL; 48198c2ecf20Sopenharmony_ci needs_recovery = 0; 48208c2ecf20Sopenharmony_ci goto no_journal; 48218c2ecf20Sopenharmony_ci } 48228c2ecf20Sopenharmony_ci 48238c2ecf20Sopenharmony_ci if (ext4_has_feature_64bit(sb) && 48248c2ecf20Sopenharmony_ci !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0, 48258c2ecf20Sopenharmony_ci JBD2_FEATURE_INCOMPAT_64BIT)) { 48268c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Failed to set 64-bit journal feature"); 48278c2ecf20Sopenharmony_ci goto failed_mount_wq; 48288c2ecf20Sopenharmony_ci } 48298c2ecf20Sopenharmony_ci 48308c2ecf20Sopenharmony_ci if (!set_journal_csum_feature_set(sb)) { 48318c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Failed to set journal checksum " 48328c2ecf20Sopenharmony_ci "feature set"); 48338c2ecf20Sopenharmony_ci goto failed_mount_wq; 48348c2ecf20Sopenharmony_ci } 48358c2ecf20Sopenharmony_ci 48368c2ecf20Sopenharmony_ci if (test_opt2(sb, JOURNAL_FAST_COMMIT) && 48378c2ecf20Sopenharmony_ci !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0, 48388c2ecf20Sopenharmony_ci JBD2_FEATURE_INCOMPAT_FAST_COMMIT)) { 48398c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 48408c2ecf20Sopenharmony_ci "Failed to set fast commit journal feature"); 48418c2ecf20Sopenharmony_ci goto failed_mount_wq; 48428c2ecf20Sopenharmony_ci } 48438c2ecf20Sopenharmony_ci 48448c2ecf20Sopenharmony_ci /* We have now updated the journal if required, so we can 48458c2ecf20Sopenharmony_ci * validate the data journaling mode. */ 48468c2ecf20Sopenharmony_ci switch (test_opt(sb, DATA_FLAGS)) { 48478c2ecf20Sopenharmony_ci case 0: 48488c2ecf20Sopenharmony_ci /* No mode set, assume a default based on the journal 48498c2ecf20Sopenharmony_ci * capabilities: ORDERED_DATA if the journal can 48508c2ecf20Sopenharmony_ci * cope, else JOURNAL_DATA 48518c2ecf20Sopenharmony_ci */ 48528c2ecf20Sopenharmony_ci if (jbd2_journal_check_available_features 48538c2ecf20Sopenharmony_ci (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)) { 48548c2ecf20Sopenharmony_ci set_opt(sb, ORDERED_DATA); 48558c2ecf20Sopenharmony_ci sbi->s_def_mount_opt |= EXT4_MOUNT_ORDERED_DATA; 48568c2ecf20Sopenharmony_ci } else { 48578c2ecf20Sopenharmony_ci set_opt(sb, JOURNAL_DATA); 48588c2ecf20Sopenharmony_ci sbi->s_def_mount_opt |= EXT4_MOUNT_JOURNAL_DATA; 48598c2ecf20Sopenharmony_ci } 48608c2ecf20Sopenharmony_ci break; 48618c2ecf20Sopenharmony_ci 48628c2ecf20Sopenharmony_ci case EXT4_MOUNT_ORDERED_DATA: 48638c2ecf20Sopenharmony_ci case EXT4_MOUNT_WRITEBACK_DATA: 48648c2ecf20Sopenharmony_ci if (!jbd2_journal_check_available_features 48658c2ecf20Sopenharmony_ci (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)) { 48668c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Journal does not support " 48678c2ecf20Sopenharmony_ci "requested data journaling mode"); 48688c2ecf20Sopenharmony_ci goto failed_mount_wq; 48698c2ecf20Sopenharmony_ci } 48708c2ecf20Sopenharmony_ci default: 48718c2ecf20Sopenharmony_ci break; 48728c2ecf20Sopenharmony_ci } 48738c2ecf20Sopenharmony_ci 48748c2ecf20Sopenharmony_ci if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA && 48758c2ecf20Sopenharmony_ci test_opt(sb, JOURNAL_ASYNC_COMMIT)) { 48768c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "can't mount with " 48778c2ecf20Sopenharmony_ci "journal_async_commit in data=ordered mode"); 48788c2ecf20Sopenharmony_ci goto failed_mount_wq; 48798c2ecf20Sopenharmony_ci } 48808c2ecf20Sopenharmony_ci 48818c2ecf20Sopenharmony_ci set_task_ioprio(sbi->s_journal->j_task, journal_ioprio); 48828c2ecf20Sopenharmony_ci 48838c2ecf20Sopenharmony_ci sbi->s_journal->j_submit_inode_data_buffers = 48848c2ecf20Sopenharmony_ci ext4_journal_submit_inode_data_buffers; 48858c2ecf20Sopenharmony_ci sbi->s_journal->j_finish_inode_data_buffers = 48868c2ecf20Sopenharmony_ci ext4_journal_finish_inode_data_buffers; 48878c2ecf20Sopenharmony_ci 48888c2ecf20Sopenharmony_cino_journal: 48898c2ecf20Sopenharmony_ci if (!test_opt(sb, NO_MBCACHE)) { 48908c2ecf20Sopenharmony_ci sbi->s_ea_block_cache = ext4_xattr_create_cache(); 48918c2ecf20Sopenharmony_ci if (!sbi->s_ea_block_cache) { 48928c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 48938c2ecf20Sopenharmony_ci "Failed to create ea_block_cache"); 48948c2ecf20Sopenharmony_ci goto failed_mount_wq; 48958c2ecf20Sopenharmony_ci } 48968c2ecf20Sopenharmony_ci 48978c2ecf20Sopenharmony_ci if (ext4_has_feature_ea_inode(sb)) { 48988c2ecf20Sopenharmony_ci sbi->s_ea_inode_cache = ext4_xattr_create_cache(); 48998c2ecf20Sopenharmony_ci if (!sbi->s_ea_inode_cache) { 49008c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 49018c2ecf20Sopenharmony_ci "Failed to create ea_inode_cache"); 49028c2ecf20Sopenharmony_ci goto failed_mount_wq; 49038c2ecf20Sopenharmony_ci } 49048c2ecf20Sopenharmony_ci } 49058c2ecf20Sopenharmony_ci } 49068c2ecf20Sopenharmony_ci 49078c2ecf20Sopenharmony_ci if (ext4_has_feature_verity(sb) && blocksize != PAGE_SIZE) { 49088c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Unsupported blocksize for fs-verity"); 49098c2ecf20Sopenharmony_ci goto failed_mount_wq; 49108c2ecf20Sopenharmony_ci } 49118c2ecf20Sopenharmony_ci 49128c2ecf20Sopenharmony_ci /* 49138c2ecf20Sopenharmony_ci * Get the # of file system overhead blocks from the 49148c2ecf20Sopenharmony_ci * superblock if present. 49158c2ecf20Sopenharmony_ci */ 49168c2ecf20Sopenharmony_ci sbi->s_overhead = le32_to_cpu(es->s_overhead_clusters); 49178c2ecf20Sopenharmony_ci /* ignore the precalculated value if it is ridiculous */ 49188c2ecf20Sopenharmony_ci if (sbi->s_overhead > ext4_blocks_count(es)) 49198c2ecf20Sopenharmony_ci sbi->s_overhead = 0; 49208c2ecf20Sopenharmony_ci /* 49218c2ecf20Sopenharmony_ci * If the bigalloc feature is not enabled recalculating the 49228c2ecf20Sopenharmony_ci * overhead doesn't take long, so we might as well just redo 49238c2ecf20Sopenharmony_ci * it to make sure we are using the correct value. 49248c2ecf20Sopenharmony_ci */ 49258c2ecf20Sopenharmony_ci if (!ext4_has_feature_bigalloc(sb)) 49268c2ecf20Sopenharmony_ci sbi->s_overhead = 0; 49278c2ecf20Sopenharmony_ci if (sbi->s_overhead == 0) { 49288c2ecf20Sopenharmony_ci err = ext4_calculate_overhead(sb); 49298c2ecf20Sopenharmony_ci if (err) 49308c2ecf20Sopenharmony_ci goto failed_mount_wq; 49318c2ecf20Sopenharmony_ci } 49328c2ecf20Sopenharmony_ci 49338c2ecf20Sopenharmony_ci /* 49348c2ecf20Sopenharmony_ci * The maximum number of concurrent works can be high and 49358c2ecf20Sopenharmony_ci * concurrency isn't really necessary. Limit it to 1. 49368c2ecf20Sopenharmony_ci */ 49378c2ecf20Sopenharmony_ci EXT4_SB(sb)->rsv_conversion_wq = 49388c2ecf20Sopenharmony_ci alloc_workqueue("ext4-rsv-conversion", WQ_MEM_RECLAIM | WQ_UNBOUND, 1); 49398c2ecf20Sopenharmony_ci if (!EXT4_SB(sb)->rsv_conversion_wq) { 49408c2ecf20Sopenharmony_ci printk(KERN_ERR "EXT4-fs: failed to create workqueue\n"); 49418c2ecf20Sopenharmony_ci ret = -ENOMEM; 49428c2ecf20Sopenharmony_ci goto failed_mount4; 49438c2ecf20Sopenharmony_ci } 49448c2ecf20Sopenharmony_ci 49458c2ecf20Sopenharmony_ci /* 49468c2ecf20Sopenharmony_ci * The jbd2_journal_load will have done any necessary log recovery, 49478c2ecf20Sopenharmony_ci * so we can safely mount the rest of the filesystem now. 49488c2ecf20Sopenharmony_ci */ 49498c2ecf20Sopenharmony_ci 49508c2ecf20Sopenharmony_ci root = ext4_iget(sb, EXT4_ROOT_INO, EXT4_IGET_SPECIAL); 49518c2ecf20Sopenharmony_ci if (IS_ERR(root)) { 49528c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "get root inode failed"); 49538c2ecf20Sopenharmony_ci ret = PTR_ERR(root); 49548c2ecf20Sopenharmony_ci root = NULL; 49558c2ecf20Sopenharmony_ci goto failed_mount4; 49568c2ecf20Sopenharmony_ci } 49578c2ecf20Sopenharmony_ci if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { 49588c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "corrupt root inode, run e2fsck"); 49598c2ecf20Sopenharmony_ci iput(root); 49608c2ecf20Sopenharmony_ci goto failed_mount4; 49618c2ecf20Sopenharmony_ci } 49628c2ecf20Sopenharmony_ci 49638c2ecf20Sopenharmony_ci#ifdef CONFIG_UNICODE 49648c2ecf20Sopenharmony_ci if (sb->s_encoding) 49658c2ecf20Sopenharmony_ci sb->s_d_op = &ext4_dentry_ops; 49668c2ecf20Sopenharmony_ci#endif 49678c2ecf20Sopenharmony_ci 49688c2ecf20Sopenharmony_ci sb->s_root = d_make_root(root); 49698c2ecf20Sopenharmony_ci if (!sb->s_root) { 49708c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "get root dentry failed"); 49718c2ecf20Sopenharmony_ci ret = -ENOMEM; 49728c2ecf20Sopenharmony_ci goto failed_mount4; 49738c2ecf20Sopenharmony_ci } 49748c2ecf20Sopenharmony_ci 49758c2ecf20Sopenharmony_ci ret = ext4_setup_super(sb, es, sb_rdonly(sb)); 49768c2ecf20Sopenharmony_ci if (ret == -EROFS) { 49778c2ecf20Sopenharmony_ci sb->s_flags |= SB_RDONLY; 49788c2ecf20Sopenharmony_ci ret = 0; 49798c2ecf20Sopenharmony_ci } else if (ret) 49808c2ecf20Sopenharmony_ci goto failed_mount4a; 49818c2ecf20Sopenharmony_ci 49828c2ecf20Sopenharmony_ci ext4_set_resv_clusters(sb); 49838c2ecf20Sopenharmony_ci 49848c2ecf20Sopenharmony_ci if (test_opt(sb, BLOCK_VALIDITY)) { 49858c2ecf20Sopenharmony_ci err = ext4_setup_system_zone(sb); 49868c2ecf20Sopenharmony_ci if (err) { 49878c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "failed to initialize system " 49888c2ecf20Sopenharmony_ci "zone (%d)", err); 49898c2ecf20Sopenharmony_ci goto failed_mount4a; 49908c2ecf20Sopenharmony_ci } 49918c2ecf20Sopenharmony_ci } 49928c2ecf20Sopenharmony_ci ext4_fc_replay_cleanup(sb); 49938c2ecf20Sopenharmony_ci 49948c2ecf20Sopenharmony_ci ext4_ext_init(sb); 49958c2ecf20Sopenharmony_ci err = ext4_mb_init(sb); 49968c2ecf20Sopenharmony_ci if (err) { 49978c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "failed to initialize mballoc (%d)", 49988c2ecf20Sopenharmony_ci err); 49998c2ecf20Sopenharmony_ci goto failed_mount5; 50008c2ecf20Sopenharmony_ci } 50018c2ecf20Sopenharmony_ci 50028c2ecf20Sopenharmony_ci /* 50038c2ecf20Sopenharmony_ci * We can only set up the journal commit callback once 50048c2ecf20Sopenharmony_ci * mballoc is initialized 50058c2ecf20Sopenharmony_ci */ 50068c2ecf20Sopenharmony_ci if (sbi->s_journal) 50078c2ecf20Sopenharmony_ci sbi->s_journal->j_commit_callback = 50088c2ecf20Sopenharmony_ci ext4_journal_commit_callback; 50098c2ecf20Sopenharmony_ci 50108c2ecf20Sopenharmony_ci block = ext4_count_free_clusters(sb); 50118c2ecf20Sopenharmony_ci ext4_free_blocks_count_set(sbi->s_es, 50128c2ecf20Sopenharmony_ci EXT4_C2B(sbi, block)); 50138c2ecf20Sopenharmony_ci err = percpu_counter_init(&sbi->s_freeclusters_counter, block, 50148c2ecf20Sopenharmony_ci GFP_KERNEL); 50158c2ecf20Sopenharmony_ci if (!err) { 50168c2ecf20Sopenharmony_ci unsigned long freei = ext4_count_free_inodes(sb); 50178c2ecf20Sopenharmony_ci sbi->s_es->s_free_inodes_count = cpu_to_le32(freei); 50188c2ecf20Sopenharmony_ci err = percpu_counter_init(&sbi->s_freeinodes_counter, freei, 50198c2ecf20Sopenharmony_ci GFP_KERNEL); 50208c2ecf20Sopenharmony_ci } 50218c2ecf20Sopenharmony_ci /* 50228c2ecf20Sopenharmony_ci * Update the checksum after updating free space/inode 50238c2ecf20Sopenharmony_ci * counters. Otherwise the superblock can have an incorrect 50248c2ecf20Sopenharmony_ci * checksum in the buffer cache until it is written out and 50258c2ecf20Sopenharmony_ci * e2fsprogs programs trying to open a file system immediately 50268c2ecf20Sopenharmony_ci * after it is mounted can fail. 50278c2ecf20Sopenharmony_ci */ 50288c2ecf20Sopenharmony_ci ext4_superblock_csum_set(sb); 50298c2ecf20Sopenharmony_ci if (!err) 50308c2ecf20Sopenharmony_ci err = percpu_counter_init(&sbi->s_dirs_counter, 50318c2ecf20Sopenharmony_ci ext4_count_dirs(sb), GFP_KERNEL); 50328c2ecf20Sopenharmony_ci if (!err) 50338c2ecf20Sopenharmony_ci err = percpu_counter_init(&sbi->s_dirtyclusters_counter, 0, 50348c2ecf20Sopenharmony_ci GFP_KERNEL); 50358c2ecf20Sopenharmony_ci if (!err) 50368c2ecf20Sopenharmony_ci err = percpu_counter_init(&sbi->s_sra_exceeded_retry_limit, 0, 50378c2ecf20Sopenharmony_ci GFP_KERNEL); 50388c2ecf20Sopenharmony_ci if (!err) 50398c2ecf20Sopenharmony_ci err = percpu_init_rwsem(&sbi->s_writepages_rwsem); 50408c2ecf20Sopenharmony_ci 50418c2ecf20Sopenharmony_ci if (err) { 50428c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "insufficient memory"); 50438c2ecf20Sopenharmony_ci goto failed_mount6; 50448c2ecf20Sopenharmony_ci } 50458c2ecf20Sopenharmony_ci 50468c2ecf20Sopenharmony_ci if (ext4_has_feature_flex_bg(sb)) 50478c2ecf20Sopenharmony_ci if (!ext4_fill_flex_info(sb)) { 50488c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 50498c2ecf20Sopenharmony_ci "unable to initialize " 50508c2ecf20Sopenharmony_ci "flex_bg meta info!"); 50518c2ecf20Sopenharmony_ci ret = -ENOMEM; 50528c2ecf20Sopenharmony_ci goto failed_mount6; 50538c2ecf20Sopenharmony_ci } 50548c2ecf20Sopenharmony_ci 50558c2ecf20Sopenharmony_ci err = ext4_register_li_request(sb, first_not_zeroed); 50568c2ecf20Sopenharmony_ci if (err) 50578c2ecf20Sopenharmony_ci goto failed_mount6; 50588c2ecf20Sopenharmony_ci 50598c2ecf20Sopenharmony_ci err = ext4_register_sysfs(sb); 50608c2ecf20Sopenharmony_ci if (err) 50618c2ecf20Sopenharmony_ci goto failed_mount7; 50628c2ecf20Sopenharmony_ci 50638c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 50648c2ecf20Sopenharmony_ci /* Enable quota usage during mount. */ 50658c2ecf20Sopenharmony_ci if (ext4_has_feature_quota(sb) && !sb_rdonly(sb)) { 50668c2ecf20Sopenharmony_ci err = ext4_enable_quotas(sb); 50678c2ecf20Sopenharmony_ci if (err) 50688c2ecf20Sopenharmony_ci goto failed_mount8; 50698c2ecf20Sopenharmony_ci } 50708c2ecf20Sopenharmony_ci#endif /* CONFIG_QUOTA */ 50718c2ecf20Sopenharmony_ci 50728c2ecf20Sopenharmony_ci /* 50738c2ecf20Sopenharmony_ci * Save the original bdev mapping's wb_err value which could be 50748c2ecf20Sopenharmony_ci * used to detect the metadata async write error. 50758c2ecf20Sopenharmony_ci */ 50768c2ecf20Sopenharmony_ci spin_lock_init(&sbi->s_bdev_wb_lock); 50778c2ecf20Sopenharmony_ci errseq_check_and_advance(&sb->s_bdev->bd_inode->i_mapping->wb_err, 50788c2ecf20Sopenharmony_ci &sbi->s_bdev_wb_err); 50798c2ecf20Sopenharmony_ci sb->s_bdev->bd_super = sb; 50808c2ecf20Sopenharmony_ci EXT4_SB(sb)->s_mount_state |= EXT4_ORPHAN_FS; 50818c2ecf20Sopenharmony_ci ext4_orphan_cleanup(sb, es); 50828c2ecf20Sopenharmony_ci EXT4_SB(sb)->s_mount_state &= ~EXT4_ORPHAN_FS; 50838c2ecf20Sopenharmony_ci if (needs_recovery) { 50848c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "recovery complete"); 50858c2ecf20Sopenharmony_ci err = ext4_mark_recovery_complete(sb, es); 50868c2ecf20Sopenharmony_ci if (err) 50878c2ecf20Sopenharmony_ci goto failed_mount8; 50888c2ecf20Sopenharmony_ci } 50898c2ecf20Sopenharmony_ci if (EXT4_SB(sb)->s_journal) { 50908c2ecf20Sopenharmony_ci if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) 50918c2ecf20Sopenharmony_ci descr = " journalled data mode"; 50928c2ecf20Sopenharmony_ci else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) 50938c2ecf20Sopenharmony_ci descr = " ordered data mode"; 50948c2ecf20Sopenharmony_ci else 50958c2ecf20Sopenharmony_ci descr = " writeback data mode"; 50968c2ecf20Sopenharmony_ci } else 50978c2ecf20Sopenharmony_ci descr = "out journal"; 50988c2ecf20Sopenharmony_ci 50998c2ecf20Sopenharmony_ci if (test_opt(sb, DISCARD)) { 51008c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(sb->s_bdev); 51018c2ecf20Sopenharmony_ci if (!blk_queue_discard(q)) 51028c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 51038c2ecf20Sopenharmony_ci "mounting with \"discard\" option, but " 51048c2ecf20Sopenharmony_ci "the device does not support discard"); 51058c2ecf20Sopenharmony_ci } 51068c2ecf20Sopenharmony_ci 51078c2ecf20Sopenharmony_ci if (___ratelimit(&ext4_mount_msg_ratelimit, "EXT4-fs mount")) 51088c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. " 51098c2ecf20Sopenharmony_ci "Opts: %.*s%s%s", descr, 51108c2ecf20Sopenharmony_ci (int) sizeof(sbi->s_es->s_mount_opts), 51118c2ecf20Sopenharmony_ci sbi->s_es->s_mount_opts, 51128c2ecf20Sopenharmony_ci *sbi->s_es->s_mount_opts ? "; " : "", orig_data); 51138c2ecf20Sopenharmony_ci 51148c2ecf20Sopenharmony_ci if (es->s_error_count) 51158c2ecf20Sopenharmony_ci mod_timer(&sbi->s_err_report, jiffies + 300*HZ); /* 5 minutes */ 51168c2ecf20Sopenharmony_ci 51178c2ecf20Sopenharmony_ci /* Enable message ratelimiting. Default is 10 messages per 5 secs. */ 51188c2ecf20Sopenharmony_ci ratelimit_state_init(&sbi->s_err_ratelimit_state, 5 * HZ, 10); 51198c2ecf20Sopenharmony_ci ratelimit_state_init(&sbi->s_warning_ratelimit_state, 5 * HZ, 10); 51208c2ecf20Sopenharmony_ci ratelimit_state_init(&sbi->s_msg_ratelimit_state, 5 * HZ, 10); 51218c2ecf20Sopenharmony_ci atomic_set(&sbi->s_warning_count, 0); 51228c2ecf20Sopenharmony_ci atomic_set(&sbi->s_msg_count, 0); 51238c2ecf20Sopenharmony_ci 51248c2ecf20Sopenharmony_ci kfree(orig_data); 51258c2ecf20Sopenharmony_ci return 0; 51268c2ecf20Sopenharmony_ci 51278c2ecf20Sopenharmony_cicantfind_ext4: 51288c2ecf20Sopenharmony_ci if (!silent) 51298c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "VFS: Can't find ext4 filesystem"); 51308c2ecf20Sopenharmony_ci goto failed_mount; 51318c2ecf20Sopenharmony_ci 51328c2ecf20Sopenharmony_cifailed_mount8: 51338c2ecf20Sopenharmony_ci ext4_unregister_sysfs(sb); 51348c2ecf20Sopenharmony_ci kobject_put(&sbi->s_kobj); 51358c2ecf20Sopenharmony_cifailed_mount7: 51368c2ecf20Sopenharmony_ci ext4_unregister_li_request(sb); 51378c2ecf20Sopenharmony_cifailed_mount6: 51388c2ecf20Sopenharmony_ci ext4_mb_release(sb); 51398c2ecf20Sopenharmony_ci rcu_read_lock(); 51408c2ecf20Sopenharmony_ci flex_groups = rcu_dereference(sbi->s_flex_groups); 51418c2ecf20Sopenharmony_ci if (flex_groups) { 51428c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_flex_groups_allocated; i++) 51438c2ecf20Sopenharmony_ci kvfree(flex_groups[i]); 51448c2ecf20Sopenharmony_ci kvfree(flex_groups); 51458c2ecf20Sopenharmony_ci } 51468c2ecf20Sopenharmony_ci rcu_read_unlock(); 51478c2ecf20Sopenharmony_ci percpu_counter_destroy(&sbi->s_freeclusters_counter); 51488c2ecf20Sopenharmony_ci percpu_counter_destroy(&sbi->s_freeinodes_counter); 51498c2ecf20Sopenharmony_ci percpu_counter_destroy(&sbi->s_dirs_counter); 51508c2ecf20Sopenharmony_ci percpu_counter_destroy(&sbi->s_dirtyclusters_counter); 51518c2ecf20Sopenharmony_ci percpu_counter_destroy(&sbi->s_sra_exceeded_retry_limit); 51528c2ecf20Sopenharmony_ci percpu_free_rwsem(&sbi->s_writepages_rwsem); 51538c2ecf20Sopenharmony_cifailed_mount5: 51548c2ecf20Sopenharmony_ci ext4_ext_release(sb); 51558c2ecf20Sopenharmony_ci ext4_release_system_zone(sb); 51568c2ecf20Sopenharmony_cifailed_mount4a: 51578c2ecf20Sopenharmony_ci dput(sb->s_root); 51588c2ecf20Sopenharmony_ci sb->s_root = NULL; 51598c2ecf20Sopenharmony_cifailed_mount4: 51608c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "mount failed"); 51618c2ecf20Sopenharmony_ci if (EXT4_SB(sb)->rsv_conversion_wq) 51628c2ecf20Sopenharmony_ci destroy_workqueue(EXT4_SB(sb)->rsv_conversion_wq); 51638c2ecf20Sopenharmony_cifailed_mount_wq: 51648c2ecf20Sopenharmony_ci ext4_xattr_destroy_cache(sbi->s_ea_inode_cache); 51658c2ecf20Sopenharmony_ci sbi->s_ea_inode_cache = NULL; 51668c2ecf20Sopenharmony_ci 51678c2ecf20Sopenharmony_ci ext4_xattr_destroy_cache(sbi->s_ea_block_cache); 51688c2ecf20Sopenharmony_ci sbi->s_ea_block_cache = NULL; 51698c2ecf20Sopenharmony_ci 51708c2ecf20Sopenharmony_ci if (sbi->s_journal) { 51718c2ecf20Sopenharmony_ci /* flush s_error_work before journal destroy. */ 51728c2ecf20Sopenharmony_ci flush_work(&sbi->s_error_work); 51738c2ecf20Sopenharmony_ci jbd2_journal_destroy(sbi->s_journal); 51748c2ecf20Sopenharmony_ci sbi->s_journal = NULL; 51758c2ecf20Sopenharmony_ci } 51768c2ecf20Sopenharmony_cifailed_mount3a: 51778c2ecf20Sopenharmony_ci ext4_es_unregister_shrinker(sbi); 51788c2ecf20Sopenharmony_cifailed_mount3: 51798c2ecf20Sopenharmony_ci /* flush s_error_work before sbi destroy */ 51808c2ecf20Sopenharmony_ci flush_work(&sbi->s_error_work); 51818c2ecf20Sopenharmony_ci del_timer_sync(&sbi->s_err_report); 51828c2ecf20Sopenharmony_ci ext4_stop_mmpd(sbi); 51838c2ecf20Sopenharmony_cifailed_mount2: 51848c2ecf20Sopenharmony_ci rcu_read_lock(); 51858c2ecf20Sopenharmony_ci group_desc = rcu_dereference(sbi->s_group_desc); 51868c2ecf20Sopenharmony_ci for (i = 0; i < db_count; i++) 51878c2ecf20Sopenharmony_ci brelse(group_desc[i]); 51888c2ecf20Sopenharmony_ci kvfree(group_desc); 51898c2ecf20Sopenharmony_ci rcu_read_unlock(); 51908c2ecf20Sopenharmony_cifailed_mount: 51918c2ecf20Sopenharmony_ci if (sbi->s_chksum_driver) 51928c2ecf20Sopenharmony_ci crypto_free_shash(sbi->s_chksum_driver); 51938c2ecf20Sopenharmony_ci 51948c2ecf20Sopenharmony_ci#ifdef CONFIG_UNICODE 51958c2ecf20Sopenharmony_ci utf8_unload(sb->s_encoding); 51968c2ecf20Sopenharmony_ci#endif 51978c2ecf20Sopenharmony_ci 51988c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 51998c2ecf20Sopenharmony_ci for (i = 0; i < EXT4_MAXQUOTAS; i++) 52008c2ecf20Sopenharmony_ci kfree(get_qf_name(sb, sbi, i)); 52018c2ecf20Sopenharmony_ci#endif 52028c2ecf20Sopenharmony_ci fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy); 52038c2ecf20Sopenharmony_ci /* ext4_blkdev_remove() calls kill_bdev(), release bh before it. */ 52048c2ecf20Sopenharmony_ci brelse(bh); 52058c2ecf20Sopenharmony_ci ext4_blkdev_remove(sbi); 52068c2ecf20Sopenharmony_ciout_fail: 52078c2ecf20Sopenharmony_ci invalidate_bdev(sb->s_bdev); 52088c2ecf20Sopenharmony_ci sb->s_fs_info = NULL; 52098c2ecf20Sopenharmony_ci kfree(sbi->s_blockgroup_lock); 52108c2ecf20Sopenharmony_ciout_free_base: 52118c2ecf20Sopenharmony_ci kfree(sbi); 52128c2ecf20Sopenharmony_ci kfree(orig_data); 52138c2ecf20Sopenharmony_ci fs_put_dax(dax_dev); 52148c2ecf20Sopenharmony_ci return err ? err : ret; 52158c2ecf20Sopenharmony_ci} 52168c2ecf20Sopenharmony_ci 52178c2ecf20Sopenharmony_ci/* 52188c2ecf20Sopenharmony_ci * Setup any per-fs journal parameters now. We'll do this both on 52198c2ecf20Sopenharmony_ci * initial mount, once the journal has been initialised but before we've 52208c2ecf20Sopenharmony_ci * done any recovery; and again on any subsequent remount. 52218c2ecf20Sopenharmony_ci */ 52228c2ecf20Sopenharmony_cistatic void ext4_init_journal_params(struct super_block *sb, journal_t *journal) 52238c2ecf20Sopenharmony_ci{ 52248c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 52258c2ecf20Sopenharmony_ci 52268c2ecf20Sopenharmony_ci journal->j_commit_interval = sbi->s_commit_interval; 52278c2ecf20Sopenharmony_ci journal->j_min_batch_time = sbi->s_min_batch_time; 52288c2ecf20Sopenharmony_ci journal->j_max_batch_time = sbi->s_max_batch_time; 52298c2ecf20Sopenharmony_ci ext4_fc_init(sb, journal); 52308c2ecf20Sopenharmony_ci 52318c2ecf20Sopenharmony_ci write_lock(&journal->j_state_lock); 52328c2ecf20Sopenharmony_ci if (test_opt(sb, BARRIER)) 52338c2ecf20Sopenharmony_ci journal->j_flags |= JBD2_BARRIER; 52348c2ecf20Sopenharmony_ci else 52358c2ecf20Sopenharmony_ci journal->j_flags &= ~JBD2_BARRIER; 52368c2ecf20Sopenharmony_ci if (test_opt(sb, DATA_ERR_ABORT)) 52378c2ecf20Sopenharmony_ci journal->j_flags |= JBD2_ABORT_ON_SYNCDATA_ERR; 52388c2ecf20Sopenharmony_ci else 52398c2ecf20Sopenharmony_ci journal->j_flags &= ~JBD2_ABORT_ON_SYNCDATA_ERR; 52408c2ecf20Sopenharmony_ci write_unlock(&journal->j_state_lock); 52418c2ecf20Sopenharmony_ci} 52428c2ecf20Sopenharmony_ci 52438c2ecf20Sopenharmony_cistatic struct inode *ext4_get_journal_inode(struct super_block *sb, 52448c2ecf20Sopenharmony_ci unsigned int journal_inum) 52458c2ecf20Sopenharmony_ci{ 52468c2ecf20Sopenharmony_ci struct inode *journal_inode; 52478c2ecf20Sopenharmony_ci 52488c2ecf20Sopenharmony_ci /* 52498c2ecf20Sopenharmony_ci * Test for the existence of a valid inode on disk. Bad things 52508c2ecf20Sopenharmony_ci * happen if we iget() an unused inode, as the subsequent iput() 52518c2ecf20Sopenharmony_ci * will try to delete it. 52528c2ecf20Sopenharmony_ci */ 52538c2ecf20Sopenharmony_ci journal_inode = ext4_iget(sb, journal_inum, EXT4_IGET_SPECIAL); 52548c2ecf20Sopenharmony_ci if (IS_ERR(journal_inode)) { 52558c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "no journal found"); 52568c2ecf20Sopenharmony_ci return NULL; 52578c2ecf20Sopenharmony_ci } 52588c2ecf20Sopenharmony_ci if (!journal_inode->i_nlink) { 52598c2ecf20Sopenharmony_ci make_bad_inode(journal_inode); 52608c2ecf20Sopenharmony_ci iput(journal_inode); 52618c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "journal inode is deleted"); 52628c2ecf20Sopenharmony_ci return NULL; 52638c2ecf20Sopenharmony_ci } 52648c2ecf20Sopenharmony_ci 52658c2ecf20Sopenharmony_ci jbd_debug(2, "Journal inode found at %p: %lld bytes\n", 52668c2ecf20Sopenharmony_ci journal_inode, journal_inode->i_size); 52678c2ecf20Sopenharmony_ci if (!S_ISREG(journal_inode->i_mode) || IS_ENCRYPTED(journal_inode)) { 52688c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "invalid journal inode"); 52698c2ecf20Sopenharmony_ci iput(journal_inode); 52708c2ecf20Sopenharmony_ci return NULL; 52718c2ecf20Sopenharmony_ci } 52728c2ecf20Sopenharmony_ci return journal_inode; 52738c2ecf20Sopenharmony_ci} 52748c2ecf20Sopenharmony_ci 52758c2ecf20Sopenharmony_cistatic journal_t *ext4_get_journal(struct super_block *sb, 52768c2ecf20Sopenharmony_ci unsigned int journal_inum) 52778c2ecf20Sopenharmony_ci{ 52788c2ecf20Sopenharmony_ci struct inode *journal_inode; 52798c2ecf20Sopenharmony_ci journal_t *journal; 52808c2ecf20Sopenharmony_ci 52818c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!ext4_has_feature_journal(sb))) 52828c2ecf20Sopenharmony_ci return NULL; 52838c2ecf20Sopenharmony_ci 52848c2ecf20Sopenharmony_ci journal_inode = ext4_get_journal_inode(sb, journal_inum); 52858c2ecf20Sopenharmony_ci if (!journal_inode) 52868c2ecf20Sopenharmony_ci return NULL; 52878c2ecf20Sopenharmony_ci 52888c2ecf20Sopenharmony_ci journal = jbd2_journal_init_inode(journal_inode); 52898c2ecf20Sopenharmony_ci if (!journal) { 52908c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Could not load journal inode"); 52918c2ecf20Sopenharmony_ci iput(journal_inode); 52928c2ecf20Sopenharmony_ci return NULL; 52938c2ecf20Sopenharmony_ci } 52948c2ecf20Sopenharmony_ci journal->j_private = sb; 52958c2ecf20Sopenharmony_ci ext4_init_journal_params(sb, journal); 52968c2ecf20Sopenharmony_ci return journal; 52978c2ecf20Sopenharmony_ci} 52988c2ecf20Sopenharmony_ci 52998c2ecf20Sopenharmony_cistatic journal_t *ext4_get_dev_journal(struct super_block *sb, 53008c2ecf20Sopenharmony_ci dev_t j_dev) 53018c2ecf20Sopenharmony_ci{ 53028c2ecf20Sopenharmony_ci struct buffer_head *bh; 53038c2ecf20Sopenharmony_ci journal_t *journal; 53048c2ecf20Sopenharmony_ci ext4_fsblk_t start; 53058c2ecf20Sopenharmony_ci ext4_fsblk_t len; 53068c2ecf20Sopenharmony_ci int hblock, blocksize; 53078c2ecf20Sopenharmony_ci ext4_fsblk_t sb_block; 53088c2ecf20Sopenharmony_ci unsigned long offset; 53098c2ecf20Sopenharmony_ci struct ext4_super_block *es; 53108c2ecf20Sopenharmony_ci struct block_device *bdev; 53118c2ecf20Sopenharmony_ci 53128c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!ext4_has_feature_journal(sb))) 53138c2ecf20Sopenharmony_ci return NULL; 53148c2ecf20Sopenharmony_ci 53158c2ecf20Sopenharmony_ci bdev = ext4_blkdev_get(j_dev, sb); 53168c2ecf20Sopenharmony_ci if (bdev == NULL) 53178c2ecf20Sopenharmony_ci return NULL; 53188c2ecf20Sopenharmony_ci 53198c2ecf20Sopenharmony_ci blocksize = sb->s_blocksize; 53208c2ecf20Sopenharmony_ci hblock = bdev_logical_block_size(bdev); 53218c2ecf20Sopenharmony_ci if (blocksize < hblock) { 53228c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 53238c2ecf20Sopenharmony_ci "blocksize too small for journal device"); 53248c2ecf20Sopenharmony_ci goto out_bdev; 53258c2ecf20Sopenharmony_ci } 53268c2ecf20Sopenharmony_ci 53278c2ecf20Sopenharmony_ci sb_block = EXT4_MIN_BLOCK_SIZE / blocksize; 53288c2ecf20Sopenharmony_ci offset = EXT4_MIN_BLOCK_SIZE % blocksize; 53298c2ecf20Sopenharmony_ci set_blocksize(bdev, blocksize); 53308c2ecf20Sopenharmony_ci if (!(bh = __bread(bdev, sb_block, blocksize))) { 53318c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "couldn't read superblock of " 53328c2ecf20Sopenharmony_ci "external journal"); 53338c2ecf20Sopenharmony_ci goto out_bdev; 53348c2ecf20Sopenharmony_ci } 53358c2ecf20Sopenharmony_ci 53368c2ecf20Sopenharmony_ci es = (struct ext4_super_block *) (bh->b_data + offset); 53378c2ecf20Sopenharmony_ci if ((le16_to_cpu(es->s_magic) != EXT4_SUPER_MAGIC) || 53388c2ecf20Sopenharmony_ci !(le32_to_cpu(es->s_feature_incompat) & 53398c2ecf20Sopenharmony_ci EXT4_FEATURE_INCOMPAT_JOURNAL_DEV)) { 53408c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "external journal has " 53418c2ecf20Sopenharmony_ci "bad superblock"); 53428c2ecf20Sopenharmony_ci brelse(bh); 53438c2ecf20Sopenharmony_ci goto out_bdev; 53448c2ecf20Sopenharmony_ci } 53458c2ecf20Sopenharmony_ci 53468c2ecf20Sopenharmony_ci if ((le32_to_cpu(es->s_feature_ro_compat) & 53478c2ecf20Sopenharmony_ci EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) && 53488c2ecf20Sopenharmony_ci es->s_checksum != ext4_superblock_csum(sb, es)) { 53498c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "external journal has " 53508c2ecf20Sopenharmony_ci "corrupt superblock"); 53518c2ecf20Sopenharmony_ci brelse(bh); 53528c2ecf20Sopenharmony_ci goto out_bdev; 53538c2ecf20Sopenharmony_ci } 53548c2ecf20Sopenharmony_ci 53558c2ecf20Sopenharmony_ci if (memcmp(EXT4_SB(sb)->s_es->s_journal_uuid, es->s_uuid, 16)) { 53568c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "journal UUID does not match"); 53578c2ecf20Sopenharmony_ci brelse(bh); 53588c2ecf20Sopenharmony_ci goto out_bdev; 53598c2ecf20Sopenharmony_ci } 53608c2ecf20Sopenharmony_ci 53618c2ecf20Sopenharmony_ci len = ext4_blocks_count(es); 53628c2ecf20Sopenharmony_ci start = sb_block + 1; 53638c2ecf20Sopenharmony_ci brelse(bh); /* we're done with the superblock */ 53648c2ecf20Sopenharmony_ci 53658c2ecf20Sopenharmony_ci journal = jbd2_journal_init_dev(bdev, sb->s_bdev, 53668c2ecf20Sopenharmony_ci start, len, blocksize); 53678c2ecf20Sopenharmony_ci if (!journal) { 53688c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "failed to create device journal"); 53698c2ecf20Sopenharmony_ci goto out_bdev; 53708c2ecf20Sopenharmony_ci } 53718c2ecf20Sopenharmony_ci journal->j_private = sb; 53728c2ecf20Sopenharmony_ci if (ext4_read_bh_lock(journal->j_sb_buffer, REQ_META | REQ_PRIO, true)) { 53738c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "I/O error on journal device"); 53748c2ecf20Sopenharmony_ci goto out_journal; 53758c2ecf20Sopenharmony_ci } 53768c2ecf20Sopenharmony_ci if (be32_to_cpu(journal->j_superblock->s_nr_users) != 1) { 53778c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "External journal has more than one " 53788c2ecf20Sopenharmony_ci "user (unsupported) - %d", 53798c2ecf20Sopenharmony_ci be32_to_cpu(journal->j_superblock->s_nr_users)); 53808c2ecf20Sopenharmony_ci goto out_journal; 53818c2ecf20Sopenharmony_ci } 53828c2ecf20Sopenharmony_ci EXT4_SB(sb)->s_journal_bdev = bdev; 53838c2ecf20Sopenharmony_ci ext4_init_journal_params(sb, journal); 53848c2ecf20Sopenharmony_ci return journal; 53858c2ecf20Sopenharmony_ci 53868c2ecf20Sopenharmony_ciout_journal: 53878c2ecf20Sopenharmony_ci jbd2_journal_destroy(journal); 53888c2ecf20Sopenharmony_ciout_bdev: 53898c2ecf20Sopenharmony_ci ext4_blkdev_put(bdev); 53908c2ecf20Sopenharmony_ci return NULL; 53918c2ecf20Sopenharmony_ci} 53928c2ecf20Sopenharmony_ci 53938c2ecf20Sopenharmony_cistatic int ext4_load_journal(struct super_block *sb, 53948c2ecf20Sopenharmony_ci struct ext4_super_block *es, 53958c2ecf20Sopenharmony_ci unsigned long journal_devnum) 53968c2ecf20Sopenharmony_ci{ 53978c2ecf20Sopenharmony_ci journal_t *journal; 53988c2ecf20Sopenharmony_ci unsigned int journal_inum = le32_to_cpu(es->s_journal_inum); 53998c2ecf20Sopenharmony_ci dev_t journal_dev; 54008c2ecf20Sopenharmony_ci int err = 0; 54018c2ecf20Sopenharmony_ci int really_read_only; 54028c2ecf20Sopenharmony_ci int journal_dev_ro; 54038c2ecf20Sopenharmony_ci 54048c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!ext4_has_feature_journal(sb))) 54058c2ecf20Sopenharmony_ci return -EFSCORRUPTED; 54068c2ecf20Sopenharmony_ci 54078c2ecf20Sopenharmony_ci if (journal_devnum && 54088c2ecf20Sopenharmony_ci journal_devnum != le32_to_cpu(es->s_journal_dev)) { 54098c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "external journal device major/minor " 54108c2ecf20Sopenharmony_ci "numbers have changed"); 54118c2ecf20Sopenharmony_ci journal_dev = new_decode_dev(journal_devnum); 54128c2ecf20Sopenharmony_ci } else 54138c2ecf20Sopenharmony_ci journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev)); 54148c2ecf20Sopenharmony_ci 54158c2ecf20Sopenharmony_ci if (journal_inum && journal_dev) { 54168c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 54178c2ecf20Sopenharmony_ci "filesystem has both journal inode and journal device!"); 54188c2ecf20Sopenharmony_ci return -EINVAL; 54198c2ecf20Sopenharmony_ci } 54208c2ecf20Sopenharmony_ci 54218c2ecf20Sopenharmony_ci if (journal_inum) { 54228c2ecf20Sopenharmony_ci journal = ext4_get_journal(sb, journal_inum); 54238c2ecf20Sopenharmony_ci if (!journal) 54248c2ecf20Sopenharmony_ci return -EINVAL; 54258c2ecf20Sopenharmony_ci } else { 54268c2ecf20Sopenharmony_ci journal = ext4_get_dev_journal(sb, journal_dev); 54278c2ecf20Sopenharmony_ci if (!journal) 54288c2ecf20Sopenharmony_ci return -EINVAL; 54298c2ecf20Sopenharmony_ci } 54308c2ecf20Sopenharmony_ci 54318c2ecf20Sopenharmony_ci journal_dev_ro = bdev_read_only(journal->j_dev); 54328c2ecf20Sopenharmony_ci really_read_only = bdev_read_only(sb->s_bdev) | journal_dev_ro; 54338c2ecf20Sopenharmony_ci 54348c2ecf20Sopenharmony_ci if (journal_dev_ro && !sb_rdonly(sb)) { 54358c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 54368c2ecf20Sopenharmony_ci "journal device read-only, try mounting with '-o ro'"); 54378c2ecf20Sopenharmony_ci err = -EROFS; 54388c2ecf20Sopenharmony_ci goto err_out; 54398c2ecf20Sopenharmony_ci } 54408c2ecf20Sopenharmony_ci 54418c2ecf20Sopenharmony_ci /* 54428c2ecf20Sopenharmony_ci * Are we loading a blank journal or performing recovery after a 54438c2ecf20Sopenharmony_ci * crash? For recovery, we need to check in advance whether we 54448c2ecf20Sopenharmony_ci * can get read-write access to the device. 54458c2ecf20Sopenharmony_ci */ 54468c2ecf20Sopenharmony_ci if (ext4_has_feature_journal_needs_recovery(sb)) { 54478c2ecf20Sopenharmony_ci if (sb_rdonly(sb)) { 54488c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "INFO: recovery " 54498c2ecf20Sopenharmony_ci "required on readonly filesystem"); 54508c2ecf20Sopenharmony_ci if (really_read_only) { 54518c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "write access " 54528c2ecf20Sopenharmony_ci "unavailable, cannot proceed " 54538c2ecf20Sopenharmony_ci "(try mounting with noload)"); 54548c2ecf20Sopenharmony_ci err = -EROFS; 54558c2ecf20Sopenharmony_ci goto err_out; 54568c2ecf20Sopenharmony_ci } 54578c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "write access will " 54588c2ecf20Sopenharmony_ci "be enabled during recovery"); 54598c2ecf20Sopenharmony_ci } 54608c2ecf20Sopenharmony_ci } 54618c2ecf20Sopenharmony_ci 54628c2ecf20Sopenharmony_ci if (!(journal->j_flags & JBD2_BARRIER)) 54638c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "barriers disabled"); 54648c2ecf20Sopenharmony_ci 54658c2ecf20Sopenharmony_ci if (!ext4_has_feature_journal_needs_recovery(sb)) 54668c2ecf20Sopenharmony_ci err = jbd2_journal_wipe(journal, !really_read_only); 54678c2ecf20Sopenharmony_ci if (!err) { 54688c2ecf20Sopenharmony_ci char *save = kmalloc(EXT4_S_ERR_LEN, GFP_KERNEL); 54698c2ecf20Sopenharmony_ci if (save) 54708c2ecf20Sopenharmony_ci memcpy(save, ((char *) es) + 54718c2ecf20Sopenharmony_ci EXT4_S_ERR_START, EXT4_S_ERR_LEN); 54728c2ecf20Sopenharmony_ci err = jbd2_journal_load(journal); 54738c2ecf20Sopenharmony_ci if (save) 54748c2ecf20Sopenharmony_ci memcpy(((char *) es) + EXT4_S_ERR_START, 54758c2ecf20Sopenharmony_ci save, EXT4_S_ERR_LEN); 54768c2ecf20Sopenharmony_ci kfree(save); 54778c2ecf20Sopenharmony_ci } 54788c2ecf20Sopenharmony_ci 54798c2ecf20Sopenharmony_ci if (err) { 54808c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "error loading journal"); 54818c2ecf20Sopenharmony_ci goto err_out; 54828c2ecf20Sopenharmony_ci } 54838c2ecf20Sopenharmony_ci 54848c2ecf20Sopenharmony_ci EXT4_SB(sb)->s_journal = journal; 54858c2ecf20Sopenharmony_ci err = ext4_clear_journal_err(sb, es); 54868c2ecf20Sopenharmony_ci if (err) { 54878c2ecf20Sopenharmony_ci EXT4_SB(sb)->s_journal = NULL; 54888c2ecf20Sopenharmony_ci jbd2_journal_destroy(journal); 54898c2ecf20Sopenharmony_ci return err; 54908c2ecf20Sopenharmony_ci } 54918c2ecf20Sopenharmony_ci 54928c2ecf20Sopenharmony_ci if (!really_read_only && journal_devnum && 54938c2ecf20Sopenharmony_ci journal_devnum != le32_to_cpu(es->s_journal_dev)) { 54948c2ecf20Sopenharmony_ci es->s_journal_dev = cpu_to_le32(journal_devnum); 54958c2ecf20Sopenharmony_ci 54968c2ecf20Sopenharmony_ci /* Make sure we flush the recovery flag to disk. */ 54978c2ecf20Sopenharmony_ci ext4_commit_super(sb); 54988c2ecf20Sopenharmony_ci } 54998c2ecf20Sopenharmony_ci 55008c2ecf20Sopenharmony_ci return 0; 55018c2ecf20Sopenharmony_ci 55028c2ecf20Sopenharmony_cierr_out: 55038c2ecf20Sopenharmony_ci jbd2_journal_destroy(journal); 55048c2ecf20Sopenharmony_ci return err; 55058c2ecf20Sopenharmony_ci} 55068c2ecf20Sopenharmony_ci 55078c2ecf20Sopenharmony_ci/* Copy state of EXT4_SB(sb) into buffer for on-disk superblock */ 55088c2ecf20Sopenharmony_cistatic void ext4_update_super(struct super_block *sb) 55098c2ecf20Sopenharmony_ci{ 55108c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 55118c2ecf20Sopenharmony_ci struct ext4_super_block *es = sbi->s_es; 55128c2ecf20Sopenharmony_ci struct buffer_head *sbh = sbi->s_sbh; 55138c2ecf20Sopenharmony_ci 55148c2ecf20Sopenharmony_ci lock_buffer(sbh); 55158c2ecf20Sopenharmony_ci /* 55168c2ecf20Sopenharmony_ci * If the file system is mounted read-only, don't update the 55178c2ecf20Sopenharmony_ci * superblock write time. This avoids updating the superblock 55188c2ecf20Sopenharmony_ci * write time when we are mounting the root file system 55198c2ecf20Sopenharmony_ci * read/only but we need to replay the journal; at that point, 55208c2ecf20Sopenharmony_ci * for people who are east of GMT and who make their clock 55218c2ecf20Sopenharmony_ci * tick in localtime for Windows bug-for-bug compatibility, 55228c2ecf20Sopenharmony_ci * the clock is set in the future, and this will cause e2fsck 55238c2ecf20Sopenharmony_ci * to complain and force a full file system check. 55248c2ecf20Sopenharmony_ci */ 55258c2ecf20Sopenharmony_ci if (!(sb->s_flags & SB_RDONLY)) 55268c2ecf20Sopenharmony_ci ext4_update_tstamp(es, s_wtime); 55278c2ecf20Sopenharmony_ci if (sb->s_bdev->bd_part) 55288c2ecf20Sopenharmony_ci es->s_kbytes_written = 55298c2ecf20Sopenharmony_ci cpu_to_le64(sbi->s_kbytes_written + 55308c2ecf20Sopenharmony_ci ((part_stat_read(sb->s_bdev->bd_part, 55318c2ecf20Sopenharmony_ci sectors[STAT_WRITE]) - 55328c2ecf20Sopenharmony_ci sbi->s_sectors_written_start) >> 1)); 55338c2ecf20Sopenharmony_ci else 55348c2ecf20Sopenharmony_ci es->s_kbytes_written = cpu_to_le64(sbi->s_kbytes_written); 55358c2ecf20Sopenharmony_ci if (percpu_counter_initialized(&sbi->s_freeclusters_counter)) 55368c2ecf20Sopenharmony_ci ext4_free_blocks_count_set(es, 55378c2ecf20Sopenharmony_ci EXT4_C2B(sbi, percpu_counter_sum_positive( 55388c2ecf20Sopenharmony_ci &sbi->s_freeclusters_counter))); 55398c2ecf20Sopenharmony_ci if (percpu_counter_initialized(&sbi->s_freeinodes_counter)) 55408c2ecf20Sopenharmony_ci es->s_free_inodes_count = 55418c2ecf20Sopenharmony_ci cpu_to_le32(percpu_counter_sum_positive( 55428c2ecf20Sopenharmony_ci &sbi->s_freeinodes_counter)); 55438c2ecf20Sopenharmony_ci /* Copy error information to the on-disk superblock */ 55448c2ecf20Sopenharmony_ci spin_lock(&sbi->s_error_lock); 55458c2ecf20Sopenharmony_ci if (sbi->s_add_error_count > 0) { 55468c2ecf20Sopenharmony_ci es->s_state |= cpu_to_le16(EXT4_ERROR_FS); 55478c2ecf20Sopenharmony_ci if (!es->s_first_error_time && !es->s_first_error_time_hi) { 55488c2ecf20Sopenharmony_ci __ext4_update_tstamp(&es->s_first_error_time, 55498c2ecf20Sopenharmony_ci &es->s_first_error_time_hi, 55508c2ecf20Sopenharmony_ci sbi->s_first_error_time); 55518c2ecf20Sopenharmony_ci strncpy(es->s_first_error_func, sbi->s_first_error_func, 55528c2ecf20Sopenharmony_ci sizeof(es->s_first_error_func)); 55538c2ecf20Sopenharmony_ci es->s_first_error_line = 55548c2ecf20Sopenharmony_ci cpu_to_le32(sbi->s_first_error_line); 55558c2ecf20Sopenharmony_ci es->s_first_error_ino = 55568c2ecf20Sopenharmony_ci cpu_to_le32(sbi->s_first_error_ino); 55578c2ecf20Sopenharmony_ci es->s_first_error_block = 55588c2ecf20Sopenharmony_ci cpu_to_le64(sbi->s_first_error_block); 55598c2ecf20Sopenharmony_ci es->s_first_error_errcode = 55608c2ecf20Sopenharmony_ci ext4_errno_to_code(sbi->s_first_error_code); 55618c2ecf20Sopenharmony_ci } 55628c2ecf20Sopenharmony_ci __ext4_update_tstamp(&es->s_last_error_time, 55638c2ecf20Sopenharmony_ci &es->s_last_error_time_hi, 55648c2ecf20Sopenharmony_ci sbi->s_last_error_time); 55658c2ecf20Sopenharmony_ci strncpy(es->s_last_error_func, sbi->s_last_error_func, 55668c2ecf20Sopenharmony_ci sizeof(es->s_last_error_func)); 55678c2ecf20Sopenharmony_ci es->s_last_error_line = cpu_to_le32(sbi->s_last_error_line); 55688c2ecf20Sopenharmony_ci es->s_last_error_ino = cpu_to_le32(sbi->s_last_error_ino); 55698c2ecf20Sopenharmony_ci es->s_last_error_block = cpu_to_le64(sbi->s_last_error_block); 55708c2ecf20Sopenharmony_ci es->s_last_error_errcode = 55718c2ecf20Sopenharmony_ci ext4_errno_to_code(sbi->s_last_error_code); 55728c2ecf20Sopenharmony_ci /* 55738c2ecf20Sopenharmony_ci * Start the daily error reporting function if it hasn't been 55748c2ecf20Sopenharmony_ci * started already 55758c2ecf20Sopenharmony_ci */ 55768c2ecf20Sopenharmony_ci if (!es->s_error_count) 55778c2ecf20Sopenharmony_ci mod_timer(&sbi->s_err_report, jiffies + 24*60*60*HZ); 55788c2ecf20Sopenharmony_ci le32_add_cpu(&es->s_error_count, sbi->s_add_error_count); 55798c2ecf20Sopenharmony_ci sbi->s_add_error_count = 0; 55808c2ecf20Sopenharmony_ci } 55818c2ecf20Sopenharmony_ci spin_unlock(&sbi->s_error_lock); 55828c2ecf20Sopenharmony_ci 55838c2ecf20Sopenharmony_ci ext4_superblock_csum_set(sb); 55848c2ecf20Sopenharmony_ci unlock_buffer(sbh); 55858c2ecf20Sopenharmony_ci} 55868c2ecf20Sopenharmony_ci 55878c2ecf20Sopenharmony_cistatic int ext4_commit_super(struct super_block *sb) 55888c2ecf20Sopenharmony_ci{ 55898c2ecf20Sopenharmony_ci struct buffer_head *sbh = EXT4_SB(sb)->s_sbh; 55908c2ecf20Sopenharmony_ci int error = 0; 55918c2ecf20Sopenharmony_ci 55928c2ecf20Sopenharmony_ci if (!sbh) 55938c2ecf20Sopenharmony_ci return -EINVAL; 55948c2ecf20Sopenharmony_ci if (block_device_ejected(sb)) 55958c2ecf20Sopenharmony_ci return -ENODEV; 55968c2ecf20Sopenharmony_ci 55978c2ecf20Sopenharmony_ci ext4_update_super(sb); 55988c2ecf20Sopenharmony_ci 55998c2ecf20Sopenharmony_ci if (buffer_write_io_error(sbh) || !buffer_uptodate(sbh)) { 56008c2ecf20Sopenharmony_ci /* 56018c2ecf20Sopenharmony_ci * Oh, dear. A previous attempt to write the 56028c2ecf20Sopenharmony_ci * superblock failed. This could happen because the 56038c2ecf20Sopenharmony_ci * USB device was yanked out. Or it could happen to 56048c2ecf20Sopenharmony_ci * be a transient write error and maybe the block will 56058c2ecf20Sopenharmony_ci * be remapped. Nothing we can do but to retry the 56068c2ecf20Sopenharmony_ci * write and hope for the best. 56078c2ecf20Sopenharmony_ci */ 56088c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "previous I/O error to " 56098c2ecf20Sopenharmony_ci "superblock detected"); 56108c2ecf20Sopenharmony_ci clear_buffer_write_io_error(sbh); 56118c2ecf20Sopenharmony_ci set_buffer_uptodate(sbh); 56128c2ecf20Sopenharmony_ci } 56138c2ecf20Sopenharmony_ci BUFFER_TRACE(sbh, "marking dirty"); 56148c2ecf20Sopenharmony_ci mark_buffer_dirty(sbh); 56158c2ecf20Sopenharmony_ci error = __sync_dirty_buffer(sbh, 56168c2ecf20Sopenharmony_ci REQ_SYNC | (test_opt(sb, BARRIER) ? REQ_FUA : 0)); 56178c2ecf20Sopenharmony_ci if (buffer_write_io_error(sbh)) { 56188c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "I/O error while writing " 56198c2ecf20Sopenharmony_ci "superblock"); 56208c2ecf20Sopenharmony_ci clear_buffer_write_io_error(sbh); 56218c2ecf20Sopenharmony_ci set_buffer_uptodate(sbh); 56228c2ecf20Sopenharmony_ci } 56238c2ecf20Sopenharmony_ci return error; 56248c2ecf20Sopenharmony_ci} 56258c2ecf20Sopenharmony_ci 56268c2ecf20Sopenharmony_ci/* 56278c2ecf20Sopenharmony_ci * Have we just finished recovery? If so, and if we are mounting (or 56288c2ecf20Sopenharmony_ci * remounting) the filesystem readonly, then we will end up with a 56298c2ecf20Sopenharmony_ci * consistent fs on disk. Record that fact. 56308c2ecf20Sopenharmony_ci */ 56318c2ecf20Sopenharmony_cistatic int ext4_mark_recovery_complete(struct super_block *sb, 56328c2ecf20Sopenharmony_ci struct ext4_super_block *es) 56338c2ecf20Sopenharmony_ci{ 56348c2ecf20Sopenharmony_ci int err; 56358c2ecf20Sopenharmony_ci journal_t *journal = EXT4_SB(sb)->s_journal; 56368c2ecf20Sopenharmony_ci 56378c2ecf20Sopenharmony_ci if (!ext4_has_feature_journal(sb)) { 56388c2ecf20Sopenharmony_ci if (journal != NULL) { 56398c2ecf20Sopenharmony_ci ext4_error(sb, "Journal got removed while the fs was " 56408c2ecf20Sopenharmony_ci "mounted!"); 56418c2ecf20Sopenharmony_ci return -EFSCORRUPTED; 56428c2ecf20Sopenharmony_ci } 56438c2ecf20Sopenharmony_ci return 0; 56448c2ecf20Sopenharmony_ci } 56458c2ecf20Sopenharmony_ci jbd2_journal_lock_updates(journal); 56468c2ecf20Sopenharmony_ci err = jbd2_journal_flush(journal); 56478c2ecf20Sopenharmony_ci if (err < 0) 56488c2ecf20Sopenharmony_ci goto out; 56498c2ecf20Sopenharmony_ci 56508c2ecf20Sopenharmony_ci if (ext4_has_feature_journal_needs_recovery(sb) && sb_rdonly(sb)) { 56518c2ecf20Sopenharmony_ci ext4_clear_feature_journal_needs_recovery(sb); 56528c2ecf20Sopenharmony_ci ext4_commit_super(sb); 56538c2ecf20Sopenharmony_ci } 56548c2ecf20Sopenharmony_ciout: 56558c2ecf20Sopenharmony_ci jbd2_journal_unlock_updates(journal); 56568c2ecf20Sopenharmony_ci return err; 56578c2ecf20Sopenharmony_ci} 56588c2ecf20Sopenharmony_ci 56598c2ecf20Sopenharmony_ci/* 56608c2ecf20Sopenharmony_ci * If we are mounting (or read-write remounting) a filesystem whose journal 56618c2ecf20Sopenharmony_ci * has recorded an error from a previous lifetime, move that error to the 56628c2ecf20Sopenharmony_ci * main filesystem now. 56638c2ecf20Sopenharmony_ci */ 56648c2ecf20Sopenharmony_cistatic int ext4_clear_journal_err(struct super_block *sb, 56658c2ecf20Sopenharmony_ci struct ext4_super_block *es) 56668c2ecf20Sopenharmony_ci{ 56678c2ecf20Sopenharmony_ci journal_t *journal; 56688c2ecf20Sopenharmony_ci int j_errno; 56698c2ecf20Sopenharmony_ci const char *errstr; 56708c2ecf20Sopenharmony_ci 56718c2ecf20Sopenharmony_ci if (!ext4_has_feature_journal(sb)) { 56728c2ecf20Sopenharmony_ci ext4_error(sb, "Journal got removed while the fs was mounted!"); 56738c2ecf20Sopenharmony_ci return -EFSCORRUPTED; 56748c2ecf20Sopenharmony_ci } 56758c2ecf20Sopenharmony_ci 56768c2ecf20Sopenharmony_ci journal = EXT4_SB(sb)->s_journal; 56778c2ecf20Sopenharmony_ci 56788c2ecf20Sopenharmony_ci /* 56798c2ecf20Sopenharmony_ci * Now check for any error status which may have been recorded in the 56808c2ecf20Sopenharmony_ci * journal by a prior ext4_error() or ext4_abort() 56818c2ecf20Sopenharmony_ci */ 56828c2ecf20Sopenharmony_ci 56838c2ecf20Sopenharmony_ci j_errno = jbd2_journal_errno(journal); 56848c2ecf20Sopenharmony_ci if (j_errno) { 56858c2ecf20Sopenharmony_ci char nbuf[16]; 56868c2ecf20Sopenharmony_ci 56878c2ecf20Sopenharmony_ci errstr = ext4_decode_error(sb, j_errno, nbuf); 56888c2ecf20Sopenharmony_ci ext4_warning(sb, "Filesystem error recorded " 56898c2ecf20Sopenharmony_ci "from previous mount: %s", errstr); 56908c2ecf20Sopenharmony_ci ext4_warning(sb, "Marking fs in need of filesystem check."); 56918c2ecf20Sopenharmony_ci 56928c2ecf20Sopenharmony_ci EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; 56938c2ecf20Sopenharmony_ci es->s_state |= cpu_to_le16(EXT4_ERROR_FS); 56948c2ecf20Sopenharmony_ci ext4_commit_super(sb); 56958c2ecf20Sopenharmony_ci 56968c2ecf20Sopenharmony_ci jbd2_journal_clear_err(journal); 56978c2ecf20Sopenharmony_ci jbd2_journal_update_sb_errno(journal); 56988c2ecf20Sopenharmony_ci } 56998c2ecf20Sopenharmony_ci return 0; 57008c2ecf20Sopenharmony_ci} 57018c2ecf20Sopenharmony_ci 57028c2ecf20Sopenharmony_ci/* 57038c2ecf20Sopenharmony_ci * Force the running and committing transactions to commit, 57048c2ecf20Sopenharmony_ci * and wait on the commit. 57058c2ecf20Sopenharmony_ci */ 57068c2ecf20Sopenharmony_ciint ext4_force_commit(struct super_block *sb) 57078c2ecf20Sopenharmony_ci{ 57088c2ecf20Sopenharmony_ci journal_t *journal; 57098c2ecf20Sopenharmony_ci 57108c2ecf20Sopenharmony_ci if (sb_rdonly(sb)) 57118c2ecf20Sopenharmony_ci return 0; 57128c2ecf20Sopenharmony_ci 57138c2ecf20Sopenharmony_ci journal = EXT4_SB(sb)->s_journal; 57148c2ecf20Sopenharmony_ci return ext4_journal_force_commit(journal); 57158c2ecf20Sopenharmony_ci} 57168c2ecf20Sopenharmony_ci 57178c2ecf20Sopenharmony_cistatic int ext4_sync_fs(struct super_block *sb, int wait) 57188c2ecf20Sopenharmony_ci{ 57198c2ecf20Sopenharmony_ci int ret = 0; 57208c2ecf20Sopenharmony_ci tid_t target; 57218c2ecf20Sopenharmony_ci bool needs_barrier = false; 57228c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 57238c2ecf20Sopenharmony_ci 57248c2ecf20Sopenharmony_ci if (unlikely(ext4_forced_shutdown(sbi))) 57258c2ecf20Sopenharmony_ci return 0; 57268c2ecf20Sopenharmony_ci 57278c2ecf20Sopenharmony_ci trace_ext4_sync_fs(sb, wait); 57288c2ecf20Sopenharmony_ci flush_workqueue(sbi->rsv_conversion_wq); 57298c2ecf20Sopenharmony_ci /* 57308c2ecf20Sopenharmony_ci * Writeback quota in non-journalled quota case - journalled quota has 57318c2ecf20Sopenharmony_ci * no dirty dquots 57328c2ecf20Sopenharmony_ci */ 57338c2ecf20Sopenharmony_ci dquot_writeback_dquots(sb, -1); 57348c2ecf20Sopenharmony_ci /* 57358c2ecf20Sopenharmony_ci * Data writeback is possible w/o journal transaction, so barrier must 57368c2ecf20Sopenharmony_ci * being sent at the end of the function. But we can skip it if 57378c2ecf20Sopenharmony_ci * transaction_commit will do it for us. 57388c2ecf20Sopenharmony_ci */ 57398c2ecf20Sopenharmony_ci if (sbi->s_journal) { 57408c2ecf20Sopenharmony_ci target = jbd2_get_latest_transaction(sbi->s_journal); 57418c2ecf20Sopenharmony_ci if (wait && sbi->s_journal->j_flags & JBD2_BARRIER && 57428c2ecf20Sopenharmony_ci !jbd2_trans_will_send_data_barrier(sbi->s_journal, target)) 57438c2ecf20Sopenharmony_ci needs_barrier = true; 57448c2ecf20Sopenharmony_ci 57458c2ecf20Sopenharmony_ci if (jbd2_journal_start_commit(sbi->s_journal, &target)) { 57468c2ecf20Sopenharmony_ci if (wait) 57478c2ecf20Sopenharmony_ci ret = jbd2_log_wait_commit(sbi->s_journal, 57488c2ecf20Sopenharmony_ci target); 57498c2ecf20Sopenharmony_ci } 57508c2ecf20Sopenharmony_ci } else if (wait && test_opt(sb, BARRIER)) 57518c2ecf20Sopenharmony_ci needs_barrier = true; 57528c2ecf20Sopenharmony_ci if (needs_barrier) { 57538c2ecf20Sopenharmony_ci int err; 57548c2ecf20Sopenharmony_ci err = blkdev_issue_flush(sb->s_bdev, GFP_KERNEL); 57558c2ecf20Sopenharmony_ci if (!ret) 57568c2ecf20Sopenharmony_ci ret = err; 57578c2ecf20Sopenharmony_ci } 57588c2ecf20Sopenharmony_ci 57598c2ecf20Sopenharmony_ci return ret; 57608c2ecf20Sopenharmony_ci} 57618c2ecf20Sopenharmony_ci 57628c2ecf20Sopenharmony_ci/* 57638c2ecf20Sopenharmony_ci * LVM calls this function before a (read-only) snapshot is created. This 57648c2ecf20Sopenharmony_ci * gives us a chance to flush the journal completely and mark the fs clean. 57658c2ecf20Sopenharmony_ci * 57668c2ecf20Sopenharmony_ci * Note that only this function cannot bring a filesystem to be in a clean 57678c2ecf20Sopenharmony_ci * state independently. It relies on upper layer to stop all data & metadata 57688c2ecf20Sopenharmony_ci * modifications. 57698c2ecf20Sopenharmony_ci */ 57708c2ecf20Sopenharmony_cistatic int ext4_freeze(struct super_block *sb) 57718c2ecf20Sopenharmony_ci{ 57728c2ecf20Sopenharmony_ci int error = 0; 57738c2ecf20Sopenharmony_ci journal_t *journal; 57748c2ecf20Sopenharmony_ci 57758c2ecf20Sopenharmony_ci if (sb_rdonly(sb)) 57768c2ecf20Sopenharmony_ci return 0; 57778c2ecf20Sopenharmony_ci 57788c2ecf20Sopenharmony_ci journal = EXT4_SB(sb)->s_journal; 57798c2ecf20Sopenharmony_ci 57808c2ecf20Sopenharmony_ci if (journal) { 57818c2ecf20Sopenharmony_ci /* Now we set up the journal barrier. */ 57828c2ecf20Sopenharmony_ci jbd2_journal_lock_updates(journal); 57838c2ecf20Sopenharmony_ci 57848c2ecf20Sopenharmony_ci /* 57858c2ecf20Sopenharmony_ci * Don't clear the needs_recovery flag if we failed to 57868c2ecf20Sopenharmony_ci * flush the journal. 57878c2ecf20Sopenharmony_ci */ 57888c2ecf20Sopenharmony_ci error = jbd2_journal_flush(journal); 57898c2ecf20Sopenharmony_ci if (error < 0) 57908c2ecf20Sopenharmony_ci goto out; 57918c2ecf20Sopenharmony_ci 57928c2ecf20Sopenharmony_ci /* Journal blocked and flushed, clear needs_recovery flag. */ 57938c2ecf20Sopenharmony_ci ext4_clear_feature_journal_needs_recovery(sb); 57948c2ecf20Sopenharmony_ci } 57958c2ecf20Sopenharmony_ci 57968c2ecf20Sopenharmony_ci error = ext4_commit_super(sb); 57978c2ecf20Sopenharmony_ciout: 57988c2ecf20Sopenharmony_ci if (journal) 57998c2ecf20Sopenharmony_ci /* we rely on upper layer to stop further updates */ 58008c2ecf20Sopenharmony_ci jbd2_journal_unlock_updates(journal); 58018c2ecf20Sopenharmony_ci return error; 58028c2ecf20Sopenharmony_ci} 58038c2ecf20Sopenharmony_ci 58048c2ecf20Sopenharmony_ci/* 58058c2ecf20Sopenharmony_ci * Called by LVM after the snapshot is done. We need to reset the RECOVER 58068c2ecf20Sopenharmony_ci * flag here, even though the filesystem is not technically dirty yet. 58078c2ecf20Sopenharmony_ci */ 58088c2ecf20Sopenharmony_cistatic int ext4_unfreeze(struct super_block *sb) 58098c2ecf20Sopenharmony_ci{ 58108c2ecf20Sopenharmony_ci if (sb_rdonly(sb) || ext4_forced_shutdown(EXT4_SB(sb))) 58118c2ecf20Sopenharmony_ci return 0; 58128c2ecf20Sopenharmony_ci 58138c2ecf20Sopenharmony_ci if (EXT4_SB(sb)->s_journal) { 58148c2ecf20Sopenharmony_ci /* Reset the needs_recovery flag before the fs is unlocked. */ 58158c2ecf20Sopenharmony_ci ext4_set_feature_journal_needs_recovery(sb); 58168c2ecf20Sopenharmony_ci } 58178c2ecf20Sopenharmony_ci 58188c2ecf20Sopenharmony_ci ext4_commit_super(sb); 58198c2ecf20Sopenharmony_ci return 0; 58208c2ecf20Sopenharmony_ci} 58218c2ecf20Sopenharmony_ci 58228c2ecf20Sopenharmony_ci/* 58238c2ecf20Sopenharmony_ci * Structure to save mount options for ext4_remount's benefit 58248c2ecf20Sopenharmony_ci */ 58258c2ecf20Sopenharmony_cistruct ext4_mount_options { 58268c2ecf20Sopenharmony_ci unsigned long s_mount_opt; 58278c2ecf20Sopenharmony_ci unsigned long s_mount_opt2; 58288c2ecf20Sopenharmony_ci kuid_t s_resuid; 58298c2ecf20Sopenharmony_ci kgid_t s_resgid; 58308c2ecf20Sopenharmony_ci unsigned long s_commit_interval; 58318c2ecf20Sopenharmony_ci u32 s_min_batch_time, s_max_batch_time; 58328c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 58338c2ecf20Sopenharmony_ci int s_jquota_fmt; 58348c2ecf20Sopenharmony_ci char *s_qf_names[EXT4_MAXQUOTAS]; 58358c2ecf20Sopenharmony_ci#endif 58368c2ecf20Sopenharmony_ci}; 58378c2ecf20Sopenharmony_ci 58388c2ecf20Sopenharmony_cistatic int ext4_remount(struct super_block *sb, int *flags, char *data) 58398c2ecf20Sopenharmony_ci{ 58408c2ecf20Sopenharmony_ci struct ext4_super_block *es; 58418c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 58428c2ecf20Sopenharmony_ci unsigned long old_sb_flags, vfs_flags; 58438c2ecf20Sopenharmony_ci struct ext4_mount_options old_opts; 58448c2ecf20Sopenharmony_ci ext4_group_t g; 58458c2ecf20Sopenharmony_ci unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO; 58468c2ecf20Sopenharmony_ci int err = 0; 58478c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 58488c2ecf20Sopenharmony_ci int enable_quota = 0; 58498c2ecf20Sopenharmony_ci int i, j; 58508c2ecf20Sopenharmony_ci char *to_free[EXT4_MAXQUOTAS]; 58518c2ecf20Sopenharmony_ci#endif 58528c2ecf20Sopenharmony_ci char *orig_data = kstrdup(data, GFP_KERNEL); 58538c2ecf20Sopenharmony_ci 58548c2ecf20Sopenharmony_ci if (data && !orig_data) 58558c2ecf20Sopenharmony_ci return -ENOMEM; 58568c2ecf20Sopenharmony_ci 58578c2ecf20Sopenharmony_ci /* Store the original options */ 58588c2ecf20Sopenharmony_ci old_sb_flags = sb->s_flags; 58598c2ecf20Sopenharmony_ci old_opts.s_mount_opt = sbi->s_mount_opt; 58608c2ecf20Sopenharmony_ci old_opts.s_mount_opt2 = sbi->s_mount_opt2; 58618c2ecf20Sopenharmony_ci old_opts.s_resuid = sbi->s_resuid; 58628c2ecf20Sopenharmony_ci old_opts.s_resgid = sbi->s_resgid; 58638c2ecf20Sopenharmony_ci old_opts.s_commit_interval = sbi->s_commit_interval; 58648c2ecf20Sopenharmony_ci old_opts.s_min_batch_time = sbi->s_min_batch_time; 58658c2ecf20Sopenharmony_ci old_opts.s_max_batch_time = sbi->s_max_batch_time; 58668c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 58678c2ecf20Sopenharmony_ci old_opts.s_jquota_fmt = sbi->s_jquota_fmt; 58688c2ecf20Sopenharmony_ci for (i = 0; i < EXT4_MAXQUOTAS; i++) 58698c2ecf20Sopenharmony_ci if (sbi->s_qf_names[i]) { 58708c2ecf20Sopenharmony_ci char *qf_name = get_qf_name(sb, sbi, i); 58718c2ecf20Sopenharmony_ci 58728c2ecf20Sopenharmony_ci old_opts.s_qf_names[i] = kstrdup(qf_name, GFP_KERNEL); 58738c2ecf20Sopenharmony_ci if (!old_opts.s_qf_names[i]) { 58748c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) 58758c2ecf20Sopenharmony_ci kfree(old_opts.s_qf_names[j]); 58768c2ecf20Sopenharmony_ci kfree(orig_data); 58778c2ecf20Sopenharmony_ci return -ENOMEM; 58788c2ecf20Sopenharmony_ci } 58798c2ecf20Sopenharmony_ci } else 58808c2ecf20Sopenharmony_ci old_opts.s_qf_names[i] = NULL; 58818c2ecf20Sopenharmony_ci#endif 58828c2ecf20Sopenharmony_ci if (sbi->s_journal && sbi->s_journal->j_task->io_context) 58838c2ecf20Sopenharmony_ci journal_ioprio = sbi->s_journal->j_task->io_context->ioprio; 58848c2ecf20Sopenharmony_ci 58858c2ecf20Sopenharmony_ci /* 58868c2ecf20Sopenharmony_ci * Some options can be enabled by ext4 and/or by VFS mount flag 58878c2ecf20Sopenharmony_ci * either way we need to make sure it matches in both *flags and 58888c2ecf20Sopenharmony_ci * s_flags. Copy those selected flags from *flags to s_flags 58898c2ecf20Sopenharmony_ci */ 58908c2ecf20Sopenharmony_ci vfs_flags = SB_LAZYTIME | SB_I_VERSION; 58918c2ecf20Sopenharmony_ci sb->s_flags = (sb->s_flags & ~vfs_flags) | (*flags & vfs_flags); 58928c2ecf20Sopenharmony_ci 58938c2ecf20Sopenharmony_ci if (!parse_options(data, sb, NULL, &journal_ioprio, 1)) { 58948c2ecf20Sopenharmony_ci err = -EINVAL; 58958c2ecf20Sopenharmony_ci goto restore_opts; 58968c2ecf20Sopenharmony_ci } 58978c2ecf20Sopenharmony_ci 58988c2ecf20Sopenharmony_ci if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^ 58998c2ecf20Sopenharmony_ci test_opt(sb, JOURNAL_CHECKSUM)) { 59008c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "changing journal_checksum " 59018c2ecf20Sopenharmony_ci "during remount not supported; ignoring"); 59028c2ecf20Sopenharmony_ci sbi->s_mount_opt ^= EXT4_MOUNT_JOURNAL_CHECKSUM; 59038c2ecf20Sopenharmony_ci } 59048c2ecf20Sopenharmony_ci 59058c2ecf20Sopenharmony_ci if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) { 59068c2ecf20Sopenharmony_ci if (test_opt2(sb, EXPLICIT_DELALLOC)) { 59078c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "can't mount with " 59088c2ecf20Sopenharmony_ci "both data=journal and delalloc"); 59098c2ecf20Sopenharmony_ci err = -EINVAL; 59108c2ecf20Sopenharmony_ci goto restore_opts; 59118c2ecf20Sopenharmony_ci } 59128c2ecf20Sopenharmony_ci if (test_opt(sb, DIOREAD_NOLOCK)) { 59138c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "can't mount with " 59148c2ecf20Sopenharmony_ci "both data=journal and dioread_nolock"); 59158c2ecf20Sopenharmony_ci err = -EINVAL; 59168c2ecf20Sopenharmony_ci goto restore_opts; 59178c2ecf20Sopenharmony_ci } 59188c2ecf20Sopenharmony_ci } else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) { 59198c2ecf20Sopenharmony_ci if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) { 59208c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "can't mount with " 59218c2ecf20Sopenharmony_ci "journal_async_commit in data=ordered mode"); 59228c2ecf20Sopenharmony_ci err = -EINVAL; 59238c2ecf20Sopenharmony_ci goto restore_opts; 59248c2ecf20Sopenharmony_ci } 59258c2ecf20Sopenharmony_ci } 59268c2ecf20Sopenharmony_ci 59278c2ecf20Sopenharmony_ci if ((sbi->s_mount_opt ^ old_opts.s_mount_opt) & EXT4_MOUNT_NO_MBCACHE) { 59288c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, "can't enable nombcache during remount"); 59298c2ecf20Sopenharmony_ci err = -EINVAL; 59308c2ecf20Sopenharmony_ci goto restore_opts; 59318c2ecf20Sopenharmony_ci } 59328c2ecf20Sopenharmony_ci 59338c2ecf20Sopenharmony_ci if (ext4_test_mount_flag(sb, EXT4_MF_FS_ABORTED)) 59348c2ecf20Sopenharmony_ci ext4_abort(sb, EXT4_ERR_ESHUTDOWN, "Abort forced by user"); 59358c2ecf20Sopenharmony_ci 59368c2ecf20Sopenharmony_ci sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | 59378c2ecf20Sopenharmony_ci (test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0); 59388c2ecf20Sopenharmony_ci 59398c2ecf20Sopenharmony_ci es = sbi->s_es; 59408c2ecf20Sopenharmony_ci 59418c2ecf20Sopenharmony_ci if (sbi->s_journal) { 59428c2ecf20Sopenharmony_ci ext4_init_journal_params(sb, sbi->s_journal); 59438c2ecf20Sopenharmony_ci set_task_ioprio(sbi->s_journal->j_task, journal_ioprio); 59448c2ecf20Sopenharmony_ci } 59458c2ecf20Sopenharmony_ci 59468c2ecf20Sopenharmony_ci /* Flush outstanding errors before changing fs state */ 59478c2ecf20Sopenharmony_ci flush_work(&sbi->s_error_work); 59488c2ecf20Sopenharmony_ci 59498c2ecf20Sopenharmony_ci if ((bool)(*flags & SB_RDONLY) != sb_rdonly(sb)) { 59508c2ecf20Sopenharmony_ci if (ext4_test_mount_flag(sb, EXT4_MF_FS_ABORTED)) { 59518c2ecf20Sopenharmony_ci err = -EROFS; 59528c2ecf20Sopenharmony_ci goto restore_opts; 59538c2ecf20Sopenharmony_ci } 59548c2ecf20Sopenharmony_ci 59558c2ecf20Sopenharmony_ci if (*flags & SB_RDONLY) { 59568c2ecf20Sopenharmony_ci err = sync_filesystem(sb); 59578c2ecf20Sopenharmony_ci if (err < 0) 59588c2ecf20Sopenharmony_ci goto restore_opts; 59598c2ecf20Sopenharmony_ci err = dquot_suspend(sb, -1); 59608c2ecf20Sopenharmony_ci if (err < 0) 59618c2ecf20Sopenharmony_ci goto restore_opts; 59628c2ecf20Sopenharmony_ci 59638c2ecf20Sopenharmony_ci /* 59648c2ecf20Sopenharmony_ci * First of all, the unconditional stuff we have to do 59658c2ecf20Sopenharmony_ci * to disable replay of the journal when we next remount 59668c2ecf20Sopenharmony_ci */ 59678c2ecf20Sopenharmony_ci sb->s_flags |= SB_RDONLY; 59688c2ecf20Sopenharmony_ci 59698c2ecf20Sopenharmony_ci /* 59708c2ecf20Sopenharmony_ci * OK, test if we are remounting a valid rw partition 59718c2ecf20Sopenharmony_ci * readonly, and if so set the rdonly flag and then 59728c2ecf20Sopenharmony_ci * mark the partition as valid again. 59738c2ecf20Sopenharmony_ci */ 59748c2ecf20Sopenharmony_ci if (!(es->s_state & cpu_to_le16(EXT4_VALID_FS)) && 59758c2ecf20Sopenharmony_ci (sbi->s_mount_state & EXT4_VALID_FS)) 59768c2ecf20Sopenharmony_ci es->s_state = cpu_to_le16(sbi->s_mount_state); 59778c2ecf20Sopenharmony_ci 59788c2ecf20Sopenharmony_ci if (sbi->s_journal) { 59798c2ecf20Sopenharmony_ci /* 59808c2ecf20Sopenharmony_ci * We let remount-ro finish even if marking fs 59818c2ecf20Sopenharmony_ci * as clean failed... 59828c2ecf20Sopenharmony_ci */ 59838c2ecf20Sopenharmony_ci ext4_mark_recovery_complete(sb, es); 59848c2ecf20Sopenharmony_ci } 59858c2ecf20Sopenharmony_ci } else { 59868c2ecf20Sopenharmony_ci /* Make sure we can mount this feature set readwrite */ 59878c2ecf20Sopenharmony_ci if (ext4_has_feature_readonly(sb) || 59888c2ecf20Sopenharmony_ci !ext4_feature_set_ok(sb, 0)) { 59898c2ecf20Sopenharmony_ci err = -EROFS; 59908c2ecf20Sopenharmony_ci goto restore_opts; 59918c2ecf20Sopenharmony_ci } 59928c2ecf20Sopenharmony_ci /* 59938c2ecf20Sopenharmony_ci * Make sure the group descriptor checksums 59948c2ecf20Sopenharmony_ci * are sane. If they aren't, refuse to remount r/w. 59958c2ecf20Sopenharmony_ci */ 59968c2ecf20Sopenharmony_ci for (g = 0; g < sbi->s_groups_count; g++) { 59978c2ecf20Sopenharmony_ci struct ext4_group_desc *gdp = 59988c2ecf20Sopenharmony_ci ext4_get_group_desc(sb, g, NULL); 59998c2ecf20Sopenharmony_ci 60008c2ecf20Sopenharmony_ci if (!ext4_group_desc_csum_verify(sb, g, gdp)) { 60018c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_ERR, 60028c2ecf20Sopenharmony_ci "ext4_remount: Checksum for group %u failed (%u!=%u)", 60038c2ecf20Sopenharmony_ci g, le16_to_cpu(ext4_group_desc_csum(sb, g, gdp)), 60048c2ecf20Sopenharmony_ci le16_to_cpu(gdp->bg_checksum)); 60058c2ecf20Sopenharmony_ci err = -EFSBADCRC; 60068c2ecf20Sopenharmony_ci goto restore_opts; 60078c2ecf20Sopenharmony_ci } 60088c2ecf20Sopenharmony_ci } 60098c2ecf20Sopenharmony_ci 60108c2ecf20Sopenharmony_ci /* 60118c2ecf20Sopenharmony_ci * If we have an unprocessed orphan list hanging 60128c2ecf20Sopenharmony_ci * around from a previously readonly bdev mount, 60138c2ecf20Sopenharmony_ci * require a full umount/remount for now. 60148c2ecf20Sopenharmony_ci */ 60158c2ecf20Sopenharmony_ci if (es->s_last_orphan) { 60168c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, "Couldn't " 60178c2ecf20Sopenharmony_ci "remount RDWR because of unprocessed " 60188c2ecf20Sopenharmony_ci "orphan inode list. Please " 60198c2ecf20Sopenharmony_ci "umount/remount instead"); 60208c2ecf20Sopenharmony_ci err = -EINVAL; 60218c2ecf20Sopenharmony_ci goto restore_opts; 60228c2ecf20Sopenharmony_ci } 60238c2ecf20Sopenharmony_ci 60248c2ecf20Sopenharmony_ci /* 60258c2ecf20Sopenharmony_ci * Mounting a RDONLY partition read-write, so reread 60268c2ecf20Sopenharmony_ci * and store the current valid flag. (It may have 60278c2ecf20Sopenharmony_ci * been changed by e2fsck since we originally mounted 60288c2ecf20Sopenharmony_ci * the partition.) 60298c2ecf20Sopenharmony_ci */ 60308c2ecf20Sopenharmony_ci if (sbi->s_journal) { 60318c2ecf20Sopenharmony_ci err = ext4_clear_journal_err(sb, es); 60328c2ecf20Sopenharmony_ci if (err) 60338c2ecf20Sopenharmony_ci goto restore_opts; 60348c2ecf20Sopenharmony_ci } 60358c2ecf20Sopenharmony_ci sbi->s_mount_state = (le16_to_cpu(es->s_state) & 60368c2ecf20Sopenharmony_ci ~EXT4_FC_REPLAY); 60378c2ecf20Sopenharmony_ci 60388c2ecf20Sopenharmony_ci err = ext4_setup_super(sb, es, 0); 60398c2ecf20Sopenharmony_ci if (err) 60408c2ecf20Sopenharmony_ci goto restore_opts; 60418c2ecf20Sopenharmony_ci 60428c2ecf20Sopenharmony_ci sb->s_flags &= ~SB_RDONLY; 60438c2ecf20Sopenharmony_ci if (ext4_has_feature_mmp(sb)) { 60448c2ecf20Sopenharmony_ci err = ext4_multi_mount_protect(sb, 60458c2ecf20Sopenharmony_ci le64_to_cpu(es->s_mmp_block)); 60468c2ecf20Sopenharmony_ci if (err) 60478c2ecf20Sopenharmony_ci goto restore_opts; 60488c2ecf20Sopenharmony_ci } 60498c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 60508c2ecf20Sopenharmony_ci enable_quota = 1; 60518c2ecf20Sopenharmony_ci#endif 60528c2ecf20Sopenharmony_ci } 60538c2ecf20Sopenharmony_ci } 60548c2ecf20Sopenharmony_ci 60558c2ecf20Sopenharmony_ci /* 60568c2ecf20Sopenharmony_ci * Handle creation of system zone data early because it can fail. 60578c2ecf20Sopenharmony_ci * Releasing of existing data is done when we are sure remount will 60588c2ecf20Sopenharmony_ci * succeed. 60598c2ecf20Sopenharmony_ci */ 60608c2ecf20Sopenharmony_ci if (test_opt(sb, BLOCK_VALIDITY) && !sbi->s_system_blks) { 60618c2ecf20Sopenharmony_ci err = ext4_setup_system_zone(sb); 60628c2ecf20Sopenharmony_ci if (err) 60638c2ecf20Sopenharmony_ci goto restore_opts; 60648c2ecf20Sopenharmony_ci } 60658c2ecf20Sopenharmony_ci 60668c2ecf20Sopenharmony_ci if (sbi->s_journal == NULL && !(old_sb_flags & SB_RDONLY)) { 60678c2ecf20Sopenharmony_ci err = ext4_commit_super(sb); 60688c2ecf20Sopenharmony_ci if (err) 60698c2ecf20Sopenharmony_ci goto restore_opts; 60708c2ecf20Sopenharmony_ci } 60718c2ecf20Sopenharmony_ci 60728c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 60738c2ecf20Sopenharmony_ci if (enable_quota) { 60748c2ecf20Sopenharmony_ci if (sb_any_quota_suspended(sb)) 60758c2ecf20Sopenharmony_ci dquot_resume(sb, -1); 60768c2ecf20Sopenharmony_ci else if (ext4_has_feature_quota(sb)) { 60778c2ecf20Sopenharmony_ci err = ext4_enable_quotas(sb); 60788c2ecf20Sopenharmony_ci if (err) 60798c2ecf20Sopenharmony_ci goto restore_opts; 60808c2ecf20Sopenharmony_ci } 60818c2ecf20Sopenharmony_ci } 60828c2ecf20Sopenharmony_ci /* Release old quota file names */ 60838c2ecf20Sopenharmony_ci for (i = 0; i < EXT4_MAXQUOTAS; i++) 60848c2ecf20Sopenharmony_ci kfree(old_opts.s_qf_names[i]); 60858c2ecf20Sopenharmony_ci#endif 60868c2ecf20Sopenharmony_ci if (!test_opt(sb, BLOCK_VALIDITY) && sbi->s_system_blks) 60878c2ecf20Sopenharmony_ci ext4_release_system_zone(sb); 60888c2ecf20Sopenharmony_ci 60898c2ecf20Sopenharmony_ci /* 60908c2ecf20Sopenharmony_ci * Reinitialize lazy itable initialization thread based on 60918c2ecf20Sopenharmony_ci * current settings 60928c2ecf20Sopenharmony_ci */ 60938c2ecf20Sopenharmony_ci if (sb_rdonly(sb) || !test_opt(sb, INIT_INODE_TABLE)) 60948c2ecf20Sopenharmony_ci ext4_unregister_li_request(sb); 60958c2ecf20Sopenharmony_ci else { 60968c2ecf20Sopenharmony_ci ext4_group_t first_not_zeroed; 60978c2ecf20Sopenharmony_ci first_not_zeroed = ext4_has_uninit_itable(sb); 60988c2ecf20Sopenharmony_ci ext4_register_li_request(sb, first_not_zeroed); 60998c2ecf20Sopenharmony_ci } 61008c2ecf20Sopenharmony_ci 61018c2ecf20Sopenharmony_ci if (!ext4_has_feature_mmp(sb) || sb_rdonly(sb)) 61028c2ecf20Sopenharmony_ci ext4_stop_mmpd(sbi); 61038c2ecf20Sopenharmony_ci 61048c2ecf20Sopenharmony_ci /* 61058c2ecf20Sopenharmony_ci * Some options can be enabled by ext4 and/or by VFS mount flag 61068c2ecf20Sopenharmony_ci * either way we need to make sure it matches in both *flags and 61078c2ecf20Sopenharmony_ci * s_flags. Copy those selected flags from s_flags to *flags 61088c2ecf20Sopenharmony_ci */ 61098c2ecf20Sopenharmony_ci *flags = (*flags & ~vfs_flags) | (sb->s_flags & vfs_flags); 61108c2ecf20Sopenharmony_ci 61118c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s", orig_data); 61128c2ecf20Sopenharmony_ci kfree(orig_data); 61138c2ecf20Sopenharmony_ci return 0; 61148c2ecf20Sopenharmony_ci 61158c2ecf20Sopenharmony_cirestore_opts: 61168c2ecf20Sopenharmony_ci /* 61178c2ecf20Sopenharmony_ci * If there was a failing r/w to ro transition, we may need to 61188c2ecf20Sopenharmony_ci * re-enable quota 61198c2ecf20Sopenharmony_ci */ 61208c2ecf20Sopenharmony_ci if ((sb->s_flags & SB_RDONLY) && !(old_sb_flags & SB_RDONLY) && 61218c2ecf20Sopenharmony_ci sb_any_quota_suspended(sb)) 61228c2ecf20Sopenharmony_ci dquot_resume(sb, -1); 61238c2ecf20Sopenharmony_ci sb->s_flags = old_sb_flags; 61248c2ecf20Sopenharmony_ci sbi->s_mount_opt = old_opts.s_mount_opt; 61258c2ecf20Sopenharmony_ci sbi->s_mount_opt2 = old_opts.s_mount_opt2; 61268c2ecf20Sopenharmony_ci sbi->s_resuid = old_opts.s_resuid; 61278c2ecf20Sopenharmony_ci sbi->s_resgid = old_opts.s_resgid; 61288c2ecf20Sopenharmony_ci sbi->s_commit_interval = old_opts.s_commit_interval; 61298c2ecf20Sopenharmony_ci sbi->s_min_batch_time = old_opts.s_min_batch_time; 61308c2ecf20Sopenharmony_ci sbi->s_max_batch_time = old_opts.s_max_batch_time; 61318c2ecf20Sopenharmony_ci if (!test_opt(sb, BLOCK_VALIDITY) && sbi->s_system_blks) 61328c2ecf20Sopenharmony_ci ext4_release_system_zone(sb); 61338c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 61348c2ecf20Sopenharmony_ci sbi->s_jquota_fmt = old_opts.s_jquota_fmt; 61358c2ecf20Sopenharmony_ci for (i = 0; i < EXT4_MAXQUOTAS; i++) { 61368c2ecf20Sopenharmony_ci to_free[i] = get_qf_name(sb, sbi, i); 61378c2ecf20Sopenharmony_ci rcu_assign_pointer(sbi->s_qf_names[i], old_opts.s_qf_names[i]); 61388c2ecf20Sopenharmony_ci } 61398c2ecf20Sopenharmony_ci synchronize_rcu(); 61408c2ecf20Sopenharmony_ci for (i = 0; i < EXT4_MAXQUOTAS; i++) 61418c2ecf20Sopenharmony_ci kfree(to_free[i]); 61428c2ecf20Sopenharmony_ci#endif 61438c2ecf20Sopenharmony_ci if (!ext4_has_feature_mmp(sb) || sb_rdonly(sb)) 61448c2ecf20Sopenharmony_ci ext4_stop_mmpd(sbi); 61458c2ecf20Sopenharmony_ci kfree(orig_data); 61468c2ecf20Sopenharmony_ci return err; 61478c2ecf20Sopenharmony_ci} 61488c2ecf20Sopenharmony_ci 61498c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 61508c2ecf20Sopenharmony_cistatic int ext4_statfs_project(struct super_block *sb, 61518c2ecf20Sopenharmony_ci kprojid_t projid, struct kstatfs *buf) 61528c2ecf20Sopenharmony_ci{ 61538c2ecf20Sopenharmony_ci struct kqid qid; 61548c2ecf20Sopenharmony_ci struct dquot *dquot; 61558c2ecf20Sopenharmony_ci u64 limit; 61568c2ecf20Sopenharmony_ci u64 curblock; 61578c2ecf20Sopenharmony_ci 61588c2ecf20Sopenharmony_ci qid = make_kqid_projid(projid); 61598c2ecf20Sopenharmony_ci dquot = dqget(sb, qid); 61608c2ecf20Sopenharmony_ci if (IS_ERR(dquot)) 61618c2ecf20Sopenharmony_ci return PTR_ERR(dquot); 61628c2ecf20Sopenharmony_ci spin_lock(&dquot->dq_dqb_lock); 61638c2ecf20Sopenharmony_ci 61648c2ecf20Sopenharmony_ci limit = min_not_zero(dquot->dq_dqb.dqb_bsoftlimit, 61658c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_bhardlimit); 61668c2ecf20Sopenharmony_ci limit >>= sb->s_blocksize_bits; 61678c2ecf20Sopenharmony_ci 61688c2ecf20Sopenharmony_ci if (limit && buf->f_blocks > limit) { 61698c2ecf20Sopenharmony_ci curblock = (dquot->dq_dqb.dqb_curspace + 61708c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_rsvspace) >> sb->s_blocksize_bits; 61718c2ecf20Sopenharmony_ci buf->f_blocks = limit; 61728c2ecf20Sopenharmony_ci buf->f_bfree = buf->f_bavail = 61738c2ecf20Sopenharmony_ci (buf->f_blocks > curblock) ? 61748c2ecf20Sopenharmony_ci (buf->f_blocks - curblock) : 0; 61758c2ecf20Sopenharmony_ci } 61768c2ecf20Sopenharmony_ci 61778c2ecf20Sopenharmony_ci limit = min_not_zero(dquot->dq_dqb.dqb_isoftlimit, 61788c2ecf20Sopenharmony_ci dquot->dq_dqb.dqb_ihardlimit); 61798c2ecf20Sopenharmony_ci if (limit && buf->f_files > limit) { 61808c2ecf20Sopenharmony_ci buf->f_files = limit; 61818c2ecf20Sopenharmony_ci buf->f_ffree = 61828c2ecf20Sopenharmony_ci (buf->f_files > dquot->dq_dqb.dqb_curinodes) ? 61838c2ecf20Sopenharmony_ci (buf->f_files - dquot->dq_dqb.dqb_curinodes) : 0; 61848c2ecf20Sopenharmony_ci } 61858c2ecf20Sopenharmony_ci 61868c2ecf20Sopenharmony_ci spin_unlock(&dquot->dq_dqb_lock); 61878c2ecf20Sopenharmony_ci dqput(dquot); 61888c2ecf20Sopenharmony_ci return 0; 61898c2ecf20Sopenharmony_ci} 61908c2ecf20Sopenharmony_ci#endif 61918c2ecf20Sopenharmony_ci 61928c2ecf20Sopenharmony_cistatic int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) 61938c2ecf20Sopenharmony_ci{ 61948c2ecf20Sopenharmony_ci struct super_block *sb = dentry->d_sb; 61958c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 61968c2ecf20Sopenharmony_ci struct ext4_super_block *es = sbi->s_es; 61978c2ecf20Sopenharmony_ci ext4_fsblk_t overhead = 0, resv_blocks; 61988c2ecf20Sopenharmony_ci u64 fsid; 61998c2ecf20Sopenharmony_ci s64 bfree; 62008c2ecf20Sopenharmony_ci resv_blocks = EXT4_C2B(sbi, atomic64_read(&sbi->s_resv_clusters)); 62018c2ecf20Sopenharmony_ci 62028c2ecf20Sopenharmony_ci if (!test_opt(sb, MINIX_DF)) 62038c2ecf20Sopenharmony_ci overhead = sbi->s_overhead; 62048c2ecf20Sopenharmony_ci 62058c2ecf20Sopenharmony_ci buf->f_type = EXT4_SUPER_MAGIC; 62068c2ecf20Sopenharmony_ci buf->f_bsize = sb->s_blocksize; 62078c2ecf20Sopenharmony_ci buf->f_blocks = ext4_blocks_count(es) - EXT4_C2B(sbi, overhead); 62088c2ecf20Sopenharmony_ci bfree = percpu_counter_sum_positive(&sbi->s_freeclusters_counter) - 62098c2ecf20Sopenharmony_ci percpu_counter_sum_positive(&sbi->s_dirtyclusters_counter); 62108c2ecf20Sopenharmony_ci /* prevent underflow in case that few free space is available */ 62118c2ecf20Sopenharmony_ci buf->f_bfree = EXT4_C2B(sbi, max_t(s64, bfree, 0)); 62128c2ecf20Sopenharmony_ci buf->f_bavail = buf->f_bfree - 62138c2ecf20Sopenharmony_ci (ext4_r_blocks_count(es) + resv_blocks); 62148c2ecf20Sopenharmony_ci if (buf->f_bfree < (ext4_r_blocks_count(es) + resv_blocks)) 62158c2ecf20Sopenharmony_ci buf->f_bavail = 0; 62168c2ecf20Sopenharmony_ci buf->f_files = le32_to_cpu(es->s_inodes_count); 62178c2ecf20Sopenharmony_ci buf->f_ffree = percpu_counter_sum_positive(&sbi->s_freeinodes_counter); 62188c2ecf20Sopenharmony_ci buf->f_namelen = EXT4_NAME_LEN; 62198c2ecf20Sopenharmony_ci fsid = le64_to_cpup((void *)es->s_uuid) ^ 62208c2ecf20Sopenharmony_ci le64_to_cpup((void *)es->s_uuid + sizeof(u64)); 62218c2ecf20Sopenharmony_ci buf->f_fsid = u64_to_fsid(fsid); 62228c2ecf20Sopenharmony_ci 62238c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 62248c2ecf20Sopenharmony_ci if (ext4_test_inode_flag(dentry->d_inode, EXT4_INODE_PROJINHERIT) && 62258c2ecf20Sopenharmony_ci sb_has_quota_limits_enabled(sb, PRJQUOTA)) 62268c2ecf20Sopenharmony_ci ext4_statfs_project(sb, EXT4_I(dentry->d_inode)->i_projid, buf); 62278c2ecf20Sopenharmony_ci#endif 62288c2ecf20Sopenharmony_ci return 0; 62298c2ecf20Sopenharmony_ci} 62308c2ecf20Sopenharmony_ci 62318c2ecf20Sopenharmony_ci 62328c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 62338c2ecf20Sopenharmony_ci 62348c2ecf20Sopenharmony_ci/* 62358c2ecf20Sopenharmony_ci * Helper functions so that transaction is started before we acquire dqio_sem 62368c2ecf20Sopenharmony_ci * to keep correct lock ordering of transaction > dqio_sem 62378c2ecf20Sopenharmony_ci */ 62388c2ecf20Sopenharmony_cistatic inline struct inode *dquot_to_inode(struct dquot *dquot) 62398c2ecf20Sopenharmony_ci{ 62408c2ecf20Sopenharmony_ci return sb_dqopt(dquot->dq_sb)->files[dquot->dq_id.type]; 62418c2ecf20Sopenharmony_ci} 62428c2ecf20Sopenharmony_ci 62438c2ecf20Sopenharmony_cistatic int ext4_write_dquot(struct dquot *dquot) 62448c2ecf20Sopenharmony_ci{ 62458c2ecf20Sopenharmony_ci int ret, err; 62468c2ecf20Sopenharmony_ci handle_t *handle; 62478c2ecf20Sopenharmony_ci struct inode *inode; 62488c2ecf20Sopenharmony_ci 62498c2ecf20Sopenharmony_ci inode = dquot_to_inode(dquot); 62508c2ecf20Sopenharmony_ci handle = ext4_journal_start(inode, EXT4_HT_QUOTA, 62518c2ecf20Sopenharmony_ci EXT4_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); 62528c2ecf20Sopenharmony_ci if (IS_ERR(handle)) 62538c2ecf20Sopenharmony_ci return PTR_ERR(handle); 62548c2ecf20Sopenharmony_ci ret = dquot_commit(dquot); 62558c2ecf20Sopenharmony_ci err = ext4_journal_stop(handle); 62568c2ecf20Sopenharmony_ci if (!ret) 62578c2ecf20Sopenharmony_ci ret = err; 62588c2ecf20Sopenharmony_ci return ret; 62598c2ecf20Sopenharmony_ci} 62608c2ecf20Sopenharmony_ci 62618c2ecf20Sopenharmony_cistatic int ext4_acquire_dquot(struct dquot *dquot) 62628c2ecf20Sopenharmony_ci{ 62638c2ecf20Sopenharmony_ci int ret, err; 62648c2ecf20Sopenharmony_ci handle_t *handle; 62658c2ecf20Sopenharmony_ci 62668c2ecf20Sopenharmony_ci handle = ext4_journal_start(dquot_to_inode(dquot), EXT4_HT_QUOTA, 62678c2ecf20Sopenharmony_ci EXT4_QUOTA_INIT_BLOCKS(dquot->dq_sb)); 62688c2ecf20Sopenharmony_ci if (IS_ERR(handle)) 62698c2ecf20Sopenharmony_ci return PTR_ERR(handle); 62708c2ecf20Sopenharmony_ci ret = dquot_acquire(dquot); 62718c2ecf20Sopenharmony_ci err = ext4_journal_stop(handle); 62728c2ecf20Sopenharmony_ci if (!ret) 62738c2ecf20Sopenharmony_ci ret = err; 62748c2ecf20Sopenharmony_ci return ret; 62758c2ecf20Sopenharmony_ci} 62768c2ecf20Sopenharmony_ci 62778c2ecf20Sopenharmony_cistatic int ext4_release_dquot(struct dquot *dquot) 62788c2ecf20Sopenharmony_ci{ 62798c2ecf20Sopenharmony_ci int ret, err; 62808c2ecf20Sopenharmony_ci handle_t *handle; 62818c2ecf20Sopenharmony_ci 62828c2ecf20Sopenharmony_ci handle = ext4_journal_start(dquot_to_inode(dquot), EXT4_HT_QUOTA, 62838c2ecf20Sopenharmony_ci EXT4_QUOTA_DEL_BLOCKS(dquot->dq_sb)); 62848c2ecf20Sopenharmony_ci if (IS_ERR(handle)) { 62858c2ecf20Sopenharmony_ci /* Release dquot anyway to avoid endless cycle in dqput() */ 62868c2ecf20Sopenharmony_ci dquot_release(dquot); 62878c2ecf20Sopenharmony_ci return PTR_ERR(handle); 62888c2ecf20Sopenharmony_ci } 62898c2ecf20Sopenharmony_ci ret = dquot_release(dquot); 62908c2ecf20Sopenharmony_ci err = ext4_journal_stop(handle); 62918c2ecf20Sopenharmony_ci if (!ret) 62928c2ecf20Sopenharmony_ci ret = err; 62938c2ecf20Sopenharmony_ci return ret; 62948c2ecf20Sopenharmony_ci} 62958c2ecf20Sopenharmony_ci 62968c2ecf20Sopenharmony_cistatic int ext4_mark_dquot_dirty(struct dquot *dquot) 62978c2ecf20Sopenharmony_ci{ 62988c2ecf20Sopenharmony_ci struct super_block *sb = dquot->dq_sb; 62998c2ecf20Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 63008c2ecf20Sopenharmony_ci 63018c2ecf20Sopenharmony_ci /* Are we journaling quotas? */ 63028c2ecf20Sopenharmony_ci if (ext4_has_feature_quota(sb) || 63038c2ecf20Sopenharmony_ci sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) { 63048c2ecf20Sopenharmony_ci dquot_mark_dquot_dirty(dquot); 63058c2ecf20Sopenharmony_ci return ext4_write_dquot(dquot); 63068c2ecf20Sopenharmony_ci } else { 63078c2ecf20Sopenharmony_ci return dquot_mark_dquot_dirty(dquot); 63088c2ecf20Sopenharmony_ci } 63098c2ecf20Sopenharmony_ci} 63108c2ecf20Sopenharmony_ci 63118c2ecf20Sopenharmony_cistatic int ext4_write_info(struct super_block *sb, int type) 63128c2ecf20Sopenharmony_ci{ 63138c2ecf20Sopenharmony_ci int ret, err; 63148c2ecf20Sopenharmony_ci handle_t *handle; 63158c2ecf20Sopenharmony_ci 63168c2ecf20Sopenharmony_ci /* Data block + inode block */ 63178c2ecf20Sopenharmony_ci handle = ext4_journal_start_sb(sb, EXT4_HT_QUOTA, 2); 63188c2ecf20Sopenharmony_ci if (IS_ERR(handle)) 63198c2ecf20Sopenharmony_ci return PTR_ERR(handle); 63208c2ecf20Sopenharmony_ci ret = dquot_commit_info(sb, type); 63218c2ecf20Sopenharmony_ci err = ext4_journal_stop(handle); 63228c2ecf20Sopenharmony_ci if (!ret) 63238c2ecf20Sopenharmony_ci ret = err; 63248c2ecf20Sopenharmony_ci return ret; 63258c2ecf20Sopenharmony_ci} 63268c2ecf20Sopenharmony_ci 63278c2ecf20Sopenharmony_ci/* 63288c2ecf20Sopenharmony_ci * Turn on quotas during mount time - we need to find 63298c2ecf20Sopenharmony_ci * the quota file and such... 63308c2ecf20Sopenharmony_ci */ 63318c2ecf20Sopenharmony_cistatic int ext4_quota_on_mount(struct super_block *sb, int type) 63328c2ecf20Sopenharmony_ci{ 63338c2ecf20Sopenharmony_ci return dquot_quota_on_mount(sb, get_qf_name(sb, EXT4_SB(sb), type), 63348c2ecf20Sopenharmony_ci EXT4_SB(sb)->s_jquota_fmt, type); 63358c2ecf20Sopenharmony_ci} 63368c2ecf20Sopenharmony_ci 63378c2ecf20Sopenharmony_cistatic void lockdep_set_quota_inode(struct inode *inode, int subclass) 63388c2ecf20Sopenharmony_ci{ 63398c2ecf20Sopenharmony_ci struct ext4_inode_info *ei = EXT4_I(inode); 63408c2ecf20Sopenharmony_ci 63418c2ecf20Sopenharmony_ci /* The first argument of lockdep_set_subclass has to be 63428c2ecf20Sopenharmony_ci * *exactly* the same as the argument to init_rwsem() --- in 63438c2ecf20Sopenharmony_ci * this case, in init_once() --- or lockdep gets unhappy 63448c2ecf20Sopenharmony_ci * because the name of the lock is set using the 63458c2ecf20Sopenharmony_ci * stringification of the argument to init_rwsem(). 63468c2ecf20Sopenharmony_ci */ 63478c2ecf20Sopenharmony_ci (void) ei; /* shut up clang warning if !CONFIG_LOCKDEP */ 63488c2ecf20Sopenharmony_ci lockdep_set_subclass(&ei->i_data_sem, subclass); 63498c2ecf20Sopenharmony_ci} 63508c2ecf20Sopenharmony_ci 63518c2ecf20Sopenharmony_ci/* 63528c2ecf20Sopenharmony_ci * Standard function to be called on quota_on 63538c2ecf20Sopenharmony_ci */ 63548c2ecf20Sopenharmony_cistatic int ext4_quota_on(struct super_block *sb, int type, int format_id, 63558c2ecf20Sopenharmony_ci const struct path *path) 63568c2ecf20Sopenharmony_ci{ 63578c2ecf20Sopenharmony_ci int err; 63588c2ecf20Sopenharmony_ci 63598c2ecf20Sopenharmony_ci if (!test_opt(sb, QUOTA)) 63608c2ecf20Sopenharmony_ci return -EINVAL; 63618c2ecf20Sopenharmony_ci 63628c2ecf20Sopenharmony_ci /* Quotafile not on the same filesystem? */ 63638c2ecf20Sopenharmony_ci if (path->dentry->d_sb != sb) 63648c2ecf20Sopenharmony_ci return -EXDEV; 63658c2ecf20Sopenharmony_ci 63668c2ecf20Sopenharmony_ci /* Quota already enabled for this file? */ 63678c2ecf20Sopenharmony_ci if (IS_NOQUOTA(d_inode(path->dentry))) 63688c2ecf20Sopenharmony_ci return -EBUSY; 63698c2ecf20Sopenharmony_ci 63708c2ecf20Sopenharmony_ci /* Journaling quota? */ 63718c2ecf20Sopenharmony_ci if (EXT4_SB(sb)->s_qf_names[type]) { 63728c2ecf20Sopenharmony_ci /* Quotafile not in fs root? */ 63738c2ecf20Sopenharmony_ci if (path->dentry->d_parent != sb->s_root) 63748c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, 63758c2ecf20Sopenharmony_ci "Quota file not on filesystem root. " 63768c2ecf20Sopenharmony_ci "Journaled quota will not work"); 63778c2ecf20Sopenharmony_ci sb_dqopt(sb)->flags |= DQUOT_NOLIST_DIRTY; 63788c2ecf20Sopenharmony_ci } else { 63798c2ecf20Sopenharmony_ci /* 63808c2ecf20Sopenharmony_ci * Clear the flag just in case mount options changed since 63818c2ecf20Sopenharmony_ci * last time. 63828c2ecf20Sopenharmony_ci */ 63838c2ecf20Sopenharmony_ci sb_dqopt(sb)->flags &= ~DQUOT_NOLIST_DIRTY; 63848c2ecf20Sopenharmony_ci } 63858c2ecf20Sopenharmony_ci 63868c2ecf20Sopenharmony_ci /* 63878c2ecf20Sopenharmony_ci * When we journal data on quota file, we have to flush journal to see 63888c2ecf20Sopenharmony_ci * all updates to the file when we bypass pagecache... 63898c2ecf20Sopenharmony_ci */ 63908c2ecf20Sopenharmony_ci if (EXT4_SB(sb)->s_journal && 63918c2ecf20Sopenharmony_ci ext4_should_journal_data(d_inode(path->dentry))) { 63928c2ecf20Sopenharmony_ci /* 63938c2ecf20Sopenharmony_ci * We don't need to lock updates but journal_flush() could 63948c2ecf20Sopenharmony_ci * otherwise be livelocked... 63958c2ecf20Sopenharmony_ci */ 63968c2ecf20Sopenharmony_ci jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); 63978c2ecf20Sopenharmony_ci err = jbd2_journal_flush(EXT4_SB(sb)->s_journal); 63988c2ecf20Sopenharmony_ci jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 63998c2ecf20Sopenharmony_ci if (err) 64008c2ecf20Sopenharmony_ci return err; 64018c2ecf20Sopenharmony_ci } 64028c2ecf20Sopenharmony_ci 64038c2ecf20Sopenharmony_ci lockdep_set_quota_inode(path->dentry->d_inode, I_DATA_SEM_QUOTA); 64048c2ecf20Sopenharmony_ci err = dquot_quota_on(sb, type, format_id, path); 64058c2ecf20Sopenharmony_ci if (!err) { 64068c2ecf20Sopenharmony_ci struct inode *inode = d_inode(path->dentry); 64078c2ecf20Sopenharmony_ci handle_t *handle; 64088c2ecf20Sopenharmony_ci 64098c2ecf20Sopenharmony_ci /* 64108c2ecf20Sopenharmony_ci * Set inode flags to prevent userspace from messing with quota 64118c2ecf20Sopenharmony_ci * files. If this fails, we return success anyway since quotas 64128c2ecf20Sopenharmony_ci * are already enabled and this is not a hard failure. 64138c2ecf20Sopenharmony_ci */ 64148c2ecf20Sopenharmony_ci inode_lock(inode); 64158c2ecf20Sopenharmony_ci handle = ext4_journal_start(inode, EXT4_HT_QUOTA, 1); 64168c2ecf20Sopenharmony_ci if (IS_ERR(handle)) 64178c2ecf20Sopenharmony_ci goto unlock_inode; 64188c2ecf20Sopenharmony_ci EXT4_I(inode)->i_flags |= EXT4_NOATIME_FL | EXT4_IMMUTABLE_FL; 64198c2ecf20Sopenharmony_ci inode_set_flags(inode, S_NOATIME | S_IMMUTABLE, 64208c2ecf20Sopenharmony_ci S_NOATIME | S_IMMUTABLE); 64218c2ecf20Sopenharmony_ci err = ext4_mark_inode_dirty(handle, inode); 64228c2ecf20Sopenharmony_ci ext4_journal_stop(handle); 64238c2ecf20Sopenharmony_ci unlock_inode: 64248c2ecf20Sopenharmony_ci inode_unlock(inode); 64258c2ecf20Sopenharmony_ci if (err) 64268c2ecf20Sopenharmony_ci dquot_quota_off(sb, type); 64278c2ecf20Sopenharmony_ci } 64288c2ecf20Sopenharmony_ci if (err) 64298c2ecf20Sopenharmony_ci lockdep_set_quota_inode(path->dentry->d_inode, 64308c2ecf20Sopenharmony_ci I_DATA_SEM_NORMAL); 64318c2ecf20Sopenharmony_ci return err; 64328c2ecf20Sopenharmony_ci} 64338c2ecf20Sopenharmony_ci 64348c2ecf20Sopenharmony_cistatic inline bool ext4_check_quota_inum(int type, unsigned long qf_inum) 64358c2ecf20Sopenharmony_ci{ 64368c2ecf20Sopenharmony_ci switch (type) { 64378c2ecf20Sopenharmony_ci case USRQUOTA: 64388c2ecf20Sopenharmony_ci return qf_inum == EXT4_USR_QUOTA_INO; 64398c2ecf20Sopenharmony_ci case GRPQUOTA: 64408c2ecf20Sopenharmony_ci return qf_inum == EXT4_GRP_QUOTA_INO; 64418c2ecf20Sopenharmony_ci case PRJQUOTA: 64428c2ecf20Sopenharmony_ci return qf_inum >= EXT4_GOOD_OLD_FIRST_INO; 64438c2ecf20Sopenharmony_ci default: 64448c2ecf20Sopenharmony_ci BUG(); 64458c2ecf20Sopenharmony_ci } 64468c2ecf20Sopenharmony_ci} 64478c2ecf20Sopenharmony_ci 64488c2ecf20Sopenharmony_cistatic int ext4_quota_enable(struct super_block *sb, int type, int format_id, 64498c2ecf20Sopenharmony_ci unsigned int flags) 64508c2ecf20Sopenharmony_ci{ 64518c2ecf20Sopenharmony_ci int err; 64528c2ecf20Sopenharmony_ci struct inode *qf_inode; 64538c2ecf20Sopenharmony_ci unsigned long qf_inums[EXT4_MAXQUOTAS] = { 64548c2ecf20Sopenharmony_ci le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum), 64558c2ecf20Sopenharmony_ci le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum), 64568c2ecf20Sopenharmony_ci le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum) 64578c2ecf20Sopenharmony_ci }; 64588c2ecf20Sopenharmony_ci 64598c2ecf20Sopenharmony_ci BUG_ON(!ext4_has_feature_quota(sb)); 64608c2ecf20Sopenharmony_ci 64618c2ecf20Sopenharmony_ci if (!qf_inums[type]) 64628c2ecf20Sopenharmony_ci return -EPERM; 64638c2ecf20Sopenharmony_ci 64648c2ecf20Sopenharmony_ci if (!ext4_check_quota_inum(type, qf_inums[type])) { 64658c2ecf20Sopenharmony_ci ext4_error(sb, "Bad quota inum: %lu, type: %d", 64668c2ecf20Sopenharmony_ci qf_inums[type], type); 64678c2ecf20Sopenharmony_ci return -EUCLEAN; 64688c2ecf20Sopenharmony_ci } 64698c2ecf20Sopenharmony_ci 64708c2ecf20Sopenharmony_ci qf_inode = ext4_iget(sb, qf_inums[type], EXT4_IGET_SPECIAL); 64718c2ecf20Sopenharmony_ci if (IS_ERR(qf_inode)) { 64728c2ecf20Sopenharmony_ci ext4_error(sb, "Bad quota inode: %lu, type: %d", 64738c2ecf20Sopenharmony_ci qf_inums[type], type); 64748c2ecf20Sopenharmony_ci return PTR_ERR(qf_inode); 64758c2ecf20Sopenharmony_ci } 64768c2ecf20Sopenharmony_ci 64778c2ecf20Sopenharmony_ci /* Don't account quota for quota files to avoid recursion */ 64788c2ecf20Sopenharmony_ci qf_inode->i_flags |= S_NOQUOTA; 64798c2ecf20Sopenharmony_ci lockdep_set_quota_inode(qf_inode, I_DATA_SEM_QUOTA); 64808c2ecf20Sopenharmony_ci err = dquot_load_quota_inode(qf_inode, type, format_id, flags); 64818c2ecf20Sopenharmony_ci if (err) 64828c2ecf20Sopenharmony_ci lockdep_set_quota_inode(qf_inode, I_DATA_SEM_NORMAL); 64838c2ecf20Sopenharmony_ci iput(qf_inode); 64848c2ecf20Sopenharmony_ci 64858c2ecf20Sopenharmony_ci return err; 64868c2ecf20Sopenharmony_ci} 64878c2ecf20Sopenharmony_ci 64888c2ecf20Sopenharmony_ci/* Enable usage tracking for all quota types. */ 64898c2ecf20Sopenharmony_cistatic int ext4_enable_quotas(struct super_block *sb) 64908c2ecf20Sopenharmony_ci{ 64918c2ecf20Sopenharmony_ci int type, err = 0; 64928c2ecf20Sopenharmony_ci unsigned long qf_inums[EXT4_MAXQUOTAS] = { 64938c2ecf20Sopenharmony_ci le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum), 64948c2ecf20Sopenharmony_ci le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum), 64958c2ecf20Sopenharmony_ci le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum) 64968c2ecf20Sopenharmony_ci }; 64978c2ecf20Sopenharmony_ci bool quota_mopt[EXT4_MAXQUOTAS] = { 64988c2ecf20Sopenharmony_ci test_opt(sb, USRQUOTA), 64998c2ecf20Sopenharmony_ci test_opt(sb, GRPQUOTA), 65008c2ecf20Sopenharmony_ci test_opt(sb, PRJQUOTA), 65018c2ecf20Sopenharmony_ci }; 65028c2ecf20Sopenharmony_ci 65038c2ecf20Sopenharmony_ci sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE | DQUOT_NOLIST_DIRTY; 65048c2ecf20Sopenharmony_ci for (type = 0; type < EXT4_MAXQUOTAS; type++) { 65058c2ecf20Sopenharmony_ci if (qf_inums[type]) { 65068c2ecf20Sopenharmony_ci err = ext4_quota_enable(sb, type, QFMT_VFS_V1, 65078c2ecf20Sopenharmony_ci DQUOT_USAGE_ENABLED | 65088c2ecf20Sopenharmony_ci (quota_mopt[type] ? DQUOT_LIMITS_ENABLED : 0)); 65098c2ecf20Sopenharmony_ci if (err) { 65108c2ecf20Sopenharmony_ci ext4_warning(sb, 65118c2ecf20Sopenharmony_ci "Failed to enable quota tracking " 65128c2ecf20Sopenharmony_ci "(type=%d, err=%d, ino=%lu). " 65138c2ecf20Sopenharmony_ci "Please run e2fsck to fix.", type, 65148c2ecf20Sopenharmony_ci err, qf_inums[type]); 65158c2ecf20Sopenharmony_ci for (type--; type >= 0; type--) { 65168c2ecf20Sopenharmony_ci struct inode *inode; 65178c2ecf20Sopenharmony_ci 65188c2ecf20Sopenharmony_ci inode = sb_dqopt(sb)->files[type]; 65198c2ecf20Sopenharmony_ci if (inode) 65208c2ecf20Sopenharmony_ci inode = igrab(inode); 65218c2ecf20Sopenharmony_ci dquot_quota_off(sb, type); 65228c2ecf20Sopenharmony_ci if (inode) { 65238c2ecf20Sopenharmony_ci lockdep_set_quota_inode(inode, 65248c2ecf20Sopenharmony_ci I_DATA_SEM_NORMAL); 65258c2ecf20Sopenharmony_ci iput(inode); 65268c2ecf20Sopenharmony_ci } 65278c2ecf20Sopenharmony_ci } 65288c2ecf20Sopenharmony_ci 65298c2ecf20Sopenharmony_ci return err; 65308c2ecf20Sopenharmony_ci } 65318c2ecf20Sopenharmony_ci } 65328c2ecf20Sopenharmony_ci } 65338c2ecf20Sopenharmony_ci return 0; 65348c2ecf20Sopenharmony_ci} 65358c2ecf20Sopenharmony_ci 65368c2ecf20Sopenharmony_cistatic int ext4_quota_off(struct super_block *sb, int type) 65378c2ecf20Sopenharmony_ci{ 65388c2ecf20Sopenharmony_ci struct inode *inode = sb_dqopt(sb)->files[type]; 65398c2ecf20Sopenharmony_ci handle_t *handle; 65408c2ecf20Sopenharmony_ci int err; 65418c2ecf20Sopenharmony_ci 65428c2ecf20Sopenharmony_ci /* Force all delayed allocation blocks to be allocated. 65438c2ecf20Sopenharmony_ci * Caller already holds s_umount sem */ 65448c2ecf20Sopenharmony_ci if (test_opt(sb, DELALLOC)) 65458c2ecf20Sopenharmony_ci sync_filesystem(sb); 65468c2ecf20Sopenharmony_ci 65478c2ecf20Sopenharmony_ci if (!inode || !igrab(inode)) 65488c2ecf20Sopenharmony_ci goto out; 65498c2ecf20Sopenharmony_ci 65508c2ecf20Sopenharmony_ci err = dquot_quota_off(sb, type); 65518c2ecf20Sopenharmony_ci if (err || ext4_has_feature_quota(sb)) 65528c2ecf20Sopenharmony_ci goto out_put; 65538c2ecf20Sopenharmony_ci 65548c2ecf20Sopenharmony_ci inode_lock(inode); 65558c2ecf20Sopenharmony_ci /* 65568c2ecf20Sopenharmony_ci * Update modification times of quota files when userspace can 65578c2ecf20Sopenharmony_ci * start looking at them. If we fail, we return success anyway since 65588c2ecf20Sopenharmony_ci * this is not a hard failure and quotas are already disabled. 65598c2ecf20Sopenharmony_ci */ 65608c2ecf20Sopenharmony_ci handle = ext4_journal_start(inode, EXT4_HT_QUOTA, 1); 65618c2ecf20Sopenharmony_ci if (IS_ERR(handle)) { 65628c2ecf20Sopenharmony_ci err = PTR_ERR(handle); 65638c2ecf20Sopenharmony_ci goto out_unlock; 65648c2ecf20Sopenharmony_ci } 65658c2ecf20Sopenharmony_ci EXT4_I(inode)->i_flags &= ~(EXT4_NOATIME_FL | EXT4_IMMUTABLE_FL); 65668c2ecf20Sopenharmony_ci inode_set_flags(inode, 0, S_NOATIME | S_IMMUTABLE); 65678c2ecf20Sopenharmony_ci inode->i_mtime = inode->i_ctime = current_time(inode); 65688c2ecf20Sopenharmony_ci err = ext4_mark_inode_dirty(handle, inode); 65698c2ecf20Sopenharmony_ci ext4_journal_stop(handle); 65708c2ecf20Sopenharmony_ciout_unlock: 65718c2ecf20Sopenharmony_ci inode_unlock(inode); 65728c2ecf20Sopenharmony_ciout_put: 65738c2ecf20Sopenharmony_ci lockdep_set_quota_inode(inode, I_DATA_SEM_NORMAL); 65748c2ecf20Sopenharmony_ci iput(inode); 65758c2ecf20Sopenharmony_ci return err; 65768c2ecf20Sopenharmony_ciout: 65778c2ecf20Sopenharmony_ci return dquot_quota_off(sb, type); 65788c2ecf20Sopenharmony_ci} 65798c2ecf20Sopenharmony_ci 65808c2ecf20Sopenharmony_ci/* Read data from quotafile - avoid pagecache and such because we cannot afford 65818c2ecf20Sopenharmony_ci * acquiring the locks... As quota files are never truncated and quota code 65828c2ecf20Sopenharmony_ci * itself serializes the operations (and no one else should touch the files) 65838c2ecf20Sopenharmony_ci * we don't have to be afraid of races */ 65848c2ecf20Sopenharmony_cistatic ssize_t ext4_quota_read(struct super_block *sb, int type, char *data, 65858c2ecf20Sopenharmony_ci size_t len, loff_t off) 65868c2ecf20Sopenharmony_ci{ 65878c2ecf20Sopenharmony_ci struct inode *inode = sb_dqopt(sb)->files[type]; 65888c2ecf20Sopenharmony_ci ext4_lblk_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb); 65898c2ecf20Sopenharmony_ci int offset = off & (sb->s_blocksize - 1); 65908c2ecf20Sopenharmony_ci int tocopy; 65918c2ecf20Sopenharmony_ci size_t toread; 65928c2ecf20Sopenharmony_ci struct buffer_head *bh; 65938c2ecf20Sopenharmony_ci loff_t i_size = i_size_read(inode); 65948c2ecf20Sopenharmony_ci 65958c2ecf20Sopenharmony_ci if (off > i_size) 65968c2ecf20Sopenharmony_ci return 0; 65978c2ecf20Sopenharmony_ci if (off+len > i_size) 65988c2ecf20Sopenharmony_ci len = i_size-off; 65998c2ecf20Sopenharmony_ci toread = len; 66008c2ecf20Sopenharmony_ci while (toread > 0) { 66018c2ecf20Sopenharmony_ci tocopy = sb->s_blocksize - offset < toread ? 66028c2ecf20Sopenharmony_ci sb->s_blocksize - offset : toread; 66038c2ecf20Sopenharmony_ci bh = ext4_bread(NULL, inode, blk, 0); 66048c2ecf20Sopenharmony_ci if (IS_ERR(bh)) 66058c2ecf20Sopenharmony_ci return PTR_ERR(bh); 66068c2ecf20Sopenharmony_ci if (!bh) /* A hole? */ 66078c2ecf20Sopenharmony_ci memset(data, 0, tocopy); 66088c2ecf20Sopenharmony_ci else 66098c2ecf20Sopenharmony_ci memcpy(data, bh->b_data+offset, tocopy); 66108c2ecf20Sopenharmony_ci brelse(bh); 66118c2ecf20Sopenharmony_ci offset = 0; 66128c2ecf20Sopenharmony_ci toread -= tocopy; 66138c2ecf20Sopenharmony_ci data += tocopy; 66148c2ecf20Sopenharmony_ci blk++; 66158c2ecf20Sopenharmony_ci } 66168c2ecf20Sopenharmony_ci return len; 66178c2ecf20Sopenharmony_ci} 66188c2ecf20Sopenharmony_ci 66198c2ecf20Sopenharmony_ci/* Write to quotafile (we know the transaction is already started and has 66208c2ecf20Sopenharmony_ci * enough credits) */ 66218c2ecf20Sopenharmony_cistatic ssize_t ext4_quota_write(struct super_block *sb, int type, 66228c2ecf20Sopenharmony_ci const char *data, size_t len, loff_t off) 66238c2ecf20Sopenharmony_ci{ 66248c2ecf20Sopenharmony_ci struct inode *inode = sb_dqopt(sb)->files[type]; 66258c2ecf20Sopenharmony_ci ext4_lblk_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb); 66268c2ecf20Sopenharmony_ci int err = 0, err2 = 0, offset = off & (sb->s_blocksize - 1); 66278c2ecf20Sopenharmony_ci int retries = 0; 66288c2ecf20Sopenharmony_ci struct buffer_head *bh; 66298c2ecf20Sopenharmony_ci handle_t *handle = journal_current_handle(); 66308c2ecf20Sopenharmony_ci 66318c2ecf20Sopenharmony_ci if (!handle) { 66328c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, "Quota write (off=%llu, len=%llu)" 66338c2ecf20Sopenharmony_ci " cancelled because transaction is not started", 66348c2ecf20Sopenharmony_ci (unsigned long long)off, (unsigned long long)len); 66358c2ecf20Sopenharmony_ci return -EIO; 66368c2ecf20Sopenharmony_ci } 66378c2ecf20Sopenharmony_ci /* 66388c2ecf20Sopenharmony_ci * Since we account only one data block in transaction credits, 66398c2ecf20Sopenharmony_ci * then it is impossible to cross a block boundary. 66408c2ecf20Sopenharmony_ci */ 66418c2ecf20Sopenharmony_ci if (sb->s_blocksize - offset < len) { 66428c2ecf20Sopenharmony_ci ext4_msg(sb, KERN_WARNING, "Quota write (off=%llu, len=%llu)" 66438c2ecf20Sopenharmony_ci " cancelled because not block aligned", 66448c2ecf20Sopenharmony_ci (unsigned long long)off, (unsigned long long)len); 66458c2ecf20Sopenharmony_ci return -EIO; 66468c2ecf20Sopenharmony_ci } 66478c2ecf20Sopenharmony_ci 66488c2ecf20Sopenharmony_ci do { 66498c2ecf20Sopenharmony_ci bh = ext4_bread(handle, inode, blk, 66508c2ecf20Sopenharmony_ci EXT4_GET_BLOCKS_CREATE | 66518c2ecf20Sopenharmony_ci EXT4_GET_BLOCKS_METADATA_NOFAIL); 66528c2ecf20Sopenharmony_ci } while (PTR_ERR(bh) == -ENOSPC && 66538c2ecf20Sopenharmony_ci ext4_should_retry_alloc(inode->i_sb, &retries)); 66548c2ecf20Sopenharmony_ci if (IS_ERR(bh)) 66558c2ecf20Sopenharmony_ci return PTR_ERR(bh); 66568c2ecf20Sopenharmony_ci if (!bh) 66578c2ecf20Sopenharmony_ci goto out; 66588c2ecf20Sopenharmony_ci BUFFER_TRACE(bh, "get write access"); 66598c2ecf20Sopenharmony_ci err = ext4_journal_get_write_access(handle, bh); 66608c2ecf20Sopenharmony_ci if (err) { 66618c2ecf20Sopenharmony_ci brelse(bh); 66628c2ecf20Sopenharmony_ci return err; 66638c2ecf20Sopenharmony_ci } 66648c2ecf20Sopenharmony_ci lock_buffer(bh); 66658c2ecf20Sopenharmony_ci memcpy(bh->b_data+offset, data, len); 66668c2ecf20Sopenharmony_ci flush_dcache_page(bh->b_page); 66678c2ecf20Sopenharmony_ci unlock_buffer(bh); 66688c2ecf20Sopenharmony_ci err = ext4_handle_dirty_metadata(handle, NULL, bh); 66698c2ecf20Sopenharmony_ci brelse(bh); 66708c2ecf20Sopenharmony_ciout: 66718c2ecf20Sopenharmony_ci if (inode->i_size < off + len) { 66728c2ecf20Sopenharmony_ci i_size_write(inode, off + len); 66738c2ecf20Sopenharmony_ci EXT4_I(inode)->i_disksize = inode->i_size; 66748c2ecf20Sopenharmony_ci err2 = ext4_mark_inode_dirty(handle, inode); 66758c2ecf20Sopenharmony_ci if (unlikely(err2 && !err)) 66768c2ecf20Sopenharmony_ci err = err2; 66778c2ecf20Sopenharmony_ci } 66788c2ecf20Sopenharmony_ci return err ? err : len; 66798c2ecf20Sopenharmony_ci} 66808c2ecf20Sopenharmony_ci#endif 66818c2ecf20Sopenharmony_ci 66828c2ecf20Sopenharmony_cistatic struct dentry *ext4_mount(struct file_system_type *fs_type, int flags, 66838c2ecf20Sopenharmony_ci const char *dev_name, void *data) 66848c2ecf20Sopenharmony_ci{ 66858c2ecf20Sopenharmony_ci return mount_bdev(fs_type, flags, dev_name, data, ext4_fill_super); 66868c2ecf20Sopenharmony_ci} 66878c2ecf20Sopenharmony_ci 66888c2ecf20Sopenharmony_ci#if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT2) 66898c2ecf20Sopenharmony_cistatic inline void register_as_ext2(void) 66908c2ecf20Sopenharmony_ci{ 66918c2ecf20Sopenharmony_ci int err = register_filesystem(&ext2_fs_type); 66928c2ecf20Sopenharmony_ci if (err) 66938c2ecf20Sopenharmony_ci printk(KERN_WARNING 66948c2ecf20Sopenharmony_ci "EXT4-fs: Unable to register as ext2 (%d)\n", err); 66958c2ecf20Sopenharmony_ci} 66968c2ecf20Sopenharmony_ci 66978c2ecf20Sopenharmony_cistatic inline void unregister_as_ext2(void) 66988c2ecf20Sopenharmony_ci{ 66998c2ecf20Sopenharmony_ci unregister_filesystem(&ext2_fs_type); 67008c2ecf20Sopenharmony_ci} 67018c2ecf20Sopenharmony_ci 67028c2ecf20Sopenharmony_cistatic inline int ext2_feature_set_ok(struct super_block *sb) 67038c2ecf20Sopenharmony_ci{ 67048c2ecf20Sopenharmony_ci if (ext4_has_unknown_ext2_incompat_features(sb)) 67058c2ecf20Sopenharmony_ci return 0; 67068c2ecf20Sopenharmony_ci if (sb_rdonly(sb)) 67078c2ecf20Sopenharmony_ci return 1; 67088c2ecf20Sopenharmony_ci if (ext4_has_unknown_ext2_ro_compat_features(sb)) 67098c2ecf20Sopenharmony_ci return 0; 67108c2ecf20Sopenharmony_ci return 1; 67118c2ecf20Sopenharmony_ci} 67128c2ecf20Sopenharmony_ci#else 67138c2ecf20Sopenharmony_cistatic inline void register_as_ext2(void) { } 67148c2ecf20Sopenharmony_cistatic inline void unregister_as_ext2(void) { } 67158c2ecf20Sopenharmony_cistatic inline int ext2_feature_set_ok(struct super_block *sb) { return 0; } 67168c2ecf20Sopenharmony_ci#endif 67178c2ecf20Sopenharmony_ci 67188c2ecf20Sopenharmony_cistatic inline void register_as_ext3(void) 67198c2ecf20Sopenharmony_ci{ 67208c2ecf20Sopenharmony_ci int err = register_filesystem(&ext3_fs_type); 67218c2ecf20Sopenharmony_ci if (err) 67228c2ecf20Sopenharmony_ci printk(KERN_WARNING 67238c2ecf20Sopenharmony_ci "EXT4-fs: Unable to register as ext3 (%d)\n", err); 67248c2ecf20Sopenharmony_ci} 67258c2ecf20Sopenharmony_ci 67268c2ecf20Sopenharmony_cistatic inline void unregister_as_ext3(void) 67278c2ecf20Sopenharmony_ci{ 67288c2ecf20Sopenharmony_ci unregister_filesystem(&ext3_fs_type); 67298c2ecf20Sopenharmony_ci} 67308c2ecf20Sopenharmony_ci 67318c2ecf20Sopenharmony_cistatic inline int ext3_feature_set_ok(struct super_block *sb) 67328c2ecf20Sopenharmony_ci{ 67338c2ecf20Sopenharmony_ci if (ext4_has_unknown_ext3_incompat_features(sb)) 67348c2ecf20Sopenharmony_ci return 0; 67358c2ecf20Sopenharmony_ci if (!ext4_has_feature_journal(sb)) 67368c2ecf20Sopenharmony_ci return 0; 67378c2ecf20Sopenharmony_ci if (sb_rdonly(sb)) 67388c2ecf20Sopenharmony_ci return 1; 67398c2ecf20Sopenharmony_ci if (ext4_has_unknown_ext3_ro_compat_features(sb)) 67408c2ecf20Sopenharmony_ci return 0; 67418c2ecf20Sopenharmony_ci return 1; 67428c2ecf20Sopenharmony_ci} 67438c2ecf20Sopenharmony_ci 67448c2ecf20Sopenharmony_cistatic struct file_system_type ext4_fs_type = { 67458c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 67468c2ecf20Sopenharmony_ci .name = "ext4", 67478c2ecf20Sopenharmony_ci .mount = ext4_mount, 67488c2ecf20Sopenharmony_ci .kill_sb = kill_block_super, 67498c2ecf20Sopenharmony_ci .fs_flags = FS_REQUIRES_DEV, 67508c2ecf20Sopenharmony_ci}; 67518c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("ext4"); 67528c2ecf20Sopenharmony_ci 67538c2ecf20Sopenharmony_ci/* Shared across all ext4 file systems */ 67548c2ecf20Sopenharmony_ciwait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ]; 67558c2ecf20Sopenharmony_ci 67568c2ecf20Sopenharmony_cistatic int __init ext4_init_fs(void) 67578c2ecf20Sopenharmony_ci{ 67588c2ecf20Sopenharmony_ci int i, err; 67598c2ecf20Sopenharmony_ci 67608c2ecf20Sopenharmony_ci ratelimit_state_init(&ext4_mount_msg_ratelimit, 30 * HZ, 64); 67618c2ecf20Sopenharmony_ci ext4_li_info = NULL; 67628c2ecf20Sopenharmony_ci mutex_init(&ext4_li_mtx); 67638c2ecf20Sopenharmony_ci 67648c2ecf20Sopenharmony_ci /* Build-time check for flags consistency */ 67658c2ecf20Sopenharmony_ci ext4_check_flag_values(); 67668c2ecf20Sopenharmony_ci 67678c2ecf20Sopenharmony_ci for (i = 0; i < EXT4_WQ_HASH_SZ; i++) 67688c2ecf20Sopenharmony_ci init_waitqueue_head(&ext4__ioend_wq[i]); 67698c2ecf20Sopenharmony_ci 67708c2ecf20Sopenharmony_ci err = ext4_init_es(); 67718c2ecf20Sopenharmony_ci if (err) 67728c2ecf20Sopenharmony_ci return err; 67738c2ecf20Sopenharmony_ci 67748c2ecf20Sopenharmony_ci err = ext4_init_pending(); 67758c2ecf20Sopenharmony_ci if (err) 67768c2ecf20Sopenharmony_ci goto out7; 67778c2ecf20Sopenharmony_ci 67788c2ecf20Sopenharmony_ci err = ext4_init_post_read_processing(); 67798c2ecf20Sopenharmony_ci if (err) 67808c2ecf20Sopenharmony_ci goto out6; 67818c2ecf20Sopenharmony_ci 67828c2ecf20Sopenharmony_ci err = ext4_init_pageio(); 67838c2ecf20Sopenharmony_ci if (err) 67848c2ecf20Sopenharmony_ci goto out5; 67858c2ecf20Sopenharmony_ci 67868c2ecf20Sopenharmony_ci err = ext4_init_system_zone(); 67878c2ecf20Sopenharmony_ci if (err) 67888c2ecf20Sopenharmony_ci goto out4; 67898c2ecf20Sopenharmony_ci 67908c2ecf20Sopenharmony_ci err = ext4_init_sysfs(); 67918c2ecf20Sopenharmony_ci if (err) 67928c2ecf20Sopenharmony_ci goto out3; 67938c2ecf20Sopenharmony_ci 67948c2ecf20Sopenharmony_ci err = ext4_init_mballoc(); 67958c2ecf20Sopenharmony_ci if (err) 67968c2ecf20Sopenharmony_ci goto out2; 67978c2ecf20Sopenharmony_ci err = init_inodecache(); 67988c2ecf20Sopenharmony_ci if (err) 67998c2ecf20Sopenharmony_ci goto out1; 68008c2ecf20Sopenharmony_ci 68018c2ecf20Sopenharmony_ci err = ext4_fc_init_dentry_cache(); 68028c2ecf20Sopenharmony_ci if (err) 68038c2ecf20Sopenharmony_ci goto out05; 68048c2ecf20Sopenharmony_ci 68058c2ecf20Sopenharmony_ci register_as_ext3(); 68068c2ecf20Sopenharmony_ci register_as_ext2(); 68078c2ecf20Sopenharmony_ci err = register_filesystem(&ext4_fs_type); 68088c2ecf20Sopenharmony_ci if (err) 68098c2ecf20Sopenharmony_ci goto out; 68108c2ecf20Sopenharmony_ci 68118c2ecf20Sopenharmony_ci return 0; 68128c2ecf20Sopenharmony_ciout: 68138c2ecf20Sopenharmony_ci unregister_as_ext2(); 68148c2ecf20Sopenharmony_ci unregister_as_ext3(); 68158c2ecf20Sopenharmony_ci ext4_fc_destroy_dentry_cache(); 68168c2ecf20Sopenharmony_ciout05: 68178c2ecf20Sopenharmony_ci destroy_inodecache(); 68188c2ecf20Sopenharmony_ciout1: 68198c2ecf20Sopenharmony_ci ext4_exit_mballoc(); 68208c2ecf20Sopenharmony_ciout2: 68218c2ecf20Sopenharmony_ci ext4_exit_sysfs(); 68228c2ecf20Sopenharmony_ciout3: 68238c2ecf20Sopenharmony_ci ext4_exit_system_zone(); 68248c2ecf20Sopenharmony_ciout4: 68258c2ecf20Sopenharmony_ci ext4_exit_pageio(); 68268c2ecf20Sopenharmony_ciout5: 68278c2ecf20Sopenharmony_ci ext4_exit_post_read_processing(); 68288c2ecf20Sopenharmony_ciout6: 68298c2ecf20Sopenharmony_ci ext4_exit_pending(); 68308c2ecf20Sopenharmony_ciout7: 68318c2ecf20Sopenharmony_ci ext4_exit_es(); 68328c2ecf20Sopenharmony_ci 68338c2ecf20Sopenharmony_ci return err; 68348c2ecf20Sopenharmony_ci} 68358c2ecf20Sopenharmony_ci 68368c2ecf20Sopenharmony_cistatic void __exit ext4_exit_fs(void) 68378c2ecf20Sopenharmony_ci{ 68388c2ecf20Sopenharmony_ci ext4_destroy_lazyinit_thread(); 68398c2ecf20Sopenharmony_ci unregister_as_ext2(); 68408c2ecf20Sopenharmony_ci unregister_as_ext3(); 68418c2ecf20Sopenharmony_ci unregister_filesystem(&ext4_fs_type); 68428c2ecf20Sopenharmony_ci ext4_fc_destroy_dentry_cache(); 68438c2ecf20Sopenharmony_ci destroy_inodecache(); 68448c2ecf20Sopenharmony_ci ext4_exit_mballoc(); 68458c2ecf20Sopenharmony_ci ext4_exit_sysfs(); 68468c2ecf20Sopenharmony_ci ext4_exit_system_zone(); 68478c2ecf20Sopenharmony_ci ext4_exit_pageio(); 68488c2ecf20Sopenharmony_ci ext4_exit_post_read_processing(); 68498c2ecf20Sopenharmony_ci ext4_exit_es(); 68508c2ecf20Sopenharmony_ci ext4_exit_pending(); 68518c2ecf20Sopenharmony_ci} 68528c2ecf20Sopenharmony_ci 68538c2ecf20Sopenharmony_ciMODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); 68548c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Fourth Extended Filesystem"); 68558c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 68568c2ecf20Sopenharmony_ciMODULE_SOFTDEP("pre: crc32c"); 68578c2ecf20Sopenharmony_cimodule_init(ext4_init_fs) 68588c2ecf20Sopenharmony_cimodule_exit(ext4_exit_fs) 6859