bitmap.c 位于 fs/bitmap.c路径下,其包含函数的主要做用是用于维护inode和block的数据结构。node
1)bitmap.clinux
该部分的汇编函数是经过汇编指令test and set指令进行并发控制数组
/**
** 备注:
** btsl指令: 将基地址%3 和 偏移量 %2 所对应的位存放到进位标识位CF上,而后设置该位为1.
** setb指令: 将CF对应的值复制到对应寄存器上。
** 思考:
** 经过该两个指令能够实现一个同步的机制,好比while(set_bit(nr, addr))或if(!set_bit(nr, addr));
** 该过程保证某一时刻只有一个进程能够经过该判断,其余进程能够继续等待或者跳过。
**
**/
#define set_bit(nr,addr) ({\
register int res __asm__("ax"); \
__asm__("btsl %2,%3\n\tsetb %%al":"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
res;})
#define clear_bit(nr,addr) ({\
register int res __asm__("ax"); \
__asm__("btrl %2,%3\n\tsetnb %%al":"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
res;})
复制代码
该函数很是经常使用,由于linux文件系统包含了inode位图和block位图,经过位图的index去找到对应的位图结构体,经过位图结构体找到相应的块内容。缓存
能够看出如下代码,经过bsfl对eax寄存器进行对比获取第一位值,若是找不到,则跳转ecx并继续尝试。
#define find_first_zero(addr) ({ \
int __res; \
__asm__("cld\n" \ // 清方向位
"1:\tlodsl\n\t" \ // 取[esi] --> eax
"notl %%eax\n\t" \ // 将eax中每位都取反
"bsfl %%eax,%%edx\n\t" \ // 从0位开始扫描扫描eax中是1的第一位,其偏移量 --> edx
"je 2f\n\t" \ // 加入eax为0,则跳转到2的位置
"addl %%edx,%%ecx\n\t" \ // 偏移量加上ecx (ecx为第一个0值位的偏移值)
"jmp 3f\n" \ // 跳转到3位置
"2:\taddl $32,%%ecx\n\t" \ // ecx+1个长字节大小
"cmpl $8192,%%ecx\n\t" \ // 是否已经扫描了8192位了
"jl 1b\n" \ // 若没有扫描完则跳回1位置
"3:" \
:"=c" (__res):"c" (0),"S" (addr):"ax","dx","si"); \
__res;})
复制代码
block bitmap大小为8个8192位大小的数组。
void free_block(int dev, int block)
{
struct super_block * sb;
struct buffer_head * bh;
// first find super_block
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");
// find dev^block ==> bh
bh = get_hash_table(dev,block);
if (bh) {
if (bh->b_count != 1) {
printk("trying to free block (%04x:%d), count=%d\n",
dev,block,bh->b_count);
return;
}
bh->b_dirt=0;
bh->b_uptodate=0;
// clear bh content and put it dirty
brelse(bh);
}
block -= sb->s_firstdatazone - 1 ;
// clear bitmap table and set block unused.
if (clear_bit(block&8191,sb->s_zmap[block/8192]->b_data)) {
printk("block (%04x:%d) ",dev,block+sb->s_firstdatazone-1);
panic("free_block: bit already cleared");
}
// 设置block bitmap块为dirty
sb->s_zmap[block/8192]->b_dirt = 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;
// 遍历8次的8192位信息,找到合适的一个位
for (i=0 ; i<8 ; i++)
if (bh=sb->s_zmap[i])
if ((j=find_first_zero(bh->b_data))<8192)
break;
if (i>=8 || !bh || j>=8192)
return 0;
// 设置block使用位
if (set_bit(j,bh->b_data))
panic("new_block: bit already set");
bh->b_dirt = 1;
j += i*8192 + sb->s_firstdatazone-1;
if (j >= sb->s_nzones)
return 0;
// 找到j对应的block块,清空block内容,不为1则停机
if (!(bh=getblk(dev,j)))
panic("new_block: cannot get block");
if (bh->b_count != 1)
panic("new block: count is != 1");
clear_block(bh->b_data);
bh->b_uptodate = 1;
bh->b_dirt = 1;
brelse(bh);
return j;
}
复制代码
void free_inode(struct m_inode * inode)
{
struct super_block * sb;
struct buffer_head * bh;
if (!inode)
return;
if (!inode->i_dev) {
memset(inode,0,sizeof(*inode));
return;
}
if (inode->i_count>1) {
printk("trying to free inode with count=%d\n",inode->i_count);
panic("free_inode");
}
if (inode->i_nlinks)
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)
panic("trying to free inode 0 or nonexistant inode");
/*
** inode 对应的i_num为inode位图对应位置的索引号,进行右移获取对应的map索引
*/
if (!(bh=sb->s_imap[inode->i_num>>13]))
panic("nonexistent imap in superblock");
if (clear_bit(inode->i_num&8191,bh->b_data))
panic("free_inode: bit already cleared");
bh->b_dirt = 1;
memset(inode,0,sizeof(*inode));
}
struct m_inode * new_inode(int dev)
{
struct m_inode * inode;
struct super_block * sb;
struct buffer_head * bh;
int i,j;
// 建立一个空白的inode结构
if (!(inode=get_empty_inode()))
return NULL;
if (!(sb = get_super(dev)))
panic("new_inode with unknown device");
// 查找一个空闲的inode位图位置
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_dirt=1;
// 为inode设置i_num 以及相关属性
inode->i_num = j + i*8192;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
return inode;
}
复制代码
truncate.c 包含三个函数,该c文件的做用是清空inode指向的i_zone空间,清除分为三部,一步是清除直接block,一步是清除一级间接block,一步是清除二级间接blockbash
void truncate(struct m_inode * inode) {
int i;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
return;
//遍历前6个直接block,调用free_block清除位图上对应的位数
for (i=0;i<7;i++)
if (inode->i_zone[i]) {
free_block(inode->i_dev,inode->i_zone[i]);
inode->i_zone[i]=0;
}
// 清除间接block
free_ind(inode->i_dev,inode->i_zone[7]);
free_dind(inode->i_dev,inode->i_zone[8]);
inode->i_zone[7] = inode->i_zone[8] = 0;
inode->i_size = 0;
inode->i_dirt = 1;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
}
static void free_ind(int dev,int block) {
struct buffer_head * bh;
unsigned short * p;
int i;
if (!block)
return;
// 读取间接块指向的内容到buffer_head上,假设高速缓存中不存在该缓存,则其会调用驱动读取文件并复制到对应的b_data上。
if (bh=bread(dev,block)) {
// 获取buffer_head的b_data,并根据16位大小进行读取block号
p = (unsigned short *) bh->b_data;
for (i=0;i<512;i++,p++)
if (*p)
free_block(dev,*p);
brelse(bh);
}
free_block(dev,block);
}
static void free_dind(int dev,int block) {
struct buffer_head * bh;
unsigned short * p;
int i;
if (!block)
return;
if (bh=bread(dev,block)) {
p = (unsigned short *) bh->b_data;
for (i=0;i<512;i++,p++)
if (*p)
free_ind(dev,*p);
brelse(bh);
}
free_block(dev,block);
}
复制代码