linux vfs open函数,Linux VFS中open系统调用实现原理

用户空间的函数在内核里面的入口函数是sys_open

通过grep open /usr/include/asm/unistd_64.h查找到的

#define __NR_open2

__SYSCALL(__NR_open, sys_open)

观察unistd_64.h,我们可以猜测用户空间open函数最终调用的系统调用号是2来发起的sys_open系统调用(毕竟glibc一般的做法都会做,用户空间的函数名字和内核空间中调用的很像,如果需要得到非常准确的,请查看glibc源码找到对应的系统调用号,再和内核里面的系统调用号去一一对比)。这里我们不纠结。

函数内容

通过前面的我们得知,sys_open实际就是下面这个函数(fs/open.c中)

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)

{

long ret;

if (force_o_largefile())

flags |= O_LARGEFILE;

ret = do_sys_open(AT_FDCWD, filename, flags, mode);

/* avoid REGPARM breakage on x86: */

asmlinkage_protect(3, ret, filename, flags, mode);

return ret;

}

其中先调用force_o_largefile()来判断是否需要设置大文件标识,然后调用do_sys_open来完成具体的工作。其中

force_o_largefile()

在IA64系统中arch/ia64/include/asm/fcntl.h,定义如下

#define _ASM_IA64_FCNTL_H

#define force_o_largefile()(personality(current->personality) != PER_LINUX32)

#include

#endif /* _ASM_IA64_FCNTL_H */

而其余的在include/linux/fcntl.h中

#ifndef force_o_largefile

#define force_o_largefile() (BITS_PER_LONG != 32)

#endif

所以,在非32位的OS上,force_o_largefile()都为true,而32位的OS则为false

另外,我们可以查看我们的OS位数:

# grep CONFIG_64BIT /boot/config-2.6.32-220.el6.x86_64

CONFIG_64BIT=y //64位

#ifdef CONFIG_64BIT

#define BITS_PER_LONG 64

#else

#define BITS_PER_LONG 32

#endif /* CONFIG_64BIT */

所以:只有在32位的OS上此处才为false(这里不考虑IA64架构,我们考虑的是x86架构),所以64位的系统上flags会自动加上O_LARGEFILE,32位的则没有,所以文件最大大小受索引节点中表示文件大小的32位的i_size的影响,只能访问2的32次方字节,即4GB(实际高位一般不用,所以通常只有2G)。加上O_LAGEFILE之后启用索引节点的i_dir_acl字段也可以一起表示文件的大小了,这样位数就变成了64位,2的64位就4GB*4GB,单个文件这么大已经很大了16T了

我们重点来看do_Sys_open函数do_sys_open(AT_FDCWD, filename, flags, mode)

函数原型long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)。

这个函数这里(我们讲述最主要的内容)执行过程

fd(int型)

(1)在当前进程打开的文件位图表中,找到第一个为0的位,返回这个位在位图表里面的下标,这个下标就是将用分配的未使用的文件描述符fd

(2)把当前进程的文件表扩展一个文件(即尝试添加一个struct file到当前

进程的文件列表中),进程task_struct->files_struct->fd_array[NR_OPEN_DEFAULT]是一个struct file 数组,而NR_OPEN_DEFAULT在64位系统中等于64(因为一般进程打开的文件数大多都用这个数组就可以直接放下了),如果扩展操作导致当前进程的这个存放struct file的数组放不下了,如要装第65个struct flie结构体,那么将重新分配一片内存区专门用来存放struct file结构体,并且这个内存区的大小为128个struct file结构体,然后将当前进程的task_struct->files_struct->fdtable->fd指针指向这片内存的首地址,然后把之前数组里面的内容复制到这片内存区里面来。下次添加如果超过了128个了,则分配256个大小直到256个也装满,超过256则分配512,依次类推,总是2的幂次方,且会把之前的复制到新分配的内存里面去

注意:这里只是更新了进程的这个file table,新的进程描述符对应的struct file还没有生成进去。

(3)设置进程的文件位图中新分配的这个文件描述符位为(1)中找到的下标,并更新下一次该分配的进程描述符起点

struct file结构体

Struct file =kmem_cache_zalloc(filp_cachep, GFP_KERNEL);

pathname查找或建立对应的dentry

并设置此dentry对应的inode。内核做这个事情借助于一个nameidata数据结构

(1)如果pathname中第一个字符是“/”,那么说明使用绝对路径,设置nameidata为更目录对应的dentry和当前目录的inode,mount点等

(2)如果不是“/”,则使用相对路径,设置nameidata为当前目录对应的dentry,inode,mount点等

(3)一层一层往下查找,直到找到最终的那个文件或者目录分量,注意:如”/usr/bin/make”,先找“/”(这是3.1就做了的),再找“/”下面的usr,再找bin,最后找make。

这里细说一下第一层怎么在“/“下面找到”usr“的:

第一层查找先找“/”下面的usr对应的dentry,内核通过“/”对应的dentry和”usr”字符串两个参数进行hash运算获取一个dentry的链表

然后逐个看这个链表里面有没有parent dentry为“/”对应的dentry的,以及dentry对应的名字的hash值是否与“usr”对应的hash值相同

前面条件都满足这里再看一下parent dentry是否有DCACHE_OP_COMPARE标识,如果有此标识且文件系统实现了dentry->dentry_operations->d_compare函数,那么就调用文件系统的这个函数来判断

如果条件都符合,那么说明内存中usr对应的这个dentry是存在的,如果这个dentry->d_flags中包含DCACHE_OP_REVALIDATE,那么就会调用此dentry->dentry_operatoin->d_revalidate来进行一次核对(网络文件系统此函数都实现了,以便于远程的便跟,在这里会得到更新)

如果最终usr对应的dentry不存在,那么内核就在内存中直接分配一个dentry结构体并且把dentry的name和“usr”对应起来,并且设置这个dentry的parent为“/”对应的dentry,然后还要调用”/”对应的dentry->d_inode这个inode的inode_operation->lookup(“/”的inode,新建的dentry,flags),如果返回了新的dentry,那么就把dentry结构体指针指向新返回的dentry,否则还是返回刚刚新创建的那个dentry。(一般的文件系统都实现了inode_operation->lookup,我猜他们会在这个函数里面如果/usr存在则把dentry对应的inode给设置好。。如果/usr不存在则返回一个NULL之类的,以一个错误跳出整个路径执行)

到这里,无论是dentry已经存在于内存中找到的,还是新创建的dentry,总之,对应于“usr”结构的dentry在内存中已经存在了。然后调用follow_managed()函数找到“usr”最新的vfsmount(这里有一点点麻烦,后续会专门讲,这里只需要指定如果”/dev/sda”mount 到了/mnt,/dev/sdb 也mount到了/mnt,那么这里返回的是最新的这条/dev/sdb mount到/mnt这个vfsmount)。

然后把这个已经找到的或创建的dentry(已经存在于内存中的dentry已经有了inode和它绑定,新建立的dentry也通过inode_operation->lookup建立起来了inode和dentry的联系(此函数会在操作真正的磁盘介质吧inode读出来))和这个最新的vfsmount存到struct path中

然后把这个含有dentry,vfsmount的path结构体存入nameidata数据结构中,到这里,“usr“对应的dentry,inode,vfsmount都准备好了,且存到了nameidata中了

(4)接着(3)里面,一层一层的往下找,依次会找到usr,bin,最后到了”make”

这里就不调用一层一层往下找的函数了,进入另外一个函数do_last()函数来

处理。在dolast,在dolast里面如果此dentry不存在则创建它,如果有O_CREATE

标识则创建这个文件的inode(这里会调用vfs_create函数,继续调用dentry->inode_operation->create来建立inode,文件系统实现的此函数会操作正在的磁盘介质去创建inode),并且建立inode和dentry的联系,并且建立”make”对应的vfsmount为最新的mount结构,至此,“/usr/bin/make”中最后一个分量“make”的dentry,inode,vfsmount都存到nameidata中去了。

接着还会把2中分配的file结构体的path(包含dentry和vfsmount)的dentry分量设置为nameidata的这个dentry(dentry结构体中已经有inode的指针),vfsmount也设置为nameidata的vfsmount,并且设置file结构体的file->f_mapppin为nameidata中dentry的inode的i_mapping.并且设置file->f_pos指针为0。

至此,make对应的新分配的这个struct file结构体中的dentry,inode,vfsmount都为nameidata中的了,并且struct file映射到内存的address_space也设置为了inode对应的address_space,struct file的当前位置指针设置为了0,“make”分量的这个struct file结构体准备好了。

接着还会把这个struct file结构体加入其inode对应的super_block超级块的s_files链表中,即struct file结构体会加入其自身inode所在超级块的所有文件链表中。

并且如果自身inode的file_operations不为空则还会设置这个struct file的file_operation等于inode的这个file_operations,即公用inode的file的操作方法。如果inode的file_operations没有实现,则设置为空。

设置此文件标识符为FILE_OPENED.

fd到这个struct file结构体的联系

调用fd_install(fd,f)来把1中分配的文件描述符和3中的struct file建立联系。

过程简单描述一下,先获取当前进程的fdtable(简单可理解为进程的关联的所有文件数组)的所有文件数组fdtable=current->files->fdt,(current为当前进程task_struct),设置fdtable->fd[fd]=file,(下标fd即新分配的文件描述符,file即为3中创建的struct file结构体)。

这样,进程和文件描述符,struct file,dentry,inode,vfsmount就全部关联起来了。

附图片:完整的内核调用我画的visio学习图,欢迎纠正理解,图片需要放很大才能看清。。

。。汗。。图片有4M多,上传不了。。

参考:kernel 3.6.7源码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/369451.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从如何停掉 Promise 链说起

在使用Promise处理一些复杂逻辑的过程中,我们有时候会想要在发生某种错误后就停止执行Promise链后面所有的代码。 然而Promise本身并没有提供这样的功能,一个操作,要么成功,要么失败,要么跳转到then里,要么…

JAXB教程–入门

注意:请查看我们的Java XML绑定JAXB教程– ULTIMATE指南 什么是JAXB? JAXB代表用于XML绑定的Java体系结构。它用于将XML转换为java对象,并将java对象转换为XML。JAXB定义了一个用于在XML文档中读写Java对象的API。与SAX和DOM不同&#xff0c…

《Kubernetes权威指南第2版》学习(二)一个简单的例子

1: 安装VirtualBox, 并下载CentOS-7-x86_64-DVD-1708.iso, 安装centOS7,具体过程可以百度。 2:开启centOS的SSH, 步骤如下: (1) yum list installed | grep openssh-server查看是否已经安装了SS…

create_volume.go

package apiimport ("net/http""io/ioutil""errors""fmt")//创建存储空间func CreateVolume(host string, port int, vid uint64) error {url : fmt.Sprintf("http://%s:%d/%d/", host, port, vid)resp, err : http.Post(ur…

linux 安装ftp下载,LINUX FTP安装与配置

转载了一篇配置vsftpd服务器的文章,经过自己的配置,终于搞定了!1.安装vsftpdXml代码 yum install vsftpd2.启动/重启/关闭vsftpd服务器Xml代码 [rootlocalhost ftp]# /sbin/service vsftpd restartShutting down vsftpd: [ OK ]Starting vs…

使用Hibernate批量获取

如果需要从Java处理大型数据库结果集,则可以选择JDBC,以提供所需的低级控制。 另一方面,如果您已在应用程序中使用ORM,则回退到JDBC可能意味着额外的麻烦。 在域模型中导航时,您将失去乐观锁定,缓存&#x…

c语言 static的用法

static在c里面可以用来修饰变量,也可以用来修饰函数。先看用来修饰变量的时候。变量在c里面可分为存在全局数据区、栈和堆里。其实我们平时所说的堆栈是栈而不是堆,不要弄混。int a ;int main(){ int b ; int c* (int *)malloc(sizeof(int));}a是…

前端经典面试题 不经典不要star!

前言 (以下内容为一个朋友所述)今天我想跟大家分享几个前端经典的面试题,为什么我突然想写这么一篇文章呢?今天我应公司要求去面试了下几位招聘者,然后又现场整不出几个难题,就搜了一下前端变态面试题! HAHA,前提我并不是一个变态,欺负人的面试官.只是我希望看看对…

CSS的常见问题

1.css的编码风格 多行式:可读性越强,但是CSS文件的行数过多,影响开发速度,增大CSS文件的大小 一行式:可读性稍差,有效减少CSS文件的行数,有利于提高开发速度,减小CSS文件的大小 2.id…

linux 磁盘科隆,Linux中ln命令用法详解(硬链接)

硬连接指向的是节点(inode),是已存在文件的另一个名字,修改其中一个,与其连接的文件同时被修改;对硬链接文件进行读写和删除操作时候,效果和符号链接相同。但如果我们删除硬链接文件的源文件,硬链接文件仍然存在,而且保留了原有的内容。这时&…

Web前端开发学习误区,你掉进去了没?

从接触网站开发以来到现在,已经有五个年头了吧,今天偶然整理电脑资料看到当时为参加系里面一个比赛而做的第一个网站时,勾起了在这网站开发道路上的一串串回忆,成功与喜悦、烦恼与纠结都历历在目,感慨颇多。 先从大家学…

Oracle Database 11g DBA手册pdf

下载地址:网盘下载内容简介编辑《Oracle Database 11g DBA手册》所提供的专业知识可以帮助读者管理灵活的、高可用性的Oracle数据库。《Oracle Database 11g DBA手册》对上一版本进行了全面的修订,涵盖了每个新特性和实用工具,展示了如何实施…

link-cut-tree 简单介绍

目录 概念辨析辅助树轻边和重边操作介绍accessmake_rootfind_rootsplitlinkcut细节问题代码前言:这个算法似乎机房全都会,就我不会了TAT...强行搞了很久,勉强照着别人代码抄了一遍qwq 这个本人看论文实在看不懂,太菜了啊!!! 只好直接看如何实现...可是实现也看不太懂... 但直到…

linux svn 看不到文件,SVN更新时不能打开新文件svn-base系统找不到指定的文件

svn服务器架设在linux系统上,svn客户端在windows上,在update的时候可能会出现“Can’t open file.XXXX/tmp/text-base/XX.svn-base 系统找不到指定的文件”的错误。这是由于Linux服务器上的目标文件中存在两个相同文件名的文件。因为linux系统的文件名区…

C++primer 13.2.1节练习

练习13.23 1 #include <iostream>2 #include <string>3 #include <memory>4 5 using namespace std;6 7 8 class HasPtr {9 friend ostream &print(ostream &os, HasPtr &h); 10 public: 11 HasPtr(const string &s string()) : ps…

编年史与微云

总览 我面临的一个常见问题是&#xff1a; 如果是单个作者&#xff0c;多个读者&#xff0c;您如何扩展基于Chronicle的系统。 尽管有解决此问题的方法&#xff0c;但很有可能根本不会出现问题。 微云 这是我用来描述单个线程来完成当前由多个服务器完成的工作的术语。 &#…

去除IE10自带的清除按钮

最近在工作中碰到了一个问题&#xff0c;原本在IE8&#xff0c;IE9下正常的input表单&#xff0c;在IE10下会出现清除按钮&#xff0c;即表单右侧会出现一个可以清除该表单内容的小叉。由于之前一直没有兼容过IE10&#xff0c;所以我专门搜了下原因。发现&#xff0c;该功能是微…

Linux/CentOS7install PackageError: Loaded plugins: fastestmirror

Centons7 其大概意思是fastestmirror不能使用&#xff0c;fastestmirror是yum的一个加速插件&#xff0c;具体我也没有仔细了解过&#xff0c;可能是系统不支持或者缺少组件导致的。 处理办法就是禁用这个插件&#xff0c;方法如下&#xff1a; [rootlocalhost ~]# vim /etc/yu…

不要仅仅依靠单元测试

当您构建一个复杂的系统时&#xff0c;仅仅测试组件是不够的。 这很关键&#xff0c;但还不够。 想象一下一家汽车厂生产并进口最高质量的零件&#xff0c;但组装好之后再也不会启动发动机了。 如果您的测试用例套件几乎不包含单元测试&#xff0c;则您将永远无法确保系统整体正…

spring mvc的工作原理

该文转载自&#xff1a;http://blog.csdn.net/u012191627/article/details/41943393 SpringMVC框架介绍 1) spring MVC属于SpringFrameWork的后续产品&#xff0c;已经融合在Spring Web Flow里面。 Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的…