支持 BypassIO 操作

从 Windows 11 开始,所有微型筛选器都应添加对 BypassIO 操作的支持。 通过调用 FltFsControlFile 或 ZwFsControlFile 来请求 BypassIO 操作:

  • FSCTL_MANAGE_BYPASS_IO控件代码。
  • InputBuffer 参数指向FS_BPIO_INPUT结构中的请求特定信息。
  • 由 OutputBuffer 参数指向的调用方分配FS_BPIO_OUTPUT结构,其中系统返回操作的结果。

本页提供了每个 BypassIO 操作的详细信息。 操作请求在 FS_BPIO_INPUT 的操作成员指定为FS_BPIO_OPERATIONS值。

有关 BypassIO 的详细信息,请参阅 有关筛选器的 BypassIO。

FS_BPIO_OP_ENABLE请求

此请求可能来自用户或内核模式。 目前不支持对非缓存 写入 的 BypassIO。

FS_BPIO_OP_ENABLE 系统为给定文件启用 BypassIO 的请求,这意味着驱动程序可能不会看到该文件的所有非缓存读取。

BypassIO 是每个文件开放的概念;也就是说, FS_BPIO_OP_ENABLE 请求仅影响与启用请求关联的文件对象,并且不会更改同一文件或流上其他打开的行为。 如果发送对同一文件对象的多个启用请求,则只有第一个请求有意义,并且将忽略所有后续请求。

在驱动程序的预操作回调中:

  • 如果驱动程序可以支持给定文件的 BypassIO,则应将请求转发到堆栈中。

  • 如果驱动程序不支持给定文件的 BypassIO,则应使用以下信息调用 FltVetoBypassIo

    • 驱动程序的名称,该名称位于 FltObjects 参数指向的FLT_RELATED_OBJECTS结构中。
    • NTSTATUS 错误代码,描述在 OperationStatus 参数中否决启用请求的原因。
    • 一个唯一的描述性字符串,其中包含有关在 FailureReason 参数中否决启用请求的原因的详细信息。

    FltVetoBypassIo 编写驱动程序名称、错误代码和字符串,描述微型筛选器在FS_BPIO_OUTPUT结构中否决启用请求的原因,并将状态、筛选器提供的原因和筛选器名称的 ETW 事件写入事件日志。

如果 FltVetoBypassIo 成功,小筛选器应使用 STATUS_SUCCESS 完成FSCTL_MANAGE_BYPASS_IO;否则,它应返回 FltVetoBypassIo 返回的错误

在操作后,驱动程序可以查看其下方的所有驱动程序是否都能够支持 BypassIO。 如果是,驱动程序应保留文件所需的任何状态并继续完成处理。 筛选器和文件系统负责维护状态以正确处理可能与已启用 BypassIO 的状态不兼容的请求。

注意

文件系统堆栈中的所有筛选器都有机会在预操作期间否决 BypassIO 启用请求,但建议尽量将其启用。

文件系统自动否决对以下文件类型的 BypassIO 启用请求:

  • 目录(目录上的备用数据流可以使用 BypassIO)
  • 卷(DASD 已打开)
  • NTFS 压缩的文件
  • NTFS 加密的文件
  • 稀疏文件
  • 页面文件
  • DAX 卷上的所有文件

大多数筛选器不需要维护在特定流上启用 BypassIO 的状态。 相反,可以通过调用 FsRtlGetBypassIoOpenCount 来查询此信息。

FS_BPIO_OP_ENABLE示例:加密筛选器

当加密筛选器收到 对文件的FS_BPIO_OP_ENABLE 操作时:

  • 如果文件已加密,筛选器应调用 FltVetoBypassIo 以否决 BypassIO 操作,提供适当的状态和诊断消息,例如:

    • OpStatus = STATUS_NOT_SUPPORTED_WITH_ENCRYPTION
    • FailureReason = “不支持加密文件”
  • 如果文件当前未加密,筛选器应允许 BypassIO。 如果以后发出加密此文件的请求,筛选器可以使用 FS_BPIO_OP_STREAM_PAUSE 操作来禁用 BypassIO。

FS_BPIO_OP_DISABLE请求

此请求可能来自用户或内核模式。 它允许驱动程序清理任何关联的 BypassIO 状态。

如果以前允许在此文件上启用 BypassIO 的驱动程序,现在需要关闭对文件的 BypassIO 支持,则应使用关联的句柄将FS_BPIO_OP_DISABLE FSCTL_MANAGE_BYPASS_IO操作发送到文件系统堆栈的顶部。 出现此情况的一个示例是收到加密此文件的请求的加密驱动程序。

如果驱动程序收到 FS_BPIO_OP_DISABLE但 当前未启用 BypassIO,则它应忽略请求。 如果在当前未启用 BypassIO 的文件上发送此操作,则应将其忽略。

此操作不应失败。

FS_BPIO_OP_QUERY请求

此请求可能来自用户或内核模式。

筛选器应处理类似于FS_BPIO_OP_ENABLE操作的FS_BPIO_OP_QUERY请求,调用 FltVetoBypassIo 以适当方式使用与前面所述的相应参数中所述的诊断信息一样否决。 主要区别在于驱动程序在 QUERY 期间未进入 BypassIO ENABLE 状态。

可以在目录和卷句柄上发送FS_BPIO_OP_QUERY操作(不能在目录或卷句柄上发送FS_BPIO_OP_ENABLE请求)。

查询示例:加密筛选器

当加密筛选器收到 对文件的FS_BPIO_OP_QUERY 操作时:

  • 如果文件已加密,筛选器应调用 FltVetoBypassIo 以否决 BypassIO 操作,并提供适当的状态和诊断消息,例如:

    • OpStatus = STATUS_NOT_SUPPORTED_WITH_ENCRYPTION
    • FailureReason = “不支持加密文件”
  • 如果文件当前未加密,筛选器应成功执行查询请求。

FS_BPIO_OP_VOLUME_STACK_PAUSE请求

此请求可能来自用户或内核模式。

如果卷堆栈驱动程序以前允许在卷上启用 BypassIO,现在需要停止 BypassIO(例如,由于某些外部请求),驱动程序应将FS_BPIO_OP_VOLUME_STACK_PAUSE FSCTL_MANAGE_BYPASS_IO操作发送到卷堆栈顶部,以通知文件系统停止在此卷的卷和存储堆栈上执行 BypassIO。 文件系统从此卷中清空所有活动的 BypassIO 操作,然后返回。 然后,卷堆栈驱动程序可以处理外部请求。

所有已启用 BypassIO 的活动文件随后停止执行存储堆栈级 BypassIO 操作。 此操作请求:

  • 可以在卷句柄或给定卷的任何文件句柄上发送。
  • 可以多次发送到同一卷。
  • 如果卷上没有启用了 BypassIO 的文件,则可以发送。

BypassIO 继续在文件系统堆栈上运行。

此操作不应失败。

卷堆栈暂停示例

BitLocker 是需要对卷启用加密时使用该操作的组件的示例。

另一个示例是以下方案:假设 Volsnap 允许在没有活动卷快照的卷上启用 BypassIO。 后来,发出了创建卷快照的请求。 Volsnap 在继续操作之前执行以下操作:

  • FS_BPIO_OP_VOLUME_STACK_PAUSE 操作发送到堆栈顶部,请求系统禁用卷堆栈上的 BypassIO。 每次创建新快照时,都会执行此操作。 成功返回后,现在禁用 BypassIO 并在给定卷上清空。
  • 处理快照创建请求

然后,Volsnap 必须否决此卷上所有未来的 BPIO_OP_ENABLEBPIO_OP_QUERY 请求。

FS_BPIO_OP_VOLUME_STACK_RESUME请求

卷堆栈驱动程序将此 FSCTL 操作发送到文件系统,以恢复给定卷上的 BypassIO 处理。 当导致驱动程序发送FS_BPIO_OP_VOLUME_STACK_PAUSE不再处于活动状态的方案时,它会发送此操作。 即使当前未启用或暂停 BypassIO,也可以发送此操作。

此请求可能来自用户或内核模式。

此操作不应失败。

卷堆栈恢复示例

使用前面所述的卷堆栈暂停方案,假设该卷不再具有任何活动快照。 只有在最后一个快照消失后,Volsnap 才会发送 FS_BPIO_OP_VOLUME_STACK_RESUME

FS_BPIO_OP_STREAM_PAUSE请求

筛选器可以发送 FS_BPIO_OP_STREAM_PAUSE 操作来暂停流上的 BypassIO。 此请求可能来自用户或内核模式。 所有已启用 BypassIO 的活动文件都停止执行 BypassIO 操作。

具体而言,如果以前允许在流上启用 BypassIO 的筛选器,并且以后需要停止 BypassIO(由于外部请求(例如加密文件或目录的请求),它可以发送一个FS_BPIO_OP_STREAM_PAUSE向下筛选堆栈,以告知文件系统停止在给定流上执行 BypassIO。 筛选器不应将此操作发送到堆栈顶部。

在文件系统返回之前,它会暂停流上打开的所有 BypassIO 句柄,并在流上完成所有活动的 BypassIO 操作。 这些操作可确保在返回时,筛选器可以执行它需要执行的文件操作。

此操作可以多次发送到同一流。 如果文件系统在当前未启用 BypassIO 的流上发送,则会将其忽略。

如果筛选器执行流暂停操作,则 BypassIO 将继续在卷和存储堆栈上继续。

此操作不应失败。

流暂停示例:加密筛选器

假设加密筛选器允许在随后未加密的流上启用 BypassIO,但后来收到加密此流的请求。

在加密筛选器继续之前,它应调用 FsRtlGetBypassIoOpenCount 来确定 BypassIO 是否在此流上处于活动状态。 如果是,加密筛选器会发送一个 FS_BPIO_OP_STREAM_PAUSE 操作,要求系统禁用 BypassIO。 成功返回后,BypassIO 将被禁用并清空,因此筛选器可以安全地执行加密请求。 若要消除可能的争用条件,筛选器必须否决所有未来的FS_BPIO_OP_ENABLE,并在此加密的流上FS_BPIO_OP_QUERY请求。

FS_BPIO_OP_STREAM_RESUME请求

当导致筛选器发送FS_BPIO_OP_STREAM_PAUSE操作不再存在的情况时,筛选器会将FS_BPIO_OP_STREAM_RESUME操作发送到文件系统以恢复对给定流的 BypassIO 处理。 此请求可能来自用户或内核模式。

如果在当前未启用或暂停 BypassIO 时发送此操作,则忽略此操作。

不会对暂停和恢复进行引用计数。 相反,在恢复时,文件系统向文件系统堆栈顶部发出 FS_BPIO_OP_QUERY 请求,以确定任何剩余的筛选器是否仍在阻止。 仅当堆栈中的所有筛选器未阻止 BypassIO 时,文件系统才会恢复 BypassIO。

此操作不应失败。

流恢复示例:加密筛选器

使用前面所述的FS_BPIO_OP_STREAM_PAUSE方案,表示调用FS_BPIO_OP_STREAM_PAUSE以前加密的文件不再加密。 然后,筛选器应发送 FS_BPIO_OP_STREAM_RESUME 操作,以允许 BypassIO 在该流上恢复。

FS_BPIO_OP_GET_INFO请求

此请求可能来自用户或内核模式。 文件系统返回有关 FS_BPIO_INFO 结构中卷的 BypassIO 的信息。