The Road to Linux Kernel - Devres - Managed Device Resource

4 篇文章 0 订阅
2 篇文章 0 订阅

devres是内核为驱动开发者提供的用来申请资源的机制,函数名都是以devm开头。总的来说,在大多数情况下,调用这类接口不需要关心资源的释放问题。
在驱动进行probe时,可以调用这类接口,若probe失败,申请的资源也会释放。
devm_request_threaded_irq接口为例,简单了解下这个机制。

函数开始调用devres_allocdevm_irq_release保存在dr->node.release节点下,然后返回dr->data,再然后通过返回的节点,把调用relase时需要传递的参数irqdev_id保存起来。然后调用devres_add把该数据结构添加到dev->devres_head链表,供probe_failed,__device_release_driver等等时调用。

int devm_request_threaded_irq(struct device *dev, unsigned int irq,
			      irq_handler_t handler, irq_handler_t thread_fn,
			      unsigned long irqflags, const char *devname,
			      void *dev_id)
{
	struct irq_devres *dr;
	int rc;

	dr = devres_alloc(devm_irq_release, sizeof(struct irq_devres),
			  GFP_KERNEL);
	if (!dr)
		return -ENOMEM;

	if (!devname)
		devname = dev_name(dev);

	rc = request_threaded_irq(irq, handler, thread_fn, irqflags, devname,
				  dev_id);
	if (rc) {
		devres_free(dr);
		return rc;
	}

	dr->irq = irq;
	dr->dev_id = dev_id;
	devres_add(dev, dr);

	return 0;
}

void * __devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid,
		      const char *name)
{
	struct devres *dr;

	dr = alloc_dr(release, size, gfp | __GFP_ZERO, nid);
	if (unlikely(!dr))
		return NULL;
	set_node_dbginfo(&dr->node, name, size);
	return dr->data;
}

static __always_inline struct devres * alloc_dr(dr_release_t release,
						size_t size, gfp_t gfp, int nid)
{
	size_t tot_size;
	struct devres *dr;

	/* We must catch any near-SIZE_MAX cases that could overflow. */
	if (unlikely(check_add_overflow(sizeof(struct devres), size,
					&tot_size)))
		return NULL;

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

	memset(dr, 0, offsetof(struct devres, data));

	INIT_LIST_HEAD(&dr->node.entry);
	dr->node.release = release;
	return dr;
}

驱动probe_failed时,调用devres_release_all,其实就是调用之前的回调函数dr->node.release将probe时申请的资源释放。

if (dev->bus->probe) {
	ret = dev->bus->probe(dev);
	if (ret)
		goto probe_failed;
} else if (drv->probe) {
	ret = drv->probe(dev);
	if (ret)
		goto probe_failed;
}

probe_failed:
	devres_release_all(dev);

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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值