Chinaunix首页 | 论坛 | 博客
  • 博客访问: 585563
  • 博文数量: 137
  • 博客积分: 4040
  • 博客等级: 上校
  • 技术积分: 1584
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-08 13:05
文章分类

全部博文(137)

文章存档

2011年(10)

2010年(23)

2009年(104)

分类: LINUX

2009-08-15 23:32:59

/*
 * linux/fs/super.c
 *
 * (C) 1991 Linus Torvalds
 */


/*
 * super.c contains code to handle the super-block tables.
 */

#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/system.h>

#include <errno.h>
#include <sys/stat.h>

int sync_dev(int dev);//对指定设备进行高速缓冲数据与设备上数据的同步操作

void wait_for_keypress(void);//等待按键


/* set_bit uses setb, as gas doesn't recognize setc */
#define set_bit(bitnr,addr) ({ \
register int __res __asm__("ax"); \
__asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \
__res; })//测试指定偏移处比特位的值,并返回该原比特位值


struct super_block super_block[NR_SUPER];// 超级块结构数组(共8 项)

/* this is initialized in init/main.c */
int ROOT_DEV = 0;// ROOT_DEV 已在init/main.c 中被初始化 */


static void lock_super(struct super_block * sb)// 锁定指定的超级块

{
    cli();//关中 段

    while (sb->s_lock)
        sleep_on(&(sb->s_wait));//将当前进程睡眠,链入sb->s_wait队列

    sb->s_lock = 1;
    sti();//开中断

}

static void free_super(struct super_block * sb)// 对指定超级块解锁。(如果使用ulock_super 这个名称则更妥帖)

{
    cli();//关中断

    sb->s_lock = 0;
    wake_up(&(sb->s_wait));//唤醒*p所指向的任务。*p为任务等待队列头指针,由于新等待任务是插入等待队列头指针处的,因此唤醒的是最后进入等待队列的任务

    sti();//开中断

}

static void wait_on_super(struct super_block * sb)// 睡眠等待超级块解锁

{
    cli();//关中断

    while (sb->s_lock)
        sleep_on(&(sb->s_wait));//将当前任务置为不可中断的等待状态,并将此放入睡眼队列P中

    sti();//开中断    

}

struct super_block * get_super(int dev)// 取指定设备的超级块。返回该超级块结构指针,查找超级块列表

{
    struct super_block * s;

    if (!dev)// 如果没有指定设备,则返回空指针。

        return NULL;
    s = 0+super_block;// s 指向超级块数组开始处。

    while (s < NR_SUPER+super_block)//搜索整个超级块数组,寻找指定设备的超级块

        if (s->s_dev == dev) {
            wait_on_super(s);// 睡眠等待超级块解锁

            if (s->s_dev == dev)//在睡眠期间该超级块有可能被其他设备使用,所以还要进一次的判断,如果是则返回

                return s;
            s = 0+super_block;//否则,则头再一次查找

        } else
            s++;
    return NULL;
}

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) {//被安装到的i 节点,安装的i节点还没有被处理过

        printk("Mounted disk changed - tssk, tssk\n\r");
        return;
    }
    lock_super(sb);//锁定指定的超级块

    sb->s_dev = 0;//置该超级块对应的设备号字段为0,也即即将放弃该超级块

    for(i=0;i<I_MAP_SLOTS;i++)//释放该设备i 节点位图在缓冲区中所占用的缓冲块

        brelse(sb->s_imap[i]);
    for(i=0;i<Z_MAP_SLOTS;i++)//释放该设备逻辑块位图在缓冲区中所占用的缓冲块

        brelse(sb->s_zmap[i]);
    free_super(sb);// 对指定超级块解锁

    return;
}

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++) {// 否则,首先在超级块数组中找出一个空项(也即其s_dev=0 的项)。如果数组已经占满则返回空指针

        if (s >= NR_SUPER+super_block)
            return NULL;
        if (!s->s_dev)
            break;
    }
    s->s_dev = dev;// 找到超级块空项后,就将该超级块用于指定设备

    s->s_isup = NULL;// 被安装的文件系统根目录的i 节点。(isup-super i)

    s->s_imount = NULL;// 被安装到的i 节点。

    s->s_time = 0;// 修改时间。

    s->s_rd_only = 0;// 只读标志。

    s->s_dirt = 0;// 已修改(脏)标志。

    lock_super(s);// 锁定指定的超级块

    if (!(bh = bread(dev,1))) {//读此设备的1号磁盘块内容(超级块的信息)到高速缓冲块区中来,0号磁盘块内容为引导块信息

        s->s_dev=0;// 超级块所在的设备号,为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_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;//从第2号块开始,0为引导块号,1为超级块号,2为i 节点位图开始的块号(最多8个),再往后是逻辑块位图开始的块号(最多8个),再往后是数据区

    for (i=0 ; i < s->s_imap_blocks ; i++)//取设备i 节点位图信息到内存超级块列表中

        if (s->s_imap[i]=bread(dev,block))
            block++;
        else
            break;
    for (i=0 ; i < s->s_zmap_blocks ; i++)//取设备逻辑块号位图信息到内存超级块列表中

        if (s->s_zmap[i]=bread(dev,block))
            block++;
        else
            break;
    if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) {//如果读出的位图逻辑块数不等于位图应该占有的逻辑块数,说明文件系统位图信息有问题,超级块初始化失败。因此只能释放前面申请的所有资源,返回空指针并退出

        for(i=0;i<I_MAP_SLOTS;i++)
            brelse(s->s_imap[i]);// 释放i 节点位图和逻辑块位图占用的高速缓冲区

        for(i=0;i<Z_MAP_SLOTS;i++)
            brelse(s->s_zmap[i]);// 释放i 节点位图和逻辑块位图占用的高速缓冲区

        s->s_dev=0;////释放上面选定的超级块数组中的项

        free_super(s);// 对指定超级块解锁

        return NULL;
    }//以下一切成功

    s->s_imap[0]->b_data[0] |= 1;//对于申请空闲i 节点的函数来讲,如果设备上所有的i 节点已经全被使用,则查找函数会返回0 值。因此0 号i 节点是不能用的,所以这里将位图中的最低位设置为1,以防止文件系统分配0 号i 节点

    s->s_zmap[0]->b_data[0] |= 1;
    free_super(s);// 对指定超级块解锁

    return s;
}

int sys_umount(char * dev_name)//卸载文件系统的系统调用函数,参数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];//并取其中的设备号,设备文件所定义设备设备号保存在其i 节点的i_zone[0]中

    if (!S_ISBLK(inode->i_mode)) {//由于文件系统需要存放在块设备中,如果不是块设备文件,则释放刚申请的i 节点dev_i,返回出错码

        iput(inode);// 释放inode节点(写入设备)

        return -ENOTBLK;
    }
    iput(inode);// 释放设备文件名的i 节点,为取设备号而建立的inode节点已完成使命

    if (dev==ROOT_DEV)// 如果设备是根文件系统,则不能被卸载,返回出错号

        return -EBUSY;
    if (!(sb=get_super(dev)) || !(sb->s_imount))// 如果取设备的超级块失败,或者该设备文件系统没有安装过,则返回出错码

        return -ENOENT;
    if (!sb->s_imount->i_mount)// 如果超级块所指明的被安装到的i 节点没有置位其安装标志,则显示警告信息。

        printk("Mounted inode has i_mount=0\n");
    for (inode=inode_table+0 ; inode<inode_table+NR_INODE ; inode++)// 查找内存中i 节点表,看是否有进程在使用该设备上的文件,如果有则返回忙出错码

        if (inode->i_dev==dev && inode->i_count)// i_dev, i 节点所在的设备号。i_count,i 节点被使用的次数,0 表示该i 节点空闲。

                return -EBUSY;
    sb->s_imount->i_mount=0;// 复位被安装到的i 节点的安装标志

    iput(sb->s_imount);//并释放该i 节点

    sb->s_imount = NULL;//置超级块中被安装i 节点字段为空

    iput(sb->s_isup);//并释放设备文件系统的根i 节点

    sb->s_isup = NULL;//置超级块中被安装系统 根i 节点指针为空

    put_super(dev);// 释放该设备的超级块以及位图占用的缓冲块

    sync_dev(dev);//并对该设备执行高速缓冲与设备上数据的同步操作

    return 0;
}

int sys_mount(char * dev_name, char * dir_name, int rw_flag)//安装文件系统调用函数

{//参数dev_name 是设备文件名,dir_name 是安装到的目录名,rw_flag 被安装文件的读写标志

    struct m_inode * dev_i, * dir_i;
    struct super_block * sb;
    int dev;

    if (!(dev_i=namei(dev_name)))//首先根据设备文件名找到对应的i 节点,

        return -ENOENT;
    dev = dev_i->i_zone[0];//并取其中的设备号,对于块特殊设备文件,设备号在i 节点的i_zone[0]中

    if (!S_ISBLK(dev_i->i_mode)) {// 如果不是块设备文件,则释放刚取得的i 节点dev_i,返回出错码

        iput(dev_i);
        return -EPERM;
    }
    iput(dev_i);// 释放该设备文件的i 节点dev_i,为取设备号而建立的inode节点已完成使命

    if (!(dir_i=namei(dir_name)))// 根据给定的目录文件名找到对应的i 节点dir_i

        return -ENOENT;
    if (dir_i->i_count != 1 || dir_i->i_num == ROOT_INO) {// 如果该i 节点的引用计数不为1(仅在这里引用),或者该i 节点的节点号是根文件系统的节点 号1,则释放该i 节点,返回出错码

        iput(dir_i);
        return -EBUSY;
    }
    if (!S_ISDIR(dir_i->i_mode)) {// 如果该节点不是一个目录文件节点,则也释放该i 节点,返回出错码

        iput(dir_i);
        return -EPERM;
    }
    if (!(sb=read_super(dev))) {//从设备上读取超级块到缓冲区中,读取将安装文件系统的超级块,如果失败则也释放该i 节点,返回出错码

        iput(dir_i);
        return -EBUSY;
    }
    if (sb->s_imount) {// 如果将要被安装的文件系统已经安装在其它地方,则释放该i 节点,返回出错码

        iput(dir_i);
        return -EBUSY;
    }
    if (dir_i->i_mount) {// 如果将要安装到的i 节点已经安装了文件系统(安装标志已经置位),则释放该i 节点,返回出错码

        iput(dir_i);
        return -EPERM;
    }
    sb->s_imount=dir_i;// 被安装文件系统超级块的“被安装到i 节点”字段指向安装到的目录名的i 节点

    dir_i->i_mount=1;// 设置安装位置i 节点的安装标志

    dir_i->i_dirt=1;//节点已修改标志        /* NOTE! we don't iput(dir_i) */

    return 0;            /* we do that in umount */
}

void mount_root(void)//安装根文件系统,该函数是在系统开机初始化设置时(sys_setup())调用的

{
    int i,free;
    struct super_block * p;
    struct m_inode * mi;

    if (32 != sizeof (struct d_inode))// 如果磁盘i 节点结构不是32 个字节,则出错,死机

        panic("bad i-node size");
    for(i=0;i<NR_FILE;i++)// 初始化文件表数组(共64 项,也即系统同时只能打开64 个文件),将所有文件结构中的引用计数设置为0

        file_table[i].f_count=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++) {// 初始化超级块数组(共8 项)

        p->s_dev = 0;
        p->s_lock = 0;
        p->s_wait = NULL;
    }
    if (!(p=read_super(ROOT_DEV)))//读根设备上超级块到缓冲区p中

        panic("Unable to mount root");
    if (!(mi=iget(ROOT_DEV,ROOT_INO)))//从根设备上读取文件系统的根i 节点(1)到内存i 节点列表中,(第0号节点为空,同理第0号逻辑块也为空,可能是系统 的规定)

        panic("Unable to read root i-node");
    mi->i_count += 3 ;// 该i 节点引用次数递增3 次    /* NOTE! it is logically used 4 times, not 1 */

    p->s_isup = p->s_imount = mi;// 置该超级块的被安装文件系统i 节点和被安装到的i 节点为该i 节点。

    current->pwd = mi;// 设置当前进程的当前工作目录,此时当前进程为1号进程

    current->root = mi;// 设置当前进程的根目录,此时当前进程为1号进程

    free=0;
    i=p->s_nzones;// 统计该设备上空闲块数。首先令i 等于超级块中表明的设备逻辑块总数

    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节点数。首先令i 等于设备上i 节点总数+1

    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);
}

阅读(952) | 评论(0) | 转发(0) |
0

上一篇:inode.c

下一篇:namei.c

给主人留下些什么吧!~~