上一节从ftrace中可以看到在cat过程中sdcardfs调用顺序,我们知道了sdcardfs的调用流程,但是这些函数在整个文件系统的调用中是怎么配合的,怎么被串起来的?下面补齐缺失的trace,来看下其在整个文件系统调用中的位置。食用下面ftrace log需要有一定的文件系统基础,可以配合这个博客:open()在Linux内核的实现-准备工作这各博客里对linux中的open()中实现的流程以及其中各函数作用都做了注解。
SyS_openat() {//系统调用
4) | do_sys_open() {
4) | getname() {//1. 将文件名由用户态拷贝到内核态
4) | getname_flags() {
4) | kmem_cache_alloc() {
4) 2.604 us | }
4) | __check_object_size() {
4) 0.052 us | is_vmalloc_addr();
4) | pfn_valid() {
4) | memblock_is_map_memory() {
4) 0.105 us | memblock_search();
4) 0.677 us | }
4) 1.250 us | }
4) 0.104 us | __check_heap_object();
4) 0.104 us | check_stack_object();
4) 3.594 us | }
4) 7.760 us | }
4) 8.333 us | }
4) | get_unused_fd_flags() {//2. 为即将打开的文件分配文件描述符
4) | __alloc_fd() {
4) | _etext() {
4) 0.156 us | preempt_count_add();
4) 1.458 us | }
4) 0.104 us | expand_files();
4) | _etext() {
4) 0.157 us | preempt_count_sub();
4) 0.729 us | }
4) 4.218 us | }
4) 4.740 us | }
4) | do_filp_open() {/*3. 根据用户传入的路径去执行open,如果找到则为文件创建
file结构体.open的核心操作函数,其解析文件路径创建
file结构体*/
4) | path_openat() {//3.1 路径查找
4) | get_empty_filp() {//3.1.1 创建新的file结构体
4) | kmem_cache_alloc() {
4) 2.865 us | }
4) | security_file_alloc() {
4) | selinux_file_alloc_security() {
4) | kmem_cache_alloc() {
4) 2.760 us | }
4) 3.334 us | }
4) 3.906 us | }
4) 0.052 us | __mutex_init();
4) + 10.885 us | }
4) | path_init() {/*3.1.2 路径查找前准备工作,主要判断遍历路径的起始位置
根目录‘/’ or 当前路径 or 指定路径
根据起始位置配置nameidata *nd中的一些参数*/
4) 0.052 us | __rcu_read_lock();
4) 1.719 us | }
4) | link_path_walk() {/*3.1.3 逐一解析文件路径,将解析结果存入
struct nameidata *nd */
4) | inode_permission2() { //这个函数是被may_lookup()调用,作用权限检查
4) | __inode_permission2() {
4) | sdcardfs_permission() { //可以看到最终调用到sdcardfs的权限检查
4) 0.105 us | generic_permission();
4) 2.188 us | }
4) | security_inode_permission() {/*安全操作,最后决定是否有权限,
调用内核自己注册的security_ops结构体的函数,新的内核特性属于 linux 安全模块(LSM)*/
4) | selinux_inode_permission() {
4) 0.052 us | __rcu_read_lock();
4) | avc_lookup() {
4) 1.823 us | }
4) 0.104 us | __rcu_read_unlock();
4) 3.750 us | }
4) 4.375 us | }
4) 8.281 us | }
4) 8.959 us | }
4) 0.678 us | sdcardfs_hash_ci(); //根据dentry拿到 hash_len name
------------------------------------------------------------------------------------
/* parent->d_op->d_hash(parent, &this);通过这种方式被调用,把hash_len 和 name写入this中*/
struct qstr this = { { .hash_len = hash_len }, .name = name };
err = parent->d_op->d_hash(parent, &this);
if (err < 0)
return err;
hash_len = this.hash_len;
name = this.name;
------------------------------------------------------------------------------------
4) + 11.510 us | }
4) | lookup_fast() {/*这个是被walk_component()调用,作用处理当前目录项
更新nd next(path类型,指向下一个目录项)*/
4) | __d_lookup_rcu() { //rcu方式的dentry lookup
4) | slow_dentry_cmp() {
4) 0.365 us | sdcardfs_cmp_ci();/*parent->d_op->d_compare(parent, dentry, tlen, tname, name),需要注意这个比较是大小 写敏感的比较*/
4) 1.145 us | }
4) 2.136 us | }
4) 0.468 us | sdcardfs_d_revalidate();
------------------------------------------------------------------------------------------
/*一致性检查,dentry->d_op->d_revalidate(dentry,flags);在调用到sdcardfs_d_revalidate后其返回
0 随后在lookup_fast中会调用unlazy_walk(),返回err = 0代码如下*/
/*这里判断,如果sdcardfs的inode中的data不存在或者被标记为abandoned,则认为这个dentry过时,通过d_drop释放当前dentry,置err = 0 */
/* If our top's inode is gone, we may be out of date */
inode = igrab(d_inode(dentry));
if (inode) {
data = top_data_get(SDCARDFS_I(inode));
if (!data || data->abandoned) {
d_drop(dentry);
err = 0;
}
if (data)
data_put(data);
iput(inode);
}
-------------------------------------------------------------------------------------------
4) | unlazy_walk() { //unlazy_walk()将当前的rcu-walk切换到ref-walk
4) | legitimize_mnt() {
4) | __legitimize_mnt() {
4) 0.156 us | preempt_count_add();
4) 0.156 us | preempt_count_sub();
4) 1.927 us | }
4) 2.552 us | }
4) 0.104 us | __rcu_read_unlock();
4) 3.750 us | }
4) | sdcardfs_d_revalidate() {//再次调用sdcardfs_d_revalidate
...................
4) | igrab() {
4) | _etext() {
4) 0.156 us | preempt_count_add();
4) 0.937 us | }
4) | _etext() {
................
4) 0.104 us | follow_managed();//重定位dentry
4) + 65.521 us | }
4) | mntget() {
4) 0.156 us | preempt_count_add();
4) 0.156 us | preempt_count_sub();
4) 1.355 us | }
4) 0.105 us | complete_walk();
4) | may_open() { //3.1.4,被do_last调用,作用权限,模式检查
---------------------------------------------------------------------------------------
/*link_path_walk 之后就是 do_last 对最后的对路径中最后一个目录项做处理,对open最常用的两种操作是
打开文件或创建文件,这里就是open 这里是通过 do_last -> finish_open_created: -> may_open */
---------------------------------------------------------------------------------------
4) | __inode_permission2() {
4) | sdcardfs_permission() {
4) 0.104 us | generic_permission();
4) 0.937 us | }
4) | security_inode_permission() {
4) | selinux_inode_permission() {
4) 0.104 us | __rcu_read_lock();
4) | avc_lookup() {
4) 0.156 us | preempt_count_add();
4) 0.156 us | preempt_count_sub();
4) 2.396 us | }
4) 0.052 us | __rcu_read_unlock();
4) 4.219 us | }
4) 4.792 us | }
4) 7.552 us | }
4) 8.125 us | }
4) | vfs_open() { //在 may_open 之后调用 vfs_open,这是第一次调用vfs_open
4) | do_dentry_open() {
4) | path_get() {
4) | mntget() {
4) 0.156 us | preempt_count_add();
4) 0.156 us | preempt_count_sub();
4) 1.823 us | }
4) 2.500 us | }
4) 0.052 us | try_module_get();
4) | security_file_open() {
4) | selinux_file_open() {
4) 0.052 us | avc_policy_seqno();
4) | avc_has_perm() {
4) 0.052 us | __rcu_read_lock();
4) | avc_lookup() {
4) 0.156 us | preempt_count_add();
4) 0.156 us | preempt_count_sub();
4) 1.355 us | }
4) 0.052 us | __rcu_read_unlock();
4) 2.969 us | }
4) 4.114 us | }
4) 0.104 us | __fsnotify_parent();
4) 0.364 us | fsnotify();
4) 6.094 us | }
4) | sdcardfs_open() { //open = f->f_op->open;调用sdcardfs_open
4) | dget_parent() {
4) 0.052 us | __rcu_read_lock();
4) 0.104 us | __rcu_read_unlock();
4) 1.146 us | }
4) 0.104 us | check_caller_access_to_name(); /*通过packgelist控制权限,可以看上一节*/
4) | override_fsids() {
4) | prepare_creds() {
4) | kmem_cache_alloc() {
4) 2.969 us | }
4) | security_prepare_creds() {
4) | selinux_cred_prepare() {
4) | kmemdup() {
4) | __kmalloc_track_caller() {
4) 0.104 us | kmalloc_slab();
4) 4.219 us | }
4) 4.792 us | }
4) 5.365 us | }
4) 6.146 us | }
4) + 11.250 us | }
4) 0.104 us | override_creds();
4) + 12.864 us | }
4) | kmem_cache_alloc_trace() {
4) 2.708 us | }
4) | _etext() {
4) 0.156 us | preempt_count_add();
4) 0.677 us | }
4) | path_get() {
4) | mntget() {
4) 1.146 us | }
4) 1.718 us | }
4) | _etext() {
4) 0.156 us | preempt_count_sub();
4) 0.729 us | }
4) | dentry_open() { //在sdcardfs中执行dentry_open
4) | get_empty_filp() {
4) | kmem_cache_alloc() {
4) 3.386 us | }
4) | security_file_alloc() {
4) | selinux_file_alloc_security() {
4) | kmem_cache_alloc() {
4) 2.604 us | }
4) 3.177 us | }
4) 3.802 us | }
4) 0.052 us | __mutex_init();
4) + 11.042 us | }
4) | do_dentry_open() {
-----------------------------------------------------------------------------------
/*do_dentry_open这个是被 dentry_open -> vfs_open -> do_dentry_open这样调用,也就是说
sdcardfs被vfs_open调用后,执行一些权限管控,又调用vfs_open执行*/
------------------------------------------------------------------------------------
4) | path_get() {
4) | mntget() {
4) 1.302 us | }
4) 1.875 us | }
4) 0.052 us | try_module_get();
4) | security_file_open() {
4) | selinux_file_open() {
4) 0.052 us | avc_policy_seqno();
4) | avc_has_perm() {
4) 0.104 us | __rcu_read_lock();
4) | avc_lookup() {
4) 1.718 us | }
4) 0.104 us | __rcu_read_unlock();
4) 3.386 us | }
4) 4.635 us | }
4) 0.052 us | __fsnotify_parent();
4) 0.885 us | fsnotify();
4) 7.136 us | }
4) | f2fs_file_open() {
4) 0.053 us | generic_file_open();
4) 0.625 us | }
4) 0.677 us | file_ra_state_init();
4) + 14.427 us | }
4) + 26.511 us | }
4) | path_put() {
4) | dput() {
4) 0.053 us | __rcu_read_lock();
4) 0.052 us | __rcu_read_unlock();
4) 1.198 us | }
4) | mntput() {
4) | mntput_no_expire() {
4) 2.396 us | }
4) 2.968 us | }
4) 5.156 us | }
4) 0.052 us | set_nlink();
4) | revert_fsids() {
4) 0.625 us | revert_creds();
4) 1.146 us | }
4) | dput() {
4) 2.031 us | }
4) + 63.282 us | }
4) 0.261 us | file_ra_state_init();
4) + 75.989 us | }
4) + 76.511 us | }
4) 0.105 us | open_check_o_direct();//检查是否为无缓存的读取,直接IO
4) | dput() {
4) 1.198 us | }
4) | mntput() {
4) | mntput_no_expire() {
4) 2.448 us | }
4) 2.969 us | }//dentry_open结束
4) | terminate_walk() {//3.2 释放nd
4) 0.104 us | drop_links.isra.30();
4) | dput() {
4) 1.146 us | }
4) | mntput() {
4) | mntput_no_expire() {
4) 2.396 us | }
4) 2.916 us | }
4) 5.730 us | }
4) ! 191.719 us | }
4) ! 192.500 us | }//path_openat结束
4) 0.052 us | __fsnotify_parent();
4) 0.104 us | fsnotify(); //将filp的监控点打开,将其添加到监控系统中
4) | fd_install() {//将fd和file关联
4) | __fd_install() {
4) 0.156 us | preempt_count_add();
4) 0.156 us | preempt_count_sub();
4) 1.354 us | }
4) 1.927 us | }
4) | putname() {
4) | kmem_cache_free() {
4) 0.156 us | preempt_count_add();
4) 0.156 us | preempt_count_sub();
4) 0.104 us | preempt_count_add();
4) 0.156 us | preempt_count_sub();
4) 2.657 us | }
4) 3.229 us | }
4) ! 214.375 us | }
4) ! 214.948 us | }
4) 0.052 us | post_ttbr_update_workaround();
read相对来说比较简单,没有open那么复杂,调用流程就是 vfs_read -> sdcardfs_read -> vfs_read
SyS_read() {
4) 0.104 us | __fdget_pos();
4) | vfs_read() {//第一次调用,会指向sdcardfs
4) | rw_verify_area() {//检查读权限
4) | security_file_permission() {
4) | selinux_file_permission() {
4) 0.052 us | avc_policy_seqno();
4) 0.677 us | }
4) 0.104 us | __fsnotify_parent();
4) 0.105 us | fsnotify();
4) 2.344 us | }
4) 2.916 us | }
4) | sdcardfs_read() {//file->f_op->read(file, buf, count, pos);
4) | vfs_read() {//第二次调用指向底层文件系统,这里是f2fs
4) | rw_verify_area() {
4) | security_file_permission() {
4) | selinux_file_permission() {
4) 0.052 us | avc_policy_seqno();
4) 0.729 us | }
4) 0.052 us | __fsnotify_parent();
4) 0.104 us | fsnotify();
4) 2.604 us | }
4) 3.750 us | }
4) | new_sync_read() { // 应为底层支持read_iter,所以用new_sync_read
4) | generic_file_read_iter() {
4) 0.105 us | _cond_resched();
4) | pagecache_get_page() {
4) | find_get_entry() {
4) 0.104 us | __rcu_read_lock();
4) 0.104 us | __rcu_read_unlock();
4) 1.406 us | }
4) 1.927 us | }
4) 0.104 us | mark_page_accessed();
4) | do_page_fault() {
4) 0.104 us | down_read_trylock();
4) | find_vma() {
4) 0.156 us | vmacache_find();
4) 0.104 us | vmacache_update();
4) 1.407 us | }
4) | handle_mm_fault() {
4) 0.208 us | preempt_count_add();
4) 0.156 us | preempt_count_sub();
4) 0.104 us | anon_vma_prepare();
...............
4) 0.052 us | add_mm_counter_fast();
4) | page_add_new_anon_rmap() {
4) 0.104 us | __mod_zone_page_state();
4) 0.678 us | }
4) | lru_cache_add_active_or_unevictable() {
4) | __lru_cache_add() {
4) 0.052 us | preempt_count_add();
4) 0.104 us | preempt_count_sub();
4) 1.198 us | }
4) 1.771 us | }
4) | _etext() {
4) 0.157 us | preempt_count_sub();
4) 0.729 us | }
4) + 41.980 us | }
4) 0.053 us | up_read();
4) + 45.885 us | }
4) 0.208 us | preempt_count_add();
4) | __check_object_size() {
4) 0.052 us | is_vmalloc_addr();
4) | pfn_valid() {
4) | memblock_is_map_memory() {
4) 0.104 us | memblock_search();
4) 0.677 us | }
4) 1.250 us | }
4) 0.052 us | check_stack_object();
4) 3.021 us | }
4) 0.156 us | preempt_count_sub();
4) 0.052 us | put_page();
4) 0.104 us | _cond_resched();
4) | pagecache_get_page() {
4) | find_get_entry() {
4) 0.052 us | __rcu_read_lock();
4) 0.104 us | __rcu_read_unlock();
4) 1.250 us | }
4) 1.823 us | }
4) 0.053 us | put_page();
4) | touch_atime() {
4) 0.364 us | atime_needs_update();
4) 0.886 us | }
4) + 84.635 us | }
4) + 85.261 us | }
4) 0.052 us | __fsnotify_parent();
4) 0.053 us | fsnotify();
4) + 91.250 us | }
4) + 91.822 us | } //这些加号是中间穿插着中断,因为要从磁盘读数据,我把这部分删掉了
4) 0.052 us | __fsnotify_parent();
4) 0.052 us | fsnotify();//这部分都是些收尾动作
4) + 97.136 us | }
4) + 98.385 us | }
SyS_close() {
4) | __close_fd() {
4) | _etext() {
4) 0.156 us | preempt_count_add();
4) 0.833 us | }
4) | _etext() {
4) 0.156 us | preempt_count_sub();
4) 0.730 us | }
4) | filp_close() {
4) 0.052 us | sdcardfs_flush();//回写
4) 0.104 us | dnotify_flush();
4) 0.104 us | locks_remove_posix();
4) | fput() {
4) | task_work_add() {
4) | kick_process() {
4) 0.157 us | preempt_count_add();
4) 0.104 us | preempt_count_sub();
4) 1.354 us | }
4) 1.928 us | }
4) 2.500 us | }
4) 5.000 us | }
4) 8.386 us | }
4) 8.958 us | }