内核register_shrinker解析

2024-12-04 279 0

Linux 驱动开发中,register_shrinker 是内核中与内存管理相关的函数,通常用于注册内存回收机制。它允许驱动或模块向内核注册一个缩减器(shrinker),用于释放可回收的内存资源,例如缓存或缓冲区。

函数定义

在内核代码中,register_shrinker 的定义如下:

int register_shrinker(struct shrinker *shrinker);
// 如果内核版本大于6.0
int register_shrinker(struct shrinker *shrinker, const char *fmt, ...)

参数:

shrinker: 一个指向 struct shrinker 的指针,描述了缩减器的属性和行为。
返回值:
成功时返回 0。
如果注册失败,则返回负值错误代码。

结构体定义

struct shrinker 是定义缩减器行为的核心结构。它的定义位于 include/linux/shrinker.h 中。

struct shrinker {
    struct list_head list;  // 用于将 shrinker 添加到全局 shrinker 链表
    long (*count_objects)(struct shrinker *);  // 计算可缩减对象的数量
    long (*scan_objects)(struct shrinker *, struct shrink_control *);  // 执行实际的内存释放
    int seeks;  // I/O 操作的开销权重,影响缩减比例
    unsigned long batch;  // 每次释放操作的对象数量
    struct rcu_head rcu;  // 用于延迟删除的 RCU 头
};

关键字段:

count_objects: 一个回调函数,返回当前可缩减对象的数量。
scan_objects: 一个回调函数,执行实际的内存释放操作。
seeks: 决定扫描比例的权重值。
batch: 定义每次缩减操作中释放的对象数量。

工作原理

注册阶段:
驱动程序调用 register_shrinker 将一个 shrinker 实例注册到内核。
内存压力:
当系统检测到内存不足时,内核会调用所有注册的 shrinker,尝试释放内存。
回调执行:
首先调用 count_objects,获取可释放对象的数量。
然后调用 scan_objects,根据需求实际释放内存。
函数使用示例
假设我们需要为一个缓存实现一个 shrinker

#include <linux/shrinker.h>
#include <linux/slab.h>

// 自定义缓存
static struct kmem_cache *my_cache;

// count_objects 回调函数
static long my_count_objects(struct shrinker *shrink, struct shrink_control *sc)
{
    // 返回缓存中的对象数量
    return kmem_cache_size(my_cache) / sizeof(struct my_object);
}

// scan_objects 回调函数
static long my_scan_objects(struct shrinker *shrink, struct shrink_control *sc)
{
    long freed = 0;
    struct my_object *obj;

    // 模拟释放对象
    while ((obj = kmem_cache_alloc(my_cache, GFP_KERNEL)) != NULL) {
        kmem_cache_free(my_cache, obj);
        freed++;
    }

    return freed;
}

// 定义 shrinker
static struct shrinker my_shrinker = {
    .count_objects = my_count_objects,
    .scan_objects = my_scan_objects,
    .seeks = DEFAULT_SEEKS,
};

static int __init my_driver_init(void)
{
    int ret;

    // 初始化缓存
    my_cache = kmem_cache_create("my_cache", sizeof(struct my_object), 0, SLAB_HWCACHE_ALIGN, NULL);
    if (!my_cache)
        return -ENOMEM;

    // 注册 shrinker
    ret = register_shrinker(&my_shrinker);
    if (ret) {
        kmem_cache_destroy(my_cache);
        return ret;
    }

    return 0;
}

static void __exit my_driver_exit(void)
{
    // 注销 shrinker
    unregister_shrinker(&my_shrinker);

    // 销毁缓存
    kmem_cache_destroy(my_cache);
}

module_init(my_driver_init);
module_exit(my_driver_exit);

关键点总结

register_shrinker 用于注册缩减器,它会与内核的内存回收机制集成。
缩减器需要提供两个关键回调函数:
count_objects:用于计算当前可释放的对象数量。
scan_objects:用于执行实际的释放操作。
需要在模块卸载时调用 unregister_shrinker,以避免内核泄漏。
通过 register_shrinker,开发者可以实现灵活的内存管理,特别适用于缓存、缓冲区等需要动态回收的场景。

相关文章

发布评论