Linux内核模块开发之创建slab内存缓存(kmem_cache_*)

Linux内核模块开发之创建slab内存缓存(kmem_cache_*)

  • 一、创建专用的内存缓存编程接口
  • 二、实现步骤
  • 三、内存缓存的数据结构
  • 四、完整代码示例
    • 4.1、源代码
    • 4.2、编译和执行

一、创建专用的内存缓存编程接口

  1. 创建内存缓存 kmem_cache_create。
  2. 指定内存缓存分配 kmem_cache_alloc。
  3. 释放对象 kmem_cache_free。
  4. 销毁内存缓存 keme_cache_destroy。

函数原型:

void *kmem_cache_alloc(struct kmem_cache *cachep, int flags);
void kmem_cache_free(struct kmem_cache *cachep, void *objp);

struct kmem_cache *
kmem_cache_create(const char *name, size_t size, size_t offset,
	unsigned long flags, void (*ctor)(void *));
void kmem_cache_destroy(struct kmem_cache *);

二、实现步骤

  1. 定义初始化模块和退出模块函数。
  2. 定义一个kmem_cache全局变量。
  3. 在初始化模块函数调用kmem_cache_create函数,指定模块名称。
  4. 如果创建成功,可以调用kmem_cache_size获取缓存大小。
  5. 退出模块调用keme_cache_destroy删除函数指针。
  6. 模块初始化操作和退出函数调用module_init()和module_exit()。
  7. 其他的声明信息,比如许可协议、作者、模块功能描述等等。

三、内存缓存的数据结构

(include/linux/slab_def.h)

struct kmem_cache {
	struct array_cache __percpu *cpu_cache;

/* 1) Cache tunables. Protected by slab_mutex */
	unsigned int batchcount;
	unsigned int limit;
	unsigned int shared;

	unsigned int size;
	struct reciprocal_value reciprocal_buffer_size;
/* 2) touched by every alloc & free from the backend */

	slab_flags_t flags;		/* constant flags */
	unsigned int num;		/* # of objs per slab */

/* 3) cache_grow/shrink */
	/* order of pgs per slab (2^n) */
	unsigned int gfporder;

	/* force GFP flags, e.g. GFP_DMA */
	gfp_t allocflags;

	size_t colour;			/* cache colouring range */
	unsigned int colour_off;	/* colour offset */
	struct kmem_cache *freelist_cache;
	unsigned int freelist_size;

	/* constructor func */
	void (*ctor)(void *obj);

/* 4) cache creation/removal */
	const char *name;
	struct list_head list;
	int refcount;
	int object_size;
	int align;

/* 5) statistics */
#ifdef CONFIG_DEBUG_SLAB
	unsigned long num_active;
	unsigned long num_allocations;
	unsigned long high_mark;
	unsigned long grown;
	unsigned long reaped;
	unsigned long errors;
	unsigned long max_freeable;
	unsigned long node_allocs;
	unsigned long node_frees;
	unsigned long node_overflow;
	atomic_t allochit;
	atomic_t allocmiss;
	atomic_t freehit;
	atomic_t freemiss;

	/*
	 * If debugging is enabled, then the allocator can add additional
	 * fields and/or padding to every object. 'size' contains the total
	 * object size including these internal fields, while 'obj_offset'
	 * and 'object_size' contain the offset to the user object and its
	 * size.
	 */
	int obj_offset;
#endif /* CONFIG_DEBUG_SLAB */

#ifdef CONFIG_MEMCG
	struct memcg_cache_params memcg_params;
#endif
#ifdef CONFIG_KASAN
	struct kasan_cache kasan_info;
#endif

#ifdef CONFIG_SLAB_FREELIST_RANDOM
	unsigned int *random_seq;
#endif

	unsigned int useroffset;	/* Usercopy region offset */
	unsigned int usersize;		/* Usercopy region size */

	struct kmem_cache_node *node[MAX_NUMNODES];
};

内存缓存的数据结构如下图所示:
Linux内核模块开发之创建slab内存缓存(kmem_cache_*)_第1张图片

四、完整代码示例

4.1、源代码

kmemd.c

/* 头文件和全局变量地声明*/
#include 
#include 
#include 
#include 


static int __init kmem_cache_create_InitFunc(void);
static void __exit kmem_cache_create_ExitFunc(void);

struct kmem_cache *pmycache = NULL;

// 模块初始化函数
int __init kmem_cache_create_InitFunc(void)
{
    pmycache = kmem_cache_create("FlyCache",64,0, SLAB_HWCACHE_ALIGN, NULL);
    if(NULL==pmycache)
    {
        printk("执行:kmem_cache_create(...)函数失败,请重新检查?\n");
    }        
    else
    {
        printk("创建slab缓存成功!\n");
        printk("FlyCache Cache大小为: %d\n", kmem_cache_size(pmycache));
    }
    return 0;
}

// 模块退出函数
void __exit kmem_cache_create_ExitFunc(void)
{
    if(pmycache)
    {
        kmem_cache_destroy(pmycache);
        printk("执行:kmem_cache_destroy()函数释放slab缓存成功!\n");
    }
    printk("内核模块退出成功!\n");
}

/* 模块初始化操作和退出函数调用 */
module_init(kmem_cache_create_InitFunc);
module_exit(kmem_cache_create_ExitFunc);

MODULE_LICENSE("GPL"); /* 描述模块代码接受的软件许可协议 */
MODULE_AUTHOR("Lion Long"); /* 描述模块的作者信息:包括作者姓名及邮箱等等 */
MODULE_DESCRIPTION(" kernel module : kmem_cache_create/kmem_cache_destroy"); /* 简要描述此模块用途及功能介绍*/

Makefile

obj-m:=kmemd.o	

CURRENT_PAHT:=$(shell pwd) 
LINUX_KERNEL:=$(shell uname -r)   

LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
all:

	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PAHT) modules

clean:

	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PAHT) cleals

4.2、编译和执行

(1)make。

$ make
make -C /usr/src/linux-headers-4.15.0-142-generic    M=/home/fly/workspace/linux_kernel  modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-142-generic'
  CC [M]  /home/fly/workspace/linux_kernel/kmemd.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/fly/workspace/linux_kernel/kmemd.mod.o
  LD [M]  /home/fly/workspace/linux_kernel/kmemd.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-142-generic'

(2)插入模块。

insmod kmemd.ko

(3)查看模块。

$ sudo dmes -c
[101921.947832] 创建slab缓存成功!
[101921.947833] FlyCache Cache大小为: 64

Linux内核模块开发之创建slab内存缓存(kmem_cache_*)_第2张图片

你可能感兴趣的:(Linux内核分析,linux,缓存,运维,伙伴系统,linux内核)