分析linux内核中的slub内存管理算法
1. 分析的linux内核源码版本为4.18.0
2. 与slub相关的内核配置项为CONFIG_SLUB
3. 一切都从一个结构体数组kmalloc_caches开始,它的原型如下:
struct kmem_cache *kmalloc_caches[KMALLOC_SHIFT_HIGH + 1] __ro_after_init;
3.1 这个数组定义在mm/slab_common.c中
3.2 KMALLOC_SHIFT_HIGH是如何定义的呢?
#define KMALLOC_SHIFT_HIGH (PAGE_SHIFT + 1)
#define PAGE_SHIFT 12 (各个架构下的定义都有些差异,如果是arm64,那么是通过CONFIG_ARM64_PAGE_SHIFT来指定的,这个配置项在arch/arm64/Kconfig文件中定义,默认为12,也就是默认页面大小为4KiB,笔者以arm64为例)
那么KMALLOC_SHIFT_HIGH=PAGE_SHIFT + 1 = 12 + 1 = 13,KMALLOC_SHIFT_HIGH+1=13+ 1= 14说明kmalloc_caches数组中有14个元素,每个元素是kmem_cache这个结构体
3.3 分析一下sturct kmem_cache这个结构体
/* * Slab cache management. */ struct kmem_cache { struct kmem_cache_cpu __percpu *cpu_slab; /* Used for retriving partial slabs etc */ slab_flags_t flags; unsigned long min_partial; unsigned int size; /* The size of an object including meta data */ unsigned int object_size;/* The size of an object without meta data */ unsigned int offset; /* Free pointer offset. */ #ifdef CONFIG_SLUB_CPU_PARTIAL /* Number of per cpu partial objects to keep around */ unsigned int cpu_partial; #endif struct kmem_cache_order_objects oo; /* Allocation and freeing of slabs */ struct kmem_cache_order_objects max; struct kmem_cache_order_objects min; gfp_t allocflags; /* gfp flags to use on each alloc */ int refcount; /* Refcount for slab cache destroy */ void (*ctor)(void *); unsigned int inuse; /* Offset to metadata */ unsigned int align; /* Alignment */ unsigned int red_left_pad; /* Left redzone padding size */ const char *name; /* Name (only for display!) */ struct list_head list; /* List of slab caches */ #ifdef CONFIG_SYSFS struct kobject kobj; /* For sysfs */ struct work_struct kobj_remove_work; #endif #ifdef CONFIG_MEMCG struct memcg_cache_params memcg_params; /* for propagation, maximum size of a stored attr */ unsigned int max_attr_size; #ifdef CONFIG_SYSFS struct kset *memcg_kset; #endif #endif #ifdef CONFIG_SLAB_FREELIST_HARDENED unsigned long random; #endif #ifdef CONFIG_NUMA /* * Defragmentation by allocating from a remote node. */ unsigned int remote_node_defrag_ratio; #endif #ifdef CONFIG_SLAB_FREELIST_RANDOM unsigned int *random_seq; #endif #ifdef CONFIG_KASAN struct kasan_cache kasan_info; #endif unsigned int useroffset; /* Usercopy region offset */ unsigned int usersize; /* Usercopy region size */ struct kmem_cache_node *node[MAX_NUMNODES]; };
3.4 struct kmem_cache中有哪些域是需要关注到的呢?
3.4.1 node
struct kmem_cache_node *node[MAX_NUMNODES];
这里面MAX_NUMNODES定义如下:
#define MAX_NUMNODES (1 << NODES_SHIFT)
那么NODES_SHIFT又是如何定义的呢?
#ifdef CONFIG_NODES_SHIFT #define NODES_SHIFT CONFIG_NODES_SHIFT #else #define NODES_SHIFT 0 #endif
如果定义了CONFIG_NODES_SHIFT,那么NODES_SHIFT就等于CONFIG_NODES_SHIFT的值;
如果未定义CONFIG_NODES_SHIFT,那么NODES_SHIFT就等于0;
假设未定义CONFIG_NODES_SHIFT,那么MAX_NUMNODES就等于1,也就是只有一个kmem_cache_node节点.
3.4.2 cpu_slab
struct kmem_cache_cpu __percpu *cpu_slab;
表示每个cpu都具有一个这个的结构来描述当前slab的情况
__percpu是什么?
# define __percpu __attribute__((noderef, address_space(3)))
__percpu表示一种特性,是用来修饰变量的.noderef指定这个变量必须是有效的,address_space(3)则指定变量所在的地址空间为3,也就是cpu空间.作用就是保证每个cpu都有这个变量的副本
3.4.3 size
unsigned int size; /* The size of an object including meta data */
表示包含元数据的一个object的大小
3.4.4 object_size
unsigned int object_size;/* The size of an object without meta data */
表示不包含元数据的一个object的大小
3.4.5 offset
unsigned int offset; /* Free pointer offset. */
表示空闲指针的偏移量
3.5 __ro_after_init是什么东西?
#define __ro_after_init __attribute__((__section__(".data..ro_after_init")))
这是一个宏,定义在include/linux/cache.h中,被用来标记初始化之后只读的内容
这里面涉及到一个段.data..ro_after_init,可以在include/asm-generic/vmlinux.lds.h中找到
1 #ifndef RO_AFTER_INIT_DATA 2 #define RO_AFTER_INIT_DATA \ 3 __start_ro_after_init = .; \ 4 *(.data..ro_after_init) \ 5 __end_ro_after_init = .; 6 #endif
4. 如何填充kmalloc_caches数组的呢?
start_kernel()-> (init/main.c)
mm_init()-> (init/main.c)
kmem_cache_init()-> (mm/slub.c)
create_kmalloc_caches()-> (mm/slab_common.c)
new_kamalloc_cache()-> (mm/slab_common.c)
create_kmalloc_cache()-> (mm/slab_common.c)
从源码中可以得知kmalloc_caches数组由create_kmalloc_cache()填充每一个数组中的元素
5. slub中支持的object的大小范围是多少?
每个kmalloc_caches中的元素会使用结构体kmem_cache中的域size和objsize来指定slab中每个object的大小,object的大小从全局常量结构体数组kmalloc_info中获取
const struct kmalloc_info_struct kmalloc_info[] __initconst = { {NULL, 0}, {"kmalloc-96", 96}, {"kmalloc-192", 192}, {"kmalloc-8", 8}, {"kmalloc-16", 16}, {"kmalloc-32", 32}, {"kmalloc-64", 64}, {"kmalloc-128", 128}, {"kmalloc-256", 256}, {"kmalloc-512", 512}, {"kmalloc-1024", 1024}, {"kmalloc-2048", 2048}, {"kmalloc-4096", 4096}, {"kmalloc-8192", 8192}, {"kmalloc-16384", 16384}, {"kmalloc-32768", 32768}, {"kmalloc-65536", 65536}, {"kmalloc-131072", 131072}, {"kmalloc-262144", 262144}, {"kmalloc-524288", 524288}, {"kmalloc-1048576", 1048576}, {"kmalloc-2097152", 2097152}, {"kmalloc-4194304", 4194304}, {"kmalloc-8388608", 8388608}, {"kmalloc-16777216", 16777216}, {"kmalloc-33554432", 33554432}, {"kmalloc-67108864", 67108864} };
从数组中的最后一个元素可以获知支持的最大object的大小为2^26=64MiB,但是从以下代码分析:
void __init create_kmalloc_caches(slab_flags_t flags) { int i; for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_HIGH; i++) { if (!kmalloc_caches[i]) new_kmalloc_cache(i, flags);
可得:
kmalloc_caches数组中仅下标为KMALLOC_SHIFT_LOW到KMALLOC_SHIFT_HIGH的元素才被初始化,
也就是从3->13支持的最小object大小为2^3=8字节,最大object大小为2^13=8KiB,说明kmalloc_caches数组的前三个元素并没有被初始化,仅初始化数组的后面11个元素.
从以上分析可得slub支持的最大object的大小为页面大小的两倍(PAGE_SIZE*2),页面大小为4KiB,那么最大object的大小为4KiB * 2 = 8KiB
相关文章
- 利用Volatility对Linux内存取证分析-常用命令翻译
- linux驱动开发--内核空间中内存的申请与释放
- [Linux]linux如何把文件切成多块
- Linux创建内存磁盘空间
- linux分享二:Linux如何修改字符集
- 如何在vim编辑时输入linux命令而不退出vim
- 信号概述 硬件异常将产生信号 进程间通信概述 进程间通信 进程间通信功能 Linux 操作系统支持的主要进程间通信的通信机制 linux 进程间通信(IPC)由以下几个部分发展而来 数据传输 信号
- Linux LED字符设备驱动 地址映射 ioremap 函数 iounmap 函数 I/O 内存访问函数
- 【Linux 内核 内存管理】物理页释放 ( 物理页释放 __free_pages 函数 )
- 【Linux 内核 内存管理】物理分配页 ⑦ ( __alloc_pages_slowpath 慢速路径调用函数源码分析 | 判断页阶数 | 读取 mems_allowed | 分配标志位转换 )
- 【Linux 内核 内存管理】分区伙伴分配器 ⑦ ( z->watermark[WMARK_MIN] 最低水位计算 | min_free_kbytes 初始化 )
- 【Linux 内核 内存管理】memblock 分配器编程接口 ④ ( memblock_alloc 函数 | memblock_alloc_base 函数 )
- 【Linux 内核 内存管理】memblock 分配器 ④ ( memblock、memblock_type、memblock_region 结构体的关系 )
- 【Linux 内核 内存管理】引导内存分配器 bootmem ② ( bootmem_data 结构体源码分析 | bootmem_data 与内存节点 pglist_data 的关联 )
- 【Linux 内核 内存管理】物理内存组织结构 ④ ( 内存区域 zone 简介 | zone 结构体源码分析 | zone 结构体源码 )
- 【Linux 内核 内存管理】munmap 系统调用源码分析 ① ( munmap 系统调用函数执行流程 | munmap 函数源码 | vm_munmap 函数源码 )
- 【Linux 内核 内存管理】mmap 系统调用源码分析 ④ ( do_mmap 函数执行流程 | do_mmap 函数源码 )
- 【Linux 内核 内存管理】mmap 系统调用源码分析 ③ ( vm_mmap_pgoff 函数执行流程 | vm_mmap_pgoff 函数源码 )
- 【Linux 内核 内存管理】内存映射相关数据结构 ⑤ ( vm_area_struct 结构体成员分析 | vm_pgoff 成员 | vm_file 成员 | vm_private_data )
- 【Linux 内核 内存管理】内存映射相关数据结构 ④ ( vm_area_struct 结构体成员分析 | vm_ops 成员 | vm_operations_struct 结构体成员分析 )
- 【Linux 内核 内存管理】内存映射相关数据结构 ① ( vm_area_struct 结构体 | task_struct、mm_struct、vm_area_struct 3 个结构体之间的关系)
- 【Linux 内核 内存管理】内存映射原理 ② ( 内存映射概念 | 文件映射 | 匿名映射 | 内存映射原理 | 分配虚拟内存页 | 产生缺页异常 | 分配物理内存页 | 共享内存 | 进程内存 )
- 【Linux 内核 内存管理】内存映射原理 ① ( 物理地址空间 | 外围设备寄存器 | 外围设备寄存器的物理地址 映射到 虚拟地址空间 )
- 【Linux 内核 内存管理】内存管理架构 ② ( 用户空间内存管理 | malloc | ptmalloc | 内核空间内存管理 | sys_brk | sys_mmap | sys_munmap)
- 【Linux 内核 内存管理】Linux 内核内存布局 ④ ( ARM64 架构体系内存分布 | 内核启动源码 start_kernel | 内存初始化 mm_init | mem_init )
- 【Linux 内核 内存管理】Linux 内核内存布局 ③ ( Linux 内核 动态分配内存 系统接口函数 | 统计输出 vmalloc 分配的内存 )
- 【Linux 内核 内存管理】优化内存屏障 ② ( 内存屏障 | 编译器屏障 | 处理器内存屏障 | 内存映射 I/O 写屏障 )
- L77.linux命令每日一练 -- 第11章 Linux系统管理命令 -- vmstat和mpstat
- 释放linux 内存
- 74:应急响应-win&linux分析后门&勒索病毒&攻击 ==》暴力破解攻击成功的在4624的eventID里!PChunter可查看非系统的可疑启动项/服务/定时任务,还是很直观的!Linux下gscan也不错,EDR可参考。