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

Linux-0.12内核打开文件过程--sys_open源码分析

2014-05-25 20:34 866 查看


上图展示了进程打开文件使用的内核数据结构,所以要打开文件,就要构造上图中的关系。

int sys_open(const char *filename,int flag,int mode)
{
	struct m_inode *inode;
	struct file *f;
	int i,fd;
	
	mode&=0777&~current->umask;
	//在filp数组中寻找“空闲位置”
	for(fd=0;fd<NR_OPEN;fd++)
		if(!current->filp[fd])
			break;
	if(fd>=NR_OPEN)
		return -EINVAL;
	current->close_on_exec&=~(1<<fd);
	//在file_table中寻找“空闲位置”
	f=0+file_table;
	for(i=0;i<NR_FILE,i++,f++)
		if(!f->f_count)
			break;
	if(i>=NR_FILE)
		return -EINVAL;
	
	//此时我们让进程对应文件句柄fd的文件结构指针指向搜索到的文件结构,并令文件引用计数加1,然后调用open_namei()函数执行打开操作,如果返回值小于0,则说明出错,于是释放刚刚申请的文件结构,返回出错码i;若文件打开成功,则inode是打开文件的i节点指针。
	(current->filp[fd]=f)->count++;
	if((i=open_namei(filename,flag,mode,&inode))<0)
	{
		current->filp[fd]=NULL;
		f->f_count=0;
		return i;
	}
	....
	f->f_mode=inode->i_mode;
	f->f_flags=flag;
	f->f_inode=inode;
	f->f_pos=0;
	return fd;
}
注解:f->f_inode=inode,这步骤完成之后,本文上来的那个图的关系就全连起来了。

sys_open核心就在于open_namei()函数,这个函数会牵扯到整个文件系统,理解这个函数就对0.12内核的文件系统有一个整体的认识,下面来重点分析open_namei()函数,这会涉及到dir_namei()、get_dir()、find_entry()、new_inode()、add_entry()、follow_link()、bmap()等函数,我们需要首先说明这些函数的功能。

1.static struct m_inode* get_dir(const char *pathname,struct m_inode *inode)

功能:根据函数给定的路径名进行搜索,直到达到最顶端目录(/etc/bin/vi--bin/是最顶端目录喔!)

参数:

pathname--路径名

inode--指定其实目录的i节点

返回值:目录或者文件的i节点指针

2.static struct m_inode* dir_namei(const char *pathname,int *namelen,const char **name,struct m_inode *base)

功能:返回指定目录名的i节点指针,以及在最顶层目录的名称

参数:

pathname--目录路径名(in)

namelen--路径名长度(out)

name--返回的最顶层目录名(out)

base--搜索其实目录的i节点(in)

返回:指定目录名最顶层目录的i节点指针和最顶层目录名和长度,出错返回NULL

static struct m_inode* dir_namei(const char *pathname,int *namelen,const char **name,struct m_inode *base)
{
	char c;
	const char *basename;
	struct m_inode *dir;
	
	if(!dir=get_dir(pathname,base))
		return NULL;
	basename=pathname;
	while(c=get_fs_byte(pathname++)
		if(c=='/')
			basename=pathname;
	*namelen=pathname-basename-1;
	*name=basename;
	return dir;
}


比如给定目录/abc/def/gh

get_dir返回def目录对应的内存i节点

dir_namei,不仅完成get_dir功能,而且返回gh和长度2

3.static struct buffer_head* find_entry(struct m_inode **dir,const char *name,int namelen,struct dir_entry **res_dir)

功能:查找指定目录和文件名的目录项

参数:*dir--指定目录i节点指针;name--文件名;namelen--文件名长度

返回:成功则返回高速缓冲区指针,并在res_dir处返回的目录项结构指针。失败则返回空指针NULL。

4.open_namei函数

int open_namei(const char *pathname,int flag,int mode,struct m_inode **res_inode)
{
	const char *basename;
	int inr,dev,namelen;
	struct m_inode *dir,*inode;
	struct buffer_head *bh;
	struct dir_entry *de;
	
	...
	if(!(dir=dir_namei(pathname,&namelen,&basename,NULL)))
		return -ENOENT
	if(!namelen)
	{
		if(!(flag & (O_ACCMODE|O_CREATE|O_TRUNC)))
		{
			*res_inode=dir;
			return 0;
		}
		iput(dir);
		return -EISDIR;
	}
	bh=find_entry(&dir,basename,namelen,&de);
	if(!bh)
	{
	//没有对应的目录项,很有可能是创建文件...
	}
	//如果bh!=NULL
	inr=de->inode;
	dev=dir->i_dev;
	brelse(bh);
	if(flag & O_EXCL)
	{
		iput(dir);
		return -EEXIST;
	}
	//读取目录项的i节点内容
	if(!(inode=follow_link(dir,iget(dev,inr))))
		return -EACCES;
	...
	inode->i_atime=CURRENT_TIME;
	if(flag & o_TRUNC)
		truncate(inode);
	*res_inode=inode;
	return;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: