Linux文件系统代码学习笔记2——Hash表&内存inode的创建与回收

时间:2022-05-06 16:12:49

igetput.cpp——内存inode的创建与回收

iget——内存inode的创建

1. hash表的作用

hash队列用来存放内存inode。
但是为什么要弄成队列的样子呢?方便查找?inode编号是唯一的,一个hash表128个队列,假设内存有256个inode
举个栗子,假设要找第129个inode:
inode编号->hash映射得到hash队列编号1->1次就能找到
如果不用hash队列,假设用数组,按照线性存放,要找129次
查找内存inode的操作经常用到,hash表的作用就是为了提高查找内存inode的效率

struct inode * iget(unsigned int dinodeid)
{
    int existed = 0, inodeid;
    long addr;
    struct inode *temp, *newinode;
    int i;
    inodeid = dinodeid % NHINO;//计算内存结点应该在第几个哈希队列里
    if (hinode[inodeid].i_forw == NULL)//若该哈希队列为空,内存结点一定未被创建
        existed = 0;
    else//若不为空,从该哈希队列头开始查找
    {
        temp = hinode[inodeid].i_forw; 
        while (temp)
        {
            if (temp->i_ino == dinodeid)//若找到 mkdir时,对象已经存在,引用计数会加1
            {
                existed = 1;
                temp->i_count ++;
                return temp;//返回该内存结点指针
            }
            else
                temp = temp->i_forw;

        }
    }

    /* 若没有找到 */   
    /* 1. 计算该磁盘i结点在文件卷中的位置 */
    addr = DINODESTART + dinodeid * DINODESIZ;

    /* 2. 分配一个内存i结点 */
    newinode = (struct inode *)malloc(sizeof(struct inode));

    /* 3. 用磁盘i结点初始化内存i结点 */
    memcpy(&(newinode->di_number), disk+addr, DINODESIZ);//除了i_count i_flag i_ino 

    /* 4. 将内存i结点链入相应的哈希队列里*/
    newinode->i_forw = hinode[inodeid].i_forw;
    hinode[inodeid].i_forw = newinode; 
    newinode->i_back = newinode;
    //newinode->i_back =hinode[inodeid]
    if (newinode->i_forw)
        newinode->i_forw->i_back = newinode;

    /*5. 初始化内存i结点的其他数据项 */
    newinode->i_count = 1;//引用计数设为1
    newinode->i_flag = 0;   /* 表示未更新 */
    newinode->i_ino = dinodeid;

    return newinode;
}

iput——内存inode的回收

0. 引用计数大于1

回收时,只需要将引用计数减1即可。内存中的信息继续保存,因为有别的进程还在引用

1. 理解内存inode的回收

顾名思义,就是将其在内存中的空间释放掉。inode在内存中是存在hash表中的。所以一旦inode引用计数为1,代表此时系统中除了当前进程,已经没有其他引用该inode进程了,那我们就不用将这个inode继续放在内存中占用空间了。所以一旦inode的引用计数为1,必然无条件要将内存inode从hash队列中删除。

2.引用计数为1&&关联文件数不为0:

因为一个inode存放的是一个文件的信息,此时没有引用该inode的进程,但关联的文件还存在,就要将内存inode的信息写到磁盘inode中;
由此可以看出,创建一个文件时,是先创建内存inode,然后回收时再将内存inode的信息拷贝到磁盘inode中。
1)内存inode信息拷贝到磁盘inode中;
2)在hash中删除内存inode。

3. 引用计数为1&&关联文件数为0:

一个文件被创建时,被分配了一个inode和对应的block。如果文件已经不存在了,那么分配给这个文件的inode和block都应该被删除。
1)删除磁盘inode和文件对应的block;
2)在hash中删除内存inode。


void iput(struct inode *pinode)
{
    long addr;
    unsigned int block_num;
    int i;

    if (pinode->i_count > 1)//若引用计数>1
    {
        pinode->i_count --;//引用计数减1
        return;
    }
    else
    {
        if (pinode->di_number != 0)//若联结计数不为0
        {
            /* 把内存i结点的内容写回磁盘i结点 */
            addr = DINODESTART + pinode->i_ino *DINODESIZ;
            memcpy(disk+addr, &pinode->di_number, DINODESIZ);
        }
        else
        {
            /* 删除磁盘i结点和文件对应的物理块 */
            block_num = pinode->di_size/BLOCKSIZ;
            for (i=0; i<block_num; i++)
                bfree(pinode->di_addr[i]);
            ifree(pinode->i_ino);
        }

        /* 释放内存i结点 */
        {
            int inodeid;
            inodeid = (pinode->i_ino)  % NHINO ;//找到所在的哈希队列

            /* 从该哈希队列里删除 */
            if (hinode[inodeid].i_forw == pinode)
            {
                hinode[inodeid].i_forw = pinode->i_forw;
                if (pinode->i_forw)
                    pinode->i_forw->i_back = pinode->i_forw;
            }
            else
            {
                pinode->i_back->i_forw = pinode->i_forw;
                if (pinode->i_forw)
                    pinode->i_forw->i_back = pinode->i_back;
            }
        }
        free(pinode);       
    }
    return;
}