장치 파일은 Linux 시스템에서 사용자 공간 프로그램이 파일 작업을 통해 장치에 액세스할 수 있도록 장치의 인터페이스를 나타내는 데 사용됩니다. 장치 파일의 구현에는 inode, file 및 file_options라는 세 가지 중요한 구조가 포함됩니다. inode 구조는 장치 번호, 권한, 크기 등과 같은 장치 파일의 메타데이터를 저장하는 데 사용됩니다. 파일 구조는 현재 위치, 개방 모드, 개인 데이터 등과 같은 장치 파일의 상태 정보를 저장하는 데 사용됩니다. file_Operations 구조는 열기, 읽기, 쓰기, 닫기 등과 같은 장치 파일 작업 기능을 저장하는 데 사용됩니다. 이 기사에서는 이 세 가지 구조의 정의와 기능을 소개하고 사용법과 주의사항에 대한 예를 제공합니다.
드라이버는 아래쪽으로 하드웨어를 제어하고 위쪽으로 인터페이스를 제공합니다. 여기서 위쪽으로 제공되는 인터페이스는 궁극적으로 세 가지 방식으로 애플리케이션 계층에 해당합니다. 장치 파일, /proc, /sys 중 가장 일반적으로 사용되는 것은 장치 파일을 사용하는 것입니다. 및 Linux 가장 일반적으로 사용되는 장치는 문자 장치입니다. 이 기사에서는 문자 장치 파일을 생성하고 여는 내부 메커니즘을 분석하기 위해 문자 장치를 예로 들어 보겠습니다.
리눅스에서는 모든 것이 파일입니다. 리눅스에서 파일을 만들면 그에 대응하는 파일 시스템에 아이노드가 생성됩니다. 파일 엔터티와 파일의 아이노드는 일대일 대응입니다 . inode가 생성되고 메모리에 저장되면 처음 열 때 동일한 파일이 여러 번 열리고 열린 모든 파일이 닫히면 inode가 생성되지 않습니다. 인스턴스가 메모리에 해제됩니다. 이 경우 mknod(또는 다른 방법)를 사용하여 장치 파일을 생성하면 파일 시스템에 inode도 생성됩니다. 이 inode는 다른 inode와 마찬가지로 파일에 대한 정적 정보(불변 정보)를 저장하는 데 사용됩니다. . ), 이 장치 파일에 해당하는 장치 번호, 파일 경로 및 해당 드라이버 개체 등이 포함됩니다. VFS의 네 가지 주요 개체 중 하나인 inode는 드라이버 개발 시 직접 채울 필요가 거의 없으며 open() 메서드에서 보고 필요에 따라 파일 구조를 채우는 것이 더 필요합니다.
파일 형식에 따라 inode의 채워진 멤버 내용도 달라집니다. 예를 들어 문자 장치를 생성하면 add_chrdev_region이 실제로 드라이브 개체와 (그룹) 장치 번호를 연결한다는 것을 알 수 있습니다. 장치 파일을 생성하면 실제로 장치 파일과 장치 번호가 함께 연결됩니다. 이 시점에서 이 세 가지는 하나로 묶여 있습니다. 이러한 방식으로 커널은 struct inode의 인스턴스를 생성할 수 있습니다. 다음은 4.8.5 커널의 inode입니다. 이 inode는 VFS의 inode이며, 가장 구체적인 파일 시스템의 inode를 추가로 캡슐화한 것입니다. 또한 특정 파일 시스템의 경우 struct ext2_inode_info와 같은 구조도 있습니다.
이 글과 관련된 주요 멤버는
“
구조체 inode
–602–>i_mode는 액세스 권한 제어를 나타냅니다
–604–>UID
–605–>GID
–606–>i_flags 파일 시스템 플래그
–630–> 하드 링크 수
–635–>i_size 파일 크기(바이트)
–636–>마지막 접속 시간
–637–>마지막 수정 시간
–638–>마지막 변경 시간
–669–>i_dentry; //카탈로그 목걸이 목록
–673–>i_count 참조 카운트, 참조 카운트가 0이 되면 inode 인스턴스가 해제됩니다
–675–>i_writecount 작가 수
–679–>장치 파일 생성 시 i_fops는 def_chr_fops, blk_blk_fops, def_fifo_fops, bad_sock_fops 중 하나로 채워집니다. 생성 과정에서 호출되는 init_special_inode()를 참조하세요
–683–>Union, Pipe, cdev, blk.link 등과 같은 특수 파일 형식. i_cdev는 이 inode가 문자 장치 파일에 속함을 나타냅니다. 이 기사에서 장치 파일을 생성할 때 관련 장치 번호의 드라이버 개체 cdev가 있습니다.
채우기가 사용됩니다. –702–>inode의 개인 데이터”
위 멤버 중에서 struct def_chr_fops만 추구할 가치가 있으며 나중에 유용하게 사용할 수 있습니다.
//fs/char_dev.c 429 const struct file_operations def_chr_fops = { 430 .open = chrdev_open, 431 .llseek = noop_llseek, 432 };
Linux内核会为每一个进程维护一个文件描述符表,这个表其实就是struct file[]的索引。open()的过程其实就是根据传入的路径填充好一个file结构并将其赋值到数组中并返回其索引。下面是file的主要内容
//include/linux/fs.h 877 struct file { 878 union { 879 struct llist_node fu_llist; 880 struct rcu_head fu_rcuhead; 881 } f_u; 882 struct path f_path; 883 struct inode *f_inode; /* cached value */ 884 const struct file_operations *f_op; 885 886 /* 887 * Protects f_ep_links, f_flags. 888 * Must not be taken from IRQ context. 889 */ 890 spinlock_t f_lock; 891 atomic_long_t f_count; 892 unsigned int f_flags; 893 fmode_t f_mode; 894 struct mutex f_pos_lock; 895 loff_t f_pos; 896 struct fown_struct f_owner; 897 const struct cred *f_cred; 898 struct file_ra_state f_ra;f 904 /* needed for tty driver, and maybe others */ 905 void *private_data; 912 struct address_space *f_mapping; 913 } __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
“
struct file
–882–>f_path里存储的是open传入的路径,VFS就是根据这个路径逐层找到相应的inode
–883–>f_inode里存储的是找到的inode
–884–>f_op里存储的就是驱动提供的file_operations对象,这个对象在open的时候被填充,具体地,应用层的open通过层层搜索会调用inode.i_fops->open,即chrdev_open()
–891–>f_count的作用是记录对文件对象的引用计数,也即当前有多少个使用CLONE_FILES标志克隆的进程在使用该文件。典型的应用是在POSIX线程中。就像在内核中普通的引用计数模块一样,最后一个进程调用put_files_struct()来释放文件描述符。
–892–>f_flags当打开文件时指定的标志,对应系统调用open的int flags,比如驱动程序为了支持非阻塞型操作需要检查这个标志是否有O_NONBLOCK。
–893–>f_mode;对文件的读写模式,对应系统调用open的mod_t mode参数,比如O_RDWR。如果驱动程序需要这个值,可以直接读取这个字段。
–905–>private_data表示file结构的私有数据”
我在Linux设备管理(二)_从cdev_add说起一文中已经分析过chrdev_open(),这里仅作概述。
//fs/chr_dev.c 348 /* 349 * Called every time a character special file is opened 350 */ 351 static int chrdev_open(struct inode *inode, struct file *filp) 352 { /* 搜索cdev */ ... 390 replace_fops(filp, fops); 391 if (filp->f_op->open) { 392 ret = filp->f_op->open(inode, filp); 393 if (ret) 394 goto out_cdev_put; 395 } ... 402 }
可以看出,这个函数有三个任务(划重点!!!):
“
chrdev_open()
–352-389–>利用container_of等根据inode中的成员找到相应的cdev
–390–>用cdev.fops替换filp->f_op,即填充了一个空的struct file的f_op成员。
–392–>回调替换之后的filp->f_op->open,由于替换,这个其实就是cdev.fops”
至此,我们知道了我们写的驱动中的open()在何时会被回调,这样我们就可以实现很多有意思的功能,比如,
我们可以在open中通过inode->cdev来识别具体的设备,并将其私有数据隐藏到file结构的private_data中,进而识别同一个驱动操作一类设备;
我们也可以在回调cdev.fops->open()阶段重新填充file结构的fop,进而实现同一个驱动操作不同的设备,这种思想就是内核驱动中常用的分层!
最后总结一下这些结构之间的关系:
“
”
이 기사를 통해 우리는 장치 파일의 세 가지 중요한 구조인 inode, file 및 file_options에 대해 배웠습니다. 장치 파일을 관리하고 운영하는 데 사용할 수 있습니다. 실제 필요에 따라 적절한 구조를 선택하고 올바른 장치 번호 사용, 합리적인 권한 사용, 효과적인 운영 기능 사용 등과 같은 몇 가지 기본 원칙을 따라야 합니다. 장치 파일의 세 가지 구조는 Linux 시스템의 가장 기본적인 개념 중 하나이며 장치를 추상화하고 캡슐화할 수 있으며 시스템의 통일성과 유연성을 향상시킬 수도 있습니다. 이 글이 여러분에게 도움이 되고 영감을 줄 수 있기를 바랍니다.
위 내용은 Linux 시스템의 장치 파일: inode, file 및 file_options의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!