📄 super.c
字号:
BUFFER_TRACE(sbi->s_sbh, "marking dirty"); mark_buffer_dirty(sbi->s_sbh); ext4_commit_super(sb, es, 1); } for (i = 0; i < sbi->s_gdb_count; i++) brelse(sbi->s_group_desc[i]); kfree(sbi->s_group_desc); 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);#ifdef CONFIG_QUOTA for (i = 0; i < MAXQUOTAS; i++) kfree(sbi->s_qf_names[i]);#endif /* Debugging code just in case the in-memory inode orphan list * isn't empty. The on-disk one can be non-empty if we've * detected an error and taken the fs readonly, but the * in-memory list had better be clean by this point. */ if (!list_empty(&sbi->s_orphan)) dump_orphan_list(sb, sbi); J_ASSERT(list_empty(&sbi->s_orphan)); invalidate_bdev(sb->s_bdev); if (sbi->journal_bdev && sbi->journal_bdev != sb->s_bdev) { /* * Invalidate the journal device's buffers. We don't want them * floating about in memory - the physical journal device may * hotswapped, and it breaks the `ro-after' testing code. */ sync_blockdev(sbi->journal_bdev); invalidate_bdev(sbi->journal_bdev); ext4_blkdev_remove(sbi); } sb->s_fs_info = NULL; kfree(sbi); return;}static struct kmem_cache *ext4_inode_cachep;/* * Called inside transaction, so use GFP_NOFS */static struct inode *ext4_alloc_inode(struct super_block *sb){ struct ext4_inode_info *ei; ei = kmem_cache_alloc(ext4_inode_cachep, GFP_NOFS); if (!ei) return NULL;#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL ei->i_acl = EXT4_ACL_NOT_CACHED; ei->i_default_acl = EXT4_ACL_NOT_CACHED;#endif ei->i_block_alloc_info = NULL; ei->vfs_inode.i_version = 1; memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache)); return &ei->vfs_inode;}static void ext4_destroy_inode(struct inode *inode){ if (!list_empty(&(EXT4_I(inode)->i_orphan))) { printk("EXT4 Inode %p: orphan list check failed!\n", EXT4_I(inode)); print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 4, EXT4_I(inode), sizeof(struct ext4_inode_info), true); dump_stack(); } kmem_cache_free(ext4_inode_cachep, EXT4_I(inode));}static void init_once(struct kmem_cache *cachep, void *foo){ struct ext4_inode_info *ei = (struct ext4_inode_info *) foo; INIT_LIST_HEAD(&ei->i_orphan);#ifdef CONFIG_EXT4DEV_FS_XATTR init_rwsem(&ei->xattr_sem);#endif mutex_init(&ei->truncate_mutex); inode_init_once(&ei->vfs_inode);}static int init_inodecache(void){ ext4_inode_cachep = kmem_cache_create("ext4_inode_cache", sizeof(struct ext4_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), init_once); if (ext4_inode_cachep == NULL) return -ENOMEM; return 0;}static void destroy_inodecache(void){ kmem_cache_destroy(ext4_inode_cachep);}static void ext4_clear_inode(struct inode *inode){ struct ext4_block_alloc_info *rsv = EXT4_I(inode)->i_block_alloc_info;#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL if (EXT4_I(inode)->i_acl && EXT4_I(inode)->i_acl != EXT4_ACL_NOT_CACHED) { posix_acl_release(EXT4_I(inode)->i_acl); EXT4_I(inode)->i_acl = EXT4_ACL_NOT_CACHED; } if (EXT4_I(inode)->i_default_acl && EXT4_I(inode)->i_default_acl != EXT4_ACL_NOT_CACHED) { posix_acl_release(EXT4_I(inode)->i_default_acl); EXT4_I(inode)->i_default_acl = EXT4_ACL_NOT_CACHED; }#endif ext4_discard_reservation(inode); EXT4_I(inode)->i_block_alloc_info = NULL; if (unlikely(rsv)) kfree(rsv);}static inline void ext4_show_quota_options(struct seq_file *seq, struct super_block *sb){#if defined(CONFIG_QUOTA) struct ext4_sb_info *sbi = EXT4_SB(sb); if (sbi->s_jquota_fmt) seq_printf(seq, ",jqfmt=%s", (sbi->s_jquota_fmt == QFMT_VFS_OLD) ? "vfsold": "vfsv0"); if (sbi->s_qf_names[USRQUOTA]) seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]); if (sbi->s_qf_names[GRPQUOTA]) seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]); if (sbi->s_mount_opt & EXT4_MOUNT_USRQUOTA) seq_puts(seq, ",usrquota"); if (sbi->s_mount_opt & EXT4_MOUNT_GRPQUOTA) seq_puts(seq, ",grpquota");#endif}/* * Show an option if * - it's set to a non-default value OR * - if the per-sb default is different from the global default */static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs){ struct super_block *sb = vfs->mnt_sb; struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_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=%llu", 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 & EXT4_DEFM_BSDGROUPS)) seq_puts(seq, ",nogrpid"); if (sbi->s_resuid != EXT4_DEF_RESUID || le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID) { seq_printf(seq, ",resuid=%u", sbi->s_resuid); } if (sbi->s_resgid != EXT4_DEF_RESGID || le16_to_cpu(es->s_def_resgid) != EXT4_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 == EXT4_ERRORS_PANIC || def_errors == EXT4_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_EXT4_FS_XATTR if (test_opt(sb, XATTR_USER)) seq_puts(seq, ",user_xattr"); if (!test_opt(sb, XATTR_USER) && (def_mount_opts & EXT4_DEFM_XATTR_USER)) { seq_puts(seq, ",nouser_xattr"); }#endif#ifdef CONFIG_EXT4_FS_POSIX_ACL if (test_opt(sb, POSIX_ACL)) seq_puts(seq, ",acl"); if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT4_DEFM_ACL)) seq_puts(seq, ",noacl");#endif if (!test_opt(sb, RESERVATION)) seq_puts(seq, ",noreservation"); if (sbi->s_commit_interval) { seq_printf(seq, ",commit=%u", (unsigned) (sbi->s_commit_interval / HZ)); } if (test_opt(sb, BARRIER)) seq_puts(seq, ",barrier=1"); if (test_opt(sb, NOBH)) seq_puts(seq, ",nobh"); if (!test_opt(sb, EXTENTS)) seq_puts(seq, ",noextents"); if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) seq_puts(seq, ",data=journal"); else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) seq_puts(seq, ",data=ordered"); else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) seq_puts(seq, ",data=writeback"); ext4_show_quota_options(seq, sb); return 0;}static struct inode *ext4_nfs_get_inode(struct super_block *sb, u64 ino, u32 generation){ struct inode *inode; if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO) return ERR_PTR(-ESTALE); if (ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count)) return ERR_PTR(-ESTALE); /* iget isn't really right if the inode is currently unallocated!! * * ext4_read_inode will return a bad_inode if the inode had been * deleted, so we should be safe. * * Currently we don't know the generation for parent directory, so * a generation of 0 means "accept any" */ inode = iget(sb, ino); if (inode == NULL) return ERR_PTR(-ENOMEM); if (is_bad_inode(inode) || (generation && inode->i_generation != generation)) { iput(inode); return ERR_PTR(-ESTALE); } return inode;}static struct dentry *ext4_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, ext4_nfs_get_inode);}static struct dentry *ext4_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, ext4_nfs_get_inode);}#ifdef CONFIG_QUOTA#define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group")#define QTYPE2MOPT(on, t) ((t)==USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA))static int ext4_dquot_initialize(struct inode *inode, int type);static int ext4_dquot_drop(struct inode *inode);static int ext4_write_dquot(struct dquot *dquot);static int ext4_acquire_dquot(struct dquot *dquot);static int ext4_release_dquot(struct dquot *dquot);static int ext4_mark_dquot_dirty(struct dquot *dquot);static int ext4_write_info(struct super_block *sb, int type);static int ext4_quota_on(struct super_block *sb, int type, int format_id, char *path);static int ext4_quota_on_mount(struct super_block *sb, int type);static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data, size_t len, loff_t off);static ssize_t ext4_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off);static struct dquot_operations ext4_quota_operations = { .initialize = ext4_dquot_initialize, .drop = ext4_dquot_drop, .alloc_space = dquot_alloc_space, .alloc_inode = dquot_alloc_inode, .free_space = dquot_free_space, .free_inode = dquot_free_inode, .transfer = dquot_transfer, .write_dquot = ext4_write_dquot, .acquire_dquot = ext4_acquire_dquot, .release_dquot = ext4_release_dquot, .mark_dirty = ext4_mark_dquot_dirty, .write_info = ext4_write_info};static struct quotactl_ops ext4_qctl_operations = { .quota_on = ext4_quota_on, .quota_off = vfs_quota_off, .quota_sync = vfs_quota_sync, .get_info = vfs_get_dqinfo, .set_info = vfs_set_dqinfo, .get_dqblk = vfs_get_dqblk, .set_dqblk = vfs_set_dqblk};#endifstatic const struct super_operations ext4_sops = { .alloc_inode = ext4_alloc_inode, .destroy_inode = ext4_destroy_inode, .read_inode = ext4_read_inode, .write_inode = ext4_write_inode, .dirty_inode = ext4_dirty_inode, .delete_inode = ext4_delete_inode, .put_super = ext4_put_super, .write_super = ext4_write_super, .sync_fs = ext4_sync_fs, .write_super_lockfs = ext4_write_super_lockfs, .unlockfs = ext4_unlockfs, .statfs = ext4_statfs, .remount_fs = ext4_remount, .clear_inode = ext4_clear_inode, .show_options = ext4_show_options,#ifdef CONFIG_QUOTA .quota_read = ext4_quota_read, .quota_write = ext4_quota_write,#endif};static const struct export_operations ext4_export_ops = { .fh_to_dentry = ext4_fh_to_dentry, .fh_to_parent = ext4_fh_to_parent, .get_parent = ext4_get_parent,};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_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh, Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev, Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota, Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota, Opt_grpquota, Opt_extents, Opt_noextents,};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, "nocheck"}, {Opt_nocheck, "check=none"}, {Opt_debug, "debug"}, {Opt_oldalloc, "oldalloc"}, {Opt_orlov, "orlov"}, {Opt_user_xattr, "user_xattr"}, {Opt_nouser_xattr, "nouser_xattr"}, {Opt_acl, "acl"}, {Opt_noacl, "noacl"}, {Opt_reservation, "reservation"}, {Opt_noreservation, "noreservation"}, {Opt_noload, "noload"}, {Opt_nobh, "nobh"}, {Opt_bh, "bh"}, {Opt_commit, "commit=%u"}, {Opt_journal_update, "journal=update"}, {Opt_journal_inum, "journal=%u"}, {Opt_journal_dev, "journal_dev=%u"}, {Opt_abort, "abort"}, {Opt_data_journal, "data=journal"}, {Opt_data_ordered, "data=ordered"}, {Opt_data_writeback, "data=writeback"}, {Opt_offusrjquota, "usrjquota="}, {Opt_usrjquota, "usrjquota=%s"}, {Opt_offgrpjquota, "grpjquota="}, {Opt_grpjquota, "grpjquota=%s"}, {Opt_jqfmt_vfsold, "jqfmt=vfsold"}, {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"}, {Opt_grpquota, "grpquota"}, {Opt_noquota, "noquota"}, {Opt_quota, "quota"}, {Opt_usrquota, "usrquota"}, {Opt_barrier, "barrier=%u"}, {Opt_extents, "extents"}, {Opt_noextents, "noextents"}, {Opt_err, NULL}, {Opt_resize, "resize"},};static ext4_fsblk_t get_sb_block(void **data){ ext4_fsblk_t sb_block; char *options = (char *) *data; if (!options || strncmp(options, "sb=", 3) != 0) return 1; /* Default location */ options += 3; /*todo: use simple_strtoll with >32bit ext4 */ sb_block = simple_strtoul(options, &options, 0); if (*options && *options != ',') { printk("EXT4-fs: Invalid sb specification: %s\n", (char *) *data); return 1; } if (*options == ',') options++; *data = (void *) options; return sb_block;}static int parse_options (char *options, struct super_block *sb, unsigned int *inum, unsigned long *journal_devnum, ext4_fsblk_t *n_blocks_count, int is_remount){ struct ext4_sb_info *sbi = EXT4_SB(sb); char * p; substring_t args[MAX_OPT_ARGS]; int data_opt = 0; int option;#ifdef CONFIG_QUOTA
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -