Coda 内核-金星接口

注意

这是一篇描述 Coda 组件的技术文档之一——本文档描述了客户端内核-金星接口。

更多信息

运行 Coda 所需的用户级软件

要运行 Coda,你需要为客户端获取一个用户级缓存管理器,名为 Venus,以及用于操作 ACL、登录等的工具。客户端需要在内核配置中选择 Coda 文件系统。

服务器需要一个用户级服务器,目前不依赖内核支持。

金星内核接口

Peter J. Braam

v1.0,1997 年 11 月 9 日

本文档描述了金星和内核级文件系统代码之间为 Coda 文件系统的运行所需的通信。本文档版本旨在描述当前接口(版本 1.0)以及我们设想的改进。

1. 引言

Coda 分布式文件系统中的一个关键组件是缓存管理器,金星。

当启用 Coda 的系统上的进程访问 Coda 文件系统中的文件时,请求将定向到操作系统中的文件系统层。操作系统将与金星通信以服务于该进程的请求。金星管理一个持久的客户端缓存,并向 Coda 文件服务器和相关服务器(例如身份验证服务器)发出远程过程调用,以服务于从操作系统接收的这些请求。当金星服务完一个请求时,它会向操作系统回复适当的返回码,以及与该请求相关的其他数据。可选地,Coda 的内核支持可以维护最近处理的请求的迷你缓存,以限制与金星的交互次数。当其迷你缓存中的元素不再有效时,金星具有通知内核的功能。

本文档精确地描述了内核和金星之间的这种通信。所谓的向上调用和向下调用的定义将给出它们处理的数据的格式。我们还将描述由调用产生的语义不变量。

历史上,Coda 是在 Mach 2.6 中的 BSD 文件系统中实现的。内核和金星之间的接口与 BSD VFS 接口非常相似。提供了类似的功能,参数和返回数据的格式与 BSD VFS 非常相似。这为在 BSD 系统中实现 Coda 的内核级文件系统驱动程序提供了一个几乎自然的开发环境。然而,其他操作系统(例如 Linux 和 Windows 95 和 NT)具有具有不同接口的虚拟文件系统。

为了在这些系统上实现 Coda,需要对金星/内核协议进行一些逆向工程。此外,人们发现其他系统可以从对协议的某些小优化和修改中获益匪浅。为了促进这项工作并使未来的移植更容易,应该详细记录金星和内核之间的通信。这是本文档的目的。

2. 服务 Coda 文件系统调用

对 Coda 文件系统服务的请求的服务起源于一个访问 Coda 文件的进程 P。它进行一个系统调用,该调用会陷入 OS 内核。陷入内核的此类调用的示例包括 Unix 上下文中的 readwriteopenclosecreatemkdirrmdirchmod。Win32 环境中存在类似的调用,并命名为 CreateFile

通常,操作系统在虚拟文件系统(VFS)层中处理请求,在 NT 中命名为 I/O 管理器,在 Windows 95 中命名为 IFS 管理器。VFS 负责请求的部分处理,并负责定位将服务于请求的部分的特定文件系统。通常,路径中的信息有助于定位正确的文件系统驱动程序。有时,在进行大量预处理后,VFS 开始调用文件系统驱动程序中导出的例程。这是文件系统特定请求处理开始的地方,Coda 特定内核代码在此发挥作用。

Coda 的文件系统层必须暴露和实现多个接口。首先,VFS 必须能够对 Coda 文件系统层进行所有必要的调用,因此 Coda 文件系统驱动程序必须暴露在操作系统中适用的 VFS 接口。这些接口在操作系统之间差异很大,但共享诸如读取/写入以及创建和删除对象的功能。Coda 文件系统层通过调用缓存管理器金星提供的一个或多个定义良好的服务来服务此类 VFS 请求。当来自金星的回复返回到文件系统驱动程序后,VFS 调用的服务将继续进行,并以回复内核的 VFS 结束。最后,VFS 层返回到进程。

由于此设计,文件系统驱动程序暴露的基本接口必须允许金星管理消息流量。特别是,金星必须能够检索和放置消息,并被通知新消息的到达。通知必须通过一种不会阻塞金星的机制进行,因为即使没有消息等待或正在处理,金星也必须处理其他任务。

Coda 文件系统驱动程序的接口

此外,文件系统层还提供了用户进程和金星之间进行通信的特殊路径,称为 pioctl 接口。pioctl 接口用于 Coda 特定服务,例如请求有关金星管理的持久缓存的详细信息。在这里,内核的参与是最小的。它识别调用进程并将信息传递给金星。当金星回复时,响应将以未修改的形式传递回调用者。

最后,金星允许内核文件系统驱动程序缓存来自某些服务的结果。这样做是为了避免过多的上下文切换,并实现高效的系统。但是,金星可能会获取信息(例如来自网络的信息),这意味着必须刷新或替换缓存的信息。然后,金星会对 Coda 文件系统层进行向下调用,以请求刷新或更新缓存。内核文件系统驱动程序同步处理此类请求。

在这些接口中,VFS 接口和放置、接收和通知消息的功能是特定于平台的。我们将不介绍导出到 VFS 层的调用,但我们将说明消息交换机制的要求。

3. 消息层

在最低级别,金星和文件系统驱动程序之间的通信通过消息进行。请求 Coda 文件服务的进程与金星之间的同步依赖于阻塞和唤醒进程。Coda 文件系统驱动程序代表进程 P 处理 VFS 和 pioctl 请求,为金星创建消息,等待回复,最后返回到调用者。消息交换的实现是特定于平台的,但语义(到目前为止)似乎普遍适用。数据缓冲区由文件系统驱动程序在内核内存中代表 P 创建,并复制到金星的用户内存中。

文件系统驱动程序在服务 P 时,会对金星进行向上调用。通过创建消息结构将此类向上调用调度到金星。该结构包含 P 的标识、消息序列号、请求的大小以及指向请求内核内存中数据的指针。由于数据缓冲区被重用来保存来自金星的回复,因此有一个用于回复大小的字段。消息中的标志字段用于精确记录消息的状态。其他平台相关的结构涉及指向队列上消息位置的指针和指向同步对象的指针。在向上调用例程中,消息结构被填充,标志设置为 0,并将其放置在挂起队列中。调用向上调用的例程负责分配数据缓冲区;其结构将在下一节中描述。

必须存在一个工具来通知金星消息已创建,并使用操作系统中可用的同步对象来实现。此通知在进程 P 的向上调用上下文中完成。当消息在挂起队列中时,进程 P 无法在向上调用中继续。必须暂停 P 在文件系统请求例程中的(内核模式)处理,直到金星回复为止。因此,P 中的调用线程在向上调用中被阻塞。消息结构中的指针将定位 P 正在睡眠的同步对象。

金星检测到有消息到达的通知,文件系统驱动程序允许金星使用 getmsg_from_kernel 调用检索消息。此操作在内核中通过将消息放入正在处理的消息队列并将标志设置为 READ 来完成。金星会传递数据缓冲区的内容。getmsg_from_kernel 调用现在返回,金星处理请求。

在稍后的某个时间点,文件系统驱动程序会收到来自金星的消息,即当金星调用 sendmsg_to_kernel 时。此时,Coda 文件系统驱动程序会查看消息的内容,并判断

  • 该消息是否是针对挂起线程 P 的回复。如果是,则它将消息从处理队列中删除,并将消息标记为 WRITTEN。最后,文件系统驱动程序取消阻塞 P(仍在金星的内核模式上下文中),并且 sendmsg_to_kernel 调用返回给金星。进程 P 将在某个时间点被调度,并继续使用来自金星的回复替换数据缓冲区来处理其向上调用。

  • 该消息是一个 向下调用。向下调用是金星向文件系统驱动程序的请求。文件系统驱动程序立即处理请求(通常是缓存驱逐或替换),并在处理完成后返回 sendmsg_to_kernel。

现在 P 唤醒并继续处理向上调用。有一些微妙之处需要考虑。首先,P 将确定它是否在向上调用中被来自其他来源的信号唤醒(例如尝试终止 P),或者通常情况下是金星在 sendmsg_to_kernel 调用中唤醒。在正常情况下,向上调用例程将释放消息结构并返回。文件系统例程可以继续进行其处理。

睡眠和 IPC 安排

如果进程 P 被信号唤醒,而不是被 Venus 唤醒,它会首先查看 flags 字段。如果消息尚未被 READ,则进程 P 可以处理其信号,而无需通知 Venus。如果 Venus 已 READ,并且该请求不应被处理,则 P 可以向 Venus 发送信号消息,指示它应该忽略之前的消息。此类信号会被放入队列头部,并由 Venus 首先读取。如果消息已被标记为 WRITTEN,则停止处理为时已晚。VFS 例程现在将继续。(-- 如果 VFS 请求涉及多个 upcall,这可能会导致复杂的状态,可以在消息结构中添加一个额外的字段“handle_signals”,以指示已通过不可返回的点。--)

3.1. 实现细节

此机制的 Unix 实现是通过实现与 Coda 关联的字符设备来实现的。Venus 通过读取设备来检索消息,通过写入发送回复,并通过设备文件描述符上的 select 系统调用进行通知。进程 P 会在可中断的等待队列对象上保持等待。

在 Windows NT 和 DPMI Windows 95 实现中,使用了 DeviceIoControl 调用。DeviceIoControl 调用旨在通过 OPCODES 将缓冲区从用户内存复制到内核内存。sendmsg_to_kernel 作为同步调用发出,而 getmsg_from_kernel 调用是异步的。Windows EventObjects 用于消息到达的通知。进程 P 在 NT 中保持在 KernelEvent 对象上等待,在 Windows 95 中保持在信号量上等待。

4. 调用级别的接口

本节描述了 Coda FS 驱动程序可以对 Venus 进行的 upcall。每个 upcall 都使用了两个结构:inputArgs 和 outputArgs。以伪 BNF 形式,这些结构采用以下形式

struct inputArgs {
    u_long opcode;
    u_long unique;     /* Keep multiple outstanding msgs distinct */
    u_short pid;                 /* Common to all */
    u_short pgid;                /* Common to all */
    struct CodaCred cred;        /* Common to all */

    <union "in" of call dependent parts of inputArgs>
};

struct outputArgs {
    u_long opcode;
    u_long unique;       /* Keep multiple outstanding msgs distinct */
    u_long result;

    <union "out" of call dependent parts of inputArgs>
};

在继续之前,让我们阐明各个字段的作用。inputArgs 以 opcode 开头,该 opcode 定义了从 Venus 请求的服务类型。目前大约有 30 个 upcall,我们将在后面讨论。unique 字段用唯一编号标记 inputArg,该编号将唯一标识该消息。传递了进程和进程组 ID。最后,包含了调用者的凭据。

在深入研究具体调用之前,我们需要讨论内核和 Venus 共享的各种数据结构。

4.1. 内核和 Venus 共享的数据结构

CodaCred 结构定义了为调用进程设置的各种用户和组 ID。vuid_t 和 vgid_t 是 32 位无符号整数。它还定义了数组中的组成员资格。在 Unix 上,CodaCred 已被证明足以实现 Coda 的良好安全语义,但当 Windows 环境成熟时,该结构可能需要进行修改

struct CodaCred {
    vuid_t cr_uid, cr_euid, cr_suid, cr_fsuid; /* Real, effective, set, fs uid */
    vgid_t cr_gid, cr_egid, cr_sgid, cr_fsgid; /* same for groups */
    vgid_t cr_groups[NGROUPS];        /* Group membership for caller */
};

注意

我们是否需要在 Venus 中使用 CodaCred 值得怀疑。最后,Venus 不知道组,尽管它会使用默认的 uid/gid 创建文件。也许组成员资格列表是多余的。

下一个项目是用于标识 Coda 文件的基本标识符 ViceFid。文件的 fid 唯一地定义了 Coda 文件系统中单元格内的文件或目录 [1]

typedef struct ViceFid {
    VolumeId Volume;
    VnodeId Vnode;
    Unique_t Unique;
} ViceFid;

每个组成字段:VolumeId、VnodeId 和 Unique_t 都是 32 位无符号整数。我们设想需要添加一个额外的字段来标识 Coda 单元格;这可能采用 IPv6 大小的 IP 地址的形式,通过 DNS 命名 Coda 单元格。

Venus 和内核之间共享的下一个重要结构是文件的属性。以下结构用于交换信息。它具有用于未来扩展的空间,例如支持设备文件(目前在 Coda 中不存在)

struct coda_timespec {
        int64_t         tv_sec;         /* seconds */
        long            tv_nsec;        /* nanoseconds */
};

struct coda_vattr {
        enum coda_vtype va_type;        /* vnode type (for create) */
        u_short         va_mode;        /* files access mode and type */
        short           va_nlink;       /* number of references to file */
        vuid_t          va_uid;         /* owner user id */
        vgid_t          va_gid;         /* owner group id */
        long            va_fsid;        /* file system id (dev for now) */
        long            va_fileid;      /* file id */
        u_quad_t        va_size;        /* file size in bytes */
        long            va_blocksize;   /* blocksize preferred for i/o */
        struct coda_timespec va_atime;  /* time of last access */
        struct coda_timespec va_mtime;  /* time of last modification */
        struct coda_timespec va_ctime;  /* time file changed */
        u_long          va_gen;         /* generation number of file */
        u_long          va_flags;       /* flags defined for file */
        dev_t           va_rdev;        /* device special file represents */
        u_quad_t        va_bytes;       /* bytes of disk space held by file */
        u_quad_t        va_filerev;     /* file modification number */
        u_int           va_vaflags;     /* operations flags, see below */
        long            va_spare;       /* remain quad aligned */
};

4.2. pioctl 接口

应用程序可以通过 pioctl 接口发出特定于 Coda 的请求。pioctl 实现为虚拟文件 /coda/.CONTROL 上的普通 ioctl。pioctl 调用打开此文件,获取文件句柄并发出 ioctl 调用。最后,它关闭文件。

内核在此中的参与仅限于提供打开和关闭以及传递 ioctl 消息的功能,并验证 pioctl 数据缓冲区中的路径是否是 Coda 文件系统中的文件。

内核收到如下形式的数据包

struct {
    const char *path;
    struct ViceIoctl vidata;
    int follow;
} data;

其中

struct ViceIoctl {
        caddr_t in, out;        /* Data to be transferred in, or out */
        short in_size;          /* Size of input buffer <= 2K */
        short out_size;         /* Maximum size of output buffer, <= 2K */
};

该路径必须是 Coda 文件,否则不会发出 ioctl upcall。

注意

数据结构和代码很混乱。我们需要清理一下。

现在我们开始记录各个调用:

4.3. root

参数

输入

输出

struct cfs_root_out {
    ViceFid VFid;
} cfs_root;
描述

在 Coda 文件系统初始化期间,会向 Venus 发出此调用。如果结果为零,则 cfs_root 结构包含 Coda 文件系统根的 ViceFid。如果生成非零结果,则其值是平台相关的错误代码,指示 Venus 在查找 Coda 文件系统根时遇到的困难。

4.4. lookup

摘要

查找目录中对象的 ViceFid 和类型(如果存在)。

参数

输入

struct  cfs_lookup_in {
    ViceFid     VFid;
    char        *name;          /* Place holder for data. */
} cfs_lookup;

输出

struct cfs_lookup_out {
    ViceFid VFid;
    int vtype;
} cfs_lookup;
描述

发出此调用以确定目录条目的 ViceFid 和文件类型。请求的目录条目带有名称“name”,Venus 将搜索由 cfs_lookup_in.VFid 标识的目录。结果可能表明该名称不存在,或者在查找该名称时遇到困难(例如,由于断开连接)。如果结果为零,则字段 cfs_lookup_out.VFid 包含目标的 ViceFid,而 cfs_lookup_out.vtype 包含 coda_vtype,表示该名称指定的对象的类型。

该对象的名称是一个 8 位字符串,最大长度为 CFS_MAXNAMLEN,当前设置为 256(包括 0 终止符。)

重要的是要意识到 Venus 会按位或字段 cfs_lookup.vtype 与 CFS_NOCACHE,以指示该对象不应放入内核名称缓存中。

注意

vtype 的类型目前是错误的。它应该是 coda_vtype。Linux 不注意 CFS_NOCACHE。它应该注意。

4.5. getattr

摘要 获取文件的属性。

参数

输入

struct cfs_getattr_in {
    ViceFid VFid;
    struct coda_vattr attr; /* XXXXX */
} cfs_getattr;

输出

struct cfs_getattr_out {
    struct coda_vattr attr;
} cfs_getattr;
描述

此调用返回由 fid 标识的文件的属性。

错误

如果具有 fid 的对象不存在、无法访问或者调用者没有获取属性的权限,则可能会发生错误。

注意

许多内核 FS 驱动程序(Linux、NT 和 Windows 95)都需要获取属性以及 fid,以实例化内部“inode”或“FileHandle”。通过在 Venus/内核交互级别和 RPC 级别上都合并 lookup 和 getattr 调用,可以在此类系统上显著提高性能。

输入参数中包含的 vattr 结构是多余的,应该删除。

4.6. setattr

摘要

设置文件的属性。

参数

输入

struct cfs_setattr_in {
    ViceFid VFid;
    struct coda_vattr attr;
} cfs_setattr;

输出

描述

attr 结构填充了要以 BSD 样式更改的属性。除了设置为 VNON 的 vtype 外,未更改的属性设置为 -1。其他属性设置为要分配的值。FS 驱动程序可能请求更改的唯一属性是 mode、owner、groupid、atime、mtime 和 ctime。返回值指示成功或失败。

错误

可能会发生各种错误。该对象可能不存在、可能无法访问,或者 Venus 可能未授予权限。

4.7. access

参数

输入

struct cfs_access_in {
    ViceFid     VFid;
    int flags;
} cfs_access;

输出

描述

验证是否允许访问由 VFid 标识的对象的由标志描述的操作。结果指示是否将授予访问权限。重要的是要记住,Coda 使用 ACL 来强制执行保护,并且最终是服务器而不是客户端强制执行系统的安全性。此调用的结果将取决于用户是否持有令牌。

错误

该对象可能不存在,或者描述保护的 ACL 可能无法访问。

4.8. create

摘要

调用以创建文件

参数

输入

struct cfs_create_in {
    ViceFid VFid;
    struct coda_vattr attr;
    int excl;
    int mode;
    char        *name;          /* Place holder for data. */
} cfs_create;

输出

struct cfs_create_out {
    ViceFid VFid;
    struct coda_vattr attr;
} cfs_create;
描述

调用此 upcall 以请求创建文件。该文件将在由 VFid 标识的目录中创建,其名称将为 name,模式将为 mode。如果设置了 excl,则如果该文件已存在,将返回错误。如果 attr 中的 size 字段设置为零,则该文件将被截断。文件的 uid 和 gid 是通过使用宏 CRTOUID 将 CodaCred 转换为 uid 来设置的(此宏是平台相关的)。成功后,将返回该文件的 VFid 和属性。Coda FS 驱动程序通常会为新对象在内核级别实例化 vnode、inode 或文件句柄。

错误

可能会发生各种错误。权限可能不足。如果该对象存在且不是文件,则在 Unix 下会返回错误 EISDIR。

注意

参数的打包效率非常低,并且似乎表明系统调用 creat 和 VFS 操作 create 之间存在混淆。VFS 操作 create 仅在创建新对象时调用。此 create 调用与 Unix 中的调用不同之处在于,它不会被调用以返回文件描述符。截断和排他选项以及模式可以像 Unix 下一样简单地成为模式的一部分。不应有 flags 参数;这在 open (2) 中用于返回 READ 或 WRITE 模式的文件描述符。

还应该返回目录的属性,因为大小和 mtime 发生了更改。

4.9. mkdir

摘要

创建新目录。

参数

输入

struct cfs_mkdir_in {
    ViceFid     VFid;
    struct coda_vattr attr;
    char        *name;          /* Place holder for data. */
} cfs_mkdir;

输出

struct cfs_mkdir_out {
    ViceFid VFid;
    struct coda_vattr attr;
} cfs_mkdir;
描述

此调用类似于 create,但会创建目录。在创建时,仅使用输入参数中的 mode 字段。成功创建后,返回的 attr 包含新目录的属性。

错误

与 create 相同。

注意

输入参数应该更改为 mode 而不是属性。

应该返回父目录的属性,因为大小和 mtime 发生了更改。

4.12. remove

摘要

删除文件

参数

输入

struct cfs_remove_in {
    ViceFid     VFid;
    char        *name;          /* Place holder for data. */
} cfs_remove;

输出

描述

删除由 VFid 标识的目录中名为 cfs_remove_in.name 的文件。

注意

应该返回该目录的属性,因为其修改时间和大小可能会更改。

4.13. rmdir

摘要

删除目录

参数

输入

struct cfs_rmdir_in {
    ViceFid     VFid;
    char        *name;          /* Place holder for data. */
} cfs_rmdir;

输出

描述

从由 VFid 标识的目录中删除名为 “name” 的目录。

注意

应该返回父目录的属性,因为其修改时间和大小可能会更改。

4.15. open

摘要

打开文件。

参数

输入

struct cfs_open_in {
    ViceFid     VFid;
    int flags;
} cfs_open;

输出

struct cfs_open_out {
    dev_t       dev;
    ino_t       inode;
} cfs_open;
描述

此请求要求 Venus 将由 VFid 标识的文件放置在其缓存中,并注意调用进程希望使用 open(2) 中的标志打开该文件。对于 Unix 和 Windows 系统,返回给内核的值是不同的。对于 Unix 系统,Coda FS 驱动程序会收到容器文件的设备和 inode 号,它们分别位于 dev 和 inode 字段中。对于 Windows,容器文件的路径会返回给内核。

注意

目前,cfs_open_out 结构尚未正确调整以处理 Windows 的情况。最好实现两个 upcall,一个用于打开以容器文件名为目标的 upcall,另一个用于打开以容器文件 inode 为目标的 upcall。

4.16. close

摘要

关闭文件,并在服务器上更新它。

参数

输入

struct cfs_close_in {
    ViceFid     VFid;
    int flags;
} cfs_close;

输出

描述

关闭由 VFid 标识的文件。

注意

flags 参数是伪造的,未使用。但是,Venus 的代码有空间来处理 execp 输入字段,可能应该使用此字段来通知 Venus 该文件已关闭但仍被内存映射以供执行。Venus vproc_vfscalls 中有关于获取数据与不获取数据的注释。这似乎很傻。如果要关闭文件,则容器文件中的数据应为新数据。在这里,execp 标志可能会产生混淆:目前,Venus 可能会认为当文件仍被内存映射时可以从缓存中刷新该文件。这需要理解。

4.17. ioctl

摘要

对文件执行 ioctl。这包括 pioctl 接口。

参数

输入

struct cfs_ioctl_in {
    ViceFid VFid;
    int cmd;
    int len;
    int rwflag;
    char *data;                 /* Place holder for data. */
} cfs_ioctl;

输出

struct cfs_ioctl_out {
    int len;
    caddr_t     data;           /* Place holder for data. */
} cfs_ioctl;
描述

对文件执行 ioctl 操作。command、len 和 data 参数照常填写。Venus 不使用 flags。

注意

另一个伪造的参数。未使用 flags。Venus 代码中关于 PREFETCHING 的业务是什么?

4.18. rename

摘要

重命名 fid。

参数

输入

struct cfs_rename_in {
    ViceFid     sourceFid;
    char        *srcname;
    ViceFid destFid;
    char        *destname;
} cfs_rename;

输出

描述

将源 Fid 目录中名为 srcname 的对象重命名为目标 Fid 目录中的 destname。重要的是名称 srcname 和 destname 是以 0 结尾的字符串。Unix 内核中的字符串并不总是以 null 结尾。

4.19. readdir

摘要

读取目录条目。

参数

输入

struct cfs_readdir_in {
    ViceFid     VFid;
    int count;
    int offset;
} cfs_readdir;

输出

struct cfs_readdir_out {
    int size;
    caddr_t     data;           /* Place holder for data. */
} cfs_readdir;
描述

从 VFid 中读取目录条目,从 offset 开始,最多读取 count 个字节。在 data 中返回数据,并在 size 中返回大小。

注意

不使用此调用。Readdir 操作利用容器文件。我们将在即将进行的目录改造期间重新评估这一点。

4.20. vget

摘要

指示 Venus 执行 FSDB->Get。

参数

输入

struct cfs_vget_in {
    ViceFid VFid;
} cfs_vget;

输出

struct cfs_vget_out {
    ViceFid VFid;
    int vtype;
} cfs_vget;
描述

此 upcall 要求 Venus 对由 VFid 标记的 fsobj 执行 get 操作。

注意

不使用此操作。但是,它非常有用,因为它可用于处理读/写内存映射文件。可以使用 vget 将这些文件“固定”在 Venus 缓存中,并使用 inactive 释放它们。

4.21. fsync

摘要

告诉 Venus 更新文件的 RVM 属性。

参数

输入

struct cfs_fsync_in {
    ViceFid VFid;
} cfs_fsync;

输出

描述

要求 Venus 更新对象 VFid 的 RVM 属性。这应作为内核级 fsync 类型调用的一部分进行调用。结果指示同步是否成功。

注意

Linux 未实现此调用。它应该实现。

4.22. inactive

摘要

告诉 Venus vnode 不再使用。

参数

输入

struct cfs_inactive_in {
    ViceFid VFid;
} cfs_inactive;

输出

描述

此操作返回 EOPNOTSUPP。

注意

或许应该删除它。

4.23. rdwr

摘要

从文件中读取或写入

参数

输入

struct cfs_rdwr_in {
    ViceFid     VFid;
    int rwflag;
    int count;
    int offset;
    int ioflag;
    caddr_t     data;           /* Place holder for data. */
} cfs_rdwr;

输出

struct cfs_rdwr_out {
    int rwflag;
    int count;
    caddr_t     data;   /* Place holder for data. */
} cfs_rdwr;
描述

此 upcall 要求 Venus 从文件中读取或写入。

注意

应该删除它,因为它违反了 Coda 哲学,即读/写操作永远不会到达 Venus。有人告诉我该操作不起作用。当前未使用。

4.24. odymount

摘要

允许在一个 Unix 挂载点上挂载多个 Coda “文件系统”。

参数

输入

struct ody_mount_in {
    char        *name;          /* Place holder for data. */
} ody_mount;

输出

struct ody_mount_out {
    ViceFid VFid;
} ody_mount;
描述

要求 Venus 返回名为 name 的 Coda 系统的 rootfid。该 fid 在 VFid 中返回。

注意

此调用由 David 用于动态集。应该删除它,因为它会导致 VFS 挂载区域中出现指针丛林。Coda 本身未使用。Venus 未实现此调用。

4.25. ody_lookup

摘要

查找某些内容。

参数

输入

不相关

输出

不相关

注意

删除它。Venus 未实现此调用。

4.26. ody_expand

摘要

在动态集中展开某些内容。

参数

输入

不相关

输出

不相关

注意

删除它。Venus 未实现此调用。

4.27. prefetch

摘要

预取动态集。

参数

输入

未记录。

输出

未记录。

描述

Venus worker.cc 支持此调用,尽管它被指出不起作用。这并不奇怪,因为内核不支持它。(ODY_PREFETCH 不是已定义的操作)。

注意

删除它。它不起作用,Coda 也不使用它。

4.28. signal

摘要

向 Venus 发送关于 upcall 的信号。

参数

输入

输出

不适用。

描述

这是一个带外 upcall,用于通知 Venus 调用进程在 Venus 从输入队列读取消息后接收到信号。Venus 应该清理操作。

错误

不给出回复。

注意

我们需要更好地了解 Venus 需要清理什么,以及它是否正确地执行此操作。我们还需要正确处理每个系统调用多个 upcall 的情况。重要的是要知道在内核负责通知 Venus 清理(例如,open 绝对是这样一种状态更改,但许多其他状态更改可能不是)的 upcall 之后,Venus 中发生了哪些状态更改。

5. 小缓存和 downcall

Coda FS 驱动程序可以缓存查找和访问 upcall 的结果,以限制 upcall 的频率。Upcall 的代价是需要发生进程上下文切换。缓存信息的对应物是 Venus 将通知 FS 驱动程序必须刷新或重命名缓存的条目。

内核代码通常必须维护一个结构,该结构将内部文件句柄(在 BSD 中称为 vnode,在 Linux 中称为 inode,在 Windows 中称为 FileHandle)与 Venus 维护的 ViceFid 链接起来。原因是需要频繁地来回转换,以便进行 upcall 并使用 upcall 的结果。这种链接对象称为 cnode。

当前的小缓存实现具有记录以下内容的缓存条目

  1. 文件的名称

  2. 包含对象的目录的 cnode

  3. 允许查找的 CodaCred 列表。

  4. 对象的 cnode

Coda FS 驱动程序中的查找调用可以通过传递其名称、目录和调用者的 CodaCred,从缓存中请求所需对象的 cnode。缓存将返回 cnode 或指示找不到该 cnode。当 Coda FS 驱动程序修改或删除对象时,必须小心地使缓存条目无效。

当 Venus 获得的信息表明缓存条目不再有效时,它将向内核进行 downcall。Downcall 由 Coda FS 驱动程序截获,并导致如下所述的缓存失效。除非 downcall 数据无法读取到内核内存中,否则 Coda FS 驱动程序不会返回错误。

5.1. INVALIDATE

没有关于此调用的信息。

5.2. FLUSH

参数

摘要

完全刷新名称缓存。

描述

Venus 在启动时以及死亡时发出此调用。这是为了防止保存过时的缓存信息。某些操作系统允许动态关闭内核名称缓存。完成此操作后,将进行此 downcall。

5.3. PURGEUSER

参数
struct cfs_purgeuser_out {/* CFS_PURGEUSER is a venus->kernel call */
    struct CodaCred cred;
} cfs_purgeuser;
描述

删除缓存中携带 Cred 的所有条目。当用户的令牌过期或被刷新时,会发出此调用。

5.4. ZAPFILE

参数
struct cfs_zapfile_out {  /* CFS_ZAPFILE is a venus->kernel call */
    ViceFid CodaFid;
} cfs_zapfile;
描述

删除具有(目录 vnode,名称)对的所有条目。这是由于 vnode 的缓存属性失效而发出的。

注意

在 NetBSD 和 Mach 中调用未正确命名。小缓存 zapfile 例程采用不同的参数。Linux 未正确实现属性的失效。

5.5. ZAPDIR

参数
struct cfs_zapdir_out {   /* CFS_ZAPDIR is a venus->kernel call */
    ViceFid CodaFid;
} cfs_zapdir;
描述

删除位于目录 CodaFid 中的缓存中的所有条目,以及此目录的所有子项。当 Venus 接收到目录的回调时,会发出此调用。

5.6. ZAPVNODE

参数
struct cfs_zapvnode_out { /* CFS_ZAPVNODE is a venus->kernel call */
    struct CodaCred cred;
    ViceFid VFid;
} cfs_zapvnode;
描述

删除缓存中携带 cred 和 VFid 作为参数的所有条目。此 downcall 可能永远不会发出。

5.7. PURGEFID

参数
struct cfs_purgefid_out { /* CFS_PURGEFID is a venus->kernel call */
    ViceFid CodaFid;
} cfs_purgefid;
描述

刷新文件的属性。如果它是目录(奇数 vnode),则从名称缓存中清除其子项,并从名称缓存中删除该文件。

5.8. REPLACE

摘要

替换名称集合的 Fid。

参数
struct cfs_replace_out { /* cfs_replace is a venus->kernel call */
    ViceFid NewFid;
    ViceFid OldFid;
} cfs_replace;
描述

此例程将名称缓存中的 ViceFid 替换为另一个 ViceFid。添加它是为了允许 Venus 在重新集成期间,即使这些 fid 的引用计数不为零,也使用全局 fid 替换在断开连接时本地分配的临时 fid。

6. 初始化和清理

本节简要介绍 Coda FS 驱动程序在启动时以及关闭或 Venus 失败时所需的功能。在进入讨论之前,重复一遍 Coda FS 驱动程序维护以下数据是很有用的

  1. 消息队列

  2. cnode

  3. 名称缓存条目

    名称缓存条目完全属于驱动程序私有,因此可以轻松地对其进行操作。消息队列通常具有清晰的初始化和销毁点。cnode 更加微妙。用户进程在 Coda 文件系统中保持引用计数,并且清理 cnode 可能很困难。

它可以预期通过以下方式接收请求

  1. 消息子系统

  2. VFS 层

  3. pioctl 接口

    目前,pioctl 通过 VFS 用于 Coda,因此我们可以类似地对待它们。

6.1. 要求

应满足以下要求:

  1. 消息队列应具有打开和关闭例程。在 Unix 上,字符设备的打开就是这样的例程。

  • 在打开之前,不能放置任何消息。

  • 打开将删除任何仍然挂起的旧消息。

  • 关闭将通知任何正在休眠的进程,它们的 upcall 无法完成。

  • 关闭将释放消息队列分配的所有内存。

  1. 在打开时,名称缓存应初始化为空状态。

  2. 在消息队列打开之前,所有 VFS 操作都将失败。幸运的是,这可以通过确保在打开之前无法成功挂载 Coda 文件系统来实现。

  3. 在队列关闭后,任何 VFS 操作都不能成功。这里需要小心,因为一些操作(lookup、read/write、readdir)可以在没有 upcall 的情况下进行。这些必须被显式阻止。

  4. 关闭时,名称缓存应刷新并禁用。

  5. cnode 持有的所有内存都可以被释放,而无需依赖 upcall。

  6. 卸载文件系统可以在不依赖 upcall 的情况下完成。

  7. 如果 Venus 无法获取根 fid 或根 fid 的属性,则挂载 Coda 文件系统应优雅地失败。后者最好通过 Venus 在尝试挂载之前获取这些对象来实现。

注意

特别是 NetBSD 以及 Linux 尚未完全实现上述要求。为了平稳运行,需要纠正这一点。