• Linux 设备模型【1】- devm_kzalloc()


    系列文章目录

    Linux 设备模型【1】- devm_kzalloc()



    前言

    Linux Kernel devm_* API源码分析
    本文通过对devm_kzalloc函数的实现进行解析,帮助理解devm系列api的用法。

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

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

    一、devm_kzalloc & devm_kfree代码

    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
    };
    
    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;
    }
    /*alloc_dr函数负责分配内存,返回的devres就包含分配到的内存,通过devres.data来访问即可. 
    devres_add(dev, dr->data);函数将数据与device进行绑定,实际调用add_dr,在这里将资源的节点头添加到device的devres_head链表中*/
    /**
     * devres_add - Register device resource
     * @dev: Device to add resource to
     * @res: Resource to register
     *
     * Register devres @res to @dev.  @res should have been allocated
     * using devres_alloc().  On driver detach, the associated release
     * function will be invoked and devres will be freed automatically.
     */
    void devres_add(struct device *dev, void *res)
    {
    	struct devres *dr = container_of(res, struct devres, data);
    	unsigned long flags;
    
    	spin_lock_irqsave(&dev->devres_lock, flags);
    	add_dr(dev, &dr->node);
    	spin_unlock_irqrestore(&dev->devres_lock, flags);
    }
    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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    二、资源释放

    kzalloc()实现了kmalloc()+memset()的功能,而 devm_kzalloc() 是具有资源管理的 kzalloc()。使用资源管理(resource-managed)函数分配的内存,是会与所属设备相关联。当设备从系统中分离或者设备驱动被卸载,该内存会被自动释放。也可以通过devm_kfree()来释放内存。

    static inline void *kzalloc(size_t size, gfp_t flags)
    {
    	return kmalloc(size, flags | __GFP_ZERO);
    }
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    竞赛 题目: 基于深度学习的疲劳驾驶检测 深度学习
    C++primer第6章函数
    高等数学教程【单变量微积分】内容目录
    今天面了个腾讯拿 38K 出来的大佬,让我见识到了 Java 面试八股文的天花板
    Ansible自动化运维工具(常用模块与命令)
    python使用代码
    ssh秘钥登录
    动态规划算法实现------空间中的移动(路径)问题
    科技驱动产业升级:浅谈制造型企业对MES系统的应用
    【数据结构初阶】复杂链表复制+带头双向循环链表+缓存级知识
  • 原文地址:https://blog.csdn.net/m0_46535940/article/details/126320673