alloc_chrdev_region 分析

研究内核版本 2.6.32


首先,要查找函数 alloc_chrdev_region 的实现。

可以在源码树中使用find+grep查找

$ find . -name *.c | xargs grep -EHn 'alloc_chrdev_region\W*\(dev_t'
./fs/char_dev.c:231:int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
找到实现,接下来就看看它吧。 羡慕


int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
			const char *name)
{
	struct char_device_struct *cd;
	cd = __register_chrdev_region(0, baseminor, count, name); 
	if (IS_ERR(cd))
		return PTR_ERR(cd);
	*dev = MKDEV(cd->major, cd->baseminor);
	return 0;
}

可以看到 关键是

__register_chrdev_region
这个函数在同一个文件中

static struct char_device_struct *
__register_chrdev_region(unsigned int major, unsigned int baseminor,
			   int minorct, const char *name)
{
	struct char_device_struct *cd, **cp;
	int ret = 0;
	int i;

	cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
	if (cd == NULL)
		return ERR_PTR(-ENOMEM);

	mutex_lock(&chrdevs_lock);

	/* temporary */
	if (major == 0) { // major为0,表示要动态分配
		// 在数组中从后向前着到一个主设备号
		for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {
			if (chrdevs[i] == NULL)
				break;
		}

		if (i == 0) { // 没有找到空闲的主设备号
			ret = -EBUSY;
			goto out;
		}
		major = i;
		ret = major;
	}

	cd->major = major;
	cd->baseminor = baseminor;
	cd->minorct = minorct;
	strlcpy(cd->name, name, sizeof(cd->name));

	i = major_to_index(major);
        
        // 检查 baseminor, minorct 是否合理
	for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) // 可以看出chrdevs这是一个哈希表,解决冲突的方式是链表法
		if ((*cp)->major > major ||
		    ((*cp)->major == major &&
		     (((*cp)->baseminor >= baseminor) ||
		      ((*cp)->baseminor + (*cp)->minorct > baseminor))))
			break;

	/* Check for overlapping minor ranges.  */
	if (*cp && (*cp)->major == major) {
		int old_min = (*cp)->baseminor;
		int old_max = (*cp)->baseminor + (*cp)->minorct - 1;
		int new_min = baseminor;
		int new_max = baseminor + minorct - 1;

		/* New driver overlaps from the left.  */
		if (new_max >= old_min && new_max <= old_max) {
			ret = -EBUSY;
			goto out;
		}

		/* New driver overlaps from the right.  */
		if (new_min <= old_max && new_min >= old_min) {
			ret = -EBUSY;
			goto out;
		}
	}

	cd->next = *cp;
	*cp = cd;
	mutex_unlock(&chrdevs_lock);
	return cd;
out:
	mutex_unlock(&chrdevs_lock);
	kfree(cd);
	return ERR_PTR(ret);
}


这篇文章中的哈希表画得不错


总结:

分析源码首先要找到它的实现在哪里(废话)。 着实现可以用 find+grep、 lxr、cscope等方法。见这里


你可能感兴趣的:(alloc_chrdev_region 分析)