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

全部博文(137)

文章存档

2011年(10)

2010年(23)

2009年(104)

分类: LINUX

2009-08-15 17:10:09

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


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

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

struct m_inode inode_table[NR_INODE]={{0,},};// 内存中i 节点表(NR_INODE=32 项)


static void read_inode(struct m_inode * inode);//读节点号的相关信息

static void write_inode(struct m_inode * inode);//写节点号的相关信息到高速缓冲区


static inline void wait_on_inode(struct m_inode * inode)// 等待指定的i 节点可用(解锁)

{
    cli();//关中断

    while (inode->i_lock)//节点上锁

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

    sti();//开中断

}

static inline void lock_inode(struct m_inode * inode)// 对指定的i 节点上锁(锁定指定的i 节点)

{
    cli();//关中断

    while (inode->i_lock)//节点上锁

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

    inode->i_lock=1;
    sti();//开中断

}

static inline void unlock_inode(struct m_inode * inode)// 对指定的i 节点解锁

{
    inode->i_lock=0;//解锁

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

}

void invalidate_inodes(int dev)// 释放内存中设备dev 的所有i 节点,扫描内存中的i 节点表数组,如果是指定设备使用的i 节点就释放之

{
    int i;
    struct m_inode * inode;

    inode = 0+inode_table;// 让指针首先指向i 节点表指针数组首项

    for(i=0 ; i<NR_INODE ; i++,inode++) { // 扫描i 节点表指针数组中的所有i 节点

        wait_on_inode(inode);// 等待该i 节点可用(解锁)

        if (inode->i_dev == dev) {
            if (inode->i_count)
                printk("inode in use on removed disk\n\r");
            inode->i_dev = inode->i_dirt = 0;// 释放该i 节点(置设备号为0 )

        }
    }
}

void sync_inodes(void)// 同步所有i 节点,同步内存与设备上的所有i 节点信息

{
    int i;
    struct m_inode * inode;

    inode = 0+inode_table;// 让指针首先指向i 节点表指针数组首项

    for(i=0 ; i<NR_INODE ; i++,inode++) {
        wait_on_inode(inode);// 等待指定的i 节点可用(解锁)

        if (inode->i_dirt && !inode->i_pipe)// 如果该i 节点已修改且不是管道节点

            write_inode(inode);// 则写盘(写入高速缓冲区中)

    }
}

static int _bmap(struct m_inode * inode,int block,int create)// 把指定 的文件数据块block对应到设备上逻辑块上,文件数据块映射到盘块的处理操作。(block 位图处理函数,bmap - block map),inode – 文件的i 节点;block – 文件中的数据块号;create - 创建标志

{//返回block 数据块对应在设备上的逻辑块号(盘块号)

    struct buffer_head * bh;
    int i;

    if (block<0)// 如果块号小于0,则死机

        panic("_bmap: block<0");
    if (block >= 7+512+512*512)// 如果块号大于直接块数 + 间接块数 + 二次间接块数,超出文件系统表示范围,则死机

        panic("_bmap: block>big");
    if (block<7) {// 如果该块号小于7,则使用直接块表示

        if (create && !inode->i_zone[block])//如果create为真且对应 的逻辑块号为0,则向相应设备申请一逻辑块

            if (inode->i_zone[block]=new_block(inode->i_dev)) {
                inode->i_ctime=CURRENT_TIME;
                inode->i_dirt=1;
            }
        return inode->i_zone[block];//回对应的逻辑块号

    }
    block -= 7;
    if (block<512) {// 如果该块号>=7,并且小于7+512,则说明是一次间接块

        if (create && !inode->i_zone[7])//如果create为真且首次使用一级间接块,则向相应设备申请一逻辑块来存放间接块信息

            if (inode->i_zone[7]=new_block(inode->i_dev)) {
                inode->i_dirt=1;
                inode->i_ctime=CURRENT_TIME;
            }
        if (!inode->i_zone[7])// 若此时i 节点间接块字段中为0,表明申请磁盘块失败,返回0 退出

            return 0;
        if (!(bh = bread(inode->i_dev,inode->i_zone[7])))// 读取设备上的一次间接块信息,(里面放的是逻辑块号数)

            return 0;
        i = ((unsigned short *) (bh->b_data))[block];// 取该间接块上第block 项中的逻辑块号

        if (create && !i)//如果create为真且读取的逻辑块号为0,则向相应设备申请一逻辑块

            if (i=new_block(inode->i_dev)) {
                ((unsigned short *) (bh->b_data))[block]=i;
                bh->b_dirt=1;
            }
        brelse(bh);// 本任务释放指定的高速缓冲块区

        return i;
    }
    block -= 512;//程序运行到此,表明数据块是二次间接块,处理过程与一次间接块类似

    if (create && !inode->i_zone[8])//如果create为真且首次使用二级间接块,则向相应设备申请一逻辑块来存放二级间接块的一级间接块信息

        if (inode->i_zone[8]=new_block(inode->i_dev)) {
            inode->i_dirt=1;
            inode->i_ctime=CURRENT_TIME;
        }
    if (!inode->i_zone[8])// 若此时i 节点二次间接块字段为0,表明申请磁盘块失败,返回0 退出

        return 0;
    if (!(bh=bread(inode->i_dev,inode->i_zone[8])))// 读取该二次间接块的一级块。

        return 0;
    i = ((unsigned short *)bh->b_data)[block>>9];// 取该二次间接块的一级块上第(block/512)项中的逻辑块号,,(要记准用这种方式的,来取二级间接块的信息)

    if (create && !i)//如果create为真且对应 的二次间接块的一级块上第(block/512)项中的逻辑块号为0,则向相应设备申请一逻辑块,来存放间接块信息

        if (i=new_block(inode->i_dev)) {
            ((unsigned short *) (bh->b_data))[block>>9]=i;
            bh->b_dirt=1;
        }
    brelse(bh);
    if (!i)/// 如果二次间接块的二级块块号为0,表示申请磁盘块失败,返回0 退出

        return 0;
    if (!(bh=bread(inode->i_dev,i)))// 读取二次间接块的二级块

        return 0;
    i = ((unsigned short *)bh->b_data)[block&511];// 取该二级块上第block 项中的逻辑块号。(与上511 是为了找在这个二级块中对应的block值,同时限定block 值不超过511)

    if (create && !i)//如果create为真且对应 的逻辑块号为0,则向相应设备申请一逻辑块

        if (i=new_block(inode->i_dev)) {
            ((unsigned short *) (bh->b_data))[block&511]=i;
            bh->b_dirt=1;
        }
    brelse(bh);
    return i;
}

int bmap(struct m_inode * inode,int block)// 根据i 节点信息取文件数据块block 在设备上对应的逻辑块号

{
    return _bmap(inode,block,0);
}

int create_block(struct m_inode * inode, int block)// 创建文件数据块block 在设备上对应的逻辑块,并返回设备上对应的逻辑块号

{
    return _bmap(inode,block,1);
}
        
void iput(struct m_inode * inode)// 释放一个i 节点(写入设备)

{
    if (!inode)
        return;
    wait_on_inode(inode);// 等待inode 节点解锁(如果已上锁的话)

    if (!inode->i_count)// ,此节点没有 被引用,i 节点被使用的次数,0 表示该i 节点空闲。

        panic("iput: trying to free free inode");
    if (inode->i_pipe) {//管道标志,如果是管道设备

        wake_up(&inode->i_wait);//则唤醒等待该管道的进程

        if (--inode->i_count)//引用次数减1,如果还有引用则返回

            return;
        free_page(inode->i_size);//释放 管道占用的内存页面

        inode->i_count=0;// i 节点被使用的次数,0 表示该i 节点空闲。

        inode->i_dirt=0;// 已修改(脏)标志。

        inode->i_pipe=0;// 管道标志。

        return;
    }
    if (!inode->i_dev) {// 如果i 节点对应的设备号=0,则将此节点的引用计数递减1,返回

        inode->i_count--;
        return;
    }
    if (S_ISBLK(inode->i_mode)) {// 如果是块设备文件的i 节点,此时逻辑块字段0 中是设备号,则刷新该设备。并等待i 节点解锁

        sync_dev(inode->i_zone[0]);//inode->i_zone[0]存放的是设备号,对指定设备进行高速缓冲数据与设备上数据的同步操作

        wait_on_inode(inode);// 等待指定的i 节点可用(解锁)

    }
repeat:
    if (inode->i_count>1) {// 如果i 节点的引用计数大于1,则递减1,后返回

        inode->i_count--;
        return;
    }
    if (!inode->i_nlinks) {// 如果i 节点的链接数为0,则释放该i 节点的所有逻辑块,并释放该i 节点

        truncate(inode);//截断文件数据函数,将节点对应的文件长度截为0,并释放占用的设备空间

        free_inode(inode);// 释放指定的i 节点

        return;
    }
    if (inode->i_dirt) {// 如果该i 节点已作过修改,则更新该i 节点,并等待该i 节点解锁

        write_inode(inode);    /* we can sleep - so do again *///将指定i 节点信息写入设备(写入缓冲区相应的缓冲块中,待缓冲区刷新时会写入盘中)

        wait_on_inode(inode);// 等待指定的i 节点可用(解锁)

        goto repeat;
    }
    inode->i_count--;// i 节点引用计数递减1

    return;
}

struct m_inode * get_empty_inode(void)//从内存i 节点表(inode_table)中获取一个空闲i 节点项,寻找引用计数count 为0 的i 节点,并将其写盘后清零,返回其指针

{
    struct m_inode * inode;
    static struct m_inode * last_inode = inode_table;// last_inode 指向i 节点表第一项

    int i;

    do {
        inode = NULL;
        for (i = NR_INODE; i ; i--) {
            if (++last_inode >= inode_table + NR_INODE)// 如果last_inode 已经指向i 节点表的最后1 项之后,则让其重新指向i 节点表开始处

                last_inode = inode_table;
            if (!last_inode->i_count) {// 如果last_inode 所指向的i 节点的计数值为0,则说明可能找到空闲i 节点项。让inode 指向 该i 节点。如果该i 节点的已修改标志和锁定标志均为0,则我们可以使用该i 节点,于是退出循环

                inode = last_inode;
                if (!inode->i_dirt && !inode->i_lock)
                    break;
            }
        }
        if (!inode) {// 如果没有找到空闲i 节点(inode=NULL),则将整个i 节点表打印出来供调试使用,并死机

            for (i=0 ; i<NR_INODE ; i++)
                printk("%04x: %6d\t",inode_table[i].i_dev,
                    inode_table[i].i_num);
            panic("No free inodes in mem");
        }
        wait_on_inode(inode);// 等待该i 节点解锁(如果又被上锁的话

        while (inode->i_dirt) {// 如果该i 节点已修改标志被置位的话,则将该i 节点刷新,并等待该i 节点解锁

            write_inode(inode);//将指定i 节点信息写入设备(写入缓冲区相应的缓冲块中,待缓冲区刷新时会写入盘中)

            wait_on_inode(inode);// 等待指定的i 节点可用(解锁)

        }
    } while (inode->i_count);// 如果i 节点又被其它占用的话,则重新寻找空闲i 节点

    memset(inode,0,sizeof(*inode));// 已找到空闲i 节点项。则将该i 节点项内容清零,

    inode->i_count = 1;//并置引用标志为1

    return inode;//,返回该i 节点指针

}

struct m_inode * get_pipe_inode(void)// 获取管道节点。返回为i 节点指针(如果是NULL 则失败)

{
    struct m_inode * inode;

    if (!(inode = get_empty_inode()))//从内存i 节点表(inode_table)中获取一个空闲i 节点项

        return NULL;
    if (!(inode->i_size=get_free_page())) {//// 文件大小(字节数),取一页空闲内存,

        inode->i_count = 0;// i 节点被使用的次数,0 表示该i 节点空闲。

        return NULL;
    }
    inode->i_count = 2;    /* sum of readers/writers *///读/写两者总计

    PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;// 复位管道头((inode).i_zone[0])尾((inode).i_zone[1])指针

    inode->i_pipe = 1;// 置节点为管道使用的标志

    return inode;// 返回i 节点指针

}

struct m_inode * iget(int dev,int nr)//取得一个i节点,dev 设备号,nr节点号,从设备上读取指定节点号的i 节点到内存i 节点表中

{//先从高速缓冲区内存节点表中查找,如查找到则用,如果找不到,则从设备上读取

    struct m_inode * inode, * empty;

    if (!dev)
        panic("iget with dev==0");
    empty = get_empty_inode();//从内存i 节点表中取一个空闲i 节点。

    inode = inode_table;//指向内存i 节点表的第一项

    while (inode < NR_INODE+inode_table) {// 扫描i 节点表。寻找指定节点号的i 节点。并递增该节点的引用次数

        if (inode->i_dev != dev || inode->i_num != nr) {// 如果当前扫描的i 节点的设备号不等于指定的设备号或者节点号不等于指定的节点号,则继续扫描

            inode++;
            continue;
        }
        wait_on_inode(inode);// 找到指定设备号和节点号的i 节点,等待该节点解锁(如果已上锁的话)

        if (inode->i_dev != dev || inode->i_num != nr) {// 在等待该节点解锁的阶段,节点表可能会发生变化,所以再次判断,如果发生了变化,则再次重新扫描整个i 节点表

            inode = inode_table;
            continue;
        }
        inode->i_count++;// 找到要找的inode节点,将该i 节点引用计数增1

        if (inode->i_mount) {// 如果该i 节点是其它文件系统的安装点,则在超级块表中搜寻安装在此i 节点的超级块

            int i;

            for (i = 0 ; i<NR_SUPER ; i++)
                if (super_block[i].s_imount==inode)
                    break;
            if (i >= NR_SUPER) {//如果没有找到超级块,则显示出错信息,并释放函数开始获取的空闲节点,返回该i 节点指针

                printk("Mounted inode hasn't got sb\n");
                if (empty)
                    iput(empty);
                return inode;
            }
            iput(inode);//找到超级块,则说明这个节点不能用,于是释放这个inode节点

            dev = super_block[i].s_dev;//在安装在此i 节点文件系统的超级块上取设备号

            nr = ROOT_INO;//并令i 节点号为1,ROOT_INO==1

            inode = inode_table;//然后重新扫描整个i 节点表,取该被安装文件系统的根节点,,,为什么要这么做呢??

            continue;
        }
        if (empty)// 已经找到相应的i 节点,因此放弃临时申请的空闲节点,返回该找到的i 节点

            iput(empty);// 释放一个i 节点

        return inode;
    }
    if (!empty)
        return (NULL);
    inode=empty;// 如果在i 节点表中没有找到指定的i 节点,则利用前面申请的空闲i 节点在i 节点表中建立该节点

    inode->i_dev = dev;
    inode->i_num = nr;
    read_inode(inode);//并从相应设备上读取该i 节点信息。返回该i 节点

    return inode;
}

static void read_inode(struct m_inode * inode)//从设备上读取指定i 节点的信息到内存中(缓冲区中)

{
    struct super_block * sb;
    struct buffer_head * bh;
    int block;

    lock_inode(inode);// 对指定的i 节点上锁(锁定指定的i 节点)

    if (!(sb=get_super(inode->i_dev)))//取该节点所在设备的超级块

        panic("trying to read inode without dev");
    block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
        (inode->i_num-1)/INODES_PER_BLOCK;// 由节点号换算成逻辑块号,该i 节点所在的逻辑块号 = (启动块+超级块) + i 节点位图占用的块数 + 逻辑块位图占用的块数 + (i 节点号-1)/每块含有的i 节点数

    if (!(bh=bread(inode->i_dev,block)))// 从设备上读取该i 节点信息所在的逻辑块,

        panic("unable to read i-node block");
    *(struct d_inode *)inode =
        ((struct d_inode *)bh->b_data)
            [(inode->i_num-1)%INODES_PER_BLOCK];//并将该inode 指针指向对应i 节点信息

    brelse(bh);//最后释放读入的缓冲区

    unlock_inode(inode);// 对指定的i 节点解锁

}

static void write_inode(struct m_inode * inode)// 将指定i 节点信息写入设备(写入缓冲区相应的缓冲块中,待缓冲区刷新时会写入盘中)

{
    struct super_block * sb;
    struct buffer_head * bh;
    int block;

    lock_inode(inode);// 首先锁定该i 节点,

    if (!inode->i_dirt || !inode->i_dev) {//如果该i 节点没有被修改过或者该i 节点的设备号等于零,

        unlock_inode(inode);//则解锁该i 节点

        return;//并退出

    }
    if (!(sb=get_super(inode->i_dev)))// 获取该i 节点的超级块。

        panic("trying to write inode without device");
    block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
        (inode->i_num-1)/INODES_PER_BLOCK;// 由节点号换算成逻辑块号,该i 节点所在的逻辑块号 = (启动块+超级块) + i 节点位图占用的块数 + 逻辑块位图占用的块数 + (i 节点号-1)/每块含有的i 节点数

    if (!(bh=bread(inode->i_dev,block)))// 从设备上读取该i 节点信息所在的逻辑块,

        panic("unable to read i-node block");
    ((struct d_inode *)bh->b_data)
        [(inode->i_num-1)%INODES_PER_BLOCK] =
            *(struct d_inode *)inode;//并将该inode 指针指向对应i 节点信息

    bh->b_dirt=1;// 置缓冲区已修改标志

    inode->i_dirt=0;//而i 节点修改标志置零

    brelse(bh);//然后释放该含有i 节点的缓冲区

    unlock_inode(inode);//并解锁该i 节点

}

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

上一篇:truncate.c

下一篇:supper.c

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