18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/ext2/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/slab.h> 248c2ecf20Sopenharmony_ci#include <linux/init.h> 258c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 268c2ecf20Sopenharmony_ci#include <linux/parser.h> 278c2ecf20Sopenharmony_ci#include <linux/random.h> 288c2ecf20Sopenharmony_ci#include <linux/buffer_head.h> 298c2ecf20Sopenharmony_ci#include <linux/exportfs.h> 308c2ecf20Sopenharmony_ci#include <linux/vfs.h> 318c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 328c2ecf20Sopenharmony_ci#include <linux/mount.h> 338c2ecf20Sopenharmony_ci#include <linux/log2.h> 348c2ecf20Sopenharmony_ci#include <linux/quotaops.h> 358c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 368c2ecf20Sopenharmony_ci#include <linux/dax.h> 378c2ecf20Sopenharmony_ci#include <linux/iversion.h> 388c2ecf20Sopenharmony_ci#include "ext2.h" 398c2ecf20Sopenharmony_ci#include "xattr.h" 408c2ecf20Sopenharmony_ci#include "acl.h" 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void ext2_write_super(struct super_block *sb); 438c2ecf20Sopenharmony_cistatic int ext2_remount (struct super_block * sb, int * flags, char * data); 448c2ecf20Sopenharmony_cistatic int ext2_statfs (struct dentry * dentry, struct kstatfs * buf); 458c2ecf20Sopenharmony_cistatic int ext2_sync_fs(struct super_block *sb, int wait); 468c2ecf20Sopenharmony_cistatic int ext2_freeze(struct super_block *sb); 478c2ecf20Sopenharmony_cistatic int ext2_unfreeze(struct super_block *sb); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_civoid ext2_error(struct super_block *sb, const char *function, 508c2ecf20Sopenharmony_ci const char *fmt, ...) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct va_format vaf; 538c2ecf20Sopenharmony_ci va_list args; 548c2ecf20Sopenharmony_ci struct ext2_sb_info *sbi = EXT2_SB(sb); 558c2ecf20Sopenharmony_ci struct ext2_super_block *es = sbi->s_es; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) { 588c2ecf20Sopenharmony_ci spin_lock(&sbi->s_lock); 598c2ecf20Sopenharmony_ci sbi->s_mount_state |= EXT2_ERROR_FS; 608c2ecf20Sopenharmony_ci es->s_state |= cpu_to_le16(EXT2_ERROR_FS); 618c2ecf20Sopenharmony_ci spin_unlock(&sbi->s_lock); 628c2ecf20Sopenharmony_ci ext2_sync_super(sb, es, 1); 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci va_start(args, fmt); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci vaf.fmt = fmt; 688c2ecf20Sopenharmony_ci vaf.va = &args; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci printk(KERN_CRIT "EXT2-fs (%s): error: %s: %pV\n", 718c2ecf20Sopenharmony_ci sb->s_id, function, &vaf); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci va_end(args); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (test_opt(sb, ERRORS_PANIC)) 768c2ecf20Sopenharmony_ci panic("EXT2-fs: panic from previous error\n"); 778c2ecf20Sopenharmony_ci if (!sb_rdonly(sb) && test_opt(sb, ERRORS_RO)) { 788c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_CRIT, 798c2ecf20Sopenharmony_ci "error: remounting filesystem read-only"); 808c2ecf20Sopenharmony_ci sb->s_flags |= SB_RDONLY; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_civoid ext2_msg(struct super_block *sb, const char *prefix, 858c2ecf20Sopenharmony_ci const char *fmt, ...) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct va_format vaf; 888c2ecf20Sopenharmony_ci va_list args; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci va_start(args, fmt); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci vaf.fmt = fmt; 938c2ecf20Sopenharmony_ci vaf.va = &args; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci printk("%sEXT2-fs (%s): %pV\n", prefix, sb->s_id, &vaf); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci va_end(args); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* 1018c2ecf20Sopenharmony_ci * This must be called with sbi->s_lock held. 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_civoid ext2_update_dynamic_rev(struct super_block *sb) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct ext2_super_block *es = EXT2_SB(sb)->s_es; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV) 1088c2ecf20Sopenharmony_ci return; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_WARNING, 1118c2ecf20Sopenharmony_ci "warning: updating to rev %d because of " 1128c2ecf20Sopenharmony_ci "new feature flag, running e2fsck is recommended", 1138c2ecf20Sopenharmony_ci EXT2_DYNAMIC_REV); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci es->s_first_ino = cpu_to_le32(EXT2_GOOD_OLD_FIRST_INO); 1168c2ecf20Sopenharmony_ci es->s_inode_size = cpu_to_le16(EXT2_GOOD_OLD_INODE_SIZE); 1178c2ecf20Sopenharmony_ci es->s_rev_level = cpu_to_le32(EXT2_DYNAMIC_REV); 1188c2ecf20Sopenharmony_ci /* leave es->s_feature_*compat flags alone */ 1198c2ecf20Sopenharmony_ci /* es->s_uuid will be set by e2fsck if empty */ 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* 1228c2ecf20Sopenharmony_ci * The rest of the superblock fields should be zero, and if not it 1238c2ecf20Sopenharmony_ci * means they are likely already in use, so leave them alone. We 1248c2ecf20Sopenharmony_ci * can leave it up to e2fsck to clean up any inconsistencies there. 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 1298c2ecf20Sopenharmony_cistatic int ext2_quota_off(struct super_block *sb, int type); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic void ext2_quota_off_umount(struct super_block *sb) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci int type; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci for (type = 0; type < MAXQUOTAS; type++) 1368c2ecf20Sopenharmony_ci ext2_quota_off(sb, type); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci#else 1398c2ecf20Sopenharmony_cistatic inline void ext2_quota_off_umount(struct super_block *sb) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci#endif 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic void ext2_put_super (struct super_block * sb) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci int db_count; 1478c2ecf20Sopenharmony_ci int i; 1488c2ecf20Sopenharmony_ci struct ext2_sb_info *sbi = EXT2_SB(sb); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci ext2_quota_off_umount(sb); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci ext2_xattr_destroy_cache(sbi->s_ea_block_cache); 1538c2ecf20Sopenharmony_ci sbi->s_ea_block_cache = NULL; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) { 1568c2ecf20Sopenharmony_ci struct ext2_super_block *es = sbi->s_es; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci spin_lock(&sbi->s_lock); 1598c2ecf20Sopenharmony_ci es->s_state = cpu_to_le16(sbi->s_mount_state); 1608c2ecf20Sopenharmony_ci spin_unlock(&sbi->s_lock); 1618c2ecf20Sopenharmony_ci ext2_sync_super(sb, es, 1); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci db_count = sbi->s_gdb_count; 1648c2ecf20Sopenharmony_ci for (i = 0; i < db_count; i++) 1658c2ecf20Sopenharmony_ci brelse(sbi->s_group_desc[i]); 1668c2ecf20Sopenharmony_ci kfree(sbi->s_group_desc); 1678c2ecf20Sopenharmony_ci kfree(sbi->s_debts); 1688c2ecf20Sopenharmony_ci percpu_counter_destroy(&sbi->s_freeblocks_counter); 1698c2ecf20Sopenharmony_ci percpu_counter_destroy(&sbi->s_freeinodes_counter); 1708c2ecf20Sopenharmony_ci percpu_counter_destroy(&sbi->s_dirs_counter); 1718c2ecf20Sopenharmony_ci brelse (sbi->s_sbh); 1728c2ecf20Sopenharmony_ci sb->s_fs_info = NULL; 1738c2ecf20Sopenharmony_ci kfree(sbi->s_blockgroup_lock); 1748c2ecf20Sopenharmony_ci fs_put_dax(sbi->s_daxdev); 1758c2ecf20Sopenharmony_ci kfree(sbi); 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic struct kmem_cache * ext2_inode_cachep; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic struct inode *ext2_alloc_inode(struct super_block *sb) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci struct ext2_inode_info *ei; 1838c2ecf20Sopenharmony_ci ei = kmem_cache_alloc(ext2_inode_cachep, GFP_KERNEL); 1848c2ecf20Sopenharmony_ci if (!ei) 1858c2ecf20Sopenharmony_ci return NULL; 1868c2ecf20Sopenharmony_ci ei->i_block_alloc_info = NULL; 1878c2ecf20Sopenharmony_ci inode_set_iversion(&ei->vfs_inode, 1); 1888c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 1898c2ecf20Sopenharmony_ci memset(&ei->i_dquot, 0, sizeof(ei->i_dquot)); 1908c2ecf20Sopenharmony_ci#endif 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return &ei->vfs_inode; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic void ext2_free_in_core_inode(struct inode *inode) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci kmem_cache_free(ext2_inode_cachep, EXT2_I(inode)); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic void init_once(void *foo) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct ext2_inode_info *ei = (struct ext2_inode_info *) foo; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci rwlock_init(&ei->i_meta_lock); 2058c2ecf20Sopenharmony_ci#ifdef CONFIG_EXT2_FS_XATTR 2068c2ecf20Sopenharmony_ci init_rwsem(&ei->xattr_sem); 2078c2ecf20Sopenharmony_ci#endif 2088c2ecf20Sopenharmony_ci mutex_init(&ei->truncate_mutex); 2098c2ecf20Sopenharmony_ci#ifdef CONFIG_FS_DAX 2108c2ecf20Sopenharmony_ci init_rwsem(&ei->dax_sem); 2118c2ecf20Sopenharmony_ci#endif 2128c2ecf20Sopenharmony_ci inode_init_once(&ei->vfs_inode); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic int __init init_inodecache(void) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci ext2_inode_cachep = kmem_cache_create_usercopy("ext2_inode_cache", 2188c2ecf20Sopenharmony_ci sizeof(struct ext2_inode_info), 0, 2198c2ecf20Sopenharmony_ci (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD| 2208c2ecf20Sopenharmony_ci SLAB_ACCOUNT), 2218c2ecf20Sopenharmony_ci offsetof(struct ext2_inode_info, i_data), 2228c2ecf20Sopenharmony_ci sizeof_field(struct ext2_inode_info, i_data), 2238c2ecf20Sopenharmony_ci init_once); 2248c2ecf20Sopenharmony_ci if (ext2_inode_cachep == NULL) 2258c2ecf20Sopenharmony_ci return -ENOMEM; 2268c2ecf20Sopenharmony_ci return 0; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic void destroy_inodecache(void) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci /* 2328c2ecf20Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 2338c2ecf20Sopenharmony_ci * destroy cache. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci rcu_barrier(); 2368c2ecf20Sopenharmony_ci kmem_cache_destroy(ext2_inode_cachep); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic int ext2_show_options(struct seq_file *seq, struct dentry *root) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct super_block *sb = root->d_sb; 2428c2ecf20Sopenharmony_ci struct ext2_sb_info *sbi = EXT2_SB(sb); 2438c2ecf20Sopenharmony_ci struct ext2_super_block *es = sbi->s_es; 2448c2ecf20Sopenharmony_ci unsigned long def_mount_opts; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci spin_lock(&sbi->s_lock); 2478c2ecf20Sopenharmony_ci def_mount_opts = le32_to_cpu(es->s_default_mount_opts); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (sbi->s_sb_block != 1) 2508c2ecf20Sopenharmony_ci seq_printf(seq, ",sb=%lu", sbi->s_sb_block); 2518c2ecf20Sopenharmony_ci if (test_opt(sb, MINIX_DF)) 2528c2ecf20Sopenharmony_ci seq_puts(seq, ",minixdf"); 2538c2ecf20Sopenharmony_ci if (test_opt(sb, GRPID)) 2548c2ecf20Sopenharmony_ci seq_puts(seq, ",grpid"); 2558c2ecf20Sopenharmony_ci if (!test_opt(sb, GRPID) && (def_mount_opts & EXT2_DEFM_BSDGROUPS)) 2568c2ecf20Sopenharmony_ci seq_puts(seq, ",nogrpid"); 2578c2ecf20Sopenharmony_ci if (!uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT2_DEF_RESUID)) || 2588c2ecf20Sopenharmony_ci le16_to_cpu(es->s_def_resuid) != EXT2_DEF_RESUID) { 2598c2ecf20Sopenharmony_ci seq_printf(seq, ",resuid=%u", 2608c2ecf20Sopenharmony_ci from_kuid_munged(&init_user_ns, sbi->s_resuid)); 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci if (!gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT2_DEF_RESGID)) || 2638c2ecf20Sopenharmony_ci le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) { 2648c2ecf20Sopenharmony_ci seq_printf(seq, ",resgid=%u", 2658c2ecf20Sopenharmony_ci from_kgid_munged(&init_user_ns, sbi->s_resgid)); 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci if (test_opt(sb, ERRORS_RO)) { 2688c2ecf20Sopenharmony_ci int def_errors = le16_to_cpu(es->s_errors); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (def_errors == EXT2_ERRORS_PANIC || 2718c2ecf20Sopenharmony_ci def_errors == EXT2_ERRORS_CONTINUE) { 2728c2ecf20Sopenharmony_ci seq_puts(seq, ",errors=remount-ro"); 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci if (test_opt(sb, ERRORS_CONT)) 2768c2ecf20Sopenharmony_ci seq_puts(seq, ",errors=continue"); 2778c2ecf20Sopenharmony_ci if (test_opt(sb, ERRORS_PANIC)) 2788c2ecf20Sopenharmony_ci seq_puts(seq, ",errors=panic"); 2798c2ecf20Sopenharmony_ci if (test_opt(sb, NO_UID32)) 2808c2ecf20Sopenharmony_ci seq_puts(seq, ",nouid32"); 2818c2ecf20Sopenharmony_ci if (test_opt(sb, DEBUG)) 2828c2ecf20Sopenharmony_ci seq_puts(seq, ",debug"); 2838c2ecf20Sopenharmony_ci if (test_opt(sb, OLDALLOC)) 2848c2ecf20Sopenharmony_ci seq_puts(seq, ",oldalloc"); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci#ifdef CONFIG_EXT2_FS_XATTR 2878c2ecf20Sopenharmony_ci if (test_opt(sb, XATTR_USER)) 2888c2ecf20Sopenharmony_ci seq_puts(seq, ",user_xattr"); 2898c2ecf20Sopenharmony_ci if (!test_opt(sb, XATTR_USER) && 2908c2ecf20Sopenharmony_ci (def_mount_opts & EXT2_DEFM_XATTR_USER)) { 2918c2ecf20Sopenharmony_ci seq_puts(seq, ",nouser_xattr"); 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci#endif 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci#ifdef CONFIG_EXT2_FS_POSIX_ACL 2968c2ecf20Sopenharmony_ci if (test_opt(sb, POSIX_ACL)) 2978c2ecf20Sopenharmony_ci seq_puts(seq, ",acl"); 2988c2ecf20Sopenharmony_ci if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT2_DEFM_ACL)) 2998c2ecf20Sopenharmony_ci seq_puts(seq, ",noacl"); 3008c2ecf20Sopenharmony_ci#endif 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (test_opt(sb, NOBH)) 3038c2ecf20Sopenharmony_ci seq_puts(seq, ",nobh"); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (test_opt(sb, USRQUOTA)) 3068c2ecf20Sopenharmony_ci seq_puts(seq, ",usrquota"); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (test_opt(sb, GRPQUOTA)) 3098c2ecf20Sopenharmony_ci seq_puts(seq, ",grpquota"); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (test_opt(sb, XIP)) 3128c2ecf20Sopenharmony_ci seq_puts(seq, ",xip"); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (test_opt(sb, DAX)) 3158c2ecf20Sopenharmony_ci seq_puts(seq, ",dax"); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (!test_opt(sb, RESERVATION)) 3188c2ecf20Sopenharmony_ci seq_puts(seq, ",noreservation"); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci spin_unlock(&sbi->s_lock); 3218c2ecf20Sopenharmony_ci return 0; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 3258c2ecf20Sopenharmony_cistatic ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, size_t len, loff_t off); 3268c2ecf20Sopenharmony_cistatic ssize_t ext2_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off); 3278c2ecf20Sopenharmony_cistatic int ext2_quota_on(struct super_block *sb, int type, int format_id, 3288c2ecf20Sopenharmony_ci const struct path *path); 3298c2ecf20Sopenharmony_cistatic struct dquot **ext2_get_dquots(struct inode *inode) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci return EXT2_I(inode)->i_dquot; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic const struct quotactl_ops ext2_quotactl_ops = { 3358c2ecf20Sopenharmony_ci .quota_on = ext2_quota_on, 3368c2ecf20Sopenharmony_ci .quota_off = ext2_quota_off, 3378c2ecf20Sopenharmony_ci .quota_sync = dquot_quota_sync, 3388c2ecf20Sopenharmony_ci .get_state = dquot_get_state, 3398c2ecf20Sopenharmony_ci .set_info = dquot_set_dqinfo, 3408c2ecf20Sopenharmony_ci .get_dqblk = dquot_get_dqblk, 3418c2ecf20Sopenharmony_ci .set_dqblk = dquot_set_dqblk, 3428c2ecf20Sopenharmony_ci .get_nextdqblk = dquot_get_next_dqblk, 3438c2ecf20Sopenharmony_ci}; 3448c2ecf20Sopenharmony_ci#endif 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic const struct super_operations ext2_sops = { 3478c2ecf20Sopenharmony_ci .alloc_inode = ext2_alloc_inode, 3488c2ecf20Sopenharmony_ci .free_inode = ext2_free_in_core_inode, 3498c2ecf20Sopenharmony_ci .write_inode = ext2_write_inode, 3508c2ecf20Sopenharmony_ci .evict_inode = ext2_evict_inode, 3518c2ecf20Sopenharmony_ci .put_super = ext2_put_super, 3528c2ecf20Sopenharmony_ci .sync_fs = ext2_sync_fs, 3538c2ecf20Sopenharmony_ci .freeze_fs = ext2_freeze, 3548c2ecf20Sopenharmony_ci .unfreeze_fs = ext2_unfreeze, 3558c2ecf20Sopenharmony_ci .statfs = ext2_statfs, 3568c2ecf20Sopenharmony_ci .remount_fs = ext2_remount, 3578c2ecf20Sopenharmony_ci .show_options = ext2_show_options, 3588c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 3598c2ecf20Sopenharmony_ci .quota_read = ext2_quota_read, 3608c2ecf20Sopenharmony_ci .quota_write = ext2_quota_write, 3618c2ecf20Sopenharmony_ci .get_dquots = ext2_get_dquots, 3628c2ecf20Sopenharmony_ci#endif 3638c2ecf20Sopenharmony_ci}; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic struct inode *ext2_nfs_get_inode(struct super_block *sb, 3668c2ecf20Sopenharmony_ci u64 ino, u32 generation) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct inode *inode; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (ino < EXT2_FIRST_INO(sb) && ino != EXT2_ROOT_INO) 3718c2ecf20Sopenharmony_ci return ERR_PTR(-ESTALE); 3728c2ecf20Sopenharmony_ci if (ino > le32_to_cpu(EXT2_SB(sb)->s_es->s_inodes_count)) 3738c2ecf20Sopenharmony_ci return ERR_PTR(-ESTALE); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* 3768c2ecf20Sopenharmony_ci * ext2_iget isn't quite right if the inode is currently unallocated! 3778c2ecf20Sopenharmony_ci * However ext2_iget currently does appropriate checks to handle stale 3788c2ecf20Sopenharmony_ci * inodes so everything is OK. 3798c2ecf20Sopenharmony_ci */ 3808c2ecf20Sopenharmony_ci inode = ext2_iget(sb, ino); 3818c2ecf20Sopenharmony_ci if (IS_ERR(inode)) 3828c2ecf20Sopenharmony_ci return ERR_CAST(inode); 3838c2ecf20Sopenharmony_ci if (generation && inode->i_generation != generation) { 3848c2ecf20Sopenharmony_ci /* we didn't find the right inode.. */ 3858c2ecf20Sopenharmony_ci iput(inode); 3868c2ecf20Sopenharmony_ci return ERR_PTR(-ESTALE); 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci return inode; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic struct dentry *ext2_fh_to_dentry(struct super_block *sb, struct fid *fid, 3928c2ecf20Sopenharmony_ci int fh_len, int fh_type) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci return generic_fh_to_dentry(sb, fid, fh_len, fh_type, 3958c2ecf20Sopenharmony_ci ext2_nfs_get_inode); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic struct dentry *ext2_fh_to_parent(struct super_block *sb, struct fid *fid, 3998c2ecf20Sopenharmony_ci int fh_len, int fh_type) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci return generic_fh_to_parent(sb, fid, fh_len, fh_type, 4028c2ecf20Sopenharmony_ci ext2_nfs_get_inode); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic const struct export_operations ext2_export_ops = { 4068c2ecf20Sopenharmony_ci .fh_to_dentry = ext2_fh_to_dentry, 4078c2ecf20Sopenharmony_ci .fh_to_parent = ext2_fh_to_parent, 4088c2ecf20Sopenharmony_ci .get_parent = ext2_get_parent, 4098c2ecf20Sopenharmony_ci}; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic unsigned long get_sb_block(void **data) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci unsigned long sb_block; 4148c2ecf20Sopenharmony_ci char *options = (char *) *data; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (!options || strncmp(options, "sb=", 3) != 0) 4178c2ecf20Sopenharmony_ci return 1; /* Default location */ 4188c2ecf20Sopenharmony_ci options += 3; 4198c2ecf20Sopenharmony_ci sb_block = simple_strtoul(options, &options, 0); 4208c2ecf20Sopenharmony_ci if (*options && *options != ',') { 4218c2ecf20Sopenharmony_ci printk("EXT2-fs: Invalid sb specification: %s\n", 4228c2ecf20Sopenharmony_ci (char *) *data); 4238c2ecf20Sopenharmony_ci return 1; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci if (*options == ',') 4268c2ecf20Sopenharmony_ci options++; 4278c2ecf20Sopenharmony_ci *data = (void *) options; 4288c2ecf20Sopenharmony_ci return sb_block; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cienum { 4328c2ecf20Sopenharmony_ci Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, 4338c2ecf20Sopenharmony_ci Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, 4348c2ecf20Sopenharmony_ci Opt_err_ro, Opt_nouid32, Opt_debug, 4358c2ecf20Sopenharmony_ci Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr, 4368c2ecf20Sopenharmony_ci Opt_acl, Opt_noacl, Opt_xip, Opt_dax, Opt_ignore, Opt_err, Opt_quota, 4378c2ecf20Sopenharmony_ci Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation 4388c2ecf20Sopenharmony_ci}; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic const match_table_t tokens = { 4418c2ecf20Sopenharmony_ci {Opt_bsd_df, "bsddf"}, 4428c2ecf20Sopenharmony_ci {Opt_minix_df, "minixdf"}, 4438c2ecf20Sopenharmony_ci {Opt_grpid, "grpid"}, 4448c2ecf20Sopenharmony_ci {Opt_grpid, "bsdgroups"}, 4458c2ecf20Sopenharmony_ci {Opt_nogrpid, "nogrpid"}, 4468c2ecf20Sopenharmony_ci {Opt_nogrpid, "sysvgroups"}, 4478c2ecf20Sopenharmony_ci {Opt_resgid, "resgid=%u"}, 4488c2ecf20Sopenharmony_ci {Opt_resuid, "resuid=%u"}, 4498c2ecf20Sopenharmony_ci {Opt_sb, "sb=%u"}, 4508c2ecf20Sopenharmony_ci {Opt_err_cont, "errors=continue"}, 4518c2ecf20Sopenharmony_ci {Opt_err_panic, "errors=panic"}, 4528c2ecf20Sopenharmony_ci {Opt_err_ro, "errors=remount-ro"}, 4538c2ecf20Sopenharmony_ci {Opt_nouid32, "nouid32"}, 4548c2ecf20Sopenharmony_ci {Opt_debug, "debug"}, 4558c2ecf20Sopenharmony_ci {Opt_oldalloc, "oldalloc"}, 4568c2ecf20Sopenharmony_ci {Opt_orlov, "orlov"}, 4578c2ecf20Sopenharmony_ci {Opt_nobh, "nobh"}, 4588c2ecf20Sopenharmony_ci {Opt_user_xattr, "user_xattr"}, 4598c2ecf20Sopenharmony_ci {Opt_nouser_xattr, "nouser_xattr"}, 4608c2ecf20Sopenharmony_ci {Opt_acl, "acl"}, 4618c2ecf20Sopenharmony_ci {Opt_noacl, "noacl"}, 4628c2ecf20Sopenharmony_ci {Opt_xip, "xip"}, 4638c2ecf20Sopenharmony_ci {Opt_dax, "dax"}, 4648c2ecf20Sopenharmony_ci {Opt_grpquota, "grpquota"}, 4658c2ecf20Sopenharmony_ci {Opt_ignore, "noquota"}, 4668c2ecf20Sopenharmony_ci {Opt_quota, "quota"}, 4678c2ecf20Sopenharmony_ci {Opt_usrquota, "usrquota"}, 4688c2ecf20Sopenharmony_ci {Opt_reservation, "reservation"}, 4698c2ecf20Sopenharmony_ci {Opt_noreservation, "noreservation"}, 4708c2ecf20Sopenharmony_ci {Opt_err, NULL} 4718c2ecf20Sopenharmony_ci}; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic int parse_options(char *options, struct super_block *sb, 4748c2ecf20Sopenharmony_ci struct ext2_mount_options *opts) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci char *p; 4778c2ecf20Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 4788c2ecf20Sopenharmony_ci int option; 4798c2ecf20Sopenharmony_ci kuid_t uid; 4808c2ecf20Sopenharmony_ci kgid_t gid; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (!options) 4838c2ecf20Sopenharmony_ci return 1; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci while ((p = strsep (&options, ",")) != NULL) { 4868c2ecf20Sopenharmony_ci int token; 4878c2ecf20Sopenharmony_ci if (!*p) 4888c2ecf20Sopenharmony_ci continue; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci token = match_token(p, tokens, args); 4918c2ecf20Sopenharmony_ci switch (token) { 4928c2ecf20Sopenharmony_ci case Opt_bsd_df: 4938c2ecf20Sopenharmony_ci clear_opt (opts->s_mount_opt, MINIX_DF); 4948c2ecf20Sopenharmony_ci break; 4958c2ecf20Sopenharmony_ci case Opt_minix_df: 4968c2ecf20Sopenharmony_ci set_opt (opts->s_mount_opt, MINIX_DF); 4978c2ecf20Sopenharmony_ci break; 4988c2ecf20Sopenharmony_ci case Opt_grpid: 4998c2ecf20Sopenharmony_ci set_opt (opts->s_mount_opt, GRPID); 5008c2ecf20Sopenharmony_ci break; 5018c2ecf20Sopenharmony_ci case Opt_nogrpid: 5028c2ecf20Sopenharmony_ci clear_opt (opts->s_mount_opt, GRPID); 5038c2ecf20Sopenharmony_ci break; 5048c2ecf20Sopenharmony_ci case Opt_resuid: 5058c2ecf20Sopenharmony_ci if (match_int(&args[0], &option)) 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci uid = make_kuid(current_user_ns(), option); 5088c2ecf20Sopenharmony_ci if (!uid_valid(uid)) { 5098c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "Invalid uid value %d", option); 5108c2ecf20Sopenharmony_ci return 0; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci opts->s_resuid = uid; 5148c2ecf20Sopenharmony_ci break; 5158c2ecf20Sopenharmony_ci case Opt_resgid: 5168c2ecf20Sopenharmony_ci if (match_int(&args[0], &option)) 5178c2ecf20Sopenharmony_ci return 0; 5188c2ecf20Sopenharmony_ci gid = make_kgid(current_user_ns(), option); 5198c2ecf20Sopenharmony_ci if (!gid_valid(gid)) { 5208c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "Invalid gid value %d", option); 5218c2ecf20Sopenharmony_ci return 0; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci opts->s_resgid = gid; 5248c2ecf20Sopenharmony_ci break; 5258c2ecf20Sopenharmony_ci case Opt_sb: 5268c2ecf20Sopenharmony_ci /* handled by get_sb_block() instead of here */ 5278c2ecf20Sopenharmony_ci /* *sb_block = match_int(&args[0]); */ 5288c2ecf20Sopenharmony_ci break; 5298c2ecf20Sopenharmony_ci case Opt_err_panic: 5308c2ecf20Sopenharmony_ci clear_opt (opts->s_mount_opt, ERRORS_CONT); 5318c2ecf20Sopenharmony_ci clear_opt (opts->s_mount_opt, ERRORS_RO); 5328c2ecf20Sopenharmony_ci set_opt (opts->s_mount_opt, ERRORS_PANIC); 5338c2ecf20Sopenharmony_ci break; 5348c2ecf20Sopenharmony_ci case Opt_err_ro: 5358c2ecf20Sopenharmony_ci clear_opt (opts->s_mount_opt, ERRORS_CONT); 5368c2ecf20Sopenharmony_ci clear_opt (opts->s_mount_opt, ERRORS_PANIC); 5378c2ecf20Sopenharmony_ci set_opt (opts->s_mount_opt, ERRORS_RO); 5388c2ecf20Sopenharmony_ci break; 5398c2ecf20Sopenharmony_ci case Opt_err_cont: 5408c2ecf20Sopenharmony_ci clear_opt (opts->s_mount_opt, ERRORS_RO); 5418c2ecf20Sopenharmony_ci clear_opt (opts->s_mount_opt, ERRORS_PANIC); 5428c2ecf20Sopenharmony_ci set_opt (opts->s_mount_opt, ERRORS_CONT); 5438c2ecf20Sopenharmony_ci break; 5448c2ecf20Sopenharmony_ci case Opt_nouid32: 5458c2ecf20Sopenharmony_ci set_opt (opts->s_mount_opt, NO_UID32); 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci case Opt_debug: 5488c2ecf20Sopenharmony_ci set_opt (opts->s_mount_opt, DEBUG); 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci case Opt_oldalloc: 5518c2ecf20Sopenharmony_ci set_opt (opts->s_mount_opt, OLDALLOC); 5528c2ecf20Sopenharmony_ci break; 5538c2ecf20Sopenharmony_ci case Opt_orlov: 5548c2ecf20Sopenharmony_ci clear_opt (opts->s_mount_opt, OLDALLOC); 5558c2ecf20Sopenharmony_ci break; 5568c2ecf20Sopenharmony_ci case Opt_nobh: 5578c2ecf20Sopenharmony_ci set_opt (opts->s_mount_opt, NOBH); 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci#ifdef CONFIG_EXT2_FS_XATTR 5608c2ecf20Sopenharmony_ci case Opt_user_xattr: 5618c2ecf20Sopenharmony_ci set_opt (opts->s_mount_opt, XATTR_USER); 5628c2ecf20Sopenharmony_ci break; 5638c2ecf20Sopenharmony_ci case Opt_nouser_xattr: 5648c2ecf20Sopenharmony_ci clear_opt (opts->s_mount_opt, XATTR_USER); 5658c2ecf20Sopenharmony_ci break; 5668c2ecf20Sopenharmony_ci#else 5678c2ecf20Sopenharmony_ci case Opt_user_xattr: 5688c2ecf20Sopenharmony_ci case Opt_nouser_xattr: 5698c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_INFO, "(no)user_xattr options" 5708c2ecf20Sopenharmony_ci "not supported"); 5718c2ecf20Sopenharmony_ci break; 5728c2ecf20Sopenharmony_ci#endif 5738c2ecf20Sopenharmony_ci#ifdef CONFIG_EXT2_FS_POSIX_ACL 5748c2ecf20Sopenharmony_ci case Opt_acl: 5758c2ecf20Sopenharmony_ci set_opt(opts->s_mount_opt, POSIX_ACL); 5768c2ecf20Sopenharmony_ci break; 5778c2ecf20Sopenharmony_ci case Opt_noacl: 5788c2ecf20Sopenharmony_ci clear_opt(opts->s_mount_opt, POSIX_ACL); 5798c2ecf20Sopenharmony_ci break; 5808c2ecf20Sopenharmony_ci#else 5818c2ecf20Sopenharmony_ci case Opt_acl: 5828c2ecf20Sopenharmony_ci case Opt_noacl: 5838c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_INFO, 5848c2ecf20Sopenharmony_ci "(no)acl options not supported"); 5858c2ecf20Sopenharmony_ci break; 5868c2ecf20Sopenharmony_ci#endif 5878c2ecf20Sopenharmony_ci case Opt_xip: 5888c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_INFO, "use dax instead of xip"); 5898c2ecf20Sopenharmony_ci set_opt(opts->s_mount_opt, XIP); 5908c2ecf20Sopenharmony_ci fallthrough; 5918c2ecf20Sopenharmony_ci case Opt_dax: 5928c2ecf20Sopenharmony_ci#ifdef CONFIG_FS_DAX 5938c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_WARNING, 5948c2ecf20Sopenharmony_ci "DAX enabled. Warning: EXPERIMENTAL, use at your own risk"); 5958c2ecf20Sopenharmony_ci set_opt(opts->s_mount_opt, DAX); 5968c2ecf20Sopenharmony_ci#else 5978c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_INFO, "dax option not supported"); 5988c2ecf20Sopenharmony_ci#endif 5998c2ecf20Sopenharmony_ci break; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci#if defined(CONFIG_QUOTA) 6028c2ecf20Sopenharmony_ci case Opt_quota: 6038c2ecf20Sopenharmony_ci case Opt_usrquota: 6048c2ecf20Sopenharmony_ci set_opt(opts->s_mount_opt, USRQUOTA); 6058c2ecf20Sopenharmony_ci break; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci case Opt_grpquota: 6088c2ecf20Sopenharmony_ci set_opt(opts->s_mount_opt, GRPQUOTA); 6098c2ecf20Sopenharmony_ci break; 6108c2ecf20Sopenharmony_ci#else 6118c2ecf20Sopenharmony_ci case Opt_quota: 6128c2ecf20Sopenharmony_ci case Opt_usrquota: 6138c2ecf20Sopenharmony_ci case Opt_grpquota: 6148c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_INFO, 6158c2ecf20Sopenharmony_ci "quota operations not supported"); 6168c2ecf20Sopenharmony_ci break; 6178c2ecf20Sopenharmony_ci#endif 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci case Opt_reservation: 6208c2ecf20Sopenharmony_ci set_opt(opts->s_mount_opt, RESERVATION); 6218c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_INFO, "reservations ON"); 6228c2ecf20Sopenharmony_ci break; 6238c2ecf20Sopenharmony_ci case Opt_noreservation: 6248c2ecf20Sopenharmony_ci clear_opt(opts->s_mount_opt, RESERVATION); 6258c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_INFO, "reservations OFF"); 6268c2ecf20Sopenharmony_ci break; 6278c2ecf20Sopenharmony_ci case Opt_ignore: 6288c2ecf20Sopenharmony_ci break; 6298c2ecf20Sopenharmony_ci default: 6308c2ecf20Sopenharmony_ci return 0; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci return 1; 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic int ext2_setup_super (struct super_block * sb, 6378c2ecf20Sopenharmony_ci struct ext2_super_block * es, 6388c2ecf20Sopenharmony_ci int read_only) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci int res = 0; 6418c2ecf20Sopenharmony_ci struct ext2_sb_info *sbi = EXT2_SB(sb); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (le32_to_cpu(es->s_rev_level) > EXT2_MAX_SUPP_REV) { 6448c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, 6458c2ecf20Sopenharmony_ci "error: revision level too high, " 6468c2ecf20Sopenharmony_ci "forcing read-only mode"); 6478c2ecf20Sopenharmony_ci res = SB_RDONLY; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci if (read_only) 6508c2ecf20Sopenharmony_ci return res; 6518c2ecf20Sopenharmony_ci if (!(sbi->s_mount_state & EXT2_VALID_FS)) 6528c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_WARNING, 6538c2ecf20Sopenharmony_ci "warning: mounting unchecked fs, " 6548c2ecf20Sopenharmony_ci "running e2fsck is recommended"); 6558c2ecf20Sopenharmony_ci else if ((sbi->s_mount_state & EXT2_ERROR_FS)) 6568c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_WARNING, 6578c2ecf20Sopenharmony_ci "warning: mounting fs with errors, " 6588c2ecf20Sopenharmony_ci "running e2fsck is recommended"); 6598c2ecf20Sopenharmony_ci else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 && 6608c2ecf20Sopenharmony_ci le16_to_cpu(es->s_mnt_count) >= 6618c2ecf20Sopenharmony_ci (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) 6628c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_WARNING, 6638c2ecf20Sopenharmony_ci "warning: maximal mount count reached, " 6648c2ecf20Sopenharmony_ci "running e2fsck is recommended"); 6658c2ecf20Sopenharmony_ci else if (le32_to_cpu(es->s_checkinterval) && 6668c2ecf20Sopenharmony_ci (le32_to_cpu(es->s_lastcheck) + 6678c2ecf20Sopenharmony_ci le32_to_cpu(es->s_checkinterval) <= 6688c2ecf20Sopenharmony_ci ktime_get_real_seconds())) 6698c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_WARNING, 6708c2ecf20Sopenharmony_ci "warning: checktime reached, " 6718c2ecf20Sopenharmony_ci "running e2fsck is recommended"); 6728c2ecf20Sopenharmony_ci if (!le16_to_cpu(es->s_max_mnt_count)) 6738c2ecf20Sopenharmony_ci es->s_max_mnt_count = cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT); 6748c2ecf20Sopenharmony_ci le16_add_cpu(&es->s_mnt_count, 1); 6758c2ecf20Sopenharmony_ci if (test_opt (sb, DEBUG)) 6768c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_INFO, "%s, %s, bs=%lu, gc=%lu, " 6778c2ecf20Sopenharmony_ci "bpg=%lu, ipg=%lu, mo=%04lx]", 6788c2ecf20Sopenharmony_ci EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize, 6798c2ecf20Sopenharmony_ci sbi->s_groups_count, 6808c2ecf20Sopenharmony_ci EXT2_BLOCKS_PER_GROUP(sb), 6818c2ecf20Sopenharmony_ci EXT2_INODES_PER_GROUP(sb), 6828c2ecf20Sopenharmony_ci sbi->s_mount_opt); 6838c2ecf20Sopenharmony_ci return res; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cistatic int ext2_check_descriptors(struct super_block *sb) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci int i; 6898c2ecf20Sopenharmony_ci struct ext2_sb_info *sbi = EXT2_SB(sb); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci ext2_debug ("Checking group descriptors"); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_groups_count; i++) { 6948c2ecf20Sopenharmony_ci struct ext2_group_desc *gdp = ext2_get_group_desc(sb, i, NULL); 6958c2ecf20Sopenharmony_ci ext2_fsblk_t first_block = ext2_group_first_block_no(sb, i); 6968c2ecf20Sopenharmony_ci ext2_fsblk_t last_block = ext2_group_last_block_no(sb, i); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || 6998c2ecf20Sopenharmony_ci le32_to_cpu(gdp->bg_block_bitmap) > last_block) 7008c2ecf20Sopenharmony_ci { 7018c2ecf20Sopenharmony_ci ext2_error (sb, "ext2_check_descriptors", 7028c2ecf20Sopenharmony_ci "Block bitmap for group %d" 7038c2ecf20Sopenharmony_ci " not in group (block %lu)!", 7048c2ecf20Sopenharmony_ci i, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap)); 7058c2ecf20Sopenharmony_ci return 0; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci if (le32_to_cpu(gdp->bg_inode_bitmap) < first_block || 7088c2ecf20Sopenharmony_ci le32_to_cpu(gdp->bg_inode_bitmap) > last_block) 7098c2ecf20Sopenharmony_ci { 7108c2ecf20Sopenharmony_ci ext2_error (sb, "ext2_check_descriptors", 7118c2ecf20Sopenharmony_ci "Inode bitmap for group %d" 7128c2ecf20Sopenharmony_ci " not in group (block %lu)!", 7138c2ecf20Sopenharmony_ci i, (unsigned long) le32_to_cpu(gdp->bg_inode_bitmap)); 7148c2ecf20Sopenharmony_ci return 0; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci if (le32_to_cpu(gdp->bg_inode_table) < first_block || 7178c2ecf20Sopenharmony_ci le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group - 1 > 7188c2ecf20Sopenharmony_ci last_block) 7198c2ecf20Sopenharmony_ci { 7208c2ecf20Sopenharmony_ci ext2_error (sb, "ext2_check_descriptors", 7218c2ecf20Sopenharmony_ci "Inode table for group %d" 7228c2ecf20Sopenharmony_ci " not in group (block %lu)!", 7238c2ecf20Sopenharmony_ci i, (unsigned long) le32_to_cpu(gdp->bg_inode_table)); 7248c2ecf20Sopenharmony_ci return 0; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci return 1; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci/* 7318c2ecf20Sopenharmony_ci * Maximal file size. There is a direct, and {,double-,triple-}indirect 7328c2ecf20Sopenharmony_ci * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks. 7338c2ecf20Sopenharmony_ci * We need to be 1 filesystem block less than the 2^32 sector limit. 7348c2ecf20Sopenharmony_ci */ 7358c2ecf20Sopenharmony_cistatic loff_t ext2_max_size(int bits) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci loff_t res = EXT2_NDIR_BLOCKS; 7388c2ecf20Sopenharmony_ci int meta_blocks; 7398c2ecf20Sopenharmony_ci unsigned int upper_limit; 7408c2ecf20Sopenharmony_ci unsigned int ppb = 1 << (bits-2); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* This is calculated to be the largest file size for a 7438c2ecf20Sopenharmony_ci * dense, file such that the total number of 7448c2ecf20Sopenharmony_ci * sectors in the file, including data and all indirect blocks, 7458c2ecf20Sopenharmony_ci * does not exceed 2^32 -1 7468c2ecf20Sopenharmony_ci * __u32 i_blocks representing the total number of 7478c2ecf20Sopenharmony_ci * 512 bytes blocks of the file 7488c2ecf20Sopenharmony_ci */ 7498c2ecf20Sopenharmony_ci upper_limit = (1LL << 32) - 1; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* total blocks in file system block size */ 7528c2ecf20Sopenharmony_ci upper_limit >>= (bits - 9); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* Compute how many blocks we can address by block tree */ 7558c2ecf20Sopenharmony_ci res += 1LL << (bits-2); 7568c2ecf20Sopenharmony_ci res += 1LL << (2*(bits-2)); 7578c2ecf20Sopenharmony_ci res += 1LL << (3*(bits-2)); 7588c2ecf20Sopenharmony_ci /* Compute how many metadata blocks are needed */ 7598c2ecf20Sopenharmony_ci meta_blocks = 1; 7608c2ecf20Sopenharmony_ci meta_blocks += 1 + ppb; 7618c2ecf20Sopenharmony_ci meta_blocks += 1 + ppb + ppb * ppb; 7628c2ecf20Sopenharmony_ci /* Does block tree limit file size? */ 7638c2ecf20Sopenharmony_ci if (res + meta_blocks <= upper_limit) 7648c2ecf20Sopenharmony_ci goto check_lfs; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci res = upper_limit; 7678c2ecf20Sopenharmony_ci /* How many metadata blocks are needed for addressing upper_limit? */ 7688c2ecf20Sopenharmony_ci upper_limit -= EXT2_NDIR_BLOCKS; 7698c2ecf20Sopenharmony_ci /* indirect blocks */ 7708c2ecf20Sopenharmony_ci meta_blocks = 1; 7718c2ecf20Sopenharmony_ci upper_limit -= ppb; 7728c2ecf20Sopenharmony_ci /* double indirect blocks */ 7738c2ecf20Sopenharmony_ci if (upper_limit < ppb * ppb) { 7748c2ecf20Sopenharmony_ci meta_blocks += 1 + DIV_ROUND_UP(upper_limit, ppb); 7758c2ecf20Sopenharmony_ci res -= meta_blocks; 7768c2ecf20Sopenharmony_ci goto check_lfs; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci meta_blocks += 1 + ppb; 7798c2ecf20Sopenharmony_ci upper_limit -= ppb * ppb; 7808c2ecf20Sopenharmony_ci /* tripple indirect blocks for the rest */ 7818c2ecf20Sopenharmony_ci meta_blocks += 1 + DIV_ROUND_UP(upper_limit, ppb) + 7828c2ecf20Sopenharmony_ci DIV_ROUND_UP(upper_limit, ppb*ppb); 7838c2ecf20Sopenharmony_ci res -= meta_blocks; 7848c2ecf20Sopenharmony_cicheck_lfs: 7858c2ecf20Sopenharmony_ci res <<= bits; 7868c2ecf20Sopenharmony_ci if (res > MAX_LFS_FILESIZE) 7878c2ecf20Sopenharmony_ci res = MAX_LFS_FILESIZE; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci return res; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_cistatic unsigned long descriptor_loc(struct super_block *sb, 7938c2ecf20Sopenharmony_ci unsigned long logic_sb_block, 7948c2ecf20Sopenharmony_ci int nr) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct ext2_sb_info *sbi = EXT2_SB(sb); 7978c2ecf20Sopenharmony_ci unsigned long bg, first_meta_bg; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (!EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_META_BG) || 8028c2ecf20Sopenharmony_ci nr < first_meta_bg) 8038c2ecf20Sopenharmony_ci return (logic_sb_block + nr + 1); 8048c2ecf20Sopenharmony_ci bg = sbi->s_desc_per_block * nr; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci return ext2_group_first_block_no(sb, bg) + ext2_bg_has_super(sb, bg); 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_cistatic int ext2_fill_super(struct super_block *sb, void *data, int silent) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci struct dax_device *dax_dev = fs_dax_get_by_bdev(sb->s_bdev); 8128c2ecf20Sopenharmony_ci struct buffer_head * bh; 8138c2ecf20Sopenharmony_ci struct ext2_sb_info * sbi; 8148c2ecf20Sopenharmony_ci struct ext2_super_block * es; 8158c2ecf20Sopenharmony_ci struct inode *root; 8168c2ecf20Sopenharmony_ci unsigned long block; 8178c2ecf20Sopenharmony_ci unsigned long sb_block = get_sb_block(&data); 8188c2ecf20Sopenharmony_ci unsigned long logic_sb_block; 8198c2ecf20Sopenharmony_ci unsigned long offset = 0; 8208c2ecf20Sopenharmony_ci unsigned long def_mount_opts; 8218c2ecf20Sopenharmony_ci long ret = -ENOMEM; 8228c2ecf20Sopenharmony_ci int blocksize = BLOCK_SIZE; 8238c2ecf20Sopenharmony_ci int db_count; 8248c2ecf20Sopenharmony_ci int i, j; 8258c2ecf20Sopenharmony_ci __le32 features; 8268c2ecf20Sopenharmony_ci int err; 8278c2ecf20Sopenharmony_ci struct ext2_mount_options opts; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); 8308c2ecf20Sopenharmony_ci if (!sbi) 8318c2ecf20Sopenharmony_ci goto failed; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci sbi->s_blockgroup_lock = 8348c2ecf20Sopenharmony_ci kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL); 8358c2ecf20Sopenharmony_ci if (!sbi->s_blockgroup_lock) { 8368c2ecf20Sopenharmony_ci kfree(sbi); 8378c2ecf20Sopenharmony_ci goto failed; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci sb->s_fs_info = sbi; 8408c2ecf20Sopenharmony_ci sbi->s_sb_block = sb_block; 8418c2ecf20Sopenharmony_ci sbi->s_daxdev = dax_dev; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci spin_lock_init(&sbi->s_lock); 8448c2ecf20Sopenharmony_ci ret = -EINVAL; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci /* 8478c2ecf20Sopenharmony_ci * See what the current blocksize for the device is, and 8488c2ecf20Sopenharmony_ci * use that as the blocksize. Otherwise (or if the blocksize 8498c2ecf20Sopenharmony_ci * is smaller than the default) use the default. 8508c2ecf20Sopenharmony_ci * This is important for devices that have a hardware 8518c2ecf20Sopenharmony_ci * sectorsize that is larger than the default. 8528c2ecf20Sopenharmony_ci */ 8538c2ecf20Sopenharmony_ci blocksize = sb_min_blocksize(sb, BLOCK_SIZE); 8548c2ecf20Sopenharmony_ci if (!blocksize) { 8558c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "error: unable to set blocksize"); 8568c2ecf20Sopenharmony_ci goto failed_sbi; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci /* 8608c2ecf20Sopenharmony_ci * If the superblock doesn't start on a hardware sector boundary, 8618c2ecf20Sopenharmony_ci * calculate the offset. 8628c2ecf20Sopenharmony_ci */ 8638c2ecf20Sopenharmony_ci if (blocksize != BLOCK_SIZE) { 8648c2ecf20Sopenharmony_ci logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize; 8658c2ecf20Sopenharmony_ci offset = (sb_block*BLOCK_SIZE) % blocksize; 8668c2ecf20Sopenharmony_ci } else { 8678c2ecf20Sopenharmony_ci logic_sb_block = sb_block; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci if (!(bh = sb_bread(sb, logic_sb_block))) { 8718c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "error: unable to read superblock"); 8728c2ecf20Sopenharmony_ci goto failed_sbi; 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci /* 8758c2ecf20Sopenharmony_ci * Note: s_es must be initialized as soon as possible because 8768c2ecf20Sopenharmony_ci * some ext2 macro-instructions depend on its value 8778c2ecf20Sopenharmony_ci */ 8788c2ecf20Sopenharmony_ci es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); 8798c2ecf20Sopenharmony_ci sbi->s_es = es; 8808c2ecf20Sopenharmony_ci sb->s_magic = le16_to_cpu(es->s_magic); 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (sb->s_magic != EXT2_SUPER_MAGIC) 8838c2ecf20Sopenharmony_ci goto cantfind_ext2; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci opts.s_mount_opt = 0; 8868c2ecf20Sopenharmony_ci /* Set defaults before we parse the mount options */ 8878c2ecf20Sopenharmony_ci def_mount_opts = le32_to_cpu(es->s_default_mount_opts); 8888c2ecf20Sopenharmony_ci if (def_mount_opts & EXT2_DEFM_DEBUG) 8898c2ecf20Sopenharmony_ci set_opt(opts.s_mount_opt, DEBUG); 8908c2ecf20Sopenharmony_ci if (def_mount_opts & EXT2_DEFM_BSDGROUPS) 8918c2ecf20Sopenharmony_ci set_opt(opts.s_mount_opt, GRPID); 8928c2ecf20Sopenharmony_ci if (def_mount_opts & EXT2_DEFM_UID16) 8938c2ecf20Sopenharmony_ci set_opt(opts.s_mount_opt, NO_UID32); 8948c2ecf20Sopenharmony_ci#ifdef CONFIG_EXT2_FS_XATTR 8958c2ecf20Sopenharmony_ci if (def_mount_opts & EXT2_DEFM_XATTR_USER) 8968c2ecf20Sopenharmony_ci set_opt(opts.s_mount_opt, XATTR_USER); 8978c2ecf20Sopenharmony_ci#endif 8988c2ecf20Sopenharmony_ci#ifdef CONFIG_EXT2_FS_POSIX_ACL 8998c2ecf20Sopenharmony_ci if (def_mount_opts & EXT2_DEFM_ACL) 9008c2ecf20Sopenharmony_ci set_opt(opts.s_mount_opt, POSIX_ACL); 9018c2ecf20Sopenharmony_ci#endif 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC) 9048c2ecf20Sopenharmony_ci set_opt(opts.s_mount_opt, ERRORS_PANIC); 9058c2ecf20Sopenharmony_ci else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_CONTINUE) 9068c2ecf20Sopenharmony_ci set_opt(opts.s_mount_opt, ERRORS_CONT); 9078c2ecf20Sopenharmony_ci else 9088c2ecf20Sopenharmony_ci set_opt(opts.s_mount_opt, ERRORS_RO); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci opts.s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid)); 9118c2ecf20Sopenharmony_ci opts.s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid)); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci set_opt(opts.s_mount_opt, RESERVATION); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (!parse_options((char *) data, sb, &opts)) 9168c2ecf20Sopenharmony_ci goto failed_mount; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci sbi->s_mount_opt = opts.s_mount_opt; 9198c2ecf20Sopenharmony_ci sbi->s_resuid = opts.s_resuid; 9208c2ecf20Sopenharmony_ci sbi->s_resgid = opts.s_resgid; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | 9238c2ecf20Sopenharmony_ci (test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0); 9248c2ecf20Sopenharmony_ci sb->s_iflags |= SB_I_CGROUPWB; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV && 9278c2ecf20Sopenharmony_ci (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) || 9288c2ecf20Sopenharmony_ci EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) || 9298c2ecf20Sopenharmony_ci EXT2_HAS_INCOMPAT_FEATURE(sb, ~0U))) 9308c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_WARNING, 9318c2ecf20Sopenharmony_ci "warning: feature flags set on rev 0 fs, " 9328c2ecf20Sopenharmony_ci "running e2fsck is recommended"); 9338c2ecf20Sopenharmony_ci /* 9348c2ecf20Sopenharmony_ci * Check feature flags regardless of the revision level, since we 9358c2ecf20Sopenharmony_ci * previously didn't change the revision level when setting the flags, 9368c2ecf20Sopenharmony_ci * so there is a chance incompat flags are set on a rev 0 filesystem. 9378c2ecf20Sopenharmony_ci */ 9388c2ecf20Sopenharmony_ci features = EXT2_HAS_INCOMPAT_FEATURE(sb, ~EXT2_FEATURE_INCOMPAT_SUPP); 9398c2ecf20Sopenharmony_ci if (features) { 9408c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "error: couldn't mount because of " 9418c2ecf20Sopenharmony_ci "unsupported optional features (%x)", 9428c2ecf20Sopenharmony_ci le32_to_cpu(features)); 9438c2ecf20Sopenharmony_ci goto failed_mount; 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci if (!sb_rdonly(sb) && (features = EXT2_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP))){ 9468c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "error: couldn't mount RDWR because of " 9478c2ecf20Sopenharmony_ci "unsupported optional features (%x)", 9488c2ecf20Sopenharmony_ci le32_to_cpu(features)); 9498c2ecf20Sopenharmony_ci goto failed_mount; 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci if (le32_to_cpu(es->s_log_block_size) > 9538c2ecf20Sopenharmony_ci (EXT2_MAX_BLOCK_LOG_SIZE - BLOCK_SIZE_BITS)) { 9548c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, 9558c2ecf20Sopenharmony_ci "Invalid log block size: %u", 9568c2ecf20Sopenharmony_ci le32_to_cpu(es->s_log_block_size)); 9578c2ecf20Sopenharmony_ci goto failed_mount; 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (test_opt(sb, DAX)) { 9628c2ecf20Sopenharmony_ci if (!bdev_dax_supported(sb->s_bdev, blocksize)) { 9638c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, 9648c2ecf20Sopenharmony_ci "DAX unsupported by block device. Turning off DAX."); 9658c2ecf20Sopenharmony_ci clear_opt(sbi->s_mount_opt, DAX); 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci /* If the blocksize doesn't match, re-read the thing.. */ 9708c2ecf20Sopenharmony_ci if (sb->s_blocksize != blocksize) { 9718c2ecf20Sopenharmony_ci brelse(bh); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (!sb_set_blocksize(sb, blocksize)) { 9748c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, 9758c2ecf20Sopenharmony_ci "error: bad blocksize %d", blocksize); 9768c2ecf20Sopenharmony_ci goto failed_sbi; 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize; 9808c2ecf20Sopenharmony_ci offset = (sb_block*BLOCK_SIZE) % blocksize; 9818c2ecf20Sopenharmony_ci bh = sb_bread(sb, logic_sb_block); 9828c2ecf20Sopenharmony_ci if(!bh) { 9838c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "error: couldn't read" 9848c2ecf20Sopenharmony_ci "superblock on 2nd try"); 9858c2ecf20Sopenharmony_ci goto failed_sbi; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); 9888c2ecf20Sopenharmony_ci sbi->s_es = es; 9898c2ecf20Sopenharmony_ci if (es->s_magic != cpu_to_le16(EXT2_SUPER_MAGIC)) { 9908c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "error: magic mismatch"); 9918c2ecf20Sopenharmony_ci goto failed_mount; 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits); 9968c2ecf20Sopenharmony_ci sb->s_max_links = EXT2_LINK_MAX; 9978c2ecf20Sopenharmony_ci sb->s_time_min = S32_MIN; 9988c2ecf20Sopenharmony_ci sb->s_time_max = S32_MAX; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) { 10018c2ecf20Sopenharmony_ci sbi->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; 10028c2ecf20Sopenharmony_ci sbi->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; 10038c2ecf20Sopenharmony_ci } else { 10048c2ecf20Sopenharmony_ci sbi->s_inode_size = le16_to_cpu(es->s_inode_size); 10058c2ecf20Sopenharmony_ci sbi->s_first_ino = le32_to_cpu(es->s_first_ino); 10068c2ecf20Sopenharmony_ci if ((sbi->s_inode_size < EXT2_GOOD_OLD_INODE_SIZE) || 10078c2ecf20Sopenharmony_ci !is_power_of_2(sbi->s_inode_size) || 10088c2ecf20Sopenharmony_ci (sbi->s_inode_size > blocksize)) { 10098c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, 10108c2ecf20Sopenharmony_ci "error: unsupported inode size: %d", 10118c2ecf20Sopenharmony_ci sbi->s_inode_size); 10128c2ecf20Sopenharmony_ci goto failed_mount; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group); 10178c2ecf20Sopenharmony_ci sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci sbi->s_inodes_per_block = sb->s_blocksize / EXT2_INODE_SIZE(sb); 10208c2ecf20Sopenharmony_ci if (sbi->s_inodes_per_block == 0 || sbi->s_inodes_per_group == 0) 10218c2ecf20Sopenharmony_ci goto cantfind_ext2; 10228c2ecf20Sopenharmony_ci sbi->s_itb_per_group = sbi->s_inodes_per_group / 10238c2ecf20Sopenharmony_ci sbi->s_inodes_per_block; 10248c2ecf20Sopenharmony_ci sbi->s_desc_per_block = sb->s_blocksize / 10258c2ecf20Sopenharmony_ci sizeof (struct ext2_group_desc); 10268c2ecf20Sopenharmony_ci sbi->s_sbh = bh; 10278c2ecf20Sopenharmony_ci sbi->s_mount_state = le16_to_cpu(es->s_state); 10288c2ecf20Sopenharmony_ci sbi->s_addr_per_block_bits = 10298c2ecf20Sopenharmony_ci ilog2 (EXT2_ADDR_PER_BLOCK(sb)); 10308c2ecf20Sopenharmony_ci sbi->s_desc_per_block_bits = 10318c2ecf20Sopenharmony_ci ilog2 (EXT2_DESC_PER_BLOCK(sb)); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci if (sb->s_magic != EXT2_SUPER_MAGIC) 10348c2ecf20Sopenharmony_ci goto cantfind_ext2; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci if (sb->s_blocksize != bh->b_size) { 10378c2ecf20Sopenharmony_ci if (!silent) 10388c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "error: unsupported blocksize"); 10398c2ecf20Sopenharmony_ci goto failed_mount; 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci if (es->s_log_frag_size != es->s_log_block_size) { 10438c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, 10448c2ecf20Sopenharmony_ci "error: fragsize log %u != blocksize log %u", 10458c2ecf20Sopenharmony_ci le32_to_cpu(es->s_log_frag_size), sb->s_blocksize_bits); 10468c2ecf20Sopenharmony_ci goto failed_mount; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if (sbi->s_blocks_per_group > sb->s_blocksize * 8) { 10508c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, 10518c2ecf20Sopenharmony_ci "error: #blocks per group too big: %lu", 10528c2ecf20Sopenharmony_ci sbi->s_blocks_per_group); 10538c2ecf20Sopenharmony_ci goto failed_mount; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci if (sbi->s_inodes_per_group < sbi->s_inodes_per_block || 10568c2ecf20Sopenharmony_ci sbi->s_inodes_per_group > sb->s_blocksize * 8) { 10578c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, 10588c2ecf20Sopenharmony_ci "error: invalid #inodes per group: %lu", 10598c2ecf20Sopenharmony_ci sbi->s_inodes_per_group); 10608c2ecf20Sopenharmony_ci goto failed_mount; 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (EXT2_BLOCKS_PER_GROUP(sb) == 0) 10648c2ecf20Sopenharmony_ci goto cantfind_ext2; 10658c2ecf20Sopenharmony_ci sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) - 10668c2ecf20Sopenharmony_ci le32_to_cpu(es->s_first_data_block) - 1) 10678c2ecf20Sopenharmony_ci / EXT2_BLOCKS_PER_GROUP(sb)) + 1; 10688c2ecf20Sopenharmony_ci if ((u64)sbi->s_groups_count * sbi->s_inodes_per_group != 10698c2ecf20Sopenharmony_ci le32_to_cpu(es->s_inodes_count)) { 10708c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "error: invalid #inodes: %u vs computed %llu", 10718c2ecf20Sopenharmony_ci le32_to_cpu(es->s_inodes_count), 10728c2ecf20Sopenharmony_ci (u64)sbi->s_groups_count * sbi->s_inodes_per_group); 10738c2ecf20Sopenharmony_ci goto failed_mount; 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci db_count = (sbi->s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) / 10768c2ecf20Sopenharmony_ci EXT2_DESC_PER_BLOCK(sb); 10778c2ecf20Sopenharmony_ci sbi->s_group_desc = kmalloc_array (db_count, 10788c2ecf20Sopenharmony_ci sizeof(struct buffer_head *), 10798c2ecf20Sopenharmony_ci GFP_KERNEL); 10808c2ecf20Sopenharmony_ci if (sbi->s_group_desc == NULL) { 10818c2ecf20Sopenharmony_ci ret = -ENOMEM; 10828c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "error: not enough memory"); 10838c2ecf20Sopenharmony_ci goto failed_mount; 10848c2ecf20Sopenharmony_ci } 10858c2ecf20Sopenharmony_ci bgl_lock_init(sbi->s_blockgroup_lock); 10868c2ecf20Sopenharmony_ci sbi->s_debts = kcalloc(sbi->s_groups_count, sizeof(*sbi->s_debts), GFP_KERNEL); 10878c2ecf20Sopenharmony_ci if (!sbi->s_debts) { 10888c2ecf20Sopenharmony_ci ret = -ENOMEM; 10898c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "error: not enough memory"); 10908c2ecf20Sopenharmony_ci goto failed_mount_group_desc; 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci for (i = 0; i < db_count; i++) { 10938c2ecf20Sopenharmony_ci block = descriptor_loc(sb, logic_sb_block, i); 10948c2ecf20Sopenharmony_ci sbi->s_group_desc[i] = sb_bread(sb, block); 10958c2ecf20Sopenharmony_ci if (!sbi->s_group_desc[i]) { 10968c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) 10978c2ecf20Sopenharmony_ci brelse (sbi->s_group_desc[j]); 10988c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, 10998c2ecf20Sopenharmony_ci "error: unable to read group descriptors"); 11008c2ecf20Sopenharmony_ci goto failed_mount_group_desc; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci if (!ext2_check_descriptors (sb)) { 11048c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "group descriptors corrupted"); 11058c2ecf20Sopenharmony_ci goto failed_mount2; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci sbi->s_gdb_count = db_count; 11088c2ecf20Sopenharmony_ci get_random_bytes(&sbi->s_next_generation, sizeof(u32)); 11098c2ecf20Sopenharmony_ci spin_lock_init(&sbi->s_next_gen_lock); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci /* per fileystem reservation list head & lock */ 11128c2ecf20Sopenharmony_ci spin_lock_init(&sbi->s_rsv_window_lock); 11138c2ecf20Sopenharmony_ci sbi->s_rsv_window_root = RB_ROOT; 11148c2ecf20Sopenharmony_ci /* 11158c2ecf20Sopenharmony_ci * Add a single, static dummy reservation to the start of the 11168c2ecf20Sopenharmony_ci * reservation window list --- it gives us a placeholder for 11178c2ecf20Sopenharmony_ci * append-at-start-of-list which makes the allocation logic 11188c2ecf20Sopenharmony_ci * _much_ simpler. 11198c2ecf20Sopenharmony_ci */ 11208c2ecf20Sopenharmony_ci sbi->s_rsv_window_head.rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; 11218c2ecf20Sopenharmony_ci sbi->s_rsv_window_head.rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; 11228c2ecf20Sopenharmony_ci sbi->s_rsv_window_head.rsv_alloc_hit = 0; 11238c2ecf20Sopenharmony_ci sbi->s_rsv_window_head.rsv_goal_size = 0; 11248c2ecf20Sopenharmony_ci ext2_rsv_window_add(sb, &sbi->s_rsv_window_head); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci err = percpu_counter_init(&sbi->s_freeblocks_counter, 11278c2ecf20Sopenharmony_ci ext2_count_free_blocks(sb), GFP_KERNEL); 11288c2ecf20Sopenharmony_ci if (!err) { 11298c2ecf20Sopenharmony_ci err = percpu_counter_init(&sbi->s_freeinodes_counter, 11308c2ecf20Sopenharmony_ci ext2_count_free_inodes(sb), GFP_KERNEL); 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci if (!err) { 11338c2ecf20Sopenharmony_ci err = percpu_counter_init(&sbi->s_dirs_counter, 11348c2ecf20Sopenharmony_ci ext2_count_dirs(sb), GFP_KERNEL); 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci if (err) { 11378c2ecf20Sopenharmony_ci ret = err; 11388c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "error: insufficient memory"); 11398c2ecf20Sopenharmony_ci goto failed_mount3; 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci#ifdef CONFIG_EXT2_FS_XATTR 11438c2ecf20Sopenharmony_ci sbi->s_ea_block_cache = ext2_xattr_create_cache(); 11448c2ecf20Sopenharmony_ci if (!sbi->s_ea_block_cache) { 11458c2ecf20Sopenharmony_ci ret = -ENOMEM; 11468c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "Failed to create ea_block_cache"); 11478c2ecf20Sopenharmony_ci goto failed_mount3; 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci#endif 11508c2ecf20Sopenharmony_ci /* 11518c2ecf20Sopenharmony_ci * set up enough so that it can read an inode 11528c2ecf20Sopenharmony_ci */ 11538c2ecf20Sopenharmony_ci sb->s_op = &ext2_sops; 11548c2ecf20Sopenharmony_ci sb->s_export_op = &ext2_export_ops; 11558c2ecf20Sopenharmony_ci sb->s_xattr = ext2_xattr_handlers; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 11588c2ecf20Sopenharmony_ci sb->dq_op = &dquot_operations; 11598c2ecf20Sopenharmony_ci sb->s_qcop = &ext2_quotactl_ops; 11608c2ecf20Sopenharmony_ci sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP; 11618c2ecf20Sopenharmony_ci#endif 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci root = ext2_iget(sb, EXT2_ROOT_INO); 11648c2ecf20Sopenharmony_ci if (IS_ERR(root)) { 11658c2ecf20Sopenharmony_ci ret = PTR_ERR(root); 11668c2ecf20Sopenharmony_ci goto failed_mount3; 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { 11698c2ecf20Sopenharmony_ci iput(root); 11708c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "error: corrupt root inode, run e2fsck"); 11718c2ecf20Sopenharmony_ci goto failed_mount3; 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci sb->s_root = d_make_root(root); 11758c2ecf20Sopenharmony_ci if (!sb->s_root) { 11768c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, "error: get root inode failed"); 11778c2ecf20Sopenharmony_ci ret = -ENOMEM; 11788c2ecf20Sopenharmony_ci goto failed_mount3; 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) 11818c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_WARNING, 11828c2ecf20Sopenharmony_ci "warning: mounting ext3 filesystem as ext2"); 11838c2ecf20Sopenharmony_ci if (ext2_setup_super (sb, es, sb_rdonly(sb))) 11848c2ecf20Sopenharmony_ci sb->s_flags |= SB_RDONLY; 11858c2ecf20Sopenharmony_ci ext2_write_super(sb); 11868c2ecf20Sopenharmony_ci return 0; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_cicantfind_ext2: 11898c2ecf20Sopenharmony_ci if (!silent) 11908c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, 11918c2ecf20Sopenharmony_ci "error: can't find an ext2 filesystem on dev %s.", 11928c2ecf20Sopenharmony_ci sb->s_id); 11938c2ecf20Sopenharmony_ci goto failed_mount; 11948c2ecf20Sopenharmony_cifailed_mount3: 11958c2ecf20Sopenharmony_ci ext2_xattr_destroy_cache(sbi->s_ea_block_cache); 11968c2ecf20Sopenharmony_ci percpu_counter_destroy(&sbi->s_freeblocks_counter); 11978c2ecf20Sopenharmony_ci percpu_counter_destroy(&sbi->s_freeinodes_counter); 11988c2ecf20Sopenharmony_ci percpu_counter_destroy(&sbi->s_dirs_counter); 11998c2ecf20Sopenharmony_cifailed_mount2: 12008c2ecf20Sopenharmony_ci for (i = 0; i < db_count; i++) 12018c2ecf20Sopenharmony_ci brelse(sbi->s_group_desc[i]); 12028c2ecf20Sopenharmony_cifailed_mount_group_desc: 12038c2ecf20Sopenharmony_ci kfree(sbi->s_group_desc); 12048c2ecf20Sopenharmony_ci kfree(sbi->s_debts); 12058c2ecf20Sopenharmony_cifailed_mount: 12068c2ecf20Sopenharmony_ci brelse(bh); 12078c2ecf20Sopenharmony_cifailed_sbi: 12088c2ecf20Sopenharmony_ci sb->s_fs_info = NULL; 12098c2ecf20Sopenharmony_ci kfree(sbi->s_blockgroup_lock); 12108c2ecf20Sopenharmony_ci kfree(sbi); 12118c2ecf20Sopenharmony_cifailed: 12128c2ecf20Sopenharmony_ci fs_put_dax(dax_dev); 12138c2ecf20Sopenharmony_ci return ret; 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic void ext2_clear_super_error(struct super_block *sb) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci struct buffer_head *sbh = EXT2_SB(sb)->s_sbh; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci if (buffer_write_io_error(sbh)) { 12218c2ecf20Sopenharmony_ci /* 12228c2ecf20Sopenharmony_ci * Oh, dear. A previous attempt to write the 12238c2ecf20Sopenharmony_ci * superblock failed. This could happen because the 12248c2ecf20Sopenharmony_ci * USB device was yanked out. Or it could happen to 12258c2ecf20Sopenharmony_ci * be a transient write error and maybe the block will 12268c2ecf20Sopenharmony_ci * be remapped. Nothing we can do but to retry the 12278c2ecf20Sopenharmony_ci * write and hope for the best. 12288c2ecf20Sopenharmony_ci */ 12298c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_ERR, 12308c2ecf20Sopenharmony_ci "previous I/O error to superblock detected"); 12318c2ecf20Sopenharmony_ci clear_buffer_write_io_error(sbh); 12328c2ecf20Sopenharmony_ci set_buffer_uptodate(sbh); 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_civoid ext2_sync_super(struct super_block *sb, struct ext2_super_block *es, 12378c2ecf20Sopenharmony_ci int wait) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci ext2_clear_super_error(sb); 12408c2ecf20Sopenharmony_ci spin_lock(&EXT2_SB(sb)->s_lock); 12418c2ecf20Sopenharmony_ci es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb)); 12428c2ecf20Sopenharmony_ci es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb)); 12438c2ecf20Sopenharmony_ci es->s_wtime = cpu_to_le32(ktime_get_real_seconds()); 12448c2ecf20Sopenharmony_ci /* unlock before we do IO */ 12458c2ecf20Sopenharmony_ci spin_unlock(&EXT2_SB(sb)->s_lock); 12468c2ecf20Sopenharmony_ci mark_buffer_dirty(EXT2_SB(sb)->s_sbh); 12478c2ecf20Sopenharmony_ci if (wait) 12488c2ecf20Sopenharmony_ci sync_dirty_buffer(EXT2_SB(sb)->s_sbh); 12498c2ecf20Sopenharmony_ci} 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci/* 12528c2ecf20Sopenharmony_ci * In the second extended file system, it is not necessary to 12538c2ecf20Sopenharmony_ci * write the super block since we use a mapping of the 12548c2ecf20Sopenharmony_ci * disk super block in a buffer. 12558c2ecf20Sopenharmony_ci * 12568c2ecf20Sopenharmony_ci * However, this function is still used to set the fs valid 12578c2ecf20Sopenharmony_ci * flags to 0. We need to set this flag to 0 since the fs 12588c2ecf20Sopenharmony_ci * may have been checked while mounted and e2fsck may have 12598c2ecf20Sopenharmony_ci * set s_state to EXT2_VALID_FS after some corrections. 12608c2ecf20Sopenharmony_ci */ 12618c2ecf20Sopenharmony_cistatic int ext2_sync_fs(struct super_block *sb, int wait) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci struct ext2_sb_info *sbi = EXT2_SB(sb); 12648c2ecf20Sopenharmony_ci struct ext2_super_block *es = EXT2_SB(sb)->s_es; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci /* 12678c2ecf20Sopenharmony_ci * Write quota structures to quota file, sync_blockdev() will write 12688c2ecf20Sopenharmony_ci * them to disk later 12698c2ecf20Sopenharmony_ci */ 12708c2ecf20Sopenharmony_ci dquot_writeback_dquots(sb, -1); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci spin_lock(&sbi->s_lock); 12738c2ecf20Sopenharmony_ci if (es->s_state & cpu_to_le16(EXT2_VALID_FS)) { 12748c2ecf20Sopenharmony_ci ext2_debug("setting valid to 0\n"); 12758c2ecf20Sopenharmony_ci es->s_state &= cpu_to_le16(~EXT2_VALID_FS); 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci spin_unlock(&sbi->s_lock); 12788c2ecf20Sopenharmony_ci ext2_sync_super(sb, es, wait); 12798c2ecf20Sopenharmony_ci return 0; 12808c2ecf20Sopenharmony_ci} 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_cistatic int ext2_freeze(struct super_block *sb) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci struct ext2_sb_info *sbi = EXT2_SB(sb); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci /* 12878c2ecf20Sopenharmony_ci * Open but unlinked files present? Keep EXT2_VALID_FS flag cleared 12888c2ecf20Sopenharmony_ci * because we have unattached inodes and thus filesystem is not fully 12898c2ecf20Sopenharmony_ci * consistent. 12908c2ecf20Sopenharmony_ci */ 12918c2ecf20Sopenharmony_ci if (atomic_long_read(&sb->s_remove_count)) { 12928c2ecf20Sopenharmony_ci ext2_sync_fs(sb, 1); 12938c2ecf20Sopenharmony_ci return 0; 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci /* Set EXT2_FS_VALID flag */ 12968c2ecf20Sopenharmony_ci spin_lock(&sbi->s_lock); 12978c2ecf20Sopenharmony_ci sbi->s_es->s_state = cpu_to_le16(sbi->s_mount_state); 12988c2ecf20Sopenharmony_ci spin_unlock(&sbi->s_lock); 12998c2ecf20Sopenharmony_ci ext2_sync_super(sb, sbi->s_es, 1); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci return 0; 13028c2ecf20Sopenharmony_ci} 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_cistatic int ext2_unfreeze(struct super_block *sb) 13058c2ecf20Sopenharmony_ci{ 13068c2ecf20Sopenharmony_ci /* Just write sb to clear EXT2_VALID_FS flag */ 13078c2ecf20Sopenharmony_ci ext2_write_super(sb); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci return 0; 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_cistatic void ext2_write_super(struct super_block *sb) 13138c2ecf20Sopenharmony_ci{ 13148c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) 13158c2ecf20Sopenharmony_ci ext2_sync_fs(sb, 1); 13168c2ecf20Sopenharmony_ci} 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_cistatic int ext2_remount (struct super_block * sb, int * flags, char * data) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci struct ext2_sb_info * sbi = EXT2_SB(sb); 13218c2ecf20Sopenharmony_ci struct ext2_super_block * es; 13228c2ecf20Sopenharmony_ci struct ext2_mount_options new_opts; 13238c2ecf20Sopenharmony_ci int err; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci sync_filesystem(sb); 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci spin_lock(&sbi->s_lock); 13288c2ecf20Sopenharmony_ci new_opts.s_mount_opt = sbi->s_mount_opt; 13298c2ecf20Sopenharmony_ci new_opts.s_resuid = sbi->s_resuid; 13308c2ecf20Sopenharmony_ci new_opts.s_resgid = sbi->s_resgid; 13318c2ecf20Sopenharmony_ci spin_unlock(&sbi->s_lock); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci if (!parse_options(data, sb, &new_opts)) 13348c2ecf20Sopenharmony_ci return -EINVAL; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci spin_lock(&sbi->s_lock); 13378c2ecf20Sopenharmony_ci es = sbi->s_es; 13388c2ecf20Sopenharmony_ci if ((sbi->s_mount_opt ^ new_opts.s_mount_opt) & EXT2_MOUNT_DAX) { 13398c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_WARNING, "warning: refusing change of " 13408c2ecf20Sopenharmony_ci "dax flag with busy inodes while remounting"); 13418c2ecf20Sopenharmony_ci new_opts.s_mount_opt ^= EXT2_MOUNT_DAX; 13428c2ecf20Sopenharmony_ci } 13438c2ecf20Sopenharmony_ci if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb)) 13448c2ecf20Sopenharmony_ci goto out_set; 13458c2ecf20Sopenharmony_ci if (*flags & SB_RDONLY) { 13468c2ecf20Sopenharmony_ci if (le16_to_cpu(es->s_state) & EXT2_VALID_FS || 13478c2ecf20Sopenharmony_ci !(sbi->s_mount_state & EXT2_VALID_FS)) 13488c2ecf20Sopenharmony_ci goto out_set; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci /* 13518c2ecf20Sopenharmony_ci * OK, we are remounting a valid rw partition rdonly, so set 13528c2ecf20Sopenharmony_ci * the rdonly flag and then mark the partition as valid again. 13538c2ecf20Sopenharmony_ci */ 13548c2ecf20Sopenharmony_ci es->s_state = cpu_to_le16(sbi->s_mount_state); 13558c2ecf20Sopenharmony_ci es->s_mtime = cpu_to_le32(ktime_get_real_seconds()); 13568c2ecf20Sopenharmony_ci spin_unlock(&sbi->s_lock); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci err = dquot_suspend(sb, -1); 13598c2ecf20Sopenharmony_ci if (err < 0) 13608c2ecf20Sopenharmony_ci return err; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci ext2_sync_super(sb, es, 1); 13638c2ecf20Sopenharmony_ci } else { 13648c2ecf20Sopenharmony_ci __le32 ret = EXT2_HAS_RO_COMPAT_FEATURE(sb, 13658c2ecf20Sopenharmony_ci ~EXT2_FEATURE_RO_COMPAT_SUPP); 13668c2ecf20Sopenharmony_ci if (ret) { 13678c2ecf20Sopenharmony_ci spin_unlock(&sbi->s_lock); 13688c2ecf20Sopenharmony_ci ext2_msg(sb, KERN_WARNING, 13698c2ecf20Sopenharmony_ci "warning: couldn't remount RDWR because of " 13708c2ecf20Sopenharmony_ci "unsupported optional features (%x).", 13718c2ecf20Sopenharmony_ci le32_to_cpu(ret)); 13728c2ecf20Sopenharmony_ci return -EROFS; 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci /* 13758c2ecf20Sopenharmony_ci * Mounting a RDONLY partition read-write, so reread and 13768c2ecf20Sopenharmony_ci * store the current valid flag. (It may have been changed 13778c2ecf20Sopenharmony_ci * by e2fsck since we originally mounted the partition.) 13788c2ecf20Sopenharmony_ci */ 13798c2ecf20Sopenharmony_ci sbi->s_mount_state = le16_to_cpu(es->s_state); 13808c2ecf20Sopenharmony_ci if (!ext2_setup_super (sb, es, 0)) 13818c2ecf20Sopenharmony_ci sb->s_flags &= ~SB_RDONLY; 13828c2ecf20Sopenharmony_ci spin_unlock(&sbi->s_lock); 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci ext2_write_super(sb); 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci dquot_resume(sb, -1); 13878c2ecf20Sopenharmony_ci } 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci spin_lock(&sbi->s_lock); 13908c2ecf20Sopenharmony_ciout_set: 13918c2ecf20Sopenharmony_ci sbi->s_mount_opt = new_opts.s_mount_opt; 13928c2ecf20Sopenharmony_ci sbi->s_resuid = new_opts.s_resuid; 13938c2ecf20Sopenharmony_ci sbi->s_resgid = new_opts.s_resgid; 13948c2ecf20Sopenharmony_ci sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | 13958c2ecf20Sopenharmony_ci (test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0); 13968c2ecf20Sopenharmony_ci spin_unlock(&sbi->s_lock); 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci return 0; 13998c2ecf20Sopenharmony_ci} 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_cistatic int ext2_statfs (struct dentry * dentry, struct kstatfs * buf) 14028c2ecf20Sopenharmony_ci{ 14038c2ecf20Sopenharmony_ci struct super_block *sb = dentry->d_sb; 14048c2ecf20Sopenharmony_ci struct ext2_sb_info *sbi = EXT2_SB(sb); 14058c2ecf20Sopenharmony_ci struct ext2_super_block *es = sbi->s_es; 14068c2ecf20Sopenharmony_ci u64 fsid; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci spin_lock(&sbi->s_lock); 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci if (test_opt (sb, MINIX_DF)) 14118c2ecf20Sopenharmony_ci sbi->s_overhead_last = 0; 14128c2ecf20Sopenharmony_ci else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) { 14138c2ecf20Sopenharmony_ci unsigned long i, overhead = 0; 14148c2ecf20Sopenharmony_ci smp_rmb(); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci /* 14178c2ecf20Sopenharmony_ci * Compute the overhead (FS structures). This is constant 14188c2ecf20Sopenharmony_ci * for a given filesystem unless the number of block groups 14198c2ecf20Sopenharmony_ci * changes so we cache the previous value until it does. 14208c2ecf20Sopenharmony_ci */ 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci /* 14238c2ecf20Sopenharmony_ci * All of the blocks before first_data_block are 14248c2ecf20Sopenharmony_ci * overhead 14258c2ecf20Sopenharmony_ci */ 14268c2ecf20Sopenharmony_ci overhead = le32_to_cpu(es->s_first_data_block); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci /* 14298c2ecf20Sopenharmony_ci * Add the overhead attributed to the superblock and 14308c2ecf20Sopenharmony_ci * block group descriptors. If the sparse superblocks 14318c2ecf20Sopenharmony_ci * feature is turned on, then not all groups have this. 14328c2ecf20Sopenharmony_ci */ 14338c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_groups_count; i++) 14348c2ecf20Sopenharmony_ci overhead += ext2_bg_has_super(sb, i) + 14358c2ecf20Sopenharmony_ci ext2_bg_num_gdb(sb, i); 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci /* 14388c2ecf20Sopenharmony_ci * Every block group has an inode bitmap, a block 14398c2ecf20Sopenharmony_ci * bitmap, and an inode table. 14408c2ecf20Sopenharmony_ci */ 14418c2ecf20Sopenharmony_ci overhead += (sbi->s_groups_count * 14428c2ecf20Sopenharmony_ci (2 + sbi->s_itb_per_group)); 14438c2ecf20Sopenharmony_ci sbi->s_overhead_last = overhead; 14448c2ecf20Sopenharmony_ci smp_wmb(); 14458c2ecf20Sopenharmony_ci sbi->s_blocks_last = le32_to_cpu(es->s_blocks_count); 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci buf->f_type = EXT2_SUPER_MAGIC; 14498c2ecf20Sopenharmony_ci buf->f_bsize = sb->s_blocksize; 14508c2ecf20Sopenharmony_ci buf->f_blocks = le32_to_cpu(es->s_blocks_count) - sbi->s_overhead_last; 14518c2ecf20Sopenharmony_ci buf->f_bfree = ext2_count_free_blocks(sb); 14528c2ecf20Sopenharmony_ci es->s_free_blocks_count = cpu_to_le32(buf->f_bfree); 14538c2ecf20Sopenharmony_ci buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count); 14548c2ecf20Sopenharmony_ci if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count)) 14558c2ecf20Sopenharmony_ci buf->f_bavail = 0; 14568c2ecf20Sopenharmony_ci buf->f_files = le32_to_cpu(es->s_inodes_count); 14578c2ecf20Sopenharmony_ci buf->f_ffree = ext2_count_free_inodes(sb); 14588c2ecf20Sopenharmony_ci es->s_free_inodes_count = cpu_to_le32(buf->f_ffree); 14598c2ecf20Sopenharmony_ci buf->f_namelen = EXT2_NAME_LEN; 14608c2ecf20Sopenharmony_ci fsid = le64_to_cpup((void *)es->s_uuid) ^ 14618c2ecf20Sopenharmony_ci le64_to_cpup((void *)es->s_uuid + sizeof(u64)); 14628c2ecf20Sopenharmony_ci buf->f_fsid = u64_to_fsid(fsid); 14638c2ecf20Sopenharmony_ci spin_unlock(&sbi->s_lock); 14648c2ecf20Sopenharmony_ci return 0; 14658c2ecf20Sopenharmony_ci} 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_cistatic struct dentry *ext2_mount(struct file_system_type *fs_type, 14688c2ecf20Sopenharmony_ci int flags, const char *dev_name, void *data) 14698c2ecf20Sopenharmony_ci{ 14708c2ecf20Sopenharmony_ci return mount_bdev(fs_type, flags, dev_name, data, ext2_fill_super); 14718c2ecf20Sopenharmony_ci} 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci#ifdef CONFIG_QUOTA 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci/* Read data from quotafile - avoid pagecache and such because we cannot afford 14768c2ecf20Sopenharmony_ci * acquiring the locks... As quota files are never truncated and quota code 14778c2ecf20Sopenharmony_ci * itself serializes the operations (and no one else should touch the files) 14788c2ecf20Sopenharmony_ci * we don't have to be afraid of races */ 14798c2ecf20Sopenharmony_cistatic ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, 14808c2ecf20Sopenharmony_ci size_t len, loff_t off) 14818c2ecf20Sopenharmony_ci{ 14828c2ecf20Sopenharmony_ci struct inode *inode = sb_dqopt(sb)->files[type]; 14838c2ecf20Sopenharmony_ci sector_t blk = off >> EXT2_BLOCK_SIZE_BITS(sb); 14848c2ecf20Sopenharmony_ci int err = 0; 14858c2ecf20Sopenharmony_ci int offset = off & (sb->s_blocksize - 1); 14868c2ecf20Sopenharmony_ci int tocopy; 14878c2ecf20Sopenharmony_ci size_t toread; 14888c2ecf20Sopenharmony_ci struct buffer_head tmp_bh; 14898c2ecf20Sopenharmony_ci struct buffer_head *bh; 14908c2ecf20Sopenharmony_ci loff_t i_size = i_size_read(inode); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci if (off > i_size) 14938c2ecf20Sopenharmony_ci return 0; 14948c2ecf20Sopenharmony_ci if (off+len > i_size) 14958c2ecf20Sopenharmony_ci len = i_size-off; 14968c2ecf20Sopenharmony_ci toread = len; 14978c2ecf20Sopenharmony_ci while (toread > 0) { 14988c2ecf20Sopenharmony_ci tocopy = sb->s_blocksize - offset < toread ? 14998c2ecf20Sopenharmony_ci sb->s_blocksize - offset : toread; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci tmp_bh.b_state = 0; 15028c2ecf20Sopenharmony_ci tmp_bh.b_size = sb->s_blocksize; 15038c2ecf20Sopenharmony_ci err = ext2_get_block(inode, blk, &tmp_bh, 0); 15048c2ecf20Sopenharmony_ci if (err < 0) 15058c2ecf20Sopenharmony_ci return err; 15068c2ecf20Sopenharmony_ci if (!buffer_mapped(&tmp_bh)) /* A hole? */ 15078c2ecf20Sopenharmony_ci memset(data, 0, tocopy); 15088c2ecf20Sopenharmony_ci else { 15098c2ecf20Sopenharmony_ci bh = sb_bread(sb, tmp_bh.b_blocknr); 15108c2ecf20Sopenharmony_ci if (!bh) 15118c2ecf20Sopenharmony_ci return -EIO; 15128c2ecf20Sopenharmony_ci memcpy(data, bh->b_data+offset, tocopy); 15138c2ecf20Sopenharmony_ci brelse(bh); 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci offset = 0; 15168c2ecf20Sopenharmony_ci toread -= tocopy; 15178c2ecf20Sopenharmony_ci data += tocopy; 15188c2ecf20Sopenharmony_ci blk++; 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci return len; 15218c2ecf20Sopenharmony_ci} 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci/* Write to quotafile */ 15248c2ecf20Sopenharmony_cistatic ssize_t ext2_quota_write(struct super_block *sb, int type, 15258c2ecf20Sopenharmony_ci const char *data, size_t len, loff_t off) 15268c2ecf20Sopenharmony_ci{ 15278c2ecf20Sopenharmony_ci struct inode *inode = sb_dqopt(sb)->files[type]; 15288c2ecf20Sopenharmony_ci sector_t blk = off >> EXT2_BLOCK_SIZE_BITS(sb); 15298c2ecf20Sopenharmony_ci int err = 0; 15308c2ecf20Sopenharmony_ci int offset = off & (sb->s_blocksize - 1); 15318c2ecf20Sopenharmony_ci int tocopy; 15328c2ecf20Sopenharmony_ci size_t towrite = len; 15338c2ecf20Sopenharmony_ci struct buffer_head tmp_bh; 15348c2ecf20Sopenharmony_ci struct buffer_head *bh; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci while (towrite > 0) { 15378c2ecf20Sopenharmony_ci tocopy = sb->s_blocksize - offset < towrite ? 15388c2ecf20Sopenharmony_ci sb->s_blocksize - offset : towrite; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci tmp_bh.b_state = 0; 15418c2ecf20Sopenharmony_ci tmp_bh.b_size = sb->s_blocksize; 15428c2ecf20Sopenharmony_ci err = ext2_get_block(inode, blk, &tmp_bh, 1); 15438c2ecf20Sopenharmony_ci if (err < 0) 15448c2ecf20Sopenharmony_ci goto out; 15458c2ecf20Sopenharmony_ci if (offset || tocopy != EXT2_BLOCK_SIZE(sb)) 15468c2ecf20Sopenharmony_ci bh = sb_bread(sb, tmp_bh.b_blocknr); 15478c2ecf20Sopenharmony_ci else 15488c2ecf20Sopenharmony_ci bh = sb_getblk(sb, tmp_bh.b_blocknr); 15498c2ecf20Sopenharmony_ci if (unlikely(!bh)) { 15508c2ecf20Sopenharmony_ci err = -EIO; 15518c2ecf20Sopenharmony_ci goto out; 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci lock_buffer(bh); 15548c2ecf20Sopenharmony_ci memcpy(bh->b_data+offset, data, tocopy); 15558c2ecf20Sopenharmony_ci flush_dcache_page(bh->b_page); 15568c2ecf20Sopenharmony_ci set_buffer_uptodate(bh); 15578c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 15588c2ecf20Sopenharmony_ci unlock_buffer(bh); 15598c2ecf20Sopenharmony_ci brelse(bh); 15608c2ecf20Sopenharmony_ci offset = 0; 15618c2ecf20Sopenharmony_ci towrite -= tocopy; 15628c2ecf20Sopenharmony_ci data += tocopy; 15638c2ecf20Sopenharmony_ci blk++; 15648c2ecf20Sopenharmony_ci } 15658c2ecf20Sopenharmony_ciout: 15668c2ecf20Sopenharmony_ci if (len == towrite) 15678c2ecf20Sopenharmony_ci return err; 15688c2ecf20Sopenharmony_ci if (inode->i_size < off+len-towrite) 15698c2ecf20Sopenharmony_ci i_size_write(inode, off+len-towrite); 15708c2ecf20Sopenharmony_ci inode_inc_iversion(inode); 15718c2ecf20Sopenharmony_ci inode->i_mtime = inode->i_ctime = current_time(inode); 15728c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 15738c2ecf20Sopenharmony_ci return len - towrite; 15748c2ecf20Sopenharmony_ci} 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_cistatic int ext2_quota_on(struct super_block *sb, int type, int format_id, 15778c2ecf20Sopenharmony_ci const struct path *path) 15788c2ecf20Sopenharmony_ci{ 15798c2ecf20Sopenharmony_ci int err; 15808c2ecf20Sopenharmony_ci struct inode *inode; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci err = dquot_quota_on(sb, type, format_id, path); 15838c2ecf20Sopenharmony_ci if (err) 15848c2ecf20Sopenharmony_ci return err; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci inode = d_inode(path->dentry); 15878c2ecf20Sopenharmony_ci inode_lock(inode); 15888c2ecf20Sopenharmony_ci EXT2_I(inode)->i_flags |= EXT2_NOATIME_FL | EXT2_IMMUTABLE_FL; 15898c2ecf20Sopenharmony_ci inode_set_flags(inode, S_NOATIME | S_IMMUTABLE, 15908c2ecf20Sopenharmony_ci S_NOATIME | S_IMMUTABLE); 15918c2ecf20Sopenharmony_ci inode_unlock(inode); 15928c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci return 0; 15958c2ecf20Sopenharmony_ci} 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_cistatic int ext2_quota_off(struct super_block *sb, int type) 15988c2ecf20Sopenharmony_ci{ 15998c2ecf20Sopenharmony_ci struct inode *inode = sb_dqopt(sb)->files[type]; 16008c2ecf20Sopenharmony_ci int err; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci if (!inode || !igrab(inode)) 16038c2ecf20Sopenharmony_ci goto out; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci err = dquot_quota_off(sb, type); 16068c2ecf20Sopenharmony_ci if (err) 16078c2ecf20Sopenharmony_ci goto out_put; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci inode_lock(inode); 16108c2ecf20Sopenharmony_ci EXT2_I(inode)->i_flags &= ~(EXT2_NOATIME_FL | EXT2_IMMUTABLE_FL); 16118c2ecf20Sopenharmony_ci inode_set_flags(inode, 0, S_NOATIME | S_IMMUTABLE); 16128c2ecf20Sopenharmony_ci inode_unlock(inode); 16138c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 16148c2ecf20Sopenharmony_ciout_put: 16158c2ecf20Sopenharmony_ci iput(inode); 16168c2ecf20Sopenharmony_ci return err; 16178c2ecf20Sopenharmony_ciout: 16188c2ecf20Sopenharmony_ci return dquot_quota_off(sb, type); 16198c2ecf20Sopenharmony_ci} 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci#endif 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_cistatic struct file_system_type ext2_fs_type = { 16248c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 16258c2ecf20Sopenharmony_ci .name = "ext2", 16268c2ecf20Sopenharmony_ci .mount = ext2_mount, 16278c2ecf20Sopenharmony_ci .kill_sb = kill_block_super, 16288c2ecf20Sopenharmony_ci .fs_flags = FS_REQUIRES_DEV, 16298c2ecf20Sopenharmony_ci}; 16308c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("ext2"); 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_cistatic int __init init_ext2_fs(void) 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci int err; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci err = init_inodecache(); 16378c2ecf20Sopenharmony_ci if (err) 16388c2ecf20Sopenharmony_ci return err; 16398c2ecf20Sopenharmony_ci err = register_filesystem(&ext2_fs_type); 16408c2ecf20Sopenharmony_ci if (err) 16418c2ecf20Sopenharmony_ci goto out; 16428c2ecf20Sopenharmony_ci return 0; 16438c2ecf20Sopenharmony_ciout: 16448c2ecf20Sopenharmony_ci destroy_inodecache(); 16458c2ecf20Sopenharmony_ci return err; 16468c2ecf20Sopenharmony_ci} 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_cistatic void __exit exit_ext2_fs(void) 16498c2ecf20Sopenharmony_ci{ 16508c2ecf20Sopenharmony_ci unregister_filesystem(&ext2_fs_type); 16518c2ecf20Sopenharmony_ci destroy_inodecache(); 16528c2ecf20Sopenharmony_ci} 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ciMODULE_AUTHOR("Remy Card and others"); 16558c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Second Extended Filesystem"); 16568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 16578c2ecf20Sopenharmony_cimodule_init(init_ext2_fs) 16588c2ecf20Sopenharmony_cimodule_exit(exit_ext2_fs) 1659