【问题标题】:vnode and file descriptor in xnu, where does the file operation vector is storedxnu中的vnode和文件描述符,文件操作向量存放在哪里
【发布时间】:2017-11-08 21:09:04
【问题描述】:

在 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=<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) 进行。

谢谢

【问题讨论】:

    标签: c macos driver kernel-extension xnu


    【解决方案1】:

    […] 在这种情况下 操作通过 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:many 关系。

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

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

    【讨论】:

    • 您好,谢谢。还有一件事。根据您的回复,我对此事进行了更多研究,发现 VNOP_READ 调用 hfs_vop_read 这是 HFS+ 驱动程序的一部分,它本身调用 cluster_read 的集群方法,它实际上执行所有低级读取(从缓存或从磁盘)..到目前为止一切都很好,但是,我在mmap中找不到同义词,它调用了调用hfs_vnop_mmap的VNOP_MMAP,但是在这个函数中,它返回ENOTSUP“因为我们希望集群层实际上做所有真正的工作。” (引自他们的评论)...
    • 这给我留下了谁负责在 mmap 案例中读取文件的问题。当然是集群层,但是谁调用了 cluster_read 或 mmap 调用跟踪中的类似内容?
    猜你喜欢
    • 2011-06-18
    • 2016-01-27
    • 2020-08-09
    • 2012-06-10
    • 1970-01-01
    • 2014-04-25
    • 1970-01-01
    • 2016-05-04
    • 2011-01-31
    相关资源
    最近更新 更多