>  기사  >  시스템 튜토리얼  >  Linux 시스템의 장치 관리: dev_add 함수로 시작

Linux 시스템의 장치 관리: dev_add 함수로 시작

PHPz
PHPz앞으로
2024-02-11 13:57:26943검색

Linux 장치 관리는 Linux 시스템에서 생성, 삭제, 검색, 수정 등 장치의 통합 관리 및 운영을 달성하는 데 사용됩니다. Linux 장치 관리에는 kobject, kset 및 kobj_type의 세 가지 핵심 개념이 포함됩니다. kobject는 모든 유형의 장치를 나타내는 데 사용할 수 있는 범용 커널 개체입니다. kset은 관련 kobject 그룹을 구성하고 관리하는 데 사용할 수 있는 컨테이너 개체입니다. kobj_type은 kobject의 속성과 작업을 정의하는 데 사용할 수 있는 유형 개체입니다.

여기에서는 Linux 커널(4.8.5 커널을 예로 들어)이 문자 장치를 관리하는 방법에 대해 설명합니다. 즉, 장치 번호를 얻을 때 cdev 구조를 할당하고 드라이버의 작동 방법 세트를 등록한 다음 마지막으로 설명합니다. cdev_add()가 커널에 정확히 전달되는 내용은 무엇이며, 커널은 내 cdev 구조를 어떻게 관리합니까? 이것이 이 기사에서 논의할 내용입니다. 우리는 Linux 커널의 장치 관리가 kobject를 기반으로 한다는 것을 알고 있습니다. 이는 cdev 구조에서 볼 수 있습니다. 따라서 다음으로 "fs/char_dev.c"에 구현된 문자 장치를 작동하는 함수를 볼 수 있습니다. **"lib/kobject.c""drivers/base/map.c"에 있는 kobject에서 작동하는 함수. 좋아요, 이제 cdev_add()**에서 시작하여 레이어별로 살펴보겠습니다.

cdev_map 개체

으아악

커널에서 문자 장치 작동 기능의 구현은 **"fs/char_dev.c"에 있습니다. 이 파일을 열면 가장 먼저 눈에 띄는 것은 커널에서 일반적이지 않은 이 정적 전역 변수입니다 cdev_map**(27), 우리는 소프트웨어의 응집력을 향상시키기 위해 Linux 커널이 설계 중에 함수 간에 데이터를 전송하는 방법으로 전역 변수를 사용하지 않으려고 한다는 것을 알고 있으며 정식 매개변수 목록을 더 자주 사용하는 것이 좋습니다. , 이 구조 변수는 이 파일의 모든 곳에서 사용되므로 시스템의 모든 문자 장치를 설명하는 일종의 정보여야 합니다. 이 아이디어를 사용하면 **에서 kobj_map** 구조의 정의를 찾을 수 있습니다. "드라이버/베이스/map.c":

으아악

이로부터 kobj_map의 핵심은 구조체 프로브 포인터 유형 및 크기 255의 배열임을 알 수 있습니다. 이 프로브 구조에서 첫 번째 멤버 next(21)는 분명히 이러한 프로브 구조를 연결된 목록 형태로 연결합니다. . dev_t 유형의 멤버 dev는 분명히 장치 번호이고, get(25) 및 lock(26)은 각각 두 가지 기능 인터페이스입니다. void*는 뱀 오일입니다. 다음은 C 언어의 cdev 구조입니다(후속 분석에서 볼 수 있듯이). 따라서 이 cdev_map은 구조체 프로브 포인터 유형과 크기 255의 배열을 포함하는 구조체 kobj_map 유형의 포인터입니다. 배열을 가리키는 프로브 구조는 장치 번호와 해당 장치 개체(여기서는 cdev)를 캡슐화합니다. 이 cdev_map은 최대 255개의 문자 장치로 시스템의 모든 cdev 구조와 해당 장치 번호를 캡슐화하는 것을 볼 수 있습니다. .
Linux 시스템의 장치 관리: dev_add 함수로 시작

cdev_add

cdev_map의 기능을 이해한 후 cdev_add()

를 탐색할 수 있습니다. 으아악

함수는 매우 짧습니다. (460-461)은 이전에 얻은 장치 번호와 장치 번호 길이를 cdev 구조에 채우는 것입니다. kobject_get()(468)은 아무 작업도 수행하지 않습니다.

으아악

그래서 핵심 작업은 당연히 kobj_map()

에 넘겨집니다.

kobj_map()

이 함수는 커널의 장치 관리에서 중요한 위치를 차지합니다. 여기서는 문자 장치의 관점에서만 해당 기능을 분석하고 먼저 구현합니다

으아악

이 함수의 설계도 매우 간단합니다. 즉, 프로브 구조를 캡슐화하고 해당 주소를 프로브 배열에 넣은 다음 이를 cdev_map에 캡슐화합니다. (48-55)j는 번호에 따라 장치를 배치하는 것입니다. 전달된 장치 번호의 번호와 cdev는 kmalloc_array에 의해 할당된 n개의 프로브 구조에 차례로 캡슐화됩니다. (57-63) NULL 값을 갖는 요소가 발견될 때까지 probs 배열을 순회한 후 프로브 주소를 저장합니다. 프로브에. 이 시점에서 우리는 cdev를 커널의 데이터 구조에 넣었습니다. 물론 cdev의 많은 속성이 커널에 의해 채워집니다.

chrdev_open()

将设备放入的内核,我们再来看看内核是怎么找到一个特定的cdev的,对一个字符设备的访问流程大概是:文件路径=>inode=>chrdev_open=>cdev->fops->my_chr_open。所以只要通过VFS找到了inode,就可以找到chrdev_open(),这里我们就来关注一个chrdev_open()是怎么从内核的数据结构中找到我们的cdev并回调里满的my_chr_open()的。首先,chrdev_open()尝试将inode->i_cdev(一个cdev结构指针)保存在局部变量p中(359),如果p为空,即inode->i_cdev为空(360),我们就根据inode->i_rdev(设备号)通过kobj_lookup搜索cdev_map,并返回与之对应kobj(364),由于kobject是cdev的父类,我们根据container_of很容易找到相应的cdev结构并将其保存在inode->i_cdev中(367),找到了cdev,我们就可以将inode->devices挂接到inode->i_cdev的管理链表中,这样下次就不用重新搜索,直接cdev_get()即可(378)。找到了我们的cdev结构,我们就可以将其中的操作方法集inode->i_cdev->ops传递给filp->f_ops(386-390),这样,我们就可以回调我们的设备打开函数my_chr_open()(392);

//fs/char_dev.c
326 static struct kobject *cdev_get(struct cdev *p)     
327 {
328         struct module *owner = p->owner;
329         struct kobject *kobj;
330         
331         if (owner && !try_module_get(owner))
332                 return NULL;
333         kobj = kobject_get(&p->kobj);
        ...
336         return kobj;
337 }

351 static int chrdev_open(struct inode *inode, struct file *filp)
352 {
353         const struct file_operations *fops;
354         struct cdev *p;
355         struct cdev *new = NULL;
356         int ret = 0;
        ...
359         p = inode->i_cdev;
360         if (!p) {
361                 struct kobject *kobj;
362                 int idx;
            ...
364                 kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);
            ...
367                 new = container_of(kobj, struct cdev, kobj);
369                 /* Check i_cdev again in case somebody beat us to it while
370                    we dropped the lock. */
371                 p = inode->i_cdev;
372                 if (!p) {
373                         inode->i_cdev = p = new;
374                         list_add(&inode->i_devices, &p->list);
375                         new = NULL;
376                 } else if (!cdev_get(p))
377                         ret = -ENXIO;
378         } else if (!cdev_get(p))
379                 ret = -ENXIO;
            ...
386         fops = fops_get(p->ops);
        ...
390         replace_fops(filp, fops);
391         if (filp->f_op->open) {
392                 ret = filp->f_op->open(inode, filp);
            ...
395         }
396 
397         return 0;
398 
399  out_cdev_put:
400         cdev_put(p);
401         return ret;
402 }

通过本文,我们了解了Linux设备管理的原理和方法。它们可以用来实现对设备的统一管理和操作。我们应该根据实际需求选择合适的方法,并遵循一些基本原则,如使用正确的引用计数,使用正确的锁机制,使用正确的属性文件等。Linux设备管理是Linux系统中最基本的机制之一,它可以实现对设备的抽象和封装,也可以提升系统的可维护性和可扩展性。希望本文能够对你有所帮助和启发。

위 내용은 Linux 시스템의 장치 관리: dev_add 함수로 시작의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 lxlinux.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제