当前位置:文档之家› innode.c

innode.c

innode.c
innode.c

/*

* linux/fs/inode.c

*/

#include

#include // 文件状态头文件

#include

#include

#include

#include

struct m_inode inode_table[NR_INODE]={{0,},}; // 内存中i 节点表static void read_inode(struct m_inode * inode);

static void write_inode(struct m_inode * inode);

/* 等待指定的i 节点可用*/

static inline void wait_on_inode(struct m_inode * inode)

{

cli();

while (inode->i_lock) // // 如果i 节点已被锁定

sleep_on(&inode->i_wait); // 不可中断的等待状态

sti();

}

/* 对指定的i 节点上锁*/

static inline void lock_inode(struct m_inode * inode)

{

cli();

while (inode->i_lock)

sleep_on(&inode->i_wait);

inode->i_lock=1; // 置锁定标志

sti();

}

/* 对指定的i 节点解锁*/

static inline void unlock_inode(struct m_inode * inode)

{

inode->i_lock=0; // 复位i 节点的锁定标志

wake_up(&inode->i_wait); // 唤醒等待此i 节点的进程

}

/* 释放内存中设备dev 的所有i 节点*/

void invalidate_inodes(int dev)

{

int i;

struct m_inode * inode;

inode = 0+inode_table;

for(i=0 ; i

{

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

if (inode->i_dev == dev)

{

if (inode->i_count) // 如果其引用数不为0

printk("inode in use on removed disk\n\r");

inode->i_dev = inode->i_dirt = 0; // 释放该i 节点,只是一个标记

}

}

}

/* 同步内存(inode数组)与设备上的所有i 节点信息*/

void sync_inodes(void)

{

int i;

struct m_inode * inode;

inode = 0+inode_table; // 第一项

for(i=0 ; i

{

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

// 如果该i 节点已修改且不是管道节点

if (inode->i_dirt && !inode->i_pipe)

write_inode(inode); // 写盘

}

}

/* 文件数据块映射到盘块的处理操作,可能需要建立新的逻辑块*/

static int _bmap(struct m_inode * inode,int block,int create)

{

// inode 文件的i 节点;block (相对于文件而言)文件中的数据块号;create 创建标志

// block是相对于文件而言,但是i_zone[block]则是相对于设备而言的。相对于文件的

// block可能不止i_zone数组大小,所以如果block的值大于7时,需要使用间接来寻址。// 如下的映射:

// |-----------| |------------------------------|

// |file block | ---> | disk block |

// |-----------| |------------------------------|

// 如果create = 1,需要建立新的逻辑块,

struct buffer_head * bh;

int i;

if (block<0) // 块号小于0 ?

panic("_bmap: block<0");

if (block >= 7+512+512*512) // 超出文件系统表示范围

panic("_bmap: block>big");

/*

* 文件在磁盘上存储时,并不是在连续空间存储的。一个文件可能对应的是

* 几个设备逻辑块号(设备的逻辑块号同样决定了系统支持的最大的文件长度)

* 这些信息存储在i_zone中。

*/

// 如果该块号小于7,则使用直接块表示

if (block<7)

{

// 创建标志置位, 并且i 节点中对应该块的逻辑块(区段)字段为0 if (create && !inode->i_zone[block])

// 向相应设备申请一磁盘块

if (inode->i_zone[block]=new_block(inode->i_dev))

{

inode->i_ctime=CURRENT_TIME; // 设置i 节点修改时间

inode->i_dirt=1; // 置i 节点已修改标志

}

return inode->i_zone[block]; // 返回逻辑块号

}

// 如果该块号>=7,并且小于7+512,则说明是一次间接块

block -= 7;

if (block<512)

{

// 如果是创建,并且该i 节点中对应间接块字段为0

if (create && !inode->i_zone[7]) // 首次使用间接块

// 需申请一磁盘块用于存放间接块信息,inode->i_zone[7]

// 中存储的是相对于软盘的逻辑块号,在以后读取该块时,

// 使用下面的据对软盘号

if (inode->i_zone[7]=new_block(inode->i_dev))

{

// 设置i 节点已修改标志和修改时间

inode->i_dirt=1;

inode->i_ctime=CURRENT_TIME;

}

// 若此时i 节点间接块字段中为0,表明申请磁盘块失败

if (!inode->i_zone[7])

return 0;

/* 读取设备上的一次间接块*/

/*

* i_zone[7] -- 逻辑块号-- 将该逻辑块号对应内容读入到

* 内存中-- 在内存中查找(间接)查找逻辑块号

*

*/

if (!(bh = bread(inode->i_dev,inode->i_zone[7])))

return 0;

// 取该间接块上第block 项中的逻辑块号(盘块号)

i = ((unsigned short *) (bh->b_data))[block];

// 如果是创建并且间接块的第block 项中的逻辑块号为0 的话

// 该初始化是在函数new_block中使用函数clear_block来讲整个

// 分配的缓冲区域置0

if (create && !i)

if (i=new_block(inode->i_dev)) // 申请一磁盘块(逻辑块)

{

// 间接块中的第block 项等于该新逻辑块块号

((unsigned short *) (bh->b_data))[block]=i;

bh->b_dirt=1; // 置位间接块的已修改标志

}

brelse(bh); // 最后释放该间接块

return i; // 返回磁盘上新申请的对应block 的逻辑块的块号

}

// 程序运行到此,表明数据块是二次间接块

block -= 512;

// 如果是新创建并且i 节点的二次间接块字段为0

if (create && !inode->i_zone[8])

// 需申请一磁盘块用于存放二次间接块的一级块信息

// 将此实际磁盘块号填入二次间接块字段中

if (inode->i_zone[8]=new_block(inode->i_dev))

{

// 置i 节点已修改编制和修改时间

inode->i_dirt=1;

inode->i_ctime=CURRENT_TIME;

}

// 若此时i 节点二次间接块字段为0,表明申请磁盘块失败

if (!inode->i_zone[8])

return 0;

// 读取该二次间接块的一级块(读取设备上的数据)。即是说明的是间接

// 寻找逻辑块的信息时存储在设备上

if (!(bh=bread(inode->i_dev,inode->i_zone[8])))

return 0;

// 取该二次间接块的一级块上第(block/512)项中的逻辑块号

i = ((unsigned short *)bh->b_data)[block>>9];

// 如果是创建并且二次间接块的一级块上第(block/512)项中的逻辑块号为0 的话if (create && !i)

// 申请一磁盘块(逻辑块)作为二次间接块的二级块

if (i=new_block(inode->i_dev))

{

((unsigned short *) (bh->b_data))[block>>9]=i;

bh->b_dirt=1; // 置位二次间接块的一级块已修改标志

}

brelse(bh); // 释放二次间接块的一级块

// 如果二次间接块的二级块块号为0,表示申请磁盘块失败

if (!i)

return 0;

// 读取二次间接块的二级块

if (!(bh=bread(inode->i_dev,i)))

return 0;

// 取该二级块上第block 项中的逻辑块号

i = ((unsigned short *)bh->b_data)[block&511];

// 如果是创建并且二级块的第block 项中的逻辑块号为0 的话,则申请一磁盘块(逻辑块)if (create && !i)

if (i=new_block(inode->i_dev)) {

((unsigned short *) (bh->b_data))[block&511]=i;

bh->b_dirt=1;

}

brelse(bh); // 最后释放该二次间接块的二级块

// 返回磁盘上新申请的对应block 的逻辑块的块号

return i;

}

/* 根据文件的块偏移量来得到设备上的逻辑块号*/

/* 根据文件的m_inode节点信息,和在文件中的偏移量block来影射到实际的*/

/* 逻辑块号,有返回值int返回*/

int bmap(struct m_inode * inode,int block)

{

/*

* 在该函数调用时,create = 0,该函数只是返回的是return inode->i_zone[block];

* 只是返回相应的信息

*/

return _bmap(inode,block,0);

}

/* 创建文件数据块block 在设备上对应的逻辑块,并返回设备上对应的逻辑块号*/

int create_block(struct m_inode * inode, int block)

{

return _bmap(inode,block,1);

}

/* 释放一个i 节点(从内存数组回写入设备文件) */

void iput(struct m_inode * inode)

{

if (!inode)

return;

wait_on_inode(inode); // 等待inode 节点解锁

if (!inode->i_count)

panic("iput: trying to free free inode");

if (inode->i_pipe) // 管道i 节点

{

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

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

return;

// 释放管道占用的内存页面

free_page(inode->i_size);

// 复位该节点的引用计数值

inode->i_count=0;

inode->i_dirt=0; // 已修改标志

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

return;

}

if (!inode->i_dev) // 如果i 节点对应的设备号0

{

inode->i_count--; // 此节点的引用计数递减1

return;

}

if (S_ISBLK(inode->i_mode)) // 块设备文件的i节点?

{

sync_dev(inode->i_zone[0]); // 刷新该设备

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

}

repeat:

if (inode->i_count>1) // // 如果i 节点的引用计数大于1

{

inode->i_count--; // 递减1

return;

}

if (!inode->i_nlinks) // 如果i 节点的链接数为0

{

truncate(inode); // 释放该i 节点的所有逻辑块

free_inode(inode); // 释放该i 节点

return;

}

if (inode->i_dirt) // 该i 节点已作过修改,没有修改的话,不需要写入文件{

// 更新该i 节点

write_inode(inode); /* we can sleep - so do again */

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

goto repeat;

}

// i 节点引用计数递减1

inode->i_count--;

return;

}

/* 从i 节点表(inode_table)中获取一个空闲i 节点项*/

struct m_inode * get_empty_inode(void)

{

struct m_inode * inode;

// last_inode 指向i 节点表第一项

static struct m_inode * last_inode = inode_table;

int i;

do {

inode = NULL;

for (i = NR_INODE; i ; i--)

{

// 循环

if (++last_inode >= inode_table + NR_INODE)

last_inode = inode_table;

// 计数值为0,则说明可能找到空闲i 节点项

if (!last_inode->i_count)

{

inode = last_inode;

// 如果该i 节点的已修改标志和锁定标志均为0,则我们可以使用该i 节点if (!inode->i_dirt && !inode->i_lock)

break;

}

}

// 此时inode就是上面寻找到的空闲的inode项

if (!inode) // 如果没有找到空闲i 节点(inode=NULL)

{

for (i=0 ; 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 节点解锁

// 如果该i 节点已修改标志被置位的话

while (inode->i_dirt)

{

write_inode(inode); // 将该i 节点刷新

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

}

// 如果i 节点又被其它占用的话,则重新寻找空闲i 节点

} while (inode->i_count);

memset(inode,0,sizeof(*inode)); // 该i节点项内容清零

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

return inode;

}

/* 获取管道节点*/

struct m_inode * get_pipe_inode(void)

{

struct m_inode * inode;

// 寻找一个空闲i 节点项

if (!(inode = get_empty_inode()))

return NULL;

// 节点的i_size 字段指向缓冲区

if (!(inode->i_size=get_free_page()))

{

inode->i_count = 0;

return NULL;

}

inode->i_count = 2; /* sum of readers/writers */

// 复位管道头尾指针

PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;

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

return inode;

}

/* 从设备上dev读取指定节点号的i 节点nr */

struct m_inode * iget(int dev,int nr)

{

struct m_inode * inode, * empty;

if (!dev)

panic("iget with dev==0");

empty = get_empty_inode();

inode = inode_table;

// 扫描i 节点表。寻找指定节点号的i 节点

while (inode < NR_INODE+inode_table)

{

if (inode->i_dev != dev || inode->i_num != nr)

{

inode++;

continue;

}

// 此时inode->i_dev == dev && inode->i_num == nr

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

// 在等待该节点解锁的阶段,节点表可能会发生变化

if (inode->i_dev != dev || inode->i_num != nr)

{

// 如果发生了变化,则再次重新扫描整个i 节点表。

inode = inode_table;

continue;

}

// 没有变化

inode->i_count++; // 将该i 节点引用计数增1

/**************************************************************/ /* 是目录inode?*/

if (inode->i_mount) // 如果该i节点是其它文件系统的安装点

{

int i;

// 在超级块表中搜寻安装在此i 节点的超级块

for (i = 0 ; i

if (super_block[i].s_imount==inode)

break;

if (i >= NR_SUPER) // 没有找到

{

// 显示出错信息

printk("Mounted inode hasn't got sb\n");

if (empty) // 如果empty不空,清空inode内存数组

iput(empty);

return inode;

}

iput(inode); // 将该i 节点写盘

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

// 扫描整个i 节点表,取该被安装文件系统的根节点

nr = ROOT_INO; // nr = ROOT_INO = 1

inode = inode_table;

continue;

}

/***************************************************************/

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

iput(empty);

return inode;

}

// 程序运行到这,说明在i 节点表中没有找到指定的i 节点

if (!empty)

return (NULL);

inode=empty;

inode->i_dev = dev;

inode->i_num = nr;

// 从相应设备上读取该i 节点信息

read_inode(inode);

return inode; // 返回该i节点的值

}

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

static void read_inode(struct m_inode * inode)

{

struct super_block * sb;

struct buffer_head * bh;

int block;

// 首先锁定该i 节点,取该节点所在设备的超级块

lock_inode(inode);

if (!(sb=get_super(inode->i_dev)))

panic("trying to read inode without dev");

// 计算inode的位置(在设备文件中存在存放inode的地方,// 此位置是在设备上存放inode的位置)

block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks + (inode->i_num-1)/INODES_PER_BLOCK;

if (!(bh=bread(inode->i_dev,block)))

panic("unable to read i-node block");

*(struct d_inode *)inode =

((struct d_inode *)bh->b_data)

[(inode->i_num-1)%INODES_PER_BLOCK];

// 最后释放读入的缓冲区,并解锁该i 节点

brelse(bh);

unlock_inode(inode);

}

/* 将指定i 节点信息写入设备*/

static void write_inode(struct m_inode * inode)

{

struct super_block * sb;

struct buffer_head * bh;

int block;

lock_inode(inode);

if (!inode->i_dirt || !inode->i_dev) // 无须写

{

unlock_inode(inode);

return;

}

if (!(sb=get_super(inode->i_dev)))

panic("trying to write inode without device");

// 同上,计算该inode在设备上inode存储区域上的位置block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks + (inode->i_num-1)/INODES_PER_BLOCK;

// 从设备上读取该i 节点所在的逻辑块

if (!(bh=bread(inode->i_dev,block)))

panic("unable to read i-node block");

// 将i节点的信息暂时的写入bh->data中,并设置b_dirty

// 标志,内核在合适的时间将bh的内容刷洗到实际的设备上((struct d_inode *)bh->b_data)

[(inode->i_num-1)%INODES_PER_BLOCK] =

*(struct d_inode *)inode;

bh->b_dirt=1;

inode->i_dirt=0;

brelse(bh);

unlock_inode(inode);

}

/*

* 这个文件主要是实现函数iget和函数iput。函数iget的主要作用是* 从设备上读取指定的inode节点号,就是实现从设备(存数介质)到* 内存inode数组的转移。函数iput则是相反的函数,该函数实现的是* 将内存inode的信息写入到设备中,在函数中调用write_inode函数* 写入。另外一个重要的函数时bmap函数,该函数实现的是根据文件* 的block来计算得到设备上的绝对逻辑块号

*/

相关主题
文本预览
相关文档 最新文档