109 Star 71 Fork 297

src-openEuler/kernel

 / 详情

内存可靠性分级需求

待办的
任务 成员
创建于  
2022-09-16 16:16

1 内存可靠性分级管理

1.1 概述

1.2 约束限制

1.3 使用方法

1.3.1 OS支持内存分级管理

1.3.2 读写缓存使用高可靠内存

1.3.3 tmpfs使用高可靠内存

1.3.4 用户态穿越内核UCE不复位

内存可靠性分级管理

1.1 概述

1.2 约束限制

1.3 使用方法

概述

本特性可以支撑使用者按照需求分配在对应可靠性的内存上,并对部分可能的UCE或CE故障影响进行一定程度的缓解,达到部分MR内存(address range mirror)的情况下,支撑业务整体可靠性不下降。

约束限制

本章节介绍该特性的通用约束,每个子特性会有具体的约束,在对应的小节中详细说明。

兼容性限制

  1. 本特性目前仅适用于ARM64。
  2. 硬件需支持部分MR内存(address range mirror),即通过UEFI标准接口上报属性为EFI_MEMORY_MORE_RELIABLE的内存,普通内存无需额外置位。镜像内存(MR)对应为高可靠内存,普通内存对应为低可靠内存。
  3. 高低可靠内存分级借助内核的内存管理区(zone)来实现,两者无法进行动态流动(即页面不能在不同zone之间移动)。
  4. 不同可靠性的连续物理内存会被分隔到不同的memblock,可能会导致原本可以申请大块连续物理内存的场景在使能内存分级后受到限制。
  5. 本特性使能需要依赖启动参数kernelcore的取值为“kernelcore=reliable”,与该参数其他取值均不兼容。

设计规格限制

  1. 内核态开发时,内存申请操作需要注意:

    • 若内存申请接口支持指定gfp_flag,只有gfp_flag包含__GFP_HIGHMEM且__GFP_MOVABLE的内存申请会强制普通内存区域分配或者将这次内存分配重定向可靠内存区域,其他gfp_flag都不会进行干预。

    • 从slab/slub/slob申请获取的都是高可靠内存(一次性申请内存大于KMALLOC_MAX_CACHE_SIZE时且gfp_flag指定为普通内存区域时可能申请到低可靠内存)。

  2. 用户态开发时,内存申请操作需要注意:

    • 更改普通进程属性为关键进程后,实际物理内存分配阶段(page fault)才会使用高可靠内存,此前已分配的内存属性不会改变,反之亦然。因此普通进程被拉起到更改关键进程属性期间申请的内存可能不是高可靠内存。是否生效可以通过查询虚拟地址对应的物理地址是否属于高可靠内存段来验证。
    • Libc库如glibc中chunk等类似机制(ptmalloc、tcmalloc、dpdk)为了提高性能存在使用cache的逻辑,而内存cache会导致用户申请内存与内核内存申请逻辑不能完全对应,普通进程变成关键进程时并不能真正使能(该标记仅仅在内核实际发生内存申请时使能)。
  3. 当上层业务申请内存的时发现高可靠内存不足(触发zone原生min水线)或者触发对应limit限制,会优先释放pagecache以尝试回收高可靠内存。如果仍然申请不到,内核会根据fallback的开关选择oom或fallback到低可靠内存区域完成内存申请。(fallback指某个内存管理区/节点内存不足时,到其他内存管理区/节点申请内存的情况。)

  4. 类似于NUMA_BALANCING的内存动态迁移机制,可能导致已经分配的高/低可靠内存被迁移到别的节点,由于该迁移操作丢失内存申请的上下文,且目标node可能没有对应可靠性的内存,因此可能导致迁移后的内存可靠性与预期不符。

  5. 按照用户态高可靠内存用途引入如下三个配置文件:

    • /proc/sys/vm/task_reliable_limit: 关键进程(包含systemd)使用的高可靠内存上限。包含匿名页和文件页。进程使用的shmem也会被统计到其中(包含在匿名页中)。

    • /proc/sys/vm/reliable_pagecache_max_bytes:全局pagecache使用的高可靠内存软上限。约束普通进程使用的高可靠pagecache的数量,系统默认不限制pagecache使用的高可靠内存的量。高可靠进程和文件系统元数据等场景不受此约束。无论fallback开关是否开启,普通进程触发该上限时,会默认申请低可靠内存,若低可靠内存申请不到,则遵循原生流程处理。

    • /proc/sys/vm/shmem_reliable_bytes_limit:全局shmem使用的高可靠内存软上限。约束普通进程shmem使用高可靠内存的数量,系统默认不限制shmem使用的高可靠内存的量。高可靠进程不受此约束。关闭fallback时,普通进程触发该上限会导致内存申请失败,但不会OOM(与原生流程一致)。

    触及这些值可能会导致内存申请fallback或者OOM。

    关键进程在tmpfs或pagecache流程产生缺页引发的内存申请,有可能触发多个limit,多个limit之间交互关系情况详见表格。

    是否触及task_reliable_limit 是否触及reliable_pagecache_max_bytes或者shmem_reliable_bytes_limit 内存申请处理策略
    优先回收pagecache以满足申请,否则Fallback或者OOM
    优先回收pagecache以满足申请,否则Fallback或者OOM
    先高可靠内存,失败Fallback或者OOM
    先高可靠内存,失败Fallback或者OOM

    关键进程会遵循task_reliable_limit的限制,如果task_reliable_limit高于tmpfs或pagecachelimit时,由关键进程产生的pagecache、tmpfs依旧会使用高可靠内存,由此会产生pagecache、tmpfs使用高可靠内存数量高于对应Limit的情况。

    当触发task_reliable_limit,如果高可靠filecache低于4M,不会进行同步回收。如果pagecache产生时,高可靠filecache低于4M,那么会fallback到低可靠内存完成申请,如果高于4M那么会优先回收pagecache满足此次申请。但接近4M时,会触发更频繁的cache直接回收,由于cache直接回收锁开销大,会导致高cpu占用率,此时文件读写性能接近裸盘性能。

  6. 即使系统存在足够申请的高可靠内存,在如下场景下也存在fallback到低可靠内存区域内存申请的场景。

    • 如果进行无法迁移到其他节点进行内存申请,那么会fallback当前节点的低可靠内存,常用场景举例如下:
    • 如果内存申请带上了__GFP_THISNODE(如透明大页申请),代表只能从当前节点申请内存,如果此节点高可靠内存不满足申请情况,那么会尝试从本内存节点的低可靠内存区域进行内存申请。
    • 进程通过taskset、numactl等命令运行在某个包含普通内存节点。
    • 进程在系统内存原生的调度机制下调度到了某个包含普通内存节点。
    • 高可靠内存申请触发高可靠内存使用水线也会导致fallback到低可靠。
  7. 内存分级fallback关闭时,高可靠内存将不能向低可靠内存扩展,有可能导致用户态应用对内存用量的判断与本特性不兼容,比如通过MemFree判断可用内存量。

  8. 内存分级fallback开启时,对原生fallback有影响,主要区别在于内存管理区zone与NUMA节点的选择上,列举如下:

  • 普通用户进程fallback流程将会是: 本节点低可靠内存->远端节点低可靠内存。
  • 关键用户进程fallback流程将会是:本节点高可靠内存-> 远端节点高可靠内存。如果还未申请到内存且开启了memory reliable的fallback功能,将会额外重试: 本节点低可靠内存-> 远端节点低可靠内存。

场景限制

  1. 默认页面大小(PAGE_SIZE)只支持4K页面大小。
  2. Numa Node0上低4G内存必须要为高可靠且高可靠内存大小与低可靠内存大小满足内核使用,否则可能导致系统无法启动。其他node的高可靠内存空间大小无要求,但需注意:
    • 某个node上没有高可靠内存或者高可靠内存不足,可能导致per-node管理结构位于其他node的高可靠内存上(因为其为内核数据结构需要在高可靠区域),由此会产生内核warning,如vmemmap会产生vmemmap_verify相关告警且存在性能影响。
  3. 本特性部分统计值(比如tmpfs高可靠总量)使用percpu技术进行统计,会有额外开销,计算总和时考虑到减少性能影响。因此存在一定的误差,误差10%内属于正常。
  4. 大页限制:
    • 启动阶段静态大页为低可靠内存,运行时申请的静态大页默认为低可靠内存,如果内存申请发生在关键进程上下文,那么申请到的大页为高可靠内存。
    • 透明大页THP场景下,通过扫描进行合并大页(2M页为例)时如果待合并的512个4k页面中某一个为高可靠页面,那么新申请的2M大页会使用高可靠内存,透明大页会导致使用更多高可靠内存。
    • 2M大页预留申请遵循原生的fallback流程,如果当前node缺少低可靠内存,那么会fallback高可靠区间申请高可靠完成内存申请。
    • 启动阶段进行2M大页预留,如果没有指定内存节点,那么会负载均衡到每个内存节点进行大页的预留。如果某个内存节点缺少低可靠内存,那么会遵循原生流程使用高可靠。
  5. 当前仅仅支持正常系统启动场景。部分异常场景内核启动可能与内存分级功能不兼容,如kdump启动阶段(当前kdump已支持自动关闭,其他场景需要上层业务关闭。)
  6. SWAP换入换出、内存offline、KSM、cma、giganic page流程下新申请的页面类型没有基于分级内存进行考量,可能出现未定义情况(未定义情况包括高可靠用量统计不准、申请到的内存可靠性等级与预期不符等)。

性能影响

  • 物理页申请因分级管理的引入而增加了判断逻辑,会有一些性能影响,具体影响程度与系统状况、申请内存类型、各节点高低可靠内存余量有关。
  • 本特性引入高可靠内存相关用量统计值,会对系统性能产生影响。
  • 触发task_reliable_limit时,会对位于高可靠区域的cache同步回收,会增加CPU占用率。pagecache申请(文件读写操作,比如dd)触发task_reliable_limit的场景下,如果当前高可靠内存可用量(ReliableFileCache视为可用内存)接近4M时,会触发更频繁的cache直接回收,由于cache直接回收锁开销大,会导致高cpu占用率。此时文件读写性能接近裸盘性能。

使用方法

OS支持内存分级管理

概述

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

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

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

约束限制

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

    1. /proc//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 0 Node 1 Node 2 Node 3
Free Mem (MB) 109290 81218 107365 112053

总耗时 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);
      
    2. **内存热插拔:**如果内核本身使能内存热插拔操作(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
      
    3. **动态关闭某项分级管理功能:**使用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
      

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

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

    4. **查看高可靠内存部分统计信息:**可以通过原生/proc/meminfo来查看,其中:

      • ReliableTotal:内核管理可靠内存总大小。
      • ReliableUsed:系统使用可靠内存总大小,包含系统阶段reserved使用。
      • ReliableBuddyMem:伙伴系统剩余可靠总内存大小。
      • ReliableTaskUsed:表示当前关键用户进程,systemd使用的高可靠内存大小,包括匿名页与文件页。
      • ReliableShmem:表示共享内存高可靠用量,包括共享内存、tmpfs、rootfs使用高可靠内存总大小。
      • ReliableFileCache:表示读写缓存高可靠内存用量。
    5. **未分配内存覆盖写:**该功能需要打开配置项。

      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
      
    6. **查看更改当前进程高低可靠属性:**可以通过/proc//reliable来查看该进程是否是高可靠进程;运行写入,该标识会继承,如果子进程不需要,则手动修改子进程属性;systemd和内核线程不支持该属性的读写;可以写0或 者1,默认为0,代表低可靠进程(权限为0644)。

      # 更改pid=1024的进程为高可靠进程,从更改之后开始进程缺页申请的内存是从高可靠内存区域申请,申请不到有可能fallback到低可靠 
       echo 1 > /proc/1024/reliable
      
    7. **设置用户态高可靠进程申请上限:**通过/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_enable 1
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_bytes unsigned 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

使用方法

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

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

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

评论 (1)

zhengzengkai 创建了任务 3年前
openeuler-ci-bot 添加了
 
sig/Kernel
标签
3年前
zhengzengkai 修改了描述 3年前
zhengzengkai 修改了描述 3年前
zhengzengkai 修改了描述 3年前
zhengzengkai 修改了描述 3年前

登录 后才可以发表评论

状态
负责人
项目
Pull Requests
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
开始日期   -   截止日期
-
置顶选项
优先级
预计工期 (小时)
参与者(2)
5329419 openeuler ci bot 1632792936 zhengzengkai-zhengzengkai
1
https://gitee.com/src-openeuler/kernel.git
git@gitee.com:src-openeuler/kernel.git
src-openeuler
kernel
kernel

搜索帮助