首页 > 解决方案 > 为linux内核中的struct数组分配内存并得到奇怪的输出od structs ids

问题描述

我在 linux 内核中编写了一个程序,它应该为 5 个具有唯一 ID 的简单结构分配内存,所以我在构造函数中使用静态 int 并递增它,最后我只是将消息打印到缓冲区。当我看到缓冲区时,我得到了一个奇怪的结果,因为 id 的值像 0、64、128、192、256我很惊讶,因为我认为我会看到像 0、1、2、3、4 这样的值。为什么我得到这样的结果是有问题吗?

输出:

[2653.505140]示例结构ID:0
[2653.505143]示例字符串字段内容:测试
[2653.526565]示例结构ID:64
[2653.526568]示例字符串字段内容:测试
[2653.526623]示例结构ID:128
[2653.526625]示例字符串字段内容测试
[2653.550439] 示例结构 id:192
[2653.550443] 示例字符串字段内容:测试
[2653.550513] 示例结构 id:256
[2653.550514] 示例字符串字段内容:测试

有我的代码:

#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[5];

static struct kmem_cache *example_cachep[5];

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: %d\n",example->id);
    pr_notice("Example string field content: %s\n",example->example_string);
}

static int __init zad1_init(void)
{
    int i;
    for(i = 0; i < 5; i++){
        example_cachep[i] = 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[i])) {
            pr_alert("Error creating cache: %ld\n",PTR_ERR(example_cachep[i]));
            return -ENOMEM;
        }
    }

    for(i = 0; i < 5; i++){
        example_struct_pointer[i] = (struct example_struct *) kmem_cache_alloc(example_cachep[i],GFP_KERNEL);
        if(IS_ERR(example_struct_pointer[i])) {
            pr_alert("Error allocating form cache: %ld\n", PTR_ERR(example_struct_pointer[i]));
            kmem_cache_destroy(example_cachep[i]);
            return -ENOMEM;
        }
    }
    
    return 0;
}

static void __exit zad1_exit(void)
{
    int i;
    for(i = 0; i < 5; i++){
        if(example_cachep[i]) {
            if(example_struct_pointer[i]) {
                print_example_struct(example_struct_pointer[i]);
                kmem_cache_free(example_cachep[i],example_struct_pointer[i]);
            }
            kmem_cache_destroy(example_cachep[i]);
        }
    }
}

module_init(zad1_init);
module_exit(zad1_exit);

MODULE_LICENSE("GPL");

标签: clinuxstructkernel

解决方案


ctor函数的参数kmem_cache_create不是常识中的构造函数。

不能保证给定的函数只会被调用一次,并且只有在从缓存中请求对象时才会被调用。保证实际上是相反的(mm/slab_common.c:389):

* The @ctor is run when new pages are allocated by the cache.

因此,调用的次数可能ctor比从缓存中请求的对象数量多得多。

如果你只是想分配和初始化几个对象,那么只需定义相应的构造函数:

// Single cache can be used for allocate multiple object.
// No needs to define a cache-per-object.
static struct kmem_cache* example_cachep;

// Constructor for the object of type 'example_struct'.
static struct example_struct* create_example_object(void)
{
    static unsigned int id;
    struct example_struct *example = kmem_cache_alloc(example_cachep, GFP_KERNEL);
    if (example != NULL)
    {
      example->id = id;
      strcpy(example->example_string, "Test");
      id++;
    }

    return example;
}

static int __init zad1_init(void)
{
  // ...
  // Create the cache.
  example_cachep = kmem_cache_create("example cache", sizeof(struct example_struct),0, SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, example_constructor);

  // create several 'example' objects.
  for(i = 0; i < 5; i++){
    example_struct_pointer[i] = create_example_object();
    if(example_struct_pointer[i] == NULL)
    {
       // ... Somehow process the allocation failure.
    }
  }

  return 0;
}

ctor参数对于仅初始化对象的某些字段很有用。这样的初始化可以节省一点时间(稍微提高性能),但只有在以下两个条件都适用时:

  1. 您从缓存中主动创建(分配 + 初始化)和销毁(解除分配)对象。
  2. 您要初始化的字段在刚刚初始化的对象和将要被释放的对象中具有完全相同的

例如,您usage_count的对象中可能有一个字段,当一个对象刚刚初始化和一个对象将被释放时,该字段都等于 0。

ctor此类字段的用处在于,ctor可能不会为先前从同一缓存中释放的已分配对象调用它。也就是说,您可以通过不初始化已经具有所需值的字段来节省时间。

因为不初始化单个(或多个)值只能节省一点时间,但ctor调用的次数可能比需要的次数多,所以您应该仔细衡量您是否真的获得了性能而不是失去它。


推荐阅读