代码:linux-0.11
以磁盘为例,磁盘中有目录的映射,把磁盘分成盘片,每一个盘片 都有一个文件系统的子系统(章节目录)
引导块:用来引导设备的。可以为空,但是一定要空开,为了保持数据的一致性
超级块:该文件子系统描述符,记录该i节点位图和逻辑块位图的地址,通过设备号可以获取超级块
逻辑位图:其每一位对应数据区的盘块(逻辑块)的使用情况,如果对应的逻辑块使用了,则逻辑块位图的值为1
i节点位图:对应着后面i节点的使用情况,如果i节点使用了则对应i节点位图的位置1
i节点:目录与磁盘的桥接,文件的属性描述
数据区的盘块:用来存储数据
i节点位图,块中1bit对应一个i节点 1024 * 8 - 1 = 8191个 0位不用
逻辑块位图中1bit对应一个逻辑块
所有的块大小是固定的,都是盘块或者磁盘块
扇区:是块设备上长度为512B的数据块。不同文件系统,扇区和盘块对应关系不同
2个扇区 对应一个盘块1024B MINX
逻辑块号是从第一个引导快开始计数的
struct m_inode {
unsigned short i_mode;//文件的类型和属性,
unsigned short i_uid; //宿主的用户ID
unsigned long i_size; //该文件的大小
unsigned long i_mtime;//该文件的修改时间
unsigned char i_gid; //宿主的组ID
unsigned char i_nlinks; //链接数,记录链接到本文件的数目
unsigned short i_zone[9]; //该文件映射在逻辑块号(数据区)的数组,表示占用了那些数据的的盘块,文件和磁盘的映射。
//前7个为直接块号,每一个代表一个块号
//第8个一次间接块号,代表了512个块号
//第9个二次间接块号,代表512*512个块号
/* these are in memory also */
struct task_struct * i_wait; //等待i节点的进程
unsigned long i_atime;//最后访问的时间
unsigned long i_ctime;//i节点自身被修改的时间
unsigned short i_dev;//i节点所在的设备号
unsigned short i_num;//i节点号
unsigned short i_count;//i节点被引用的次数,0是空闲
unsigned char i_lock;//i节点被锁定的标志
unsigned char i_dirt;//i节点被修改的标志
unsigned char i_pipe;//i节点用作管道标志
unsigned char i_mount;//i节点安装其他文件系统的标志
unsigned char i_seek;//收索标志
unsigned char i_update;//i节点已更新的标志
};
例如crw-rw-
c代表文件类型
c:字符型设备
b:块设备
p:管道
l:链接
d:目录
-:普通文件
s:符号文件
属性:rwxrwxrwx
第一个rwx:表示当前用户的权限
第二个rwx:表示当前用户组的权限
第三个rwx:其他人的权限
struct super_block {
unsigned short s_ninodes;//i节点数目
unsigned short s_nzones;//逻辑块数
unsigned short s_imap_blocks;//i节点位图所占块数
unsigned short s_zmap_blocks;//逻辑块位图所在块数
unsigned short s_firstdatazone;//数据区中第一个逻辑块块号
unsigned short s_log_zone_size;//log2(磁盘块/逻辑块)
unsigned long s_max_size;//最大文件长度
unsigned short s_magic;//文件系统幻术(0x137f)
/* These are only in memory */
struct buffer_head * s_imap[8]; //i节点位图在高速缓冲块指针数组, 从磁盘上缓冲到对应的缓冲区上,数组存放在缓冲区对应的地址,一个设备最大支持8个文件系统
struct buffer_head * s_zmap[8]; //i节点位图在高速缓冲块指针数组
unsigned short s_dev; //设备号
struct m_inode * s_isup; //根目录的I节点, 被安装文件系统根目录的i节点
struct m_inode * s_imount;//安装i节点, 该文件系统被安装到的i节点
unsigned long s_time;//修改时间
struct task_struct * s_wait;//等待本超级快进程的指针
unsigned char s_lock; //锁定标志
unsigned char s_rd_only;//只读标志
unsigned char s_dirt;//已被修改的配置
};
不管读取磁盘上什么资源,都是:
先getblk(获取该资源对应的设备和块号对用的缓冲区)
然后bread(确认有效数据的缓冲区
最后进行区域内存的拷贝,从bh(buff_head结构体)b_data数据区域拷贝到数据的内存中
操作i节点位图和逻辑块位图(销毁,创建,查找)
/*
* linux/fs/bitmap.c
*
* (C) 1991 Linus Torvalds
*/
//将指定地址的一块1024字节内存清0
#define clear_block(addr) \
__asm__("cld\n\t" \
"rep\n\t" \
"stosl" \
::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
//指定地址开始的第nr个位偏移处的比特位置位(置1), 并返回原来bit位。可以用来操作i节点位图和逻辑位图
#define set_bit(nr,addr) ({\
register int res __asm__("ax"); \
__asm__ __volatile__("btsl %2,%3\n\tsetb %%al": \
"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
res;})
//指定地址开始的第nr个位偏移处的比特位复位(置0), 并返回原来bit位。可以用来操作i节点位图和逻辑位图
#define clear_bit(nr,addr) ({\
register int res __asm__("ax"); \
__asm__ __volatile__("btrl %2,%3\n\tsetnb %%al": \
"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
res;})
//从addr开始寻找第一个0值的比特位,并返回偏移量。可以用来找i节点位图和逻辑位图空闲的位置
#define find_first_zero(addr) ({ \
int __res; \
__asm__("cld\n" \
"1:\tlodsl\n\t" \
"notl %%eax\n\t" \
"bsfl %%eax,%%edx\n\t" \
"je 2f\n\t" \
"addl %%edx,%%ecx\n\t" \
"jmp 3f\n" \
"2:\taddl $32,%%ecx\n\t" \
"cmpl $8192,%%ecx\n\t" \
"jl 1b\n" \
"3:" \
:"=c" (__res):"c" (0),"S" (addr):"ax","dx","si"); \
__res;})
//释放逻辑块
void free_block(int dev, int block)
{
struct super_block * sb;
struct buffer_head * bh;
if (!(sb = get_super(dev))) //根据设备号获取设备对应的超级快结构体
panic("trying to free block on nonexistent device");
if (block < sb->s_firstdatazone || block >= sb->s_nzones) //传入块号,在第一个块号和最后块号范围之外,就报错
panic("trying to free block not in datazone");
bh = get_hash_table(dev,block); //是否能在hash表中找到,对应的高速缓冲区
if (bh) {//已经在高速缓冲区中存在,下面就把对应的高速缓冲区释放
if (bh->b_count != 1) {//b_count为0 表示未在使用,不需要释放
printk("trying to free block (%04x:%d), count=%d\n",
dev,block,bh->b_count);
return;
}
//以下是在使用的状态
bh->b_dirt=0;//修改状态清空
bh->b_uptodate=0;//更新状态清空
brelse(bh);//释放高速缓冲区
}
//不在高速缓冲区或者已经从高速缓冲区释放,再进行下面操作
//复位block在逻辑块图的比特位(置0), 先计算block在数据区开始运算起的数据逻辑块号(从1开始运算)
//然后对逻辑块位图进行操作,复位对应的bit位,如果对应的bit位原来就是0,则停机出错
//由于1个缓冲区块1024字节,即8192 bit。因此block / 8192,可以计算出指定块block在逻辑位图中的哪个块上,
//而block&8191 (8191 = 0x1FFF)(相当于block%8191)可以得到block在逻辑块图中bit位的偏移
block -= sb->s_firstdatazone - 1 ; //计算这个块在数据区相对于数据区起始位置的位置
if (clear_bit(block&8191,sb->s_zmap[block/8192]->b_data)) { //清空这个块的块的对应的逻辑位图,成功返回0表示(由1->0)
printk("block (%04x:%d) ",dev,block+sb->s_firstdatazone-1);
panic("free_block: bit already cleared");
}
sb->s_zmap[block/8192]->b_dirt = 1;//相应的逻辑块位图所在缓冲区的 已修改标志置1
}
//新建逻辑块
int new_block(int dev)
{
struct buffer_head * bh;
struct super_block * sb;
int i,j;
if (!(sb = get_super(dev)))
panic("trying to get new block from nonexistant device");
j = 8192;
for (i=0 ; i<8 ; i++) //遍历8个逻辑块位图
if (bh=sb->s_zmap[i]) //获取逻辑位图对应的的高速缓冲区
if ((j=find_first_zero(bh->b_data))<8192) //在高速缓冲区的位置,从缓冲区开始找到第一个为0的块位置,返回的位置小于8192即算找到
break;
if (i>=8 || !bh || j>=8192)
return 0;
if (set_bit(j,bh->b_data))//设置高速缓冲区的j的位置为1
panic("new_block: bit already set");
bh->b_dirt = 1;//修改标志置1,后期给写盘检测用不用写
j += i*8192 + sb->s_firstdatazone-1; //计算当前分配的逻辑块是第几个block
if (j >= sb->s_nzones)
return 0;
if (!(bh=getblk(dev,j))) //针对设备dev和块号j来获取缓冲区
panic("new_block: cannot get block");
if (bh->b_count != 1)//不为1就打印错误信息,因为getblk回把它置1
panic("new block: count is != 1");
clear_block(bh->b_data);//把缓冲区的内存清空
bh->b_uptodate = 1;//设置缓冲区更新标志
bh->b_dirt = 1;//设置缓冲区修改标志
brelse(bh);
return j;
}
//释放指定的i节点,把i节点对应的i节点位图中的bit置0,清空i节点位图的信息
void free_inode(struct m_inode * inode)
{
struct super_block * sb;
struct buffer_head * bh;
if (!inode)
return;
if (!inode->i_dev) { //设备号为0
memset(inode,0,sizeof(*inode));
return;
}
if (inode->i_count>1) {//>1 节点被使用
printk("trying to free inode with count=%d\n",inode->i_count);
panic("free_inode");
}
if (inode->i_nlinks)//>=1 节点被使用
panic("trying to free inode with links");
if (!(sb = get_super(inode->i_dev)))//取出超级块
panic("trying to free inode on nonexistent device");
if (inode->i_num < 1 || inode->i_num > sb->s_ninodes)//i_num不在正确范围内
panic("trying to free inode 0 or nonexistant inode");
if (!(bh=sb->s_imap[inode->i_num>>13])) //找到i节点对应的高速缓冲区
panic("nonexistent imap in superblock");
if (clear_bit(inode->i_num&8191,bh->b_data)) //清除对应位i节点位图上的bit位
printk("free_inode: bit already cleared.\n\r");
bh->b_dirt = 1;//修改标志置1
memset(inode,0,sizeof(*inode));
}
//创建一个新的i节点, 返回i节点的指针,通过super_block找到inode的信息(i节点位图, 逻辑块位图)
//通过inode操作函数找到对应的inode的分配内存区
//设置inode位图中对应的位为1
//返回设置号的inode结构体
struct m_inode * new_inode(int dev)
{
struct m_inode * inode;
struct super_block * sb;
struct buffer_head * bh;
int i,j;
if (!(inode=get_empty_inode())) //找到空闲的inode
return NULL;
if (!(sb = get_super(dev)))
panic("new_inode with unknown device");
j = 8192;
for (i=0 ; i<8 ; i++)
if (bh=sb->s_imap[i])
if ((j=find_first_zero(bh->b_data))<8192)
break;
if (!bh || j >= 8192 || j+i*8192 > sb->s_ninodes) {
iput(inode);
return NULL;
}
if (set_bit(j,bh->b_data)) //对应高速缓冲区的位置置位
panic("new_inode: bit already set");
bh->b_dirt = 1;
inode->i_count=1;
inode->i_nlinks=1;
inode->i_dev=dev;
inode->i_uid=current->euid;
inode->i_gid=current->egid;
inode->i_dirt=1;
inode->i_num = j + i*8192; //在逻辑块上的位置
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
return inode;
}
mount
操作系统中有一个超级块数组
mount->把需要挂在设备文件系统的super_block读到高速缓冲区中并且放到超级块数组中
处理inode节点的函数
iget:获得inode节点
iput:释放inode节点
bmap:对文件进行磁盘映射
从磁盘读写数据信息 inode的流程
/*
* linux/fs/inode.c
*
* (C) 1991 Linus Torvalds
*/
#define BLOCK_SIZE 1024
#define INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct d_inode)))
//把i节点的信息写入缓冲区中
//该函数把参数指定的i节点信息写入缓冲区相应的缓冲区块中,待缓冲区刷新时会写入磁盘。
//为了确认i节点所在的逻辑块号(或缓冲块)必须首先读取相应设备上的超级块,已获取用于计算逻辑块号的每块i节点信息INODES_PER_BLOCK
//在计算出i节点所在逻辑块号后,就把该逻辑块读入一缓冲块中,然后把i节点的内容复制到缓冲块的相应位置处
static void write_inode(struct m_inode * inode)//参数struct m_inode * inode是自己在内存上开辟的空间,不在磁盘上,也不在高速缓冲区
{
struct super_block * sb;
struct buffer_head * bh;
int block;
lock_inode(inode);//锁定i节点
if (!inode->i_dirt || !inode->i_dev) { //(i节点没有被修改过 || i节点设备号是0)
unlock_inode(inode); //解锁i节点
return;//退出
}
if (!(sb=get_super(inode->i_dev)))//获得i节点对应的超级块
panic("trying to write inode without device");
//计算当前inode节点的
// i节点所在的逻辑块号 = 2 (引导快 + 超级快) + i节点位图个数 + 逻辑块的个数 + (i节点总数-1)/ 每一块含i节点的个数
block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +(inode->i_num-1)/INODES_PER_BLOCK;
if (!(bh=bread(inode->i_dev,block))) //从设备读取i节点所在的逻辑块
panic("unable to read i-node block");
//把该i节点的信息复制到逻辑块对应该i节点啊的项位置处
((struct d_inode *)bh->b_data)[(inode->i_num-1)%INODES_PER_BLOCK] = *(struct d_inode *)inode;
bh->b_dirt=1; //缓冲区修改标志置1
inode->i_dirt=0; //i节点的内容和缓冲区一直,因此修改标志置0
brelse(bh);//释放该含有i节点的缓冲区
unlock_inode(inode);//解锁i节点
}
//inode同步
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的信息, 读出的信息不报括内存动态信息信息的,只有struct d_inode的信息
static void read_inode(struct m_inode * inode) //struct m_inode * inode是自己在内存上开辟的空间
{
struct super_block * sb;
struct buffer_head * bh;
int block;
lock_inode(inode);//i节点上锁
if (!(sb=get_super(inode->i_dev)))//获取超级快
panic("trying to read inode without dev");
//计算当前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");
//从高速缓冲区中 读到用户的inode结构体中
*(struct d_inode *)inode =((struct d_inode *)bh->b_data)[(inode->i_num-1)%INODES_PER_BLOCK];
brelse(bh);//释放缓冲区中
unlock_inode(inode);//i节点解锁
}
高速缓冲区与磁盘同步
系统调用,进行同步
int sys_sync(void)
{
int i;
struct buffer_head * bh;
sync_inodes(); /* write out inodes into buffers */
bh = start_buffer;
for (i=0 ; i<NR_BUFFERS ; i++,bh++) { //遍历高速缓冲区
wait_on_buffer(bh);
if (bh->b_dirt) //当前缓冲区修改标志位为1
ll_rw_block(WRITE,bh);//调用底层驱动,进行写盘操作
}
return 0;
}
主要是对i_zone进行赋值
struct m_inode {
unsigned short i_zone[9]; //inode节点的磁盘块映射,
前7个对应直接的逻辑块号(大小为7 * 1K = 7K),
第8个对应一次间接块(1024/2 = 512 个逻辑块,地址是short类型占2个字节。大小为512 * 1K = 512K)
第9个对应二次间接块(512 个一次间接块 512 * 512 个逻辑块。 大小为 512*512*1K)
则一个文件最大的块数 7 + 512 + 512*512 = 262663
则一个文件最大值为7K + 512K + 512*512K = 262663K = 256.5M
如有已有磁盘信息则进行赋值
如果没有磁盘信息先分配再赋值
文件数据块映射到盘块的处理操作, 调用一次申请一个block
inode: 文件的i节点指针
block: 文件中的数据块号
create: 创建标志
该函数把指定文件数据块block对应到设备上的逻辑块上,并返回逻辑块号。
如果创建标志位置位,则在设备上对应逻辑块不存在时就申请新的磁盘块,返回文件数据块block对应在设备上的逻辑号(盘块号)
static int _bmap(struct m_inode * inode,int block,int create)
{
struct buffer_head * bh;
int i;
//判断block得有效性
if (block<0)
panic("_bmap: block<0");
if (block >= 7+512+512*512) //超过文件的最大限制
panic("_bmap: block>big");
//块号 小于7
if (block<7) {//小于7,直接块号就可以
if (create && !inode->i_zone[block]) //crete为1 创建新 为0不创建 , inode->i_zone[block]为0表示对应的块中没有信息
if (inode->i_zone[block]=new_block(inode->i_dev)) { //新块创建,并把块号放到i_zone中去
inode->i_ctime=CURRENT_TIME; //时间标志
inode->i_dirt=1; //修改标志
}
return inode->i_zone[block];//返回块号
}
//块号 大于等于7 且小于512+7
block -= 7;//去掉直接块的大小
if (block<512) {//一次间接块大小小于512
if (create && !inode->i_zone[7])//创建 && i_zone[7]= 0。说明是首次使用间接块
if (inode->i_zone[7]=new_block(inode->i_dev)) {//申请一磁盘块来存放间接块信息,把块号写到i_zone[7]
inode->i_dirt=1;//设置i节点已修改
inode->i_ctime=CURRENT_TIME;//设置i节点修改时间
}
if (!inode->i_zone[7])//i_zone[7]= 0。创建失败
return 0;
if (!(bh = bread(inode->i_dev,inode->i_zone[7])))//读取i节点一次间接块,读到高速缓冲区
return 0;
i = ((unsigned short *) (bh->b_data))[block];.//取得间接块中第block项中逻辑块号i,每一项占2个字节
if (create && !i)//create = 1 && i = 0
if (i=new_block(inode->i_dev)) {//申请一个盘块,块号赋值给i
((unsigned short *) (bh->b_data))[block]=i; //让间接块第block项等于该新逻辑块号i
bh->b_dirt=1;//间接块得高速缓冲区修改标志位置1
}
brelse(bh);//释放该间接块占用的高速缓冲区
return i;//返回磁盘上新申请或原有对应block的逻辑块块号
}
//块号 大于512+7 分配二级间接块
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;
if (!(bh=bread(inode->i_dev,inode->i_zone[8])))//读取该i节点的二次间接块到缓冲区
return 0;
i = ((unsigned short *)bh->b_data)[block>>9];//并读取该二次间接块的一级块第(block / 512)项的逻辑块号i
if (create && !i)//创建 && i= 0
if (i=new_block(inode->i_dev)) { //则为i分配一个块
((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)))//读取该i节点的一次间接块到缓冲区
return 0;
i = ((unsigned short *)bh->b_data)[block&511];//读取一次间接块上的第(block%511)项直接逻辑块号
if (create && !i)//创建 && i= 0
if (i=new_block(inode->i_dev)) {//则为i分配一个块
((unsigned short *) (bh->b_data))[block&511]=i;//把分配的块号赋值给直接块项上
bh->b_dirt=1;
}
brelse(bh);
return i;
}
//读取文件数据块block在设备中对应的逻辑块号
//成功:返回对应的逻辑块号。失败:返回0
int bmap(struct m_inode * inode,int block)
{
return _bmap(inode,block,0);
}
//读取文件数据块block在设备中对应的逻辑块号
//如果对应得逻辑块号不存在就创建一块。返回设备上对应已存在或者新建得逻辑块号
//成功:返回对应的逻辑块号。失败:返回0
int create_block(struct m_inode * inode, int block)
{
return _bmap(inode,block,1);
}
主要是对i_count引用次数进行操作,把i节点引用数值减1
并且若是管道i节点,则唤醒等待进程
若是块设备文件i节点则刷新设备
若i节点的链接计数为0,则释放该i节点占用的所有磁盘逻辑块,并释放该节点
void iput(struct m_inode * inode)
{
if (!inode) //判断i节点的有效性
return;
wait_on_inode(inode);//等地啊i节点解锁(如果已经上锁的话)
if (!inode->i_count)//i节点应用计数是0,表示i节点已经是空闲的,内核还要球释放放回操作,说明其调用代码有问题,显示错误并停机
panic("iput: trying to free free inode");
if (inode->i_pipe) {//inode是pipe 管道节点
wake_up(&inode->i_wait);//唤醒等待管道的等待队列
if (--inode->i_count)//引用计数减1,如果还有引用则直接返回
return;
free_page(inode->i_size);//否则释放管道占用的内存页面。对于管道节点,inode->size存放着内存页地址,参考get_pipe_inode() 288,234行
//复位该节点的引用计数,已修改标志位和管道标志,并返回。
inode->i_count=0;
inode->i_dirt=0;
inode->i_pipe=0;
return;
}
if (!inode->i_dev) {//i节点对于的设备号是0,则将此节点应用计数递减1,返回。例如用于管道操作的i节点,对于的设备号是0
inode->i_count--;
return;
}
if (S_ISBLK(inode->i_mode)) { //如果是块设备,先进行块的同步刷新设备
sync_dev(inode->i_zone[0]);//同步,i_zone[0]存放的是设备号
wait_on_inode(inode);//等待inode节点解锁
}
repeat:
if (inode->i_count>1) {//引用仍大于1,则说明还被引用,则不能释放
inode->i_count--; //递减后直接返回
return;//结束返回
}
//引用 <= 1, 则检查链接数和已修改标志位
if (!inode->i_nlinks) {//i_nlinks链接为0,说明i节点对应文件被删
truncate(inode); //释放i节点的所有逻辑块
free_inode(inode); //释放i节点,即复位i节点对应的i节点位图上的bit位,清空i节点结构内容
return;//结束返回
}
//链接数不为0,则检查已修改标志位
if (inode->i_dirt) {//修改位是1,则先写盘,在去释放
write_inode(inode); /* we can sleep - so do again */ //回写更新i节点
wait_on_inode(inode);//等待i节点解锁,由于此时其他进程可能修改i节点,因此唤醒后需要再次重复上述判断过程
goto repeat;//再次回到repeat处执行
}
//执行到此,说明引用计数为1, 有链接不为0,修改标志为0。此时只要把i节点引用计数减1,返回。此时i_count = 0 表示已经释放
inode->i_count--;
return;
}
struct m_inode * iget(int dev,int nr)
参数:
dev - 设备号
nr - i节点号
从设备上读取指定节点号的i节点到内存i节点表中,并返回该i节点指针
首先在位于高速缓冲区的i节点表中寻找,若找到指定节点号的i节点则再经过一些判断处理后返回i节点指针
否则通过设备号和指定i节点号,从设备中读取的i节点信息,放入在i节点表中申请的空闲节点中,并返回该i节点指针
struct m_inode * iget(int dev,int nr)//nr是设备第几个节点
{
struct m_inode * inode, * empty;
if (!dev) //有效性判断
panic("iget with dev==0");
empty = get_empty_inode();//从i节点表中,取出一个空闲的的inode节点备用
inode = inode_table;
while (inode < NR_INODE+inode_table) {//遍历inode_table
if (inode->i_dev != dev || inode->i_num != nr) {//找到和dev和nr都相等的节点
inode++;
continue;
}
wait_on_inode(inode);//找到后等待节点,等待过程中i节点可能会发生变化
if (inode->i_dev != dev || inode->i_num != nr) {//等待结束后再次验证,如果发生了变化则再次重新扫描整个i节点表
inode = inode_table;
continue;
}
inode->i_count++;//找到相应的i节点,把节点引用计数加1
if (inode->i_mount) {//查看是否是另一个文件系统的安装点。若是则寻找被安装文件系统根节点并返回。
//意思就是这个节点如果是挂在另一个设备的文件系统,那么需要得到就是这个被挂载的文件系统,获取这个文件系统的根节点即可,
//那么就需要得到这个设备的设备号dev,和根界节点 1, 就能找到这个文件系统根节点,也就能访问这个文件系统了
int i;
for (i = 0 ; i<NR_SUPER ; i++)//在超级块中寻找安装在此i节点的超级块
if (super_block[i].s_imount==inode) //找到超级快super_block
break;
if (i >= NR_SUPER) {//没有找到超级快
printk("Mounted inode hasn't got sb\n");//显示错误信息
if (empty)
iput(empty);//放回本函数开始时获取的空闲节点empty
return inode;//把在节点表中找到符合要求的i节点返回
}
iput(inode);//找到安装到inode节点的文件系统的超级块后,将i节点写盘放回
dev = super_block[i].s_dev;//获取超级快中的设备号
nr = ROOT_INO;//令i节点号为ROOT_INO (#define ROOT_INO 1)
inode = inode_table;//i节点指向节点链表头,重新扫描整个i节点表,以获取该被安装文件系统的i节点信息
continue; //回到 while (inode < NR_INODE+inode_table)
}
if (empty)
iput(empty);//放回本函数开始时获取的空闲节点empty
return inode; //把在节点表中找到符合要求的i节点返回
}
//执行到此,说明没有在i节点表中找到指定的i节点,则利用前面申请的空闲i节点empty,在i节点表中建立该i节点
if (!empty)//为0返回NULL
return (NULL);
inode=empty;//i节点指向empty
inode->i_dev = dev;//对i节点赋值设备号
inode->i_num = nr;//对i节点赋值节点号
read_inode(inode);//根据i节点的dev和nr,从相应的设备上读取信息,复制到i节点中
return inode;//在节点表中新建的i节点返回
}
struct m_inode * get_empty_inode(void)
{
struct m_inode * inode;
static struct m_inode * last_inode = inode_table;
int i;
//在inode节点数组中找到一个没有被引用修改的空槽
do {
inode = NULL;
for (i = NR_INODE; i ; i--) {
if (++last_inode >= inode_table + NR_INODE)
last_inode = inode_table;
if (!last_inode->i_count) {
inode = last_inode;
if (!inode->i_dirt && !inode->i_lock)
break;
}
}
//inode =0,没有找到,则打印当前全部的inode
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) {//i_dirt修改标志位位1,则写回磁盘
write_inode(inode);
wait_on_inode(inode);
}
} while (inode->i_count);
memset(inode,0,sizeof(*inode)); //清0 inode节点内存
inode->i_count = 1;
return inode;
}
struct m_inode * get_pipe_inode(void)
{
struct m_inode * inode;
if (!(inode = get_empty_inode()))
return NULL;
if (!(inode->i_size=get_free_page())) {//为当前inode节点分配一个内存页,作为pipe
inode->i_count = 0;
return NULL;
}
inode->i_count = 2; /* sum of readers/writers */ //这个节点又读又写,引用置2,一个进程读,一个进程写
PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;//初始化pipe的头尾
inode->i_pipe = 1;//i_pipe置1
return inode; //返回inode节点
}