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

Dan*_*ert 10 windows fat16 usb-flash-drive

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

驱动器的大小很重要。我已经在 15MB 或更小的 FAT 文件系统上进行了测试并看到了问题。在 16MB 及以上时,写入不会延迟。当我在 Windows 中格式化驱动器时,16MB 是我在使用 FAT12 和 FAT16 之间看到的断点。(注:但FAT12/FAT16断点取决于簇数,而不是绝对文件系统大小)。

在 16MB 和更大的内存上,WindowsPrevent/Allow Medium Removal在写入之前发送 SCSI命令,要求不要删除该设备。USB 记忆棒实际上会在这些请求上返回失败(因为它不能保证不会移除),但 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
Run Code Online (Sandbox Code Playgroud)

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

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

Dan*_*ert 4

我可能已经找到了导致问题的实际 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);
Run Code Online (Sandbox Code Playgroud)

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