温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

基于linux的open原理是什么

发布时间:2021-12-18 13:43:11 阅读:158 作者:iii 栏目:大数据
Linux服务器限时活动,0元免费领,库存有限,领完即止! 点击查看>>

本篇内容介绍了“基于linux的open原理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

我们操作一个文件之前都需要先open一下。我们看看open在虚拟文件系统中大致的执行过程。不会分析具体的过程。主要分析一下虚拟文件系统的实现原理。

   
     
 
    
    asmlinkage int sys_open(const char * filename,int flags,int mode){	char * tmp;	int error;	error = getname(filename, &tmp);	if (error)		return error;	error = do_open(tmp,flags,mode);	putname(tmp);	return error;}
   
     
 
    
    AI代码助手复制代码

下面是do_open的代码。

   
     
 
    
    // 打开一个文件int do_open(const char * filename,int flags,int mode){	struct inode * inode;	struct file * f;	int flag,error,fd;	// 找到一个可用的文件描述符	for(fd=0; fd<NR_OPEN && fd<current->rlim[RLIMIT_NOFILE].rlim_cur; fd++)		// 还没被使用则找到可用的		if (!current->files->fd[fd])			break;	// 找不到可用的	if (fd>=NR_OPEN || fd>=current->rlim[RLIMIT_NOFILE].rlim_cur)		return -EMFILE;	// 清除close_on_exec标记位	FD_CLR(fd,&current->files->close_on_exec);	// 获取一个可用的file结构体	f = get_empty_filp();	if (!f)		return -ENFILE;	// 建立fd到file结构体的映射	current->files->fd[fd] = f;	f->f_flags = flag = flags;	f->f_mode = (flag+1) & O_ACCMODE;	if (f->f_mode)		flag++;	if (flag & (O_TRUNC | O_CREAT))		flag |= 2;	// 找到文件对应的inode节点,放到inode变量中	error = open_namei(filename,flag,mode,&inode,NULL);	if (!error && (f->f_mode & 2)) {		error = get_write_access(inode);		if (error)			iput(inode);	}	if (error) {		current->files->fd[fd]=NULL;		f->f_count--;		return error;	}	// 建立file结构体和inode的映射关系	f->f_inode = inode;	// 初始化文件偏移	f->f_pos = 0;	f->f_reada = 0;	f->f_op = NULL;	// 赋值操作file结构体的函数集	if (inode->i_op)		f->f_op = inode->i_op->default_file_ops;	if (f->f_op && f->f_op->open) {		// 调用底层文件系统的open函数		error = f->f_op->open(inode,f);		if (error) {			if (f->f_mode & 2) put_write_access(inode);			iput(inode);			f->f_count--;			current->files->fd[fd]=NULL;			return error;		}	}	f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);	return (fd);}
   
     
 
    
    AI代码助手复制代码

主要工作是通过open_namei找到文件对应的inode节点,然后执行底层的open。最后建立fd到file到inode的关系。在虚拟文件系统中,超级块、inode、目录、文件都是一个抽象的概念,具体的操作函数由各个文件系统实现。所以我们首先找到一个结构体,然后根据实际的操作值调用具体文件系统的操作函数就行。

所以我们先看open_namei,再看具体的open函数。

下面是open_namei的核心代码。

   
     
 
    
    // 找出最后一级目录的inode	error = dir_namei(pathname,&namelen,&basename,base,&dir);// 在最后一级目录下找出某文件对应的inode	error = lookup(dir,basename,namelen,&inode);
   
     
 
    
    AI代码助手复制代码

大致思路就是先找到最后一级目录的inode,然后在最后一级目录下找某个文件。我们看看怎么找到最后一级目录对应的inode。

   
     
 
    
    // 找出pathname中最后一级目录对应的inodestatic int dir_namei(const char * pathname, int * namelen, const char ** name,	struct inode * base, struct inode ** res_inode){	char c;	const char * thisname;	int len,error;	struct inode * inode;	*res_inode = NULL;	// 没有传base则从进程的当前工作目录开始找	if (!base) {		base = current->fs->pwd;		base->i_count++;	}	// 绝对路径,则从根目录开始找	if ((c = *pathname) == '/') {		iput(base);		base = current->fs->root;		pathname++;		base->i_count++;	}	// 找出pathname最后一级目录对应的inode节点	while (1) {		thisname = pathname;		// 以/分割路径部分,遇到/则得到某级路径名称,thisname指向当前路径首地址,len代表该部分路径对应的长度		for(len=0;(c = *(pathname++))&&(c != '/');len++)			/* nothing */ ;		// c为空说明到最后一个字符,即路径结束,不找最后一级的文件或者目录了		if (!c)			break;		base->i_count++;		// 在base目录下查找某个文件		error = lookup(base,thisname,len,&inode);		if (error) {			iput(base);			return error;		}		// 设置base为inode,继续找		error = follow_link(base,inode,0,0,&base);		if (error)			return error;	}	if (!base->i_op || !base->i_op->lookup) {		iput(base);		return -ENOTDIR;	}	*name = thisname;	*namelen = len;	*res_inode = base;	return 0;}
   
     
 
    
    AI代码助手复制代码

就是通过以/分割字符串,在开始的目录下,即根目录或者给定的目录。找到下一级目录的inode,不断地迭代就能找到最后一级目录的inode了。我们发现在查找最后一级目录的inode和在某个目录下找某个文件的inode都用到lookup函数。我们看看他的实现。核心代码。

   
     
 
    
    return dir->i_op->lookup(dir,name,len,result);

以ext文件系统为例。看看lookup的实现。

   
     
 
    
    int ext_lookup(struct inode * dir,const char * name, int len,	struct inode ** result){	int ino;	struct ext_dir_entry * de;	struct buffer_head * bh;	*result = NULL;	if (!dir)		return -ENOENT;	if (!S_ISDIR(dir->i_mode)) {		iput(dir);		return -ENOENT;	}	if (!(bh = ext_find_entry(dir,name,len,&de,NULL,NULL))) {		iput(dir);		return -ENOENT;	}	ino = de->inode;	brelse(bh);	if (!(*result = iget(dir->i_sb,ino))) {		iput(dir);		return -EACCES;	}	iput(dir);	return 0;}static struct buffer_head * ext_find_entry(struct inode * dir,	const char * name, int namelen, struct ext_dir_entry ** res_dir,	struct ext_dir_entry ** prev_dir, struct ext_dir_entry ** next_dir){	long offset;	struct buffer_head * bh;	struct ext_dir_entry * de;	*res_dir = NULL;	if (!dir)		return NULL;#ifdef NO_TRUNCATE	if (namelen > EXT_NAME_LEN)		return NULL;#else	if (namelen > EXT_NAME_LEN)		namelen = EXT_NAME_LEN;#endif	// 读取目录的文件内容,然后比较	bh = ext_bread(dir,0,0);	if (!bh)		return NULL;	if (prev_dir)		*prev_dir = NULL;	if (next_dir)		*next_dir = NULL;	offset = 0;	de = (struct ext_dir_entry *) bh->b_data;	while (offset < dir->i_size) {		if ((char *)de >= BLOCK_SIZE+bh->b_data) {			brelse(bh);			bh = NULL;			bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,0);			if (!bh)				continue;			de = (struct ext_dir_entry *) bh->b_data;			if (prev_dir)				*prev_dir = NULL;		}		if (de->rec_len < 8 || de->rec_len % 8 != 0 ||de->rec_len < de->name_len + 8 ||(((char *) de) + de->rec_len-1 >= BLOCK_SIZE+bh->b_data)) {			printk ("ext_find_entry: bad dir entry\n");			printk ("dev=%d, dir=%ld, offset=%ld, rec_len=%d, name_len=%d\n",				dir->i_dev, dir->i_ino, offset, de->rec_len, de->name_len);			de = (struct ext_dir_entry *) (bh->b_data+BLOCK_SIZE);			offset = ((offset / BLOCK_SIZE) + 1) * BLOCK_SIZE;			continue;/*			brelse (bh);			return NULL; */		}		// 是否找到了想要的文件		if (ext_match(namelen,name,de)) {			*res_dir = de;			if (next_dir)				if (offset + de->rec_len < dir->i_size &&((char *)de) + de->rec_len < BLOCK_SIZE+bh->b_data)					*next_dir = (struct ext_dir_entry *)						((char *) de + de->rec_len);				else					*next_dir = NULL;			return bh;		}		offset += de->rec_len;		if (prev_dir)			*prev_dir = de;		de = (struct ext_dir_entry *) ((char *) de + de->rec_len);	}	brelse(bh);	return NULL;}
   
     
 
    
    AI代码助手复制代码

代码比较多,可以不用细究,主要是把目录的文件内容从硬盘读取进来,然后遍历每一个文件名是否和要找的一致就行。

     通过上面的分析我们已经找到了一个文件对应的inode节点了。一般文件系统没有实现open函数。所以直接返回inode,建立fd到file到inode的关系即可。后面对文件的操作也是通过inode节点的操作函数集进行。

“基于linux的open原理是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!

亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

原文链接:https://my.oschina.net/u/4217331/blog/4379407

AI

开发者交流群×