xnu中的vnode和文件描述符,存储文件操作向量的位置

在xnu中,我们有vnode_t实体,它代表全局文件。

每个进程都可以通过设置新的文件描述符并在fg_data下设置vnode来访问该文件(假设它具有正确的权限)

 fp->f_fglob->fg_data = vp; 

vnode包含所有相关操作的基本操作列表,并根据文件的FS进行设置。 即HFS +驱动程序实现此类向量并相应地设置其vnode。

 int (**v_op)(void *); /* vnode operations vector */ 

这是可以在vnode上运行的所有操作的函数指针的向量。

另外,我们有fileops结构,它是文件描述符(fg_global)的一部分,它描述了这些函数的最小子集:

这是一个典型的定义:

 const struct fileops vnops = { .fo_type = DTYPE_VNODE, .fo_read = vn_read, .fo_write = vn_write, .fo_ioctl = vn_ioctl, .fo_select = vn_select, .fo_close = vn_closefile, .fo_kqfilter = vn_kqfilt_add, .fo_drain = NULL, }; 

我们在这里设置:

 fp->f_fglob->fg_ops = &vnops; 

我看到当在本地文件系统(HFS +)下读取常规文件时,它通过file_descriptor而不是vnode工作…

  * frame #0: 0xffffff801313c67c kernel`vn_read(fp=0xffffff801f004d98, uio=0xffffff807240be70, flags=0, ctx=0xffffff807240bf10) at vfs_vnops.c:978 [opt] frame #1: 0xffffff801339cc1a kernel`dofileread [inlined] fo_read(fp=0xffffff801f004d98, uio=0xffffff807240be70, flags=0, ctx=0xffffff807240bf10) at kern_descrip.c:5832 [opt] frame #2: 0xffffff801339cbff kernel`dofileread(ctx=0xffffff807240bf10, fp=0xffffff801f004d98, bufp=140222138463456, nbyte=282, offset=, flags=, retval=) at sys_generic.c:365 [opt] frame #3: 0xffffff801339c983 kernel`read_nocancel(p=0xffffff801a597658, uap=0xffffff801a553cc0, retval=) at sys_generic.c:215 [opt] frame #4: 0xffffff8013425695 kernel`unix_syscall64(state=) at systemcalls.c:376 [opt] frame #5: 0xffffff8012e9dd46 kernel`hndl_unix_scall64 + 22 

我的问题是为什么需要这种二元性,并且在哪种情况下,操作通过file_descriptor向量(fg_ops)工作,以及哪些情况下操作通过vnode向量(vp-> v_op)工作。

谢谢

[…]在这种情况下,操作通过file_descriptor向量(fg_ops)工作,在哪种情况下,操作通过vnode向量(vp-> v_op)工作。

我将首先回答问题的第二部分:如果你进一步追踪你的调用堆栈,并查看vn_read函数,你会发现它包含这一行:

  error = VNOP_READ(vp, uio, ioflag, ctx); 

VNOP_READ函数(kpi_vfs.c)依次具有:

 _err = (*vp->v_op[vnop_read_desc.vdesc_offset])(&a); 

因此,您的问题的答案是,对于典型文件, 两个表都用于调度操作。

除此之外,

我的问题是为什么这种二元性需要[…]

并非进程可以保存文件描述符的所有内容也在文件系统中表示。 例如,管道不一定必须命名。 vnode在该上下文中没有任何意义。 所以在sys_pipe.c中,你会看到一个不同的fileops表:

 static const struct fileops pipeops = { .fo_type = DTYPE_PIPE, .fo_read = pipe_read, .fo_write = pipe_write, .fo_ioctl = pipe_ioctl, .fo_select = pipe_select, .fo_close = pipe_close, .fo_kqfilter = pipe_kqfilter, .fo_drain = pipe_drain, }; 

类似的套接字交易。

文件描述符跟踪进程的文件或对象视图的状态,该文件或对象允许类似文件的操作。 诸如文件中的位置等等 – 不同的进程可以打开相同的文件,并且它们必须各自具有自己的读/写位置 – 因此vnode:fileglob是1:多关系。

同时,使用vnode对象来跟踪文件系统中的对象以外的东西也没有任何意义。 此外,v_op表是特定于文件系统的,而vn_read / VNOP_READ包含适用于在文件系统中表示的任何文件的代码。

总而言之,它们实际上只是I / O堆栈中的不同层。