📄 super.c
字号:
/* * 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/parser.h>#include <linux/random.h>#include <linux/buffer_head.h>#include <linux/exportfs.h>#include <linux/smp_lock.h>#include <linux/vfs.h>#include <linux/seq_file.h>#include <linux/mount.h>#include <linux/log2.h>#include <asm/uaccess.h>#include "ext2.h"#include "xattr.h"#include "acl.h"#include "xip.h"static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es);static int ext2_remount (struct super_block * sb, int * flags, char * data);static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf);void ext2_error (struct super_block * sb, const char * function, const char * fmt, ...){ va_list args; struct ext2_sb_info *sbi = EXT2_SB(sb); struct ext2_super_block *es = sbi->s_es; if (!(sb->s_flags & MS_RDONLY)) { sbi->s_mount_state |= EXT2_ERROR_FS; es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) | EXT2_ERROR_FS); ext2_sync_super(sb, es); } va_start(args, fmt); printk(KERN_CRIT "EXT2-fs error (device %s): %s: ",sb->s_id, function); vprintk(fmt, args); printk("\n"); va_end(args); if (test_opt(sb, ERRORS_PANIC)) panic("EXT2-fs panic from previous error\n"); if (test_opt(sb, ERRORS_RO)) { printk("Remounting filesystem read-only\n"); sb->s_flags |= MS_RDONLY; }}void ext2_warning (struct super_block * sb, const char * function, const char * fmt, ...){ va_list args; va_start(args, fmt); printk(KERN_WARNING "EXT2-fs warning (device %s): %s: ", sb->s_id, function); vprintk(fmt, args); printk("\n"); va_end(args);}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_warning(sb, __FUNCTION__, "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. */}static void ext2_put_super (struct super_block * sb){ int db_count; int i; struct ext2_sb_info *sbi = EXT2_SB(sb); ext2_xattr_put_super(sb); if (!(sb->s_flags & MS_RDONLY)) { struct ext2_super_block *es = sbi->s_es; es->s_state = cpu_to_le16(sbi->s_mount_state); ext2_sync_super(sb, es); } db_count = sbi->s_gdb_count; for (i = 0; i < db_count; i++) if (sbi->s_group_desc[i]) brelse (sbi->s_group_desc[i]); kfree(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); return;}static struct kmem_cache * ext2_inode_cachep;static struct inode *ext2_alloc_inode(struct super_block *sb){ struct ext2_inode_info *ei; ei = (struct ext2_inode_info *)kmem_cache_alloc(ext2_inode_cachep, GFP_KERNEL); if (!ei) return NULL;#ifdef CONFIG_EXT2_FS_POSIX_ACL ei->i_acl = EXT2_ACL_NOT_CACHED; ei->i_default_acl = EXT2_ACL_NOT_CACHED;#endif ei->i_block_alloc_info = NULL; ei->vfs_inode.i_version = 1; return &ei->vfs_inode;}static void ext2_destroy_inode(struct inode *inode){ kmem_cache_free(ext2_inode_cachep, EXT2_I(inode));}static void init_once(struct kmem_cache * cachep, 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_inodecache(void){ ext2_inode_cachep = kmem_cache_create("ext2_inode_cache", sizeof(struct ext2_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), init_once); if (ext2_inode_cachep == NULL) return -ENOMEM; return 0;}static void destroy_inodecache(void){ kmem_cache_destroy(ext2_inode_cachep);}static void ext2_clear_inode(struct inode *inode){ struct ext2_block_alloc_info *rsv = EXT2_I(inode)->i_block_alloc_info;#ifdef CONFIG_EXT2_FS_POSIX_ACL struct ext2_inode_info *ei = EXT2_I(inode); if (ei->i_acl && ei->i_acl != EXT2_ACL_NOT_CACHED) { posix_acl_release(ei->i_acl); ei->i_acl = EXT2_ACL_NOT_CACHED; } if (ei->i_default_acl && ei->i_default_acl != EXT2_ACL_NOT_CACHED) { posix_acl_release(ei->i_default_acl); ei->i_default_acl = EXT2_ACL_NOT_CACHED; }#endif ext2_discard_reservation(inode); EXT2_I(inode)->i_block_alloc_info = NULL; if (unlikely(rsv)) kfree(rsv);}static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs){ struct super_block *sb = vfs->mnt_sb; struct ext2_sb_info *sbi = EXT2_SB(sb); struct ext2_super_block *es = sbi->s_es; unsigned long def_mount_opts; 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 (sbi->s_resuid != EXT2_DEF_RESUID || le16_to_cpu(es->s_def_resuid) != EXT2_DEF_RESUID) { seq_printf(seq, ",resuid=%u", sbi->s_resuid); } if (sbi->s_resgid != EXT2_DEF_RESGID || le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) { seq_printf(seq, ",resgid=%u", sbi->s_resgid); } if (test_opt(sb, ERRORS_CONT)) { int def_errors = le16_to_cpu(es->s_errors); if (def_errors == EXT2_ERRORS_PANIC || def_errors == EXT2_ERRORS_RO) { seq_puts(seq, ",errors=continue"); } } if (test_opt(sb, ERRORS_RO)) seq_puts(seq, ",errors=remount-ro"); 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, NOBH)) seq_puts(seq, ",nobh");#if defined(CONFIG_QUOTA) if (sbi->s_mount_opt & EXT2_MOUNT_USRQUOTA) seq_puts(seq, ",usrquota"); if (sbi->s_mount_opt & EXT2_MOUNT_GRPQUOTA) seq_puts(seq, ",grpquota");#endif#if defined(CONFIG_EXT2_FS_XIP) if (sbi->s_mount_opt & EXT2_MOUNT_XIP) seq_puts(seq, ",xip");#endif 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);#endifstatic const struct super_operations ext2_sops = { .alloc_inode = ext2_alloc_inode, .destroy_inode = ext2_destroy_inode, .read_inode = ext2_read_inode, .write_inode = ext2_write_inode, .delete_inode = ext2_delete_inode, .put_super = ext2_put_super, .write_super = ext2_write_super, .statfs = ext2_statfs, .remount_fs = ext2_remount, .clear_inode = ext2_clear_inode, .show_options = ext2_show_options,#ifdef CONFIG_QUOTA .quota_read = ext2_quota_read, .quota_write = ext2_quota_write,#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); /* iget isn't really right if the inode is currently unallocated!! * ext2_read_inode currently does appropriate checks, but * it might be "neater" to call ext2_get_inode first and check * if the inode is valid..... */ inode = iget(sb, ino); if (inode == NULL) return ERR_PTR(-ENOMEM); if (is_bad_inode(inode) || (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);}/* Yes, most of these are left as NULL!! * A NULL value implies the default, which works with ext2-like file * systems, but can be improved upon. * Currently only get_parent is required. */static const struct export_operations ext2_export_ops = { .fh_to_dentry = ext2_fh_to_dentry, .fh_to_parent = ext2_fh_to_parent, .get_parent = ext2_get_parent,};static unsigned long get_sb_block(void **data){ unsigned long sb_block; char *options = (char *) *data; if (!options || strncmp(options, "sb=", 3) != 0) return 1; /* Default location */ options += 3; sb_block = simple_strtoul(options, &options, 0); if (*options && *options != ',') { printk("EXT2-fs: Invalid sb specification: %s\n", (char *) *data); return 1; } if (*options == ',') options++; *data = (void *) options; return sb_block;}enum { Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota, Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation};static match_table_t tokens = { {Opt_bsd_df, "bsddf"}, {Opt_minix_df, "minixdf"}, {Opt_grpid, "grpid"}, {Opt_grpid, "bsdgroups"}, {Opt_nogrpid, "nogrpid"}, {Opt_nogrpid, "sysvgroups"}, {Opt_resgid, "resgid=%u"}, {Opt_resuid, "resuid=%u"}, {Opt_sb, "sb=%u"}, {Opt_err_cont, "errors=continue"}, {Opt_err_panic, "errors=panic"}, {Opt_err_ro, "errors=remount-ro"}, {Opt_nouid32, "nouid32"}, {Opt_nocheck, "check=none"}, {Opt_nocheck, "nocheck"}, {Opt_debug, "debug"}, {Opt_oldalloc, "oldalloc"}, {Opt_orlov, "orlov"}, {Opt_nobh, "nobh"}, {Opt_user_xattr, "user_xattr"}, {Opt_nouser_xattr, "nouser_xattr"}, {Opt_acl, "acl"}, {Opt_noacl, "noacl"}, {Opt_xip, "xip"}, {Opt_grpquota, "grpquota"}, {Opt_ignore, "noquota"}, {Opt_quota, "quota"}, {Opt_usrquota, "usrquota"}, {Opt_reservation, "reservation"}, {Opt_noreservation, "noreservation"}, {Opt_err, NULL}};static int parse_options (char * options, struct ext2_sb_info *sbi){ char * p; substring_t args[MAX_OPT_ARGS]; int option; if (!options) return 1; while ((p = strsep (&options, ",")) != NULL) { int token; if (!*p) continue; token = match_token(p, tokens, args); switch (token) { case Opt_bsd_df: clear_opt (sbi->s_mount_opt, MINIX_DF); break; case Opt_minix_df: set_opt (sbi->s_mount_opt, MINIX_DF); break; case Opt_grpid: set_opt (sbi->s_mount_opt, GRPID); break; case Opt_nogrpid: clear_opt (sbi->s_mount_opt, GRPID); break; case Opt_resuid: if (match_int(&args[0], &option)) return 0; sbi->s_resuid = option; break; case Opt_resgid: if (match_int(&args[0], &option)) return 0; sbi->s_resgid = option; break; case Opt_sb: /* handled by get_sb_block() instead of here */ /* *sb_block = match_int(&args[0]); */ break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -