<>1:基本信息
代码:linux-0.11
<>2:linux文件系统的几部分
* 有关linux中高速缓冲区的管理部分。分页机制 buff.c
* 文件系统的底层通用函数。(对于硬盘的读写,分配,释放,对于目录的节点管理,内存和磁盘的映射)
* 对文件数据进行读写操作的模块(VFS 虚拟文件系统,硬件驱动和文件系统的关系, pipe,块设备的读取)
* 文件系统与其他程序的接口实现(fopen 关闭,创建等文件的调用方式)
<>3.文件系统的基本概念
以磁盘为例,磁盘中有目录的映射,把磁盘分成盘片,每一个盘片 都有一个文件系统的子系统(章节目录)
引导块:用来引导设备的。可以为空,但是一定要空开,为了保持数据的一致性
超级块:该文件子系统描述符,记录该i节点位图和逻辑块位图的地址,通过设备号可以获取超级块
逻辑位图:其每一位对应数据区的盘块(逻辑块)的使用情况,如果对应的逻辑块使用了,则逻辑块位图的值为1
i节点位图:对应着后面i节点的使用情况,如果i节点使用了则对应i节点位图的位置1
i节点:目录与磁盘的桥接,文件的属性描述
数据区的盘块:用来存储数据
i节点位图,块中1bit对应一个i节点 1024 * 8 - 1 = 8191个 0位不用
逻辑块位图中1bit对应一个逻辑块
所有的块大小是固定的,都是盘块或者磁盘块
扇区:是块设备上长度为512B的数据块。不同文件系统,扇区和盘块对应关系不同
2个扇区 对应一个盘块1024B MINX
逻辑块号是从第一个引导快开始计数的
<>3.1 inode的结构体
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节点已更新的标志 };
<>3.1.1 文件的类型和属性
例如crw-rw-
c代表文件类型
c:字符型设备
b:块设备
p:管道
l:链接
d:目录
-:普通文件
s:符号文件
属性:rwxrwxrwx
第一个rwx:表示当前用户的权限
第二个rwx:表示当前用户组的权限
第三个rwx:其他人的权限
<>3.1.2 文件的类型和属性i_zone[9]
<>4:超级快的结构体
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数据区域拷贝到数据的内存中
<>5:bitmap.c
操作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读到高速缓冲区中并且放到超级块数组中
<>6: inode.c
处理inode节点的函数
iget:获得inode节点
iput:释放inode节点
bmap:对文件进行磁盘映射
从磁盘读写数据信息 inode的流程
* 找到dev
* 找到设备的super_block
* 通过sb的信息计算要读的块号
* 调用bread将其读取或写入到高速缓冲区
* 读:将高速缓冲区的b_data读到内存地址,释放高速缓冲区
写: 将要写入的数据写到高速缓冲的b_data 并设置dirt修改标志位,等待系统的sys_sync进行写盘,释放高速缓冲区
<>6.1 读写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; }
<>6.2 进行inode节点和磁盘块映射 bmap
主要是对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); }
<>6.3 释放一个inode节点
主要是对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; }
<>6.4 获得一个inode节点
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节点 }