- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
在 xnu 中,我们有 vnode_t
实体,它代表全局文件。
每个进程都可以通过设置新的文件描述符并设置fg_data下的vnode来访问文件(假设它有正确的权限)
fp->f_fglob->fg_data = vp;
vnode 包含所有相关操作的基本操作列表,并根据文件的 FS 设置。即 HFS+ 驱动程序实现此类 vector 并相应地设置其 vnode。
int (**v_op)(void *); /* vnode operations vector */
这是一个函数指针 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=<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 vector (fg_ops) 进行,哪些情况下操作通过 vnode vector (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);
所以你的问题的答案是,对于你的典型文件,两个表都用于调度操作。
有了这个,
My question is why does this duality needed […]
并非进程可以保存文件描述符的所有内容都在文件系统中表示。例如,管道不一定必须命名。在这种情况下,vnode 没有任何意义。所以在 sys_pipe.c 中,你会看到一个不同的文件操作表:
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,
};
套接字的类似交易。
文件描述符跟踪允许类文件操作的文件或对象的进程 View 状态。文件中的位置等 - 不同的进程可以打开相同的文件,并且它们必须各自有自己的读/写位置 - 所以 vnode:fileglob 是一对多的关系。
与此同时,使用 vnode 对象来跟踪文件系统中对象以外的事物也没有任何意义。此外,v_op 表是特定于文件系统的,而 vn_read/VNOP_READ 包含适用于文件系统中表示的任何文件的代码。
所以总而言之,它们实际上只是 I/O 堆栈中的不同层。
关于c - xnu中的vnode和文件描述符,文件操作 vector 存放在哪里,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44413909/
我有一个 Vagrant 盒子(ubuntu 16.04)用于开发,我做了几个apt install并在初始化后对配置文件(.ini、.cnf 等)进行了一些更改。现在,我对这个盒子和它的内容很满意。
我是一名优秀的程序员,十分优秀!