长期支持版本

    前置条件

    1. 本特性目前仅适用于ARM64。
    2. 硬件需支持部分MR内存(address range mirror),即通过UEFI标准接口上报属性为EFI_MEMORY_MORE_RELIABLE的内存,普通内存不用额外置位。镜像内存(MR)对应为高可靠内存,普通内存对应为低可靠内存。在暂时没有MR内存的机器上可以通过 efi_fake_mem 启动参数进行模拟验证。

    使用方法

    OS支持内存分级管理

    概述

    由于内存按照高低可靠性分为两段,内存的申请释放也需要按照高低可靠来进行分开管理。OS需要能够控制内存申请路径,用户态进程使用低可靠内存,内核态使用高可靠内存。高可靠内存不足时需要能够fallback到低可靠区申请或者直接申请失败。

    同时对于进程部分内存段的可靠性需求与进程本身的性质,也需要能够支持按需指定申请高低可靠内存。如指定关键进程使用高可靠内存,减少关键进程遇到内存错误的概率。目前内核使用的都是高可靠内存,用户态进程使用的都是低可靠内存。如此会造成一些关键或者核心服务的不稳定,如业务转发进程,如果发生故障,会造成IO中断,影响业务的稳定性。因此需要对这些关键服务特殊处理,使其使用高可靠内存,提高关键进程运行的稳定性。

    在系统遇到内存错误,OS应对未分配的低可靠内存进行覆盖写,以清除未发现的内存错误。

    约束限制

    • 关键进程使用高可靠内存

      1. /proc/ <pid>/reliable 接口的滥用可能存在高可靠内存被过多使用的风险。
      2. 用户态进程 reliable 属性只能在进程被拉起后,通过 proc 接口修改或者直接继承父进程该属性。systemd(pid=1)使用高可靠内存,其 reliable 属性无作用,也不继承,内核态线程reliable属性无效。
      3. 进程的程序段和数据使用高可靠内存,高可靠不足,使用低可靠启动。
      4. 普通进程在某些场景也会使用到高可靠内存,如hugetlb、pagecache、vdso、tmpfs等。
    • 未分配内存覆盖写特性

      未分配内存覆盖写特性只能执行一次,不支持并发操作,如果执行会有如下影响:

      1. 该特性耗时较大,每个 Node 有一个 CPU 被覆盖写线程所占用,其他任务在该 CPU 上无法调度。
      2. 覆盖写过程需获取 Zone lock,其他业务进程内存申请要等待覆盖写完成,可能导致内存分配不及时。
      3. 并发执行情况下会排队阻塞,产生更大的延时。

      如果机器性能不佳,将有可能触发内核RCU stall或soft lockup警告,以及进程内存申请操作被阻塞。因此请限制该特性在必要时只在物理机环境下使用,虚拟机等场景大概率出现如上现象。

      物理机参考数据可见下表(实际耗时与硬件性能、当前系统负载有关系)。

    表:基于物理机TaiShan 2280 V2空载状态下测试数据

    测试项Node 0Node 1Node 2Node 3
    Free Mem (MB)10929081218107365112053

    总耗时 3.2s

    使用方法

    本特性提供较多接口,使能特性并校验只需要步骤1-6即可。

    1. 配置启动参数“kernelcore=reliable”,代表打开内存分级管理开关,CONFIG_MEMORY_RELIABLE是必要的配置,否则整个系统的内存可靠性分级管理不使能。

    2. 根据需要,可以通过启动参数reliable_debug=[F][,S][,P]来选择性关闭fallback功能(F)、关闭tmpfs使用高可靠内存(S)以及关闭读写缓存使用高可靠内存(P),默认以上功能都使能。

    3. 根据BIOS上报的地址段,查找高可靠内存,并进行标记,对于NUMA系统,不一定每个node上都要预留可靠内存,但是node 0上低4G物理空间必须为高可靠的内存,系统启动过程中会申请内存,如果无法分到高可靠内存,则会 fallback 到低可靠内存进行分配(mirror功能自带的fallback逻辑)或导致系统无法启动。如果使用低可靠内存,整个系统都不稳定,所以要保留node0上的高可靠内存且低4G物理空间必须为高可靠的内存。

    4. 启动后,用户可以通过启动日志判断内存分级是否使能,应出现如下打印:

      mem reliable: init succeed, mirrored memory
      
    5. 高可靠内存对应的物理地址段可以通过启动日志来查询,观察efi上报memory map里的属性,带有“MR”的即为高可靠内存段,如下为启动日志节选,其中内存段mem06为高可靠内存,mem07为低可靠内存,其物理地址范围也列举在后(其他方式无法直接查询高、低可靠内存地址范围)。

      [  0.000000] efi: mem06: [Conventional Memory|  |MR| | | | | |  |WB| | | ] range=[0x0000000100000000-0x000000013fffffff] (1024MB) 
      [  0.000000] efi: mem07: [Conventional Memory|  | | | | | | |  |WB| | | ] range=[0x0000000140000000-0x000000083eb6cfff] (28651MB)     
      
    6. 内核态开发时,对于一个页面struct page,可以通过其所处的 zone来判断,ZONE_MOVABLE为低可靠内存区,zone编号小于ZONE_MOVABLE的均为高可靠内存区,判断方式举例如下。

      bool page_reliable(struct page *page) 
       { 
         if (!mem_reliable_status() || !page) 
           return false; 
         return page_zonenum(page) < ZONE_MOVABLE; 
       }
      

      此外提供的若干接口按照功能点分类列举如下:

      1. 代码层面判断可靠性是否使能: 在内核模块中通过如下接口来判断,返回 true 表示内存分级功能真正使能,返回false则未使能。
      #include <linux/mem_reliable.h>   
      bool mem_reliable_status(void);
      
      1. 内存热插拔: 如果内核本身使能内存热插拔操作(Logical Memory hot-add),高低可靠内存也支持该操作,操作单位为memory block,与原生流程一致。
      # 上线内存到高可靠区 
      echo online_kernel > /sys/devices/system/memory/auto_online_blocks 
      # 上线内存到低可靠区 
      echo online_movable > /sys/devices/system/memory/auto_online_blocks
      
      1. 动态关闭某项分级管理功能:

      注:此功能用于逃生使用,仅异常场景或者调测阶段需要关闭内存可靠性特性时配置,禁止作为常规功能直接使用。

      使用long类型控制根据每个bit判断内存分级功能开关与关闭某项功能:

      • bit0:内存可靠性分级管理功能。

      • bit1:禁止fallback到低可靠区域。

      • bit2:关闭tmpfs使用高可靠内存。

      • bit3:关闭pagecache使用高可靠内存。

        其他bit预留,用于扩展。如需更改,可通过如下proc接口(权限为600),取值范围0-15,(只有当总功能bit0为1时才会处理后续功能,否则直接关闭所有功能)。

        echo 15 > /proc/sys/vm/reliable_debug 
        # 关闭所有功能,因为bit0为0 
        echo 14 > /proc/sys/vm/reliable_debug
        

        此命令只能用于关闭功能,不能打开。对于已经关闭的功能或者运行时关闭的功能,这个命令不能将其打开。

      1. 查看高可靠内存部分统计信息: 可以通过原生/proc/meminfo来查看,其中:
      • ReliableTotal:内核管理可靠内存总大小。
      • ReliableUsed:系统使用可靠内存总大小,包含系统阶段reserved使用。
      • ReliableBuddyMem:伙伴系统剩余可靠总内存大小。
      • ReliableTaskUsed:表示当前关键用户进程,systemd使用的高可靠内存大小,包括匿名页与文件页。
      • ReliableShmem:表示共享内存高可靠用量,包括共享内存、tmpfs、rootfs使用高可靠内存总大小。
      • ReliableFileCache:表示读写缓存高可靠内存用量。
      1. 未分配内存覆盖写: 该功能需要打开配置项。

      CONFIG_CLEAR_FREELIST_PAGE,并且添加启动参数clear_freelist,两者具备才会使能。通过proc接口触发,取值范围只能为1(权限为0200)。

      echo 1 > /proc/sys/vm/clear_freelist_pages
      

      注:该特性依赖启动参数clear_freelist,内核对启动参数只匹配前缀,故诸如“clear_freelisttt”也会生效该特性。

      为防止误操作,加入内核模块参数cfp_timeout_ms,代表调用覆盖写功能的最长执行时长(超时则没写完也退出),通过sys接口触发,默认取值为2000ms(权限为0644):

      echo 500 > /sys/module/clear_freelist_page/parameters/cfp_timeout_ms # 设置超时为500ms
      
      1. 查看更改当前进程高低可靠属性: 可以通过/proc//reliable来查看该进程是否是高可靠进程;运行写入,该标识会继承,如果子进程不需要,则手动修改子进程属性;systemd和内核线程不支持该属性的读写;可以写0或 者1,缺省值为0,代表低可靠进程(权限为0644)。
      # 更改pid=1024的进程为高可靠进程,从更改之后开始进程缺页申请的内存是从高可靠内存区域申请,申请不到有可能fallback到低可靠 
       echo 1 > /proc/1024/reliable
      
      1. 设置用户态高可靠进程申请上限: 通过/proc/sys/vm/task_reliable_limit来修改用户态进程申请高可靠内存的上限,对应取值范围为[ReliableTaskUsed, ReliableTotal],单位为Byte(权限为0644)。需注意:
      • 缺省值为ulong_max,代表不受限制。
      • 当该值为0,可靠进程不可使用高可靠内存,fallback模式下,fallback到低可靠内存区域申请,否则直接OOM。
      • 当该值不为0并且触发该limit, 使能fallback功能,fallback到低可靠内存区域申请内存,不使能fallback功能,则返回OOM。

    读写缓存使用高可靠内存

    概述

    Page cache 也叫页缓冲或文件缓冲,在linux读写文件时,它用于缓存文件的逻辑内容,从而加快对磁盘上映像和数据的访问。Page cache申请如果使用低可靠内存,当访问时可能触发UCE导致系统异常。因此,需要将读写缓存(page cache)放到高可靠内存区域,同时为了防止Page cache申请过多(默认无限制)将高可靠内存耗尽,需要对page cache的总量及使用可靠内存总量进行限制。

    约束限制

    1. page cache超过限制后,page cache会进行定期回收,如果page cache的产生的速度大于page cache回收的速度则无法保证page cache的数量在指定的限制之下。
    2. /proc/sys/vm/reliable_pagecache_max_bytes的使用有一定限制,有部分场景的page cache会强制使用可靠内存,如读文件系统的元数据(inode, dentry等),会导致page cache使用的可靠内存超过接口的限制,可以通过 echo 2 > /proc/sys/vm/drop_caches 来释放inode和dentry。
    3. page cache使用的高可靠内存超过reliable_pagecache_max_bytes限制时,会默认申请低可靠内存,若低可靠内存申请不到,则遵循原生流程处理。
    4. FileCache的统计会先统计到per cpu的缓存中,当缓存中的值超过阈值时才会加到整个系统中,之后才能在/proc/meminfo中体现,ReliableFileCache在/proc/meminfo中没有上述的阈值,会导致有时ReliableFileCache比FileCache的统计值稍大。
    5. 写缓存场景会被dirty_limit限制(由/proc/sys/vm/dirty_ratio限制,代表单个内存节点脏页百分比),超过阈值会跳过当前zone。对于内存分级而言,由于高低可靠内存处于不同的zone,写缓存有可能触发本节点的fallback,使用本节点的低可靠内存。可以通过echo 100 > /proc/sys/vm/dirty_ratio来取消限制。
    6. 读写缓存使用高可靠内存的特性中会限制page cache的使用量,如下几种情况会导致系统性能受影响:
      • 如果page cache的上限值限制的过小,会导致IO增加,影响系统性能。
      • 如果page cache 回收的过于频繁,则可能会导致系统卡顿。
      • 如果page cache超过限制后每次回收量过大,则可能导致系统卡顿。

    使用方法

    读写缓存使用高可靠内存默认使能,如需关闭,可通过启动项参数设置reliable_debug=P。且page cache不能无限使用,需要限制page cache的使用量。限制page cache量的功能依赖的config开关为CONFIG_SHRINK_PAGECACHE。

    /proc/meminfo中的FileCache可以用来查询page cache的使用量,ReliableFileCache可以用来查询page cache中可靠内存的使用量。

    限制page cache量的功能依赖若干proc接口,接口定义在/proc/sys/vm/下,用来控制page cache的使用量,具体如下表:

    接口名称(原生/新增)权限说明缺省值
    cache_reclaim_enable(原生)644含义 :表示page cache限制的功能的使能开关。 取值范围 :0 或者 1,输入非法值,返回错误。 示例 :echo 1 > cache_reclaim_enable1
    cache_limit_mbytes(新增)644含义 :表示cache的上限,以M为单位,最小值0(表示关闭限制功能),最大值为meminfo中的MemTotal值(以M为单位换算后)。 取值范围: 最小值0(表示关闭限制功能),最大值为内存大小(以M为单位,如free –m看到的值)。 示例:echo 1024 > cache_limit_mbytes 其他: 建议cache上限不要低于总内存的一半,否则cache过小可能影响IO性能0
    cache_reclaim_s(原生)644含义: 表示定期触发cache回收的时间,以秒为单位系统会根据当前online的cpu个数来创建工作队列,如果有n个cpu则创建n个工作队列,每个工作队列每隔cache_reclaim_s秒进行一次回收。该参数与cpu上下线功能兼容,如果cpu offline,则会减少工作队列个数,cpu online,则会增加。 取值范围 :最小值0(表示关闭定期回收功能),最大43200,输入非法值,返回错误。 示例 :echo 120 > cache_reclaim_s 其他 :建议定期回收时间设成几分钟的级别(如2分钟),否则频繁回收可能导致系统卡顿0
    cache_reclaim_weight(原生)644含义: 表示每次回收的权值,内核每个CPU每次期望回收32 * cache_reclaim_weight个page。该权值同时作用于page上限触发的回收和定期page cache回收。 取值范围:最小值1,最大值100,输入非法值,返回错误。 示例 :echo 10 > cache_reclaim_weight 。其他 :建议设为10或以下,否则每次回收过多内存时,系统可能卡顿1
    reliable_pagecache_max_bytes(新增)644含义 :该接口用于控制page cache中高可靠内存的总量。 取值范围:0 ~ 高可靠内存最大值,单位为Bytes,高可靠内存的最大值可以通过/proc/meminfo查询,输入非法值返回错误。 示例: echo 4096000 > reliable_pagecache_max_bytesunsigned long 类型的最大值,代表不限制用量。

    tmpfs使用高可靠内存

    概述

    对于使用tmpfs做rootfs,rootfs中存放的操作系统使用的核心文件和数据。但是tmpfs默认使用的是低可靠内存,这样会造成核心文件和数据的不可靠。因此需要tmpfs整体使用高可靠内存。

    使用方法

    tmpfs使用高可靠内存默认使能,如需关闭,可通过启动项参数设置reliable_debug=S,可以通过/proc/sys/vm/reliable_debug动态关闭,但不能动态打开。

    在使能tmpfs使用高可靠内存时,可通过/proc/meminfo中ReliableShmem查看当前tmpfs已经使用的高可靠内存。

    默认tmpfs使用上限是物理内存的一半(rootfs使用tmpfs时除外)。基于传统的SYS V的共享内存,它的使用同时受/proc/sys/kernel/shmmax以及/proc/sys/kernel/shmall的限制,可以动态配置。同时他们也受tmpfs使用高可靠内存的限制。详见下表.

    参数说明
    /proc/sys/kernel/shmmax(原生)SysV共享内存单个段可使用的大小
    /proc/sys/kernel/shmall(原生)SysV共享内存总的可使用的大小

    新增接口 /proc/sys/vm/shmem_reliable_bytes_limit 用户设置系统级别 tmpfs 可用的高可靠大小(单位为Byte),缺省值为LONG_MAX,代表用量不受限。可设置的范围为[0, 系统可靠内存总大小],权限为644。fallback关闭时,在达到该使用上限时,返回没有内存的错误,fallback开启时会尝试从低可靠区域申请。使用示例:

    echo 10000000 > /proc/sys/vm/shmem_reliable_bytes_limit
    

    用户态穿越内核UCE不复位

    概述

    按照内存可靠性分级的方案,内核以及关键进程使用高可靠内存。大部分用户态进程使用低可靠内存。系统运行时,涉及大量的用户态与内核态数据交换,数据传入内核态时,即发生低可靠内存上数据拷贝到高可靠内存区域。拷贝动作发生在内核态,如果这时在读取用户态数据时发生UCE错误,即发生内核态消费内存UCE,系统会触发panic。本子特性对部分用户态穿越内核UCE场景提供解决方案,避免系统复位,包括COW场景、copy_to_user场景、copy_from_user场景、get_user场景、put_user场景、coredump场景,其余场景均不支持。

    约束限制

    1. ARMv8.2及以上版本支持的RAS特性。
    2. 本特性更改的是同步异常处理策略,因此本特性的生效依赖于内核收到Firmware上报的同步异常。
    3. 内核处理依赖BIOS上报的错误类型,不能处理fatal级别硬件错误,可以处理recoverable级别的硬件错误。
    4. 仅支持COW场景、copy_to_user场景(包含读缓存pagecache)、copy_from_user场景、get_user场景、put_user场景、coredump场景六个用户态穿越内核态场景,其余场景不支持。
    5. 在coredump场景中,因为需要在文件系统的write接口上做UCE容错,本特性只支持常用的三个文件系统:ext4、tmpfs、pipefs,对应的容错接口如下:
      • pipefs:copy_page_from_iter
      • ext4/tmpfs:iov_iter_copy_from_user_atomic
    6. 应用程序默认处理SIGBUS信号,忽略或自定义SIGBUS信号处理会导致进程状态异常。

    使用方法

    确保内核开启config开关CONFIG_ARCH_HAS_COPY_MC,/proc/sys/kernel/machine_check_safe值为1时代表全场景使能,改为0代表不使能,其他值均为非法。

    当前各场景容错处理机制如下:

    序号场景现象应对措施
    1copy_from/to_user:最基本的用户态穿越,主要涉及syscall,sysctl,procfs的操作如果在拷贝时出现UCE异常,会导致内核复位出现 UCE 异常时,kill 当前进程,内核不主动复位
    2get/put_user:用于简单的变量拷贝,主要是netlink的场景用的比较多如果在拷贝时出现UCE异常,会导致内核复位出现 UCE 异常时,kill 当前进程,内核不主动复位
    3COW:fork子进程,触发写时拷贝触发写时拷贝,如果出现UCE会导致内核复位出现 UCE 异常时,kill 相关进程,内核不主动复位
    4读缓存:用户态使用了低可靠内存,用户态程序读写文件时,操作系统会使用空闲内存缓存硬盘文件,提升性能。但用户态程序对文件的读取会先经过内核访问缓存出现UCE异常,会导致内核复位出现 UCE 错误时,kill 当前进程,内核不主动复位
    5coredump时内存访问触发UCE出现UCE异常,会导致内核复位出现 UCE 错误时,kill 当前进程,内核不主动复位
    6写缓存:写缓存回刷到磁盘时,触发UCE回刷缓存其实就是磁盘DMA数据的搬移,如果在此过程中触发UCE,超时结束后,页面写失败,这样会造成数据不一致,进而会导致文件系统不可用,如果是关键的数据,会出现内核复位没有解决方案,不支持,内核会发生复位
    7内核启动参数、模块参数使用的都是高可靠内存/不支持,且本身风险降低
    8relayfs:是一个快速的转发数据的文件系统,用于从内核态转发数据到用户态,/不支持,且本身风险降低
    9seq_file:将内核数据通过文件的形式传输到用户态/不支持,且本身风险降低

    由于用户态数据大多使用低可靠内存,本项目只涉及内核态读取用户态数据的场景。Linux系统下用户空间与内核空间数据交换有九种方式, 包括内核启动参数、模块参数与 sysfs、sysctl、syscall(系统调用)、netlink、procfs、seq_file、debugfs和relayfs。另有两种情况,进程创建时,COW(copy on write,写时复制)场景,和读写文件缓存(pagecache)场景。

    其中sysfs,syscall, netlink, procfs 等方式从用户态传输数据到内核都是通过copy_from_user或者get_user的方式。

    因此用户态传输到内核有如下几种场景:

    copy_from_user、get_user、COW、读缓存、写缓存回刷。

    内核态传到用户态有如下几种场景:

    relayfs、seq_file、copy_to_user、put_user。

    文档捉虫

    “有虫”文档片段

    问题描述

    提交类型 issue

    有点复杂...

    找人问问吧。

    PR

    小问题,全程线上修改...

    一键搞定!

    问题类型
    规范和低错类

    ● 错别字或拼写错误;标点符号使用错误;

    ● 链接错误、空单元格、格式错误;

    ● 英文中包含中文字符;

    ● 界面和描述不一致,但不影响操作;

    ● 表述不通顺,但不影响理解;

    ● 版本号不匹配:如软件包名称、界面版本号;

    易用性

    ● 关键步骤错误或缺失,无法指导用户完成任务;

    ● 缺少必要的前提条件、注意事项等;

    ● 图形、表格、文字等晦涩难懂;

    ● 逻辑不清晰,该分类、分项、分步骤的没有给出;

    正确性

    ● 技术原理、功能、规格等描述和软件不一致,存在错误;

    ● 原理图、架构图等存在错误;

    ● 命令、命令参数等错误;

    ● 代码片段错误;

    ● 命令无法完成对应功能;

    ● 界面错误,无法指导操作;

    风险提示

    ● 对重要数据或系统存在风险的操作,缺少安全提示;

    内容合规

    ● 违反法律法规,涉及政治、领土主权等敏感词;

    ● 内容侵权;

    您对文档的总体满意度

    非常不满意
    非常满意
    提交
    根据您的反馈,会自动生成issue模板。您只需点击按钮,创建issue即可。
    文档捉虫
    编组 3备份