Linux Kernel devm_* API源码分析

Linux Kernel devm_* API源码分析

本文通过对devm_kzalloc函数的实现进行解析,帮助理解devm系列api的用法。

devm系列api的主要特别之处:

  • 使用devm系列申请到的资源可以由系统自动释放,解放双手

devm_kzalloc代码:

void * devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
{
    struct devres *dr;

    /* use raw alloc_dr for kmalloc caller tracing */
    dr = alloc_dr(devm_kzalloc_release, size, gfp);
    if (unlikely(!dr))
        return NULL;

    set_node_dbginfo(&dr->node, "devm_kzalloc_release", size);
    devres_add(dev, dr->data);
    return dr->data;
}
static __always_inline struct devres * alloc_dr(dr_release_t release,
                        size_t size, gfp_t gfp)
{
    size_t tot_size = sizeof(struct devres) + size;
    struct devres *dr;

    dr = kmalloc_track_caller(tot_size, gfp);
    if (unlikely(!dr))
        return NULL;

    memset(dr, 0, tot_size);
    INIT_LIST_HEAD(&dr->node.entry);
    dr->node.release = release;
    return dr;
}
struct devres {
    struct devres_node      node;
    /* -- 3 pointers */
    unsigned long long      data[]; /* guarantee ull alignment */
};
struct devres_node {
    struct list_head        entry;
    dr_release_t            release;
#ifdef CONFIG_DEBUG_DEVRES
    const char          *name;
    size_t              size;
#endif
};

alloc_dr函数负责分配内存,返回的devres就包含分配到的内存,通过devres.data来访问即可.
devres_add(dev, dr->data);函数将数据与device进行绑定,实际调用add_dr,在这里将资源的节点头添加到device的devres_head链表中

static void add_dr(struct device *dev, struct devres_node *node)
{
    devres_log(dev, node, "ADD");
    BUG_ON(!list_empty(&node->entry));
    list_add_tail(&node->entry, &dev->devres_head);
}

现在资源与dev的绑定已经完成,下面就找一找是如何释放资源的.
device_release_driver -> devres_release_all->release_nodes

static int release_nodes(struct device *dev, struct list_head *first,
             struct list_head *end, unsigned long flags)
    __releases(&dev->devres_lock)
{
    LIST_HEAD(todo);
    int cnt;
    struct devres *dr, *tmp;

    cnt = remove_nodes(dev, first, end, &todo);

    spin_unlock_irqrestore(&dev->devres_lock, flags);

    /* Release.  Note that both devres and devres_group are
     * handled as devres in the following loop.  This is safe.
     */
    list_for_each_entry_safe_reverse(dr, tmp, &todo, node.entry) {
        devres_log(dev, &dr->node, "REL");
        dr->node.release(dev, dr->data);
        kfree(dr);
    }

    return cnt;
}

在这里首先执行node的release函数,这个函数跟据资源的不同而有不同的实现,接着吧dr释放掉.由此,生成过程以及释放过程已经全部完成.


release函数在这里指定:
dr = alloc_dr(devm_kzalloc_release, size, gfp);


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值