Slab缓存分配没有预定义函数的结构堆栈
Slab cache allocate stack of structures without predefined functions
我正在编写一个使用 kmem_cache_create 和 kmem_cache_alloc 在内核 space 中创建堆栈的模块,但是它不起作用。也许我对指针做了一些不好的事情,或者我不理解 slab 分配的整个概念。我已经把代码给同学和我的实验室负责人看了,遗憾的是没有人能帮助我。
这是我在 "stack"
上分配 5 个结构的代码
#include<linux/module.h>
#include<linux/slab.h>
#include<linux/string.h>
static struct example_struct {
unsigned int id;
char example_string[10];
struct example_struct *next;
} *example_struct_pointer;
static struct example_struct *top = NULL;
static struct kmem_cache *example_cachep;
static void example_constructor(void *argument)
{
static unsigned int id;
static char test_string[] = "Stack";
struct example_struct *example = (struct example_struct *)argument;
example->id = id;
strcpy(example->example_string,test_string);
example->next = top;
top = example;
id++;
}
void print_example_struct(struct example_struct *example)
{
pr_notice("Struct id: %u\n",example->id);
pr_notice("String field content: %s\n",example->example_string);
}
static int __init slabmod_init(void)
{
example_cachep = kmem_cache_create("example cache", sizeof(struct example_struct),0, SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, example_constructor);
if(IS_ERR(example_cachep)) {
pr_alert("Error creating cache: %ld\n",PTR_ERR(example_cachep));
return -ENOMEM;
}
for(i=1 ; i<6 ; i++)
{
printk(KERN_ALERT "i: %d\n",i);
example_struct_pointer = (struct example_struct *) kmem_cache_alloc(example_cachep,GFP_KERNEL);
if(IS_ERR(example_struct_pointer)) {
pr_alert("Error allocating from cache: %ld\n", PTR_ERR(example_struct_pointer));
kmem_cache_destroy(example_cachep);
return -ENOMEM;
}
}
return 0;
}
static void __exit slabmod_exit(void)
{
struct example_struct *tmp = example_struct_pointer;
if(example_cachep) {
while(example_struct_pointer != NULL) {
print_example_struct(example_struct_pointer);
tmp = example_struct_pointer;
example_struct_pointer = tmp->next;
kmem_cache_free(example_cachep,tmp);
}
kmem_cache_destroy(example_cachep);
}
}
module_init(slabmod_init);
module_exit(slabmod_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kostek888888");
MODULE_DESCRIPTION("A module demonstrating use of the slab allocator.");
MODULE_VERSION("1.0");
我也有这段代码的调试版本:
#include<linux/module.h>
#include<linux/slab.h>
#include<linux/string.h>
static struct example_struct {
unsigned int id;
char example_string[10];
struct example_struct *next;
} *example_struct_pointer;
static struct example_struct *top = NULL;
static struct kmem_cache *example_cachep;
static unsigned int i;
static void example_constructor(void *argument)
{
static unsigned int id;
static char test_string[] = "Stack";
struct example_struct *example = (struct example_struct *)argument;
example->id = id;
strcpy(example->example_string,test_string);
example->next = top;
top = example;
id++;
}
void print_example_struct(struct example_struct *example)
{
pr_notice("Struct id: %u\n",example->id);
//pr_notice("String field content: %s\n",example->example_string);
printk(KERN_ALERT "example_struct_pointer: %p\n",example_struct_pointer);
//printk(KERN_ALERT "top: %p\n",top);
printk(KERN_ALERT "i: %d\n",i);
i++;
}
static int __init slabmod_init(void)
{
example_cachep = kmem_cache_create("example cache", sizeof(struct example_struct),0, SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, example_constructor);
if(IS_ERR(example_cachep)) {
pr_alert("Error creating cache: %ld\n",PTR_ERR(example_cachep));
return -ENOMEM;
}
for(i=1 ; i<6 ; i++)
{
printk(KERN_ALERT "i: %d\n",i);
example_struct_pointer = (struct example_struct *) kmem_cache_alloc(example_cachep,GFP_KERNEL);
if(IS_ERR(example_struct_pointer)) {
pr_alert("Error allocating from cache: %ld\n", PTR_ERR(example_struct_pointer));
kmem_cache_destroy(example_cachep);
return -ENOMEM;
}
}
return 0;
}
static void __exit slabmod_exit(void)
{
struct example_struct *tmp = example_struct_pointer;
i = 1;
if(example_cachep) {
while(example_struct_pointer != NULL) {
print_example_struct(example_struct_pointer);
printk(KERN_ALERT "tmp: %p\n",tmp);
printk(KERN_ALERT "next: %p / %p\n\n",top->next,*(top->next));
tmp = example_struct_pointer;
example_struct_pointer = tmp->next;
kmem_cache_free(example_cachep,tmp);
}
printk(KERN_ALERT "tmp: %p\n",tmp);
printk(KERN_ALERT "next: %p\n\n",top->next);
printk(KERN_ALERT "example_struct_pointer: %p\n",example_struct_pointer);
kmem_cache_destroy(example_cachep);
}
}
module_init(slabmod_init);
module_exit(slabmod_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kostek888888");
MODULE_DESCRIPTION("A module demonstrating use of the slab allocator.");
MODULE_VERSION("1.0");
在输出中,当我只在 1-5 范围内执行 kmem_cache_alloc 5 次以及消息 "Slab cache still has objects" 时,我在 0-11 范围内得到 12 个元素。
Here is screenshot demonstrating words above
之后我收到呼叫跟踪消息,所以内存有问题。有时它会停止整个虚拟机。
我已经将 __exit 的 while 循环中的指针替换为 "top" 指针以检查它将显示什么 - 我有 122 个元素和相同的消息所以这可能是一个完整的 slab(但是可能因为消息而不完整?)。指针 "next" 在 DEC 中始终具有相同的值 122 - 结构是否为 122 字节宽? Sizeof 结构用 %d 给了我超过 1,000,000 的巨大价值。
原始代码,只分配一个结构并且工作起来很有魅力:
#include<linux/module.h>
#include<linux/slab.h>
#include<linux/string.h>
static struct example_struct {
unsigned int id;
char example_string[10];
} *example_struct_pointer;
static struct kmem_cache *example_cachep;
static void example_constructor(void *argument)
{
static unsigned int id;
static char test_string[] = "Test";
struct example_struct *example = (struct example_struct *)argument;
example->id = id;
strcpy(example->example_string,test_string);
id++;
}
void print_example_struct(struct example_struct *example)
{
pr_notice("Example struct id: %u\n",example->id);
pr_notice("Example string field content: %s\n",example->example_string);
}
static int __init slabmod_init(void)
{
example_cachep = kmem_cache_create("example cache", sizeof(struct example_struct),0, SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, example_constructor);
if(IS_ERR(example_cachep)) {
pr_alert("Error creating cache: %ld\n",PTR_ERR(example_cachep));
return -ENOMEM;
}
example_struct_pointer = (struct example_struct *) kmem_cache_alloc(example_cachep,GFP_KERNEL);
if(IS_ERR(example_struct_pointer)) {
pr_alert("Error allocating form cache: %ld\n", PTR_ERR(example_struct_pointer));
kmem_cache_destroy(example_cachep);
return -ENOMEM;
}
return 0;
}
static void __exit slabmod_exit(void)
{
if(example_cachep) {
if(example_struct_pointer) {
print_example_struct(example_struct_pointer);
kmem_cache_free(example_cachep,example_struct_pointer);
}
kmem_cache_destroy(example_cachep);
}
}
module_init(slabmod_init);
module_exit(slabmod_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Arkadiusz Chrobot <***>");
MODULE_DESCRIPTION("A module demonstrating useing of the slab allocator.");
MODULE_VERSION("1.0");
我已经查过像 Linux 设备驱动程序和类似的书 - 到处都是简单的功能,其中一个元素有示例。
我正在使用内核 3.16.0-4-686-pae 但在内核 4.9 中情况是一样的。
我将不胜感激:)
你错误地假设ctor()
(kmem_cache_create()
的最后一个参数)被调用每次你呼叫 kmem_cache_create()
.
实际上,调用此回调函数只是为了在分配器控制它之前预初始化 "garbage" 内存。
按此顺序:
kmem_cache_alloc()
, returns 指针 p.
kmem_cache_free(p)
(假设分配器保持对 p 的控制)。
kmem_cache_alloc()
, returns 指针 p.
回调函数在步骤 1 中仅 调用 ONCE。分配器假定在步骤 2(释放) p指向的对象已经处于初始化状态,所以第3步不需要初始化。
使用 kmem_cache
实现列表的正确方法是:
static void example_constructor(void *argument)
{
static unsigned int id;
static char test_string[] = "Stack";
struct example_struct *example = (struct example_struct *)argument;
/*
* This only garantee that at any time every element in the stack has unique id.
* New element may have same id as previously deleted one.
*/
example->id = id;
// All elements will have given string.
strcpy(example->example_string,test_string);
// Appending into the stack cannot be performed in the constructor.
// example->next = top;
// top = example;
id++;
}
/* Push allocated element into the stack and return that element. */
struct example_struct* push(void)
{
struct example_struct* example = kmem_cache_alloc(example_cachep,GFP_KERNEL);
if(example) {
// Add to the stack here
example->next = top;
top = example;
}
return example;
}
/* Pop element from the stack and free the element. */
void pop(void)
{
// Take the first element.
struct example_struct *example = top;
// Remove the element from the stack
top = example->next;
// In given example re-initialization actions before freeing the element are not needed.
kmem_cache_free(example_cachep, example);
}
static int __init slabmod_init(void)
{
...
// Test the stack.
for(i=1 ; i<6 ; i++) {
printk(KERN_ALERT "i: %d\n",i);
example_struct_pointer = push();
if(!example_struct_pointer)) {
...
}
}
return 0;
}
static void __exit slabmod_exit(void)
{
...
// Clean the stack
while(top) pop();
...
}
我正在编写一个使用 kmem_cache_create 和 kmem_cache_alloc 在内核 space 中创建堆栈的模块,但是它不起作用。也许我对指针做了一些不好的事情,或者我不理解 slab 分配的整个概念。我已经把代码给同学和我的实验室负责人看了,遗憾的是没有人能帮助我。
这是我在 "stack"
#include<linux/module.h>
#include<linux/slab.h>
#include<linux/string.h>
static struct example_struct {
unsigned int id;
char example_string[10];
struct example_struct *next;
} *example_struct_pointer;
static struct example_struct *top = NULL;
static struct kmem_cache *example_cachep;
static void example_constructor(void *argument)
{
static unsigned int id;
static char test_string[] = "Stack";
struct example_struct *example = (struct example_struct *)argument;
example->id = id;
strcpy(example->example_string,test_string);
example->next = top;
top = example;
id++;
}
void print_example_struct(struct example_struct *example)
{
pr_notice("Struct id: %u\n",example->id);
pr_notice("String field content: %s\n",example->example_string);
}
static int __init slabmod_init(void)
{
example_cachep = kmem_cache_create("example cache", sizeof(struct example_struct),0, SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, example_constructor);
if(IS_ERR(example_cachep)) {
pr_alert("Error creating cache: %ld\n",PTR_ERR(example_cachep));
return -ENOMEM;
}
for(i=1 ; i<6 ; i++)
{
printk(KERN_ALERT "i: %d\n",i);
example_struct_pointer = (struct example_struct *) kmem_cache_alloc(example_cachep,GFP_KERNEL);
if(IS_ERR(example_struct_pointer)) {
pr_alert("Error allocating from cache: %ld\n", PTR_ERR(example_struct_pointer));
kmem_cache_destroy(example_cachep);
return -ENOMEM;
}
}
return 0;
}
static void __exit slabmod_exit(void)
{
struct example_struct *tmp = example_struct_pointer;
if(example_cachep) {
while(example_struct_pointer != NULL) {
print_example_struct(example_struct_pointer);
tmp = example_struct_pointer;
example_struct_pointer = tmp->next;
kmem_cache_free(example_cachep,tmp);
}
kmem_cache_destroy(example_cachep);
}
}
module_init(slabmod_init);
module_exit(slabmod_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kostek888888");
MODULE_DESCRIPTION("A module demonstrating use of the slab allocator.");
MODULE_VERSION("1.0");
我也有这段代码的调试版本:
#include<linux/module.h>
#include<linux/slab.h>
#include<linux/string.h>
static struct example_struct {
unsigned int id;
char example_string[10];
struct example_struct *next;
} *example_struct_pointer;
static struct example_struct *top = NULL;
static struct kmem_cache *example_cachep;
static unsigned int i;
static void example_constructor(void *argument)
{
static unsigned int id;
static char test_string[] = "Stack";
struct example_struct *example = (struct example_struct *)argument;
example->id = id;
strcpy(example->example_string,test_string);
example->next = top;
top = example;
id++;
}
void print_example_struct(struct example_struct *example)
{
pr_notice("Struct id: %u\n",example->id);
//pr_notice("String field content: %s\n",example->example_string);
printk(KERN_ALERT "example_struct_pointer: %p\n",example_struct_pointer);
//printk(KERN_ALERT "top: %p\n",top);
printk(KERN_ALERT "i: %d\n",i);
i++;
}
static int __init slabmod_init(void)
{
example_cachep = kmem_cache_create("example cache", sizeof(struct example_struct),0, SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, example_constructor);
if(IS_ERR(example_cachep)) {
pr_alert("Error creating cache: %ld\n",PTR_ERR(example_cachep));
return -ENOMEM;
}
for(i=1 ; i<6 ; i++)
{
printk(KERN_ALERT "i: %d\n",i);
example_struct_pointer = (struct example_struct *) kmem_cache_alloc(example_cachep,GFP_KERNEL);
if(IS_ERR(example_struct_pointer)) {
pr_alert("Error allocating from cache: %ld\n", PTR_ERR(example_struct_pointer));
kmem_cache_destroy(example_cachep);
return -ENOMEM;
}
}
return 0;
}
static void __exit slabmod_exit(void)
{
struct example_struct *tmp = example_struct_pointer;
i = 1;
if(example_cachep) {
while(example_struct_pointer != NULL) {
print_example_struct(example_struct_pointer);
printk(KERN_ALERT "tmp: %p\n",tmp);
printk(KERN_ALERT "next: %p / %p\n\n",top->next,*(top->next));
tmp = example_struct_pointer;
example_struct_pointer = tmp->next;
kmem_cache_free(example_cachep,tmp);
}
printk(KERN_ALERT "tmp: %p\n",tmp);
printk(KERN_ALERT "next: %p\n\n",top->next);
printk(KERN_ALERT "example_struct_pointer: %p\n",example_struct_pointer);
kmem_cache_destroy(example_cachep);
}
}
module_init(slabmod_init);
module_exit(slabmod_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kostek888888");
MODULE_DESCRIPTION("A module demonstrating use of the slab allocator.");
MODULE_VERSION("1.0");
在输出中,当我只在 1-5 范围内执行 kmem_cache_alloc 5 次以及消息 "Slab cache still has objects" 时,我在 0-11 范围内得到 12 个元素。
Here is screenshot demonstrating words above
之后我收到呼叫跟踪消息,所以内存有问题。有时它会停止整个虚拟机。
我已经将 __exit 的 while 循环中的指针替换为 "top" 指针以检查它将显示什么 - 我有 122 个元素和相同的消息所以这可能是一个完整的 slab(但是可能因为消息而不完整?)。指针 "next" 在 DEC 中始终具有相同的值 122 - 结构是否为 122 字节宽? Sizeof 结构用 %d 给了我超过 1,000,000 的巨大价值。
原始代码,只分配一个结构并且工作起来很有魅力:
#include<linux/module.h>
#include<linux/slab.h>
#include<linux/string.h>
static struct example_struct {
unsigned int id;
char example_string[10];
} *example_struct_pointer;
static struct kmem_cache *example_cachep;
static void example_constructor(void *argument)
{
static unsigned int id;
static char test_string[] = "Test";
struct example_struct *example = (struct example_struct *)argument;
example->id = id;
strcpy(example->example_string,test_string);
id++;
}
void print_example_struct(struct example_struct *example)
{
pr_notice("Example struct id: %u\n",example->id);
pr_notice("Example string field content: %s\n",example->example_string);
}
static int __init slabmod_init(void)
{
example_cachep = kmem_cache_create("example cache", sizeof(struct example_struct),0, SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, example_constructor);
if(IS_ERR(example_cachep)) {
pr_alert("Error creating cache: %ld\n",PTR_ERR(example_cachep));
return -ENOMEM;
}
example_struct_pointer = (struct example_struct *) kmem_cache_alloc(example_cachep,GFP_KERNEL);
if(IS_ERR(example_struct_pointer)) {
pr_alert("Error allocating form cache: %ld\n", PTR_ERR(example_struct_pointer));
kmem_cache_destroy(example_cachep);
return -ENOMEM;
}
return 0;
}
static void __exit slabmod_exit(void)
{
if(example_cachep) {
if(example_struct_pointer) {
print_example_struct(example_struct_pointer);
kmem_cache_free(example_cachep,example_struct_pointer);
}
kmem_cache_destroy(example_cachep);
}
}
module_init(slabmod_init);
module_exit(slabmod_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Arkadiusz Chrobot <***>");
MODULE_DESCRIPTION("A module demonstrating useing of the slab allocator.");
MODULE_VERSION("1.0");
我已经查过像 Linux 设备驱动程序和类似的书 - 到处都是简单的功能,其中一个元素有示例。
我正在使用内核 3.16.0-4-686-pae 但在内核 4.9 中情况是一样的。
我将不胜感激:)
你错误地假设ctor()
(kmem_cache_create()
的最后一个参数)被调用每次你呼叫 kmem_cache_create()
.
实际上,调用此回调函数只是为了在分配器控制它之前预初始化 "garbage" 内存。
按此顺序:
kmem_cache_alloc()
, returns 指针 p.kmem_cache_free(p)
(假设分配器保持对 p 的控制)。kmem_cache_alloc()
, returns 指针 p.
回调函数在步骤 1 中仅 调用 ONCE。分配器假定在步骤 2(释放) p指向的对象已经处于初始化状态,所以第3步不需要初始化。
使用 kmem_cache
实现列表的正确方法是:
static void example_constructor(void *argument)
{
static unsigned int id;
static char test_string[] = "Stack";
struct example_struct *example = (struct example_struct *)argument;
/*
* This only garantee that at any time every element in the stack has unique id.
* New element may have same id as previously deleted one.
*/
example->id = id;
// All elements will have given string.
strcpy(example->example_string,test_string);
// Appending into the stack cannot be performed in the constructor.
// example->next = top;
// top = example;
id++;
}
/* Push allocated element into the stack and return that element. */
struct example_struct* push(void)
{
struct example_struct* example = kmem_cache_alloc(example_cachep,GFP_KERNEL);
if(example) {
// Add to the stack here
example->next = top;
top = example;
}
return example;
}
/* Pop element from the stack and free the element. */
void pop(void)
{
// Take the first element.
struct example_struct *example = top;
// Remove the element from the stack
top = example->next;
// In given example re-initialization actions before freeing the element are not needed.
kmem_cache_free(example_cachep, example);
}
static int __init slabmod_init(void)
{
...
// Test the stack.
for(i=1 ; i<6 ; i++) {
printk(KERN_ALERT "i: %d\n",i);
example_struct_pointer = push();
if(!example_struct_pointer)) {
...
}
}
return 0;
}
static void __exit slabmod_exit(void)
{
...
// Clean the stack
while(top) pop();
...
}