为 linux 内核中的结构数组分配内存并得到奇怪的输出 od structs ids

Allocating memory for array of struct in linux kernel and got strange output od structs ids

我在 linux 内核中写了一个程序,它应该为 5 个简单的结构分配内存,每个结构都有唯一的 ID,所以我在构造函数中使用 static 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");

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 可能会被调用多次,所以你应该小心 measure 你是否真的获得了表现而不是失去了表现。