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()**에서 시작하여 레이어별로 살펴보겠습니다.
커널에서 문자 장치 작동 기능의 구현은 **"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 구조와 해당 장치 번호를 캡슐화하는 것을 볼 수 있습니다. .
cdev_map의 기능을 이해한 후 cdev_add()
를 탐색할 수 있습니다. 으아악함수는 매우 짧습니다. (460-461)은 이전에 얻은 장치 번호와 장치 번호 길이를 cdev 구조에 채우는 것입니다. kobject_get()(468)은 아무 작업도 수행하지 않습니다.
으아악그래서 핵심 작업은 당연히 kobj_map()
에 넘겨집니다.이 함수는 커널의 장치 관리에서 중요한 위치를 차지합니다. 여기서는 문자 장치의 관점에서만 해당 기능을 분석하고 먼저 구현합니다
으아악이 함수의 설계도 매우 간단합니다. 즉, 프로브 구조를 캡슐화하고 해당 주소를 프로브 배열에 넣은 다음 이를 cdev_map에 캡슐화합니다. (48-55)j는 번호에 따라 장치를 배치하는 것입니다. 전달된 장치 번호의 번호와 cdev는 kmalloc_array에 의해 할당된 n개의 프로브 구조에 차례로 캡슐화됩니다. (57-63) NULL 값을 갖는 요소가 발견될 때까지 probs 배열을 순회한 후 프로브 주소를 저장합니다. 프로브에. 이 시점에서 우리는 cdev를 커널의 데이터 구조에 넣었습니다. 물론 cdev의 많은 속성이 커널에 의해 채워집니다.
将设备放入的内核,我们再来看看内核是怎么找到一个特定的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 중국어 웹사이트의 기타 관련 기사를 참조하세요!