首页 > 系统相关 >linux内存管理(五)- 缺页处理

linux内存管理(五)- 缺页处理

时间:2024-06-11 13:55:19浏览次数:25  
标签:mm FAULT linux VM vma flags 内存 fault 缺页

分析一下缺页的处理。缺页的意思是在访问内存的时候该地址还没有建好页表,页面尚未分配,或者页面被swap出去或者没有权限。缺页是同步异常,用户态发生缺页异常会等待内核解决,当然这一切对于用户态都是透明的。缺页处理的核心函数是do_page_fault,这个函数是架构相关的所以这个函数分布在各个架构相关的代码中。我们以arm64为例。

static int __kprobes do_page_fault(unsigned long far, unsigned long esr,
                   struct pt_regs *regs)
{
    const struct fault_info *inf;
    struct mm_struct *mm = current->mm;
    vm_fault_t fault;
    unsigned long vm_flags;
    unsigned int mm_flags = FAULT_FLAG_DEFAULT;
    unsigned long addr = untagged_addr(far);
    struct vm_area_struct *vma;

//kprobe还会处理page fault? if (kprobe_page_fault(regs, esr)) return 0; /* * If we're in an interrupt or have no user context, we must not take * the fault. */
//task_struct里面有一个pagefault_disabled成员用来作禁止pagefault的标志 if (faulthandler_disabled() || !mm) goto no_context; //查看pstate错误是否用户态 if (user_mode(regs)) mm_flags |= FAULT_FLAG_USER; /* * vm_flags tells us what bits we must have in vma->vm_flags * for the fault to be benign, __do_page_fault() would check * vma->vm_flags & vm_flags and returns an error if the * intersection is empty */
//判断错误类型 if (is_el0_instruction_abort(esr)) { /* It was exec fault */ vm_flags = VM_EXEC; mm_flags |= FAULT_FLAG_INSTRUCTION; } else if (is_write_abort(esr)) { /* It was write fault */ vm_flags = VM_WRITE; mm_flags |= FAULT_FLAG_WRITE; } else { /* It was read fault */ vm_flags = VM_READ; /* Write implies read */ vm_flags |= VM_WRITE; /* If EPAN is absent then exec implies read */ if (!alternative_has_cap_unlikely(ARM64_HAS_EPAN)) vm_flags |= VM_EXEC; } if (is_ttbr0_addr(addr) && is_el1_permission_fault(addr, esr, regs)) {
//在kernel态执行用户态指令出错 if (is_el1_instruction_abort(esr)) die_kernel_fault("execution of user memory", addr, esr, regs); if (!search_exception_tables(regs->pc)) die_kernel_fault("access to user memory outside uaccess routines", addr, esr, regs); }
//perf软件事件?有空看看 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr); if (!(mm_flags & FAULT_FLAG_USER)) goto lock_mmap; //获取vma vma = lock_vma_under_rcu(mm, addr); if (!vma) goto lock_mmap; //出错类型跟vma的权限一定得对的上,不然就有问题 if (!(vma->vm_flags & vm_flags)) { vma_end_read(vma); goto lock_mmap; }
//上次刚分析了一下,分配页面,如果一切顺利,返回0 fault = handle_mm_fault(vma, addr, mm_flags | FAULT_FLAG_VMA_LOCK, regs); if (!(fault & (VM_FAULT_RETRY | VM_FAULT_COMPLETED))) vma_end_read(vma); //不需要重试就goto done if (!(fault & VM_FAULT_RETRY)) { count_vm_vma_lock_event(VMA_LOCK_SUCCESS); goto done; } count_vm_vma_lock_event(VMA_LOCK_RETRY); if (fault & VM_FAULT_MAJOR) mm_flags |= FAULT_FLAG_TRIED; /* Quick path to respond to signals */ if (fault_signal_pending(fault, regs)) { if (!user_mode(regs)) goto no_context; return 0; } lock_mmap: retry: vma = lock_mm_and_find_vma(mm, addr, regs); if (unlikely(!vma)) { fault = VM_FAULT_BADMAP; goto done; } //还是调用handle_mm_fault fault = __do_page_fault(mm, vma, addr, mm_flags, vm_flags, regs); /* Quick path to respond to signals */ if (fault_signal_pending(fault, regs)) { if (!user_mode(regs)) goto no_context; return 0; } /* The fault is fully completed (including releasing mmap lock) */ if (fault & VM_FAULT_COMPLETED) return 0; if (fault & VM_FAULT_RETRY) { mm_flags |= FAULT_FLAG_TRIED; goto retry; } mmap_read_unlock(mm); done: /* * Handle the "normal" (no error) case first. */
//正常情况这里就返回了 if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS)))) return 0; /* * If we are in kernel mode at this point, we have no context to * handle this fault with. */ if (!user_mode(regs)) goto no_context; if (fault & VM_FAULT_OOM) { /* * We ran out of memory, call the OOM killer, and return to * userspace (which will retry the fault, or kill us if we got * oom-killed). */
//没内存了,咋整 pagefault_out_of_memory(); return 0; } inf = esr_to_fault_info(esr);
//task_struct里面有一个thread成员保存进程上下文,里面有标志出错的成员,fault_address和fault_code,设置他们 set_thread_esr(addr, esr); if (fault & VM_FAULT_SIGBUS) { /* * We had some memory, but were unable to successfully fix up * this page fault. */ arm64_force_sig_fault(SIGBUS, BUS_ADRERR, far, inf->name); } else if (fault & (VM_FAULT_HWPOISON_LARGE | VM_FAULT_HWPOISON)) { unsigned int lsb; lsb = PAGE_SHIFT; if (fault & VM_FAULT_HWPOISON_LARGE) lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); arm64_force_sig_mceerr(BUS_MCEERR_AR, far, lsb, inf->name); } else { /* * Something tried to access memory that isn't in our memory * map. */ arm64_force_sig_fault(SIGSEGV, fault == VM_FAULT_BADACCESS ? SEGV_ACCERR : SEGV_MAPERR, far, inf->name); } return 0; no_context:
//kernel一般是不会有page fault的,大概率是bug,发一个Oops然后杀掉进程算了 __do_kernel_fault(addr, esr, regs); return 0; }

 kernel一般只处理用户进程发生的page fault,如果发生在kernel态可能是个bug。do_page_fault会调用handle_mm_fault去处理。这个函数在之前已经分析过了,这里就省略,不过为了完整性,之后会补上。

标签:mm,FAULT,linux,VM,vma,flags,内存,fault,缺页
From: https://www.cnblogs.com/banshanjushi/p/17995048

相关文章

  • 在Linux中,当用户反馈网站访问慢,如何处理?
    当用户反馈网站访问慢时,在Linux环境中进行问题排查和解决可以遵循以下步骤:确认问题存在:首先,尝试复现问题。自己或让同事从不同地点和网络环境下访问网站,看是否同样慢。使用浏览器的开发者工具(如Chrome的Network面板)检查页面加载时间,识别哪个资源加载慢。定位问题源头:......
  • 在Linux中,文件权限有哪些?
    在Linux中,文件权限是确保系统安全的重要机制,它们控制着用户能够对文件或目录执行的操作类型。Linux文件权限分为以下几种基本类型:读权限(r):对于文件:允许用户查看文件的内容,例如使用cat、less或more命令阅读文件。对于目录:允许用户查看目录中的文件列表,即可以执行ls命令。......
  • 在Linux中,性能调优都有哪几种方法?
    在Linux中,性能调优是一个综合性的过程,旨在提升系统的运行效率、响应速度和资源利用率。以下是一些关键的性能调优方法:监控与分析使用工具如top,htop,vmstat,iostat,netstat,dstat,iftop,nmon等监控CPU使用率、内存使用、磁盘I/O、网络流量等,以便识别瓶颈。利用sysdig......
  • Linux-应用编程学习笔记(字符串处理)
    一、字符串输入/输出1、字符串输出//C库函数,向标准输出设备(屏幕、显示器)输出字符串并自行换行#include<stdio.h>intputs(constchar*s);s:需要进行输出的字符串。返回值:成功返回一个非负数;失败将返回EOF,EOF其实就是-1。//C库函数,既可以是标准输出、标准错误设备......
  • 在Linux中,如何进行调度任务?什么是 crontab 并解释 crontab 中的字段?
    在Linux中,调度任务通常指的是在预定的时间自动执行脚本或命令。cron(cronjob)是一种常用的任务调度工具,它按照设定的时间表周期性地执行任务。1.什么是crontab?crontab是一个配置文件,它包含了一个或多个cron任务的列表。每个任务都有一个特定的时间表,定义了任务何时执行。cro......
  • linux内存管理(二)- vmalloc
    个人笔记,谨慎观看.先看看vmalloc是怎么实现的。它能在非连续物理内存之上建立连续的虚拟内存映射。这里有一篇博客Linux内存管理(6)vmalloc-ArnoldLu-博客园(cnblogs.com)调用链vmalloc->_vmalloc_node->_vmalloc_node_rangevoid*__vmalloc_node(unsignedlongsize,......
  • 在Linux中,如何规划⼀台 Linux 主机,步骤是怎样?
    在Linux中规划一台主机是一个涉及多个方面的过程,以下是一个详细的步骤指南:1.确定需求首先,明确你的需求,包括预期的硬件配置、操作系统版本、软件需求等。这有助于为后续的磁盘分区和资源分配提供依据。2.选择合适的硬件配置处理器(CPU):选择适合应用场景的处理器。对于小型系......
  • Linux 相关基础知识(无关命令)
    Linux相关基础知识(无关命令)目录Linux相关基础知识(无关命令)1.Linux系统的启动过程2.linux内核的作用3.linux七种文件以及对应符号4.linux的目录结构5.MMU内存管理单元6.文件系统(FAT32和NTFS)7.内存1.Linux系统的启动过程1)上电 2)执行启动引导程序 3)加载linux内核......
  • 玄机——第一章 应急响应- Linux入侵排查 wp
    文章目录一、前言二、概览简介三、参考文章四、步骤(解析)步骤#1.1web目录存在木马,请找到木马的密码提交步骤#1.2服务器疑似存在不死马,请找到不死马的密码提交步骤#1.3不死马是通过哪个文件生成的,请提交文件名步骤#1.4黑客留下了木马文件,请找出黑客的服务器ip提交步骤......
  • 文件系统(六):一文看懂linux ext4文件系统工作原理
    liwen012024.06.09前言Linux系统中的ext2、ext3、ext4文件系统,它们都有很强的向后和向前兼容性,可以在数据不丢失的情况下进行文件系统的升级。目前ext4是一个相对较成熟、稳定且高效的文件系统,适用于绝大部分规模和需求的Linux环境。ext4它突出的特点有:数据分段管理、多块分......