研究内核版本 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等方法。见这里