xnu中的vnode和文件描述符,文件操作向量存放在哪里
vnode and file descriptor in xnu, where does the file operation vector is stored
在 xnu 中我们有 vnode_t
全局代表文件的实体。
每个进程都可以通过设置新的文件描述符并在 fg_data
下设置 vnode 来访问文件(假设它具有正确的权限)
fp->f_fglob->fg_data = vp;
vnode 包含所有相关操作的基本操作列表,并根据文件的 FS 设置。即 HFS+ 驱动程序实现此类向量并相应地设置其 vnode。
int (**v_op)(void *); /* vnode operations vector */
这是一个函数指针向量,用于可能在 vnode 上运行的所有操作。
此外,我们有文件描述符 (fg_global) 的一部分 fileops 结构,它描述了这些函数的最小子集:
这是一个典型的定义:
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=<unavailable>, flags=<unavailable>, retval=<unavailable>) at sys_generic.c:365 [opt]
frame #3: 0xffffff801339c983 kernel`read_nocancel(p=0xffffff801a597658, uap=0xffffff801a553cc0, retval=<unavailable>) at sys_generic.c:215 [opt]
frame #4: 0xffffff8013425695 kernel`unix_syscall64(state=<unavailable>) at systemcalls.c:376 [opt]
frame #5: 0xffffff8012e9dd46 kernel`hndl_unix_scall64 + 22
我的问题是为什么需要这种对偶性,在哪些情况下操作通过 file_descriptor 向量(fg_ops)进行,在哪些情况下操作通过 vnode 向量(vp-> v_op).
谢谢
[…] in which cases the
operation works through the file_descriptor vector (fg_ops) and which
cases the operation works through the vnode vector (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);
所以你的问题的答案是,对于你的典型文件,tables 都用于调度操作。
除此之外,
My question is why does this duality needed […]
并非进程可以保存文件描述符的所有内容都在文件系统中表示。例如,管道不一定必须命名。在这种情况下,vnode 没有任何意义。所以在 sys_pipe.c 中,你会看到一个不同的 fileops table:
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,
};
套接字的类似优惠。
文件描述符跟踪允许类文件操作的文件或对象的进程视图状态。文件中的位置等 - 不同的进程可以打开相同的文件,并且它们必须各自有自己的 read/write 位置 - 所以 vnode:fileglob 是一个 1:many 关系。
与此同时,使用 vnode 对象来跟踪文件系统中对象以外的事物也没有任何意义。此外,v_op table 是特定于文件系统的,而 vn_read/VNOP_READ 包含适用于文件系统中表示的任何文件的代码。
所以总而言之,它们实际上只是 I/O 堆栈中的不同层。
在 xnu 中我们有 vnode_t
全局代表文件的实体。
每个进程都可以通过设置新的文件描述符并在 fg_data
下设置 vnode 来访问文件(假设它具有正确的权限)fp->f_fglob->fg_data = vp;
vnode 包含所有相关操作的基本操作列表,并根据文件的 FS 设置。即 HFS+ 驱动程序实现此类向量并相应地设置其 vnode。
int (**v_op)(void *); /* vnode operations vector */
这是一个函数指针向量,用于可能在 vnode 上运行的所有操作。
此外,我们有文件描述符 (fg_global) 的一部分 fileops 结构,它描述了这些函数的最小子集:
这是一个典型的定义:
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=<unavailable>, flags=<unavailable>, retval=<unavailable>) at sys_generic.c:365 [opt]
frame #3: 0xffffff801339c983 kernel`read_nocancel(p=0xffffff801a597658, uap=0xffffff801a553cc0, retval=<unavailable>) at sys_generic.c:215 [opt]
frame #4: 0xffffff8013425695 kernel`unix_syscall64(state=<unavailable>) at systemcalls.c:376 [opt]
frame #5: 0xffffff8012e9dd46 kernel`hndl_unix_scall64 + 22
我的问题是为什么需要这种对偶性,在哪些情况下操作通过 file_descriptor 向量(fg_ops)进行,在哪些情况下操作通过 vnode 向量(vp-> v_op).
谢谢
[…] in which cases the operation works through the file_descriptor vector (fg_ops) and which cases the operation works through the vnode vector (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);
所以你的问题的答案是,对于你的典型文件,tables 都用于调度操作。
除此之外,
My question is why does this duality needed […]
并非进程可以保存文件描述符的所有内容都在文件系统中表示。例如,管道不一定必须命名。在这种情况下,vnode 没有任何意义。所以在 sys_pipe.c 中,你会看到一个不同的 fileops table:
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,
};
套接字的类似优惠。
文件描述符跟踪允许类文件操作的文件或对象的进程视图状态。文件中的位置等 - 不同的进程可以打开相同的文件,并且它们必须各自有自己的 read/write 位置 - 所以 vnode:fileglob 是一个 1:many 关系。
与此同时,使用 vnode 对象来跟踪文件系统中对象以外的事物也没有任何意义。此外,v_op table 是特定于文件系统的,而 vn_read/VNOP_READ 包含适用于文件系统中表示的任何文件的代码。
所以总而言之,它们实际上只是 I/O 堆栈中的不同层。