尽管有“快速删除”选项,Windows 仍延迟在小型 USB 驱动器上写入 FAT 表

尽管有“快速删除”选项,Windows 仍延迟在小型 USB 驱动器上写入 FAT 表

我发现小容量 FAT(FAT12)格式的 USB 闪存驱动器上的 FAT 写入延迟,即使驱动器的策略设置为“快速移除”。(我相信这意味着SurpriseRemovalOK设置了标志)。我捕获了通过 USB 发送到驱动器的 SCSI 命令:文件截断写入立即发生,整个文件(2 个 512 字节扇区长)随后立即写入,但随后在 FAT 更新以反映文件写入之前会有 20-90 秒的延迟。

驱动器的大小非常重要。我已经测试过,发现 15MB 及以下大小的 FAT 文件系统存在问题。在 16MB 及以上大小的文件系统上,写入不会延迟。当我在 Windows 中格式化驱动器时,我看到使用 FAT12 和 FAT16 之间的断点是 16MB。(稍后添加的注释:但 FAT12/FAT16 断点取决于簇数,而不是绝对文件系统大小)。

在 16MB 及以上容量的 U 盘上,Windows 在写入之前会发送 SCSIPrevent/Allow Medium Removal命令,要求不要移除设备。U 盘实际上会对这些请求返回失败(因为它无法保证不移除),但 Windows 还是会尝试。15MB 及以下容量的跟踪显示 Prevent/Allow Medium Removal命令。

(我在使用支持包含 Python 代码的微型 FAT 文件系统的微控制器板时发现了这个问题。当微控制器检测到对文件系统的写入时,它会等待一段时间以完成写入,然后自动重新启动并运行新编写的 Python 代码。但由于写入延迟,微控制器看到的是损坏的代码或损坏的文件系统。)

为什么尽管设置了“快速删除”,但写入 FAT 仍然延迟了这么长时间?我可以通过对驱动器执行“弹出”来强制写入,但这违背了“快速移除”的承诺。如果我提前拔出驱动器,它将有一个错误的 FAT 表。这与下面屏幕截图中关于不必使用“安全移除硬件”的声明相矛盾。这是一个错误还是我遗漏了什么?有没有办法强制立即进行所有写入,而无需手动“弹出”?

USB 驱动器设置为“快速删除”

以下是从 Wireshark/USBPcap 跟踪中截取的一段显示该问题的摘录。我截断了一个现有文件,然后写入了它的新副本。我添加了注释###。大多数对 USB 驱动器的写入发生在跟踪开始后的 5 秒左右,但最后的 FAT 写入要到 26 秒才会发生。

No.    Time  Source       Destination  Protocol  Length  Info
    ### write directory entry to truncate file
13 5.225586    host         1.2.2        USBMS    58     SCSI: Write(10) LUN: 0x00 (LBA: 0x00000041, Len: 8)
14 5.225838    host         1.2.2        USB      4123   URB_BULK out
    ### write FAT entries to truncate file
16 5.230488    host         1.2.2        USBMS    58     SCSI: Write(10) LUN: 0x00 (LBA: 0x0000003b, Len: 1)
17 5.230707    host         1.2.2        USB      539    URB_BULK out
19 5.235110    host         1.2.2        USBMS    58     SCSI: Write(10) LUN: 0x00 (LBA: 0x0000003e, Len: 1)
20 5.235329    host         1.2.2        USB      539    URB_BULK out
    ### write directory entry for 
22 5.252672    host         1.2.2        USBMS    58     SCSI: Write(10) LUN: 0x00 (LBA: 0x00000041, Len: 8)
23 5.252825    host         1.2.2        USB      4123   URB_BULK out
    ### write out file data (2 sectors of 512 bytes)
25 5.257416    host         1.2.2        USBMS    58     SCSI: Write(10) LUN: 0x00 (LBA: 0x000000c1, Len: 2)
26 5.257572    host         1.2.2        USB      1051   URB_BULK out
    ### 20 second delay
    ### finally, write FAT entries to indicate used sectors
79 26.559964      host      1.2.2        USBMS    58     SCSI: Write(10) LUN: 0x00 (LBA: 0x0000003b, Len: 1)
80 26.560191      host      1.2.2        USB      539    URB_BULK out
82 26.560834      host      1.2.2        USBMS    58     SCSI: Write(10) LUN: 0x00 (LBA: 0x0000003e, Len: 1)
83 26.560936      host      1.2.2        USB      539    URB_BULK out

我使用常规闪存驱动器以及模拟微型 USB MSC 驱动器的微控制器板在 Windows 7 和 Windows 10 上生成了这样的跟踪。

需要明确的是,这是一个 FAT12 格式的驱动器,在 Windows 格式化工具中仅称为“FAT”。

答案1

我可能已经找到了导致该问题的实际 Windows 驱动程序代码。

MS 恰好将 FAT 文件系统驱动程序包含在示例驱动程序代码包中。该驱动程序中有几处地方,如果文件系统是 FAT12,驱动程序将不会费心执行诸如设置脏位(FAT12 可能没有)或刷新 FAT 数据之类的操作。

https://github.com/Microsoft/Windows-driver-samples/blob/master/filesys/fastfat/verfysup.c#L774 https://github.com/Microsoft/Windows-driver-samples/blob/master/filesys/fastfat/cachesup.c#L1212 也许最关键的是: https://github.com/Microsoft/Windows-driver-samples/blob/master/filesys/fastfat/cleanup.c#L1101

在最后一个链接中,cleanup.c如果文件系统是 FAT12,则不会刷新 FAT。我认为这可能导致我看到的行为:

    //
    //  If that worked ok,  then see if we should flush the FAT as well.
    //

    if (NT_SUCCESS(Status) && Fcb && !FatIsFat12( Vcb) && 
        FlagOn( Fcb->FcbState, FCB_STATE_FLUSH_FAT)) {

        Status = FatFlushFat( IrpContext, Vcb);

在 Windows 反馈中心向 Microsoft 报告https://aka.ms/btvdog(在反馈中心打开的特殊 URL)。

相关内容