linux0.11文件系统文件读写1

来源:互联网 发布:返利软件有哪些 编辑:程序博客网 时间:2024/04/30 19:36


首先,我们要明确要用到的数据结构:
struct file{
           unsigned short f_mode;
           unsigned short f_flages;
           unsigned short f_count;
           struct m_inode *f_inode;
           off_t f_pos;
};
 
struct file *filp[NR_OPEN];
struct file file_table[NR_FILE];


    下面我们假定用户进程要打开/mnt/user/helloc.txt这个文件(int fd =open("/mnt/user/helloc.txt",O_RDWR,0644) ;
    首先第一步将用户进程管理结构中的*filp[20]与内核中的文件管理结构file_table[64]进行挂接:
        历遍task_struct中的*filp[20]和内核管理表file_table[64],找出他们中的空闲项
int sys_open(const char *filename, int flag,int mode)
  {
    struct m_inode * inode;
    struct file *f;
    int i, fd;


    
mode &= 0777 & ~current->umask;
    for(fd = 0 ;fd<NR_OPEN ;fd++)
if (!current-> filp[fd])
break;
if(fd>=NR_OPEN)
return -EINVAL;

current->close_on_exec &= ~(1<<fd);
f = 0+file_table;
for(i = 0; i<NR_FILE; i++, f++)
if(!f->f_count)
break;
if(i >= NR_FILE)
return -RINVAL;
             


}
 然后让两者挂接:
(current->filp[fd] = f)-> f_count++;
第二步:以用户给定的路径名“/mnt/user/helloc.txt”为线索,找到helloc.txt文件的I节点:
                                        
        我觉得上图很好的表明了查找的某个文件i节点的步骤(另外上图是LINUX内核设计的艺术这本书上的,我个人认为这本书不错),下面我们开始实质性的解析工作,解析路径是通过get_dir()这个函数完成的,他的下面有两个平行的函数,分别是:find_entry()在目录文件中找到与指定目录名相同的项和iget()获取i节点。
   
static struct m_inode *get_dir(const char * pathname, struct m_inode * ionde)
{
char c;
const char * thisname;
struct buffer_head *bh;
int manelen, inr;
struct dir_entry * de;
struct m_inode * dir;


if(!inode) {
inode = current -> pwd;
inode -> i_count++;
}
if ((c = get_fs_byte(pathname)) == '/'){
iput(inode);
inode = current->root;
pathname++;
inode-> i_count++;
}  //前面这些代码的作用是确定i节点

while(1) {
thisname = pathname;  //这时pathname已经指向‘mnt’这个字符串了
if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)){
iput(inode);
return NULL;
}
for(namelen = 0; (c = get_fs_byte(pathname++))&&(c!='/');namelen++)

if(!c)
return inode;
       if(!(bh = find_entry(&inode, thisname, namelen, &de))){  //thisname确定了位置,namelen确定长度,这样就锁定了字符串了。
iput(inode);
return NULL;
}
inr = de->inode;  //看来find_entry这个函数的作用之一就是提供目录项,以便通过目录项取得i节点号。
brelse(bh);
dir = inode;   //根目录I节点
if (!(inode = iget(dir->i_dev, inr))){
iput(dir);
return NULL;
}
if(!(inode = follow_link(dir, inode)))
return NULL;
}
}
     下面看一下find_entry这个函数:
static struct buffer_head * find_entry(struct m_inode **dir, const char * name, int namelen, struct dir_entry ** res_dir)
{
int entries;
int block,i;
struct buffer_head *hd;
struct dir_entry *de;
struct super_block * sb;
............
if(!(block = (*dir)->i_zone[0])) //zone[]文件所占用的盘上逻辑块号数组
return NULL;
if(!(bh = bread((*dir)->i_dev,block)))//通过i节点找到设备号和逻辑盘块号(数据块号),从而将硬盘上的指定数据块读入相应缓冲区中
return NULL;
i = 0;
de = (struct dir_entry *)bh->b_data;
while(i < entries) {
if((char*)de >= BLOCK_SIZE+bh->b_bata) {
brelse(bh);
bh = NULL;
if(!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK))||!(bh = bread((*dir)->i_dir,bolck))){
i+= DIR_ENTRIES_PER_BLOCK;
continue;
}
de = (struct dir_entry *)bh->b_data;
}
if(match(namelen,name,de)){
*res_dir = de;
return bh;
}
de++;
i++;
}
brelse(bh);
return NULL;
}


       上面这个函数主要功能是找到目录文件,然后与指定目录项进行比较,然后返回缓冲区和目录项结构。
       下面看一看i节点捕获函数iget(),这个函数通过设备号dev和i节点号nr来确定,设备号是通过上一个目录项的i节点确定下来的,nr是通过find_entry()这个函数得来的。
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(ionde->i_dev != || inode-> i_num != nr){
ionde = inode_table;
continue;
}
inode-> i_conut++;
if (inode-> i_mount) {
int i;

for(i =0;i< NR_SUPER; i++)
if(super_block[i].s_imount == inode)  //这个i节点就是mnt的i节点,它在之前放在inode_table[32]中
break;
if (i >= NR_SUPER){
printk("Mounted ionde hasn`s got sb\n");
if (empty)
iput (empty);
return inode;
}
iput(inode);
dev = super_block[i].s_dev;
nr = ROOT_INO;
inode = inode_table;
continue;
}
if (empty)
iput(empty);
return inode;
}
if (!empty)
return (NULL);
inode = empty;
inode-> i_dev = dev;
inode-> i_num = nr;  //i节点号,在read_inode()中用于确定i节点所在的盘块号
read_inode(inode);
return inode;
}


   这段代码中inode = inode_table;引进了内核中的inode_table表,然后通过参数dev和nr来与inode_table中的i节点比较:if (inode->i_dev != i_dev || inode->i_num != nr),如果找到,就判断是不是挂载点,如果是挂载点,我们就通过被安装文件系统的超级块找到设备号,再人工设置i节点号ROOT_INO,因为从未在inode_table表中设置过硬盘的根文件节点,所以就执行read_inode(inode);

    
                                                 


0 0