山西省住房建设厅网站下载,网站的页面设计,专业做app下载网站,甘肃建设局网站首页用户空间的函数在内核里面的入口函数是sys_open通过grep open /usr/include/asm/unistd_64.h查找到的#define __NR_open2__SYSCALL(__NR_open, sys_open)观察unistd_64.h#xff0c;我们可以猜测用户空间open函数最终调用的系统调用号是2来发起的sys_open系统调用(毕竟glibc一…用户空间的函数在内核里面的入口函数是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_64CONFIG_64BITy //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和当前目录的inodemount点等(2)如果不是“/”则使用相对路径设置nameidata为当前目录对应的dentryinodemount点等(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新建的dentryflags)如果返回了新的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中然后把这个含有dentryvfsmount的path结构体存入nameidata数据结构中到这里“usr“对应的dentryinodevfsmount都准备好了且存到了nameidata中了(4)接着(3)里面一层一层的往下找依次会找到usrbin最后到了”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”的dentryinodevfsmount都存到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结构体中的dentryinodevfsmount都为nameidata中的了并且struct file映射到内存的address_space也设置为了inode对应的address_spacestruct 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(简单可理解为进程的关联的所有文件数组)的所有文件数组fdtablecurrent-files-fdt(current为当前进程task_struct)设置fdtable-fd[fd]file(下标fd即新分配的文件描述符file即为3中创建的struct file结构体)。这样进程和文件描述符struct filedentryinodevfsmount就全部关联起来了。附图片完整的内核调用我画的visio学习图欢迎纠正理解图片需要放很大才能看清。。。。汗。。图片有4M多上传不了。。参考kernel 3.6.7源码