文章目录
- 数据结构总述
- 数据结构初始化流程概述
- 各结构初始化及关联说明
- 文件描述符表
- 文件结构(文件表)
- 文件节点
- 设备节点
- 内核驱动表
数据结构总述
本文基于NEW_1 型内核数据结构展开,通过上图可以看出了使用三种数据结构(文件描述符表项、文件结构、文件节点)来表示打开的文件,它们的关系决定了在文件共享方面,一个进程对另一个进程可能产生的影响。
每
- 每个进程都维护着自己的一个文件描述符表,每个文件描述符占其中一项,与每个文件描述符相关联的是:
指向文件结构的指针;
文件引用计数;
文件描述符标志(FD_CLOEXEC)。 - 内核为所有打开的文件维护一个文件结构表,每一个文件结构表项包括(部分):
设备头指针(这个指针指向设备节点);
文件名;
文件节点指针;
文件属性标志(读、写等,更多信息 点击查看iFlag选项描述);
文件当前指针(指示文件偏移)。 - 每个打开的文件都有一个文件节点,文件节点包括(部分):
设备描述符;
inode(同一个文件只有一个 inode,SylixOS 中 inode 并不和 Linux 中的 inode 一样,SylixOS 中 inode 可看做是一种文件识别码);
文件权限信息(可读、可写、可执行);
文件用户信息;
当前文件大小;
文件记录锁指针。
下图展示了两个独立进程各自打开了同一个文件的情景,我们假定第一个进程在文件描述符 3 上打开该文件,而另一个进程在文件描述符 4 上打开相同文件。打开该文件的每个进程都获得各自的一个文件结构,但对于一个给定的文件只有一个文件节点。之所以每个进程都获得自己的文件结构,是因为这可以使每个进程都有它自己的对该文件的当前读写指针(文件操作偏移量)。
文件描述符标志和文件属性标志在作用范围方面是有区别的,前者只用于一个进程中的一个文件描述符,而后者则应用于指向该给定文件结构的任何进程中的所有文件描述符。
数据结构初始化流程概述
• iosDevAddEx()以注册驱动函数为参数,创建设备;(dev_hdr)
• _IosFileNew() 创建并初始化 fd_entry 文件结构;(fd_desc)
• _IosFileDup() 以 fd_entry 为参数,创建并初始化 fd_desc 文件描述符;(fd_desc->fd_entry)
• API_IosFdNodeAdd() 以 dev_hdr 为参数,创建初始化并返回 fd_node 文件节点;(fd_desc->fd_entry)(fd_node->dev_hdr)
• _IosFileSet() 以 dev_hdr 、fd_node为参数,配置 fd_entry 结构;(fd_desc->fd_entry->fd_node->dev_hdr) ;
各结构初始化及关联说明
文件描述符表
○ 文件描述符表:_G_fddescTbl[LW_CFG_MAX_FILES],type:LW_FD_DESC;
§ 每个进程都维护着自己的一个文件描述符表(数组),每个文件描述符占其中一项;
○ 应用层调用 open/create 函数时,底层会调用 INT _IosFileDup (PLW_FD_ENTRY pfdentry, INT iMinFd),_IosFileDup() 调用 vprocIoFileDup (PLW_FD_ENTRY pfdentry, INT iMinFd) ,以 PLW_FD_ENTRY(文件结构)为参数对 LW_FD_DESC(文件描述符) 结构体进行初始化,并返回一个文件描述符(对应文件描述符表数组的下标),(PLW_FD_DESC 结构体内包含 PLW_FD_ENTRY 成员);
○ 以 PLW_FD_ENTRY(文件结构)为参数初始化并返回一个文件描述符(对应文件描述符表数组的下标),(PLW_FD_DESC 结构体内包含 PLW_FD_ENTRY 成员);
§ INT open (CPCHAR cpcName, INT iFlag, ...)
□ static INT _IoOpen (PCHAR pcName, INT iFlag, INT iMode, BOOL bCreate)
® INT API_IosFdNew (PLW_DEV_HDR pdevhdrHdr, CPCHAR pcName, LONG lValue, INT iFlag) //返回文件描述符
◊ PLW_FD_ENTRY INT _IosFileDup (PLW_FD_ENTRY pfdentry, INT iMinFd) //申请并初始化一个新的文件描述符
※ INT vprocIoFileDup (PLW_FD_ENTRY pfdentry, INT iMinFd) //查找空文件描述符, 初始化文件描述符结构体
○ vprocIoFileDup() 函数中,获取进程控制块 LW_LD_VPROC *pvproc,初始化进程fd表(PLW_FD_DESC pvproc->VP_fddescTbl[iFd])中最小未使用的文件表描述符;
文件结构(文件表)
○ 文件结构表头:_S_plineFileEntryHeader,type:LW_LIST_LINE_HEADER;
§ 内核为所有打开的文件维护一个文件结构表;
○ 应用层调用 open/create 函数时,底层会调用 _IoOpen (PCHAR pcName, INT iFlag, INT iMode, BOOL bCreate),其中:
§ iFd = iosFdNew(pdevhdrHdr, cFullFileName, PX_ERROR, iFlag); //返回申请的文件描述符
□ pfdentry = _IosFileNew(pdevhdrHdr, pcName); //创建并初始化 fd_entry 结构
□ iFd = _IosFileDup(pfdentry, 0); //查找空的fd_desc文件描述符, 配置文件结构 pfdentry
□ _IosFileSet(pfdentry, pdevhdrHdr, lValue, iFlag, state); //设置一个 fd_entry 结构(初始配置)
§ lValue = iosOpen(pdevhdrHdr, cFullFileName, iFlag, iMode);
□ lFValue = pfuncDrvOpen(pdevhdrHdr, pcName, iFlag, iMode);
® PLW_FD_NODE API_IosFdNodeAdd(LW_LIST_LINE_HEADER *pplineHeader, dev_t dev, ino64_t inode, INT iFlags, mode_t mode, uid_t uid, gid_t gid, off_t oftSize, PVOID pvFile, BOOL *pbIsNew); //创建初始化并返回 fd_node 文件节点,见文件节点章节
§ iosFdSet(iFd, pdevhdrHdr, lValue, iFlag, FDSTAT_OK);
□ pfdentry = _IosFileGet(iFd, LW_TRUE); //通过 fd 获得 fd_entry
□ _IosFileSet(pfdentry, pdevhdrHdr, lValue, iFlag, state); //设置一个 fd_entry 结构(补充配置,填充fd_entry的fd_node和dev_hdr)
○ 底层会调用PLW_FD_ENTRY _IosFileNew (PLW_DEV_HDR pdevhdrHdr, CPCHAR pcName),以 PLW_DEV_HDR(设备头指针)为参数创建并初始化文件结构,(LW_FD_ENTRY 结构体内包含 PLW_DEV_HDR 成员);
§ INT open (CPCHAR cpcName, INT iFlag, ...)
□ static INT _IoOpen (PCHAR pcName, INT iFlag, INT iMode, BOOL bCreate)
® INT API_IosFdNew (PLW_DEV_HDR pdevhdrHdr, CPCHAR pcName, LONG lValue, INT iFlag) //返回文件描述符
◊ PLW_FD_ENTRY _IosFileNew (PLW_DEV_HDR pdevhdrHdr, CPCHAR pcName) //创建并初始化 fd_entry 结构
○ _IosFileNew() 通过_List_Line_Add_Ahead(PLW_LIST_LINE &(PLW_FD_ENTRY->FDENTRY_lineManage), LW_LIST_LINE_HEADER * (&_S_plineFileEntryHeader)) 函数将 (LW_FD_ENTRY 文件结构的) FDENTRY_lineManage 成员加入文件结构表;
文件节点
○ 文件节点链表:pplineHeader,type:LW_LIST_LINE_HEADER *;
§ 设备私有链表,一个设备节点对应一个文件节点链表。
○ 应用层调用 open/create 函数时,底层会调用_S_deventryTbl[__LW_DEV_MAINDRV].DEVENTRY_pfuncDevOpen((PLW_DEV_HDR pdevhdrHdr, PCHAR pcName, INT iFlag, INT iMode));
§ INT open (CPCHAR cpcName, INT iFlag, ...)
□ static INT _IoOpen (PCHAR pcName, INT iFlag, INT iMode, BOOL bCreate)
® LONG API_IosOpen (PLW_DEV_HDR pdevhdrHdr, PCHAR pcName, INT iFlag, INT iMode)
◊ _S_deventryTbl[__LW_DEV_MAINDRV].DEVENTRY_pfuncDevOpen((PLW_DEV_HDR pdevhdrHdr, PCHAR pcName, INT iFlag, INT iMode));
○ DEVENTRY_pfuncDevOpen() 内调用 API_IosFdNodeAdd (LW_LIST_LINE_HEADER *pplineHeader, dev_t dev, ino64_t inode64, INT iFlags, mode_t mode, uid_t uid, gid_t gid, off_t oftSize, PVOID pvFile, BOOL *pbIsNew);
§ pplineHeade 链表头通常初始化为设备控制块成员变量 ;
○ API_IosFdNodeAdd() 通过_List_Line_Add_Ahead(PLW_LIST_LINE &PLW_FD_NODE->FDNODE_lineManage, LW_LIST_LINE_HEADER *pplineHeader) 将(初始化完成的文件节点的)FDNODE_lineManage 成员添加至“同一设备的 fd_node 链表”进行统计管理;
设备节点
○ 设备表表头:_S_plineDevHdrHeader,type:LW_LIST_LINE_HEADER;
§ 全局设备头链表为全局变量;
§ 设备链表内会添加关联所有设备,包括不同驱动号(主设备号)的设备及相同驱动号(主设备号),不同子设备号的设备;
○ 使用 API_IosDevAddEx (PLW_DEV_HDR pdevhdrHdr, CPCHAR pcDevName, INT iDrvNum, UCHAR ucType)向系统中添加一个设备;
○ 使用 _List_Line_Add_Ahead(&pdevhdrHdr->DEVHDR_lineManage, &_S_plineDevHdrHeader); 将设备头的管理链表成员加入全局设备头链表;
○ LW_DEV_HDR 设备头通常初始化为设备控制块成员变量 ;
内核驱动表
○ 驱动程序表:_S_deventryTbl[iDrvNum],type:LW_DEV_ENTRY;
§ 全局变量,保存所有设备驱动的底层操作实现;
§ 每组驱动函数对应一个驱动程序索引号;
○ 使用 API_IosDrvInstallEx (struct file_operations *pfileop)向内核注册设备驱动程序,输出“驱动程序索引号(iDrvNum)”;
○ 使用 pfileop(设备文件操作控制块) 初始化 _S_deventryTbl[iDrvNum];