大家好,感谢邀请,今天来为大家分享一下swapper_pg_dir 和kmalloc() 和vmalloc() 简介的问题,以及和的一些困惑,大家要是还不太明白的话,也没有关系,因为接下来将为大家分享,希望可以帮助到大家,解决大家的问题,下面就开始吧!
swapper_pg_dir只是在内核初始化时加载到cr3中表示内存映射信息,然后在init进程启动后成为空闲内核线程的页目录指针。
/sbin/init是由一个名为init的内核线程的exec形成的,而init内核线程是由原内核的do_fork形成的,也就是后来的空闲线程。在do_fork中,将为新进程重启分配一个页目录指针。可见swapper_pg_dir仅在idle线程和kernel线程中使用。
do_fork -copy_mm -mm_init -pgd_allocpgd_t *pgd_alloc(struct mm_struct *mm){pgd_t *pgd=(pgd_t *)__get_free_page(GFP_KERNEL);if (pgd) {memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));memcpy( pgd + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));}返回pgd;}
USER_PTRS_PER_PGD值为768,pgd_alloc将swapper_pg_dir中的768~1023项复制到进程页表中。
所有进程共享内核空间,因此共享内核页表是很自然的。理论上,内核只有一张页表,对应内核全局页目录swapper_pg_dir。每个进程都有自己的页目录,共有1024个表项,其中768个表项与swapper_pg_dir相同,指向内核空间。
然而,每个进程的内核地址空间的页表与主内核页表并不完全一致。原因是vmalloc后修改了主内核页表,但进程的页表没有修改。
asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code){.if (address=TASK_SIZE !(error_code 5))goto vmalloc_fault;vmalloc_fault:{/** 将此任务的顶级页表*与“参考”页表。**不要在此处使用“tsk”。我们可能在任务切换过程中*处于中断状态.*/int offset=__pgd_offset(address); //页目录项偏移量pgd_t *pgd, *pgd_k;pmd_t *pmd, *pmd_k;pte_t *pte_k;asm('movl %%cr3,%0':'=r' (pgd));pgd=offset + ( pgd_t *)__va(pgd) ; //对应pgdpgd_k=init_mm.pgd + 用户态页表中的偏移量; //内核页表的偏移量swapper_pg_dir if (!pgd_present(*pgd_k))goto no_context;set_pgd(pgd, *pgd_k); //将内核页表swapper_pg_dir中的目录项复制到用户页表pmd=pmd_offset(pgd, address); //页表偏移pmd_k=pmd_offset(pgd_k, address); //swapper_pg_dir中的页表偏移量if (!pmd_present(*pmd_k)) //判断pmd项是否存在。如果不是,则返回失败goto no_context;set_pmd(pmd, *pmd_k); //复制内核页表swapper_pg_dir页表项到用户页表pte_k=pte_offset(pmd_k, address);if (!pte_present(*pte_k)) //判断pte项是否存在。如果不是,返回失败goto no_context;return;}}
当进程访问这个虚拟地址空间时,该进程的页目录项为空。此时会产生缺页中断,然后调用do_page_fault。该方法中会判断访问的虚拟地址是否大于0xc0000000(3G)。如果大于3G,则说明要访问的虚拟地址处于内核态,因此执行vmalloc_fault。在vmalloc_fault中,虚拟地址对应的页目录项和页表项会从swapper_pg_dir复制到进程的页表中,从而使进程页目录项的值与主内核页表完全一致后同步。这样一来,只有访问这个vmalloc区间的进程才会更新主内核页表。当然,内核修改主内核页表后,必须向所有CPU发送TLB刷新请求,因为有可能某个CPU正在运行的进程对应的页表项存储在TLB中。
vmalloc简介
vmalloc分配的每一块内核虚拟内存都对应一个vm_struct结构。不同的内核虚拟地址被4k空闲区域分隔开,防止越界。
vmalloc区域与用户空间内存映射不一样。页面通过页面错误加载。 vmalloc映射建立后,逻辑地址和物理页全部分配完毕,页表也已更新。不过,这是内核页表,相关进程的页表还没有更新。当vmalloc区域发生缺页时,将“内核页表”同步到“进程页表”。当内核使用vmalloc为这部分区域对应的线性地址分配内存时,对应的物理内存实际上已经被分配并进行了相应的映射,并建立了对应的页表项,但是相关的页表项只有被写入的“内核页表”并没有实时更新到“进程页表”。内核这里采用了“延迟更新”策略,将“进程页表”的实际更新推迟到第一次访问到相关线性地址时才进行,从而导致页面错误。此时,“进程页表”在缺页处理过程中被更新。
使用vfree() 方法释放该区域。该方法仅在释放区域时修改内核页表swapper_pg_dir。它会将addr对应的pte页表项设置为0,即调用ptep_get_and_clear()将该页表项清除为0。设置完之后再调用flush_tlb_all()刷新TLB。但它并不会修改所有进程的进程页表。
从上面可以看出,swapper_pg_dir和用户进程页表共享页目录表,所以当再次访问虚拟地址时,就找不到页表项,出现页错误。
缺页异常与上面分配的过程是一样的,只不过最后检查内核页表的pte表项时,发现addr的内核页表的pte页表项为0,并且将报告错误。这避免了进程的非法访问。

kmalloc() 和vmalloc() 之间的区别
kmalloc()和vmalloc()都是内核代码中提供给其他子系统分配内存的函数,但是它们有什么区别呢?
kmalloc。。kernel_malloc,它是内核的内存分配函数。
kmalloc的释放对应kfree。
从前面的介绍可以看出,这两个函数分配的内存都在内核空间,即3GB到4GB;但位置不同。 kmalloc()分配的内存在3GB到high_memory之间,而vmalloc()分配的内存范围在VMALLOC_START到4GB之间,属于非连续内存区域。
一般来说,驱动程序中调用kmalloc() 为数据结构分配内存,而vmalloc() 用于为活动交换区域分配数据结构,为某些I/O 驱动程序或模块分配缓冲区。分配空间,例如include/asm-i386/module.h中定义如下语句:
#定义module_map(x) vmalloc(x)
含义是将模块映射到非连续的内存区域。
对应kmalloc()和vmalloc(),释放内存的两个函数是kfree()和vfree()。
vmalloc()分配的物理地址不需要是连续的,而kmalloc()则确保页面在物理上连续。
函数vmalloc()从内核的虚拟地址空间(3G以上)分配一块虚拟内存和对应的物理内存,类似于系统调用brk()。
不过brk()是由用户空间的进程启动,从用户空间分配的,而vmalloc()是从系统空间,即从内核启动,从内核空间分配。
vmalloc()分配的空间不会被kswapd换出,因为kswapd只扫描每个进程的用户空间,根本看不到vmalloc()分配的页表项。
对于通过kmalloc()分配的数据结构,kswapd只是从每个slab队列中查找并收集未使用的slab,并释放占用的页面,但不会换出仍在使用的slab占用的页面。
标题:swapper_pg_dir 和kmalloc() 和vmalloc() 简介
链接:https://www.ltthb.com/news/xydt/124236.html
版权:文章转载自网络,如有侵权,请联系删除!
用户评论
终于找到关于 kernel memory alloc 的详细介绍了!学习Linux内核越来越难了,很多操作机制和函数还是比较抽象的,这篇博客讲得很通俗易懂,尤其是 swapper_pg_dir 和 swap espaços 部分,真的很好理解。
有6位网友表示赞同!
kmalloc() 和 vmalloc(),这两个函数我以前搞不太明白区别。这篇文章解释得真棒!前者用于分配内核空间的内存,后者可以用作 用户空间地址空间扩展,这样就能在进程之间共享页面,挺厉害的!
有15位网友表示赞同!
swapper_pg_dir 这个概念还是第一次接触,感觉很理论性的东西,但是博主讲得很有逻辑,结合实际例子解释,让我印象深刻。学习 Linux 内核确实像要学一门新的语言一样,需要不断积累和实践。
有10位网友表示赞同!
这篇文章太棒了!我一直对 kernel memory 管理感兴趣,终于找到了能够详细讲解 swapper_pg_dir 和不同内存分配函数的博客!以后我要好好练习一下kmalloc()和vmalloc()的使用
有6位网友表示赞同!
感觉这篇博客对新手来说还是有些难度,一些专业术语不太容易理解。建议博主可以提供更多具体的代码示例,这样学习效果会更好!
有19位网友表示赞同!
swapper_pg_dir 对我来说比较抽象,如果能用简单的图示或动画来解释,说不定更容易理解?!
有19位网友表示赞同!
kmalloc() 和 vmalloc() 都很常用,但是经常混淆。这篇文章非常清晰地讲解了他们的区别和适用场景,受益匪浅!感谢博主分享。
有14位网友表示赞同!
其实我觉得 kernel memory management 越来越复杂了,各种函数和概念真让人头疼!希望以后能有更多深入浅出讲解Kernel的博客。
有15位网友表示赞同!
这篇文章把我写的代码都打乱了!swapper_pg_dir 和 kmalloc() 的用法我之前没有完全弄懂,现在看到这篇分析,我才明白为什么会出现问题。
有18位网友表示赞同!
学习Linux内核真是太难了!kmalloc() 和 vmalloc() 只是冰山一角,还有很多其他机制和函数需要深入了解。希望以后能有机会进一步学习。
有12位网友表示赞同!
我以前一直把 kmalloc() 和 vmalloc() 当成同一个东西, 这篇文章帮我拨开云雾,终于明白它们之间的区别!
有14位网友表示赞同!
这篇文章很不错,特别是对 swapper_pg_dir 的讲解很 hilfreich,让我对 Linux 内核的内存管理有了更深入的理解。
有16位网友表示赞同!
对于我来说,这篇博客写的有点过于技术化了,希望能简化一些语言和描述,更容易理解!
有5位网友表示赞同!
感谢博主分享这篇文章!学习Linux内核需要踏踏实实的学习,这篇文章帮我理清了一些思路和认知。我会继续关注相关内容,不断提升自己!
有10位网友表示赞同!
我觉得这篇文章最大的问题是缺乏具体的代码示例,如果能提供一些实际的代码案例,对于理解 swapper_pg_dir 和 kmalloc() 的用法会更加有帮助。
有20位网友表示赞同!
我非常喜欢这篇博文!它让我对内核空间的内存管理有了更深入的了解。我会把这篇文章分享给我的同学和朋友们,一起学习linux kernel!
有20位网友表示赞同!
如果能结合最新的Linux内核版本进行讲解,那就更加完美了!我相信许多读者和我一样,希望能掌握最新版本的内核开发知识。
有13位网友表示赞同!
对于 linux 内核内存管理 来说, 这篇文章只是一个初级的介绍。 希望作者能够继续深入探讨一些更复杂的概念和机制
有10位网友表示赞同!
虽然这篇博文讲解了一些入门级的内容,但对于想要深入了解 Linux 内核的读者来说,可能还显得不够专业! 希望作者能够加入更多细节性的解释和分析。
有14位网友表示赞同!