您的位置:首页 > 运维架构 > Linux

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

2014-01-29 22:27 218 查看
首先,我们要明确要用到的数据结构:

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);



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: