/*
* linux/fs/bitmap.c
*
* (C) 1991 Linus Torvalds
*/
/* bitmap.c contains the code that handles the inode and block bitmaps */
#include <string.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#define clear_block(addr) \
__asm__("cld\n\t" \
"rep\n\t" \
"stosl" \
::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")//将指定地址(addr)处的一块1024字节内存清零
#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 个位偏移处的比特位(nr 可以大于32!),返回原比特位(0 或1)
#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;})// 复位指定地址开始的第nr 位偏移处的比特位。返回原比特位的反码
#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;})// 从addr 开始寻找第1 个0 值比特位,并将其距离addr 的比特位偏移值返回
void free_block(int dev, int block)// 释放设备dev 上数据区中的逻辑块block
{
struct super_block * sb;
struct buffer_head * bh;
if (!(sb = get_super(dev)))// 取指定设备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) {
printk("trying to free block (%04x:%d), count=%d\n",
dev,block,bh->b_count);
return;
}
bh->b_dirt=0;/* 0-clean,1-dirty *///修改标志0为未修改,1为修改
bh->b_uptodate=0;//更新标志,缓冲区上的数据是否为块上的数据同步,1为与硬盘上的数据同步一样
brelse(bh);// 本任务释放指定的缓冲块区,
}//以下操作为,复位blok在逻辑块位图中的比特位
block -= sb->s_firstdatazone - 1 ;// 计算block 在数据区开始算起的数据逻辑块号(从1 开始计数)
if (clear_bit(block&8191,sb->s_zmap[block/8192]->b_data)) {// 复位指定地址开始的第nr 位偏移处的比特位,一个缓冲块有1024字节,8192比特位
printk("block (%04x:%d) ",dev,block+sb->s_firstdatazone-1);
panic("free_block: bit already cleared");
}
sb->s_zmap[block/8192]->b_dirt = 1;// 置相应逻辑块位图所在缓冲区已修改标志, 0-clean,1-dirty 修改标志0为未修改,1为修改
}
int new_block(int dev)//向设备dev 申请一个逻辑块(盘块,区块),返回逻辑块号(盘块号)
{
struct buffer_head * bh;
struct super_block * sb;
int i,j;
if (!(sb = get_super(dev)))// 取指定设备dev 的超级块,如果指定设备不存在,则出错死机
panic("trying to get new block from nonexistant device");
j = 8192;//一块的比特位,1k=1024字节==1024*8比特位
for (i=0 ; i<8 ; i++)//寻找全部8块逻辑块位图,每块为1K(1024*8==8192)比特位
if (bh=sb->s_zmap[i])
if ((j=find_first_zero(bh->b_data))<8192)// 从addr 开始寻找第1 个0 值比特位,并将其距离addr 的比特位偏移值返回
break;
if (i>=8 || !bh || j>=8192)// 如果全部扫描完还没找到(i>=8 或j>=8192)或者位图所在的缓冲块无效(bh=NULL)则 返回0
return 0;
if (set_bit(j,bh->b_data))// 置位指定地址开始的第nr 个位偏移处的比特位(nr 可以大于32!),返回原比特位(0 或1)
panic("new_block: bit already set");
bh->b_dirt = 1;/* 0-clean,1-dirty *///修改标志0为未修改,1为修改
j += i*8192 + sb->s_firstdatazone-1;//将J转化为逻辑块号
if (j >= sb->s_nzones)// sb->s_nzones为总的逻辑块数
return 0;
if (!(bh=getblk(dev,j)))//然后在高速缓冲区为该设备指定的逻辑块号取一缓冲块区
panic("new_block: cannot get block");
if (bh->b_count != 1)// 新块的引用计数应为1,
panic("new block: count is != 1");
clear_block(bh->b_data);//将新申请遥逻辑块区清0,将指定地址(addr)处的一块1024字节内存清零
bh->b_uptodate = 1;//更新标志,缓冲区上的数据是否为块上的数据同步,1为与硬盘上的数据同步一样
bh->b_dirt = 1;/* 0-clean,1-dirty *///修改标志0为未修改,1为修改
brelse(bh);// 本任务释放指定的缓冲块区,(这里有点不明白,为什么刚申请了缓冲块,又给释放了呢?)
return j;
}
void free_inode(struct m_inode * inode)// 释放指定的i 节点
{
struct super_block * sb;
struct buffer_head * bh;
if (!inode)// 如果i 节点指针=NULL,则退出
return;
if (!inode->i_dev) {// i 节点所在的设备,如果为空则说明此节点没有被使用,用0填充所有内存
memset(inode,0,sizeof(*inode));//用0填充此节点的所有内存
return;
}
if (inode->i_count>1) {// 如果此i 节点还有其它程序引用,则不能释放,说明内核有问题,死机
printk("trying to free inode with count=%d\n",inode->i_count);
panic("free_inode");
}
if (inode->i_nlinks)// 如果文件目录项连接数不为0,则表示还有其它文件目录项在使用该节点,不应释放,而应该放回
panic("trying to free inode with links");
if (!(sb = get_super(inode->i_dev)))// 取i 节点所在设备的超级块,并测试设备是否存在
panic("trying to free inode on nonexistent device");
if (inode->i_num < 1 || inode->i_num > sb->s_ninodes)// 如果i 节点号小于0 或大于该设备上i 节点总数,则出错
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))// 复位指定地址开始的第nr 位偏移处的比特位。返回原比特位的反码
printk("free_inode: bit already cleared.\n\r")
bh->b_dirt = 1;// 置i 节点位图所在缓冲区已修改标志,并清空该i 节点结构所占内存区
memset(inode,0,sizeof(*inode));//释放此节点
}
struct m_inode * new_inode(int dev)// 为设备dev 建立一个新i 节点。返回该新i 节点的指针
{// 在内存i 节点表中获取一个空闲i 节点表项,并从i 节点位图中找一个空闲i 节点。
struct m_inode * inode;
struct super_block * sb;
struct buffer_head * bh;
int i,j;
if (!(inode=get_empty_inode()))// 从内存i 节点表(inode_table)中获取一个空闲i 节点项(inode)
return NULL;
if (!(sb = get_super(dev)))// 取i 节点所在设备的超级块,并测试设备是否存在
panic("new_inode with unknown device");
j = 8192;//一块的比特位,1k=1024字节==1024*8比特位
for (i=0 ; i<8 ; i++)//寻找全部8块节点位图,每块为1K(1024*8==8192)比特位
if (bh=sb->s_imap[i])
if ((j=find_first_zero(bh->b_data))<8192)// 从addr 开始寻找第1 个0 值比特位,并将其距离addr 的比特位偏移值返回
break;
if (!bh || j >= 8192 || j+i*8192 > sb->s_ninodes) {// 如果全部扫描完还没找到,或者位图所在的缓冲块无效(bh=NULL)则 返回0,退出
iput(inode);//放回刚才申请的inode节点
return NULL;
}
if (set_bit(j,bh->b_data))//将相应的i节点位图置位,置位指定地址开始的第nr 个位偏移处的比特位(nr 可以大于32!),返回原比特位(0 或1),如果已经置位,则出错
panic("new_inode: bit already set");
bh->b_dirt = 1;/* 0-clean,1-dirty *///修改标志0为未修改,1为修改
inode->i_count=1;// i 节点被使用的次数,0 表示该i 节点空闲。
inode->i_nlinks=1;// 文件目录项链接数。
inode->i_dev=dev;// i 节点所在的设备号。
inode->i_uid=current->euid;// 用户id(文件拥有者标识符)。
inode->i_gid=current->egid;// 组id(文件拥有者所在的组)。
inode->i_dirt=1;// 已修改(脏)标志。
inode->i_num = j + i*8192;// i 节点号。
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;// 修改时间(自1970.1.1:0 算起,秒)。
return inode;
}
转自http://shuwei.bian.blog.163.com/blog/static/142629666201022361139420/
阅读(1684) | 评论(0) | 转发(0) |