文章目录
获取系统的物理内存信息
Linux 内核对每个物理页面都采用struct page数据结构来描述,内核为每一个物理页面都分配了这样一个struct page数据结构,并且存储到一个全局的数组mem_map[]中。它们之间一一映射,数组的第i个元素指向页帧号为i的物理页面的struct page数据结构。 基于此,我们可以编写一个内核模块,通过遍历这个mem_map[]`数组来统计当前系统有多少个空闲页面、保留页面、swapcache页面、slab页面、脏页面、活跃页面、正在回写的页面等。
代码
mem_info.c
c
// mem_info.c
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/mm.h>
// 指定license版本
MODULE_LICENSE("GPL");
// 作者信息
MODULE_AUTHOR("Marvin");
// 模块描述
MODULE_DESCRIPTION("show memory info");
// 提供别名
MODULE_ALIAS("meminfo");
#define PRT(a, b) \
pr_info("%-15s=%10d %10ld %8ld\n", a, b, (PAGE_SIZE * b) / 1024, \
(PAGE_SIZE * b) / 1024 / 1024)
//设置初始化入口函数
static int __init mem_info_init(void)
{
struct page *p;
int i;
unsigned long pfn, valid = 0;
int free = 0, locked = 0, reserved = 0, swapcache = 0, referenced = 0,
slab = 0, private = 0, uptodate = 0, dirty = 0, active = 0,
writeback = 0, mappedtodisk = 0;
unsigned long num_physpages;
num_physpages = get_num_physpages();
for (i = 0; i< num_physpages; i++) {
pfn = i + PREEMPT_OFFSET;
// skip empty hole
if (!pfn_valid(pfn)) {
continue;
}
valid++;
p = pfn_to_page(pfn);
// page_count == 0 is a free page
if (!page_count(p)) {
free ++;
continue;
}
if (PageLocked(p)) {
locked++;
}
if (PageReserved(p)) {
reserved++;
}
if (PageSwapCache(p)) {
swapcache++;
}
if (PageReferenced(p)) {
referenced++;
}
if (PageSlab(p)) {
slab++;
}
if (PagePrivate(p)) {
private++;
}
if (PageUptodate(p)) {
uptodate++;
}
if(PageDirty(p)) {
dirty++;
}
if (PageActive(p)) {
active++;
}
if (PageWriteback(p)) {
writeback++;
}
if (PageMappedToDisk(p)) {
mappedtodisk++;
}
}
pr_info("\nExamining %ld pages(num_phys_pages) = %ls MB\n", num_physpages,
num_physpages * PAGE_SIZE / 1024 / 1024);
pr_info("Pages with valid PFN's = %ld, = %ld MB\n", valid,
valid * PAGE_SIZE / 1024 / 1024);
pr_info("\n Pages KB MB\n\n");
PRT("free", free);
PRT("locked", locked);
PRT("reserved", reserved);
PRT("swapcache", swapcache);
PRT("referenced", referenced);
PRT("slab", slab);
PRT("private", private);
PRT("uptodate", uptodate);
PRT("dirty", dirty);
PRT("active", active);
PRT("writeback", writeback);
PRT("mappedtodisk", mappedtodisk);
return 0;
}
//设置出口函数
static void __exit mem_info_exit(void)
{
printk(KERN_DEBUG "goodbye!!!\n");
}
//将上述定义的init()和exit()函数定义为模块入口/出口函数
module_init(mem_info_init);
module_exit(mem_info_exit);
Makefile
makefile
ifneq ($(KERNELRELEASE),)
MODULE_NAME = showmeminfo
$(MODULE_NAME)-objs := mem_info.o
obj-m := $(MODULE_NAME).o
else
KERNEL_DIR = /lib/modules/`uname -r`/build
MODULEDIR := $(shell pwd)
.PHONY: modules
default: modules
modules:
make -C $(KERNEL_DIR) M=$(MODULEDIR) modules
clean distclean:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
rm -f *.o *.mod.c .*.*.cmd *.ko
rm -rf .tmp_versions
endif
测试
bash
$ sudo insmod showmeminfo.ko
dmesg 输出
[ 1943.870130]
Examining 1043558 pages(num_phys_pages) = (efault) MB
[ 1943.870135] Pages with valid PFN's = 524287, = 2047 MB
[ 1943.870136]
Pages KB MB
[ 1943.870136] free = 43554 174216 170
[ 1943.870138] locked = 0 0 0
[ 1943.870139] reserved = 29070 116280 113
[ 1943.870140] swapcache = 0 0 0
[ 1943.870140] referenced = 148195 592780 578
[ 1943.870141] slab = 85462 341848 333
[ 1943.870142] private = 179942 719768 702
[ 1943.870142] uptodate = 346732 1386928 1354
[ 1943.870143] dirty = 14310 57240 55
[ 1943.870144] active = 25 100 0
[ 1943.870145] writeback = 0 0 0
[ 1943.870145] mappedtodisk = 88168 352672 344
分配内存
在Linux内核中,可以通过alloc_page分配一个物理页面,然后输出该物理页面的物理地址,并输出该物理页面在内核空间的虚拟地址。
可以通过__get_free_pages来分配物理页面,也可以通过kmalloc直接分配物理内存。
代码
mem_alloc.c
c
// mem_alloc.c
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
// 指定license版本
MODULE_LICENSE("GPL");
// 作者信息
MODULE_AUTHOR("Marvin");
// 模块描述
MODULE_DESCRIPTION("alloc memmory");
// 提供别名
MODULE_ALIAS("memalloc");
#define PRT(a, b) \
pr_info("%-15s=%10d %10ld %8ld\n", a, b, (PAGE_SIZE * b) / 1024, \
(PAGE_SIZE * b) / 1024 / 1024)
#define MB (1024*1024)
static int mem = 64;
//设置初始化入口函数
static int __init mem_alloc_init(void)
{
static char *kbuf, *vm_buff;
static unsigned long order;
int size;
for (size = PAGE_SIZE, order = 0; order < MAX_ORDER; order++, size *= 2) {
pr_info(" order=%2ld, pages=%5ld, size=%8d ", order, size / PAGE_SIZE, size);
kbuf = (char *)__get_free_pages(GFP_ATOMIC, order);
if (!kbuf) {
pr_err("__get_free_pages failed!");
break;
}
pr_info("__get_free_pages OK");
free_pages((unsigned long)kbuf, order);
}
for (size = PAGE_SIZE, order = 0; order < MAX_ORDER; order++, size *= 2) {
pr_info(" order=%2ld, pages=%5ld, size=%8d ", order, size / PAGE_SIZE, size);
kbuf = kmalloc((size_t) size, GFP_ATOMIC);
if (!kbuf) {
pr_err("kmalloc failed!");
break;
}
pr_info("kmalloc OK");
kfree(kbuf);
}
for (size = 4 * MB; size <= mem * MB; size += 4 * MB) {
pr_info(" pages=%6lu, size=%8lu ", size / PAGE_SIZE, size / MB);
vm_buff = vmalloc(size);
if (!vm_buff) {
pr_err("... vmalloc failed\n");
break;
}
pr_info("... vmalloc OK\n");
vfree(vm_buff);
}
return 0;
}
//设置出口函数
static void __exit mem_alloc_exit(void)
{
printk(KERN_DEBUG "goodbye!!!\n");
}
//将上述定义的init()和exit()函数定义为模块入口/出口函数
module_init(mem_alloc_init);
module_exit(mem_alloc_exit);
Makefile
Makefile
ifneq ($(KERNELRELEASE),)
MODULE_NAME = memalloc
$(MODULE_NAME)-objs := mem_alloc.o
obj-m := $(MODULE_NAME).o
else
KERNEL_DIR = /lib/modules/`uname -r`/build
MODULEDIR := $(shell pwd)
.PHONY: modules
default: modules
modules:
make -C $(KERNEL_DIR) M=$(MODULEDIR) modules
clean distclean:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
rm -f *.o *.mod.c .*.*.cmd *.ko
rm -rf .tmp_versions
endif
测试
bash
$ sudo insmod memalloc.ko
dmesg输出:
[ 5111.502527] order= 0, pages= 1, size= 4096
[ 5111.502531] __get_free_pages OK
[ 5111.502531] order= 1, pages= 2, size= 8192
[ 5111.502533] __get_free_pages OK
[ 5111.502534] order= 2, pages= 4, size= 16384
[ 5111.502537] __get_free_pages OK
[ 5111.502537] order= 3, pages= 8, size= 32768
[ 5111.502540] __get_free_pages OK
[ 5111.502540] order= 4, pages= 16, size= 65536
[ 5111.502544] __get_free_pages OK
[ 5111.502545] order= 5, pages= 32, size= 131072
[ 5111.502570] __get_free_pages OK
[ 5111.502571] order= 6, pages= 64, size= 262144
[ 5111.502583] __get_free_pages OK
[ 5111.502584] order= 7, pages= 128, size= 524288
[ 5111.502606] __get_free_pages OK
[ 5111.502607] order= 8, pages= 256, size= 1048576
[ 5111.502651] __get_free_pages OK
[ 5111.502652] order= 9, pages= 512, size= 2097152
[ 5111.502773] __get_free_pages OK
[ 5111.502782] order=10, pages= 1024, size= 4194304
[ 5111.502998] __get_free_pages OK
[ 5111.503002] order= 0, pages= 1, size= 4096
[ 5111.503004] kmalloc OK
[ 5111.503005] order= 1, pages= 2, size= 8192
[ 5111.503006] kmalloc OK
[ 5111.503006] order= 2, pages= 4, size= 16384
[ 5111.503008] kmalloc OK
[ 5111.503009] order= 3, pages= 8, size= 32768
[ 5111.503040] kmalloc OK
[ 5111.503041] order= 4, pages= 16, size= 65536
[ 5111.503048] kmalloc OK
[ 5111.503049] order= 5, pages= 32, size= 131072
[ 5111.503056] kmalloc OK
[ 5111.503057] order= 6, pages= 64, size= 262144
[ 5111.503078] kmalloc OK
[ 5111.503079] order= 7, pages= 128, size= 524288
[ 5111.503137] kmalloc OK
[ 5111.503138] order= 8, pages= 256, size= 1048576
[ 5111.503221] kmalloc OK
[ 5111.503225] order= 9, pages= 512, size= 2097152
[ 5111.503363] kmalloc OK
[ 5111.503365] order=10, pages= 1024, size= 4194304
[ 5111.503585] kmalloc OK
[ 5111.503588] pages= 1024, size= 4
[ 5111.503977] ... vmalloc OK
[ 5111.504094] pages= 2048, size= 8
[ 5111.504548] ... vmalloc OK
[ 5111.504946] pages= 3072, size= 12
[ 5111.505723] ... vmalloc OK
[ 5111.505995] pages= 4096, size= 16
[ 5111.506893] ... vmalloc OK
[ 5111.507246] pages= 5120, size= 20
[ 5111.508254] ... vmalloc OK
[ 5111.508652] pages= 6144, size= 24
[ 5111.509853] ... vmalloc OK
[ 5111.510383] pages= 7168, size= 28
[ 5111.511969] ... vmalloc OK
[ 5111.512642] pages= 8192, size= 32
[ 5111.514359] ... vmalloc OK
[ 5111.514982] pages= 9216, size= 36
[ 5111.517869] ... vmalloc OK
[ 5111.518718] pages= 10240, size= 40
[ 5111.521890] ... vmalloc OK
[ 5111.523108] pages= 11264, size= 44
[ 5111.528199] ... vmalloc OK
[ 5111.529169] pages= 12288, size= 48
[ 5111.533407] ... vmalloc OK
[ 5111.534582] pages= 13312, size= 52
[ 5111.539651] ... vmalloc OK
[ 5111.540847] pages= 14336, size= 56
[ 5111.544862] ... vmalloc OK
[ 5111.545983] pages= 15360, size= 60
[ 5111.551694] ... vmalloc OK
[ 5111.552957] pages= 16384, size= 64
[ 5111.558645] ... vmalloc OK
[ 5119.521126] goodbye!!!
slab 内存分配
mem_slab.c
c
// mem_slab.c
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
// 指定license版本
MODULE_LICENSE("GPL");
// 作者信息
MODULE_AUTHOR("Marvin");
// 模块描述
MODULE_DESCRIPTION("memmory slab");
// 提供别名
MODULE_ALIAS("memslab");
#define PRT(a, b) \
pr_info("%-15s=%10d %10ld %8ld\n", a, b, (PAGE_SIZE * b) / 1024, \
(PAGE_SIZE * b) / 1024 / 1024)
static char *kbuf;
static int size = 20;
static int align = 8;
static struct kmem_cache *my_cache;
//设置初始化入口函数
static int __init mem_slab_init(void)
{
// 创建一个kmem_cache
my_cache = kmem_cache_create("mycache", size, align, 0, NULL);
if (!my_cache) {
pr_err("kmem_cache_create failed!");
return -ENOMEM;
}
pr_info("kmem_cache_create OK");
// 分配一个缓存对象
kbuf = kmem_cache_alloc(my_cache, GFP_ATOMIC);
if (!kbuf) {
pr_err("create a cache object failed!");
(void)kmem_cache_destroy(my_cache);
return -1;
}
pr_info("create a cache object OK");
return 0;
}
//设置出口函数
static void __exit mem_slab_exit(void)
{
kmem_cache_free(my_cache, kbuf);
pr_info("destroyed memory cache object");
(void)kmem_cache_destroy(my_cache);
printk(KERN_DEBUG "goodbye!!!\n");
}
//将上述定义的init()和exit()函数定义为模块入口/出口函数
module_init(mem_slab_init);
module_exit(mem_slab_exit);
// sudo insmod memslab.ko
Makefile
makefile
ifneq ($(KERNELRELEASE),)
MODULE_NAME = memslab
$(MODULE_NAME)-objs := mem_slab.o
obj-m := $(MODULE_NAME).o
else
KERNEL_DIR = /lib/modules/`uname -r`/build
MODULEDIR := $(shell pwd)
.PHONY: modules
default: modules
modules:
make -C $(KERNEL_DIR) M=$(MODULEDIR) modules
clean distclean:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
rm -f *.o *.mod.c .*.*.cmd *.ko
rm -rf .tmp_versions
endif
测试
bash
$ sudo insmod memslab.ko
$ sudo rmmod memslab.ko
dmesg 信息
[ 5896.854844] kmem_cache_create OK
[ 5896.854851] create a cache object OK
[ 5904.684947] destroyed memory cache object
[ 5904.684950] goodbye!!!