平板缓存分配没有预定义函数的结构堆栈

时间:2017-03-19 21:39:13

标签: c linux linux-kernel stack kernel-module


我正在编写一个使用kmem_cache_create和kmem_cache_alloc在内核空间中创建堆栈的模块但是它不起作用。也许我已经用指针做了一些不好的事情,或者我没有理解slab分配的整个概念。我已经向同学和我的实验室负责人展示了代码,遗憾的是,任何人都无法帮助我。

这是我的代码在“堆栈”上分配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中执行5次kmem_cache_alloc时,我得到范围为0-11的12个元素,并且还显示消息“Slab cache仍然有对象”。
Here is screenshot demonstrating words above
之后我收到了Call Trace消息,因此内存错误。有时它会暂停整个虚拟机。 我在__exit的while循环中交换了指针,用于检查它将显示的内容 - 我有122个元素和相同的消息,所以这可能是一个整块(但可能因为消息而不完整?)。指针“next”在DEC中始终具有相同的值122 - 结构是122字节宽吗?结构尺寸给了我一些巨大的价值超过1,000,000%d。

原始代码,只分配一个结构,像魅力一样:

#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中的情况是一样的。 我将对每一个回复表示感谢:)

1 个答案:

答案 0 :(得分:1)

错误假设每次调用ctor()kmem_cache_create()kmem_cache_create()的最后一个参数)被称为。< / p>

实际上,只有在分配器控制它之前,才会调用此回调函数以预先初始化“垃圾”内存。

按顺序:

  1. kmem_cache_alloc(),返回指针 p
  2. kmem_cache_free(p)(假设分配器仍然控制 p )。
  3. kmem_cache_alloc(),返回指针 p
  4. 回调函数在步骤1中仅称为 ONCE 。分配器假定在步骤2(释放) p <指向的对象/ em> 已处于初始化状态,因此步骤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();
        ...
    }