Microsoft Windows Vista 中的 MUP 更改
Windows Vista 对多个 UNC 提供程序 (MUP) 实施许多更改,这些更改可能会影响网络重定向程序。
MUP 和分布式文件系统 (DFS) 客户端位于单独的二进制文件中。 MUP 组件位于 mup.sys,DFS 客户端处于 dfsc.sys。 在 Windows Server 2003、Windows XP 和 Windows 2000 上,MUP 内核组件mup.sys也包含 DFS 客户端。
Windows Vista 上定义了新的重定向程序模型:
MUP 通过调用 IoRegisterFileSystem 注册为 I/O 管理器的文件系统。
网络重定向程序使用 FsRtlRegisterUncProviderEx (Windows Vista 中引入的一个新例程)向 MUP 注册。
网络重定向程序将未命名的设备对象传递给 FsRtlRegisterUncProviderEx。
网络重定向程序将设备名称传递给 FsRtlRegisterUncProviderEx。
网络重定向程序不会向 I/O 管理器注册为文件系统, (不调用 IoRegisterFileSystem) 。
从 MUP 到网络重定向程序的所有调用(包括前缀解析、IOCTL 和 FSCL)都是在启用 APC 的情况下进行的。 从其他组件到 MUP 的所有调用都应在启用 APC 的情况下进行。 当调用与 FsRtlCancellableWaitForSingleObject 或 FsRtlCancellableWaitForMultipleObjects(Windows Vista 中引入的新例程)一起使用时,这将确保在终止发出 I/O 请求的线程时可以中止长时间的等待。
前缀解析使用 IOCTL_REDIR_QUERY_PATH_EX(Windows Vista 中引入的新 IOCTL)执行。
注册到 MUP 的网络重定向程序设备名称将成为指向 MUP 设备对象的符号链接。
对于符合 Windows Vista 重定向程序模型的网络重定向程序,MUP 在对象管理器命名空间中创建一个符号链接,其中包含网络重定向程序在调用 FsRtlRegisterUncProviderEx 时指定的设备名称。 此符号链接的目标是 MUP 设备对象 (\Device\Mup) 。
将 MUP 注册为文件系统并将网络重定向程序的设备名称作为 MUP 设备对象的符号链接的优点是,所有远程文件系统 I/O 操作(而不仅仅是基于名称的操作)都会通过 MUP。 因此,需要位于远程文件系统堆栈上的文件系统筛选器驱动程序只需附加到 MUP 设备对象即可。 文件系统筛选器驱动程序不必将提供程序设备对象名称 (\Device\LanmanRedirector 硬编码,例如,) 到其驱动程序中。 这样,文件系统筛选器驱动程序就可以监视通过单个附件向所有网络重定向程序发出的所有 I/O 操作。 这也消除了在 Windows Vista 之前文件系统筛选器驱动程序看到的重复 I/O 操作,Windows Vista 单独附加到 DFS (mup.sys) 和单个网络重定向程序 (\Device\LanmanRedirector,例如) ,以便监视两者的 I/O 操作。
附加到 MUP 设备对象的文件系统筛选器驱动程序可以有选择地筛选发送到特定网络重定向程序的流量。 在这种情况下,筛选器驱动程序通过调用 FsRtlMupGetProviderIdFromName 例程,将感兴趣的网络重定向程序的设备名称映射到提供程序标识符。 然后,筛选器驱动程序可以通过将调用 FsRtlMupGetProviderInfoFromFileObject 例程获得的提供程序标识符与相关网络控制器的提供程序标识符进行比较,来确定是否应筛选特定文件对象的流量。
对于符合 Windows Vista 重定向程序模型的网络重定向程序:
远程文件系统堆栈上的所有文件对象都解析为 MUP。 因此, IoGetDeviceAttachmentBaseRef 返回 MUP 的设备对象,而不是拥有文件对象的网络重定向程序。 但是,文件对象的内容仍归网络重定向程序所有。
IRP_MJ_CREATE颁发给网络重定向程序 (\Device\LanmanRedirector\server\share 的设备名称,例如,) 将面向该网络重定向程序,而无需通过 MUP 前缀解析,就像在 Windows Server 2003、Windows XP 和 Windows 2000 上一样。
不基于 Windows Vista RDBSS (动态或静态链接) 的网络重定向程序称为“旧重定向程序”。 这些旧版网络重定向程序包括:
为使用 FsRtlRegisterUncProvider 直接注册到 MUP 的 Windows Server 2003、Windows XP 和 Windows 2000 编写的网络重定向程序。
为 Windows Server 2003、Windows XP 和 Windows 2000 编写的网络微型重定向程序,以静态方式链接到适用于 Windows Server 2003、Windows XP 或 Windows 2000 的 rdbsslib.lib 库。
为使用 FsRtlRegisterUncProviderEx 直接注册到 MUP 的 Windows Vista 编写的网络重定向程序。
针对 Windows Vista RDBSS (rdbss.sys 动态链接的网络微型重定向程序) 自动符合 Windows Vista 重定向程序模型,因为 RDBSS 使用 FsRtlRegisterUncProviderEx 向 MUP 注册。 静态链接到 Windows Vista RDBSS (rdbsslib.lib) 的网络微型重定向程序也自动符合 Windows Vista 重定向程序模型,因为 RDBSS 使用 FsRtlRegisterUncProviderEx 向 MUP 注册。
为直接注册 MUP 的 Windows Vista 编写的旧网络重定向程序必须符合 Windows Vista 重定向程序模型。
为直接使用 FsRtlRegisterUncProvider 注册到 MUP 的 Windows Server 2003、Windows XP 和 Windows 2000 编写的网络重定向程序继续以与在 Windows Server 2003、Windows XP 和 Windows 2000 上完全相同的方式工作。 为 Windows Server 2003、Windows XP 和 Windows 2000 编写的网络微型重定向程序与适用于 Windows Server 2003、Windows XP 和 Windows 2000 的 rdbsslib.lib 库静态链接,其工作方式与在 Windows Server 2003、Windows XP 和 Windows 2000 上完全相同。 这些旧版网络重定向器和微型重定向程序表现出以下行为:
它们对监视文件系统注册的文件系统筛选器驱动程序可见。
其设备对象已命名。 设备名称不是符号链接,也不指向 \Device\MUP。
文件对象解析为网络重定向程序的命名设备对象。
MUP 仅涉及前缀解析操作。 标识网络提供程序后,MUP 会通过返回STATUS_REPARSE来“退出”。 所有后续操作都不会通过 MUP 传递。
保留此行为以防止在提供程序设备名称是指向 \Device\MUP 的符号链接时发生双重筛选。 出现这种双重筛选的原因如下:
文件系统筛选器驱动程序已附加到 \Device\MUP。
文件系统筛选器驱动程序附加到任何注册文件系统。 由于使用命名设备对象的网络重定向程序将自身注册为文件系统,因此文件系统筛选器驱动程序最终会筛选相同的 I/O 两次。
在 Windows Vista 上对 MUP 进行调用和从 MUP 调用时启用了 APC,这具有以下影响:
请务必根据需要保护从 MUP 调用的代码路径,防止通过适当的方式(尤其是IOCTL_REDIR_QUERY_PATH处理程序)挂起线程。 请注意,线程挂起是一种可能持续很长时间的“无限等待”操作。
请务必确保涉及用户模式线程的任何“等待 I/O”操作 (而不是系统线程) 始终使用“可取消等待”。 有关详细信息,请参阅 FsRtlCancellableWaitForSingleObject 和 FsRtlCancellableWaitForMultipleObjects 例程。
当持有某些重要锁的线程被挂起时,可能会出现死锁。 在出现任意挂起的用户模式线程的情况下运行测试非常重要,以便针对死锁条件检查。
请务必运行测试,以验证“等待 I/O 操作”是否确实可取消,以及用户模式应用程序是否可以足够快地终止线程,以便应用程序在尝试终止上述线程时看起来不会处于“无响应”状态。
Windows Vista 上的 MUP 使用的前缀缓存大小和超时现在由以下注册表值控制:
PrefixCacheSizeInKB
PrefixCacheTimeoutInSeconds。
无需重新启动即可动态更改这些注册表值。 这些注册表值位于以下注册表项下:
HKLM\System\CurrentControlSet\Services\Mup\Parameters.
ProviderOrder 注册表值,用于确定 MUP 向单个重定向程序发出前缀解析请求的顺序,无需重新启动系统即可动态更改。 此注册表值位于以下注册表项下:
HKLM\CurrentControlSet\Control\NetworkProvider\Order
在 Windows Vista 上,MUP 执行前缀解析的方式不同,具体取决于网络重定向程序是通过调用 FsRtlRegisterUncProvider 还是 FsRtlRegisterUncProviderEx 向 MUP 注册的。 通过调用 FsRtlRegisterUncProvider 注册到 MUP 的旧网络重定向程序将收到前缀解析 IOCTL_REDIR_QUERY_PATH 请求。 此方法与 Windows Server 2003、Windows XP 和 Windows 2000 上使用的方法相同。
符合 Windows Vista 重定向程序模型并通过调用 FsRtlRegisterUncProviderEx 注册到 MUP 的网络重定向程序将收到前缀解析 IOCTL_REDIR_QUERY_PATH_EX 请求。 请注意,在 Windows Vista 上,使用 rdbsslib.lib 静态链接或与 rdbss.sys 动态链接的网络微型重定向程序将通过 RDBSS 间接调用 FsRtlRegisterUncProviderEx 。
IOCTL_REDIR_QUERY_PATH_EX的输入和输出缓冲区如下所示:
参数的可用位置 | 数据结构格式 | |
输入缓冲区 |
IrpSp-> Parameters.DeviceIoControl.Type3InputBuffer |
QUERY_PATH_REQUEST_EX |
输出缓冲区 |
IRP-UserBuffer> |
QUERY_PATH_RESPONSE |
IOCTL 和数据结构在 ntifs.h 中定义。 缓冲区是从非分页池分配的。
网络重定向程序应仅接受此 IOCTL 的内核模式发送方,方法是验证 Irp-RequestorMode> 是否为 KernelMode。
MUP 对请求信息使用QUERY_PATH_REQUEST_EX数据结构。
typedef struct _QUERY_PATH_REQUEST_EX {
PIO_SECURITY_CONTEXT pSecurityContext;
ULONG EaLength;
PVOID pEaBuffer;
UNICODE_STRING PathName;
} QUERY_PATH_REQUEST_EX, *PQUERY_PATH_REQUEST_EX;
结构成员 | 说明 |
---|---|
pSecurityContext |
指向安全上下文的指针。 |
EaLength |
扩展属性缓冲区的长度(以字节为单位)。 |
pEaBuffer |
指向扩展属性缓冲区的指针。 |
PathName |
表单 <服务器><共享><路径>的非 NULL 终止 Unicode 字符串。 |
UNC 提供程序应将QUERY_PATH_RESPONSE数据结构用于响应信息。
typedef struct _QUERY_PATH_RESPONSE {
ULONG LengthAccepted;
} QUERY_PATH_RESPONSE, *PQUERY_PATH_RESPONSE;
结构成员 | 说明 |
---|---|
LengthAccepted |
提供程序从 QUERY_PATH_REQUEST_EX 结构的 PathName 成员中指定的 Unicode 字符串路径中声明的前缀的长度(以字节为单位)。 |
请注意,IOCTL_REDIR_QUERY_PATH_EX是 IOCTL METHOD_NEITHER。 这意味着输入和输出缓冲区可能不在同一地址。 UNC 提供程序的一个常见错误是假定输入缓冲区和输出缓冲区相同,并使用输入缓冲区指针提供响应。
当 UNC 提供程序收到IOCTL_REDIR_QUERY_PATH_EX请求时,它必须确定它是否可以处理在 QUERY_PATH_REQUEST_EX 结构的 PathName 成员中指定的 UNC 路径。 如果是这样,UNC 提供程序必须更新QUERY_PATH_RESPONSE结构的 LengthAccepted 成员,其所声明的前缀长度(以字节为单位),并使用STATUS_SUCCESS完成 IRP。 如果提供程序无法处理指定的 UNC 路径,则它必须使IOCTL_REDIR_QUERY_PATH_EX请求失败并显示相应的 NTSTATUS 错误代码,并且不得更新QUERY_PATH_RESPONSE结构的 LengthAccepted 成员。 提供程序不得在任何条件下修改任何其他成员或 PathName 字符串。
在 Windows Vista 上,基于使用 RDBSS 指示支持作为 UNC 提供程序的网络微型重定向程序将接收此前缀声明,就像它是常规树连接创建一样,类似于设置了FILE_CREATE_TREE_CONNECTION标志的用户模式 Createfile 调用。 RDBSS 将向网络微型重定向程序发送 MRxCreateSrvCall 请求,然后调用 MRxSrvCallWinnerNotify 和 MRxCreateVNetRoot。 此前缀声明不会作为对 MRxLowIOSubmit[LOWIO_OP_IOCTL] 的调用接收。 当网络微型重定向程序注册到 RDBSS 时,RDBSS 将复制网络微型重定向程序的驱动程序调度表,以指向内部 RDBSS 入口点。 然后,RDBSS 在内部接收网络微型重定向程序的此IOCTL_REDIR_QUERY_PATH_EX,并调用 MRxCreateSrvCall、 MRxSrvCallWinnerNotify 和 MRxCreateVNetRoot。 原始IOCTL_REDIR_QUERY_PATH_EX IRP 将包含在传递给 MRxCreateSrvCall 例程的RX_CONTEXT中。 此外,将修改传递给 MRxCreateSrvCall 的RX_CONTEXT中的以下成员:
即使原始 IRP 已IRP_MJ_DEVICE_CONTROL, MajorFunction 成员也设置为 IRP_MJ_CREATE。
PrefixClaim.SuppliedPathName.Buffer 成员设置为 QUERY_PATH_REQUEST_EX 结构的 PathName.Buffer 成员。
PrefixClaim.SuppliedPathName.Length 成员设置为 QUERY_PATH_REQUEST_EX 结构的 PathName.Length 成员。
Create.ThisIsATreeConnectOpen 成员设置为 TRUE。
Create.ThisIsAPrefixClaim 成员设置为 TRUE。
Create.NtCreateParameters.SecurityContext 成员设置为 QUERY_PATH_REQUEST_EX 结构的 SecurityContext 成员。
Create.EaBuffer 成员设置为 QUERY_PATH_REQUEST_EX 结构的 pEaBuffer 成员。
Create.EaLength 成员设置为 QUERY_PATH_REQUEST_EX 结构的 EaLength 成员。
Create.Flags 成员将设置RX_CONTEXT_CREATE_FLAG_UNC_NAME位。
如果网络微型重定向程序想要查看前缀声明的详细信息,则可以在传递给 MRxCreateSrvCall 的RX_CONTEXT结构中读取这些成员。 否则,如果 MRxCreateSrvCall 调用成功,它只能尝试连接到服务器共享并返回STATUS_SUCCESS。 RDBSS 将代表网络微型重定向程序发出前缀声明。