inode.c主要是管理文件系统中inode结构的,功能包括,把硬盘的inode读入内容,把内存的inode内容写入硬盘,或内存的inode表中获取一个空的或者指定的inode,生成一个管道的inode,查找inode中的某个块,或者在inode中生成新的块。
/*
* linux/fs/inode.c
*
* (C) 1991 Linus Torvalds
*/
#include
#include
#include
#include
#include
#include
// 系统的inode表,整个系统的所有进程共享
struct m_inode inode_table[NR_INODE]={{0,},};
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)
{
cli();
while (inode->i_lock)
sleep_on(&inode->i_wait);
sti();
}
static inline void lock_inode(struct m_inode * inode)
{
cli();
while (inode->i_lock)
sleep_on(&inode->i_wait);
inode->i_lock=1;
sti();
}
static inline void unlock_inode(struct m_inode * inode)
{
inode->i_lock=0;
wake_up(&inode->i_wait);
}
// 置属于dev的inode无效
void invalidate_inodes(int dev)
{
int i;
struct m_inode * inode;
inode = 0+inode_table;
for(i=0 ; i<NR_INODE ; i++,inode++) {
wait_on_inode(inode);
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;
}
}
}
// 遍历所有inode,从硬盘读包括该inode的数据块,然后用内存的inode覆盖硬盘读进来的,存在buffer里,等待回写
void sync_inodes(void)
{
int i;
struct m_inode * inode;
inode = 0+inode_table;
for(i=0 ; i<NR_INODE ; i++,inode++) {
wait_on_inode(inode);
// 管道的内容存放在内存,所以不需要同步
if (inode->i_dirt && !inode->i_pipe)
write_inode(inode);
}
}
// 找到inode中块号为block的块对应哪个硬盘块号或如果没有该块则在硬盘中新建一个块
static int _bmap(struct m_inode * inode,int block,int create)
{
struct buffer_head * bh;
int i;
if (block<0)
panic("_bmap: block<0");
// 文件的大小最大值,(7+512+512*512) * 硬盘每块的大小
if (block >= 7+512+512*512)
panic("_bmap: block>big");
// 块号小于7则直接在i_zone数组的前面7个中找就行
if (block<7) {
// 如果是创建模式并且该索引为空则创建一个块
if (create && !inode->i_zone[block])
// 保存块号
if (inode->i_zone[block]=new_block(inode->i_dev)) {
inode->i_ctime=CURRENT_TIME;
// 该inode需要回写硬盘
inode->i_dirt=1;
}
// 返回硬盘中的块号
return inode->i_zone[block];
}
block -= 7;
if (block<512) {
if (create && !inode->i_zone[7])
if (inode->i_zone[7]=new_block(inode->i_dev)) {
inode->i_dirt=1;
inode->i_ctime=CURRENT_TIME;
}
if (!inode->i_zone[7])
return 0;
// 索引为7的块是间接块,需要把内容读进来才知道具体的硬盘块号
if (!(bh = bread(inode->i_dev,inode->i_zone[7])))
return 0;
// 直接根据block取得对应的硬盘块号
i = ((unsigned short *) (bh->b_data))[block];
// 之前没有,新建一个块
if (create && !i)
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])
if (inode->i_zone[8]=new_block(inode->i_dev)) {
inode->i_dirt=1;
inode->i_ctime=CURRENT_TIME;
}
if (!inode->i_zone[8])
return 0;
// 先取得一级索引对应的数据,数据中的每一项对应512个项
if (!(bh=bread(inode->i_dev,inode->i_zone[8])))
return 0;
// 每一个索引对应512个项,所以除以512,即右移9位,取得二级索引
i = ((unsigned short *)bh->b_data)[block>>9];
if (create && !i)
if (i=new_block(inode->i_dev)) {
((unsigned short *) (bh->b_data))[block>>9]=i;
bh->b_dirt=1;
}
brelse(bh);
if (!i)
return 0;
// 取得二级索引对应的数据
if (!(bh=bread(inode->i_dev,i)))
return 0;
// 算出偏移,最大偏移是511,所以&511
i = ((unsigned short *)bh->b_data)[block&511];
if (create && !i)
if (i=new_block(inode->i_dev)) {
((unsigned short *) (bh->b_data))[block&511]=i;
bh->b_dirt=1;
}
brelse(bh);
return i;
}
// 查找inode中第block块对应硬盘的块号
int bmap(struct m_inode * inode,int block)
{
return _bmap(inode,block,0);
}
// 查找inode中的第block块对应的硬盘哪个块,如果有则返回,没有则创建,返回硬盘中的块号
int create_block(struct m_inode * inode, int block)
{
return _bmap(inode,block,1);
}
void iput(struct m_inode * inode)
{
if (!inode)
return;
wait_on_inode(inode);
if (!inode->i_count)
panic("iput: trying to free free inode");
// 管道inode
if (inode->i_pipe) {
// 唤醒等待队列,因为该管道要被销毁了,不然那会使等待者无限等待,这句是不是可以放到if后
wake_up(&inode->i_wait);
// 还有进程在引用则先不销毁
if (--inode->i_count)
return;
// 释放管道对应的一页大小
free_page(inode->i_size);
// 该inode可以重用
inode->i_count=0;
inode->i_dirt=0;
inode->i_pipe=0;
return;
}
if (!inode->i_dev) {
inode->i_count--;
return;
}
if (S_ISBLK(inode->i_mode)) {
// 块文件,inode->i_zone[0]保存的是设备号,把buffer中属于该dev设备的回写到硬盘
sync_dev(inode->i_zone[0]);
wait_on_inode(inode);
}
repeat:
// 还有人引用引用数减一后返回
if (inode->i_count>1) {
inode->i_count--;
return;
}
// 没人引用该inode,删除该inode的内容,并释放该inode
if (!inode->i_nlinks) {
truncate(inode);
free_inode(inode);
return;
}
// 需要回写硬盘,则回写
if (inode->i_dirt) {
write_inode(inode); /* we can sleep - so do again */
wait_on_inode(inode);
goto repeat;
}
inode->i_count--;
return;
}
// 从inode表(数组)里找到一个未使用的inode结构
struct m_inode * get_empty_inode(void)
{
struct m_inode * inode;
static struct m_inode * last_inode = inode_table;
int i;
do {
inode = NULL;
for (i = NR_INODE; i ; i--) {
// 越界则从头再找,因为for会执行很多次,但last_inode是一直往前走
if (++last_inode >= inode_table + NR_INODE)
last_inode = inode_table;
// 找到一个未被使用的inode
if (!last_inode->i_count) {
// 找到未使用的并且没有被锁、数据是有效的才返回,否则先保存一个备选的
inode = last_inode;
if (!inode->i_dirt && !inode->i_lock)
break;
}
}
if (!inode) {
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);
// 没有被引用还会有需要回写的数据?
while (inode->i_dirt) {
write_inode(inode);
wait_on_inode(inode);
}
// 找到后该inode又被引用了,继续找
} while (inode->i_count);
memset(inode,0,sizeof(*inode));
inode->i_count = 1;
return inode;
}
// 获取一个用于管道的inode节点
struct m_inode * get_pipe_inode(void)
{
struct m_inode * inode;
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是管道类型
inode->i_pipe = 1;
return inode;
}
// 在inode表中找到对应的inode节点,如果找到的是挂载的文件系统,则要查找的等于挂载点的设备和,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;
while (inode < NR_INODE+inode_table) {
// 不相等则比较下一个节点
if (inode->i_dev != dev || inode->i_num != nr) {
inode++;
continue;
}
wait_on_inode(inode);
// 阻塞的时候数据可能发生了变化,继续比较,不一样了则从头开始再找
if (inode->i_dev != dev || inode->i_num != nr) {
inode = inode_table;
continue;
}
inode->i_count++;
// 另一个文件系统挂载在该inode下
if (inode->i_mount) {
int i;
for (i = 0 ; i<NR_SUPER ; i++)
// 找到挂载在该inode节点的超级块结构
if (super_block[i].s_imount==inode)
break;
// 没找到对应的超级块,直接返回找到的inode
if (i >= NR_SUPER) {
printk("Mounted inode hasn't got sb\n");
if (empty)
iput(empty);
return inode;
}
iput(inode);
// 找到了该超级块,更新dev为该超级块的的设备号,块号为第一块,从新的起点开始找
dev = super_block[i].s_dev;
nr = ROOT_INO;
inode = inode_table;
continue;
}
if (empty)
iput(empty);
return inode;
}
if (!empty)
return (NULL);
// 找不到则返回一个新的inode
inode=empty;
inode->i_dev = dev;
inode->i_num = nr;
read_inode(inode);
return inode;
}
// 把inode的数据从硬盘中读进来,通过超级块的信息和inode中的编号算出inode在硬盘的块号,读进来
static void read_inode(struct m_inode * inode)
{
struct super_block * sb;
struct buffer_head * bh;
int block;
lock_inode(inode);
if (!(sb=get_super(inode->i_dev)))
panic("trying to read inode without dev");
// 文件系统第一块是超级块,然后inode位图块,数据块块位图块,inode节点块,数据块,i_num为inode节点在硬盘inode表中编号
block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
(inode->i_num-1)/INODES_PER_BLOCK;
// 从硬盘中把inode节点的内容读进来
if (!(bh=bread(inode->i_dev,block)))
panic("unable to read i-node block");
// 读进来整个数据块,包含了要找的inode,算出inode的索引然后取值,d_inode为硬盘中的结构,m_inode为内存的结构
*(struct d_inode *)inode =
((struct d_inode *)bh->b_data)
[(inode->i_num-1)%INODES_PER_BLOCK]; // 取得偏移
brelse(bh);
unlock_inode(inode);
}
// 先把inode从硬盘中读进来,然后覆盖,等待回写
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");
block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
(inode->i_num-1)/INODES_PER_BLOCK;
// 读入包含该inode的整个数据块
if (!(bh=bread(inode->i_dev,block)))
panic("unable to read i-node block");
// 写到高速缓存等待回写到硬盘
((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);
}