Linux内核源码分析–文件系统(六、Super.c) – YuZhiHui

put_super()

1、释放指定设备的超级块:首先是对设备块号检查以及检查设备块号对应的超级块的合法性;然后释放8块i节点位图和逻辑块位图,最后释放掉超级块;

//释放指定设备的超级块,//释放设备所使用的超级块数组项(s_dev=0),并释放该设备i节点位图和逻辑块所占用的高速缓存块//如果超级块对应的是文件系统根文件系统,或者其i节点上已经安装其他的文件系统,则不能释放该超级块void put_super(int dev){struct super_block * sb;struct m_inode * inode;int i;if (dev == ROOT_DEV) {//如果是根设备printk("root diskette changed: prepare for armageddon\n\r");return;}if (!(sb = get_super(dev)))//没找到超级块return;if (sb->s_imount) {//在卸载文件系统时会先把s_imount设置成NULLprintk("Mounted disk changed - tssk, tssk\n\r");return;}lock_super(sb);sb->s_dev = 0;//设置为0,表示释放该设备上的文件系统超级块for(i=0;i<I_MAP_SLOTS;i++)brelse(sb->s_imap[i]);//释放8块i节点位图for(i=0;i<Z_MAP_SLOTS;i++)//释放8块逻辑块位图brelse(sb->s_zmap[i]);free_super(sb);//释放超级块return;}

read_super()

2、读取指定设备的超级块:首先也是对设备号检查,然后通过get_super(dev)函数获取到指定设备号的超级块,有直接返回得到的超级块;如果没有,则在超级块表中查找一个空闲位置,新创建一个超级块;接着把新创建的超级块进行一些缓存属性设置,用来指定一个文件系统;

这里要说明下因为超级块结构有两种,一种是内存中使用的super_block,其中包括文件系统的基本信息,还包括其在缓存区中的一些信息;第二种是磁盘上的d_super_block,其和内存中使用的结构的前几项(文件系统的基本信息)是一样的;

所以前面一步设置了文件系统在缓存中的一些基本信息,接下来就要从磁盘上得到超级块的文件系统基本信息(这一项和super_block前几个字段一样);这样基本就设置好了内存使用的超级块并放到相应的超级块数组中;

接下来几步就是初始化些位图和,对文件系统进行检查(检查文件系统如果有问题,则释放掉开始初始化好的数据),最后还要设置下位图比特位0的值(因为位图比特位0在系统中是不使用的)

//读取指定设备的超级块static struct super_block * read_super(int dev){struct super_block * s;struct buffer_head * bh;int i,block;if (!dev)return NULL;check_disk_change(dev);//如果更换过设备,则文件系统释放掉if (s = get_super(dev))return s;//得到指定设备的超级块,则返回for (s = 0+super_block ;; s++) {//在超级块数组中查找一个空的超级块if (s >= NR_SUPER+super_block)return NULL;if (!s->s_dev)break;}//对找到的空超级块项后,进行属性设置(用来指定文件系统)s->s_dev = dev;s->s_isup = NULL;s->s_imount = NULL;s->s_time = 0;s->s_rd_only = 0;s->s_dirt = 0;lock_super(s);if (!(bh = bread(dev,1))) {//从设备上读取超级块信息到缓存区中s->s_dev=0;//读取不到超级块信息,则释放掉超级块数组中选定的元素free_super(s);return NULL;}//把超级块信息从设备映射的缓存区中复制到超级块数组中*((struct d_super_block *) s) =*((struct d_super_block *) bh->b_data);brelse(bh);if (s->s_magic != SUPER_MAGIC) {//文件系统魔数表示一个文件系统释放正确s->s_dev = 0;free_super(s);return NULL;}for (i=0;i<I_MAP_SLOTS;i++)//初始化i节点位图s->s_imap[i] = NULL;for (i=0;i<Z_MAP_SLOTS;i++)//初始化逻辑块位图s->s_zmap[i] = NULL;block=2;for (i=0 ; i < s->s_imap_blocks ; i++)//从设备上读取i节点位图逻辑块放在缓存区中if (s->s_imap[i]=bread(dev,block))block++;elsebreak;for (i=0 ; i < s->s_zmap_blocks ; i++)//从设备上读取逻辑块位图放在缓存区中if (s->s_zmap[i]=bread(dev,block))block++;elsebreak;//测试读取的逻辑块数是否等于实际总数if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) {for(i=0;i<I_MAP_SLOTS;i++)//不等于,表示文件系统位图有问题,释放掉所有资源brelse(s->s_imap[i]);for(i=0;i<Z_MAP_SLOTS;i++)brelse(s->s_zmap[i]);s->s_dev=0;free_super(s);return NULL;}//下面是把位图的第一个比特位设置为1,也就是位图中第一个比特位不能用s->s_imap[0]->b_data[0] |= 1;s->s_zmap[0]->b_data[0] |= 1;free_super(s);return s;}

sys_umount() 3、卸载文件系统:首先是通过设备名称得到i节点,再根据i节点得到设备号,检查该i节点是否为目录节点,检查完以后就要释放掉i节点;接着检查下设备号以及设备号对应的超级块是否合法;然后检查下是否有其他进程使用该文件系统中的i节点;最后做些属性设置,同步下数据;

//卸载文件系统//参数 dev_name是文件系统所在设备的设备文件名int sys_umount(char * dev_name){struct m_inode * inode;struct super_block * sb;int dev;if (!(inode=namei(dev_name)))//根据设备文件名找到i节点return -ENOENT;dev = inode->i_zone[0];//取其中的设备号if (!S_ISBLK(inode->i_mode)) {//文件系统要存放在块设备上,如果不是块设备文件,则释放i节点iput(inode);return -ENOTBLK;}iput(inode);//上面是通过i节点来获取到设备号,已经获取到了设备,那么就把i节点释放掉if (dev==ROOT_DEV)//根文件系统不能被卸载return -EBUSY;//是否找到设备的超级块,该设备上是否安装过文件系统(是否能找到文件系统安装的i节点)if (!(sb=get_super(dev)) || !(sb->s_imount))return -ENOENT;if (!sb->s_imount->i_mount)//安装标志是否置位printk("Mounted inode has i_mount=0\n");for (inode=inode_table+0 ; inode<inode_table+NR_INODE ; inode++)if (inode->i_dev==dev && inode->i_count)//查看下是否有其他进程在使用i节点return -EBUSY;//因为有其他进程还在使用该文件系统,则不能卸载sb->s_imount->i_mount=0;//被安装到的i节点安装标志置空iput(sb->s_imount);//释放被安装到的i节点sb->s_imount = NULL;iput(sb->s_isup);//释放根文件目录中的i节点sb->s_isup = NULL;put_super(dev);sync_dev(dev);//上面修改的都是在高速缓存区中的,所以最后要同步到块设备中去return 0;}

sys_mount()

4、安装文件系统:开始和上面一样通过设备名称得到设备号;然后判断下将要被安装的目录节点是否合法(是否是目录i节点?该节点是否安装了其他文件系统?);最后设置下超级块结构体属性就可以了;

//安装文件系统//参会 dev_name 设备文件名;dir_name 安装到的目录名;rw_flag 被安装文件系统的权限//将被加载的地方必须是一个目录名,并且对应的i节点没有被其他程序占用int sys_mount(char * dev_name, char * dir_name, int rw_flag){struct m_inode * dev_i, * dir_i;struct super_block * sb;int dev;if (!(dev_i=namei(dev_name)))return -ENOENT;dev = dev_i->i_zone[0];if (!S_ISBLK(dev_i->i_mode)) {iput(dev_i);return -EPERM;}iput(dev_i);//上面几步和卸载文件系统时一样,通过设备名得到设备号//下面是对文件系统将要安装的安装点检查if (!(dir_i=namei(dir_name)))//得到将被安装的目录i节点return -ENOENT;//如果该节点引用不为1,或者是根文件系统的节点号,出错退出if (dir_i->i_count != 1 || dir_i->i_num == ROOT_INO) {iput(dir_i);return -EBUSY;}//如果该i节点对应的不是一个目录,也出错退出;//因为文件系统必须安装在一个目录名上if (!S_ISDIR(dir_i->i_mode)) {iput(dir_i);return -EPERM;}//读取超级块操作失败,则释放上面得到的目录i节点if (!(sb=read_super(dev))) {iput(dir_i);return -EBUSY;}if (sb->s_imount) {//将要安装的文件系统已经安装在其他地方,释放目录i节点iput(dir_i);return -EBUSY;}if (dir_i->i_mount) {//将要被安装的目录上已经安装了其他文件系统,出错返回iput(dir_i);return -EPERM;}//当所有条件满足时,开始设置安装属性sb->s_imount=dir_i;dir_i->i_mount=1;dir_i->i_dirt=1;/* NOTE! we don't iput(dir_i) */return 0;/* we do that in umount */}

mount_root() 5、安装根文件系统,这是系统初始化的一部分,会同时初始化文件表数组和超级块数组;首先是初始化文件表数组,和初始化超级块数组;接着就是安装根文件系统,对根i节点进行一些设置;最后打印下整个文件系统的所有资源;

//安装文件根系统//这是系统初始化的一部分,将会初始化文件表数组和超级块数组//然后读取根文件系统超级块,并取得文件系统根i节点//最后统计并显示出根文件系统上的可用资源,空闲块数和空闲i节点数void mount_root(void){int i,free;struct super_block * p;struct m_inode * mi;//简单判断磁盘i节点是否为32个字节if (32 != sizeof (struct d_inode))panic("bad i-node size");//下面是初始化文件表数组,共64项,系统同时只能打开54个文件和超级块表for(i=0;i<NR_FILE;i++)file_table[i].f_count=0;//引用全部设置为0,表示空闲状态if (MAJOR(ROOT_DEV) == 2) {//如果是软盘,则提示插入软盘printk("Insert root floppy and press ENTER");wait_for_keypress();}//下面是对超级块表进行初始化设置for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++) {p->s_dev = 0;p->s_lock = 0;p->s_wait = NULL;}//下面开始安装根文件系统if (!(p=read_super(ROOT_DEV)))//得到根文件系统的超级块panic("Unable to mount root");if (!(mi=iget(ROOT_DEV,ROOT_INO)))//根据设备号和i节点号得到在内存根i节点的指针panic("Unable to read root i-node");//下面是初始化时,对根文件系统的i节点mi->i_count += 3 ;/* NOTE! it is logically used 4 times, not 1 */p->s_isup = p->s_imount = mi;//被安装到的根文件目录i节点,该文件系统被安装到的i节点current->pwd = mi;//当前工作目录i节点current->root = mi;//当前根目录i节点free=0;i=p->s_nzones;//根设备的逻辑块总数while (-- i >= 0)if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data))free++;printk("%d/%d free blocks\n\r",free,p->s_nzones);free=0;i=p->s_ninodes+1;//根设备i节点的总数,+1表示把第一个不用的i节点也统计进来while (-- i >= 0)if (!set_bit(i&8191,p->s_imap[i>>13]->b_data))free++;printk("%d/%d free inodes\n\r",free,p->s_ninodes);}

http://blog.csdn.net/yuzhihui_no1/article/details/43954819

若有不正确之处,望大家指正,共同学习!谢谢!!

成功是奋斗的结果,而奋斗是成功的必经之路。

Linux内核源码分析–文件系统(六、Super.c) – YuZhiHui

相关文章:

你感兴趣的文章:

标签云: