1701 lines · 45.8 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* *  linux/fs/ext2/super.c * * Copyright (C) 1992, 1993, 1994, 1995 * Remy Card (card@masi.ibp.fr) * Laboratoire MASI - Institut Blaise Pascal * Universite Pierre et Marie Curie (Paris VI) * *  from * *  linux/fs/minix/inode.c * *  Copyright (C) 1991, 1992  Linus Torvalds * *  Big-endian to little-endian byte-swapping/bitmaps by *        David S. Miller (davem@caip.rutgers.edu), 1995 */ #include <linux/module.h>#include <linux/string.h>#include <linux/fs.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/blkdev.h>#include <linux/fs_context.h>#include <linux/fs_parser.h>#include <linux/random.h>#include <linux/buffer_head.h>#include <linux/exportfs.h>#include <linux/vfs.h>#include <linux/seq_file.h>#include <linux/mount.h>#include <linux/log2.h>#include <linux/quotaops.h>#include <linux/uaccess.h>#include <linux/iversion.h>#include "ext2.h"#include "xattr.h"#include "acl.h" static void ext2_write_super(struct super_block *sb);static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf);static int ext2_sync_fs(struct super_block *sb, int wait);static int ext2_freeze(struct super_block *sb);static int ext2_unfreeze(struct super_block *sb); void ext2_error(struct super_block *sb, const char *function,		const char *fmt, ...){	struct va_format vaf;	va_list args;	struct ext2_sb_info *sbi = EXT2_SB(sb);	struct ext2_super_block *es = sbi->s_es; 	if (!sb_rdonly(sb)) {		spin_lock(&sbi->s_lock);		sbi->s_mount_state |= EXT2_ERROR_FS;		es->s_state |= cpu_to_le16(EXT2_ERROR_FS);		spin_unlock(&sbi->s_lock);		ext2_sync_super(sb, es, 1);	} 	va_start(args, fmt); 	vaf.fmt = fmt;	vaf.va = &args; 	printk(KERN_CRIT "EXT2-fs (%s): error: %s: %pV\n",	       sb->s_id, function, &vaf); 	va_end(args); 	if (test_opt(sb, ERRORS_PANIC))		panic("EXT2-fs: panic from previous error\n");	if (!sb_rdonly(sb) && test_opt(sb, ERRORS_RO)) {		ext2_msg(sb, KERN_CRIT,			     "error: remounting filesystem read-only");		sb->s_flags |= SB_RDONLY;	}} static void ext2_msg_fc(struct fs_context *fc, const char *prefix,			const char *fmt, ...){	struct va_format vaf;	va_list args;	const char *s_id; 	if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {		s_id = fc->root->d_sb->s_id;	} else {		/* get last path component of source */		s_id = strrchr(fc->source, '/');		if (s_id)			s_id++;		else			s_id = fc->source;	}	va_start(args, fmt); 	vaf.fmt = fmt;	vaf.va = &args; 	printk("%sEXT2-fs (%s): %pV\n", prefix, s_id, &vaf); 	va_end(args);} void ext2_msg(struct super_block *sb, const char *prefix,		const char *fmt, ...){	struct va_format vaf;	va_list args; 	va_start(args, fmt); 	vaf.fmt = fmt;	vaf.va = &args; 	printk("%sEXT2-fs (%s): %pV\n", prefix, sb->s_id, &vaf); 	va_end(args);} /* * This must be called with sbi->s_lock held. */void ext2_update_dynamic_rev(struct super_block *sb){	struct ext2_super_block *es = EXT2_SB(sb)->s_es; 	if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV)		return; 	ext2_msg(sb, KERN_WARNING,		     "warning: updating to rev %d because of "		     "new feature flag, running e2fsck is recommended",		     EXT2_DYNAMIC_REV); 	es->s_first_ino = cpu_to_le32(EXT2_GOOD_OLD_FIRST_INO);	es->s_inode_size = cpu_to_le16(EXT2_GOOD_OLD_INODE_SIZE);	es->s_rev_level = cpu_to_le32(EXT2_DYNAMIC_REV);	/* leave es->s_feature_*compat flags alone */	/* es->s_uuid will be set by e2fsck if empty */ 	/*	 * The rest of the superblock fields should be zero, and if not it	 * means they are likely already in use, so leave them alone.  We	 * can leave it up to e2fsck to clean up any inconsistencies there.	 */} #ifdef CONFIG_QUOTAstatic int ext2_quota_off(struct super_block *sb, int type); static void ext2_quota_off_umount(struct super_block *sb){	int type; 	for (type = 0; type < MAXQUOTAS; type++)		ext2_quota_off(sb, type);}#elsestatic inline void ext2_quota_off_umount(struct super_block *sb){}#endif static void ext2_put_super (struct super_block * sb){	int db_count;	int i;	struct ext2_sb_info *sbi = EXT2_SB(sb); 	ext2_quota_off_umount(sb); 	ext2_xattr_destroy_cache(sbi->s_ea_block_cache);	sbi->s_ea_block_cache = NULL; 	if (!sb_rdonly(sb)) {		struct ext2_super_block *es = sbi->s_es; 		spin_lock(&sbi->s_lock);		es->s_state = cpu_to_le16(sbi->s_mount_state);		spin_unlock(&sbi->s_lock);		ext2_sync_super(sb, es, 1);	}	db_count = sbi->s_gdb_count;	for (i = 0; i < db_count; i++)		brelse(sbi->s_group_desc[i]);	kvfree(sbi->s_group_desc);	kfree(sbi->s_debts);	percpu_counter_destroy(&sbi->s_freeblocks_counter);	percpu_counter_destroy(&sbi->s_freeinodes_counter);	percpu_counter_destroy(&sbi->s_dirs_counter);	brelse (sbi->s_sbh);	sb->s_fs_info = NULL;	kfree(sbi->s_blockgroup_lock);	kfree(sbi);} static struct kmem_cache * ext2_inode_cachep; static struct inode *ext2_alloc_inode(struct super_block *sb){	struct ext2_inode_info *ei;	ei = alloc_inode_sb(sb, ext2_inode_cachep, GFP_KERNEL);	if (!ei)		return NULL;	ei->i_block_alloc_info = NULL;	inode_set_iversion(&ei->vfs_inode, 1);#ifdef CONFIG_QUOTA	memset(&ei->i_dquot, 0, sizeof(ei->i_dquot));#endif	mmb_init(&ei->i_metadata_bhs, &ei->vfs_inode.i_data); 	return &ei->vfs_inode;} static void ext2_free_in_core_inode(struct inode *inode){	kmem_cache_free(ext2_inode_cachep, EXT2_I(inode));} static void init_once(void *foo){	struct ext2_inode_info *ei = (struct ext2_inode_info *) foo; 	rwlock_init(&ei->i_meta_lock);#ifdef CONFIG_EXT2_FS_XATTR	init_rwsem(&ei->xattr_sem);#endif	mutex_init(&ei->truncate_mutex);	inode_init_once(&ei->vfs_inode);} static int __init init_inodecache(void){	ext2_inode_cachep = kmem_cache_create_usercopy("ext2_inode_cache",				sizeof(struct ext2_inode_info), 0,				SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT,				offsetof(struct ext2_inode_info, i_data),				sizeof_field(struct ext2_inode_info, i_data),				init_once);	if (ext2_inode_cachep == NULL)		return -ENOMEM;	return 0;} static void destroy_inodecache(void){	/*	 * Make sure all delayed rcu free inodes are flushed before we	 * destroy cache.	 */	rcu_barrier();	kmem_cache_destroy(ext2_inode_cachep);} static int ext2_show_options(struct seq_file *seq, struct dentry *root){	struct super_block *sb = root->d_sb;	struct ext2_sb_info *sbi = EXT2_SB(sb);	struct ext2_super_block *es = sbi->s_es;	unsigned long def_mount_opts; 	spin_lock(&sbi->s_lock);	def_mount_opts = le32_to_cpu(es->s_default_mount_opts); 	if (sbi->s_sb_block != 1)		seq_printf(seq, ",sb=%lu", sbi->s_sb_block);	if (test_opt(sb, MINIX_DF))		seq_puts(seq, ",minixdf");	if (test_opt(sb, GRPID))		seq_puts(seq, ",grpid");	if (!test_opt(sb, GRPID) && (def_mount_opts & EXT2_DEFM_BSDGROUPS))		seq_puts(seq, ",nogrpid");	if (!uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT2_DEF_RESUID)) ||	    le16_to_cpu(es->s_def_resuid) != EXT2_DEF_RESUID) {		seq_printf(seq, ",resuid=%u",				from_kuid_munged(&init_user_ns, sbi->s_resuid));	}	if (!gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT2_DEF_RESGID)) ||	    le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) {		seq_printf(seq, ",resgid=%u",				from_kgid_munged(&init_user_ns, sbi->s_resgid));	}	if (test_opt(sb, ERRORS_RO)) {		int def_errors = le16_to_cpu(es->s_errors); 		if (def_errors == EXT2_ERRORS_PANIC ||		    def_errors == EXT2_ERRORS_CONTINUE) {			seq_puts(seq, ",errors=remount-ro");		}	}	if (test_opt(sb, ERRORS_CONT))		seq_puts(seq, ",errors=continue");	if (test_opt(sb, ERRORS_PANIC))		seq_puts(seq, ",errors=panic");	if (test_opt(sb, NO_UID32))		seq_puts(seq, ",nouid32");	if (test_opt(sb, DEBUG))		seq_puts(seq, ",debug");	if (test_opt(sb, OLDALLOC))		seq_puts(seq, ",oldalloc"); #ifdef CONFIG_EXT2_FS_XATTR	if (test_opt(sb, XATTR_USER))		seq_puts(seq, ",user_xattr");	if (!test_opt(sb, XATTR_USER) &&	    (def_mount_opts & EXT2_DEFM_XATTR_USER)) {		seq_puts(seq, ",nouser_xattr");	}#endif #ifdef CONFIG_EXT2_FS_POSIX_ACL	if (test_opt(sb, POSIX_ACL))		seq_puts(seq, ",acl");	if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT2_DEFM_ACL))		seq_puts(seq, ",noacl");#endif 	if (test_opt(sb, USRQUOTA))		seq_puts(seq, ",usrquota"); 	if (test_opt(sb, GRPQUOTA))		seq_puts(seq, ",grpquota");   	if (!test_opt(sb, RESERVATION))		seq_puts(seq, ",noreservation"); 	spin_unlock(&sbi->s_lock);	return 0;} #ifdef CONFIG_QUOTAstatic ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, size_t len, loff_t off);static ssize_t ext2_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off);static int ext2_quota_on(struct super_block *sb, int type, int format_id,			 const struct path *path);static struct dquot __rcu **ext2_get_dquots(struct inode *inode){	return EXT2_I(inode)->i_dquot;} static const struct quotactl_ops ext2_quotactl_ops = {	.quota_on	= ext2_quota_on,	.quota_off	= ext2_quota_off,	.quota_sync	= dquot_quota_sync,	.get_state	= dquot_get_state,	.set_info	= dquot_set_dqinfo,	.get_dqblk	= dquot_get_dqblk,	.set_dqblk	= dquot_set_dqblk,	.get_nextdqblk	= dquot_get_next_dqblk,};#endif static const struct super_operations ext2_sops = {	.alloc_inode	= ext2_alloc_inode,	.free_inode	= ext2_free_in_core_inode,	.write_inode	= ext2_write_inode,	.sync_inode_metadata = ext2_sync_inode_metadata,	.evict_inode	= ext2_evict_inode,	.put_super	= ext2_put_super,	.sync_fs	= ext2_sync_fs,	.freeze_fs	= ext2_freeze,	.unfreeze_fs	= ext2_unfreeze,	.statfs		= ext2_statfs,	.show_options	= ext2_show_options,#ifdef CONFIG_QUOTA	.quota_read	= ext2_quota_read,	.quota_write	= ext2_quota_write,	.get_dquots	= ext2_get_dquots,#endif}; static struct inode *ext2_nfs_get_inode(struct super_block *sb,		u64 ino, u32 generation){	struct inode *inode; 	if (ino < EXT2_FIRST_INO(sb) && ino != EXT2_ROOT_INO)		return ERR_PTR(-ESTALE);	if (ino > le32_to_cpu(EXT2_SB(sb)->s_es->s_inodes_count))		return ERR_PTR(-ESTALE); 	/*	 * ext2_iget isn't quite right if the inode is currently unallocated!	 * However ext2_iget currently does appropriate checks to handle stale	 * inodes so everything is OK.	 */	inode = ext2_iget(sb, ino);	if (IS_ERR(inode))		return ERR_CAST(inode);	if (generation && inode->i_generation != generation) {		/* we didn't find the right inode.. */		iput(inode);		return ERR_PTR(-ESTALE);	}	return inode;} static struct dentry *ext2_fh_to_dentry(struct super_block *sb, struct fid *fid,		int fh_len, int fh_type){	return generic_fh_to_dentry(sb, fid, fh_len, fh_type,				    ext2_nfs_get_inode);} static struct dentry *ext2_fh_to_parent(struct super_block *sb, struct fid *fid,		int fh_len, int fh_type){	return generic_fh_to_parent(sb, fid, fh_len, fh_type,				    ext2_nfs_get_inode);} static const struct export_operations ext2_export_ops = {	.encode_fh = generic_encode_ino32_fh,	.fh_to_dentry = ext2_fh_to_dentry,	.fh_to_parent = ext2_fh_to_parent,	.get_parent = ext2_get_parent,}; enum {	Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, Opt_resgid, Opt_resuid,	Opt_sb, Opt_errors, Opt_nouid32, Opt_debug, Opt_oldalloc, Opt_orlov,	Opt_nobh, Opt_user_xattr, Opt_acl, Opt_xip, Opt_dax, Opt_ignore,	Opt_quota, Opt_usrquota, Opt_grpquota, Opt_reservation,}; static const struct constant_table ext2_param_errors[] = {	{"continue",	EXT2_MOUNT_ERRORS_CONT},	{"panic",	EXT2_MOUNT_ERRORS_PANIC},	{"remount-ro",	EXT2_MOUNT_ERRORS_RO},	{}}; static const struct fs_parameter_spec ext2_param_spec[] = {	fsparam_flag	("bsddf", Opt_bsd_df),	fsparam_flag	("minixdf", Opt_minix_df),	fsparam_flag	("grpid", Opt_grpid),	fsparam_flag	("bsdgroups", Opt_grpid),	fsparam_flag	("nogrpid", Opt_nogrpid),	fsparam_flag	("sysvgroups", Opt_nogrpid),	fsparam_gid	("resgid", Opt_resgid),	fsparam_uid	("resuid", Opt_resuid),	fsparam_u32	("sb", Opt_sb),	fsparam_enum	("errors", Opt_errors, ext2_param_errors),	fsparam_flag	("nouid32", Opt_nouid32),	fsparam_flag	("debug", Opt_debug),	fsparam_flag	("oldalloc", Opt_oldalloc),	fsparam_flag	("orlov", Opt_orlov),	fsparam_flag	("nobh", Opt_nobh),	fsparam_flag_no	("user_xattr", Opt_user_xattr),	fsparam_flag_no	("acl", Opt_acl),	fsparam_flag	("xip", Opt_xip),	fsparam_flag	("dax", Opt_dax),	fsparam_flag	("grpquota", Opt_grpquota),	fsparam_flag	("noquota", Opt_ignore),	fsparam_flag	("quota", Opt_quota),	fsparam_flag	("usrquota", Opt_usrquota),	fsparam_flag_no	("reservation", Opt_reservation),	{}}; #define EXT2_SPEC_s_resuid                      (1 << 0)#define EXT2_SPEC_s_resgid                      (1 << 1) struct ext2_fs_context {	unsigned long	vals_s_flags;	/* Bits to set in s_flags */	unsigned long	mask_s_flags;	/* Bits changed in s_flags */	unsigned int	vals_s_mount_opt;	unsigned int	mask_s_mount_opt;	kuid_t		s_resuid;	kgid_t		s_resgid;	unsigned long	s_sb_block;	unsigned int	spec; }; static inline void ctx_set_mount_opt(struct ext2_fs_context *ctx,				  unsigned long flag){	ctx->mask_s_mount_opt |= flag;	ctx->vals_s_mount_opt |= flag;} static inline void ctx_clear_mount_opt(struct ext2_fs_context *ctx,				    unsigned long flag){	ctx->mask_s_mount_opt |= flag;	ctx->vals_s_mount_opt &= ~flag;} static inline unsigned longctx_test_mount_opt(struct ext2_fs_context *ctx, unsigned long flag){

Lines 1–500 of 1701.