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