2022-01-07

如何查看linux系统调用的函数实现 && 和进程创建相关的几个系统调用

描述

  • 系统调用的调用号,在系统调用的前面,加上 __NR_ (NR前面2个下划线)即可,比如搜索 __NR_vfork.
  • 系统调用的实现函数的定义,都是形如 SYSCALL_DEFINE(vfork,) 或者 SYSCALL_DEFINEx(vfork,),(这里的x表示参数个数),可以通过grep快速搜索实现定义
   grep -rn "SYSCALL_DEFINE" | grep vfork 

__do_fork的实现

  • 不论是fork还是vfork内部最终都会调到 __do_fork
_do_fork
  copy_process
    dup_task_struct  // 创建task_struct结构
      copy_files     // 创建 files_struct *files ,复制原 task 该结构体的内容,但并不是完全一样的, 具体不一样的细节没看明白
        copy_mm      // [重要] 将 struct mm_struct *mm 指向原 task 的指针 
        xx           // 其它操作 
  • 上面引入了重要的数据结构 struce mm_struct ,该结构定义了一个进程的整个虚拟地址空间,它里面有一个结构体 struct vm_area_struct *mmap
    struct vm_area_struct *mmap 是什么呢,它就是大名鼎鼎的这个进程所有VMA的列表。
  • VMA是虚拟内存的中的连续的一块虚拟内存,这块连续内存出于相同目的创建,有相同权限,默认是4KB对齐的,可以通过/proc/PID/maps查看

do_execve的实现

  do_execve
    do_execveat_common
      exec_binprm
        search_binary_handler // 轮询名为formats的list,看谁可以处理这种格式的文件,会找到下面这个节点 elf_format
            static struct linux_binfmt elf_format = {
            .module     = THIS_MODULE,
            .load_binary    = load_elf_binary,
            .load_shlib = load_elf_library,
            .core_dump  = elf_core_dump,
            .min_coredump   = ELF_EXEC_PAGESIZE,
        };
           load_elf_binary (可以参考这个wiki,很详细 https://www.cnblogs.com/inevermore/p/4438944.html )
             elf_map // 最终调用到 do_mmap , 也就是 mmap的核心处理,完成文件的映射
             elf_entry = load_elf_interp // 获取ld.so的入口地址,如果有动态链接库就会有,如果没有就不会有,没有的话,elf_entry就会赋值为进程本身入口地址
             start_thread(regs, elf_entry, bprm->p);   // 传入执行入口地址(elf_entry,也就是ld.so的入口地址或者可执行程序本身的入口地址),同时传入了regs寄存器组,这个寄存器组是当前进程的寄存器组,也就是用户态寄存器组,这样自动同时自动切换到了用户态

do_mmap的实现

  do_mmap
    do_mmap_pgoff
      找到一块可用的虚拟内存地址, 作为vma的起始地址
      mmap_region
        (由于MMAP有 MAP_FIXED 的场景,这种情况下,需要先 do_munmap )
        vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);  // 创建1个vma
        vma->vm_mm = mm; // 设置这个vma的内存描述符 (struct mm_struct *),每个进程只有1个
        vma->vm_pgoff = pgoff; // 设置这个vma的以page为单位的偏移
        
        error = file->f_op->mmap(file, vma); // 通过调用文件系统本身的mmap钩子,来实现地址映射,常用的是ext4:
        ext4_file_mmap()是ext4对应的mmap。
          ext4_file_mmap 
            vma->vm_ops = &ext4_file_vm_ops;    // 核心的一行,可以看到并没有发生实际的虚拟地址到文件的映射,只是设置了这个vma的操作函数
              /*
              static const struct vm_operations_struct ext4_file_vm_ops = {
                .fault      = filemap_fault,
                .map_pages  = filemap_map_pages,
                .page_mkwrite   = ext4_page_mkwrite,
              };                                
              */
  • 可以看到mmap执行本身最后并没有发生虚拟地址的映射,只是设置了vma的操作函数,其中有个重要的操作函数是61行的filemap_fault.这个函数是用于随后,
    当实际访问这个虚拟地址时,由于没有映射,会触发缺页中断,OS就会找到这个 vma的.fault的处理函数,也就是61行的filemap_fault. 下面看下这个函数。

filemap_fault的实现 - 填充page cache

  • 这个函数核心目的是,找到page cache,没有就创建1个,然后进行预取动作,我俗称填充动作(也就是将文件的内容从flash读取到page cache对应的物理页中)。
  • 这个函数具体流程是,检查是否存在这个文件的page cache(page cache是啥,往下看)发起IO,将falsh内容,读取到page cache , 然后把文件对应的page cache,也就是 struct page * ,找到并赋值给 vmf->page (struct vm_fault* vmf)。
  • linux的page cache:
    linux的每个物理文件,在内存中都有一个对应的page cache,在linux中通过 struct page*来表示这个page cache.
    主要作用:提供一个内存,并对这个内存区域进行预读,提高效率。这样相比直接读写flash效率更高
    filemap_fault
      page_cache_read  // 若page cache不存在,则发起IO,将falsh内容,读取到 page cache。执行完后,再通过goto走到下面第7行的page cache存在的处理,即预读。
        ext4_readpage (也就是mapping->a_ops->readpage这一行,它最终调到下面的函数)
          ext4_read_inline_page
            kaddr = kmap_atomic(page) // 将物理内存映射到内核的虚拟地址空间,得到映射后的地址kaddr
            ext4_read_inline_data   // 读取flash中的内容到这个地址kaddr
            kunmap_atomic   // 取消映射
      do_async_mmap_readahead // 若page cache存在,则进行预读处理,也就是把flash中文件内存读取到 page cache 中

  • 上面的4~6行具体是在将文件内容从flash读取到page所在的物理内存(page没忘吧, 就是page cache), 但是即便是OS也不能直接对物理内存进行写,因为也要通过MMU来访问物理内存,所以OS先通过kmap_atomic拿到1个和这个物理地址对应的虚拟地址kaddr,再通过这个地址kaddr去写其对应的物理地址,也就是这个page cache.

建立虚拟地址到page cache的映射

  • 上面的filemap_fault只是填充了page cache,也就是填充了 struct page * , 但是还欠缺虚拟地址到这个page cache的映射,也就是建立这个页表,只有这个完成了,缺页异常的处理才算完整了。下面跟着流程,从缺页异常的开始,是怎么建立页表,并和上面的filemap_fault建立联系的,继续往下看

do_page_fault // 区分是用户态的 page_fault 还是内核态的 page_fault 
    __do_page_fault // 查找对应的vma,如果没有(会检查权限不够吗?)则触发 SEGV 段错误
       handle_mm_fault
         __handle_mm_fault
           handle_pte_fault  // 建立页表函数
             do_anonymous_page  // 处理匿名映射
             do_fault  // 处理匿名映射,这里就会逐渐调入
                do_read_fault
                    __do_fault(,&fault_page))  // 返回出来这个文件的page cache
                        vma->vm_ops->fault  // 这里就是走到了之前mmap的时候,注册的page fault的回调了,也就是走到了上面的那个ext4_file_vm_ops注册的filemap_fault. 从这里可以看到,通过这个来申请或填充这个page cache,并且返回出来这个page cache
                    do_set_pte(fault_page)  // 建立vma的虚拟地址和page cache的映射
                                                  * 
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352

推荐阅读更多精彩内容

  • 一、前言 在 Linux设备驱动 中,内存使用 是一个逃不掉的话题。Linux内核 的内存管理庞大且复杂,要想理解...
    wipping的技术小栈阅读 4,349评论 0 3
  • 进程 创建 创建进程用fork()函数。fork()为子进程创建新的地址空间并且拷贝页表。子进程的虚拟地址空间...
    梅花怒阅读 1,898评论 0 7
  • 转自 https://blog.csdn.net/xiaojsj111/article/details/31422...
    han在路上阅读 728评论 0 0
  • Linux进程通信实现机制有很多,也有各自优缺点和适用场景,关于她们之间的对比,等各种通信机制一一介绍后,再来一个...
    batbattle阅读 4,070评论 3 13
  • 内存管理 内存管理包含: 物理内存管理; 虚拟内存管理; 两者的映射 除了内存管理模块, 其他都使用虚拟地址(包括...
    西山薄凉阅读 753评论 0 2