今天来看一个ext2文件系统里的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/smp_lock.h>
#include <linux/vfs.h>
#include <linux/seq_file.h>
#include <linux/mount.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);
/*ext2的打印错误信息的函数,参数有可变参数*/
void ext2_error (struct super_block * sb, const char * function,
const char * fmt, ...)
{
va_list args;
/*内存里存放的超级块信息结构体*/
struct ext2_sb_info *sbi = EXT2_SB(sb);
/*ext2硬盘上存放的超级块*/
struct ext2_super_block *es = sbi->s_es;
/*如果文件系统不是只读的*/
if (!(sb->s_flags & MS_RDONLY)) {
/*出错了,就在ext2_sb_info结构体的对应位上或上对应位,标记文件系统有错误发生*/
sbi->s_mount_state |= EXT2_ERROR_FS;
/*ext2_super_block结构体上对应位置位,标识文件系统有错误发生*/
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);
}
/*更新文件系统为动态的inode的修改级别*/
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);
/*设置第一个inode号,inode大小*/
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);
/* 此处不处理 es->s_feature_*compat*/
/* es->s_uuid会被e2fsck处理 */
/* 超级块的其他字段应该是0,如果不是,说明他们正在被使用,我们可以接下来让e2fsck来解决*/
}
/*释放正在使用的超级块*/
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;
/*释放ext2_sb_info结构体*/
kfree(sbi);
return;
}
/*用来存放ext2的inode的缓冲区*/
static struct kmem_cache * ext2_inode_cachep;
/*ext2分配一个空的inode*/
static struct inode *ext2_alloc_inode(struct super_block *sb)
{
struct ext2_inode_info *ei;
/*先从ext2_inode_cachep上分配内存对应的ext2_inode_info结构体*/
ei = (struct ext2_inode_info *)kmem_cache_alloc(ext2_inode_cachep, GFP_KERNEL);
if (!ei)
return NULL;
/*配置了acl,先初始化acl为没有映射状态*/
#ifdef CONFIG_EXT2_FS_POSIX_ACL
ei->i_acl = EXT2_ACL_NOT_CACHED;
ei->i_default_acl = EXT2_ACL_NOT_CACHED;
#endif
/*版本号*/
ei->vfs_inode.i_version = 1;
return &ei->vfs_inode;
}
/*释放一个inode*/
static void ext2_destroy_inode(struct inode *inode)
{
/*调用内存的缓冲释放函数,从ext2_inode_cachep上释放*/
kmem_cache_free(ext2_inode_cachep, EXT2_I(inode));
}
/*初始化ext2_inode_info的指针*/
static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
{
/*先转化获得ext2_inode_info指针*/
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
/*初始化vfs层的inode*/
inode_init_once(&ei->vfs_inode);
}
/*初始化ext2_inode_cachep的缓冲区*/
static int init_inodecache(void)
{
/*创建一块可延展的内存缓冲区,并使用init_once函数初始化,然后赋值给ext2_inode_cachep,kmem_cache_create是内存子系统的函数,第一个参数是这个缓冲区的名字,第二个参数是缓冲区的大小,先设置为一个ext2_inode_info的大小,第三个参数是对齐,第四个参数flag,标志这缓冲区可延展,就是可以向后继续分配,并且可以重新设置大小,第五个参数是初始化函数*/
ext2_inode_cachep = kmem_cache_create("ext2_inode_cache",
sizeof(struct ext2_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
init_once, NULL);
/*失败了,就返回内存不够的错误*/
if (ext2_inode_cachep == NULL)
return -ENOMEM;
return 0;
}
/*销毁上个函数创建的ext2_inode_cachep*/
static void destroy_inodecache(void)
{
/*内存子系统的内存销毁函数*/
kmem_cache_destroy(ext2_inode_cachep);
}
/*清理inode的额外的内存资源,一般是指acl结构体*/
static void ext2_clear_inode(struct inode *inode)
{
/*如果没有配置acl,就不用释放了*/
#ifdef CONFIG_EXT2_FS_POSIX_ACL
struct ext2_inode_info *ei = EXT2_I(inode);
/*如果i_acl不是未映射状态就说明需要释放*/
if (ei->i_acl && ei->i_acl != EXT2_ACL_NOT_CACHED) {
/*之前讲过的函数,释放acl结构体*/
posix_acl_release(ei->i_acl);
/*标记为未映射*/
ei->i_acl = EXT2_ACL_NOT_CACHED;
}
/*如果i_default_acl不是未映射状态就说明需要释放*/
if (ei->i_default_acl && ei->i_default_acl != EXT2_ACL_NOT_CACHED) {
/*之前讲过的函数,释放acl结构体*/
posix_acl_release(ei->i_default_acl);
/*标记为未映射*/
ei->i_default_acl = EXT2_ACL_NOT_CACHED;
}
#endif
}
/*得到文件系统的挂载选项,存放在seq里*/
static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs)
{
/*先得到超级块的内存的信息结构体,大部分信息都在这个结构体里放着*/
struct ext2_sb_info *sbi = EXT2_SB(vfs->mnt_sb);
/*EXT2_MOUNT_GRPID这个标志代表着在目录里创建文件要设置这个文件的组为这个目录的*/
if (sbi->s_mount_opt & EXT2_MOUNT_GRPID)
seq_puts(seq, ",grpid");
/*如果配置的配额*/
#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_QUOTA
static 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);
#endif
/*超级块的操作函数集合*/
static 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,
.put_inode = ext2_put_inode,
.delete_inode = ext2_delete_ino